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)