1 /*  PokerTH automated tests.
2 	Copyright (C) 2013 Lothar May
3 
4 	This program is free software: you can redistribute it and/or modify
5 	it under the terms of the GNU Affero General Public License as
6 	published by the Free Software Foundation, either version 3 of the
7 	License, or (at your option) any later version.
8 
9 	This program is distributed in the hope that it will be useful,
10 	but WITHOUT ANY WARRANTY; without even the implied warranty of
11 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 	GNU Affero General Public License for more details.
13 
14 	You should have received a copy of the GNU Affero General Public License
15 	along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 
18 package de.pokerth.test;
19 
20 import static org.junit.Assert.*;
21 
22 import java.net.Socket;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 
26 import org.junit.Test;
27 
28 import de.pokerth.protocol.ProtoBuf.NetGameInfo;
29 import de.pokerth.protocol.ProtoBuf.PokerTHMessage;
30 import de.pokerth.protocol.ProtoBuf.StartEventAckMessage;
31 import de.pokerth.protocol.ProtoBuf.NetGameInfo.EndRaiseMode;
32 import de.pokerth.protocol.ProtoBuf.NetGameInfo.NetGameType;
33 import de.pokerth.protocol.ProtoBuf.PokerTHMessage.PokerTHMessageType;
34 
35 public class SpectatorJoinTest extends TestBase {
36 
37 	@Test
testSpectatorJoinGameBeforeStart()38 	public void testSpectatorJoinGameBeforeStart() throws Exception {
39 		Guid firstPlayerSession = new Guid();
40 		int firstPlayerId = userInit(sock, AuthUser, AuthPassword, null, firstPlayerSession);
41 
42 		// Waiting for player list update.
43 		PokerTHMessage msg;
44 		msg = receiveMessage();
45 		if (!msg.hasPlayerListMessage()) {
46 			failOnErrorMessage(msg);
47 			fail("Invalid message: " + msg.getMessageType());
48 		}
49 
50 		Collection<Integer> l = new ArrayList<Integer>();
51 		String gameName = AuthUser + " rejoin game";
52 		NetGameInfo gameInfo = createGameInfo(NetGameType.normalGame, 5, 7, 5, EndRaiseMode.doubleBlinds, 0, 50, gameName, l, 10, 0, 11, 10000);
53 		sendMessage(createGameRequestMsg(
54 				gameInfo,
55 				"",
56 				false));
57 
58 		// Game list update (new game)
59 		msg = receiveMessage();
60 		if (!msg.hasGameListNewMessage()) {
61 			failOnErrorMessage(msg);
62 			fail("Invalid message: " + msg.getMessageType());
63 		}
64 
65 		// Join game ack.
66 		msg = receiveMessage();
67 		if (!msg.hasJoinGameAckMessage()) {
68 			failOnErrorMessage(msg);
69 			fail("Could not create game!");
70 		}
71 		int gameId = msg.getJoinGameAckMessage().getGameId();
72 
73 		// Game list update (player joined).
74 		msg = receiveMessage();
75 		if (!msg.hasGameListPlayerJoinedMessage()) {
76 			failOnErrorMessage(msg);
77 			fail("Invalid message: " + msg.getMessageType());
78 		}
79 
80 		// Let a spectator join.
81 		Socket spectatorSock = new Socket("localhost", 7234);
82 		int spectatorId = userInit(spectatorSock, "test20", "test20");
83 
84 		msg = receiveMessage(spectatorSock);
85 		if (!msg.hasPlayerListMessage()) {
86 			failOnErrorMessage(msg);
87 			fail("Invalid message: " + msg.getMessageType());
88 		}
89 		msg = receiveMessage(spectatorSock);
90 		if (!msg.hasGameListNewMessage()) {
91 			failOnErrorMessage(msg);
92 			fail("Invalid message: " + msg.getMessageType());
93 		}
94 		msg = receiveMessage(spectatorSock);
95 		if (!msg.hasPlayerListMessage()) {
96 			failOnErrorMessage(msg);
97 			fail("Invalid message: " + msg.getMessageType());
98 		}
99 		// Player List should also be updated for first player.
100 		msg = receiveMessage();
101 		if (!msg.hasPlayerListMessage()) {
102 			failOnErrorMessage(msg);
103 			fail("Invalid message: " + msg.getMessageType());
104 		}
105 
106 		sendMessage(joinGameRequestMsg(gameId, "", false, true), spectatorSock);
107 		msg = receiveMessage(spectatorSock);
108 		if (!msg.hasJoinGameAckMessage()) {
109 			failOnErrorMessage(msg);
110 			fail("Invalid message: " + msg.getMessageType());
111 		}
112 		assertTrue(msg.getJoinGameAckMessage().getSpectateOnly());
113 
114 		msg = receiveMessage(spectatorSock);
115 		if (!msg.hasGamePlayerJoinedMessage()) {
116 			failOnErrorMessage(msg);
117 			fail("Invalid message: " + msg.getMessageType());
118 		}
119 		assertEquals(firstPlayerId, msg.getGamePlayerJoinedMessage().getPlayerId());
120 		// TODO Spectator joined message is missing here!
121 
122 		msg = receiveMessage(spectatorSock);
123 		if (!msg.hasGameListSpectatorJoinedMessage()) {
124 			failOnErrorMessage(msg);
125 			fail("Invalid message: " + msg.getMessageType());
126 		}
127 		assertEquals(gameId, msg.getGameListSpectatorJoinedMessage().getGameId());
128 		assertEquals(spectatorId, msg.getGameListSpectatorJoinedMessage().getPlayerId());
129 
130 		// Spectator should be visible for first player.
131 		msg = receiveMessage();
132 		if (!msg.hasGameSpectatorJoinedMessage()) {
133 			failOnErrorMessage(msg);
134 			fail("Invalid message: " + msg.getMessageType());
135 		}
136 		msg = receiveMessage();
137 		if (!msg.hasGameListSpectatorJoinedMessage()) {
138 			failOnErrorMessage(msg);
139 			fail("Invalid message: " + msg.getMessageType());
140 		}
141 
142 		// Let 9 additional clients join.
143 		Socket s[] = new Socket[9];
144 		int playerId[] = new int[9];
145 		for (int i = 0; i < 9; i++) {
146 			s[i] = new Socket("localhost", 7234);
147 			String username = "test" + (i+1);
148 			String password = username;
149 			playerId[i] = userInit(s[i], username, password);
150 
151 			// Waiting for player list update.
152 			do {
153 				msg = receiveMessage(s[i]);
154 			} while (msg.hasPlayerListMessage());
155 
156 			if (!msg.hasGameListNewMessage()) {
157 				failOnErrorMessage(msg);
158 				fail("Invalid message: " + msg.getMessageType());
159 			}
160 			assertEquals(1, msg.getGameListNewMessage().getSpectatorIdsCount());
161 			assertEquals(spectatorId, msg.getGameListNewMessage().getSpectatorIds(0));
162 			do {
163 				msg = receiveMessage(s[i]);
164 			} while (msg.hasGameListPlayerJoinedMessage() || msg.hasGamePlayerJoinedMessage());
165 			sendMessage(joinGameRequestMsg(gameId, "", false), s[i]);
166 			do {
167 				msg = receiveMessage(s[i]);
168 				failOnErrorMessage(msg);
169 			} while (!msg.hasJoinGameAckMessage() && !msg.hasJoinGameFailedMessage());
170 			if (!msg.hasJoinGameAckMessage()) {
171 				fail("User " + username + " could not join ranking game.");
172 			}
173 
174 			// The player should have joined the game.
175 			msg = receiveMessage();
176 			if (!msg.hasPlayerListMessage()) {
177 				failOnErrorMessage(msg);
178 				fail("Invalid message: " + msg.getMessageType());
179 			}
180 			msg = receiveMessage();
181 			if (!msg.hasGamePlayerJoinedMessage()) {
182 				failOnErrorMessage(msg);
183 				fail("Invalid message: " + msg.getMessageType());
184 			}
185 			msg = receiveMessage();
186 			if (!msg.hasGameListPlayerJoinedMessage()) {
187 				failOnErrorMessage(msg);
188 				fail("Invalid message: " + msg.getMessageType());
189 			}
190 			// The spectator should also receive the updates.
191 			msg = receiveMessage(spectatorSock);
192 			if (!msg.hasPlayerListMessage()) {
193 				failOnErrorMessage(msg);
194 				fail("Invalid message: " + msg.getMessageType());
195 			}
196 			msg = receiveMessage(spectatorSock);
197 			if (!msg.hasGamePlayerJoinedMessage()) {
198 				failOnErrorMessage(msg);
199 				fail("Invalid message: " + msg.getMessageType());
200 			}
201 			msg = receiveMessage(spectatorSock);
202 			if (!msg.hasGameListPlayerJoinedMessage()) {
203 				failOnErrorMessage(msg);
204 				fail("Invalid message: " + msg.getMessageType());
205 			}
206 		}
207 
208 		// Server should automatically send start event.
209 		msg = receiveMessage();
210 		if (!msg.hasStartEventMessage()) {
211 			failOnErrorMessage(msg);
212 			fail("Invalid message: " + msg.getMessageType());
213 		}
214 		for (int i = 0; i < 9; i++) {
215 			do {
216 				msg = receiveMessage(s[i]);
217 				failOnErrorMessage(msg);
218 			} while (!msg.hasStartEventMessage());
219 		}
220 		// Acknowledge start event.
221 		StartEventAckMessage startAck = StartEventAckMessage.newBuilder()
222 			.setGameId(gameId)
223 			.build();
224 		msg = PokerTHMessage.newBuilder()
225 			.setMessageType(PokerTHMessageType.Type_StartEventAckMessage)
226 			.setStartEventAckMessage(startAck)
227 			.build();
228 		sendMessage(msg);
229 		for (int i = 0; i < 9; i++) {
230 			sendMessage(msg, s[i]);
231 		}
232 
233 		// Game list update (game now running).
234 		msg = receiveMessage(spectatorSock);
235 		if (!msg.hasGameListUpdateMessage()) {
236 			failOnErrorMessage(msg);
237 			fail("Invalid message: " + msg.getMessageType());
238 		}
239 
240 		msg = receiveMessage(spectatorSock);
241 		if (!msg.hasGameStartInitialMessage()) {
242 			failOnErrorMessage(msg);
243 			fail("Invalid message: " + msg.getMessageType());
244 		}
245 
246 		// Spectator should receive a hand start message without cards.
247 		msg = receiveMessage(spectatorSock);
248 		if (!msg.hasHandStartMessage()) {
249 			failOnErrorMessage(msg);
250 			fail("Invalid message: " + msg.getMessageType());
251 		}
252 		assertFalse(msg.getHandStartMessage().hasEncryptedCards());
253 		assertFalse(msg.getHandStartMessage().hasPlainCards());
254 		assertEquals(gameId, msg.getHandStartMessage().getGameId());
255 
256 		for (int i = 0; i < 9; i++) {
257 			s[i].close();
258 		}
259 		spectatorSock.close();
260 	}
261 
262 }
263