示例#1
0
func TestMerger(t *testing.T) {
	// Use 3 reports to check the pair-wise merging in SmartMerger
	report1 := report.MakeReport()
	report1.Endpoint.AddNode(report.MakeNode("foo"))
	report2 := report.MakeReport()
	report2.Endpoint.AddNode(report.MakeNode("bar"))
	report3 := report.MakeReport()
	report3.Endpoint.AddNode(report.MakeNode("baz"))
	reports := []report.Report{
		report1, report2, report3,
	}
	want := report.MakeReport()
	want.Endpoint.
		AddNode(report.MakeNode("foo")).
		AddNode(report.MakeNode("bar")).
		AddNode(report.MakeNode("baz"))

	for _, merger := range []app.Merger{app.MakeDumbMerger(), app.NewSmartMerger()} {
		// Test the empty list case
		if have := merger.Merge([]report.Report{}); !reflect.DeepEqual(have, report.MakeReport()) {
			t.Errorf("Bad merge: %s", test.Diff(have, want))
		}

		if have := merger.Merge(reports); !reflect.DeepEqual(have, want) {
			t.Errorf("Bad merge: %s", test.Diff(have, want))
		}

		// Repeat the above test to ensure caching works
		if have := merger.Merge(reports); !reflect.DeepEqual(have, want) {
			t.Errorf("Bad merge: %s", test.Diff(have, want))
		}
	}
}
示例#2
0
func TestMerge(t *testing.T) {
	var (
		hostID = "xyz"
		src    = newMockSource([]byte{}, nil)
		on     = time.Millisecond
		off    = time.Millisecond
		rpt    = report.MakeReport()
		p      = sniff.Packet{
			SrcIP:     "1.0.0.0",
			SrcPort:   "1000",
			DstIP:     "2.0.0.0",
			DstPort:   "2000",
			Network:   512,
			Transport: 256,
		}

		_, ipnet, _ = net.ParseCIDR(p.SrcIP + "/24") // ;)
		localNets   = report.Networks([]*net.IPNet{ipnet})
	)
	sniff.New(hostID, localNets, src, on, off).Merge(p, &rpt)

	var (
		srcEndpointNodeID = report.MakeEndpointNodeID(hostID, p.SrcIP, p.SrcPort)
		dstEndpointNodeID = report.MakeEndpointNodeID(hostID, p.DstIP, p.DstPort)
	)
	if want, have := (report.Topology{
		Nodes: report.Nodes{
			srcEndpointNodeID: report.MakeNode(srcEndpointNodeID).WithEdge(dstEndpointNodeID, report.EdgeMetadata{
				EgressPacketCount: newu64(1),
				EgressByteCount:   newu64(256),
			}),
			dstEndpointNodeID: report.MakeNode(dstEndpointNodeID),
		},
	}), rpt.Endpoint; !reflect.DeepEqual(want, have) {
		t.Errorf("%s", test.Diff(want, have))
	}

	var (
		srcAddressNodeID = report.MakeAddressNodeID(hostID, p.SrcIP)
		dstAddressNodeID = report.MakeAddressNodeID(hostID, p.DstIP)
	)
	if want, have := (report.Topology{
		Nodes: report.Nodes{
			srcAddressNodeID: report.MakeNode(srcAddressNodeID).WithEdge(dstAddressNodeID, report.EdgeMetadata{
				EgressPacketCount: newu64(1),
				EgressByteCount:   newu64(512),
			}),
			dstAddressNodeID: report.MakeNode(dstAddressNodeID),
		},
	}), rpt.Address; !reflect.DeepEqual(want, have) {
		t.Errorf("%s", test.Diff(want, have))
	}
}
示例#3
0
func TestMetricCopy(t *testing.T) {
	want := report.MakeMetric()
	have := want.Copy()
	if !reflect.DeepEqual(want, have) {
		t.Errorf("diff: %s", test.Diff(want, have))
	}

	want = report.MakeMetric().Add(time.Now(), 1)
	have = want.Copy()
	if !reflect.DeepEqual(want, have) {
		t.Errorf("diff: %s", test.Diff(want, have))
	}
}
示例#4
0
func TestCountersDeepEquals(t *testing.T) {
	want := EmptyCounters.
		Add("foo", 3)
	have := EmptyCounters.
		Add("foo", 3)
	if !reflect.DeepEqual(want, have) {
		t.Errorf(test.Diff(want, have))
	}
	notequal := EmptyCounters.
		Add("foo", 4)
	if reflect.DeepEqual(want, notequal) {
		t.Errorf(test.Diff(want, have))
	}
}
func TestLatestMapDeepEquals(t *testing.T) {
	now := time.Now()
	want := EmptyLatestMap.
		Set("foo", now, "Bar")
	have := EmptyLatestMap.
		Set("foo", now, "Bar")
	if !reflect.DeepEqual(want, have) {
		t.Errorf(test.Diff(want, have))
	}
	notequal := EmptyLatestMap.
		Set("foo", now, "Baz")
	if reflect.DeepEqual(want, notequal) {
		t.Errorf(test.Diff(want, have))
	}
}
示例#6
0
func TestPipes(t *testing.T) {
	oldNewPipe := controls.NewPipe
	defer func() { controls.NewPipe = oldNewPipe }()
	controls.NewPipe = func(_ controls.PipeClient, _ string) (string, xfer.Pipe, error) {
		return "pipeid", mockPipe{}, nil
	}

	mdc := newMockClient()
	setupStubs(mdc, func() {
		registry, _ := docker.NewRegistry(10*time.Second, nil, false, "")
		defer registry.Stop()

		test.Poll(t, 100*time.Millisecond, true, func() interface{} {
			_, ok := registry.GetContainer("ping")
			return ok
		})

		for _, tc := range []string{
			docker.AttachContainer,
			docker.ExecContainer,
		} {
			result := controls.HandleControlRequest(xfer.Request{
				Control: tc,
				NodeID:  report.MakeContainerNodeID("ping"),
			})
			want := xfer.Response{
				Pipe:   "pipeid",
				RawTTY: true,
			}
			if !reflect.DeepEqual(result, want) {
				t.Errorf("diff %s: %s", tc, test.Diff(want, result))
			}
		}
	})
}
示例#7
0
func TestMetadataRowCopy(t *testing.T) {
	var (
		row = report.MetadataRow{
			ID:       "id",
			Value:    "value",
			Priority: 1,
			Datatype: "datatype",
		}
		cp = row.Copy()
	)

	// copy should be identical
	if !reflect.DeepEqual(row, cp) {
		t.Error(test.Diff(row, cp))
	}

	// changing the copy should not change the original
	cp.ID = ""
	cp.Value = ""
	cp.Priority = 2
	cp.Datatype = ""
	if row.ID != "id" || row.Value != "value" || row.Priority != 1 || row.Datatype != "datatype" {
		t.Errorf("Expected changing the copy not to modify the original")
	}
}
func TestLatestMapDeleteNil(t *testing.T) {
	want := LatestMap{}
	have := LatestMap{}.Delete("foo")
	if !reflect.DeepEqual(want, have) {
		t.Errorf(test.Diff(want, have))
	}
}
func TestLatestMapEncodingNil(t *testing.T) {
	want := LatestMap{}

	{
		gobs, err := want.GobEncode()
		if err != nil {
			t.Fatal(err)
		}
		have := EmptyLatestMap
		have.GobDecode(gobs)
		if have.Map == nil {
			t.Error("Decoded LatestMap.psMap should not be nil")
		}
	}

	{

		for _, h := range []codec.Handle{
			codec.Handle(&codec.MsgpackHandle{}),
			codec.Handle(&codec.JsonHandle{}),
		} {
			buf := &bytes.Buffer{}
			encoder := codec.NewEncoder(buf, h)
			want.CodecEncodeSelf(encoder)
			decoder := codec.NewDecoder(buf, h)
			have := EmptyLatestMap
			have.CodecDecodeSelf(decoder)
			if !reflect.DeepEqual(want, have) {
				t.Error(test.Diff(want, have))
			}
		}
	}
}
示例#10
0
func TestReportPostHandler(t *testing.T) {
	test := func(contentType string, encoder func(interface{}) ([]byte, error)) {
		router := mux.NewRouter()
		c := app.NewCollector(1 * time.Minute)
		app.RegisterReportPostHandler(c, router)
		ts := httptest.NewServer(router)
		defer ts.Close()

		b, err := encoder(fixture.Report)
		if err != nil {
			t.Fatalf("Content-Type %s: %s", contentType, err)
		}

		req, err := http.NewRequest("POST", ts.URL+"/api/report", bytes.NewReader(b))
		if err != nil {
			t.Fatalf("Error posting report: %v", err)
		}
		req.Header.Set("Content-Type", contentType)

		resp, err := http.DefaultClient.Do(req)
		if err != nil {
			t.Fatalf("Error posting report %v", err)
		}

		_, err = ioutil.ReadAll(resp.Body)
		resp.Body.Close()
		if err != nil {
			t.Fatalf("Error posting report: %v", err)
		}

		if resp.StatusCode != http.StatusOK {
			t.Fatalf("Error posting report: %d", resp.StatusCode)
		}

		ctx := context.Background()
		report, err := c.Report(ctx)
		if err != nil {
			t.Error(err)
		}
		if want, have := fixture.Report.Endpoint.Nodes, report.Endpoint.Nodes; len(have) == 0 || len(want) != len(have) {
			t.Fatalf("Content-Type %s: %v", contentType, test.Diff(have, want))
		}
	}

	test("", func(v interface{}) ([]byte, error) {
		buf := &bytes.Buffer{}
		err := gob.NewEncoder(buf).Encode(v)
		return buf.Bytes(), err
	})
	test("application/json", func(v interface{}) ([]byte, error) {
		buf := &bytes.Buffer{}
		err := codec.NewEncoder(buf, &codec.JsonHandle{}).Encode(v)
		return buf.Bytes(), err
	})
	test("application/msgpack", func(v interface{}) ([]byte, error) {
		buf := &bytes.Buffer{}
		err := codec.NewEncoder(buf, &codec.MsgpackHandle{}).Encode(v)
		return buf.Bytes(), err
	})
}
func TestEdgeMetadatasEncodingNil(t *testing.T) {
	want := EdgeMetadatas{}

	{
		gobs, err := want.GobEncode()
		if err != nil {
			t.Fatal(err)
		}
		have := EmptyEdgeMetadatas
		have.GobDecode(gobs)
		if have.psMap == nil {
			t.Error("needed to get back a non-nil psMap for EdgeMetadata")
		}
	}

	{

		for _, h := range []codec.Handle{
			codec.Handle(&codec.MsgpackHandle{}),
			codec.Handle(&codec.JsonHandle{}),
		} {
			buf := &bytes.Buffer{}
			encoder := codec.NewEncoder(buf, h)
			want.CodecEncodeSelf(encoder)
			decoder := codec.NewDecoder(buf, h)
			have := EmptyEdgeMetadatas
			have.CodecDecodeSelf(decoder)
			if !reflect.DeepEqual(want, have) {
				t.Error(test.Diff(want, have))
			}
		}
	}
}
示例#12
0
func TestHostRenderer(t *testing.T) {
	have := Prune(render.HostRenderer.Render(fixture.Report, render.FilterNoop))
	want := Prune(expected.RenderedHosts)
	if !reflect.DeepEqual(want, have) {
		t.Error(test.Diff(want, have))
	}
}
示例#13
0
func TestContainerRenderer(t *testing.T) {
	have := Prune(render.ContainerWithImageNameRenderer.Render(fixture.Report, render.FilterNoop))
	want := Prune(expected.RenderedContainers)
	if !reflect.DeepEqual(want, have) {
		t.Error(test.Diff(want, have))
	}
}
示例#14
0
func TestDNSAdd(t *testing.T) {
	mtx := sync.Mutex{}
	published := map[string]entry{}
	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		mtx.Lock()
		defer mtx.Unlock()
		parts := strings.SplitN(r.URL.Path, "/", 4)
		containerID, ip := parts[2], net.ParseIP(parts[3])
		fqdn := r.FormValue("fqdn")
		published[fqdn] = entry{containerID, ip}
		w.WriteHeader(http.StatusNoContent)
	}))
	defer s.Close()

	client := weave.NewClient(s.URL)
	err := client.AddDNSEntry(mockHostname, mockContainerID, mockIP)
	if err != nil {
		t.Fatal(err)
	}

	want := map[string]entry{
		mockHostname: {mockContainerID, mockIP},
	}
	if !reflect.DeepEqual(published, want) {
		t.Fatal(test.Diff(published, want))
	}
}
示例#15
0
func TestMetricRowSummary(t *testing.T) {
	var (
		now    = time.Now()
		metric = report.MakeMetric().Add(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))
	}
}
示例#16
0
func TestContainerHostnameFilterRenderer(t *testing.T) {
	// add a system container into the topology and ensure
	// it is filtered out correctly.
	input := fixture.Report.Copy()

	clientContainer2ID := "f6g7h8i9j1"
	clientContainer2NodeID := report.MakeContainerNodeID(clientContainer2ID)
	input.Container.AddNode(report.MakeNodeWith(clientContainer2NodeID, map[string]string{
		docker.LabelPrefix + "works.weave.role": "system",
		docker.ContainerHostname:                fixture.ClientContainerHostname,
		report.HostNodeID:                       fixture.ClientHostNodeID,
	}).
		WithParents(report.EmptySets.
			Add("host", report.MakeStringSet(fixture.ClientHostNodeID)),
		).WithTopology(report.Container))

	have := Prune(render.ContainerHostnameRenderer.Render(input, render.FilterApplication))
	want := Prune(expected.RenderedContainerHostnames)
	// Test works by virtue of the RenderedContainerHostname only having a container
	// counter == 1

	if !reflect.DeepEqual(want, have) {
		t.Error(test.Diff(want, have))
	}
}
示例#17
0
func TestPodServiceRenderer(t *testing.T) {
	have := Prune(render.PodServiceRenderer.Render(fixture.Report, nil))
	want := Prune(expected.RenderedPodServices)
	if !reflect.DeepEqual(want, have) {
		t.Error(test.Diff(want, have))
	}
}
示例#18
0
func TestReportLocalNetworks(t *testing.T) {
	r := report.MakeReport().Merge(report.Report{
		Host: report.Topology{
			Nodes: report.Nodes{
				"nonets": report.MakeNode("nonets"),
				"foo": report.MakeNode("foo").WithSets(report.EmptySets.
					Add(host.LocalNetworks, report.MakeStringSet(
						"10.0.0.1/8", "192.168.1.1/24", "10.0.0.1/8", "badnet/33")),
				),
			},
		},
		Overlay: report.Topology{
			Nodes: report.Nodes{
				"router": report.MakeNode("router").WithSets(report.EmptySets.
					Add(host.LocalNetworks, report.MakeStringSet("10.32.0.1/12")),
				),
			},
		},
	})
	want := report.Networks([]*net.IPNet{
		mustParseCIDR("10.0.0.1/8"),
		mustParseCIDR("192.168.1.1/24"),
		mustParseCIDR("10.32.0.1/12"),
	})
	have := render.LocalNetworks(r)
	if !reflect.DeepEqual(want, have) {
		t.Errorf("%s", test.Diff(want, have))
	}
}
func TestEdgeMetadataFlatten(t *testing.T) {
	// Test two EdgeMetadatas flatten to the correct values
	{
		have := (EdgeMetadata{
			EgressPacketCount: newu64(1),
		}).Flatten(EdgeMetadata{
			EgressPacketCount: newu64(4),
			EgressByteCount:   newu64(8),
		})
		want := EdgeMetadata{
			EgressPacketCount: newu64(1 + 4),
			EgressByteCount:   newu64(8),
		}
		if !reflect.DeepEqual(want, have) {
			t.Error(test.Diff(want, have))
		}
	}

	// Test an EdgeMetadatas flatten to the correct value (should
	// just sum)
	{
		have := EmptyEdgeMetadatas.
			Add("foo", EdgeMetadata{
				EgressPacketCount: newu64(1),
			}).
			Add("bar", EdgeMetadata{
				EgressPacketCount: newu64(3),
			}).Flatten()
		want := EdgeMetadata{
			EgressPacketCount: newu64(1 + 3),
		}
		if !reflect.DeepEqual(want, have) {
			t.Error(test.Diff(want, have))
		}
	}

	{
		// Should not panic on nil
		have := EdgeMetadatas{}.Flatten()
		want := EdgeMetadata{}
		if !reflect.DeepEqual(want, have) {
			t.Error(test.Diff(want, have))
		}
	}
}
示例#20
0
func TestMemoise(t *testing.T) {
	calls := 0
	r := renderFunc(func(rpt report.Report) report.Nodes {
		calls++
		return report.Nodes{rpt.ID: report.MakeNode(rpt.ID)}
	})
	m := render.Memoise(r)
	rpt1 := report.MakeReport()

	result1 := m.Render(rpt1, nil)
	// it should have rendered it.
	if _, ok := result1[rpt1.ID]; !ok {
		t.Errorf("Expected rendered report to contain a node, but got: %v", result1)
	}
	if calls != 1 {
		t.Errorf("Expected renderer to have been called the first time")
	}

	result2 := m.Render(rpt1, nil)
	if !reflect.DeepEqual(result1, result2) {
		t.Errorf("Expected memoised result to be returned: %s", test.Diff(result1, result2))
	}
	if calls != 1 {
		t.Errorf("Expected renderer to not have been called the second time")
	}

	rpt2 := report.MakeReport()
	result3 := m.Render(rpt2, nil)
	if reflect.DeepEqual(result1, result3) {
		t.Errorf("Expected different result for different report, but were the same")
	}
	if calls != 2 {
		t.Errorf("Expected renderer to have been called again for a different report")
	}

	render.ResetCache()
	result4 := m.Render(rpt1, nil)
	if !reflect.DeepEqual(result1, result4) {
		t.Errorf("Expected original result to be returned: %s", test.Diff(result1, result4))
	}
	if calls != 3 {
		t.Errorf("Expected renderer to have been called again after cache reset")
	}
}
示例#21
0
func checkLoadedPlugins(t *testing.T, forEach iterator, expected []xfer.PluginSpec) {
	var plugins []xfer.PluginSpec
	forEach(func(p *Plugin) {
		plugins = append(plugins, p.PluginSpec)
	})
	sort.Sort(xfer.PluginSpecsByID(plugins))
	if !reflect.DeepEqual(plugins, expected) {
		t.Fatalf(test.Diff(expected, plugins))
	}
}
示例#22
0
func TestLatestMapDelete(t *testing.T) {
	now := time.Now()
	want := EmptyLatestMap
	have := EmptyLatestMap.
		Set("foo", now, "Baz").
		Delete("foo")
	if !reflect.DeepEqual(want, have) {
		t.Errorf(test.Diff(want, have))
	}
}
示例#23
0
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:         docker.StateRunning,
			}).WithTopology(report.Container).WithSets(report.EmptySets.
				Add(docker.ContainerIPs, report.MakeStringSet("10.10.10.0/24", "10.10.10.1/24")),
			),
			want: []report.Table{
				{
					ID:    docker.EnvPrefix,
					Label: "Environment Variables",
					Rows:  []report.MetadataRow{},
				},
				{
					ID:    docker.LabelPrefix,
					Label: "Docker Labels",
					Rows: []report.MetadataRow{
						{
							ID:    "label_label1",
							Label: "label1",
							Value: "label1value",
						},
					},
				},
			},
		},
		{
			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 {
		have := detailed.NodeTables(input.rpt, input.node)
		if !reflect.DeepEqual(input.want, have) {
			t.Errorf("%s: %s", input.name, test.Diff(input.want, have))
		}
	}
}
示例#24
0
func TestControlsNotFound(t *testing.T) {
	want := xfer.Response{
		Error: "Control \"baz\" not recognised",
	}
	have := controls.HandleControlRequest(xfer.Request{
		Control: "baz",
	})
	if !reflect.DeepEqual(want, have) {
		t.Fatal(test.Diff(want, have))
	}
}
func TestEdgeMetadataReversed(t *testing.T) {
	have := EdgeMetadata{
		EgressPacketCount: newu64(1),
	}.Reversed()
	want := EdgeMetadata{
		IngressPacketCount: newu64(1),
	}
	if !reflect.DeepEqual(want, have) {
		t.Error(test.Diff(want, have))
	}
}
示例#26
0
func TestMetricsCopy(t *testing.T) {
	t1 := time.Now()
	want := report.Metrics{
		"metric1": report.MakeMetric().Add(t1, 0.1),
	}
	delete(want.Copy(), "metric1") // Modify a copy
	have := want.Copy()            // Check the original wasn't affected
	if !reflect.DeepEqual(want, have) {
		t.Errorf("diff: %s", test.Diff(want, have))
	}
}
示例#27
0
func TestCollector(t *testing.T) {
	ctx := context.Background()
	window := 10 * time.Second
	c := app.NewCollector(window)

	r1 := report.MakeReport()
	r1.Endpoint.AddNode(report.MakeNode("foo"))

	r2 := report.MakeReport()
	r2.Endpoint.AddNode(report.MakeNode("foo"))

	have, err := c.Report(ctx)
	if err != nil {
		t.Error(err)
	}
	if want := report.MakeReport(); !reflect.DeepEqual(want, have) {
		t.Error(test.Diff(want, have))
	}

	c.Add(ctx, r1)
	have, err = c.Report(ctx)
	if err != nil {
		t.Error(err)
	}
	if want := r1; !reflect.DeepEqual(want, have) {
		t.Error(test.Diff(want, have))
	}

	c.Add(ctx, r2)
	merged := report.MakeReport()
	merged = merged.Merge(r1)
	merged = merged.Merge(r2)
	have, err = c.Report(ctx)
	if err != nil {
		t.Error(err)
	}
	if want := merged; !reflect.DeepEqual(want, have) {
		t.Error(test.Diff(want, have))
	}
}
示例#28
0
func TestCollectorExpire(t *testing.T) {
	now := time.Now()
	mtime.NowForce(now)
	defer mtime.NowReset()

	ctx := context.Background()
	window := 10 * time.Second
	c := app.NewCollector(window)

	// 1st check the collector is empty
	have, err := c.Report(ctx)
	if err != nil {
		t.Error(err)
	}
	if want := report.MakeReport(); !reflect.DeepEqual(want, have) {
		t.Error(test.Diff(want, have))
	}

	// Now check an added report is returned
	r1 := report.MakeReport()
	r1.Endpoint.AddNode(report.MakeNode("foo"))
	c.Add(ctx, r1)
	have, err = c.Report(ctx)
	if err != nil {
		t.Error(err)
	}
	if want := r1; !reflect.DeepEqual(want, have) {
		t.Error(test.Diff(want, have))
	}

	// Finally move time forward to expire the report
	mtime.NowForce(now.Add(window))
	have, err = c.Report(ctx)
	if err != nil {
		t.Error(err)
	}
	if want := report.MakeReport(); !reflect.DeepEqual(want, have) {
		t.Error(test.Diff(want, have))
	}
}
示例#29
0
func TestCache(t *testing.T) {
	processes := []process.Process{
		{PID: 1, PPID: 0, Name: "init", Cmdline: "init"},
		{PID: 2, PPID: 1, Name: "bash", Cmdline: "bash"},
		{PID: 3, PPID: 1, Name: "apache", Threads: 2, Cmdline: "apache"},
		{PID: 4, PPID: 2, Name: "ping", Cmdline: "ping foo.bar.local"},
	}
	walker := &mockWalker{
		processes: processes,
	}
	cachingWalker := process.NewCachingWalker(walker)
	err := cachingWalker.Tick()
	if err != nil {
		t.Fatal(err)
	}

	want, err := all(walker)
	have, err := all(cachingWalker)
	if err != nil || !reflect.DeepEqual(want, have) {
		t.Errorf("%v (%v)", test.Diff(want, have), err)
	}

	walker.processes = []process.Process{}
	have, err = all(cachingWalker)
	if err != nil || !reflect.DeepEqual(want, have) {
		t.Errorf("%v (%v)", test.Diff(want, have), err)
	}

	err = cachingWalker.Tick()
	if err != nil {
		t.Fatal(err)
	}

	have, err = all(cachingWalker)
	want = map[process.Process]struct{}{}
	if err != nil || !reflect.DeepEqual(want, have) {
		t.Errorf("%v (%v)", test.Diff(want, have), err)
	}
}
func TestEdgeMetadatasEncoding(t *testing.T) {
	want := EmptyEdgeMetadatas.
		Add("foo", EdgeMetadata{
			EgressPacketCount: newu64(1),
		}).
		Add("bar", EdgeMetadata{
			EgressPacketCount: newu64(3),
		})

	{
		gobs, err := want.GobEncode()
		if err != nil {
			t.Fatal(err)
		}
		have := EmptyEdgeMetadatas
		have.GobDecode(gobs)
		if !reflect.DeepEqual(want, have) {
			t.Error(test.Diff(want, have))
		}
	}

	{
		for _, h := range []codec.Handle{
			codec.Handle(&codec.MsgpackHandle{}),
			codec.Handle(&codec.JsonHandle{}),
		} {
			buf := &bytes.Buffer{}
			encoder := codec.NewEncoder(buf, h)
			want.CodecEncodeSelf(encoder)
			decoder := codec.NewDecoder(buf, h)
			have := EmptyEdgeMetadatas
			have.CodecDecodeSelf(decoder)
			if !reflect.DeepEqual(want, have) {
				t.Error(test.Diff(want, have))
			}
		}
	}
}