Skip to content
quarry Artifact [1c9a28c318]
Login

Artifact [1c9a28c318]

Artifact 1c9a28c31836572324592a0347d47579fb6c1fef2a8aa25f0e96e18449cfd1e8:


package chat

import (
	"reflect"
	"testing"
	"time"

	"craftdesign.group/quarry/internal/events"
)

// Presence is an open stream and nothing else: joining puts you in the
// room at once, leaving takes you out at once, and the two are visible
// to every instance on the bus — which here is one instance with two
// Presence values, the shape two servers behind a balancer would have.
func TestPresenceIsSharedAndImmediate(t *testing.T) {
	ev, err := events.Start(t.TempDir())
	if err != nil {
		t.Fatal(err)
	}
	defer ev.Close()
	a, err := NewPresence(ev.Conn())
	if err != nil {
		t.Fatal(err)
	}
	defer a.Close()
	b, err := NewPresence(ev.Conn())
	if err != nil {
		t.Fatal(err)
	}
	defer b.Close()

	tick, stop := b.Changed("A")
	defer stop()

	leave := a.Join("A", "dan")
	waitTick(t, tick, "dan's arrival")
	if got := b.Present("A"); !reflect.DeepEqual(got, []string{"dan"}) {
		t.Fatalf("the other instance sees %v, want [dan]", got)
	}
	// Another channel is another room.
	if got := b.Present("B"); len(got) != 0 {
		t.Fatalf("B sees A's reader: %v", got)
	}

	leave2 := a.Join("A", "eve")
	waitTick(t, tick, "eve's arrival")
	if got := b.Present("A"); !reflect.DeepEqual(got, []string{"dan", "eve"}) {
		t.Fatalf("after two joins %v, want [dan eve] (sorted)", got)
	}

	leave()
	waitTick(t, tick, "dan's departure")
	if got := b.Present("A"); !reflect.DeepEqual(got, []string{"eve"}) {
		t.Fatalf("after dan left %v, want [eve]", got)
	}
	leave2()
	// A second leave is a no-op, not a second goodbye.
	leave2()
	waitTick(t, tick, "eve's departure")
	if got := b.Present("A"); len(got) != 0 {
		t.Fatalf("after everybody left %v, want empty", got)
	}
}

// Nobody signed in joins nowhere: an anonymous stream must not put an
// empty name in the room.
func TestPresenceIgnoresAnonymous(t *testing.T) {
	ev, err := events.Start(t.TempDir())
	if err != nil {
		t.Fatal(err)
	}
	defer ev.Close()
	p, err := NewPresence(ev.Conn())
	if err != nil {
		t.Fatal(err)
	}
	defer p.Close()
	leave := p.Join("A", "")
	leave()
	time.Sleep(100 * time.Millisecond)
	if got := p.Present("A"); len(got) != 0 {
		t.Fatalf("an anonymous join was recorded: %v", got)
	}
}

func waitTick(t *testing.T, tick <-chan struct{}, what string) {
	t.Helper()
	select {
	case <-tick:
	case <-time.After(3 * time.Second):
		t.Fatalf("no change notified for %s", what)
	}
}