123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476 |
- package detailed_test
- import (
- "context"
- "sort"
- "testing"
- "time"
- "github.com/weaveworks/common/mtime"
- "github.com/weaveworks/common/test"
- "github.com/weaveworks/scope/probe/docker"
- "github.com/weaveworks/scope/probe/process"
- "github.com/weaveworks/scope/render"
- "github.com/weaveworks/scope/render/detailed"
- "github.com/weaveworks/scope/render/expected"
- "github.com/weaveworks/scope/report"
- "github.com/weaveworks/scope/test/fixture"
- "github.com/weaveworks/scope/test/reflect"
- )
- func TestSummaries(t *testing.T) {
- {
- // Just a convenient source of some rendered nodes
- have := detailed.Summaries(context.Background(), detailed.RenderContext{Report: fixture.Report}, render.ProcessRenderer.Render(context.Background(), fixture.Report).Nodes)
- // The ids of the processes rendered above
- expectedIDs := []string{
- fixture.ClientProcess1NodeID,
- fixture.ClientProcess2NodeID,
- fixture.ServerProcessNodeID,
- fixture.NonContainerProcessNodeID,
- render.IncomingInternetID,
- render.OutgoingInternetID,
- }
- sort.Strings(expectedIDs)
- // It should summarize each node
- ids := []string{}
- for id := range have {
- ids = append(ids, id)
- }
- sort.Strings(ids)
- if !reflect.DeepEqual(expectedIDs, ids) {
- t.Fatalf("Expected Summaries to have summarized every node in the process renderer: %v, but got %v", expectedIDs, ids)
- }
- }
- // It should summarize nodes' metrics
- {
- t1, t2 := mtime.Now().Add(-1*time.Minute), mtime.Now()
- metric := report.MakeMetric([]report.Sample{{Timestamp: t1, Value: 1}, {Timestamp: t2, Value: 2}})
- input := fixture.Report.Copy()
- processNode := input.Process.Nodes[fixture.ClientProcess1NodeID]
- processNode.Metrics = processNode.Metrics.Copy()
- processNode.Metrics[process.CPUUsage] = metric
- input.Process.Nodes[fixture.ClientProcess1NodeID] = processNode
- have := detailed.Summaries(context.Background(), detailed.RenderContext{Report: input}, render.ProcessRenderer.Render(context.Background(), input).Nodes)
- node, ok := have[fixture.ClientProcess1NodeID]
- if !ok {
- t.Fatalf("Expected output to have the node we added the metric to")
- }
- var row report.MetricRow
- ok = false
- for _, metric := range node.Metrics {
- if metric.ID == process.CPUUsage {
- row = metric
- ok = true
- break
- }
- }
- if !ok {
- t.Fatalf("Expected node to have the metric we added")
- }
- // Our summarized MetricRow
- want := report.MetricRow{
- ID: process.CPUUsage,
- Label: "CPU",
- Format: "percent",
- Value: 2,
- Priority: 1,
- Metric: &report.Metric{
- Samples: nil,
- Min: metric.Min,
- Max: metric.Max,
- },
- }
- if !reflect.DeepEqual(want, row) {
- t.Fatalf("Expected to have summarized the node's metrics: %s", test.Diff(want, row))
- }
- }
- }
- func TestMakeNodeSummary(t *testing.T) {
- testcases := []struct {
- name string
- input report.Node
- ok bool
- want detailed.NodeSummary
- }{
- {
- name: "single process rendering",
- input: expected.RenderedProcesses[fixture.ClientProcess1NodeID],
- ok: true,
- want: detailed.NodeSummary{
- BasicNodeSummary: detailed.BasicNodeSummary{
- ID: fixture.ClientProcess1NodeID,
- Label: fixture.Client1Name,
- LabelMinor: "client.hostname.com (10001)",
- Rank: fixture.Client1Name,
- Shape: "square",
- Tag: "",
- },
- Metadata: []report.MetadataRow{
- {ID: process.PID, Label: "PID", Value: fixture.Client1PID, Priority: 1, Datatype: report.Number},
- },
- Adjacency: report.MakeIDList(fixture.ServerProcessNodeID),
- },
- },
- {
- name: "single container rendering",
- input: expected.RenderedContainers[fixture.ClientContainerNodeID],
- ok: true,
- want: detailed.NodeSummary{
- BasicNodeSummary: detailed.BasicNodeSummary{
- ID: fixture.ClientContainerNodeID,
- Label: fixture.ClientContainerName,
- LabelMinor: fixture.ClientHostName,
- Rank: fixture.ClientContainerImageName,
- Shape: "hexagon",
- Tag: "",
- },
- Metadata: []report.MetadataRow{
- {ID: docker.ImageName, Label: "Image name", Value: fixture.ClientContainerImageName, Priority: 2},
- {ID: docker.ContainerID, Label: "ID", Value: fixture.ClientContainerID, Priority: 11, Truncate: 12},
- },
- Adjacency: report.MakeIDList(fixture.ServerContainerNodeID),
- },
- },
- {
- name: "single container image rendering",
- input: expected.RenderedContainerImages[expected.ClientContainerImageNodeID],
- ok: true,
- want: detailed.NodeSummary{
- BasicNodeSummary: detailed.BasicNodeSummary{
- ID: expected.ClientContainerImageNodeID,
- Label: fixture.ClientContainerImageName,
- LabelMinor: "1 container",
- Rank: fixture.ClientContainerImageName,
- Shape: "hexagon",
- Tag: "",
- Stack: true,
- },
- Metadata: []report.MetadataRow{
- {ID: report.Container, Label: "# Containers", Value: "1", Priority: 2, Datatype: report.Number},
- },
- Adjacency: report.MakeIDList(expected.ServerContainerImageNodeID),
- },
- },
- {
- name: "single host rendering",
- input: expected.RenderedHosts[fixture.ClientHostNodeID],
- ok: true,
- want: detailed.NodeSummary{
- BasicNodeSummary: detailed.BasicNodeSummary{
- ID: fixture.ClientHostNodeID,
- Label: "client",
- LabelMinor: "hostname.com",
- Rank: "hostname.com",
- Shape: "circle",
- Tag: "",
- },
- Metadata: []report.MetadataRow{
- {ID: report.HostName, Label: "Hostname", Value: fixture.ClientHostName, Priority: 11},
- },
- Adjacency: report.MakeIDList(fixture.ServerHostNodeID),
- },
- },
- {
- name: "group node rendering",
- input: expected.RenderedProcessNames[fixture.ServerName],
- ok: true,
- want: detailed.NodeSummary{
- BasicNodeSummary: detailed.BasicNodeSummary{
- ID: "apache",
- Label: "apache",
- LabelMinor: "1 process",
- Rank: "apache",
- Shape: "square",
- Tag: "",
- Stack: true,
- },
- },
- },
- }
- for _, testcase := range testcases {
- have, ok := detailed.MakeNodeSummary(detailed.RenderContext{Report: fixture.Report}, testcase.input)
- if ok != testcase.ok {
- t.Errorf("%s: MakeNodeSummary failed: expected ok value to be: %v", testcase.name, testcase.ok)
- continue
- }
- if !reflect.DeepEqual(testcase.want, have) {
- t.Errorf("%s: Node Summary did not match: %s", testcase.name, test.Diff(testcase.want, have))
- }
- }
- }
- func TestMakeNodeSummaryNoMetadata(t *testing.T) {
- processNameTopology := render.MakeGroupNodeTopology(report.Process, process.Name)
- for topology, id := range map[string]string{
- render.Pseudo: render.MakePseudoNodeID("id"),
- report.Process: report.MakeProcessNodeID("ip-123-45-6-100", "1234"),
- report.Container: report.MakeContainerNodeID("0001accbecc2c95e650fe641926fb923b7cc307a71101a1200af3759227b6d7d"),
- report.ContainerImage: report.MakeContainerImageNodeID("0001accbecc2c95e650fe641926fb923b7cc307a71101a1200af3759227b6d7d"),
- report.Pod: report.MakePodNodeID("005e2999-d429-11e7-8535-0a41257e78e8"),
- report.Service: report.MakeServiceNodeID("005e2999-d429-11e7-8535-0a41257e78e8"),
- report.Deployment: report.MakeDeploymentNodeID("005e2999-d429-11e7-8535-0a41257e78e8"),
- report.DaemonSet: report.MakeDaemonSetNodeID("005e2999-d429-11e7-8535-0a41257e78e8"),
- report.StatefulSet: report.MakeStatefulSetNodeID("005e2999-d429-11e7-8535-0a41257e78e8"),
- report.CronJob: report.MakeCronJobNodeID("005e2999-d429-11e7-8535-0a41257e78e8"),
- report.ECSTask: report.MakeECSTaskNodeID("arn:aws:ecs:us-east-1:012345678910:task/1dc5c17a-422b-4dc4-b493-371970c6c4d6"),
- report.ECSService: report.MakeECSServiceNodeID("cluster", "service"),
- report.SwarmService: report.MakeSwarmServiceNodeID("0001accbecc2c95e650fe641926fb923b7cc307a71101a1200af3759227b6d7d"),
- report.Host: report.MakeHostNodeID("ip-123-45-6-100"),
- report.Overlay: report.MakeOverlayNodeID("", "3e:ca:14:ca:12:5c"),
- processNameTopology: "/home/weave/scope",
- } {
- summary, b := detailed.MakeNodeSummary(detailed.RenderContext{}, report.MakeNode(id).WithTopology(topology))
- switch {
- case !b:
- t.Errorf("Node Summary missing for topology %s, id %s", topology, id)
- case summary.Label == "":
- t.Errorf("Node Summary Label missing for topology %s, id %s", topology, id)
- case summary.Label == id && topology != processNameTopology:
- t.Errorf("Node Summary Label same as id (that's cheating!) for topology %s, id %s", topology, id)
- }
- }
- }
- func TestNodeMetadata(t *testing.T) {
- inputs := []struct {
- name string
- node report.Node
- want []report.MetadataRow
- }{
- {
- name: "container",
- node: report.MakeNodeWith(fixture.ClientContainerNodeID, map[string]string{
- docker.ContainerID: fixture.ClientContainerID,
- docker.LabelPrefix + "label1": "label1value",
- docker.ContainerStateHuman: report.StateRunning,
- }).WithTopology(report.Container).WithSets(report.MakeSets().
- Add(docker.ContainerIPs, report.MakeStringSet("10.10.10.0/24", "10.10.10.1/24")),
- ),
- want: []report.MetadataRow{
- {ID: docker.ContainerStateHuman, Label: "State", Value: "running", Priority: 4},
- {ID: docker.ContainerIPs, Label: "IPs", Value: "10.10.10.0/24, 10.10.10.1/24", Priority: 8},
- {ID: docker.ContainerID, Label: "ID", Value: fixture.ClientContainerID, Priority: 11, Truncate: 12},
- },
- },
- {
- name: "unknown topology",
- node: report.MakeNodeWith(fixture.ClientContainerNodeID, map[string]string{
- docker.ContainerID: fixture.ClientContainerID,
- }).WithTopology("foobar"),
- want: nil,
- },
- }
- for _, input := range inputs {
- summary, _ := detailed.MakeNodeSummary(detailed.RenderContext{Report: fixture.Report}, input.node)
- have := summary.Metadata
- if !reflect.DeepEqual(input.want, have) {
- t.Errorf("%s: %s", input.name, test.Diff(input.want, have))
- }
- }
- }
- func TestNodeMetrics(t *testing.T) {
- inputs := []struct {
- name string
- node report.Node
- want []report.MetricRow
- }{
- {
- name: "process",
- node: fixture.Report.Process.Nodes[fixture.ClientProcess1NodeID],
- want: []report.MetricRow{
- {
- ID: process.CPUUsage,
- Label: "CPU",
- Format: "percent",
- Group: "",
- Value: 0.01,
- Priority: 1,
- Metric: &fixture.ClientProcess1CPUMetric,
- },
- {
- ID: process.MemoryUsage,
- Label: "Memory",
- Format: "filesize",
- Group: "",
- Value: 0.02,
- Priority: 2,
- Metric: &fixture.ClientProcess1MemoryMetric,
- },
- },
- },
- {
- name: "container",
- node: fixture.Report.Container.Nodes[fixture.ClientContainerNodeID],
- want: []report.MetricRow{
- {
- ID: docker.CPUTotalUsage,
- Label: "CPU",
- Format: "percent",
- Group: "",
- Value: 0.03,
- Priority: 1,
- Metric: &fixture.ClientContainerCPUMetric,
- },
- {
- ID: docker.MemoryUsage,
- Label: "Memory",
- Format: "filesize",
- Group: "",
- Value: 0.04,
- Priority: 2,
- Metric: &fixture.ClientContainerMemoryMetric,
- },
- },
- },
- {
- name: "host",
- node: fixture.Report.Host.Nodes[fixture.ClientHostNodeID],
- want: []report.MetricRow{
- {
- ID: report.HostCPUUsage,
- Label: "CPU",
- Format: "percent",
- Group: "",
- Value: 0.07,
- Priority: 1,
- Metric: &fixture.ClientHostCPUMetric,
- },
- {
- ID: report.HostMemoryUsage,
- Label: "Memory",
- Format: "filesize",
- Group: "",
- Value: 0.08,
- Priority: 2,
- Metric: &fixture.ClientHostMemoryMetric,
- },
- {
- ID: report.Load1,
- Label: "Load (1m)",
- Group: "load",
- Value: 0.09,
- Priority: 11,
- Metric: &fixture.ClientHostLoad1Metric,
- },
- },
- },
- {
- name: "unknown topology",
- node: report.MakeNode(fixture.ClientContainerNodeID).WithTopology("foobar"),
- want: nil,
- },
- }
- for _, input := range inputs {
- summary, _ := detailed.MakeNodeSummary(detailed.RenderContext{Report: fixture.Report}, input.node)
- have := summary.Metrics
- if !reflect.DeepEqual(input.want, have) {
- t.Errorf("%s: %s", input.name, test.Diff(input.want, have))
- }
- }
- }
- func TestMetricRowSummary(t *testing.T) {
- var (
- now = time.Now()
- metric = report.MakeSingletonMetric(now, 1.234)
- row = report.MetricRow{
- ID: "id",
- Format: "format",
- Group: "group",
- Value: 1.234,
- Priority: 1,
- Metric: &metric,
- }
- summary = row.Summary()
- )
- // summary should not have any samples
- if summary.Metric.Len() != 0 {
- t.Errorf("Expected summary to have no samples, but had %d", summary.Metric.Len())
- }
- // original metric should still have its samples
- if metric.Len() != 1 {
- t.Errorf("Expected original metric to still have it's samples, but had %d", metric.Len())
- }
- // summary should have all the same fields (minus the metric)
- summary.Metric = nil
- row.Metric = nil
- if !reflect.DeepEqual(summary, row) {
- t.Errorf("Expected summary to have same fields as original: %s", test.Diff(summary, row))
- }
- }
- func TestNodeTables(t *testing.T) {
- inputs := []struct {
- name string
- rpt report.Report
- node report.Node
- want []report.Table
- }{
- {
- name: "container",
- rpt: report.Report{
- Container: report.MakeTopology().
- WithTableTemplates(docker.ContainerTableTemplates),
- },
- node: report.MakeNodeWith(fixture.ClientContainerNodeID, map[string]string{
- docker.ContainerID: fixture.ClientContainerID,
- docker.LabelPrefix + "label1": "label1value",
- docker.ContainerState: report.StateRunning,
- }).WithTopology(report.Container).WithSets(report.MakeSets().
- Add(docker.ContainerIPs, report.MakeStringSet("10.10.10.0/24", "10.10.10.1/24")),
- ),
- want: []report.Table{
- {
- ID: docker.EnvPrefix,
- Type: report.PropertyListType,
- Label: "Environment variables",
- Rows: []report.Row{},
- },
- {
- ID: docker.LabelPrefix,
- Type: report.PropertyListType,
- Label: "Docker labels",
- Rows: []report.Row{
- {
- ID: "label_label1",
- Entries: map[string]string{
- "label": "label1",
- "value": "label1value",
- },
- },
- },
- },
- {
- ID: docker.ImageTableID,
- Type: report.PropertyListType,
- Label: "Image",
- Rows: []report.Row{},
- },
- },
- },
- {
- name: "unknown topology",
- rpt: report.MakeReport(),
- node: report.MakeNodeWith(fixture.ClientContainerNodeID, map[string]string{
- docker.ContainerID: fixture.ClientContainerID,
- }).WithTopology("foobar"),
- want: nil,
- },
- }
- for _, input := range inputs {
- summary, _ := detailed.MakeNodeSummary(detailed.RenderContext{Report: input.rpt}, input.node)
- have := summary.Tables
- if !reflect.DeepEqual(input.want, have) {
- t.Errorf("%s: %s", input.name, test.Diff(input.want, have))
- }
- }
- }
|