github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/families/battleship/tests/test_tp_battleship.py (about) 1 # Copyright 2017 Intel Corporation 2 # 3 # Licensed under the Apache License, Version 2.0 (the "License"); 4 # you may not use this file except in compliance with the License. 5 # You may obtain a copy of the License at 6 # 7 # http://www.apache.org/licenses/LICENSE-2.0 8 # 9 # Unless required by applicable law or agreed to in writing, software 10 # distributed under the License is distributed on an "AS IS" BASIS, 11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 # See the License for the specific language governing permissions and 13 # limitations under the License. 14 # ------------------------------------------------------------------------------ 15 16 import logging 17 import json 18 19 from sawtooth_sdk.protobuf.validator_pb2 import Message 20 from sawtooth_processor_test.transaction_processor_test_case \ 21 import TransactionProcessorTestCase 22 from sawtooth_battleship_test.battleship_message_factory \ 23 import BattleshipMessageFactory 24 25 from sawtooth_battleship.battleship_board import BoardLayout 26 from sawtooth_battleship.battleship_board import create_nonces 27 from sawtooth_battleship.battleship_board import ShipPosition 28 29 LOGGER = logging.getLogger(__name__) 30 31 32 class TestBattleship(TransactionProcessorTestCase): 33 34 @classmethod 35 def setUpClass(cls): 36 super().setUpClass() 37 38 cls.player_1 = BattleshipMessageFactory() 39 cls.public_key_1 = cls.player_1.get_public_key() 40 41 cls.player_2 = BattleshipMessageFactory() 42 cls.public_key_2 = cls.player_2.get_public_key() 43 44 cls.test_ships = ["AAAAA", "BBBB", "CCC", "DD", "DD", "SSS", "SSS"] 45 cls.validator.register_comparator( 46 Message.TP_STATE_SET_REQUEST, compare_set_request) 47 48 # invalid inputs 49 50 def test_no_action(self): 51 payload = { 52 'Name': 'noActionGame', 53 'Action': None 54 } 55 56 self.validator.send( 57 self.player_1.create_tp_process_request(payload) 58 ) 59 60 self.send_state_to_tp('noActionGame') 61 62 self.expect_invalid() 63 64 def test_invalid_action(self): 65 payload = { 66 'Name': 'invalidAction', 67 'Action': 'MAKE_TACOS' 68 } 69 70 self.validator.send( 71 self.player_1.create_tp_process_request(payload) 72 ) 73 74 self.send_state_to_tp('invalidAction') 75 76 self.expect_invalid() 77 78 def test_no_name(self): 79 payload = { 80 'Name': '', 81 'Action': 'CREATE' 82 } 83 84 self.validator.send( 85 self.player_1.create_tp_process_request(payload) 86 ) 87 88 self.send_state_to_tp('') 89 90 self.expect_invalid() 91 92 def test_invalid_name(self): 93 payload = { 94 'Name': 'invalid-name', 95 'Action': 'CREATE' 96 } 97 98 self.validator.send( 99 self.player_1.create_tp_process_request(payload) 100 ) 101 102 self.send_state_to_tp('invalid-name') 103 104 self.expect_invalid() 105 106 # create 107 108 def test_create_game_valid(self): 109 self.create_game('createGame') 110 111 self.send_state_to_tp('createGame') 112 113 self.update_state('createGame', { 114 'Ships': self.test_ships, 115 'State': 'NEW' 116 }) 117 118 self.expect_ok() 119 120 def test_create_already_exists(self): 121 self.create_game('alreadyExists') 122 123 self.send_state_to_tp('alreadyExists', { 124 'Ships': self.test_ships, 125 'State': 'NEW' 126 }) 127 128 self.expect_invalid() 129 130 # join 131 132 def test_join_game_valid(self): 133 layout = BoardLayout.generate(self.test_ships) 134 nonces = create_nonces(10) 135 136 # Send join payload to tp 137 138 join_req = create_join_payload('join_game', layout, nonces) 139 self.validator.send( 140 self.player_1.create_tp_process_request(join_req) 141 ) 142 143 # give state back to tp 144 145 self.send_state_to_tp('join_game', { 146 'Ships': self.test_ships, 147 'State': 'NEW' 148 }) 149 150 # mock state set 151 LOGGER.debug('state update') 152 self.update_state('join_game', { 153 'Ships': self.test_ships, 154 'TargetBoard1': [['?'] * 10 for _ in range(10)], 155 'Player1': self.public_key_1, 156 'HashedBoard1': layout.render_hashed(nonces), 157 'State': 'NEW' 158 }) 159 160 self.expect_ok() 161 162 def test_join_game_too_many_players(self): 163 layout = BoardLayout.generate(self.test_ships) 164 nonces = create_nonces(10) 165 166 # Send join payload to tp 167 join_req = create_join_payload('full_game', layout, nonces) 168 self.validator.send( 169 self.player_1.create_tp_process_request(join_req) 170 ) 171 172 # give state back to tp 173 174 self.send_state_to_tp('full_game', { 175 'Ships': self.test_ships, 176 'TargetBoard1': [['?'] * 10 for _ in range(10)], 177 'TargetBoard2': [['?'] * 10 for _ in range(10)], 178 'Player1': self.public_key_1, 179 'Player2': self.public_key_2, 180 'HashedBoard1': layout.render_hashed(nonces), 181 'HashedBoard2': layout.render_hashed(nonces), 182 'State': 'P1-NEXT' 183 }) 184 185 self.expect_invalid() 186 187 def test_join_nonexistent_game(self): 188 layout = BoardLayout.generate(self.test_ships) 189 nonces = create_nonces(10) 190 191 # Send join payload to tp 192 join_req = create_join_payload('nonexistent_game', layout, nonces) 193 self.validator.send( 194 self.player_1.create_tp_process_request(join_req) 195 ) 196 197 # give state back to tp 198 199 self.send_state_to_tp('nonexistent_game') 200 201 self.expect_invalid() 202 203 # fire 204 205 def test_fire_first_move(self): 206 # Create test board 207 layout = BoardLayout(10) 208 layout.append( 209 ShipPosition(text='AA', row=0, column=0, orientation='horizontal')) 210 nonces = create_nonces(10) 211 212 # Player 1 fires 213 fire_req = create_fire_payload('fire_game', '1', 'B') 214 215 self.validator.send( 216 self.player_1.create_tp_process_request(fire_req)) 217 218 self.send_state_to_tp('fire_game', { 219 'Ships': ['AA'], 220 'TargetBoard1': [['?'] * 10 for _ in range(10)], 221 'TargetBoard2': [['?'] * 10 for _ in range(10)], 222 'Player1': self.public_key_1, 223 'Player2': self.public_key_2, 224 'HashedBoard1': layout.render_hashed(nonces), 225 'HashedBoard2': layout.render_hashed(nonces), 226 'State': 'P1-NEXT' 227 }) 228 229 self.update_state('fire_game', { 230 'Ships': ['AA'], 231 'TargetBoard1': [['?'] * 10 for _ in range(10)], 232 'TargetBoard2': [['?'] * 10 for _ in range(10)], 233 'Player1': self.public_key_1, 234 'Player2': self.public_key_2, 235 'HashedBoard1': layout.render_hashed(nonces), 236 'HashedBoard2': layout.render_hashed(nonces), 237 'LastFireRow': '1', 238 'LastFireColumn': 'B', 239 'State': 'P2-NEXT' 240 }) 241 242 self.expect_ok() 243 244 def test_fire_hit_ship(self): 245 # Create test board 246 layout = BoardLayout(10) 247 layout.append( 248 ShipPosition(text='AA', row=0, column=0, orientation='horizontal')) 249 nonces = create_nonces(10) 250 251 # Player 2 fires 252 fire_req = \ 253 create_fire_payload('fire_game', '1', 'A', 'A', nonces[0][0]) 254 255 self.validator.send( 256 self.player_2.create_tp_process_request(fire_req)) 257 258 self.send_state_to_tp('fire_game', { 259 'Ships': ['AA'], 260 'TargetBoard1': [['?'] * 10 for _ in range(10)], 261 'TargetBoard2': [['?'] * 10 for _ in range(10)], 262 'Player1': self.public_key_1, 263 'Player2': self.public_key_2, 264 'HashedBoard1': layout.render_hashed(nonces), 265 'HashedBoard2': layout.render_hashed(nonces), 266 'State': 'P2-NEXT', 267 'LastFireRow': '1', 268 'LastFireColumn': 'A' 269 }, self.player_2) 270 271 target_board1 = [['?'] * 10 for _ in range(10)] 272 target_board1[0][0] = 'H' 273 274 self.update_state('fire_game', { 275 'Ships': ['AA'], 276 'TargetBoard1': target_board1, 277 'TargetBoard2': [['?'] * 10 for _ in range(10)], 278 'Player1': self.public_key_1, 279 'Player2': self.public_key_2, 280 'HashedBoard1': layout.render_hashed(nonces), 281 'HashedBoard2': layout.render_hashed(nonces), 282 'LastFireRow': '1', 283 'LastFireColumn': 'A', 284 'State': 'P1-NEXT' 285 }, self.player_2) 286 287 self.expect_ok() 288 289 def test_fire_miss_ship(self): 290 # Create test board 291 layout = BoardLayout(10) 292 layout.append( 293 ShipPosition(text='AA', row=0, column=0, orientation='horizontal')) 294 nonces = create_nonces(10) 295 296 # Player 2 fires 297 fire_req = \ 298 create_fire_payload('fire_game', '2', 'A', '-', nonces[1][0]) 299 300 self.validator.send( 301 self.player_2.create_tp_process_request(fire_req)) 302 303 self.send_state_to_tp('fire_game', { 304 'Ships': ['AA'], 305 'TargetBoard1': [['?'] * 10 for _ in range(10)], 306 'TargetBoard2': [['?'] * 10 for _ in range(10)], 307 'Player1': self.public_key_1, 308 'Player2': self.public_key_2, 309 'HashedBoard1': layout.render_hashed(nonces), 310 'HashedBoard2': layout.render_hashed(nonces), 311 'State': 'P2-NEXT', 312 'LastFireRow': '2', 313 'LastFireColumn': 'A' 314 }, self.player_2) 315 316 target_board1 = [['?'] * 10 for _ in range(10)] 317 target_board1[1][0] = 'M' 318 319 self.update_state('fire_game', { 320 'Ships': ['AA'], 321 'TargetBoard1': target_board1, 322 'TargetBoard2': [['?'] * 10 for _ in range(10)], 323 'Player1': self.public_key_1, 324 'Player2': self.public_key_2, 325 'HashedBoard1': layout.render_hashed(nonces), 326 'HashedBoard2': layout.render_hashed(nonces), 327 'LastFireRow': '2', 328 'LastFireColumn': 'A', 329 'State': 'P1-NEXT' 330 }, self.player_2) 331 332 self.expect_ok() 333 334 def test_fire_game_won(self): 335 # Create test board 336 layout = BoardLayout(10) 337 layout.append( 338 ShipPosition(text='AA', row=0, column=0, orientation='horizontal')) 339 nonces = create_nonces(10) 340 341 # Player 2 fires 342 fire_req = \ 343 create_fire_payload('fire_game', '1', 'B', 'A', nonces[0][1]) 344 345 self.validator.send( 346 self.player_2.create_tp_process_request(fire_req)) 347 348 target_board1 = [['?'] * 10 for _ in range(10)] 349 target_board1[0][0] = 'H' 350 351 self.send_state_to_tp('fire_game', { 352 'Ships': ['AA'], 353 'TargetBoard1': target_board1, 354 'TargetBoard2': [['?'] * 10 for _ in range(10)], 355 'Player1': self.public_key_1, 356 'Player2': self.public_key_2, 357 'HashedBoard1': layout.render_hashed(nonces), 358 'HashedBoard2': layout.render_hashed(nonces), 359 'State': 'P2-NEXT', 360 'LastFireRow': '1', 361 'LastFireColumn': 'B' 362 }, self.player_2) 363 364 target_board1[0][1] = 'H' 365 366 self.update_state('fire_game', { 367 'Ships': ['AA'], 368 'TargetBoard1': target_board1, 369 'TargetBoard2': [['?'] * 10 for _ in range(10)], 370 'Player1': self.public_key_1, 371 'Player2': self.public_key_2, 372 'HashedBoard1': layout.render_hashed(nonces), 373 'HashedBoard2': layout.render_hashed(nonces), 374 'LastFireRow': '1', 375 'LastFireColumn': 'B', 376 'State': 'P1-WIN' 377 }, self.player_2) 378 379 self.expect_ok() 380 381 def test_fire_nonexistent_game(self): 382 # Send join payload to tp 383 384 fire_req = create_fire_payload('nonexistent_game', '1', 'A') 385 386 self.validator.send( 387 self.player_1.create_tp_process_request(fire_req) 388 ) 389 390 # give state back to tp 391 392 self.send_state_to_tp('nonexistent_game') 393 394 self.expect_invalid() 395 396 def test_fire_invalid_row(self): 397 layout = BoardLayout(10) 398 layout.append( 399 ShipPosition(text='AA', row=0, column=0, orientation='horizontal')) 400 nonces = create_nonces(10) 401 402 # Send join payload to tp 403 404 fire_req = create_fire_payload('invalid_row', '100', 'A') 405 406 self.validator.send( 407 self.player_1.create_tp_process_request(fire_req) 408 ) 409 410 # give state back to tp 411 412 self.send_state_to_tp('invalid_row', { 413 'Ships': ['AA'], 414 'TargetBoard1': [['?'] * 10 for _ in range(10)], 415 'TargetBoard2': [['?'] * 10 for _ in range(10)], 416 'Player1': self.public_key_1, 417 'Player2': self.public_key_2, 418 'HashedBoard1': layout.render_hashed(nonces), 419 'HashedBoard2': layout.render_hashed(nonces), 420 'State': 'P1-NEXT' 421 }) 422 423 self.expect_invalid() 424 425 def test_fire_invalid_column(self): 426 layout = BoardLayout(10) 427 layout.append( 428 ShipPosition(text='AA', row=0, column=0, orientation='horizontal')) 429 nonces = create_nonces(10) 430 431 # Send join payload to tp 432 fire_req = create_fire_payload('invalid_row', '1', 'Z') 433 434 self.validator.send( 435 self.player_1.create_tp_process_request(fire_req) 436 ) 437 438 # give state back to tp 439 440 self.send_state_to_tp('invalid_row', { 441 'Ships': ['AA'], 442 'TargetBoard1': [['?'] * 10 for _ in range(10)], 443 'TargetBoard2': [['?'] * 10 for _ in range(10)], 444 'Player1': self.public_key_1, 445 'Player2': self.public_key_2, 446 'HashedBoard1': layout.render_hashed(nonces), 447 'HashedBoard2': layout.render_hashed(nonces), 448 'State': 'P1-NEXT' 449 }) 450 451 self.expect_invalid() 452 453 def test_fire_game_over(self): 454 layout = BoardLayout(10) 455 layout.append( 456 ShipPosition(text='AA', row=0, column=0, orientation='horizontal')) 457 nonces = create_nonces(10) 458 459 # Send join payload to tp 460 fire_req = create_fire_payload('invalid_row', '1', 'A') 461 462 self.validator.send( 463 self.player_1.create_tp_process_request(fire_req) 464 ) 465 466 # give state back to tp 467 468 self.send_state_to_tp('invalid_row', { 469 'Ships': ['AA'], 470 'TargetBoard1': [['?'] * 10 for _ in range(10)], 471 'TargetBoard2': [['?'] * 10 for _ in range(10)], 472 'Player1': self.public_key_1, 473 'Player2': self.public_key_2, 474 'HashedBoard1': layout.render_hashed(nonces), 475 'HashedBoard2': layout.render_hashed(nonces), 476 'State': 'P1-WIN' 477 }) 478 479 self.expect_invalid() 480 481 def test_fire_wrong_turn(self): 482 layout = BoardLayout(10) 483 layout.append( 484 ShipPosition(text='AA', row=0, column=0, orientation='horizontal')) 485 nonces = create_nonces(10) 486 487 # Send join payload to tp 488 fire_req = create_fire_payload('invalid_row', '1', 'Z') 489 490 self.validator.send( 491 self.player_1.create_tp_process_request(fire_req) 492 ) 493 494 # give state back to tp 495 496 self.send_state_to_tp('invalid_row', { 497 'Ships': ['AA'], 498 'TargetBoard1': [['?'] * 10 for _ in range(10)], 499 'TargetBoard2': [['?'] * 10 for _ in range(10)], 500 'Player1': self.public_key_1, 501 'Player2': self.public_key_2, 502 'HashedBoard1': layout.render_hashed(nonces), 503 'HashedBoard2': layout.render_hashed(nonces), 504 'State': 'P2-NEXT' 505 }) 506 507 self.expect_invalid() 508 509 # Helper methods 510 511 def create_game(self, name, ships=None, player=None): 512 ships = ships if ships else self.test_ships 513 514 player = player if player else self.player_1 515 516 req_to_tp = player.create_tp_process_request({ 517 'Action': 'CREATE', 518 'Name': name, 519 'Ships': ships 520 }) 521 self.validator.send(req_to_tp) 522 523 def send_state_to_tp(self, name, state=None, player=None): 524 state = state if state else {} 525 player = player if player else self.player_1 526 527 get_req_from_tp = self.validator.expect( 528 player.create_get_request(name)) 529 get_res_from_validator = player.create_get_response(name, state) 530 self.validator.respond(get_res_from_validator, get_req_from_tp) 531 532 def update_state(self, name, state=None, player=None): 533 state = state if state else {} 534 player = player if player else self.player_1 535 LOGGER.debug('expecing set') 536 set_req_from_tp = self.validator.expect( 537 player.create_set_request(name, state)) 538 self.validator.respond( 539 player.create_set_response(name), set_req_from_tp) 540 541 def expect_ok(self): 542 self.expect_tp_response('OK') 543 544 def expect_invalid(self): 545 self.expect_tp_response('INVALID_TRANSACTION') 546 547 def expect_tp_response(self, response): 548 self.validator.expect( 549 self.player_1.create_tp_response( 550 response)) 551 552 553 def compare_set_request(req1, req2): 554 if len(req1.entries) != len(req2.entries): 555 return False 556 557 entries1 = sorted( 558 [(e.address, json.loads(e.data.decode(), encoding="utf-8")) 559 for e in req1.entries]) 560 entries2 = sorted( 561 [(e.address, json.loads(e.data.decode(), encoding="utf-8")) 562 for e in req2.entries]) 563 if entries1 != entries2: 564 return False 565 566 return True 567 568 569 def create_join_payload(name, board_layout, nonces): 570 return { 571 'Action': 'JOIN', 572 'Name': name, 573 'Board': board_layout.render_hashed(nonces) 574 } 575 576 577 def create_fire_payload( 578 name, 579 row, 580 column, 581 reveal_space=None, 582 reveal_nonce=None): 583 return { 584 'Action': 'FIRE', 585 'Name': name, 586 'Row': row, 587 'Column': column, 588 'RevealSpace': reveal_space, 589 'RevealNonce': reveal_nonce 590 }