async def test_happy_path(self): """ Test command flow executes as expected. """ # Call the command with a tail hash. # Let's mock away GetBundlesCommand, and we don't do # BroadcastTransactionsCommand either. # We could seed a response to our MockAdapter, but then we shall provide # valid values to pass GetBundlesRequestFilter. Instead we mock away the # whole command, so no filter is applied. It is safe because it is tested # elsewhere. with patch( 'iota.commands.extended.get_bundles.GetBundlesCommand.__call__', MagicMock(return_value=async_return( [self.trytes]))) as mocked_get_bundles: # We could seed a reponse to our MockAdapter, but then the returned value # from `GetBundlesCommand` shall be valid to pass # BroadcastTransactionRequestFilter. # Anyway, nature loves symmetry and so do we. with patch( 'iota.commands.core.BroadcastTransactionsCommand.__call__', MagicMock( return_value=async_return([]))) as mocked_broadcast: response = await self.command(tail_hash=self.tail) self.assertEqual(response['trytes'], self.trytes)
async def test_transaction_found(self): """ A transaction is found with the inputs. A transaction object is returned """ with mock.patch( 'iota.commands.core.find_transactions.FindTransactionsCommand.' '_execute', mock.Mock(return_value=async_return( {'hashes': [ self.transaction_hash, ]})), ): with mock.patch( 'iota.commands.core.get_trytes.GetTrytesCommand._execute', mock.Mock( return_value=async_return({'trytes': [ self.trytes, ]})), ): response = await self.command(addresses=[self.address]) self.assertEqual(len(response['transactions']), 1) transaction = response['transactions'][0] self.assertIsInstance(transaction, Transaction) self.assertEqual(transaction.address, self.address)
async def test_non_tail(self): """ Called with a non-tail transaction. """ # For mocking GetTrytesCommand call self.adapter.seed_response( 'getTrytes', { # Tx with ID=1 'trytes': [self.three_tx_bundle[1].as_tryte_string()] }) # For mocking FindTransactionObjectsCommand call self.adapter.seed_response( 'findTransactions', {'hashes': [tx.hash for tx in self.three_tx_bundle]}) self.adapter.seed_response( 'getTrytes', {'trytes': [tx.as_tryte_string() for tx in self.three_tx_bundle]}) with mock.patch( 'iota.commands.extended.get_latest_inclusion.GetLatestInclusionCommand.__call__', MagicMock(return_value=async_return({ 'states': { self.three_tx_bundle.tail_transaction.hash: True } }))) as mocked_glis: with mock.patch( 'iota.commands.extended.get_bundles.GetBundlesCommand.__call__', MagicMock(return_value=async_return( {'bundles': [ self.three_tx_bundle, ]}))) as mocked_get_bundles: response = await get_bundles_from_transaction_hashes( adapter=self.adapter, transaction_hashes=[self.three_tx_bundle[1].hash], inclusion_states=True, ) self.assertListEqual( response, [ self.three_tx_bundle, ], ) self.assertTrue(response[0].is_confirmed) mocked_glis.assert_called_once_with( hashes=[self.three_tx_bundle.tail_transaction.hash]) mocked_get_bundles.assert_called_once_with( transactions=[self.three_tx_bundle.tail_transaction.hash])
async def test_happy_path(self): """ Loading account data for an account. """ async def mock_iter_used_addresses(adapter, seed, start, security_level): """ Mocks the ``iter_used_addresses`` function, so that we can simulate its functionality without actually connecting to the Tangle. References: - :py:func:`iota.commands.extended.utils.iter_used_addresses` """ yield self.addy1, [self.hash1] yield self.addy2, [self.hash2] mock_get_balances = mock.Mock( return_value=async_return({'balances': [42, 0]})) # Not particularly realistic, but good enough to prove that the # mocked function was invoked correctly. bundles = [Bundle(), Bundle()] mock_get_bundles_from_transaction_hashes = mock.Mock( return_value=async_return(bundles)) with mock.patch( 'iota.commands.extended.get_account_data.iter_used_addresses', mock_iter_used_addresses, ): with mock.patch( 'iota.commands.extended.get_account_data.get_bundles_from_transaction_hashes', mock_get_bundles_from_transaction_hashes, ): with mock.patch( 'iota.commands.core.get_balances.GetBalancesCommand._execute', mock_get_balances, ): response = await self.command(seed=Seed.random()) self.assertDictEqual( response, { 'addresses': [self.addy1, self.addy2], 'balance': 42, 'bundles': bundles, }, )
async def test_success_response(self): """ Simulates sending a command to the node and getting a success response. """ adapter = HttpAdapter('http://localhost:14265') payload = {'command': 'helloWorld'} expected_result = {'message': 'Hello, IOTA!'} mocked_response = create_http_response(json.dumps(expected_result)) mocked_sender = mock.Mock(return_value=async_return(mocked_response)) with mock.patch.object(adapter, '_send_http_request', mocked_sender): result = await adapter.send_request(payload) self.assertEqual(result, expected_result) # https://github.com/iotaledger/iota.py/issues/84 mocked_sender.assert_called_once_with( headers={ 'Content-type': 'application/json', 'X-IOTA-API-Version': API_VERSION, }, payload=json.dumps(payload), url=adapter.node_url, )
async def test_exception_response(self): """ Simulates sending a command to the node and getting an exception response. """ adapter = HttpAdapter('http://localhost:14265') error_message = 'java.lang.ArrayIndexOutOfBoundsException: 4' mocked_response = create_http_response( status=500, content=json.dumps({ 'exception': error_message, 'duration': 16, }), ) mocked_sender = mock.Mock(return_value=async_return(mocked_response)) with mock.patch.object(adapter, '_send_http_request', mocked_sender): with self.assertRaises(BadApiResponse) as context: await adapter.send_request({'command': 'helloWorld'}) self.assertEqual( str(context.exception), '500 response from node: {error}'.format(error=error_message), )
async def test_non_200_status(self): """ The node sends back a non-200 response that we don't know how to handle. """ adapter = HttpAdapter('http://localhost') decoded_response = {'message': 'Request limit exceeded.'} mocked_response = create_http_response( status=429, content=json.dumps(decoded_response), ) mocked_sender = mock.Mock(return_value=async_return(mocked_response)) with mock.patch.object(adapter, '_send_http_request', mocked_sender): with self.assertRaises(BadApiResponse) as context: await adapter.send_request({'command': 'helloWorld'}) self.assertEqual( str(context.exception), '429 response from node: {decoded}'.format( decoded=decoded_response), )
async def test_generate_single_digest(self): """ Generating a single digest. """ seed = Seed.random() mock_get_private_keys = mock.Mock( return_value=async_return({'keys': [self.key1]})) with mock.patch( 'iota.multisig.commands.get_private_keys.GetPrivateKeysCommand._execute', mock_get_private_keys): with mock.patch.object( self.key1, 'get_digest') as mock_get_digest_1: # type: mock.MagicMock mock_get_digest_1.return_value = self.digest1 result = await self.command(seed=seed, index=0, count=1, securityLevel=1) self.assertDictEqual(result, {'digests': [self.digest1]}) mock_get_private_keys.assert_called_once_with({ 'count': 1, 'index': 0, 'securityLevel': 1, 'seed': seed, })
async def test_happy_path(self): """ Successfully promoting a bundle. """ self.adapter.seed_response('checkConsistency', { 'state': True, }) result_bundle = Bundle.from_tryte_strings([ TransactionTrytes(self.trytes1), TransactionTrytes(self.trytes2), ]) mock_send_transfer = mock.Mock(return_value=async_return({ 'bundle': result_bundle, })) with mock.patch( 'iota.commands.extended.send_transfer.SendTransferCommand._execute', mock_send_transfer, ): response = await self.command( transaction=self.hash1, depth=3, minWeightMagnitude=16, ) self.assertDictEqual( response, { 'bundle': result_bundle, } )
def mock_send_trytes(_,request): """ Ensures that the correct trytes are sent to the ``sendTrytes`` command to replay the bundle. References: - https://github.com/iotaledger/iota.py/issues/74 """ self.assertEqual(request['trytes'], send_trytes_response['trytes']) return async_return(send_trytes_response)
async def test_happy_path_no_inclusion(self): """ A bundle is successfully fetched without inclusion states. """ self.adapter.seed_response( 'getTrytes', { 'trytes': self.single_bundle.as_tryte_strings() } ) with mock.patch( 'iota.commands.core.get_inclusion_states.GetInclusionStatesCommand.__call__', MagicMock(return_value=async_return({'states': { self.single_bundle.tail_transaction.hash: True }})) ) as mocked_glis: with mock.patch( 'iota.commands.extended.get_bundles.GetBundlesCommand.__call__', MagicMock(return_value=async_return({'bundles': [self.single_bundle]})) ) as mocked_get_bundles: response = await get_bundles_from_transaction_hashes( adapter=self.adapter, transaction_hashes=[self.single_bundle.tail_transaction.hash], inclusion_states=False, ) self.assertListEqual( response, [self.single_bundle], ) self.assertFalse( mocked_glis.called ) mocked_get_bundles.assert_called_once_with( transactions=[self.single_bundle.tail_transaction.hash] ) self.assertFalse( response[0].is_confirmed )
async def test_happy_path_multiple_bundle(self): """ Test if command returns the correct bundle if underlying `get_bundles` returns multiple bundles. """ # Call the command with a tail hash. # Let's mock away GetBundlesCommand, and we don't do # BroadcastTransactionsCommand either. # Note that GetBundlesCommand returns multiple bundles! with patch( 'iota.commands.extended.get_bundles.GetBundlesCommand.__call__', MagicMock(return_value=async_return( [self.trytes, self.trytes_dummy]))) as mocked_get_bundles: with patch( 'iota.commands.core.BroadcastTransactionsCommand.__call__', MagicMock( return_value=async_return([]))) as mocked_broadcast: response = await self.command(tail_hash=self.tail) # Expect only the first bundle self.assertEqual(response['trytes'], self.trytes)
async def test_instance_attribute_timeout(self): # mock for returning dummy response mocked_request = mock.Mock(return_value=async_return( mock.Mock(text='{ "dummy": "payload"}', status_code=200))) # create adapter mock_payload = {'dummy': 'payload'} adapter = HttpAdapter('http://localhost:14265') # test with explicit attribute adapter.timeout = 77 with mock.patch('iota.adapter.AsyncClient.request', mocked_request): await adapter.send_request(payload=mock_payload) _, kwargs = mocked_request.call_args self.assertEqual(kwargs['timeout'], 77)
async def test_argument_overriding_init_timeout(self): # mock for returning dummy response mocked_request = mock.Mock(return_value=async_return( mock.Mock(text='{ "dummy": "payload"}', status_code=200))) # create adapter mock_payload = {'dummy': 'payload'} adapter = HttpAdapter('http://localhost:14265') # test with timeout at adapter creation adapter = HttpAdapter('http://localhost:14265', timeout=99) with mock.patch('iota.adapter.AsyncClient.request', mocked_request): await adapter.send_request(payload=mock_payload) _, kwargs = mocked_request.call_args self.assertEqual(kwargs['timeout'], 99)
async def test_default_timeout(self): # create adapter mock_payload = {'dummy': 'payload'} adapter = HttpAdapter('http://localhost:14265') # mock for returning dummy response mocked_request = mock.Mock(return_value=async_return( mock.Mock(text='{ "dummy": "payload"}', status_code=200))) with mock.patch('iota.adapter.AsyncClient.request', mocked_request): # test with default timeout await adapter.send_request(payload=mock_payload) # Was the default timeout correctly injected into the request? _, kwargs = mocked_request.call_args self.assertEqual(kwargs['timeout'], socket.getdefaulttimeout())
async def test_no_transactions_fround(self): """ No transaction is found with the inputs. An empty list is returned """ with mock.patch( 'iota.commands.core.get_trytes.GetTrytesCommand._execute', mock.Mock(return_value=async_return({'trytes': []})), ): response = await self.command(hashes=[self.transaction_hash]) self.assertDictEqual( response, { 'transactions': [], }, )
async def test_wireup_async(self): """ Verify that the command is wired up correctly. (async) The API method indeed calls the appropiate command. """ with patch('iota.commands.core.get_tips.GetTipsCommand.__call__', MagicMock(return_value=async_return( 'You found me!'))) as mocked_command: api = AsyncIota(self.adapter) response = await api.get_tips() self.assertTrue(mocked_command.called) self.assertEqual(response, 'You found me!')
async def test_no_transactions_fround(self): """ No transaction is found with the inputs. An empty list is returned """ with mock.patch( 'iota.commands.core.find_transactions.FindTransactionsCommand.' '_execute', mock.Mock(return_value=async_return({'hashes': []})), ): response = await self.command(addresses=[self.address]) self.assertDictEqual( response, { 'transactions': [], }, )
async def test_empty_response(self): """ The response is empty. """ adapter = HttpAdapter('http://localhost:14265') mocked_response = create_http_response('') mocked_sender = mock.Mock(return_value=async_return(mocked_response)) with mock.patch.object(adapter, '_send_http_request', mocked_sender): with self.assertRaises(BadApiResponse) as context: await adapter.send_request({'command': 'helloWorld'}) self.assertEqual( str(context.exception), 'Empty 200 response from node.', )
async def test_wireup_async(self): """ Verify that the command is wired up correctly. (async) The API method indeed calls the appropiate command. """ with patch( 'iota.commands.core.attach_to_tangle.AttachToTangleCommand.__call__', MagicMock(return_value=async_return( 'You found me!'))) as mocked_command: api = AsyncIota(self.adapter) response = await api.attach_to_tangle('trunk', 'branch', 'trytes') self.assertTrue(mocked_command.called) self.assertEqual(response, 'You found me!')
def test_wireup(self): """ Verify that the command is wired up correctly. (sync) The API method indeed calls the appropiate command. """ with patch( 'iota.commands.core.remove_neighbors.RemoveNeighborsCommand.__call__', MagicMock(return_value=async_return( 'You found me!'))) as mocked_command: api = Iota(self.adapter) response = api.remove_neighbors('uris') self.assertTrue(mocked_command.called) self.assertEqual(response, 'You found me!')
def test_wireup(self): """ Verify that the command is wired up correctly. (sync) The API method indeed calls the appropiate command. """ with patch( 'iota.commands.core.interrupt_attaching_to_tangle.InterruptAttachingToTangleCommand.__call__', MagicMock(return_value=async_return( 'You found me!'))) as mocked_command: api = Iota(self.adapter) response = api.interrupt_attaching_to_tangle() self.assertTrue(mocked_command.called) self.assertEqual(response, 'You found me!')
def test_wireup(self): """ Verify that the command is wired up correctly. (sync) The API method indeed calls the appropiate command. """ with patch( 'iota.commands.core.get_missing_transactions.GetMissingTransactionsCommand.__call__', MagicMock(return_value=async_return( 'You found me!'))) as mocked_command: api = Iota(self.adapter) response = api.get_missing_transactions() self.assertTrue(mocked_command.called) self.assertEqual(response, 'You found me!')
async def test_wireup_async(self): """ Verify that the command is wired up correctly. (async) The API method indeed calls the appropiate command. """ with patch( 'iota.commands.core.were_addresses_spent_from.WereAddressesSpentFromCommand.__call__', MagicMock(return_value=async_return( 'You found me!'))) as mocked_command: api = AsyncIota(self.adapter) response = await api.were_addresses_spent_from('addresses') self.assertTrue(mocked_command.called) self.assertEqual(response, 'You found me!')
async def test_wireup_async(self): """ Verify that the command is wired up correctly. (async) The API method indeed calls the appropiate command. """ with patch( 'iota.multisig.commands.get_private_keys.GetPrivateKeysCommand.__call__', MagicMock(return_value=async_return( 'You found me!'))) as mocked_command: api = AsyncMultisigIota(self.adapter) # Don't need to call with proper args here. response = await api.get_private_keys() self.assertTrue(mocked_command.called) self.assertEqual(response, 'You found me!')
def test_wireup(self): """ Verify that the command is wired up correctly. (sync) The API method indeed calls the appropiate command. """ with patch( 'iota.multisig.commands.create_multisig_address.CreateMultisigAddressCommand.__call__', MagicMock(return_value=async_return( 'You found me!'))) as mocked_command: api = MultisigIota(self.adapter) # Don't need to call with proper args here. response = api.create_multisig_address('digests') self.assertTrue(mocked_command.called) self.assertEqual(response, 'You found me!')
def test_wireup(self): """ Verify that the command is wired up correctly. (sync) The API method indeed calls the appropiate command. """ with patch( 'iota.commands.extended.get_account_data.GetAccountDataCommand.__call__', MagicMock(return_value=async_return( 'You found me!'))) as mocked_command: api = Iota(self.adapter) # Don't need to call with proper args here. response = api.get_account_data() self.assertTrue(mocked_command.called) self.assertEqual(response, 'You found me!')
def test_wireup(self): """ Verify that the command is wired up correctly. (sync) The API method indeed calls the appropiate command. """ with patch( 'iota.commands.extended.find_transaction_objects.FindTransactionObjectsCommand.__call__', MagicMock(return_value=async_return( 'You found me!'))) as mocked_command: api = Iota(self.adapter) # Don't need to call with proper args here. response = api.find_transaction_objects('bundle') self.assertTrue(mocked_command.called) self.assertEqual(response, 'You found me!')
async def test_wireup_async(self): """ Verify that the command is wired up correctly. (async) The API method indeed calls the appropiate command. """ with patch( 'iota.commands.extended.send_trytes.SendTrytesCommand.__call__', MagicMock(return_value=async_return( 'You found me!'))) as mocked_command: api = AsyncIota(self.adapter) # Don't need to call with proper args here. response = await api.send_trytes('trytes') self.assertTrue(mocked_command.called) self.assertEqual(response, 'You found me!')
async def test_non_json_response(self): """ The response is not JSON. """ adapter = HttpAdapter('http://localhost:14265') invalid_response = 'EHLO iotatoken.com' # Erm... mocked_response = create_http_response(invalid_response) mocked_sender = mock.Mock(return_value=async_return(mocked_response)) with mock.patch.object(adapter, '_send_http_request', mocked_sender): with self.assertRaises(BadApiResponse) as context: await adapter.send_request({'command': 'helloWorld'}) self.assertEqual( str(context.exception), 'Non-JSON 200 response from node: ' + invalid_response, )