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)
def test_stdin_rt_err(self): with mock.patch("sys.stdin", mock.Mock(read=mock.Mock(return_value="${q}"))): with self._capture_output_fixture("stderr") as stderr: with raises(SystemExit): cmdline(["--var", "x=5", "-"]) assert "NameError: Undefined" in stderr.write.mock_calls[0][1][0] assert "Traceback" in stderr.write.mock_calls[0][1][0]
def test_stdin_success(self): with self._capture_output_fixture() as stdout: with mock.patch( "sys.stdin", mock.Mock(read=mock.Mock(return_value="hello world ${x}")), ): cmdline(["--var", "x=5", "-"]) eq_(stdout.write.mock_calls[0][1][0], "hello world 5")
def test_stdin_syntax_err(self): with mock.patch("sys.stdin", mock.Mock(read=mock.Mock(return_value="${x"))): with self._capture_output_fixture("stderr") as stderr: with raises(SystemExit): cmdline(["--var", "x=5", "-"]) assert "SyntaxException: Expected" in \ stderr.write.mock_calls[0][1][0] assert "Traceback" in stderr.write.mock_calls[0][1][0]
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)
def test_happy_path(self): """ Loading account data for an account. """ # noinspection PyUnusedLocal def mock_iter_used_addresses(adapter, seed, start): """ 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={'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=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 = self.command(seed=Seed.random()) self.assertDictEqual( response, { 'addresses': [self.addy1, self.addy2], 'balance': 42, 'bundles': bundles, }, )
def test_stop_threshold_zero(self): """ ``stop`` provided, ``threshold`` is 0. """ # Note that the first address has a zero balance. self.adapter.seed_response('getBalances', { 'balances': [0, 1], }) # To keep the unit test nice and speedy, we will mock the address # generator. We already have plenty of unit tests for that # functionality, so we can get away with mocking it here. mock_address_generator = mock.Mock( return_value=[self.addy0, self.addy1]) with mock.patch( 'iota.crypto.addresses.AddressGenerator.get_addresses', mock_address_generator, ): response = self.command( seed=Seed.random(), stop=2, threshold=0, ) self.assertEqual(response['totalBalance'], 1) self.assertEqual(len(response['inputs']), 1) # Address 0 was skipped because it has a zero balance. input0 = response['inputs'][0] self.assertIsInstance(input0, Address) self.assertEqual(input0, self.addy1) self.assertEqual(input0.balance, 1) self.assertEqual(input0.key_index, 1)
def test_error_response(self): """ Simulates sending a command to the node and getting an error response. """ adapter = HttpAdapter('http://localhost:14265') error_message = 'Command \u0027helloWorld\u0027 is unknown' mocked_response = create_http_response( status=400, content=json.dumps({ 'error': error_message, 'duration': 42, }), ) mocked_sender = mock.Mock(return_value=mocked_response) # noinspection PyUnresolvedReferences with mock.patch.object(adapter, '_send_http_request', mocked_sender): with self.assertRaises(BadApiResponse) as context: adapter.send_request({'command': 'helloWorld'}) self.assertEqual( text_type(context.exception), '400 response from node: {error}'.format(error=error_message), )
def setUpClass(cls): def side_effect(idx): return [0, 1, 2][idx] cls.node = mock.Mock() cls.node.get_subfield = mock.MagicMock(side_effect=side_effect) cls.node.is_genfunc = mock.MagicMock(return_value=False)
def test_error_non_200_response(self): """ The node sends back a non-200 response. """ adapter = SandboxAdapter('https://localhost', 'ACCESS-TOKEN') decoded_response = { 'message': 'You have reached maximum request limit.', } mocked_sender = mock.Mock(return_value=create_http_response( status=429, content=json.dumps(decoded_response), )) # noinspection PyUnresolvedReferences with mock.patch.object(adapter, '_send_http_request', mocked_sender): with self.assertRaises(BadApiResponse) as context: adapter.send_request({'command': 'helloWorld'}) self.assertEqual( text_type(context.exception), '429 response from node: {decoded}'.format( decoded=decoded_response), )
def test_regular_command_null_token(self): """ Sending commands to a sandbox that doesn't require authorization. This is generally not recommended, but the sandbox node may use other methods to control access (e.g., listen only on loopback interface, use IP address whitelist, etc.). """ # No access token. adapter = SandboxAdapter('https://localhost', None) expected_result = { 'message': 'Hello, IOTA!', } mocked_response = create_http_response(json.dumps(expected_result)) mocked_sender = mock.Mock(return_value=mocked_response) payload = {'command': 'helloWorld'} # noinspection PyUnresolvedReferences with mock.patch.object(adapter, '_send_http_request', mocked_sender): result = adapter.send_request(payload) self.assertEqual(result, expected_result) mocked_sender.assert_called_once_with( payload=json.dumps(payload), url=adapter.node_url, headers={ # No auth token, so no Authorization header. # 'Authorization': 'token ACCESS-TOKEN', 'Content-type': 'application/json', }, )
def test_regular_command(self): """ Sending a non-sandbox command to the node. """ adapter = SandboxAdapter('https://localhost', 'ACCESS-TOKEN') expected_result = { 'message': 'Hello, IOTA!', } mocked_response = create_http_response(json.dumps(expected_result)) mocked_sender = mock.Mock(return_value=mocked_response) payload = {'command': 'helloWorld'} # noinspection PyUnresolvedReferences with mock.patch.object(adapter, '_send_http_request', mocked_sender): result = adapter.send_request(payload) self.assertEqual(result, expected_result) mocked_sender.assert_called_once_with( payload=json.dumps(payload), url=adapter.node_url, # Auth token automatically added to the HTTP request. headers={ 'Authorization': 'token ACCESS-TOKEN', 'Content-type': 'application/json', }, )
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, })
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={ 'bundle': result_bundle, }) with mock.patch( 'iota.commands.extended.send_transfer.SendTransferCommand._execute', mock_send_transfer, ): response = self.command( transaction=self.hash1, depth=3, minWeightMagnitude=16, ) self.assertDictEqual(response, { 'bundle': result_bundle, })
def test_generate_multiple_digests(self): """ Generating multiple digests. """ seed = Seed.random() mock_get_private_keys = \ mock.Mock(return_value={'keys': [self.key1, self.key2]}) with mock.patch( 'iota.multisig.commands.get_private_keys.GetPrivateKeysCommand._execute', mock_get_private_keys ): # noinspection PyUnresolvedReferences with mock.patch.object(self.key1, 'get_digest') as mock_get_digest_1: # type: mock.MagicMock mock_get_digest_1.return_value = self.digest1 # noinspection PyUnresolvedReferences with mock.patch.object(self.key2, 'get_digest') as mock_get_digest_2: # type: mock.MagicMock mock_get_digest_2.return_value = self.digest2 result = self.command(seed=seed, index=0, count=2, securityLevel=1) self.assertDictEqual(result, {'digests': [self.digest1, self.digest2]}) mock_get_private_keys.assert_called_once_with({ 'count': 2, 'index': 0, 'securityLevel': 1, 'seed': seed, })
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_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_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_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, )
def test_default_timeout(self, request_mock): # create dummy response request_mock.return_value = mock.Mock(text='{ "dummy": "payload"}', status_code=200) # create adapter mock_payload = {'dummy': 'payload'} adapter = HttpAdapter('http://localhost:14265') # test with default timeout adapter.send_request(payload=mock_payload) _, kwargs = request_mock.call_args self.assertEqual(kwargs['timeout'], socket.getdefaulttimeout())
def test_instance_attribute_timeout(self, request_mock): # create dummy response request_mock.return_value = 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 adapter.send_request(payload=mock_payload) _, kwargs = request_mock.call_args self.assertEqual(kwargs['timeout'], 77)
def test_argument_overriding_init_timeout(self, request_mock): # create dummy response request_mock.return_value = 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) adapter.send_request(payload=mock_payload) _, kwargs = request_mock.call_args self.assertEqual(kwargs['timeout'], 99)
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={'trytes': []}), ): response = self.command(hashes=[self.transaction_hash]) self.assertDictEqual( response, { 'transactions': [], }, )
def test_generate_single_key(self): """ Generating a single key. """ keys = [PrivateKey(self.trytes1, 0)] mock_get_keys = mock.Mock(return_value=keys) with mock.patch('iota.crypto.signing.KeyGenerator.get_keys', mock_get_keys): result = self.command(seed=Seed.random(), securityLevel=2) self.assertDictEqual(result, {'keys': keys}) mock_get_keys.assert_called_once_with( count=1, iterations=2, start=0, )
def test_transaction_found(self): """ A transaction is found with the inputs. A transaction object is returned """ with mock.patch( 'iota.commands.core.get_trytes.GetTrytesCommand._execute', mock.Mock(return_value={'trytes': [ self.trytes, ]}), ): response = self.command(hashes=[self.transaction_hash]) self.assertEqual(len(response['transactions']), 1) transaction = response['transactions'][0] self.assertIsInstance(transaction, Transaction) self.assertEqual(transaction.hash, self.transaction_hash)
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={'hashes': []}), ): response = self.command(addresses=[self.address]) self.assertDictEqual( response, { 'transactions': [], }, )
def test_no_transactions(self): """ Loading account data for a seed that hasn't been used yet. """ with mock.patch( 'iota.commands.extended.get_account_data.iter_used_addresses', mock.Mock(return_value=[]), ): response = self.command(seed=Seed.random()) self.assertDictEqual( response, { 'addresses': [], 'balance': 0, 'bundles': [], }, )
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_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, )