func TestJoin(t *testing.T) {

	cfg1 := config.New(true, map[string]string{})
	cfg1.AddOrSetUserTag("tag", "1")
	cfg2 := config.New(false, map[string]string{})
	cfg2.AddOrSetUserTag("tag", "2")

	p1 := 666
	p2 := 667

	t1, err := New("127.0.0.1", p1, cfg1)

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

	t2, err := New("127.0.0.1", p2, cfg2)

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

	c1 := t1.Join().AsChan()
	c2 := t2.Join().AsChan()

	t2.JoinCluster([]string{fmt.Sprintf("%s:%d", "127.0.0.1", t1.Port())})

	select {
	case <-time.After(10 * time.Second):
		t.Fatal("Couldnt find tracker 2")
	case n := <-c1:

		if n.UUID() != cfg2.UUID() {
			t.Error("Found wrong UUID", n.UUID().FullString(), cfg2.UUID().FullString())
		}

		if n.Node.Meta[0] != service.PROTOCOLL_SIGNATURE || !bytes.Equal(n.Node.Meta[1:3], port2byte(p2)) || n.Node.Meta[3] != 0 || string(n.Node.Meta[4:]) != "tag:2" {
			t.Error("Wrong Meta")
		}
	}

	select {
	case <-time.After(10 * time.Second):
		t.Fatal("Couldnt find tracker 1")
	case n := <-c2:
		if n.UUID() != cfg1.UUID() {
			t.Error("Found wrong UUID", n.UUID().FullString(), cfg2.UUID().FullString())
		}

		if n.Node.Meta[0] != service.PROTOCOLL_SIGNATURE || !bytes.Equal(n.Node.Meta[1:3], port2byte(p1)) || n.Node.Meta[3] != 1 || string(n.Node.Meta[4:]) != "tag:1" {
			t.Error("Wrong Meta", n.Node.Meta)
		}
	}
}
func TestInitConnection(t *testing.T) {

	i1, err := connection.NewIncoming("127.0.0.1")
	if err != nil {
		t.Fatal(err)
	}

	i2, err := connection.NewIncoming("127.0.0.1")
	if err != nil {
		t.Fatal(err)
	}

	cfg1 := config.New(true, map[string]string{})
	cfg2 := config.New(false, map[string]string{})

	c := i2.MessagesFromSender(cfg1.UUID()).Where(messages.Is(messages.HELLO)).AsChan()

	p1, err := New(cfg2.UUID(), "127.0.0.1", i2.Port(), i1, cfg1)
	if err != nil {
		t.Fatal(err)
	}
	p1.InitConnection()

	var p2 *Peer
	select {
	case <-time.After(5 * time.Second):
		t.Fatal("Did not received Hello")
	case d := <-c:
		m := d.(*messages.Hello)
		if m.Address != i1.Addr() || m.Port != i1.Port() {
			t.Fatal("Wrong message", m)
		}
		p2, err = NewFromHello(m, i2, cfg2)
		if err != nil {
			t.Fatal(err)
		}
	}

	time.Sleep(5 * time.Second)

	if !p1.initialized.Completed() {
		t.Error("Connection 1 did not initialize")
	}
	if !p2.initialized.Completed() {
		t.Error("Connection 2 did not initialize")
	}

}
func getTestManager(e bool) (m *Manager) {
	cfg := config.New(e, map[string]string{})
	cfg.AddOrSetUserTag("tag1", "1")
	cfg.OverrideInterfaces([]string{"127.0.0.1"})

	m, _ = New(cfg)
	return
}
func TestAutoJoin(t *testing.T) {

	cfg1 := config.New(true, map[string]string{})
	cfg1.AddOrSetUserTag("tag", "1")
	cfg2 := config.New(false, map[string]string{})
	cfg2.AddOrSetUserTag("tag", "2")

	t1, err := New("127.0.0.1", 0, cfg1)
	if err != nil {
		t.Fatal(err)
	}

	t2, err := New("127.0.0.1", 0, cfg2)
	if err != nil {
		t.Fatal(err)
	}

	c1 := t1.Join().AsChan()
	c2 := t2.Join().AsChan()

	err = t1.StartAutoJoin()
	if err != nil {
		t.Fatal(err)
	}

	err = t2.StartAutoJoin()
	if err != nil {
		t.Fatal(err)
	}

	select {
	case <-time.After(10 * time.Second):
		t.Fatal("Couldnt find tracker 2")
	case <-c1:
	}

	select {
	case <-time.After(10 * time.Second):
		t.Fatal("Couldnt find tracker 1")
	case <-c2:
	}
}
func TestNotConnecting(t *testing.T) {

	i1, err := connection.NewIncoming("127.0.0.1")
	if err != nil {
		t.Fatal(err)
	}

	i2, err := connection.NewIncoming("127.0.0.1")
	if err != nil {
		t.Fatal(err)
	}

	cfg1 := config.New(true, map[string]string{})
	cfg1.AddOrSetUserTag("tag1", "1")
	cfg1.AddOrSetUserTag("tag2", "2")
	cfg2 := config.New(false, map[string]string{})
	cfg2.AddOrSetUserTag("tag2", "2")
	cfg2.AddOrSetUserTag("tag1", "2")

	p1, err := New(cfg2.UUID(), "127.0.0.1", i2.Port(), i1, cfg1)
	if err != nil {
		t.Fatal(err)
	}

	p2, err := NewFromHello(&messages.Hello{string(cfg1.UUID()), "127.0.0.1", i1.Port()}, i2, cfg2)
	if err != nil {
		t.Fatal(err)
	}
	p2.Check()
	time.Sleep(5 * time.Second)

	if p1.Connected().Completed() {
		t.Error("Connection 1 did initialize")
	}
	if p2.Connected().Completed() {
		t.Error("Connection 2 did initialize")
	}

}
func testConfig(export bool) (cfg *config.Config) {
	cfg = config.New(export, testDescriptor.AsTagSet())
	return
}
func TestManagerMessaging(t *testing.T) {
	cfg1 := config.New(true, map[string]string{})
	cfg1.OverrideUUID("exp")
	cfg1.AddOrSetUserTag("tag1", "1")
	cfg1.OverrideInterfaces([]string{"127.0.0.1"})

	cfg2 := config.New(false, map[string]string{})
	cfg2.OverrideUUID("imp1")
	cfg2.AddOrSetUserTag("tag1", "1")
	cfg2.OverrideInterfaces([]string{"127.0.0.1"})

	cfg3 := config.New(false, map[string]string{})
	cfg3.OverrideUUID("imp2")
	cfg3.AddOrSetUserTag("tag1", "1")
	cfg3.OverrideInterfaces([]string{"127.0.0.1"})

	m1, err := New(cfg1)
	if err != nil {
		t.Fatal(err)
	}
	defer m1.Shutdown()
	c1 := m1.Messages().Transform(connection.ToMessage).AsChan()

	m2, err := New(cfg2)
	if err != nil {
		t.Fatal(err)
	}
	defer m2.Shutdown()
	c2 := m2.Messages().Transform(connection.ToMessage).AsChan()

	m3, err := New(cfg3)
	if err != nil {
		t.Fatal(err)
	}
	defer m3.Shutdown()
	c3 := m3.Messages().Transform(connection.ToMessage).AsChan()

	m1.Run()
	f := m2.Connected().First()
	m2.Run()
	f.WaitUntilComplete()
	f = m3.Connected().First()
	m3.Run()
	f.WaitUntilComplete()
	msg := &messages.Mock{true}
	m2.Send(msg)

	if r := (<-c1).(*messages.Mock); r.Data != msg.Data {
		t.Error("peer1 did not not got the message", r)
	}
	time.Sleep(10 * time.Millisecond)
	m1.SendTo(cfg3.UUID(), msg)
	if r := (<-c3).(*messages.Mock); r.Data != msg.Data {
		t.Error("peer3 did not not got the message", r)
	}

	m1.SendToAll(msg)
	if r := (<-c2).(*messages.Mock); r.Data != msg.Data {
		t.Error("peer2 did not not got the message", r)
	}
	if r := (<-c3).(*messages.Mock); r.Data != msg.Data {
		t.Error("peer3 did not not got the message", r)
	}
}
func TestManagerConnection(t *testing.T) {

	cfg1 := config.New(true, map[string]string{})
	cfg1.OverrideUUID("exp")
	cfg1.AddOrSetUserTag("tag1", "1")
	cfg1.AddOrSetUserTag("tag2", "2")
	cfg1.OverrideInterfaces([]string{"127.0.0.1"})

	cfg2 := config.New(false, map[string]string{})
	cfg2.OverrideUUID("imp1")
	cfg2.AddOrSetUserTag("tag2", "2")
	cfg2.OverrideInterfaces([]string{"127.0.0.1"})

	cfg3 := config.New(false, map[string]string{})
	cfg3.OverrideUUID("imp2")
	cfg3.AddOrSetUserTag("tag1", "1")
	cfg3.OverrideInterfaces([]string{"127.0.0.1"})

	m1, err := New(cfg1)
	if err != nil {
		t.Fatal(err)
	}
	defer m1.Shutdown()

	m2, err := New(cfg2)
	if err != nil {
		t.Fatal(err)
	}
	defer m2.Shutdown()
	c2 := m2.Connected().First().AsChan()

	m3, err := New(cfg3)
	if err != nil {
		t.Fatal(err)
	}
	defer m3.Shutdown()
	c3 := m3.Connected().First().AsChan()

	m1.Run()
	m2.Run()
	m3.Run()

	select {
	case <-time.After(10 * time.Second):
		t.Error("peer2 did not connect", cfg2.UUID())
	case <-c2:
		if len(m2.peers) != 1 {
			t.Error("Not all peers connected to peer 2, want 1 got", len(m2.peers))
		}
	}

	select {
	case <-time.After(10 * time.Second):
		t.Error("peer3 did not connect", cfg3.UUID())
	case <-c3:
		if len(m3.peers) != 1 {
			t.Error("Not all peers connected to peer 3, want 1 got", len(m2.peers))
		}
	}

	time.Sleep(10 * time.Second)
	if len(m1.peers) != 2 {
		t.Error("Not all peers connected to peer 1, want 2 got", len(m1.peers))
	}
}
func TestLeaveAndReconnect(t *testing.T) {

	cfg1 := config.New(true, map[string]string{})
	cfg1.AddOrSetUserTag("tag", "1")
	cfg2 := config.New(false, map[string]string{})
	cfg2.AddOrSetUserTag("tag", "2")

	t1, err := New("127.0.0.1", 0, cfg1)
	if err != nil {
		t.Fatal(err)
	}

	t2, err := New("127.0.0.1", 0, cfg2)
	if err != nil {
		t.Fatal(err)
	}

	c1 := t1.Join().AsChan()
	c2 := t1.Leave().First().AsChan()

	err = t1.StartAutoJoin()
	if err != nil {
		t.Fatal(err)
	}

	err = t2.StartAutoJoin()
	if err != nil {
		t.Fatal(err)
	}

	select {
	case <-time.After(5 * time.Second):
		t.Fatal("Service didnt join")
	case <-c1:
	}

	t2.Shutdown(nil)

	select {
	case <-time.After(5 * time.Second):
		t.Fatal("Service didnt leave")
	case <-c2:
	}

	cfg3 := config.New(false, map[string]string{})
	cfg3.AddOrSetUserTag("tag", "2")

	t3, err := New("127.0.0.1", 0, cfg3)
	if err != nil {
		t.Fatal(err)
	}

	err = t3.StartAutoJoin()
	if err != nil {
		t.Fatal(err)
	}
	select {
	case <-time.After(10 * time.Second):
		t.Fatal("Service didnt join")
	case <-c1:
	}

}