async def test_block_list_paginated_by_start_id(self): """Verifies GET /blocks paginated by a start id works properly. It will receive a Protobuf response with: - a head id of ID_D - a paging response with start of 0x0003 and limit of 5 - three blocks with the ids ID_C, ID_B and ID_A It should send a Protobuf request with: - paging controls with a limit of 5, and a startof ID_C It should send back a JSON response with: - a response status of 200 - a head property of ID_D - a link property that ends in '/blocks?head={}&start=0x0003&limit=5'.format(ID_C) - paging that matches the response, with a previous link - a data property that is a list of 3 dicts - and those dicts are full blocks with ids ID_C, ID_B, and ID_A """ paging = Mocks.make_paging_response("", "0x0003", 5) blocks = Mocks.make_blocks(ID_C, ID_B, ID_A) self.connection.preset_response( head_id=ID_D, paging=paging, blocks=blocks) response = await self.get_assert_200('/blocks?start=0x0003&limit=5') controls = Mocks.make_paging_controls(5, start="0x0003") self.connection.assert_valid_request_sent(paging=controls) self.assert_has_valid_head(response, ID_D) self.assert_has_valid_link( response, '/blocks?head={}&start=0x0003&limit=5'.format(ID_D)) self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 3) self.assert_blocks_well_formed(response['data'], ID_C, ID_B, ID_A)
async def test_batch_list_paginated_without_count(self): """Verifies GET /batches paginated without count works properly. It will receive a Protobuf response with: - a head id of ID_D - a paging response with start of ID_B and limit of 100 - two batches with the ids ID_B and ID_A It should send a Protobuf request with: - paging controls with a start of 2 It should send back a JSON response with: - a response status of 200 - a head property of ID_D - a link property that ends in '/batches?head={}&start={}&limit=100'.format(ID_D, ID_B) - paging that matches the response, with a previous link - a data property that is a list of 2 dicts - and those dicts are full batches with ids ID_D and ID_C """ paging = Mocks.make_paging_response("", ID_B, DEFAULT_LIMIT) batches = Mocks.make_batches(ID_B, ID_A) self.connection.preset_response( head_id=ID_D, paging=paging, batches=batches) response = await self.get_assert_200('/batches?start={}'.format(ID_B)) controls = Mocks.make_paging_controls(None, start=ID_B) self.connection.assert_valid_request_sent(paging=controls) self.assert_has_valid_head(response, ID_D) self.assert_has_valid_link( response, '/batches?head={}&start={}&limit=100'.format(ID_D, ID_B)) self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 2) self.assert_batches_well_formed(response['data'], ID_B, ID_A)
async def test_batch_list(self): """Verifies a GET /batches without parameters works properly. It will receive a Protobuf response with: - a head id of ID_C - a paging response with a start of ID_C and limit of 100 - three batches with ids of ID_C, ID_B, and ID_A It should send a Protobuf request with: - empty paging controls It should send back a JSON response with: - a response status of 200 - a head property of ID_C - a link property that ends in '/batches?start={}&limit=100&head={}'.format(ID_C, ID_C) - a paging property that matches the paging response - a data property that is a list of 3 dicts - and those dicts are full batches with ids ID_C, ID_B, and ID_A """ paging = Mocks.make_paging_response("", ID_C, DEFAULT_LIMIT) batches = Mocks.make_batches(ID_C, ID_B, ID_A) self.connection.preset_response( head_id=ID_C, paging=paging, batches=batches) response = await self.get_assert_200('/batches') controls = Mocks.make_paging_controls() self.connection.assert_valid_request_sent(paging=controls) self.assert_has_valid_head(response, ID_C) self.assert_has_valid_link( response, '/batches?head={}&start={}&limit=100'.format(ID_C, ID_C)) self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 3) self.assert_batches_well_formed(response['data'], ID_C, ID_B, ID_A)
async def test_state_list_sorted_in_reverse(self): """Verifies a GET /state can send proper sort parameters. It will receive a Protobuf response with: - a head id of ID_C - a paging response with a start of c and limit of 100 - three entries with addresses/data of: * 'c': b'7' * 'b': b'5' * 'a': b'3' It should send a Protobuf request with: - empty paging controls - sort controls with a key of 'address' that is reversed It should send back a JSON response with: - a status of 200 - a head property of ID_C - a link property ending in '/state?head={}&start=c&limit=100&reverse'.format(ID_C) - a paging property that matches the paging response - a data property that is a list of 3 dicts - three entries that match those in Protobuf response """ paging = Mocks.make_paging_response("", "c", DEFAULT_LIMIT) entries = Mocks.make_entries(c=b'7', b=b'5', a=b'3') self.connection.preset_response(state_root='beef', paging=paging, entries=entries) self.connection.preset_response( proto=client_block_pb2.ClientBlockGetResponse, block=block_pb2.Block( header_signature=ID_C, header=block_pb2.BlockHeader( state_root_hash='beef').SerializeToString())) response = await self.get_assert_200('/state?reverse') page_controls = Mocks.make_paging_controls() sorting = Mocks.make_sort_controls('default', reverse=True) self.connection.assert_valid_request_sent( state_root='beef', paging=page_controls, sorting=sorting) self.assert_has_valid_head(response, ID_C) self.assert_has_valid_link( response, '/state?head={}&start=c&limit=100&reverse'.format(ID_C)) self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 3) self.assert_entries_match(entries, response['data'])
async def test_txn_list_with_bad_ids(self): """Verifies GET /transactions with a bad id filter breaks properly. It will receive a Protobuf response with: - a status of NO_RESOURCE - a head id of ID_C It should send back a JSON response with: - a response status of 200 - a head property of ID_C, the latest - a link property that ends in '/transactions?head={}&start={}&limit=100&id={},{}' .format(ID_C, ID_C, ID_B, ID_D)) - a paging property with only a total_count of 0 - a data property that is an empty list """ paging = Mocks.make_paging_response("", ID_C, DEFAULT_LIMIT) self.connection.preset_response( self.status.NO_RESOURCE, head_id=ID_C, paging=paging) response = await self.get_assert_200('/transactions?id={},{}'.format( ID_B, ID_D)) self.assert_has_valid_head(response, ID_C) link =\ '/transactions?head={ID_C}&start={ID_C}&limit=100&id={ID_B},{ID_D}' self.assert_has_valid_link( response, link.format(ID_C=ID_C, ID_B=ID_B, ID_D=ID_D)) self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 0)
async def test_state_list_with_bad_address(self): """Verifies a GET /state breaks properly filtered by a bad address. It will receive a Protobuf response with: - a status of NO_RESOURCE - a head id of ID_C It should send back a JSON response with: - a response status of 200 - a head property of ID_C - a link property that ends in '/state?head={}&start=c&limit=100address=bad'.format(ID_C) - a paging property with only a total_count of 0 - a data property that is an empty list """ paging = Mocks.make_paging_response("", "c", DEFAULT_LIMIT) self.connection.preset_response( self.status.NO_RESOURCE, state_root='beef', paging=paging) self.connection.preset_response( proto=client_block_pb2.ClientBlockGetResponse, block=block_pb2.Block( header_signature=ID_C, header=block_pb2.BlockHeader( state_root_hash='beef').SerializeToString())) response = await self.get_assert_200('/state?address=bad') self.assert_has_valid_head(response, ID_C) self.assert_has_valid_link( response, '/state?head={}&start=c&limit=100&address=bad'.format(ID_C)) self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 0)
async def test_state_list_with_head_and_address(self): """Verifies GET /state works with a head and filtered by address. It will receive a Protobuf response with: - a head id of ID_B - a paging response with a start of a and a limit of 100 - one leaf with addresses/data of: 'a': b'2' It should send a Protobuf request with: - a head_id property of ID_B - an address property of 'a' - empty paging controls It should send back a JSON response with: - a response status of 200 - a head property of ID_B - a link property that ends in '/state?head={}&start=a&limit=100&address=a'.format(ID_B) - a paging property that matches the paging response - a data property that is a list of 1 leaf dict - one leaf that matches the Protobuf response """ paging = Mocks.make_paging_response("", "a", DEFAULT_LIMIT) entries = Mocks.make_entries(a=b'2') self.connection.preset_response(state_root='beef', paging=paging, entries=entries) self.connection.preset_response( proto=client_block_pb2.ClientBlockGetResponse, block=block_pb2.Block( header_signature=ID_B, header=block_pb2.BlockHeader( state_root_hash='beef').SerializeToString())) response = await self.get_assert_200( '/state?address=a&head={}'.format(ID_B)) self.connection.assert_valid_request_sent( state_root='beef', address='a', paging=Mocks.make_paging_controls()) self.assert_has_valid_head(response, ID_B) self.assert_has_valid_link( response, '/state?head={}&start=a&limit=100&address=a'.format(ID_B)) self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 1) self.assert_entries_match(entries, response['data'])
async def test_state_list(self): """Verifies a GET /state without parameters works properly. It will receive a Protobuf response with: - a state root of ID_C - a paging response with start of "a" and a limit of 100 - three entries with addresses/data of: * 'a': b'3' * 'b': b'5' * 'c': b'7' It should send a Protobuf request with: - empty paging controls It should send back a JSON response with: - a response status of 200 - a head property of ID_C - a link property that ends in /state?head={}&start=a&limit=100'.format(ID_C) - a paging property that matches the paging response - a data property that is a list of 3 leaf dicts - three entries that match those in Protobuf response """ paging = Mocks.make_paging_response("", "a", DEFAULT_LIMIT) entries = Mocks.make_entries(a=b'3', b=b'5', c=b'7') self.connection.preset_response(state_root='beef', paging=paging, entries=entries) self.connection.preset_response( proto=client_block_pb2.ClientBlockGetResponse, block=block_pb2.Block( header_signature=ID_C, header=block_pb2.BlockHeader( state_root_hash='beef').SerializeToString())) response = await self.get_assert_200('/state') controls = Mocks.make_paging_controls() self.connection.assert_valid_request_sent( state_root='beef', paging=controls) self.assert_has_valid_head(response, ID_C) self.assert_has_valid_link( response, '/state?head={}&start=a&limit=100'.format(ID_C)) self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 3) self.assert_entries_match(entries, response['data'])
async def test_batch_list_with_head_and_ids(self): """Verifies GET /batches with head and id parameters work properly. It should send a Protobuf request with: - a head_id property of ID_B - a paging reponse with a start of ID_B and limit of 100 - a batch_ids property of [ID_A] It will receive a Protobuf response with: - a head id of ID_B - one batch with an id of ID_A - empty paging controls It should send back a JSON response with: - a response status of 200 - a head property of ID_B - a link property that ends in '/batches?head={}&start={}&limit=100&id={}' .format(ID_B, ID_B, ID_A) - a paging property that matches the paging response - a data property that is a list of 1 dict - and that dict is a full batch with an id of ID_A """ paging = Mocks.make_paging_response("", ID_B, DEFAULT_LIMIT) batches = Mocks.make_batches(ID_A) self.connection.preset_response( head_id=ID_B, paging=paging, batches=batches) response = await self.get_assert_200('/batches?id={}&head={}'.format( ID_A, ID_B)) controls = Mocks.make_paging_controls() self.connection.assert_valid_request_sent( head_id=ID_B, batch_ids=[ID_A], paging=controls) self.assert_has_valid_head(response, ID_B) self.assert_has_valid_link( response, '/batches?head={ID_B}&start={ID_B}&limit=100&id={ID_A}'.format( ID_B=ID_B, ID_A=ID_A)) self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 1) self.assert_batches_well_formed(response['data'], ID_A)
async def test_state_list_paginated_with_just_limit(self): """Verifies GET /state paginated just by limit works properly. It will receive a Protobuf response with: - a head id of ID_D - a paging response with a start of d and limit of 2 - two entries of {ID_D: b'4'}, and {'c': b'3'} It should send a Protobuf request with: - a paging controls with a limit of 2 It should send back a JSON response with: - a response status of 200 - a head property of ID_D - a link property that ends in '/state?head={}&start=d&limit=2'.format(ID_D) - paging that matches the response with a next link - a data property that is a list of 2 dicts - and those dicts are entries that match those received """ paging = Mocks.make_paging_response("b", "d", 2) entries = Mocks.make_entries(d=b'4', c=b'3') self.connection.preset_response(state_root='beef', paging=paging, entries=entries) self.connection.preset_response( proto=client_block_pb2.ClientBlockGetResponse, block=block_pb2.Block( header_signature=ID_D, header=block_pb2.BlockHeader( state_root_hash='beef').SerializeToString())) response = await self.get_assert_200('/state?limit=2') controls = Mocks.make_paging_controls(2) self.connection.assert_valid_request_sent( state_root='beef', paging=controls) self.assert_has_valid_head(response, ID_D) self.assert_has_valid_link( response, '/state?head={}&start=d&limit=2'.format(ID_D)) self.assert_has_valid_paging( response, paging, '/state?head={}&start=b&limit=2'.format(ID_D)) self.assert_has_valid_data_list(response, 2) self.assert_entries_match(entries, response['data'])
async def test_state_list_paginated(self): """Verifies GET /state paginated by works properly. It will receive a Protobuf response with: - a head id of ID_D - a paging response with a start of 2 - one leaf of {'c': b'3'} It should send a Protobuf request with: - a paging controls with a limit of 1, and a start of 1 It should send back a JSON response with: - a response status of 200 - a head property of ID_D - a link property that ends in '/state?head={}&start=c&limit=1'.format(ID_D) - paging that matches the response, with next and previous links - a data property that is a list of 1 dict - and that dict is a leaf that matches the one received """ paging = Mocks.make_paging_response("b", "c", 1) entries = Mocks.make_entries(c=b'3') self.connection.preset_response(state_root='beef', paging=paging, entries=entries) self.connection.preset_response( proto=client_block_pb2.ClientBlockGetResponse, block=block_pb2.Block( header_signature=ID_D, header=block_pb2.BlockHeader( state_root_hash='beef').SerializeToString())) response = await self.get_assert_200('/state?start=c&limit=1') controls = Mocks.make_paging_controls(1, start="c") self.connection.assert_valid_request_sent( state_root='beef', paging=controls) self.assert_has_valid_head(response, ID_D) self.assert_has_valid_link( response, '/state?head={}&start=c&limit=1'.format(ID_D)) self.assert_has_valid_paging( response, paging, '/state?head={}&start=b&limit=1'.format(ID_D)) self.assert_has_valid_data_list(response, 1) self.assert_entries_match(entries, response['data'])
async def test_txn_list_with_ids(self): """Verifies GET /transactions with an id filter works properly. It will receive a Protobuf response with: - a head id of ID_C - a paging response with a start of ID_C and limit of 100 - two transactions with ids of ID_A and ID_C It should send a Protobuf request with: - a transaction_ids property of [ID_A, ID_C] - empty paging controls It should send back a JSON response with: - a response status of 200 - a head property of ID_C, the latest - a link property that ends in '/transactions?head={}&start={}&limit=100&id={},{}' .format(ID_C, ID_C, ID_A, ID_C)) - a paging property that matches the paging response - a data property that is a list of 2 dicts - those dicts are full transactions with ids ID_A and ID_C """ paging = Mocks.make_paging_response("", ID_C, DEFAULT_LIMIT) transactions = Mocks.make_txns(ID_A, ID_C) self.connection.preset_response( head_id=ID_C, paging=paging, transactions=transactions) response = await self.get_assert_200('/transactions?id={},{}'.format( ID_A, ID_C)) controls = Mocks.make_paging_controls() self.connection.assert_valid_request_sent( transaction_ids=[ID_A, ID_C], paging=controls) self.assert_has_valid_head(response, ID_C) link =\ '/transactions?head={ID_C}&start={ID_C}&limit=100&id={ID_A},{ID_C}' self.assert_has_valid_link( response, link.format(ID_C=ID_C, ID_A=ID_A)) self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 2) self.assert_txns_well_formed(response['data'], ID_A, ID_C)
async def test_txn_list_sorted_in_reverse(self): """Verifies a GET /transactions can send proper sort parameters. It will receive a Protobuf response with: - a head id of ID_C - a paging response with start of ID_C and limit of 100 - three transactions with ids ID_C, ID_B, and ID_A It should send a Protobuf request with: - empty paging controls - sort controls with a key of 'header_signature' that is reversed It should send back a JSON response with: - a status of 200 - a head property of ID_C - a link property ending in '/transactions?head={}&start={}&limit=100&reverse' .format(ID_C, ID_C)) - a paging property that matches the paging response - a data property that is a list of 3 dicts - and those dicts are full transactions with ids ID_C, ID_B, and ID_A """ paging = Mocks.make_paging_response("", ID_C, DEFAULT_LIMIT) transactions = Mocks.make_txns(ID_C, ID_B, ID_A) self.connection.preset_response( head_id=ID_C, paging=paging, transactions=transactions) response = await self.get_assert_200('/transactions?reverse') page_controls = Mocks.make_paging_controls() sorting = Mocks.make_sort_controls("default", reverse=True) self.connection.assert_valid_request_sent( paging=page_controls, sorting=sorting) self.assert_has_valid_head(response, ID_C) self.assert_has_valid_link( response, '/transactions?head={ID_C}&start={ID_C}&limit=100&reverse'.format( ID_C=ID_C)) self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 3) self.assert_txns_well_formed(response['data'], ID_C, ID_B, ID_A)
async def test_state_list_paginated_by_start_id(self): """Verifies GET /state paginated by a start id works properly. It will receive a Protobuf response with: - a head id of ID_D - a paging response with a start of c and limit of 5 - three entries of {'c': b'3'}, {'b': b'2'}, and {'a': b'1'} It should send a Protobuf request with: - a paging controls with a start_id of ID_C It should send back a JSON response with: - a response status of 200 - a head property of ID_D - a link property that ends in '/state?head={}&start=c&limit=5'.format(ID_D, ID_C) - paging that matches the response, with a previous link - a data property that is a list of 3 dicts - and those dicts are entries that match those received """ paging = Mocks.make_paging_response("", "c", 5) entries = Mocks.make_entries(c=b'3', b=b'2', a=b'1') self.connection.preset_response(state_root='beef', paging=paging, entries=entries) self.connection.preset_response( proto=client_block_pb2.ClientBlockGetResponse, block=block_pb2.Block( header_signature=ID_D, header=block_pb2.BlockHeader( state_root_hash='beef').SerializeToString())) response = await self.get_assert_200('/state?start=c&limit=5') controls = Mocks.make_paging_controls(5, "c") self.connection.assert_valid_request_sent( state_root='beef', paging=controls) self.assert_has_valid_head(response, ID_D) self.assert_has_valid_link( response, '/state?head={}&start=c&limit=5'.format(ID_D)) self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 3) self.assert_entries_match(entries, response['data'])
async def test_state_list_paginated_without_count(self): """Verifies GET /state paginated without count works properly. It will receive a Protobuf response with: - a head id of ID_D - a paging response start of "b" and limit of 100 - two entries of {'b': b'2'} and {'a': b'1'} It should send a Protobuf request with: - a paging controls with a start of 2 It should send back a JSON response with: - a response status of 200 - a head property of ID_D - a link property that ends in '/state?head={}&start=b&limit=100'.format(ID_D)) - paging that matches the response, with a previous link - a data property that is a list of 2 dicts - and those dicts are entries that match those received """ paging = Mocks.make_paging_response("", "b", DEFAULT_LIMIT) entries = Mocks.make_entries(b=b'2', a=b'1') self.connection.preset_response(state_root='beef', paging=paging, entries=entries) self.connection.preset_response( proto=client_block_pb2.ClientBlockGetResponse, block=block_pb2.Block( header_signature=ID_D, header=block_pb2.BlockHeader( state_root_hash='beef').SerializeToString())) response = await self.get_assert_200('/state?start=2') controls = Mocks.make_paging_controls(None, start="2") self.connection.assert_valid_request_sent( state_root='beef', paging=controls) self.assert_has_valid_head(response, ID_D) self.assert_has_valid_link( response, '/state?head={}&start=b&limit=100'.format(ID_D)) self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 2) self.assert_entries_match(entries, response['data'])
async def test_block_list_paginated(self): """Verifies GET /blocks paginated by min id works properly. It will receive a Protobuf response with: - a head id of ID_D - a paging response with a next of '0x0002', start of 0x0003 and limit of 1 - one block with the id ID_C It should send a Protobuf request with: - paging controls with a limit of 1, and a start_id of start='0x0003' It should send back a JSON response with: - a response status of 200 - a head property of ID_D - a link property that ends in '/blocks?head={}&start=1&limit=1'.format(ID_D) - paging that matches the response, with next and previous links - a data property that is a list of 1 dict - and that dict is a full block with the id ID_C """ # Block list only returns a next id paging = Mocks.make_paging_response('0x0002', "0x0003", 1) blocks = Mocks.make_blocks(ID_C) self.connection.preset_response( head_id=ID_D, paging=paging, blocks=blocks) response = await self.get_assert_200('/blocks?start=0x0003&limit=1') controls = Mocks.make_paging_controls(1, start='0x0003') self.connection.assert_valid_request_sent(paging=controls) self.assert_has_valid_head(response, ID_D) self.assert_has_valid_link( response, '/blocks?head={}&start=0x0003&limit=1'.format(ID_D)) self.assert_has_valid_paging( response, paging, '/blocks?head={}&start=0x0002&limit=1'.format(ID_D)) self.assert_has_valid_data_list(response, 1) self.assert_blocks_well_formed(response['data'], ID_C)
async def test_block_list_paginated_with_just_limit(self): """Verifies GET /blocks paginated just by limit works properly. It will receive a Protobuf response with: - a head id of ID_D - a paging response with a next of 0x0002, start of 0x004 and limit of 2 - two blocks with the ids ID_D and ID_C It should send a Protobuf request with: - paging controls with a limit of 2 It should send back a JSON response with: - a response status of 200 - a head property of ID_D - a link property that ends in '/blocks?head={}&start=0x0004&limit=2'.format(ID_D) - paging that matches the response with a next link - a data property that is a list of 2 dicts - and those dicts are full blocks with ids ID_D and ID_C """ # Block list only returns a next id paging = Mocks.make_paging_response('0x0002', '0x0004', 2) blocks = Mocks.make_blocks(ID_D, ID_C) self.connection.preset_response( head_id=ID_D, paging=paging, blocks=blocks) response = await self.get_assert_200('/blocks?limit=2') controls = Mocks.make_paging_controls(2) self.connection.assert_valid_request_sent(paging=controls) self.assert_has_valid_head(response, ID_D) self.assert_has_valid_link( response, '/blocks?head={}&start=0x0004&limit=2'.format(ID_D)) self.assert_has_valid_paging( response, paging, '/blocks?head={}&start=0x0002&limit=2'.format(ID_D)) self.assert_has_valid_data_list(response, 2) self.assert_blocks_well_formed(response['data'], ID_D, ID_C)
async def test_txn_list_paginated_with_just_limit(self): """Verifies GET /transactions paginated just by limit works properly. It will receive a Protobuf response with: - a head id of ID_D - a paging response with a start of ID_D, next of ID_B and limit of 2 - two transactions with the ids ID_D and ID_C It should send a Protobuf request with: - paging controls with a limit of 2 It should send back a JSON response with: - a response status of 200 - a head property of ID_D - a link property that ends in '/transactions?head={}&start={}&limit=2'.format(ID_D, ID_D)) - paging that matches the response with a next link - a data property that is a list of 2 dicts - those dicts are full transactions with ids ID_D and ID_C """ paging = Mocks.make_paging_response(ID_B, ID_D, 2) self.connection.preset_response( head_id=ID_D, paging=paging, transactions=Mocks.make_txns(ID_D, ID_C)) response = await self.get_assert_200('/transactions?limit=2') controls = Mocks.make_paging_controls(2) self.connection.assert_valid_request_sent(paging=controls) self.assert_has_valid_head(response, ID_D) self.assert_has_valid_link( response, '/transactions?head={ID_D}&start={ID_D}&limit=2'.format( ID_D=ID_D)) self.assert_has_valid_paging( response, paging, '/transactions?head={}&start={}&limit=2'.format( ID_D, ID_B)) self.assert_has_valid_data_list(response, 2) self.assert_txns_well_formed(response['data'], ID_D, ID_C)
async def test_batch_list_paginated(self): """Verifies GET /batches paginated by start works properly. It will receive a Protobuf response with: - a head id of ID_D - a paging response with a start of ID_D, next of ID_C and limit of 1 - one batch with the id ID_C It should send a Protobuf request with: - paging controls with a start of 1 It should send back a JSON response with: - a response status of 200 - a head property of ID_D - a link property that ends in '/batches?head={}&start={}&limit=1'.format(ID_D, ID_D) - paging that matches the response, with next and previous links - a data property that is a list of 1 dict - and that dict is a full batch with the id ID_C """ paging = Mocks.make_paging_response(ID_C, ID_D, 1) batches = Mocks.make_batches(ID_C) self.connection.preset_response( head_id=ID_D, paging=paging, batches=batches) response = await self.get_assert_200('/batches?start=1&limit=1') controls = Mocks.make_paging_controls(1, start="1") self.connection.assert_valid_request_sent(paging=controls) self.assert_has_valid_head(response, ID_D) self.assert_has_valid_link( response, '/batches?head={ID_D}&start={ID_D}&limit=1'.format( ID_D=ID_D)) self.assert_has_valid_paging( response, paging, '/batches?head={}&start={}&limit=1'.format( ID_D, ID_C)) self.assert_has_valid_data_list(response, 1) self.assert_batches_well_formed(response['data'], ID_C)
async def test_txn_list_with_head(self): """Verifies a GET /transactions with a head parameter works properly. It will receive a Protobuf response with: - a head id of ID_B - a paging response with a start of ID_B and limit of 100 - two transactions with ids of 1' and ID_A It should send a Protobuf request with: - a head_id property of ID_B - empty paging controls It should send back a JSON response with: - a response status of 200 - a head property of ID_B - a link property that ends in '/transactions?head={}&start={}&limit=100'.format(ID_B, ID_B)) - a paging property that matches the paging response - a data property that is a list of 2 dicts - those dicts are full transactions with ids ID_B and ID_A """ paging = Mocks.make_paging_response("", ID_B, DEFAULT_LIMIT) self.connection.preset_response( head_id=ID_B, paging=paging, transactions=Mocks.make_txns(ID_B, ID_A)) response = await self.get_assert_200( '/transactions?head={}'.format(ID_B)) controls = Mocks.make_paging_controls() self.connection.assert_valid_request_sent( head_id=ID_B, paging=controls) self.assert_has_valid_head(response, ID_B) self.assert_has_valid_link( response, '/transactions?head={ID_B}&start={ID_B}&limit=100'.format( ID_B=ID_B)) self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 2) self.assert_txns_well_formed(response['data'], ID_B, ID_A)
async def test_txn_list_paginated_without_count(self): """Verifies GET /transactions paginated without count works properly. It will receive a Protobuf response with: - a head id of ID_D - a paging response with a start of ID_D and a limit of 100 - two transactions with the ids ID_B and ID_A It should send a Protobuf request with: - paging controls with a start of 2 It should send back a JSON response with: - a response status of 200 - a head property of ID_D - a link property that ends in '/transactions?head={}&start={}&limit=100'.format(ID_D, ID_D)) - paging that matches the response, with a previous link - a data property that is a list of 2 dicts - those dicts are full transactions with ids ID_D and ID_C """ paging = Mocks.make_paging_response("", ID_D, DEFAULT_LIMIT) self.connection.preset_response(head_id=ID_D, paging=paging, transactions=Mocks.make_txns( ID_B, ID_A)) response = await self.get_assert_200('/transactions?start=2') controls = Mocks.make_paging_controls(None, start="2") self.connection.assert_valid_request_sent(paging=controls) self.assert_has_valid_head(response, ID_D) self.assert_has_valid_link( response, '/transactions?head={ID_D}&start={ID_D}&limit=100'.format( ID_D=ID_D)) self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 2) self.assert_txns_well_formed(response['data'], ID_B, ID_A)
async def test_txn_list_sorted_with_nested_keys(self): """Verifies GET /transactions can send proper sort controls with nested keys. It will receive a Protobuf response with: - a head id of '2' - a paging response with a start of 0, and 3 total resources - three transactions with ids '0', '1', and '2' It should send a Protobuf request with: - empty paging controls - sort controls with keys of 'header' and 'signer_public_key' It should send back a JSON response with: - a status of 200 - a head property of '2' - a link ending in '/transactions?head=2&sort=header.signer_public_key' - a paging property that matches the paging response - a data property that is a list of 3 dicts - and those dicts are full transactions with ids '0', '1', and '2' """ paging = Mocks.make_paging_response(0, 3) transactions = Mocks.make_txns('0', '1', '2') self.connection.preset_response(head_id='2', paging=paging, transactions=transactions) response = await self.get_assert_200( '/transactions?sort=header.signer_public_key') page_controls = Mocks.make_paging_controls() sorting = Mocks.make_sort_controls('header', 'signer_public_key') self.connection.assert_valid_request_sent( paging=page_controls, sorting=sorting) self.assert_has_valid_head(response, '2') self.assert_has_valid_link(response, '/transactions?head=2&sort=header.signer_public_key') self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 3) self.assert_txns_well_formed(response['data'], '0', '1', '2')
async def test_batch_list_paginated(self): """Verifies GET /batches paginated by start works properly. It will receive a Protobuf response with: - a head id of ID_D - a paging response with a start of ID_D, next of ID_C and limit of 1 - one batch with the id ID_C It should send a Protobuf request with: - paging controls with a start of 1 It should send back a JSON response with: - a response status of 200 - a head property of ID_D - a link property that ends in '/batches?head={}&start={}&limit=1'.format(ID_D, ID_D) - paging that matches the response, with next and previous links - a data property that is a list of 1 dict - and that dict is a full batch with the id ID_C """ paging = Mocks.make_paging_response(ID_C, ID_D, 1) batches = Mocks.make_batches(ID_C) self.connection.preset_response(head_id=ID_D, paging=paging, batches=batches) response = await self.get_assert_200('/batches?start=1&limit=1') controls = Mocks.make_paging_controls(1, start="1") self.connection.assert_valid_request_sent(paging=controls) self.assert_has_valid_head(response, ID_D) self.assert_has_valid_link( response, '/batches?head={}&start={}&limit=1'.format(ID_D, ID_D)) self.assert_has_valid_paging( response, paging, '/batches?head={}&start={}&limit=1'.format(ID_D, ID_C)) self.assert_has_valid_data_list(response, 1) self.assert_batches_well_formed(response['data'], ID_C)
async def test_batch_list_with_head(self): """Verifies a GET /batches with a head parameter works properly. It will receive a Protobuf response with: - a head id of ID_B - a paging response with a start ID_B and limit 100 - two batches with ids of 1' and ID_A It should send a Protobuf request with: - a head_id property of ID_B - empty paging controls It should send back a JSON response with: - a response status of 200 - a head property of ID_B - a link property that ends in '/batches?head={}&start={}&limit=100'.format(ID_B, ID_B)) - a paging property that matches the paging response - a data property that is a list of 2 dicts - and those dicts are full batches with ids ID_B and ID_A """ paging = Mocks.make_paging_response("", ID_B, DEFAULT_LIMIT) batches = Mocks.make_batches(ID_B, ID_A) self.connection.preset_response(head_id=ID_B, paging=paging, batches=batches) response = await self.get_assert_200('/batches?head={}'.format(ID_B)) controls = Mocks.make_paging_controls() self.connection.assert_valid_request_sent(head_id=ID_B, paging=controls) self.assert_has_valid_head(response, ID_B) self.assert_has_valid_link( response, '/batches?head={}&start={}&limit=100'.format(ID_B, ID_B)) self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 2) self.assert_batches_well_formed(response['data'], ID_B, ID_A)
async def test_batch_list_paginated_with_just_limit(self): """Verifies GET /batches paginated just by limit works properly. It will receive a Protobuf response with: - a head id of ID_D - a paging response with a start ID_D, next ID_B, and limit pf 2 - two batches with the ids ID_D and ID_C It should send a Protobuf request with: - paging controls with a limit of 2 It should send back a JSON response with: - a response status of 200 - a head property of ID_D - a link property that ends in '/batches?head={}&start={}&limit=2'.format(ID_D, ID_D) - paging that matches the response with a next link - a data property that is a list of 2 dicts - and those dicts are full batches with ids ID_D and ID_C """ paging = Mocks.make_paging_response(ID_B, ID_D, 2) batches = Mocks.make_batches(ID_D, ID_C) self.connection.preset_response(head_id=ID_D, paging=paging, batches=batches) response = await self.get_assert_200('/batches?limit=2') controls = Mocks.make_paging_controls(2) self.connection.assert_valid_request_sent(paging=controls) self.assert_has_valid_head(response, ID_D) self.assert_has_valid_link( response, '/batches?head={}&start={}&limit=2'.format(ID_D, ID_D)) self.assert_has_valid_paging( response, paging, '/batches?head={}&start={}&limit=2'.format(ID_D, ID_B)) self.assert_has_valid_data_list(response, 2) self.assert_batches_well_formed(response['data'], ID_D, ID_C)
async def test_txn_list_paginated_by_min_id(self): """Verifies GET /transactions paginated by a min id works properly. It will receive a Protobuf response with: - a head id of 'd' - a paging response with: * a start_index of 1 * total_resources of 4 * a previous_id of 'd' - three transactions with the ids 'c', 'b' and 'a' It should send a Protobuf request with: - paging controls with a count of 5, and a start_id of 'c' It should send back a JSON response with: - a response status of 200 - a head property of 'd' - a link property that ends in '/transactions?head=d&min=c&count=5' - paging that matches the response, with a previous link - a data property that is a list of 3 dicts - those dicts are full transactions with ids 'c', 'b', and 'a' """ paging = Mocks.make_paging_response(1, 4, previous_id='d') self.connection.preset_response( head_id='d', paging=paging, transactions=Mocks.make_txns('c', 'b', 'a')) response = await self.get_assert_200('/transactions?min=c&count=5') controls = Mocks.make_paging_controls(5, start_id='c') self.connection.assert_valid_request_sent(paging=controls) self.assert_has_valid_head(response, 'd') self.assert_has_valid_link(response, '/transactions?head=d&min=c&count=5') self.assert_has_valid_paging(response, paging, previous_link='/transactions?head=d&max=d&count=5') self.assert_has_valid_data_list(response, 3) self.assert_txns_well_formed(response['data'], 'c', 'b', 'a')
async def test_batch_list_paginated_by_start_id(self): """Verifies GET /batches paginated by a start id works properly. It will receive a Protobuf response with: - a head id of ID_D - an empty paging response - three batches with the ids ID_C, ID_B and ID_A It should send a Protobuf request with: - paging controls with a limit of 5, and a start of ID_C It should send back a JSON response with: - a response status of 200 - a head property of ID_D - a link property that ends in '/batches?head={}&start={}&limit=5' .format(ID_D, ID_C) - paging that matches the response, with a previous link - a data property that is a list of 3 dicts - and those dicts are full batches with ids ID_C, ID_B, and ID_A """ paging = Mocks.make_paging_response("", ID_C, 5) batches = Mocks.make_batches(ID_C, ID_B, ID_A) self.connection.preset_response(head_id=ID_D, paging=paging, batches=batches) response = await self.get_assert_200( '/batches?start={}&limit=5'.format(ID_C)) controls = Mocks.make_paging_controls(5, start=ID_C) self.connection.assert_valid_request_sent(paging=controls) self.assert_has_valid_head(response, ID_D) self.assert_has_valid_link( response, '/batches?head={}&start={}&limit=5'.format(ID_D, ID_C)) self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 3) self.assert_batches_well_formed(response['data'], ID_C, ID_B, ID_A)
async def test_block_list_paginated_by_max_id(self): """Verifies GET /blocks paginated by a max id works properly. It will receive a Protobuf response with: - a head id of 'd' - a paging response with: * a start_index of 1 * a total_resources of 4 * a previous_id of 'd' * a next_id of 'a' - two blocks with the ids 'c' and 'b' It should send a Protobuf request with: - paging controls with a count of 2, and an end_id of 'b' It should send back a JSON response with: - a response status of 200 - a head property of 'd' - a link property that ends in '/blocks?head=d&max=b&count=2' - paging that matches the response, with next and previous links - a data property that is a list of 2 dicts - and those dicts are full blocks with ids 'c' and 'b' """ paging = Mocks.make_paging_response(1, 4, previous_id='d', next_id='a') blocks = Mocks.make_blocks('c', 'b') self.connection.preset_response(head_id='d', paging=paging, blocks=blocks) response = await self.get_assert_200('/blocks?max=b&count=2') controls = Mocks.make_paging_controls(2, end_id='b') self.connection.assert_valid_request_sent(paging=controls) self.assert_has_valid_head(response, 'd') self.assert_has_valid_link(response, '/blocks?head=d&max=b&count=2') self.assert_has_valid_paging(response, paging, '/blocks?head=d&min=a&count=2', '/blocks?head=d&max=d&count=2') self.assert_has_valid_data_list(response, 2) self.assert_blocks_well_formed(response['data'], 'c', 'b')
async def test_txn_list(self): """Verifies a GET /transactions without parameters works properly. It will receive a Protobuf response with: - a head id of ID_C - a paging response with a start of ID_C and limit of 100 - three transactions with ids of ID_C, ID_B, and ID_A It should send a Protobuf request with: - empty paging controls It should send back a JSON response with: - a response status of 200 - a head property of ID_C - a link property that ends in '/transactions?head={}&start={}&limit=100'.format(ID_C, ID_C) - a paging property that matches the paging response - a data property that is a list of 3 dicts - those dicts are full transactions with ids ID_C, ID_B, and ID_A """ paging = Mocks.make_paging_response("", ID_C, DEFAULT_LIMIT) self.connection.preset_response(head_id=ID_C, paging=paging, transactions=Mocks.make_txns( ID_C, ID_B, ID_A)) response = await self.get_assert_200('/transactions') controls = Mocks.make_paging_controls() self.connection.assert_valid_request_sent(paging=controls) self.assert_has_valid_head(response, ID_C) self.assert_has_valid_link( response, '/transactions?head={ID_C}&start={ID_C}&limit=100'.format( ID_C=ID_C)) self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 3) self.assert_txns_well_formed(response['data'], ID_C, ID_B, ID_A)
async def test_batch_list_sorted_in_reverse(self): """Verifies a GET /batches can send proper sort parameters. It will receive a Protobuf response with: - a head id of '2' - a paging response with a start of 0, and 3 total resources - three batches with ids '2', '1', and '0' It should send a Protobuf request with: - empty paging controls - sort controls with a key of 'header_signature' that is reversed It should send back a JSON response with: - a status of 200 - a head property of '2' - a link property ending in '/batches?head=2&sort=-header_signature' - a paging property that matches the paging response - a data property that is a list of 3 dicts - and those dicts are full batches with ids '2', '1', and '0' """ paging = Mocks.make_paging_response(0, 3) batches = Mocks.make_batches('2', '1', '0') self.connection.preset_response(head_id='2', paging=paging, batches=batches) response = await self.get_assert_200('/batches?sort=-header_signature') page_controls = Mocks.make_paging_controls() sorting = Mocks.make_sort_controls('header_signature', reverse=True) self.connection.assert_valid_request_sent(paging=page_controls, sorting=sorting) self.assert_has_valid_head(response, '2') self.assert_has_valid_link(response, '/batches?head=2&sort=-header_signature') self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 3) self.assert_batches_well_formed(response['data'], '2', '1', '0')
async def test_batch_list_with_head_and_ids(self): """Verifies GET /batches with head and id parameters work properly. It should send a Protobuf request with: - a head_id property of '1' - a paging response with a start of 0, and 1 total resource - a batch_ids property of ['0'] It will receive a Protobuf response with: - a head id of '1' - one batch with an id of '0' - empty paging controls It should send back a JSON response with: - a response status of 200 - a head property of '1' - a link property that ends in '/batches?head=1&id=0' - a paging property that matches the paging response - a data property that is a list of 1 dict - and that dict is a full batch with an id of '0' """ paging = Mocks.make_paging_response(0, 1) batches = Mocks.make_batches('0') self.connection.preset_response(head_id='1', paging=paging, batches=batches) response = await self.get_assert_200('/batches?id=0&head=1') controls = Mocks.make_paging_controls() self.connection.assert_valid_request_sent(head_id='1', batch_ids=['0'], paging=controls) self.assert_has_valid_head(response, '1') self.assert_has_valid_link(response, '/batches?head=1&id=0') self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 1) self.assert_batches_well_formed(response['data'], '0')
async def test_state_list_paginated_by_min_id(self): """Verifies GET /state paginated by a min id works properly. It will receive a Protobuf response with: - a head id of 'd' - a paging response with: * a start_index of 1 * total_resources of 4 * a previous_id of 'd' - three leaves of {'c': b'3'}, {'b': b'2'}, and {'a': b'1'} It should send a Protobuf request with: - a paging controls with a start_id of 'c' It should send back a JSON response with: - a response status of 200 - a head property of 'd' - a link property that ends in '/state?head=d&min=c&count=5' - paging that matches the response, with a previous link - a data property that is a list of 3 dicts - and those dicts are leaves that match those received """ paging = Mocks.make_paging_response(1, 4, previous_id='d') leaves = Mocks.make_leaves(c=b'3', b=b'2', a=b'1') self.connection.preset_response(head_id='d', paging=paging, leaves=leaves) response = await self.get_assert_200('/state?min=c&count=5') controls = Mocks.make_paging_controls(5, start_id='c') self.connection.assert_valid_request_sent(paging=controls) self.assert_has_valid_head(response, 'd') self.assert_has_valid_link(response, '/state?head=d&min=c&count=5') self.assert_has_valid_paging( response, paging, previous_link='/state?head=d&max=d&count=5') self.assert_has_valid_data_list(response, 3) self.assert_leaves_match(leaves, response['data'])
async def test_state_list_with_head_and_address(self): """Verifies GET /state works with a head and filtered by address. It will receive a Protobuf response with: - a head id of '1' - a paging response with a start of 0, and 1 total resource - one leaf with addresses/data of: 'a': b'2' It should send a Protobuf request with: - a head_id property of '1' - an address property of 'a' - empty paging controls It should send back a JSON response with: - a response status of 200 - a head property of '1' - a link property that ends in '/state?head=1&min=0&count=1&address=a' - a paging property that matches the paging response - a data property that is a list of 1 leaf dict - one leaf that matches the Protobuf response """ paging = Mocks.make_paging_response(0, 1) entries = Mocks.make_entries(a=b'2') self.connection.preset_response(head_id='1', paging=paging, entries=entries) response = await self.get_assert_200('/state?address=a&head=1') self.connection.assert_valid_request_sent( head_id='1', address='a', paging=Mocks.make_paging_controls()) self.assert_has_valid_head(response, '1') self.assert_has_valid_link(response, '/state?head=1&address=a') self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 1) self.assert_entries_match(entries, response['data'])
async def test_state_list_with_head(self): """Verifies a GET /state works properly with head specified. It will receive a Protobuf response with: - a head id of '1' - a paging response with a start of 0, and 2 total resources - two entries with addresses/data of: * 'a': b'2' * 'b': b'4' It should send a Protobuf request with: - a head_id property of '1' - empty paging controls It should send back a JSON response with: - a response status of 200 - a head property of '1' - a link property that ends in '/state?head=1&min=0&count=2' - a paging property that matches the paging response - a data property that is a list of 2 leaf dicts - three entries that match those in Protobuf response """ paging = Mocks.make_paging_response(0, 2) entries = Mocks.make_entries(a=b'2', b=b'4') self.connection.preset_response(head_id='1', paging=paging, entries=entries) response = await self.get_assert_200('/state?head=1') controls = Mocks.make_paging_controls() self.connection.assert_valid_request_sent(head_id='1', paging=controls) self.assert_has_valid_head(response, '1') self.assert_has_valid_link(response, '/state?head=1') self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 2) self.assert_entries_match(entries, response['data'])
async def test_block_list_paginated(self): """Verifies GET /blocks paginated by min id works properly. It will receive a Protobuf response with: - a head id of 'd' - a paging response with a start of 1, and 4 total resources - one block with the id 'c' It should send a Protobuf request with: - paging controls with a count of 1, and a start_index of 1 It should send back a JSON response with: - a response status of 200 - a head property of 'd' - a link property that ends in '/blocks?head=d&min=1&count=1' - paging that matches the response, with next and previous links - a data property that is a list of 1 dict - and that dict is a full block with the id 'c' """ # Block list only returns a next id paging = Mocks.make_paging_response(None, 4, next_id='0x0002') blocks = Mocks.make_blocks('c') self.connection.preset_response(head_id='d', paging=paging, blocks=blocks) response = await self.get_assert_200('/blocks?min=0x0003&count=1') controls = Mocks.make_paging_controls(1, start_id='0x0003') self.connection.assert_valid_request_sent(paging=controls) self.assert_has_valid_head(response, 'd') self.assert_has_valid_link(response, '/blocks?head=d&min=0x0003&count=1') self.assert_has_valid_paging(response, paging, '/blocks?head=d&min=0x0002&count=1') self.assert_has_valid_data_list(response, 1) self.assert_blocks_well_formed(response['data'], 'c')
async def test_state_list(self): """Verifies a GET /state without parameters works properly. It will receive a Protobuf response with: - a head id of '2' - a paging response with a start of 0, and 3 total resources - three leaves with addresses/data of: * 'a': b'3' * 'b': b'5' * 'c': b'7' It should send a Protobuf request with: - empty paging controls It should send back a JSON response with: - a response status of 200 - a head property of '2' - a link property that ends in '/state?head=2&min=0&count=3' - a paging property that matches the paging response - a data property that is a list of 3 leaf dicts - three leaves that match those in Protobuf response """ paging = Mocks.make_paging_response(0, 3) leaves = Mocks.make_leaves(a=b'3', b=b'5', c=b'7') self.connection.preset_response(head_id='2', paging=paging, leaves=leaves) response = await self.get_assert_200('/state') controls = Mocks.make_paging_controls() self.connection.assert_valid_request_sent(paging=controls) self.assert_has_valid_head(response, '2') self.assert_has_valid_link(response, '/state?head=2') self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 3) self.assert_leaves_match(leaves, response['data'])
async def test_batch_list_with_ids(self): """Verifies GET /batches with an id filter works properly. It will receive a Protobuf response with: - a head id of '2' - a paging response with a start of 0, and 2 total resources - two batches with ids of '0' and '2' It should send a Protobuf request with: - a batch_ids property of ['0', '2'] - empty paging controls It should send back a JSON response with: - a response status of 200 - a head property of '2', the latest - a link property that ends in '/batches?head=2&id=0,2' - a paging property that matches the paging response - a data property that is a list of 2 dicts - and those dicts are full batches with ids '0' and '2' """ paging = Mocks.make_paging_response(0, 2) batches = Mocks.make_batches('0', '2') self.connection.preset_response(head_id='2', paging=paging, batches=batches) response = await self.get_assert_200('/batches?id=0,2') controls = Mocks.make_paging_controls() self.connection.assert_valid_request_sent(batch_ids=['0', '2'], paging=controls) self.assert_has_valid_head(response, '2') self.assert_has_valid_link(response, '/batches?head=2&id=0,2') self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 2) self.assert_batches_well_formed(response['data'], '0', '2')
async def test_block_list_paginated_with_just_count(self): """Verifies GET /blocks paginated just by count works properly. It will receive a Protobuf response with: - a head id of 'd' - a paging response with a start of 0, and 4 total resources - two blocks with the ids 'd' and 'c' It should send a Protobuf request with: - paging controls with a count of 2 It should send back a JSON response with: - a response status of 200 - a head property of 'd' - a link property that ends in '/blocks?head=d' - paging that matches the response with a next link - a data property that is a list of 2 dicts - and those dicts are full blocks with ids 'd' and 'c' """ # Block list only returns a next id paging = Mocks.make_paging_response(None, 4, next_id='0x0002') blocks = Mocks.make_blocks('d', 'c') self.connection.preset_response(head_id='d', paging=paging, blocks=blocks) response = await self.get_assert_200('/blocks?count=2') controls = Mocks.make_paging_controls(2) self.connection.assert_valid_request_sent(paging=controls) self.assert_has_valid_head(response, 'd') self.assert_has_valid_link(response, '/blocks?head=d&count=2') self.assert_has_valid_paging(response, paging, '/blocks?head=d&min=0x0002&count=2') self.assert_has_valid_data_list(response, 2) self.assert_blocks_well_formed(response['data'], 'd', 'c')
async def test_state_list_paginated(self): """Verifies GET /state paginated by min id works properly. It will receive a Protobuf response with: - a head id of 'd' - a paging response with a start of 1, and 4 total resources - one leaf of {'c': b'3'} It should send a Protobuf request with: - a paging controls with a count of 1, and a start_index of 1 It should send back a JSON response with: - a response status of 200 - a head property of 'd' - a link property that ends in '/state?head=d&min=1&count=1' - paging that matches the response, with next and previous links - a data property that is a list of 1 dict - and that dict is a leaf that matches the one received """ paging = Mocks.make_paging_response(1, 4) leaves = Mocks.make_leaves(c=b'3') self.connection.preset_response(head_id='d', paging=paging, leaves=leaves) response = await self.get_assert_200('/state?min=1&count=1') controls = Mocks.make_paging_controls(1, start_index=1) self.connection.assert_valid_request_sent(paging=controls) self.assert_has_valid_head(response, 'd') self.assert_has_valid_link(response, '/state?head=d&min=1&count=1') self.assert_has_valid_paging(response, paging, '/state?head=d&min=2&count=1', '/state?head=d&min=0&count=1') self.assert_has_valid_data_list(response, 1) self.assert_leaves_match(leaves, response['data'])
async def test_txn_list_paginated_by_max_index(self): """Verifies GET /transactions paginated by a max index works properly. It will receive a Protobuf response with: - a head id of 'd' - a paging response with a start of 0, and 4 total resources - three transactions with the ids 'd', 'c' and 'b' It should send a Protobuf request with: - paging controls with a count of 3, and an start_index of 0 It should send back a JSON response with: - a response status of 200 - a head property of 'd' - a link property that ends in '/transactions?head=d&min=3&count=7' - paging that matches the response, with a next link - a data property that is a list of 2 dicts - those dicts are full transactions with ids 'd', 'c', and 'b' """ paging = Mocks.make_paging_response(0, 4) self.connection.preset_response(head_id='d', paging=paging, transactions=Mocks.make_txns( 'd', 'c', 'b')) response = await self.get_assert_200('/transactions?max=2&count=7') controls = Mocks.make_paging_controls(3, start_index=0) self.connection.assert_valid_request_sent(paging=controls) self.assert_has_valid_head(response, 'd') self.assert_has_valid_link(response, '/transactions?head=d&max=2&count=7') self.assert_has_valid_paging(response, paging, '/transactions?head=d&min=3&count=7') self.assert_has_valid_data_list(response, 3) self.assert_txns_well_formed(response['data'], 'd', 'c', 'b')
async def test_txn_list_paginated_without_count(self): """Verifies GET /transactions paginated without count works properly. It will receive a Protobuf response with: - a head id of 'd' - a paging response with a start of 2, and 4 total resources - two transactions with the ids 'b' and 'a' It should send a Protobuf request with: - paging controls with a start_index of 2 It should send back a JSON response with: - a response status of 200 - a head property of 'd' - a link property that ends in '/transactions?head=d&min=2' - paging that matches the response, with a previous link - a data property that is a list of 2 dicts - those dicts are full transactions with ids 'd' and 'c' """ paging = Mocks.make_paging_response(2, 4) self.connection.preset_response(head_id='d', paging=paging, transactions=Mocks.make_txns('b', 'a')) response = await self.get_assert_200('/transactions?min=2') controls = Mocks.make_paging_controls(None, start_index=2) self.connection.assert_valid_request_sent(paging=controls) self.assert_has_valid_head(response, 'd') self.assert_has_valid_link(response, '/transactions?head=d&min=2') self.assert_has_valid_paging( response, paging, previous_link='/transactions?head=d&min=0&count=2') self.assert_has_valid_data_list(response, 2) self.assert_txns_well_formed(response['data'], 'b', 'a')
async def test_state_list_with_address(time=100): """Verifies a GET /state works properly filtered by address. It will receive a Protobuf response with: - a head id of ID_C - an empty paging response - one leaf with addresses/data of: 'c': b'7' It should send a Protobuf request with: - an address property of 'c' - empty paging controls It should send back a JSON response with: - a response status of 200 - a head property of ID_C - a link property that ends in '/state?head={}&start=c&limit=100&address=c'.format(ID_C) - a paging property that matches the paging response - a data property that is a list of 1 leaf dict - one leaf that matches the Protobuf response """ paging = Mocks.make_paging_response("", "c", DEFAULT_LIMIT) entries = Mocks.make_entries(c=b'7') stateListTests.connection.preset_response(state_root='beef', paging=paging, entries=entries) stateListTests.connection.preset_response( proto=client_block_pb2.ClientBlockGetResponse, block=block_pb2.Block( header_signature=ID_C, header=block_pb2.BlockHeader( state_root_hash='beef').SerializeToString())) for _ in range(time): response = await stateListTests.get_assert_200('/state?address=c') print(response)
async def test_txn_list_paginated(self): """Verifies GET /transactions paginated by min id works properly. It will receive a Protobuf response with: - a head id of 'd' - a paging response with a start of 1, and 4 total resources - one transaction with the id 'c' It should send a Protobuf request with: - paging controls with a count of 1, and a start_index of 1 It should send back a JSON response with: - a response status of 200 - a head property of 'd' - a link property that ends in '/transactions?head=d&min=1&count=1' - paging that matches the response, with next and previous links - a data property that is a list of 1 dict - that dict is a full transaction with the id 'c' """ paging = Mocks.make_paging_response(1, 4) self.connection.preset_response( head_id='d', paging=paging, transactions=Mocks.make_txns('c')) response = await self.get_assert_200('/transactions?min=1&count=1') controls = Mocks.make_paging_controls(1, start_index=1) self.connection.assert_valid_request_sent(paging=controls) self.assert_has_valid_head(response, 'd') self.assert_has_valid_link(response, '/transactions?head=d&min=1&count=1') self.assert_has_valid_paging(response, paging, '/transactions?head=d&min=2&count=1', '/transactions?head=d&min=0&count=1') self.assert_has_valid_data_list(response, 1) self.assert_txns_well_formed(response['data'], 'c')
async def test_post_rejected_due_to_full_queue(self): """Verifies a POST /batches when the validator reports QUEUE_FULL breaks properly. It will receive a Protobuf response with: - a status of QUEUE_FULL It should send back a JSON response with: - a response status of 429 - an error property with a code of 31 """ batches = Mocks.make_batches(ID_A) self.connection.preset_response(self.status.QUEUE_FULL) request = await self.post_batches(batches) self.assertEqual(429, request.status) response = await request.json() self.assert_has_valid_error(response, 31)
async def test_post_invalid_batch(self): """Verifies a POST /batches with an invalid batch breaks properly. It will receive a Protobuf response with: - a status of INVALID_BATCH It should send back a JSON response with: - a response status of 400 - an error property with a code of 30 """ batches = Mocks.make_batches('bad') self.connection.preset_response(self.status.INVALID_BATCH) request = await self.post_batches(batches) self.assertEqual(400, request.status) response = await request.json() self.assert_has_valid_error(response, 30)
async def test_post_batch_with_validator_error(self): """Verifies a POST /batches with a validator error breaks properly. It will receive a Protobuf response with: - a status of INTERNAL_ERROR It should send back a JSON response with: - a status of 500 - an error property with a code of 10 """ batches = Mocks.make_batches(ID_A) self.connection.preset_response(self.status.INTERNAL_ERROR) request = await self.post_batches(batches) self.assertEqual(500, request.status) response = await request.json() self.assert_has_valid_error(response, 10)
async def test_txn_get(self): """Verifies a GET /transactions/{transaction_id} works properly. It should send a Protobuf request with: - a transaction_id property of '1' It will receive a Protobuf response with: - a transaction with an id of '1' It should send back a JSON response with: - a response status of 200 - no head property - a link property that ends in '/transactions/1' - a data property that is a full batch with an id of '1' """ self.connection.preset_response(transaction=Mocks.make_txns('1')[0]) response = await self.get_assert_200('/transactions/1') self.connection.assert_valid_request_sent(transaction_id='1') self.assertNotIn('head', response) self.assert_has_valid_link(response, '/transactions/1') self.assertIn('data', response) self.assert_txns_well_formed(response['data'], '1')
async def test_post_batch(self): """Verifies a POST /batches with one id works properly. It will receive a Protobuf response with: - the default status of OK It should send a Protobuf request with: - a batches property that matches the batches sent It should send back a JSON response with: - a response status of 202 - no data property - a link property that ends in '/batch_status?id=a' """ batches = Mocks.make_batches('a') self.connection.preset_response() request = await self.post_batches(batches) self.connection.assert_valid_request_sent(batches=batches) self.assertEqual(202, request.status) response = await request.json() self.assertNotIn('data', response) self.assert_has_valid_link(response, '/batch_status?id=a')
async def test_txn_get(self): """Verifies a GET /transactions/{transaction_id} works properly. It should send a Protobuf request with: - a transaction_id property of ID_B It will receive a Protobuf response with: - a transaction with an id of ID_B It should send back a JSON response with: - a response status of 200 - no head property - a link property that ends in '/transactions/{}'.format(ID_B) - a data property that is a full batch with an id of ID_B """ self.connection.preset_response(transaction=Mocks.make_txns(ID_B)[0]) response = await self.get_assert_200('/transactions/{}'.format(ID_B)) self.connection.assert_valid_request_sent(transaction_id=ID_B) self.assertNotIn('head', response) self.assert_has_valid_link(response, '/transactions/{}'.format(ID_B)) self.assertIn('data', response) self.assert_txns_well_formed(response['data'], ID_B)
async def test_block_get(self): """Verifies a GET /blocks/{block_id} works properly. It should send a Protobuf request with: - a block_id property of ID_B It will receive a Protobuf response with: - a block with an id of ID_B It should send back a JSON response with: - a response status of 200 - no head property - a link property that ends in '/blocks/{}'.format(ID_B) - a data property that is a full block with an id of ID_A """ self.connection.preset_response(block=Mocks.make_blocks(ID_B)[0]) response = await self.get_assert_200('/blocks/{}'.format(ID_B)) self.connection.assert_valid_request_sent(block_id=ID_B) self.assertNotIn('head', response) self.assert_has_valid_link(response, '/blocks/{}'.format(ID_B)) self.assertIn('data', response) self.assert_blocks_well_formed(response['data'], ID_B)
async def test_batch_list_with_bad_ids(self): """Verifies GET /batches with a bad id filter breaks properly. It will receive a Protobuf response with: - a status of NO_RESOURCE - a head id of '2' It should send back a JSON response with: - a response status of 200 - a head property of '2', the latest - a link property that ends in '/batches?head=2&id=bad,notgood' - a paging property with only a total_count of 0 - a data property that is an empty list """ paging = Mocks.make_paging_response(None, 0) self.connection.preset_response(self.status.NO_RESOURCE, head_id='2', paging=paging) response = await self.get_assert_200('/batches?id=bad,notgood') self.assert_has_valid_head(response, '2') self.assert_has_valid_link(response, '/batches?head=2&id=bad,notgood') self.assert_has_valid_paging(response, paging) self.assert_has_valid_data_list(response, 0)