1 /* PokerTH automated tests. 2 Copyright (C) 2011 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 java.net.Socket; 21 22 import static org.junit.Assert.*; 23 24 import java.sql.ResultSet; 25 import java.sql.Statement; 26 import java.util.ArrayList; 27 import java.util.Collection; 28 29 import org.junit.Test; 30 31 import de.pokerth.protocol.ProtoBuf.NetGameInfo; 32 import de.pokerth.protocol.ProtoBuf.StartEventAckMessage; 33 import de.pokerth.protocol.ProtoBuf.NetGameInfo.EndRaiseMode; 34 import de.pokerth.protocol.ProtoBuf.NetGameInfo.NetGameType; 35 import de.pokerth.protocol.ProtoBuf.PlayerListMessage.PlayerListNotification; 36 import de.pokerth.protocol.ProtoBuf.PokerTHMessage.PokerTHMessageType; 37 import de.pokerth.protocol.ProtoBuf.StartEventMessage.StartEventType; 38 import de.pokerth.protocol.ProtoBuf.PokerTHMessage; 39 40 41 public class RejoinMultiGameTest extends TestBase { 42 43 @Test testRejoinMultiGame()44 public void testRejoinMultiGame() throws Exception { 45 46 Statement dbStatement = dbConn.createStatement(); 47 ResultSet countBeforeResult = dbStatement.executeQuery("SELECT COUNT(idgame) FROM game"); 48 countBeforeResult.first(); 49 long countBefore = countBeforeResult.getLong(1); 50 51 userInit(); 52 53 // Waiting for player list update. 54 PokerTHMessage msg; 55 msg = receiveMessage(); 56 if (!msg.hasPlayerListMessage()) { 57 failOnErrorMessage(msg); 58 fail("Invalid message."); 59 } 60 61 Collection<Integer> l = new ArrayList<Integer>(); 62 String gameName = AuthUser + " rejoin game"; 63 NetGameInfo gameInfo = createGameInfo(NetGameType.rankingGame, 5, 7, 5, EndRaiseMode.doubleBlinds, 0, 50, gameName, l, 10, 0, 11, 10000); 64 sendMessage(createGameRequestMsg( 65 gameInfo, 66 "", 67 false)); 68 69 // Game list update (new game) 70 msg = receiveMessage(); 71 if (!msg.hasGameListNewMessage()) { 72 failOnErrorMessage(msg); 73 fail("Invalid message."); 74 } 75 76 // Join game ack. 77 msg = receiveMessage(); 78 if (!msg.hasJoinGameAckMessage()) { 79 failOnErrorMessage(msg); 80 fail("Could not create game!"); 81 } 82 int gameId = msg.getJoinGameAckMessage().getGameId(); 83 84 // Game list update (player joined). 85 msg = receiveMessage(); 86 if (!msg.hasGameListPlayerJoinedMessage()) { 87 failOnErrorMessage(msg); 88 fail("Invalid message."); 89 } 90 91 // Let 9 additional clients join. 92 Socket s[] = new Socket[9]; 93 int playerId[] = new int[9]; 94 Guid playerSession[] = new Guid[9]; 95 for (int i = 0; i < 9; i++) { 96 s[i] = new Socket("localhost", 7234); 97 playerSession[i] = new Guid(); 98 String username = "test" + (i+1); 99 String password = username; 100 playerId[i] = userInit(s[i], username, password, null, playerSession[i]); 101 // Waiting for player list update. 102 do { 103 msg = receiveMessage(s[i]); 104 } while (msg.hasGameListNewMessage() || msg.hasGameListPlayerJoinedMessage() || msg.hasGamePlayerJoinedMessage()); 105 if (!msg.hasPlayerListMessage()) { 106 failOnErrorMessage(msg); 107 fail("Invalid message."); 108 } 109 sendMessage(joinGameRequestMsg(gameId, "", false), s[i]); 110 do { 111 msg = receiveMessage(s[i]); 112 failOnErrorMessage(msg); 113 } while (!msg.hasJoinGameAckMessage() && !msg.hasJoinGameFailedMessage()); 114 if (!msg.hasJoinGameAckMessage()) { 115 fail("User " + username + " could not join ranking game."); 116 } 117 118 // The player should have joined the game. 119 msg = receiveMessage(); 120 if (!msg.hasPlayerListMessage()) { 121 failOnErrorMessage(msg); 122 fail("Invalid message."); 123 } 124 msg = receiveMessage(); 125 if (!msg.hasGamePlayerJoinedMessage()) { 126 failOnErrorMessage(msg); 127 fail("Invalid message."); 128 } 129 msg = receiveMessage(); 130 if (!msg.hasGameListPlayerJoinedMessage()) { 131 failOnErrorMessage(msg); 132 fail("Invalid message."); 133 } 134 } 135 136 // Server should automatically send start event. 137 msg = receiveMessage(); 138 if (!msg.hasStartEventMessage()) { 139 failOnErrorMessage(msg); 140 fail("Invalid message."); 141 } 142 for (int i = 0; i < 9; i++) { 143 do { 144 msg = receiveMessage(s[i]); 145 failOnErrorMessage(msg); 146 } while (!msg.hasStartEventMessage()); 147 } 148 // Acknowledge start event. 149 StartEventAckMessage startAck = StartEventAckMessage.newBuilder() 150 .setGameId(gameId) 151 .build(); 152 msg = PokerTHMessage.newBuilder() 153 .setMessageType(PokerTHMessageType.Type_StartEventAckMessage) 154 .setStartEventAckMessage(startAck) 155 .build(); 156 sendMessage(msg); 157 for (int i = 0; i < 9; i++) { 158 sendMessage(msg, s[i]); 159 } 160 161 // Game list update (game now running). 162 msg = receiveMessage(); 163 if (!msg.hasGameListUpdateMessage()) { 164 failOnErrorMessage(msg); 165 fail("Invalid message."); 166 } 167 168 msg = receiveMessage(); 169 if (!msg.hasGameStartInitialMessage()) { 170 failOnErrorMessage(msg); 171 fail("Invalid message."); 172 } 173 174 // Wait for start of hand. 175 do { 176 msg = receiveMessage(); 177 failOnErrorMessage(msg); 178 for (int i = 0; i < 9; i++) { 179 while (s[i].getInputStream().available() > 0) { 180 PokerTHMessage inMsg = receiveMessage(s[i]); 181 failOnErrorMessage(inMsg); 182 } 183 } 184 } while (!msg.hasHandStartMessage()); 185 186 // 9 players leave the game by closing the socket. 187 for (int i = 0; i < 9; i++) { 188 s[i].close(); 189 Thread.sleep(500); 190 } 191 // No rejoin game id set yet. 192 assertEquals(0, lastRejoinGameId); 193 194 // The remaining player should have received "player left" 9 times. 195 for (int i = 0; i < 9; i++) { 196 do { 197 msg = receiveMessage(); 198 failOnErrorMessage(msg); 199 } while (!msg.hasPlayerListMessage()); 200 assertEquals(playerId[i], msg.getPlayerListMessage().getPlayerId()); 201 assertEquals(PlayerListNotification.playerListLeft, msg.getPlayerListMessage().getPlayerListNotification()); 202 } 203 204 // Let all players reconnect. 205 long playerIdAfterRejoin[] = new long[9]; 206 for (int i = 0; i < 9; i++) { 207 s[i] = new Socket("localhost", 7234); 208 String username = "test" + (i+1); 209 String password = username; 210 playerIdAfterRejoin[i] = userInit(s[i], username, password, null, playerSession[i]); 211 assertEquals(gameId, lastRejoinGameId); 212 // Waiting for player list update. 213 do { 214 msg = receiveMessage(s[i]); 215 } while (msg.hasGameListNewMessage() || msg.hasGameListPlayerJoinedMessage() || msg.hasGamePlayerJoinedMessage()); 216 if (!msg.hasPlayerListMessage()) { 217 failOnErrorMessage(msg); 218 fail("Invalid message."); 219 } 220 sendMessage(rejoinGameRequestMsg(gameId, false), s[i]); 221 do { 222 msg = receiveMessage(s[i]); 223 failOnErrorMessage(msg); 224 } while (!msg.hasJoinGameAckMessage() && !msg.hasJoinGameFailedMessage()); 225 if (!msg.hasJoinGameAckMessage()) { 226 fail("User " + username + " could not rejoin ranking game."); 227 } 228 } 229 // The remaining player should have received "player joined" 9 times. 230 for (int i = 0; i < 9; i++) { 231 do { 232 msg = receiveMessage(); 233 failOnErrorMessage(msg); 234 } while (!msg.hasPlayerListMessage()); 235 assertEquals(playerIdAfterRejoin[i], msg.getPlayerListMessage().getPlayerId()); 236 assertEquals(PlayerListNotification.playerListNew, msg.getPlayerListMessage().getPlayerListNotification()); 237 } 238 239 for (int i = 0; i < 9; i++) { 240 // Wait for start event. 241 do { 242 msg = receiveMessage(s[i]); 243 failOnErrorMessage(msg); 244 } while (!msg.hasStartEventMessage()); 245 246 assertEquals(gameId, msg.getStartEventMessage().getGameId()); 247 assertEquals(StartEventType.rejoinEvent, msg.getStartEventMessage().getStartEventType()); 248 249 // Acknowledge start event. 250 startAck = StartEventAckMessage.newBuilder() 251 .setGameId(gameId) 252 .build(); 253 msg = PokerTHMessage.newBuilder() 254 .setMessageType(PokerTHMessageType.Type_StartEventAckMessage) 255 .setStartEventAckMessage(startAck) 256 .build(); 257 sendMessage(msg, s[i]); 258 } 259 260 for (int i = 0; i < 9; i++) { 261 // Wait for game start. This may take a while, because rejoin is performed at the beginning of the next hand. 262 do { 263 msg = receiveMessage(s[i]); 264 failOnErrorMessage(msg); 265 } while (!msg.hasGameStartRejoinMessage()); 266 267 // Check whether we got all necessary data to rejoin. 268 assertEquals(gameId, msg.getGameStartRejoinMessage().getGameId()); 269 // We left at the first hand. 270 assertTrue(msg.getGameStartRejoinMessage().getHandNum() >= 1); 271 // 10 Players should now be active again. 272 assertEquals(10, msg.getGameStartRejoinMessage().getRejoinPlayerDataCount()); 273 } 274 275 // The remaining player should have received 9 "player id changed". 276 for (int i = 0; i < 9; i++) { 277 do { 278 msg = receiveMessage(); 279 failOnErrorMessage(msg); 280 } while (!msg.hasPlayerIdChangedMessage()); 281 assertEquals(playerId[i], msg.getPlayerIdChangedMessage().getOldPlayerId()); 282 assertEquals(playerIdAfterRejoin[i], msg.getPlayerIdChangedMessage().getNewPlayerId()); 283 } 284 285 // Everyone should receive a "hand start message" now. 286 do { 287 msg = receiveMessage(); 288 failOnErrorMessage(msg); 289 } while (!msg.hasHandStartMessage()); 290 for (int i = 0; i < 9; i++) { 291 do { 292 msg = receiveMessage(s[i]); 293 failOnErrorMessage(msg); 294 } while (!msg.hasHandStartMessage()); 295 } 296 297 // The game should continue to the end. 298 do { 299 msg = receiveMessage(); 300 failOnErrorMessage(msg); 301 } while (!msg.hasEndOfGameMessage()); 302 303 for (int i = 0; i < 9; i++) { 304 s[i].close(); 305 } 306 Thread.sleep(2000); 307 308 // Check database entry for the game. 309 ResultSet countAfterResult = dbStatement.executeQuery("SELECT COUNT(idgame) FROM game"); 310 countAfterResult.first(); 311 long countAfter = countAfterResult.getLong(1); 312 assertEquals(countBefore + 1, countAfter); 313 314 // Select the latest game. 315 ResultSet gameResult = dbStatement.executeQuery("SELECT idgame, name, start_time, end_time FROM game WHERE start_time = (SELECT MAX(start_time) from game)"); 316 gameResult.first(); 317 long idgame = gameResult.getLong(1); 318 319 // Check database entries for the players in the game. 320 // There should be exactly 10 entries, just as usual. 321 ResultSet gamePlayerResult = dbStatement.executeQuery("SELECT COUNT(*) FROM game_has_player WHERE game_idgame = " + idgame); 322 gamePlayerResult.first(); 323 assertEquals(10, gamePlayerResult.getLong(1)); 324 // Each player should have a place in the range 1..10 325 ResultSet winnerResult = dbStatement.executeQuery( 326 "SELECT place FROM game_has_player LEFT JOIN player_login on (game_has_player.player_idplayer = player_login.id) WHERE game_idgame = " + idgame); 327 winnerResult.first(); 328 for (int i = 0; i < 9; i++) { 329 assertTrue(winnerResult.getLong(1) >= 1); 330 assertTrue(winnerResult.getLong(1) <= 10); 331 winnerResult.next(); 332 } 333 } 334 } 335