github.com/muhammedhassanm/blockchain@v0.0.0-20200120143007-697261defd4d/sawtooth-core-master/rest_api/tests/unit/test_submit_requests.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 json 17 18 from aiohttp.test_utils import unittest_run_loop 19 20 from components import Mocks, BaseApiTest 21 from sawtooth_rest_api.protobuf.validator_pb2 import Message 22 from sawtooth_rest_api.protobuf import client_batch_submit_pb2 23 from sawtooth_rest_api.protobuf.client_batch_submit_pb2 \ 24 import ClientBatchStatus 25 26 27 ID_A = 'a' * 128 28 ID_B = 'b' * 128 29 ID_C = 'c' * 128 30 ID_D = 'd' * 128 31 32 33 class PostBatchTests(BaseApiTest): 34 async def get_application(self): 35 self.set_status_and_connection( 36 Message.CLIENT_BATCH_SUBMIT_REQUEST, 37 client_batch_submit_pb2.ClientBatchSubmitRequest, 38 client_batch_submit_pb2.ClientBatchSubmitResponse) 39 40 handlers = self.build_handlers(self.loop, self.connection) 41 return self.build_app(self.loop, '/batches', handlers.submit_batches) 42 43 @unittest_run_loop 44 async def test_post_batch(self): 45 """Verifies a POST /batches with one id works properly. 46 47 It will receive a Protobuf response with: 48 - the default status of OK 49 50 It should send a Protobuf request with: 51 - a batches property that matches the batches sent 52 53 It should send back a JSON response with: 54 - a response status of 202 55 - no data property 56 - a link property that ends in '/batch_statuses?id={}'.format(ID_A) 57 """ 58 batches = Mocks.make_batches(ID_A) 59 self.connection.preset_response() 60 61 request = await self.post_batches(batches) 62 self.connection.assert_valid_request_sent(batches=batches) 63 self.assertEqual(202, request.status) 64 65 response = await request.json() 66 self.assertNotIn('data', response) 67 self.assert_has_valid_link( 68 response, '/batch_statuses?id={}'.format(ID_A)) 69 70 @unittest_run_loop 71 async def test_post_batch_with_validator_error(self): 72 """Verifies a POST /batches with a validator error breaks properly. 73 74 It will receive a Protobuf response with: 75 - a status of INTERNAL_ERROR 76 77 It should send back a JSON response with: 78 - a status of 500 79 - an error property with a code of 10 80 """ 81 batches = Mocks.make_batches(ID_A) 82 self.connection.preset_response(self.status.INTERNAL_ERROR) 83 84 request = await self.post_batches(batches) 85 self.assertEqual(500, request.status) 86 87 response = await request.json() 88 self.assert_has_valid_error(response, 10) 89 90 @unittest_run_loop 91 async def test_post_json_batch(self): 92 """Verifies a POST /batches with a JSON request body breaks properly. 93 94 It should send back a JSON response with: 95 - a response status of 400 96 - an error property with a code of 42 97 """ 98 request = await self.client.post( 99 '/batches', 100 data='{"bad": "data"}', 101 headers={'content-type': 'application/json'}) 102 self.assertEqual(400, request.status) 103 104 response = await request.json() 105 self.assert_has_valid_error(response, 42) 106 107 @unittest_run_loop 108 async def test_post_invalid_batch(self): 109 """Verifies a POST /batches with an invalid batch breaks properly. 110 111 It will receive a Protobuf response with: 112 - a status of INVALID_BATCH 113 114 It should send back a JSON response with: 115 - a response status of 400 116 - an error property with a code of 30 117 """ 118 batches = Mocks.make_batches('bad') 119 self.connection.preset_response(self.status.INVALID_BATCH) 120 121 request = await self.post_batches(batches) 122 self.assertEqual(400, request.status) 123 124 response = await request.json() 125 self.assert_has_valid_error(response, 30) 126 127 @unittest_run_loop 128 async def test_post_many_batches(self): 129 """Verifies a POST /batches with many ids works properly. 130 131 It will receive a Protobuf response with: 132 - the default status of OK 133 134 It should send a Protobuf request with: 135 - a batches property that matches the batches sent 136 137 It should send back a JSON response with: 138 - a response status of 202 139 - no data property 140 - a link property that ends in 141 '/batch_statuses?id={},{},{}'.format(ID_A, ID_B, ID_C) 142 """ 143 batches = Mocks.make_batches(ID_A, ID_B, ID_C) 144 self.connection.preset_response() 145 146 request = await self.post_batches(batches) 147 self.connection.assert_valid_request_sent(batches=batches) 148 self.assertEqual(202, request.status) 149 150 response = await request.json() 151 self.assertNotIn('data', response) 152 self.assert_has_valid_link( 153 response, '/batch_statuses?id={},{},{}'.format(ID_A, ID_B, ID_C)) 154 155 @unittest_run_loop 156 async def test_post_no_batches(self): 157 """Verifies a POST /batches with no batches breaks properly. 158 159 It should send back a JSON response with: 160 - a response status of 400 161 - an error property with a code of 34 162 """ 163 request = await self.post_batches([]) 164 self.assertEqual(400, request.status) 165 166 response = await request.json() 167 self.assert_has_valid_error(response, 34) 168 169 @unittest_run_loop 170 async def test_post_rejected_due_to_full_queue(self): 171 """Verifies a POST /batches when the validator reports QUEUE_FULL 172 breaks properly. 173 174 It will receive a Protobuf response with: 175 - a status of QUEUE_FULL 176 177 It should send back a JSON response with: 178 - a response status of 429 179 - an error property with a code of 31 180 """ 181 batches = Mocks.make_batches(ID_A) 182 self.connection.preset_response(self.status.QUEUE_FULL) 183 184 request = await self.post_batches(batches) 185 self.assertEqual(429, request.status) 186 response = await request.json() 187 self.assert_has_valid_error(response, 31) 188 189 190 class ClientBatchStatusTests(BaseApiTest): 191 192 async def get_application(self): 193 self.set_status_and_connection( 194 Message.CLIENT_BATCH_STATUS_REQUEST, 195 client_batch_submit_pb2.ClientBatchStatusRequest, 196 client_batch_submit_pb2.ClientBatchStatusResponse) 197 198 handlers = self.build_handlers(self.loop, self.connection) 199 return self.build_app(self.loop, '/batch_statuses', 200 handlers.list_statuses) 201 202 @unittest_run_loop 203 async def test_batch_statuses_with_one_id(self): 204 """Verifies a GET /batch_statuses with one id works properly. 205 206 It will receive a Protobuf response with: 207 - batch statuses of {batch_id: ID_D, status: PENDING} 208 209 It should send a Protobuf request with: 210 - a batch_ids property of [ID_D] 211 212 It should send back a JSON response with: 213 - a response status of 200 214 - a link property that ends in '/batch_statuses?id={}'.format(ID_D) 215 - a data property matching the batch statuses received 216 """ 217 statuses = [ClientBatchStatus( 218 batch_id=ID_D, status=ClientBatchStatus.PENDING)] 219 self.connection.preset_response(batch_statuses=statuses) 220 221 response = await self.get_assert_200( 222 '/batch_statuses?id={}'.format(ID_D)) 223 self.connection.assert_valid_request_sent(batch_ids=[ID_D]) 224 225 self.assert_has_valid_link( 226 response, '/batch_statuses?id={}'.format(ID_D)) 227 self.assert_statuses_match(statuses, response['data']) 228 229 @unittest_run_loop 230 async def test_batch_statuses_with_invalid_data(self): 231 """Verifies a GET /batch_statuses with fetched invalid data works. 232 233 It will receive a Protobuf response with: 234 - batch_id: ID_D 235 - status: INVALID 236 - invalid_transaction: ID_D 237 - message: 'error message' 238 - extended_data: b'error data' 239 240 It should send a Protobuf request with: 241 - a batch_ids property of [ID_D] 242 243 It should send back a JSON response with: 244 - a response status of 200 245 - a link property that ends in '/batch_statuses?id={}'.format(ID_D) 246 - a data property matching the batch statuses received 247 """ 248 statuses = [ 249 ClientBatchStatus( 250 batch_id='bad-batch', 251 status=ClientBatchStatus.INVALID, 252 invalid_transactions=[ 253 ClientBatchStatus.InvalidTransaction( 254 transaction_id=ID_D, 255 message='error message', 256 extended_data=b'error data') 257 ]) 258 ] 259 self.connection.preset_response(batch_statuses=statuses) 260 261 response = await self.get_assert_200( 262 '/batch_statuses?id={}'.format(ID_D)) 263 self.connection.assert_valid_request_sent(batch_ids=[ID_D]) 264 265 self.assert_has_valid_link( 266 response, '/batch_statuses?id={}'.format(ID_D)) 267 self.assert_statuses_match(statuses, response['data']) 268 269 @unittest_run_loop 270 async def test_batch_statuses_with_validator_error(self): 271 """Verifies a GET /batch_statuses with a validator error breaks 272 properly. 273 274 It will receive a Protobuf response with: 275 - a status of INTERNAL_ERROR 276 277 It should send back a JSON response with: 278 - a status of 500 279 - an error property with a code of 10 280 """ 281 self.connection.preset_response(self.status.INTERNAL_ERROR) 282 response = await self.get_assert_status( 283 '/batch_statuses?id={}'.format(ID_D), 500) 284 285 self.assert_has_valid_error(response, 10) 286 287 @unittest_run_loop 288 async def test_batch_statuses_with_missing_statuses(self): 289 """Verifies a GET /batch_statuses with no statuses breaks properly. 290 291 It will receive a Protobuf response with: 292 - a status of NO_RESOURCE 293 294 It should send back a JSON response with: 295 - a status of 500 296 - an error property with a code of 27 297 """ 298 self.connection.preset_response(self.status.NO_RESOURCE) 299 response = await self.get_assert_status( 300 '/batch_statuses?id={}'.format(ID_D), 500) 301 302 self.assert_has_valid_error(response, 27) 303 304 @unittest_run_loop 305 async def test_batch_statuses_with_wait(self): 306 """Verifies a GET /batch_statuses with a wait set works properly. 307 308 It will receive a Protobuf response with: 309 - batch statuses of {batch_id: ID_D, status: COMMITTED} 310 311 It should send a Protobuf request with: 312 - a batch_ids property of [ID_D] 313 - a wait property that is True 314 - a timeout property of 4 (Rest Api default) 315 316 It should send back a JSON response with: 317 - a response status of 200 318 - a link property that ends in 319 '/batch_statuses?id={}&{}'.format(ID_C, ID_D) 320 - a data property matching the batch statuses received 321 """ 322 statuses = [ 323 ClientBatchStatus( 324 batch_id=ID_D, status=ClientBatchStatus.COMMITTED) 325 ] 326 self.connection.preset_response(batch_statuses=statuses) 327 328 response = await self.get_assert_200( 329 '/batch_statuses?id={}&wait'.format(ID_D)) 330 self.connection.assert_valid_request_sent( 331 batch_ids=[ID_D], 332 wait=True, 333 timeout=4) 334 335 self.assert_has_valid_link( 336 response, '/batch_statuses?id={}&wait'.format(ID_D)) 337 self.assert_statuses_match(statuses, response['data']) 338 339 @unittest_run_loop 340 async def test_batch_statuses_with_many_ids(self): 341 """Verifies a GET /batch_statuses with many ids works properly. 342 343 It will receive a Protobuf response with: 344 - batch statuses of: 345 * ID_A: COMMITTED 346 * ID_B: UNKNOWN 347 * ID_C: UNKNOWN 348 349 It should send a Protobuf request with: 350 - a batch_ids property of [ID_A, ID_B, ID_C] 351 352 It should send back a JSON response with: 353 - a response status of 200 354 - link property ending in 355 '/batch_statuses?id={},{},{}'.format(ID_A, ID_B, ID_C) 356 - a data property matching the batch statuses received 357 """ 358 statuses = [ 359 ClientBatchStatus( 360 batch_id=ID_A, status=ClientBatchStatus.COMMITTED), 361 ClientBatchStatus( 362 batch_id=ID_B, status=ClientBatchStatus.UNKNOWN), 363 ClientBatchStatus( 364 batch_id=ID_C, status=ClientBatchStatus.UNKNOWN)] 365 self.connection.preset_response(batch_statuses=statuses) 366 367 response = await self.get_assert_200( 368 '/batch_statuses?id={},{},{}'.format(ID_A, ID_B, ID_C)) 369 self.connection.assert_valid_request_sent( 370 batch_ids=[ID_A, ID_B, ID_C]) 371 372 self.assert_has_valid_link( 373 response, 374 '/batch_statuses?id={},{},{}'.format(ID_A, ID_B, ID_C)) 375 self.assert_statuses_match(statuses, response['data']) 376 377 @unittest_run_loop 378 async def test_batch_statuses_with_no_id(self): 379 """Verifies a GET /batch_statuses with no id breaks properly. 380 381 It should send back a JSON response with: 382 - a response status of 400 383 - an error property with a code of 66 384 """ 385 response = await self.get_assert_status('/batch_statuses', 400) 386 387 self.assert_has_valid_error(response, 66) 388 389 @unittest_run_loop 390 async def test_batch_statuses_as_post(self): 391 """Verifies a POST to /batch_statuses works properly. 392 393 It will receive a Protobuf response with: 394 - batch statuses of: 395 * ID_A: COMMITTED 396 * ID_B: PENDING 397 * ID_C: UNKNOWN 398 399 It should send a Protobuf request with: 400 - a batch_ids property of [ID_A, ID_B, ID_C] 401 402 It should send back a JSON response with: 403 - a response status of 200 404 - an empty link property 405 - a data property matching the batch statuses received 406 """ 407 statuses = [ 408 ClientBatchStatus( 409 batch_id=ID_A, status=ClientBatchStatus.COMMITTED), 410 ClientBatchStatus( 411 batch_id=ID_B, status=ClientBatchStatus.PENDING), 412 ClientBatchStatus( 413 batch_id=ID_C, status=ClientBatchStatus.UNKNOWN)] 414 self.connection.preset_response(batch_statuses=statuses) 415 416 request = await self.client.post( 417 '/batch_statuses', 418 data=json.dumps([ID_A, ID_B, ID_C]).encode(), 419 headers={'content-type': 'application/json'}) 420 self.connection.assert_valid_request_sent( 421 batch_ids=[ID_A, ID_B, ID_C]) 422 self.assertEqual(200, request.status) 423 424 response = await request.json() 425 self.assertNotIn('link', response) 426 self.assert_statuses_match(statuses, response['data']) 427 428 @unittest_run_loop 429 async def test_batch_statuses_wrong_post_type(self): 430 """Verifies a bad POST to /batch_statuses breaks properly. 431 432 It should send back a JSON response with: 433 - a response status of 400 434 - an error property with a code of 43 435 """ 436 request = await self.client.post( 437 '/batch_statuses', 438 data=json.dumps([ID_A, ID_B, ID_C]).encode(), 439 headers={'content-type': 'application/octet-stream'}) 440 self.assertEqual(400, request.status) 441 442 response = await request.json() 443 self.assert_has_valid_error(response, 43) 444 445 @unittest_run_loop 446 async def test_batch_statuses_as_bad_post(self): 447 """Verifies an empty POST to /batch_statuses breaks properly. 448 449 It should send back a JSON response with: 450 - a response status of 400 451 - an error property with a code of 46 452 """ 453 request = await self.client.post( 454 '/batch_statuses', 455 data=json.dumps('bad body').encode(), 456 headers={'content-type': 'application/json'}) 457 self.assertEqual(400, request.status) 458 459 response = await request.json() 460 self.assert_has_valid_error(response, 46) 461 462 @unittest_run_loop 463 async def test_batch_statuses_as_empty_post(self): 464 """Verifies an empty POST to /batch_statuses breaks properly. 465 466 It should send back a JSON response with: 467 - a response status of 400 468 - an error property with a code of 46 469 """ 470 request = await self.client.post( 471 '/batch_statuses', 472 data=json.dumps([]).encode(), 473 headers={'content-type': 'application/json'}) 474 self.assertEqual(400, request.status) 475 476 response = await request.json() 477 self.assert_has_valid_error(response, 46)