Add test for ContainerRenderer and make tests in /app pass.

This commit is contained in:
Tom Wilkie
2015-06-17 12:55:03 +00:00
parent 3de721bb16
commit 75b5e07482
7 changed files with 149 additions and 38 deletions

View File

@@ -26,15 +26,15 @@ func TestAPITopology(t *testing.T) {
}
if have := topology.Stats.EdgeCount; have <= 0 {
t.Errorf("EdgeCount isn't positive: %d", have)
t.Errorf("EdgeCount isn't positive for %s: %d", topology.Name, have)
}
if have := topology.Stats.NodeCount; have <= 0 {
t.Errorf("NodeCount isn't positive: %d", have)
t.Errorf("NodeCount isn't positive for %s: %d", topology.Name, have)
}
if have := topology.Stats.NonpseudoNodeCount; have <= 0 {
t.Errorf("NonpseudoNodeCount isn't positive: %d", have)
t.Errorf("NonpseudoNodeCount isn't positive for %s: %d", topology.Name, have)
}
}
}

View File

@@ -23,36 +23,37 @@ func TestAPITopologyApplications(t *testing.T) {
t.Fatal(err)
}
equals(t, 4, len(topo.Nodes))
node, ok := topo.Nodes["pid:node-a.local:23128"]
node, ok := topo.Nodes["pid:hostA:23128"]
if !ok {
t.Errorf("missing curl node")
}
equals(t, 1, len(node.Adjacency))
equals(t, report.MakeIDList("pid:node-b.local:215"), node.Adjacency)
equals(t, report.MakeIDList("pid:hostB:215"), node.Adjacency)
equals(t, report.MakeIDList(
report.MakeEndpointNodeID("hostA", "192.168.1.1", "12345"),
report.MakeEndpointNodeID("hostA", "192.168.1.1", "12346"),
report.MakeProcessNodeID("hostA", "23128"),
report.MakeHostNodeID("hostA"),
), node.Origins)
equals(t, "curl", node.LabelMajor)
equals(t, "node-a.local (23128)", node.LabelMinor)
equals(t, "hostA (23128)", node.LabelMinor)
equals(t, "23128", node.Rank)
equals(t, false, node.Pseudo)
}
{
body := getRawJSON(t, ts, "/api/topology/applications/pid:node-a.local:23128")
body := getRawJSON(t, ts, "/api/topology/applications/pid:hostA:23128")
var node APINode
if err := json.Unmarshal(body, &node); err != nil {
t.Fatal(err)
}
equals(t, "pid:node-a.local:23128", node.Node.ID)
equals(t, "pid:hostA:23128", node.Node.ID)
equals(t, "curl", node.Node.LabelMajor)
equals(t, "node-a.local (23128)", node.Node.LabelMinor)
equals(t, "hostA (23128)", node.Node.LabelMinor)
equals(t, false, node.Node.Pseudo)
// Let's not unit-test the specific content of the detail tables
}
{
body := getRawJSON(t, ts, "/api/topology/applications/pid:node-a.local:23128/pid:node-b.local:215")
body := getRawJSON(t, ts, "/api/topology/applications/pid:hostA:23128/pid:hostB:215")
var edge APIEdge
if err := json.Unmarshal(body, &edge); err != nil {
t.Fatalf("JSON parse error: %s", err)

View File

@@ -55,32 +55,63 @@ func (s StaticReport) Report() report.Report {
},
NodeMetadatas: report.NodeMetadatas{
report.MakeEndpointNodeID("hostA", "192.168.1.1", "12345"): report.NodeMetadata{
"addr": "192.168.1.1",
"port": "12345",
"pid": "23128",
"name": "curl",
"domain": "node-a.local",
report.HostNodeID: report.MakeHostNodeID("hostA"),
},
report.MakeEndpointNodeID("hostA", "192.168.1.1", "12346"): report.NodeMetadata{ // <-- same as :12345
"addr": "192.168.1.1",
"port": "12346",
"pid": "23128",
"name": "curl",
"domain": "node-a.local",
report.HostNodeID: report.MakeHostNodeID("hostA"),
},
report.MakeEndpointNodeID("hostA", "192.168.1.1", "8888"): report.NodeMetadata{
"addr": "192.168.1.1",
"port": "8888",
"pid": "55100",
"name": "ssh",
"domain": "node-a.local",
report.HostNodeID: report.MakeHostNodeID("hostA"),
},
report.MakeEndpointNodeID("hostB", "192.168.1.2", "80"): report.NodeMetadata{
"addr": "192.168.1.2",
"port": "80",
"pid": "215",
"name": "apache",
"domain": "node-b.local",
report.HostNodeID: report.MakeHostNodeID("hostB"),
},
},
},
Process: report.Topology{
NodeMetadatas: report.NodeMetadatas{
report.MakeProcessNodeID("hostA", "23128"): report.NodeMetadata{
"pid": "23128",
"comm": "curl",
report.HostNodeID: report.MakeHostNodeID("hostA"),
},
report.MakeProcessNodeID("hostA", "8888"): report.NodeMetadata{
"pid": "8888",
"comm": "ssh",
report.HostNodeID: report.MakeHostNodeID("hostA"),
},
report.MakeProcessNodeID("hostB", "80"): report.NodeMetadata{
"pid": "80",
"comm": "apache",
"docker_container_id": "abcdefg",
report.HostNodeID: report.MakeHostNodeID("hostB"),
},
},
},
Container: report.Topology{
NodeMetadatas: report.NodeMetadatas{
report.MakeContainerNodeID("hostB", "abcdefg"): report.NodeMetadata{
"docker_container_id": "abcdefg",
"docker_container_name": "server",
report.HostNodeID: report.MakeHostNodeID("hostB"),
},
},
},
Address: report.Topology{
Adjacency: report.Adjacency{
report.MakeAdjacencyID(report.MakeAddressNodeID("hostA", "192.168.1.1")): report.MakeIDList(report.MakeAddressNodeID("hostB", "192.168.1.2"), report.MakeAddressNodeID("", "1.2.3.4")),

View File

@@ -107,7 +107,7 @@ func mapFunc(r *http.Request) render.LeafMapFunc {
case "hosts", "networkhost", "networkhostname":
return render.NetworkHostname
}
return render.ProcessPID
return render.MapProcessIdentity
}
func classView(r *http.Request) bool {

View File

@@ -7,9 +7,10 @@ import (
"github.com/weaveworks/scope/report"
)
// Constants are used in the tests.
const (
uncontainedID = "uncontained"
uncontainedMajor = "Uncontained"
UncontainedID = "uncontained"
UncontainedMajor = "Uncontained"
humanTheInternet = "the Internet"
)
@@ -44,11 +45,17 @@ type MapFunc func(RenderableNode) (RenderableNode, bool)
// presences of certain keys.
func MapEndpointIdentity(m report.NodeMetadata) (RenderableNode, bool) {
var (
id = fmt.Sprintf("endpoint:%s:%s:%s", getHostname(m), m["addr"], m["port"])
major = fmt.Sprintf("%s:%s", m["addr"], m["port"])
minor = fmt.Sprintf("%s (%s)", getHostname(m), m["pid"])
rank = m["pid"]
id = fmt.Sprintf("endpoint:%s:%s:%s", getHostname(m), m["addr"], m["port"])
major = fmt.Sprintf("%s:%s", m["addr"], m["port"])
pid, ok = m["pid"]
minor = getHostname(m)
rank = major
)
if ok {
minor = fmt.Sprintf("%s (%s)", getHostname(m), pid)
}
return NewRenderableNode(id, major, minor, rank, m), true
}
@@ -119,8 +126,8 @@ func MapEndpoint2Process(n RenderableNode) (RenderableNode, bool) {
// must be merged with a container graph to get that info.
func MapProcess2Container(n RenderableNode) (RenderableNode, bool) {
id, ok := n.NodeMetadata["docker_container_id"]
if !ok {
return newPseudoNode(uncontainedID, uncontainedMajor, ""), true
if !ok || n.Pseudo {
return newDerivedPseudoNode(UncontainedID, UncontainedMajor, n), true
}
return newDerivedNode(id, n), true
@@ -154,21 +161,13 @@ func getHostname(m report.NodeMetadata) string {
return hostname
}
// ProcessName takes a node NodeMetadata from a topology, and returns a
// representation with the ID based on the process name (grouping all
// processes with the same name together).
func ProcessName(m report.NodeMetadata) (RenderableNode, bool) {
show := m["pid"] != "" && m["name"] != ""
return NewRenderableNode(m["name"], m["name"], "", m["name"], m), show
}
// ProcessContainerImage maps topology nodes to the container images they run
// on. If no container metadata is found, nodes are grouped into the
// Uncontained node.
func ProcessContainerImage(m report.NodeMetadata) (RenderableNode, bool) {
var id, major, minor, rank string
if m["docker_image_id"] == "" {
id, major, minor, rank = "uncontained", "Uncontained", "", "uncontained"
id, major, minor, rank = UncontainedID, UncontainedMajor, "", UncontainedID
} else {
id, major, minor, rank = m["docker_image_id"], m["docker_image_name"], "", m["docker_image_id"]
}

View File

@@ -97,3 +97,16 @@ func newPseudoNode(id, major, minor string) RenderableNode {
NodeMetadata: report.NodeMetadata{},
}
}
func newDerivedPseudoNode(id, major string, node RenderableNode) RenderableNode {
return RenderableNode{
ID: id,
LabelMajor: major,
LabelMinor: "",
Rank: "",
Pseudo: true,
AggregateMetadata: node.AggregateMetadata,
Origins: node.Origins,
NodeMetadata: node.NodeMetadata,
}
}

View File

@@ -54,6 +54,11 @@ var (
clientProcessNodeID = report.MakeProcessNodeID(clientHostID, clientPID)
serverProcessNodeID = report.MakeProcessNodeID(serverHostID, serverPID)
nonContainerProcessNodeID = report.MakeProcessNodeID(serverHostID, nonContainerPID)
clientContainerID = "a1b2c3d4e5"
serverContainerID = "5e4d3c2b1a"
clientContainerNodeID = report.MakeContainerNodeID(clientHostID, clientContainerID)
serverContainerNodeID = report.MakeContainerNodeID(serverHostID, serverContainerID)
)
var (
@@ -132,13 +137,13 @@ var (
clientProcessNodeID: report.NodeMetadata{
"pid": clientPID,
"comm": "curl",
"docker_container_id": "a1b2c3d4e5",
"docker_container_id": clientContainerID,
report.HostNodeID: clientHostNodeID,
},
serverProcessNodeID: report.NodeMetadata{
"pid": serverPID,
"comm": "apache",
"docker_container_id": "5e4d3c2b1a",
"docker_container_id": serverContainerID,
report.HostNodeID: serverHostNodeID,
},
nonContainerProcessNodeID: report.NodeMetadata{
@@ -149,6 +154,20 @@ var (
},
EdgeMetadatas: report.EdgeMetadatas{},
},
Container: report.Topology{
NodeMetadatas: report.NodeMetadatas{
clientContainerNodeID: report.NodeMetadata{
"docker_container_id": clientContainerID,
"docker_container_name": "client",
report.HostNodeID: clientHostNodeID,
},
serverContainerNodeID: report.NodeMetadata{
"docker_container_id": serverContainerID,
"docker_container_name": "server",
report.HostNodeID: serverHostNodeID,
},
},
},
Address: report.Topology{
Adjacency: report.Adjacency{
report.MakeAdjacencyID(clientAddressNodeID): report.MakeIDList(serverAddressNodeID),
@@ -351,6 +370,54 @@ func TestProcessNameRenderer(t *testing.T) {
}
}
func TestContainerRenderer(t *testing.T) {
// For grouped, I've somewhat arbitrarily chosen to squash together all
// processes with the same name by removing the PID and domain (host)
// dimensions from the ID. That could be changed.
want := render.RenderableNodes{
clientContainerID: {
ID: clientContainerID,
LabelMajor: "client",
LabelMinor: clientHostName,
Rank: "",
Pseudo: false,
Adjacency: report.MakeIDList(serverContainerID),
Origins: report.MakeIDList(clientContainerNodeID, client54001NodeID, client54002NodeID, clientProcessNodeID, clientHostNodeID),
AggregateMetadata: report.AggregateMetadata{
report.KeyBytesIngress: 300,
report.KeyBytesEgress: 30,
},
},
serverContainerID: {
ID: serverContainerID,
LabelMajor: "server",
LabelMinor: serverHostName,
Rank: "",
Pseudo: false,
Adjacency: report.MakeIDList(clientContainerID, render.UncontainedID),
Origins: report.MakeIDList(serverContainerNodeID, server80NodeID, serverProcessNodeID, serverHostNodeID),
AggregateMetadata: report.AggregateMetadata{
report.KeyBytesIngress: 150,
report.KeyBytesEgress: 1500,
},
},
render.UncontainedID: {
ID: render.UncontainedID,
LabelMajor: render.UncontainedMajor,
LabelMinor: "",
Rank: "",
Pseudo: true,
Origins: report.MakeIDList(nonContainerProcessNodeID, serverHostNodeID),
AggregateMetadata: report.AggregateMetadata{},
},
}
have := render.ContainerRenderer.Render(rpt)
have = trimNodeMetadata(have)
if !reflect.DeepEqual(want, have) {
t.Error("\n" + diff(want, have))
}
}
func TestRenderByNetworkHostname(t *testing.T) {
want := render.RenderableNodes{
"host:client.hostname.com": {