diff --git a/draftbot/draftbot_test.go b/draftbot/draftbot_test.go index c8dd6a6..ea0f268 100644 --- a/draftbot/draftbot_test.go +++ b/draftbot/draftbot_test.go @@ -4,28 +4,33 @@ import ( "testing" "time" + "git.fromouter.space/mcg/draft" "git.fromouter.space/mcg/draft/mlp" "git.fromouter.space/mcg/cardgage/client/bot" lobby "git.fromouter.space/mcg/cardgage/lobby/proto" room "git.fromouter.space/mcg/cardgage/room/api" - draft "git.fromouter.space/mcg/mlp-server-tools/draftbot" + draftbot "git.fromouter.space/mcg/mlp-server-tools/draftbot" ) const TestBotName = "test-bot" const TestRoomName = "test-room" type MockServer struct { - in chan room.ServerMessage - out chan room.BotMessage + in chan room.ServerMessage + out chan room.BotMessage + t *testing.T + timeout time.Duration } -func makeMockServer() *MockServer { +func makeMockServer(t *testing.T, timeout int) *MockServer { in := make(chan room.ServerMessage, 99) out := make(chan room.BotMessage, 99) srv := &MockServer{ - in: in, - out: out, + in: in, + out: out, + t: t, + timeout: time.Duration(timeout) * time.Second, } return srv } @@ -41,9 +46,9 @@ func (m *MockServer) Bind(fn bot.MessageHandler) { } func TestDraftSession(t *testing.T) { - mock := makeMockServer() - draftbot := draft.NewDraftBot(mock, TestBotName) - go mock.Bind(draftbot.OnMessage) + mock := makeMockServer(t, 5) + drafter := draftbot.NewDraftBot(mock, TestBotName) + go mock.Bind(drafter.OnMessage) // Create a new room mock.in <- room.ServerMessage{ @@ -60,33 +65,49 @@ func TestDraftSession(t *testing.T) { } // Create new session with a fake message from owner - mock.message("test-owner", "create", draft.SessionOptions{ + mock.message("test-owner", "create", draftbot.SessionOptions{ Players: 8, // Two players, six bots - Options: draft.DraftOptions{ - Type: draft.DraftSet, - Positioning: draft.PosEven, + Options: draftbot.DraftOptions{ + Type: draftbot.DraftSet, + Positioning: draftbot.PosEven, Set: mlp.SetAbsoluteDiscord, PackCount: 4, }, }) - mock.expect(t, "session-open", 5) + mock.expect("session-open") // Join session as owner mock.message("test-owner", "join", nil) - mock.expect(t, "player-joined-session", 5) + mock.expect("player-joined-session") // .. and as second player mock.message("test-guest", "join", nil) - mock.expect(t, "player-joined-session", 5) + mock.expect("player-joined-session") // Try to start the session mock.message("test-owner", "start", nil) // These two can happen in any order, so they get their own special check - mock.multiexpect(t, 5, "session-start", "draft-order") + mock.multiexpect("session-start", "draft-order") - //TODO make players pick cards etc + // Pick card for each player + for packi := 0; packi < 4; packi++ { + mock.expect("draft-newpack") + for cardi := 0; cardi < 12; cardi++ { + // Get packs + msg1 := mock.expect("draft-newpick") + pack1 := msg1.Data.(draft.Pack) + msg2 := mock.expect("draft-newpick") + pack2 := msg2.Data.(draft.Pack) + // Pick first card in each pack + mock.message(msg1.To, "pick", pack1[0].ID) + mock.message(msg2.To, "pick", pack2[0].ID) + // Intercept picked events + mock.multiexpect("card-picked", "card-picked") + } + } + mock.expect("draft-finish") // Close the room mock.in <- room.ServerMessage{ @@ -99,9 +120,9 @@ func TestDraftSession(t *testing.T) { } func TestDraftSessionButEverythingGoesWrong(t *testing.T) { - mock := makeMockServer() - draftbot := draft.NewDraftBot(mock, TestBotName) - go mock.Bind(draftbot.OnMessage) + mock := makeMockServer(t, 5) + drafter := draftbot.NewDraftBot(mock, TestBotName) + go mock.Bind(drafter.OnMessage) // Create a new room mock.in <- room.ServerMessage{ @@ -117,80 +138,80 @@ func TestDraftSessionButEverythingGoesWrong(t *testing.T) { } // Try creating a new session as NOT the owner - mock.message("test-guest", "create", draft.SessionOptions{ + mock.message("test-guest", "create", draftbot.SessionOptions{ Players: 8, - Options: draft.DraftOptions{ - Type: draft.DraftSet, - Positioning: draft.PosEven, + Options: draftbot.DraftOptions{ + Type: draftbot.DraftSet, + Positioning: draftbot.PosEven, Set: mlp.SetAbsoluteDiscord, PackCount: 4, }, }) - mock.expect(t, "must-be-owner", 5) + mock.expect("must-be-owner") // Try creating a session with an invalid type - mock.message("test-owner", "create", draft.SessionOptions{ + mock.message("test-owner", "create", draftbot.SessionOptions{ Players: 8, - Options: draft.DraftOptions{ + Options: draftbot.DraftOptions{ Type: "lolwhat", }, }) - mock.expect(t, "session-create-error", 5) + mock.expect("session-create-error") // Try creating a session with invalid data mock.message("test-owner", "create", 42) - mock.expect(t, "invalid-data", 5) + mock.expect("invalid-data") // Try starting a session that doesn't exist mock.message("test-owner", "start", nil) - mock.expect(t, "command-unavailable", 5) + mock.expect("command-unavailable") // Try creating the session twice - mock.message("test-owner", "create", draft.SessionOptions{ + mock.message("test-owner", "create", draftbot.SessionOptions{ Players: 2, - Options: draft.DraftOptions{ - Type: draft.DraftSet, - Positioning: draft.PosEven, + Options: draftbot.DraftOptions{ + Type: draftbot.DraftSet, + Positioning: draftbot.PosEven, Set: mlp.SetAbsoluteDiscord, PackCount: 4, }, }) - mock.expect(t, "session-open", 5) + mock.expect("session-open") - mock.message("test-owner", "create", draft.SessionOptions{ + mock.message("test-owner", "create", draftbot.SessionOptions{ Players: 2, - Options: draft.DraftOptions{ - Type: draft.DraftSet, - Positioning: draft.PosEven, + Options: draftbot.DraftOptions{ + Type: draftbot.DraftSet, + Positioning: draftbot.PosEven, Set: mlp.SetAbsoluteDiscord, PackCount: 4, }, }) - mock.expect(t, "command-unavailable", 5) + mock.expect("command-unavailable") // Try to start session when no-one has joined mock.message("test-owner", "start", nil) - mock.expect(t, "session-start-error", 5) + mock.expect("session-start-error") // Try to make too many players join mock.message("a", "join", nil) - mock.expect(t, "player-joined-session", 5) + mock.expect("player-joined-session") mock.message("b", "join", nil) - mock.expect(t, "player-joined-session", 5) + mock.expect("player-joined-session") mock.message("c", "join", nil) - mock.expect(t, "session-full", 5) + mock.expect("session-full") // Try to make someone join a session that already started mock.message("test-owner", "start", nil) - mock.multiexpect(t, 5, "session-start", "draft-order") + mock.multiexpect("session-start", "draft-order", "draft-newpack", "draft-newpick", "draft-newpick") mock.message("c", "join", nil) - mock.expect(t, "session-already-started", 5) + mock.expect("session-already-started") //TODO More picking, etc shenanigans } -func (m *MockServer) expect(t *testing.T, typ string, timeout int) { +func (m *MockServer) expect(typ string) *room.Message { for { select { case msg := <-m.out: @@ -202,27 +223,31 @@ func (m *MockServer) expect(t *testing.T, typ string, timeout int) { // Check expected type if msg.Message.Type != typ { // Oh noes - t.Fatalf("Expected message \"%s\" but got \"%s\"", typ, msg.Message.Type) + m.t.Fatalf("Expected message \"%s\" but got \"%s\"", typ, msg.Message.Type) } - return - case <-time.After(time.Duration(timeout) * time.Second): - t.Fatalf("Expected message \"%s\" but found nothing (timeout after %d seconds)!", typ, timeout) + return msg.Message + case <-time.After(m.timeout): + m.t.Fatalf("Expected message \"%s\" but found nothing (timeout)!", typ) + return nil } } } -func (m *MockServer) multiexpect(t *testing.T, timeout int, types ...string) { +func (m *MockServer) multiexpect(types ...string) { for { if len(types) < 1 { return } select { case msg := <-m.out: + // Skip all actions if msg.Type != room.MsgMessage { continue } + m.t.Logf("-> [%s] %s", msg.Message.Type, msg.Message.Message) + // Check expected type found := false for i, typ := range types { @@ -235,15 +260,16 @@ func (m *MockServer) multiexpect(t *testing.T, timeout int, types ...string) { } if !found { // Oh noes - t.Fatalf("Expected one of %s but got \"%s\"", types, msg.Message.Type) + m.t.Fatalf("Expected one of %s but got \"%s\"", types, msg.Message.Type) } - case <-time.After(time.Duration(timeout) * time.Second): - t.Fatalf("Expected one of %s but found nothing (timeout after %d seconds)!", types, timeout) + case <-time.After(m.timeout): + m.t.Fatalf("Expected one of %s but found nothing (timeout)!", types) } } } func (m *MockServer) message(from string, typ string, data interface{}) { + m.t.Logf("<- <%s> %s (%v)", from, typ, data) m.in <- room.ServerMessage{ RoomID: TestRoomName, Type: room.MsgMessage, diff --git a/draftbot/session.go b/draftbot/session.go index 51841ea..9eb85e4 100644 --- a/draftbot/session.go +++ b/draftbot/session.go @@ -231,15 +231,20 @@ func (s *session) handlePicks() { bot.PickNext() } // Tell every players their new cards - for _, player := range s.Players { + for pname, player := range s.Players { s.messages <- room.Message{ - Channel: "draft", + To: pname, Type: "draft-newpick", Data: player.CurrentPack, Message: fmt.Sprintf("You got these cards: %s", player.CurrentPack), } } + + nextPack := false select { + case <-s.Pod.ReadyNextPack: + // Break of pick loop, get next packs + nextPack = true case <-s.Pod.ReadyNextPick: // Pass packs around err := s.Pod.NextPacks() @@ -253,15 +258,16 @@ func (s *session) handlePicks() { return } } - case <-s.Pod.ReadyNextPack: - // Break of pick loop, get next packs - break case <-s.exit: // Room closed, exit early close(s.messages) close(s.exit) return } + + if nextPack { + break + } } } }