func TestDockerShareNamespace(t *testing.T) {
	g := helper.NewGraph(t)

	agent := helper.StartAgentWithConfig(t, confTopology)
	defer agent.Stop()

	setupCmds := []helper.Cmd{
		{"docker run -d -t -i --name test-skydive-docker busybox", false},
		{"docker run -d -t -i --name test-skydive-docker2 --net=container:test-skydive-docker busybox", false},
	}

	tearDownCmds := []helper.Cmd{
		{"docker rm -f test-skydive-docker", false},
		{"docker rm -f test-skydive-docker2", false},
	}

	tr := traversal.NewGraphTraversal(g)

	testPassed := false
	onChange := func(ws *websocket.Conn) {
		g.Lock()
		defer g.Unlock()

		if !testPassed {
			tv := tr.V().Has("Type", "netns", "Manager", "docker")
			logging.GetLogger().Warningf("Looking for docker namespace: %+v (%d)\n", tv.Values(), len(tv.Values()))

			if len(tv.Values()) > 1 {
				t.Error("There should be only one namespace managed by Docker")
				ws.Close()
			} else if len(tv.Values()) == 1 {
				tv = tv.Out().Has("Type", "container", "Docker/ContainerName", traversal.Within("/test-skydive-docker", "/test-skydive-docker2"))
				logging.GetLogger().Warningf("Found namespace, looking for containers: %+v (%d)\n", tv.Values(), len(tv.Values()))

				if len(tv.Values()) == 2 {
					testPassed = true
					ws.Close()
				}
			}
		}
	}

	testTopology(t, g, setupCmds, onChange)
	if !testPassed {
		t.Error("test not executed or failed")
	}

	testCleanup(t, g, tearDownCmds, []string{"test-skydive-docker"})
}
func TestPatchOVS(t *testing.T) {
	g := helper.NewGraph(t)

	agent := helper.StartAgentWithConfig(t, confTopology)
	defer agent.Stop()

	setupCmds := []helper.Cmd{
		{"ovs-vsctl add-br br-test1", true},
		{"ovs-vsctl add-br br-test2", true},
		{"ovs-vsctl add-port br-test1 patch-br-test2 -- set interface patch-br-test2 type=patch", true},
		{"ovs-vsctl add-port br-test2 patch-br-test1 -- set interface patch-br-test1 type=patch", true},
		{"ovs-vsctl set interface patch-br-test2 option:peer=patch-br-test1", true},
		{"ovs-vsctl set interface patch-br-test1 option:peer=patch-br-test2", true},
	}

	tearDownCmds := []helper.Cmd{
		{"ovs-vsctl del-br br-test1", true},
		{"ovs-vsctl del-br br-test2", true},
	}

	tr := traversal.NewGraphTraversal(g)

	testPassed := false
	onChange := func(ws *websocket.Conn) {
		g.Lock()
		defer g.Unlock()

		if !testPassed {
			tv := tr.V().Has("Type", "patch", "Name", "patch-br-test1", "Driver", "openvswitch")
			tv = tv.Both("Type", "patch", "Name", "patch-br-test2", "Driver", "openvswitch")

			if len(tv.Values()) == 1 {
				testPassed = true
				ws.Close()
			}
		}
	}

	testTopology(t, g, setupCmds, onChange)
	if !testPassed {
		t.Error("test not executed or failed")
	}

	testCleanup(t, g, tearDownCmds, []string{"br-test1", "br-test2", "patch-br-test1", "patch-br-test2"})
}
func TestBondOVS(t *testing.T) {
	g := helper.NewGraph(t)

	agent := helper.StartAgentWithConfig(t, confTopology)
	defer agent.Stop()

	setupCmds := []helper.Cmd{
		{"ovs-vsctl add-br br-test1", true},
		{"ip tuntap add mode tap dev intf1", true},
		{"ip tuntap add mode tap dev intf2", true},
		{"ovs-vsctl add-bond br-test1 bond0 intf1 intf2", true},
	}

	tearDownCmds := []helper.Cmd{
		{"ovs-vsctl del-br br-test1", true},
		{"ip link del intf1", true},
		{"ip link del intf2", true},
	}

	tr := traversal.NewGraphTraversal(g)

	testPassed := false
	onChange := func(ws *websocket.Conn) {
		g.Lock()
		defer g.Unlock()

		if !testPassed {
			tv := tr.V().Has("Type", "ovsport", "Name", "bond0")
			tv = tv.Out()

			if len(tv.Values()) == 2 {
				testPassed = true
				ws.Close()
			}
		}
	}

	testTopology(t, g, setupCmds, onChange)
	if !testPassed {
		t.Error("test not executed or failed")
	}

	testCleanup(t, g, tearDownCmds, []string{"br-test1", "intf1", "intf2"})
}
func TestDockerNetHost(t *testing.T) {
	g := helper.NewGraph(t)

	agent := helper.StartAgentWithConfig(t, confTopology)
	defer agent.Stop()

	setupCmds := []helper.Cmd{
		{"docker run -d -t -i --net=host --name test-skydive-docker busybox", false},
	}

	tearDownCmds := []helper.Cmd{
		{"docker rm -f test-skydive-docker", false},
	}

	tr := traversal.NewGraphTraversal(g)

	testPassed := false
	onChange := func(ws *websocket.Conn) {
		g.Lock()
		defer g.Unlock()

		if !testPassed {
			tv := tr.V().Has("Docker/ContainerName", "/test-skydive-docker", "Type", "container")

			if len(tv.Values()) == 1 {
				tv = tr.V().Has("Type", "netns", "Manager", "docker", "Name", "test-skydive-docker")
				if len(tv.Values()) == 1 {
					t.Error("There should be only no namespace managed by Docker")
				} else {
					testPassed = true
				}
				ws.Close()
			}
		}
	}

	testTopology(t, g, setupCmds, onChange)
	if !testPassed {
		t.Error("test not executed or failed")
	}

	testCleanup(t, g, tearDownCmds, []string{"test-skydive-docker"})
}
func TestNameSpaceOVSInterface(t *testing.T) {
	g := helper.NewGraph(t)

	agent := helper.StartAgentWithConfig(t, confTopology)
	defer agent.Stop()

	setupCmds := []helper.Cmd{
		{"ip netns add ns1", true},
		{"ovs-vsctl add-br br-test1", true},
		{"ovs-vsctl add-port br-test1 intf1 -- set interface intf1 type=internal", true},
		{"ip l set intf1 netns ns1", true},
	}

	tearDownCmds := []helper.Cmd{
		{"ovs-vsctl del-br br-test1", true},
		{"ip netns del ns1", true},
	}

	tr := traversal.NewGraphTraversal(g)

	testPassed := false
	onChange := func(ws *websocket.Conn) {
		g.Lock()
		defer g.Unlock()

		if !testPassed {
			tv := tr.V().Has("Name", "ns1", "Type", "netns")
			tv = tv.Out("Name", "intf1", "Type", "internal")

			if len(tv.Values()) == 1 && len(tr.V().Has("Name", "intf1", "Type", "internal").Values()) == 1 {
				testPassed = true
				ws.Close()
			}
		}
	}

	testTopology(t, g, setupCmds, onChange)
	if !testPassed {
		t.Error("test not executed or failed")
	}

	testCleanup(t, g, tearDownCmds, []string{"ns1", "br-test1"})
}
func TestNameSpaceVeth(t *testing.T) {
	g := helper.NewGraph(t)

	agent := helper.StartAgentWithConfig(t, confTopology)
	defer agent.Stop()

	setupCmds := []helper.Cmd{
		{"ip netns add ns1", true},
		{"ip l add vm1-veth0 type veth peer name vm1-veth1 netns ns1", true},
	}

	tearDownCmds := []helper.Cmd{
		{"ip link del vm1-veth0", true},
		{"ip netns del ns1", true},
	}

	tr := traversal.NewGraphTraversal(g)

	testPassed := false
	onChange := func(ws *websocket.Conn) {
		g.Lock()
		defer g.Unlock()

		if !testPassed {
			tv := tr.V().Has("Name", "ns1", "Type", "netns")
			tv = tv.Out("Name", "vm1-veth1", "Type", "veth")

			if len(tv.Values()) == 1 {
				testPassed = true
				ws.Close()
			}
		}
	}

	testTopology(t, g, setupCmds, onChange)
	if !testPassed {
		t.Error("test not executed or failed")
	}

	testCleanup(t, g, tearDownCmds, []string{"ns1", "vm1-veth0"})
}
func TestMacNameUpdate(t *testing.T) {
	g := helper.NewGraph(t)

	agent := helper.StartAgentWithConfig(t, confTopology)
	defer agent.Stop()

	setupCmds := []helper.Cmd{
		{"ip l add vm1-veth0 type veth peer name vm1-veth1", true},
		{"ip l set vm1-veth1 name vm1-veth2", true},
		{"ip l set vm1-veth2 address 00:00:00:00:00:aa", true},
	}

	tearDownCmds := []helper.Cmd{
		{"ip link del vm1-veth0", true},
	}

	tr := traversal.NewGraphTraversal(g)

	testPassed := false
	onChange := func(ws *websocket.Conn) {
		g.Lock()
		defer g.Unlock()

		if !testPassed {
			tv := tr.V().Has("Name", "vm1-veth2", "MAC", "00:00:00:00:00:aa")

			if len(tv.Values()) == 1 && len(tr.V().Has("Name", "vm1-veth1").Values()) == 0 {
				testPassed = true
				ws.Close()
			}
		}
	}

	testTopology(t, g, setupCmds, onChange)
	if !testPassed {
		t.Error("test not executed or failed")
	}

	testCleanup(t, g, tearDownCmds, []string{"vm1-veth0", "vm1-veth1", "vm1-veth2"})
}