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)) } } }) }
func TestReverseResolver(t *testing.T) { tests := map[string][]string{ "1.2.3.4": {"test.domain.name"}, "4.3.2.1": {"im.a.little.tea.pot"}, } revRes := newReverseResolver() defer revRes.stop() // Use a mocked resolver function. revRes.Resolver = func(addr string) (names []string, err error) { if names, ok := tests[addr]; ok { return names, nil } return []string{}, errors.New("invalid IP") } // Up the rate limit so the test runs faster. revRes.Throttle = time.Tick(time.Millisecond) for ip, names := range tests { test.Poll(t, 100*time.Millisecond, names, func() interface{} { ns, _ := revRes.get(ip) return ns }) } }
func TestWeave(t *testing.T) { weaveClient := &mockWeaveClient{ published: map[string]entry{}, } dockerClient := mockDockerClient{} interfaces := func() ([]app.Interface, error) { return []app.Interface{ { Name: "eth0", Addrs: []net.Addr{ &net.IPAddr{ IP: ip, }, }, }, { Name: "docker0", Addrs: []net.Addr{ &net.IPAddr{ IP: net.ParseIP("4.3.2.1"), }, }, }, }, nil } publisher := app.NewWeavePublisher( weaveClient, dockerClient, interfaces, hostname, containerName) defer publisher.Stop() want := map[string]entry{ hostname: {containerID, ip}, } test.Poll(t, 100*time.Millisecond, want, func() interface{} { weaveClient.Lock() defer weaveClient.Unlock() result := map[string]entry{} for k, v := range weaveClient.published { result[k] = v } return result }) }
func TestProbe(t *testing.T) { // marshalling->unmarshaling is not idempotent due to `json:"omitempty"` // tags, transforming empty slices into nils. So, we make DeepEqual // happy by setting empty `json:"omitempty"` entries to nil const probeID = "probeid" now := time.Now() mtime.NowForce(now) defer mtime.NowReset() want := report.MakeReport() node := report.MakeNodeWith("a", map[string]string{"b": "c"}) node.Metrics = nil // omitempty // omitempty want.Endpoint.Controls = nil want.Process.Controls = nil want.Container.Controls = nil want.ContainerImage.Controls = nil want.Pod.Controls = nil want.Service.Controls = nil want.Deployment.Controls = nil want.ReplicaSet.Controls = nil want.Host.Controls = nil want.Overlay.Controls = nil want.Endpoint.AddNode(node) pub := mockPublisher{make(chan report.Report, 10)} p := New(10*time.Millisecond, 100*time.Millisecond, pub) p.AddReporter(mockReporter{want}) p.Start() defer p.Stop() test.Poll(t, 300*time.Millisecond, want, func() interface{} { return <-pub.have }) }
func TestContainer(t *testing.T) { log.SetOutput(ioutil.Discard) oldDialStub, oldNewClientConnStub := docker.DialStub, docker.NewClientConnStub defer func() { docker.DialStub, docker.NewClientConnStub = oldDialStub, oldNewClientConnStub }() docker.DialStub = func(network, address string) (net.Conn, error) { return nil, nil } reader, writer := io.Pipe() connection := &mockConnection{reader} docker.NewClientConnStub = func(c net.Conn, r *bufio.Reader) docker.ClientConn { return connection } now := time.Unix(12345, 67890).UTC() mtime.NowForce(now) defer mtime.NowReset() const hostID = "scope" c := docker.NewContainer(container1, hostID) err := c.StartGatheringStats() if err != nil { t.Errorf("%v", err) } defer c.StopGatheringStats() // Send some stats to the docker container stats := &client.Stats{} stats.Read = now stats.MemoryStats.Usage = 12345 stats.MemoryStats.Limit = 45678 encoder := codec.NewEncoder(writer, &codec.JsonHandle{}) if err = encoder.Encode(&stats); err != nil { t.Error(err) } // Now see if we go them { uptime := (now.Sub(startTime) / time.Second) * time.Second want := report.MakeNodeWith("ping;<container>", map[string]string{ "docker_container_command": " ", "docker_container_created": "01 Jan 01 00:00 UTC", "docker_container_id": "ping", "docker_container_name": "pong", "docker_image_id": "baz", "docker_label_foo1": "bar1", "docker_label_foo2": "bar2", "docker_container_state": "running", "docker_container_state_human": "Up 6 years", "docker_container_uptime": uptime.String(), }). WithControls( docker.RestartContainer, docker.StopContainer, docker.PauseContainer, docker.AttachContainer, docker.ExecContainer, ).WithMetrics(report.Metrics{ "docker_cpu_total_usage": report.MakeMetric(), "docker_memory_usage": report.MakeMetric().Add(now, 12345).WithMax(45678), }).WithParents(report.EmptySets. Add(report.ContainerImage, report.MakeStringSet(report.MakeContainerImageNodeID("baz"))), ) test.Poll(t, 100*time.Millisecond, want, func() interface{} { node := c.GetNode() node.Latest.ForEach(func(k, v string) { if v == "0" || v == "" { node.Latest = node.Latest.Delete(k) } }) return node }) } { want := report.EmptySets. Add("docker_container_ports", report.MakeStringSet("1.2.3.4:80->80/tcp", "81/tcp")). Add("docker_container_ips", report.MakeStringSet("1.2.3.4")). Add("docker_container_ips_with_scopes", report.MakeStringSet(";1.2.3.4")) test.Poll(t, 100*time.Millisecond, want, func() interface{} { return c.NetworkInfo([]net.IP{}) }) } if c.Image() != "baz" { t.Errorf("%s != baz", c.Image()) } if c.PID() != 2 { t.Errorf("%d != 2", c.PID()) } node := c.GetNode().WithSets(c.NetworkInfo([]net.IP{})) if have := docker.ExtractContainerIPs(node); !reflect.DeepEqual(have, []string{"1.2.3.4"}) { t.Errorf("%v != %v", have, []string{"1.2.3.4"}) } }
func TestConntracker(t *testing.T) { oldExecCmd, oldConntrackPresent := exec.Command, ConntrackModulePresent defer func() { exec.Command, ConntrackModulePresent = oldExecCmd, oldConntrackPresent }() ConntrackModulePresent = func() bool { return true } first := true existingConnectionsReader, existingConnectionsWriter := io.Pipe() reader, writer := io.Pipe() exec.Command = func(name string, args ...string) exec.Cmd { if first { first = false return testexec.NewMockCmd(existingConnectionsReader) } return testexec.NewMockCmd(reader) } flowWalker := newConntrackFlowWalker(true) defer flowWalker.stop() // First write out some empty xml for the existing connections ecbw := bufio.NewWriter(existingConnectionsWriter) if _, err := ecbw.WriteString(xmlHeader); err != nil { t.Fatal(err) } if _, err := ecbw.WriteString(conntrackOpenTag); err != nil { t.Fatal(err) } if _, err := ecbw.WriteString(conntrackCloseTag); err != nil { t.Fatal(err) } if err := ecbw.Flush(); err != nil { t.Fatal(err) } // Then write out eventa bw := bufio.NewWriter(writer) if _, err := bw.WriteString(xmlHeader); err != nil { t.Fatal(err) } if _, err := bw.WriteString(conntrackOpenTag); err != nil { t.Fatal(err) } if err := bw.Flush(); err != nil { t.Fatal(err) } have := func() interface{} { result := []flow{} flowWalker.walkFlows(func(f flow) { f.Original = nil f.Reply = nil f.Independent = nil result = append(result, f) }) return result } ts := 100 * time.Millisecond // First, assert we have no flows test.Poll(t, ts, []flow{}, have) // Now add some flows xmlEncoder := xml.NewEncoder(bw) writeFlow := func(f flow) { if err := xmlEncoder.Encode(f); err != nil { t.Fatal(err) } if _, err := bw.WriteString("\n"); err != nil { t.Fatal(err) } if err := bw.Flush(); err != nil { t.Fatal(err) } } flow1 := makeFlow(updateType) addMeta(&flow1, "original", "1.2.3.4", "2.3.4.5", 2, 3) addIndependant(&flow1, 1, "") writeFlow(flow1) test.Poll(t, ts, []flow{flow1}, have) // Now check when we remove the flow, we still get it in the next Walk flow2 := makeFlow(destroyType) addMeta(&flow2, "original", "1.2.3.4", "2.3.4.5", 2, 3) addIndependant(&flow2, 1, "") writeFlow(flow2) test.Poll(t, ts, []flow{flow1}, have) test.Poll(t, ts, []flow{}, have) // This time we're not going to remove it, but put it in state TIME_WAIT flow1.Type = updateType writeFlow(flow1) test.Poll(t, ts, []flow{flow1}, have) flow1.Metas[1].State = timeWait writeFlow(flow1) test.Poll(t, ts, []flow{flow1}, have) test.Poll(t, ts, []flow{}, have) }
func TestWeaveTaggerOverlayTopology(t *testing.T) { w := overlay.NewWeave(mockHostID, weave.MockClient{}) defer w.Stop() // Wait until the reporter reports some nodes test.Poll(t, 300*time.Millisecond, 1, func() interface{} { have, _ := w.Report() return len(have.Overlay.Nodes) }) { // Overlay node should include peer name and nickname have, err := w.Report() if err != nil { t.Fatal(err) } nodeID := report.MakeOverlayNodeID(weave.MockWeavePeerName) node, ok := have.Overlay.Nodes[nodeID] if !ok { t.Errorf("Expected overlay node %q, but not found", nodeID) } if peerName, ok := node.Latest.Lookup(overlay.WeavePeerName); !ok || peerName != weave.MockWeavePeerName { t.Errorf("Expected weave peer name %q, got %q", weave.MockWeavePeerName, peerName) } if peerNick, ok := node.Latest.Lookup(overlay.WeavePeerNickName); !ok || peerNick != weave.MockWeavePeerNickName { t.Errorf("Expected weave peer nickname %q, got %q", weave.MockWeavePeerNickName, peerNick) } if localNetworks, ok := node.Sets.Lookup(host.LocalNetworks); !ok || !reflect.DeepEqual(localNetworks, report.MakeStringSet(weave.MockWeaveDefaultSubnet)) { t.Errorf("Expected weave node local_networks %q, got %q", report.MakeStringSet(weave.MockWeaveDefaultSubnet), localNetworks) } } { // Container nodes should be tagged with their overlay info nodeID := report.MakeContainerNodeID(weave.MockContainerID) have, err := w.Tag(report.Report{ Container: report.MakeTopology().AddNode(report.MakeNodeWith(nodeID, map[string]string{ docker.ContainerID: weave.MockContainerID, })), }) if err != nil { t.Fatal(err) } node, ok := have.Container.Nodes[nodeID] if !ok { t.Errorf("Expected container node %q, but not found", nodeID) } // Should have Weave DNS Hostname if have, ok := node.Latest.Lookup(overlay.WeaveDNSHostname); !ok || have != weave.MockHostname { t.Errorf("Expected weave dns hostname %q, got %q", weave.MockHostname, have) } // Should have Weave MAC Address if have, ok := node.Latest.Lookup(overlay.WeaveMACAddress); !ok || have != weave.MockContainerMAC { t.Errorf("Expected weave mac address %q, got %q", weave.MockContainerMAC, have) } // Should have Weave container ip if have, ok := node.Sets.Lookup(docker.ContainerIPs); !ok || !have.Contains(weave.MockContainerIP) { t.Errorf("Expected container ips to include the weave IP %q, got %q", weave.MockContainerIP, have) } // Should have Weave container ip (with scope) if have, ok := node.Sets.Lookup(docker.ContainerIPsWithScopes); !ok || !have.Contains(mockContainerIPWithScope) { t.Errorf("Expected container ips to include the weave IP (with scope) %q, got %q", mockContainerIPWithScope, have) } } }
func TestPipeClose(t *testing.T) { router := mux.NewRouter() pr := NewLocalPipeRouter() RegisterPipeRoutes(router, pr) defer pr.Stop() server := httptest.NewServer(router) defer server.Close() ip, port, err := net.SplitHostPort(strings.TrimPrefix(server.URL, "http://")) if err != nil { t.Fatal(err) } probeConfig := appclient.ProbeConfig{ ProbeID: "foo", } client, err := appclient.NewAppClient(probeConfig, ip+":"+port, ip+":"+port, nil) if err != nil { t.Fatal(err) } defer client.Stop() // this is the probe end of the pipe pipeID, pipe, err := controls.NewPipe(adapter{client}, "appid") if err != nil { t.Fatal(err) } // this is a client to the app pipeURL := fmt.Sprintf("ws://%s:%s/api/pipe/%s", ip, port, pipeID) conn, _, err := websocket.DefaultDialer.Dial(pipeURL, http.Header{}) if err != nil { t.Fatal(err) } // Send something from pipe -> app -> conn local, _ := pipe.Ends() msg := []byte("hello world") if _, err := local.Write(msg); err != nil { t.Fatal(err) } if _, buf, err := conn.ReadMessage(); err != nil { t.Fatal(err) } else if !bytes.Equal(buf, msg) { t.Fatalf("%v != %v", buf, msg) } // Send something from conn -> app -> probe msg = []byte("goodbye, cruel world") if err := conn.WriteMessage(websocket.BinaryMessage, msg); err != nil { t.Fatal(err) } buf := make([]byte, 1024) if n, err := local.Read(buf); err != nil { t.Fatal(err) } else if !bytes.Equal(msg, buf[:n]) { t.Fatalf("%v != %v", buf, msg) } // Now delete the pipe if err := pipe.Close(); err != nil { t.Fatal(err) } // the client backs off for 1 second before trying to reconnect the pipe, // so we need to wait for longer. test.Poll(t, 2*time.Second, true, func() interface{} { return pipe.Closed() }) }