mirror of
https://github.com/weaveworks/scope.git
synced 2026-07-28 01:31:17 +00:00
Add test for ContainerRenderer and make tests in /app pass.
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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")),
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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"]
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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": {
|
||||
|
||||
Reference in New Issue
Block a user