def test_routing(self): """ Routing commands to different adapters. """ default_adapter = MockAdapter() pow_adapter = MockAdapter() wrapper = ( RoutingWrapper(default_adapter) .add_route('attachToTangle', pow_adapter) .add_route('interruptAttachingToTangle', pow_adapter) ) default_adapter.seed_response('getNodeInfo', {'id': 'default1'}) pow_adapter.seed_response('attachToTangle', {'id': 'pow1'}) pow_adapter.seed_response('interruptAttachingToTangle', {'id': 'pow2'}) self.assertDictEqual( wrapper.send_request({'command': 'attachToTangle'}), {'id': 'pow1'}, ) self.assertDictEqual( wrapper.send_request({'command': 'interruptAttachingToTangle'}), {'id': 'pow2'}, ) # Any commands that aren't routed go to the default adapter. self.assertDictEqual( wrapper.send_request({'command': 'getNodeInfo'}), {'id': 'default1'}, )
def setUp(self): super(GetInputsCommandTestCase, self).setUp() self.adapter = MockAdapter() self.command = GetInputsCommand(self.adapter) # Define some valid tryte sequences that we can reuse between # tests. self.addy0 =\ Address( trytes = b'TESTVALUE9DONTUSEINPRODUCTION99999FIODSG' b'IC9CCIFCNBTBDFIEHHE9RBAEVGK9JECCLCPBIINAX', key_index = 0, ) self.addy1 =\ Address( trytes = b'TESTVALUE9DONTUSEINPRODUCTION999999EPCNH' b'MBTEH9KDVFMHHESDOBTFFACCGBFGACEDCDDCGICIL', key_index = 1, ) self.addy2 =\ Address( trytes = b'TESTVALUE9DONTUSEINPRODUCTION99999YDOHWF' b'U9PFOFHGKFACCCBGDALGI9ZBEBABFAMBPDSEQ9XHJ', key_index = 2, )
def setUp(self): super(GetNewAddressesCommandTestCase, self).setUp() self.adapter = MockAdapter() self.command = GetNewAddressesCommand(self.adapter) self.seed =\ Seed( b'TESTVALUE9DONTUSEINPRODUCTION99999ZDCCUF' b'CBBIQCLGMEXAVFQEOF9DRAB9VCEBAGXAF9VF9FLHP', ) self.addy_1 =\ Address( b'NYMWLBUJEISSACZZBRENC9HEHYQXHCGQHSNHVCEA' b'ZDCTEVNGSDUEKTSYBSQGMVJRIEDHWDYSEYCFAZAH9', ) self.addy_2 =\ Address( b'NTPSEVZHQITARYWHIRTSIFSERINLRYVXLGIQKKHY' b'IWYTLQUUHDWSOVXLIKVJTYZBFKLABWRBFYVSMD9NB', ) self.addy_1_checksum =\ Address( b'NYMWLBUJEISSACZZBRENC9HEHYQXHCGQHSNHVCEA' b'ZDCTEVNGSDUEKTSYBSQGMVJRIEDHWDYSEYCFAZAH' b'9T9FPJROTW', )
class BroadcastAndStoreCommandTestCase(TestCase): # noinspection SpellCheckingInspection def setUp(self): super(BroadcastAndStoreCommandTestCase, self).setUp() self.adapter = MockAdapter() self.command = BroadcastAndStoreCommand(self.adapter) # Define a few valid values that we can reuse across tests. self.trytes1 = b'RBTC9D9DCDQAEASBYBCCKBFA' self.trytes2 =\ b'CCPCBDVC9DTCEAKDXC9D9DEARCWCPCBDVCTCEAHDWCTCEAKDCDFD9DSCSA' def test_wireup(self): """ Verify that the command is wired up correctly. """ self.assertIsInstance( Iota(self.adapter).broadcastAndStore, BroadcastAndStoreCommand, ) def test_happy_path(self): """ Successful invocation of ``broadcastAndStore``. """ self.adapter.seed_response('broadcastTransactions', { 'trytes': [ text_type(self.trytes1, 'ascii'), text_type(self.trytes2, 'ascii'), ], }) self.adapter.seed_response('storeTransactions', {}) trytes = [ TransactionTrytes(self.trytes1), TransactionTrytes(self.trytes2), ] response = self.command(trytes=trytes) self.assertDictEqual(response, {'trytes': trytes})
def setUp(self): super(BroadcastAndStoreCommandTestCase, self).setUp() self.adapter = MockAdapter() self.command = BroadcastAndStoreCommand(self.adapter) # Define a few valid values that we can reuse across tests. self.trytes1 = b'RBTC9D9DCDQAEASBYBCCKBFA' self.trytes2 =\ b'CCPCBDVC9DTCEAKDXC9D9DEARCWCPCBDVCTCEAHDWCTCEAKDCDFD9DSCSA'
def setUp(self): super(GetTransfersCommandTestCase, self).setUp() self.adapter = MockAdapter() self.command = GetTransfersCommand(self.adapter) # Define some tryte sequences we can re-use between tests. self.addy1 =\ Address( b'TESTVALUEONE9DONTUSEINPRODUCTION99999YDZ' b'E9TAFAJGJA9CECKDAEPHBICDR9LHFCOFRBQDHC9IG' ) self.addy2 =\ Address( b'TESTVALUETWO9DONTUSEINPRODUCTION99999TES' b'GINEIDLEEHRAOGEBMDLENFDAFCHEIHZ9EBZDD9YHL' )
def setUp(self): super(GetLatestInclusionCommandTestCase, self).setUp() self.adapter = MockAdapter() self.command = GetLatestInclusionCommand(self.adapter) # Define some tryte sequences that we can re-use across tests. self.milestone =\ TransactionHash( b'TESTVALUE9DONTUSEINPRODUCTION99999W9KDIH' b'BALAYAFCADIDU9HCXDKIXEYDNFRAKHN9IEIDZFWGJ' ) self.hash1 =\ TransactionHash( b'TESTVALUE9DONTUSEINPRODUCTION99999TBPDM9' b'ADFAWCKCSFUALFGETFIFG9UHIEFE9AYESEHDUBDDF' ) self.hash2 =\ TransactionHash( b'TESTVALUE9DONTUSEINPRODUCTION99999CIGCCF' b'KIUFZF9EP9YEYGQAIEXDTEAAUGAEWBBASHYCWBHDX' )
def setUp(self): super(CustomCommandTestCase, self).setUp() self.name = 'helloWorld' self.adapter = MockAdapter() self.command = CustomCommand(self.adapter, self.name)
class StoreTransactionsRequestFilterTestCase(BaseFilterTestCase): filter_type = StoreTransactionsCommand(MockAdapter()).get_request_filter skip_value_check = True # noinspection SpellCheckingInspection def setUp(self): super(StoreTransactionsRequestFilterTestCase, self).setUp() # Define a few valid values here that we can reuse across multiple # tests. self.trytes1 = 'RBTC9D9DCDQAEASBYBCCKBFA' self.trytes2 =\ 'CCPCBDVC9DTCEAKDXC9D9DEARCWCPCBDVCTCEAHDWCTCEAKDCDFD9DSCSA' def test_pass_happy_path(self): """ The incoming request is valid. """ request = { # Raw trytes are extracted to match the IRI's JSON protocol. 'trytes': [ text_type(TransactionTrytes(self.trytes1)), text_type(TransactionTrytes(self.trytes2)), ], } filter_ = self._filter(request) self.assertFilterPasses(filter_) self.assertDictEqual(filter_.cleaned_data, request) def test_pass_compatible_types(self): """ The incoming request contains values that can be converted into the expected types. """ filter_ = self._filter({ # Any value that can be converted into an ASCII representation of # a TryteString is allowed here. 'trytes': [ TransactionTrytes(self.trytes1), bytearray(self.trytes2.encode('ascii')), ], }) self.assertFilterPasses(filter_) self.assertDictEqual( filter_.cleaned_data, { # Raw trytes are extracted to match the IRI's JSON protocol. 'trytes': [ text_type(TransactionTrytes(self.trytes1)), text_type(TransactionTrytes(self.trytes2)), ], }, ) def test_fail_empty(self): """ The incoming request is empty. """ self.assertFilterErrors( {}, { 'trytes': [f.FilterMapper.CODE_MISSING_KEY], }, ) def test_fail_unexpected_parameters(self): """ The incoming value contains unexpected parameters. """ self.assertFilterErrors( { 'trytes': [TryteString(self.trytes1)], # Alright buddy, let's see some ID. 'foo': 'bar', }, { 'foo': [f.FilterMapper.CODE_EXTRA_KEY], }, ) def test_fail_trytes_null(self): """ ``trytes`` is null. """ self.assertFilterErrors( { 'trytes': None, }, { 'trytes': [f.Required.CODE_EMPTY], }, ) def test_fail_trytes_wrong_type(self): """ ``trytes`` is not an array. """ self.assertFilterErrors( { # ``trytes`` has to be an array, even if there's only one # TryteString. 'trytes': TryteString(self.trytes1), }, { 'trytes': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_trytes_empty(self): """ ``trytes`` is an array, but it's empty. """ self.assertFilterErrors( { 'trytes': [], }, { 'trytes': [f.Required.CODE_EMPTY], }, ) def test_trytes_contents_invalid(self): """ ``trytes`` is an array, but it contains invalid values. """ self.assertFilterErrors( { 'trytes': [ b'', True, None, b'not valid trytes', # This is actually valid; I just added it to make sure the # filter isn't cheating! TryteString(self.trytes2), 2130706433, b'9' * (TransactionTrytes.LEN + 1), ], }, { 'trytes.0': [f.NotEmpty.CODE_EMPTY], 'trytes.1': [f.Type.CODE_WRONG_TYPE], 'trytes.2': [f.Required.CODE_EMPTY], 'trytes.3': [Trytes.CODE_NOT_TRYTES], 'trytes.5': [f.Type.CODE_WRONG_TYPE], 'trytes.6': [Trytes.CODE_WRONG_FORMAT], }, )
class SendTransferRequestFilterTestCase(BaseFilterTestCase): filter_type = SendTransferCommand(MockAdapter()).get_request_filter skip_value_check = True # noinspection SpellCheckingInspection def setUp(self): super(SendTransferRequestFilterTestCase, self).setUp() # Define some tryte sequences that we can reuse between tests. self.trytes1 = (b'TESTVALUEONE9DONTUSEINPRODUCTION99999JBW' b'GEC99GBXFFBCHAEJHLC9DX9EEPAI9ICVCKBX9FFII') self.trytes2 = (b'TESTVALUETWO9DONTUSEINPRODUCTION99999THZ' b'BODYHZM99IR9KOXLZXVUOJM9LQKCQJBWMTY999999') self.trytes3 = (b'TESTVALUETHREE9DONTUSEINPRODUCTIONG99999' b'GTQ9CSNUFPYW9MBQ9LFQJSORCF9LGTY9BWQFY9999') self.trytes4 = (b'TESTVALUEFOUR9DONTUSEINPRODUCTION99999ZQ' b'HOGCBZCOTZVZRFBEHQKHENBIZWDTUQXTOVWEXRIK9') self.transfer1 =\ ProposedTransaction( address = Address( b'TESTVALUEFIVE9DONTUSEINPRODUCTION99999MG' b'AAAHJDZ9BBG9U9R9XEOHCBVCLCWCCCCBQCQGG9WHK' ), value = 42, ) self.transfer2 =\ ProposedTransaction( address = Address( b'TESTVALUESIX9DONTUSEINPRODUCTION99999GGT' b'FODSHHELBDERDCDRBCINDCGQEI9NAWDJBC9TGPFME' ), value = 86, ) def test_pass_happy_path(self): """ Request is valid. """ request = { 'changeAddress': Address(self.trytes1), 'depth': 100, 'minWeightMagnitude': 18, 'seed': Seed(self.trytes2), 'inputs': [ Address(self.trytes3), Address(self.trytes4), ], 'transfers': [self.transfer1, self.transfer2], 'reference': TransactionHash(self.trytes1), 'securityLevel': AddressGenerator.DEFAULT_SECURITY_LEVEL, } filter_ = self._filter(request) self.assertFilterPasses(filter_) self.assertDictEqual(filter_.cleaned_data, request) def test_pass_compatible_types(self): """ Request contains values that can be converted to the expected types. """ filter_ = self._filter({ # Any TrytesCompatible values will work here. 'changeAddress': binary_type(self.trytes1), 'seed': bytearray(self.trytes2), 'reference': binary_type(self.trytes1), 'inputs': [ binary_type(self.trytes3), bytearray(self.trytes4), ], # These values must have the correct type, however. 'transfers': [self.transfer1, self.transfer2], 'depth': 100, 'minWeightMagnitude': 18, 'securityLevel': None, }) self.assertFilterPasses(filter_) self.assertDictEqual( filter_.cleaned_data, { 'changeAddress': Address(self.trytes1), 'depth': 100, 'minWeightMagnitude': 18, 'seed': Seed(self.trytes2), 'reference': TransactionHash(self.trytes1), 'inputs': [ Address(self.trytes3), Address(self.trytes4), ], 'transfers': [self.transfer1, self.transfer2], 'securityLevel': AddressGenerator.DEFAULT_SECURITY_LEVEL }) def test_pass_optional_parameters_omitted(self): """ Request omits optional parameters. """ filter_ = self._filter({ 'depth': 100, 'minWeightMagnitude': 13, 'seed': Seed(self.trytes2), 'transfers': [self.transfer1, self.transfer2], }) self.assertFilterPasses(filter_) self.assertDictEqual( filter_.cleaned_data, { 'changeAddress': None, 'inputs': None, 'reference': None, 'depth': 100, 'minWeightMagnitude': 13, 'securityLevel': AddressGenerator.DEFAULT_SECURITY_LEVEL, 'seed': Seed(self.trytes2), 'transfers': [self.transfer1, self.transfer2], }) def test_fail_empty(self): """ Request is empty. """ self.assertFilterErrors( {}, { 'depth': [f.FilterMapper.CODE_MISSING_KEY], 'minWeightMagnitude': [f.FilterMapper.CODE_MISSING_KEY], 'seed': [f.FilterMapper.CODE_MISSING_KEY], 'transfers': [f.FilterMapper.CODE_MISSING_KEY], }, ) def test_fail_unexpected_parameters(self): """ Request contains unexpected parameters. """ self.assertFilterErrors( { 'depth': 100, 'minWeightMagnitude': 18, 'seed': Seed(self.trytes1), 'transfers': [self.transfer1], # Maybe he's not that smart; maybe he's like a worker bee who # only knows how to push buttons or something. 'foo': 'bar', }, { 'foo': [f.FilterMapper.CODE_EXTRA_KEY], }, ) def test_fail_seed_null(self): """ ``seed`` is null. """ self.assertFilterErrors( { 'seed': None, 'depth': 100, 'minWeightMagnitude': 18, 'transfers': [self.transfer1], }, { 'seed': [f.Required.CODE_EMPTY], }, ) def test_fail_seed_wrong_type(self): """ ``seed`` is not a TrytesCompatible value. """ self.assertFilterErrors( { 'seed': 42, 'depth': 100, 'minWeightMagnitude': 18, 'transfers': [self.transfer1], }, { 'seed': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_seed_not_trytes(self): """ ``seed`` contains invalid characters. """ self.assertFilterErrors( { 'seed': b'not valid; must contain only uppercase and "9"', 'depth': 100, 'minWeightMagnitude': 18, 'transfers': [self.transfer1], }, { 'seed': [Trytes.CODE_NOT_TRYTES], }, ) def test_fail_transfers_wrong_type(self): """ ``transfers`` is not an array. """ self.assertFilterErrors( { 'transfers': self.transfer1, 'depth': 100, 'minWeightMagnitude': 18, 'seed': Seed(self.trytes1), }, { 'transfers': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_transfers_empty(self): """ ``transfers`` is an array, but it is empty. """ self.assertFilterErrors( { 'transfers': [], 'depth': 100, 'minWeightMagnitude': 18, 'seed': Seed(self.trytes1), }, { 'transfers': [f.Required.CODE_EMPTY], }, ) def test_fail_transfers_contents_invalid(self): """ ``transfers`` is a non-empty array, but it contains invalid values. """ self.assertFilterErrors( { 'transfers': [ None, # This value is valid; just adding it to make sure the filter # doesn't cheat! ProposedTransaction(address=Address(self.trytes2), value=42), { 'address': Address(self.trytes2), 'value': 42 }, ], 'depth': 100, 'minWeightMagnitude': 18, 'seed': Seed(self.trytes1), }, { 'transfers.0': [f.Required.CODE_EMPTY], 'transfers.2': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_change_address_wrong_type(self): """ ``changeAddress`` is not a TrytesCompatible value. """ self.assertFilterErrors( { 'changeAddress': 42, 'depth': 100, 'minWeightMagnitude': 18, 'seed': Seed(self.trytes1), 'transfers': [self.transfer1], }, { 'changeAddress': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_change_address_not_trytes(self): """ ``changeAddress`` contains invalid characters. """ self.assertFilterErrors( { 'changeAddress': b'not valid; must contain only uppercase and "9"', 'depth': 100, 'minWeightMagnitude': 18, 'seed': Seed(self.trytes1), 'transfers': [self.transfer1], }, { 'changeAddress': [Trytes.CODE_NOT_TRYTES], }, ) def test_fail_inputs_wrong_type(self): """ ``inputs`` is not an array. """ self.assertFilterErrors( { # Must be an array, even if there's only one input. 'inputs': Address(self.trytes4), 'depth': 100, 'minWeightMagnitude': 18, 'seed': Seed(self.trytes1), 'transfers': [self.transfer1], }, { 'inputs': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_inputs_contents_invalid(self): """ ``inputs`` is a non-empty array, but it contains invalid values. """ self.assertFilterErrors( { 'inputs': [ b'', True, None, b'not valid trytes', # This is actually valid; I just added it to make sure the # filter isn't cheating! TryteString(self.trytes4), 2130706433, b'9' * 82, ], 'depth': 100, 'minWeightMagnitude': 18, 'seed': Seed(self.trytes1), 'transfers': [self.transfer1], }, { 'inputs.0': [f.Required.CODE_EMPTY], 'inputs.1': [f.Type.CODE_WRONG_TYPE], 'inputs.2': [f.Required.CODE_EMPTY], 'inputs.3': [Trytes.CODE_NOT_TRYTES], 'inputs.5': [f.Type.CODE_WRONG_TYPE], 'inputs.6': [Trytes.CODE_WRONG_FORMAT], }, ) def test_fail_depth_null(self): """ ``depth`` is null. """ self.assertFilterErrors( { 'depth': None, 'minWeightMagnitude': 18, 'seed': Seed(self.trytes1), 'transfers': [self.transfer1], }, { 'depth': [f.Required.CODE_EMPTY], }, ) def test_fail_depth_string(self): """ ``depth`` is a string. """ self.assertFilterErrors( { # Too ambiguous; it must be an int. 'depth': '2', 'minWeightMagnitude': 18, 'seed': Seed(self.trytes1), 'transfers': [self.transfer1], }, { 'depth': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_depth_float(self): """ ``depth`` is a float. """ self.assertFilterErrors( { # Even with an empty fpart, floats are invalid. 'depth': 100.0, 'minWeightMagnitude': 18, 'seed': Seed(self.trytes1), 'transfers': [self.transfer1], }, { 'depth': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_depth_too_small(self): """ ``depth`` is < 1. """ self.assertFilterErrors( { 'depth': 0, 'minWeightMagnitude': 18, 'seed': Seed(self.trytes1), 'transfers': [self.transfer1], }, { 'depth': [f.Min.CODE_TOO_SMALL], }, ) def test_fail_min_weight_magnitude_null(self): """ ``minWeightMagnitude`` is null. """ self.assertFilterErrors( { 'minWeightMagnitude': None, 'depth': 100, 'seed': Seed(self.trytes1), 'transfers': [self.transfer1], }, { 'minWeightMagnitude': [f.Required.CODE_EMPTY], }, ) def test_fail_min_weight_magnitude_string(self): """ ``minWeightMagnitude`` is a string. """ self.assertFilterErrors( { # Nope; it's gotta be an int. 'minWeightMagnitude': '18', 'depth': 100, 'seed': Seed(self.trytes1), 'transfers': [self.transfer1], }, { 'minWeightMagnitude': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_min_weight_magnitude_float(self): """ ``minWeightMagnitude`` is a float. """ self.assertFilterErrors( { # Even with an empty fpart, floats are invalid. 'minWeightMagnitude': 18.0, 'depth': 100, 'seed': Seed(self.trytes1), 'transfers': [self.transfer1], }, { 'minWeightMagnitude': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_min_weight_magnitude_too_small(self): """ ``minWeightMagnitude`` is < 1. """ self.assertFilterErrors( { 'minWeightMagnitude': 0, 'depth': 100, 'seed': Seed(self.trytes1), 'transfers': [self.transfer1], }, { 'minWeightMagnitude': [f.Min.CODE_TOO_SMALL], }, ) def test_fail_reference_wrong_type(self): """ ``reference`` is not a TrytesCompatible value. """ self.assertFilterErrors( { 'reference': 42, 'seed': Seed(self.trytes1), 'depth': 100, 'minWeightMagnitude': 18, 'transfers': [self.transfer1], }, { 'reference': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_reference_not_trytes(self): """ ``reference`` contains invalid characters. """ self.assertFilterErrors( { 'reference': b'not valid; must contain only uppercase and "9"', 'seed': Seed(self.trytes1), 'depth': 100, 'minWeightMagnitude': 18, 'transfers': [self.transfer1], }, { 'reference': [Trytes.CODE_NOT_TRYTES], }, ) def test_fail_wrong_security_level(self): """ ``security_level`` is not one of integers 1, 2 or 3. """ self.assertFilterErrors( { 'depth': 100, 'minWeightMagnitude': 18, 'seed': Seed(self.trytes1), 'transfers': [self.transfer1], # Maybe he's not that smart; maybe he's like a worker bee who # only knows how to push buttons or something. 'securityLevel': 0, }, { 'securityLevel': [f.Min.CODE_TOO_SMALL], }, ) def test_fail_wrong_security_level_type(self): """ ``security_level`` is not one of integers 1, 2 or 3. """ self.assertFilterErrors( { 'depth': 100, 'minWeightMagnitude': 18, 'seed': Seed(self.trytes1), 'transfers': [self.transfer1], # Maybe he's not that smart; maybe he's like a worker bee who # only knows how to push buttons or something. 'securityLevel': "2", }, { 'securityLevel': [f.Type.CODE_WRONG_TYPE], }, )
class CustomClient(object): client = StrictIota(MockAdapter())
def setUp(self): super(GetNeighborsCommandTestCase, self).setUp() self.adapter = MockAdapter()
def setUp(self): super(TraverseBundleCommandTestCase, self).setUp() self.adapter = MockAdapter() self.command = TraverseBundleCommand(self.adapter)
class CustomClient(object, metaclass=ABCMeta): client = StrictIota(MockAdapter())
def setUp(self): super(GetTrytesCommandTestCase, self).setUp() self.adapter = MockAdapter()
class GetTrytesRequestFilterTestCase(BaseFilterTestCase): filter_type = GetTrytesCommand(MockAdapter()).get_request_filter skip_value_check = True # noinspection SpellCheckingInspection def setUp(self): super(GetTrytesRequestFilterTestCase, self).setUp() # Define some valid tryte sequences that we can re-use between # tests. self.trytes1 = (b'OAATQS9VQLSXCLDJVJJVYUGONXAXOFMJOZNSYWRZ' b'SWECMXAQQURHQBJNLD9IOFEPGZEPEMPXCIVRX9999') self.trytes2 = (b'ZIJGAJ9AADLRPWNCYNNHUHRRAC9QOUDATEDQUMTN' b'OTABUVRPTSTFQDGZKFYUUIE9ZEBIVCCXXXLKX9999') def test_pass_happy_path(self): """ The request is valid. """ request = { 'hashes': [ TransactionHash(self.trytes1), TransactionHash(self.trytes2), ], } filter_ = self._filter(request) self.assertFilterPasses(filter_) self.assertDictEqual(filter_.cleaned_data, request) def test_pass_compatible_types(self): """ The request contains values that can be converted to the expected types. """ filter_ = self._filter({ 'hashes': [ # Any sequence that can be converted into a TransactionHash is # valid. binary_type(self.trytes1), bytearray(self.trytes2), ], }) self.assertFilterPasses(filter_) self.assertDictEqual( filter_.cleaned_data, { 'hashes': [ TransactionHash(self.trytes1), TransactionHash(self.trytes2), ], }, ) def test_fail_empty(self): """ The request is empty. """ self.assertFilterErrors( {}, { 'hashes': [f.FilterMapper.CODE_MISSING_KEY], }, ) def test_fail_unexpected_parameters(self): """ The request contains unexpected parameters. """ self.assertFilterErrors( { 'hashes': [TransactionHash(self.trytes1)], # This is why we can't have nice things! 'foo': 'bar', }, { 'foo': [f.FilterMapper.CODE_EXTRA_KEY], }, ) def test_fail_hashes_null(self): """ ``hashes`` is null. """ self.assertFilterErrors( { 'hashes': None, }, { 'hashes': [f.Required.CODE_EMPTY], }, ) def test_fail_hashes_wrong_type(self): """ ``hashes`` is not an array. """ self.assertFilterErrors( { # ``hashes`` must be an array, even if we're only querying # against a single transaction. 'hashes': TransactionHash(self.trytes1), }, { 'hashes': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_hashes_empty(self): """ ``hashes`` is an array, but it is empty. """ self.assertFilterErrors( { 'hashes': [], }, { 'hashes': [f.Required.CODE_EMPTY], }, ) def test_fail_hashes_contents_invalid(self): """ ``hashes`` is an array, but it contains invalid values. """ self.assertFilterErrors( { 'hashes': [ b'', text_type(self.trytes1, 'ascii'), True, None, b'not valid trytes', # This is actually valid; I just added it to make sure the # filter isn't cheating! TryteString(self.trytes1), 2130706433, b'9' * 82, ], }, { 'hashes.0': [f.Required.CODE_EMPTY], 'hashes.1': [f.Type.CODE_WRONG_TYPE], 'hashes.2': [f.Type.CODE_WRONG_TYPE], 'hashes.3': [f.Required.CODE_EMPTY], 'hashes.4': [Trytes.CODE_NOT_TRYTES], 'hashes.6': [f.Type.CODE_WRONG_TYPE], 'hashes.7': [Trytes.CODE_WRONG_FORMAT], }, )
def setUp(self): super(GetBundlesCommandTestCase, self).setUp() self.adapter = MockAdapter() self.command = GetBundlesCommand(self.adapter)
def setUp(self): super(InterruptAttachingToTangleCommandTestCase, self).setUp() self.adapter = MockAdapter()
def setUp(self): super(GetInclusionStatesCommandTestCase, self).setUp() self.adapter = MockAdapter()
class GetInclusionStatesRequestFilterTestCase(BaseFilterTestCase): filter_type = GetInclusionStatesCommand(MockAdapter()).get_request_filter skip_value_check = True # noinspection SpellCheckingInspection def setUp(self): super(GetInclusionStatesRequestFilterTestCase, self).setUp() self.trytes1 = ('TESTVALUE9DONTUSEINPRODUCTION99999GCXWZZ' 'ZKNRIZENRRXGPAGJOSSWQQOJDD9VGQRMEFCOIFLQB') self.trytes2 = ('TESTVALUE9DONTUSEINPRODUCTION99999KGTGVN' 'GEDAJAXCTEPOJKF9FCJXXDHISFANKOPFXY9IDPMKC') def test_pass_happy_path(self): """ Typical ``getInclusionStates`` request. """ request = { # Raw trytes are extracted to match the IRI's JSON protocol. 'transactions': [self.trytes1, self.trytes2], # These values would normally be different from # ``transactions``, but for purposes of this unit test, we just # need to make sure the format is correct. 'tips': [self.trytes1, self.trytes2], } filter_ = self._filter(request) self.assertFilterPasses(filter_) self.assertDictEqual(filter_.cleaned_data, request) def test_pass_optional_parameters_omitted(self): """ The request omits optional parameters. """ filter_ = self._filter({ 'transactions': [self.trytes1, self.trytes2], }) self.assertFilterPasses(filter_) self.assertDictEqual( filter_.cleaned_data, { 'tips': [], 'transactions': [self.trytes1, self.trytes2], }, ) def test_pass_compatible_types(self): """ The request contains values that can be converted to expected types. """ filter_ = self._filter({ 'transactions': [ TransactionHash(self.trytes1), bytearray(self.trytes2.encode('ascii')), ], 'tips': [ TransactionHash(self.trytes1), bytearray(self.trytes2.encode('ascii')), ], }) self.assertFilterPasses(filter_) self.assertDictEqual( filter_.cleaned_data, { 'tips': [self.trytes1, self.trytes2], 'transactions': [self.trytes1, self.trytes2], }, ) def test_fail_empty(self): """ The incoming request is empty. """ self.assertFilterErrors( {}, { 'transactions': [f.FilterMapper.CODE_MISSING_KEY], }, ) def test_fail_unexpected_parameters(self): """ The incoming request contains unexpected parameters. """ self.assertFilterErrors( { 'transactions': [TransactionHash(self.trytes1)], # I bring scientists, you bring a rock star. 'foo': 'bar', }, { 'foo': [f.FilterMapper.CODE_EXTRA_KEY], }, ) def test_fail_transactions_null(self): """ ``transactions`` is null. """ self.assertFilterErrors( { 'transactions': None, }, { 'transactions': [f.Required.CODE_EMPTY], }, ) def test_fail_transactions_wrong_type(self): """ ``transactions`` is not an array. """ self.assertFilterErrors( { # Has to be an array, even if we're only querying for one # transaction. 'transactions': TransactionHash(self.trytes1), }, { 'transactions': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_transactions_empty(self): """ ``transactions`` is an array, but it is empty. """ self.assertFilterErrors( { 'transactions': [], }, { 'transactions': [f.Required.CODE_EMPTY], }, ) def test_fail_transactions_contents_invalid(self): """ ``transactions`` is a non-empty array, but it contains invalid values. """ self.assertFilterErrors( { 'transactions': [ b'', True, None, b'not valid trytes', # This is actually valid; I just added it to make sure the # filter isn't cheating! TryteString(self.trytes1), 2130706433, b'9' * 82, ], }, { 'transactions.0': [f.Required.CODE_EMPTY], 'transactions.1': [f.Type.CODE_WRONG_TYPE], 'transactions.2': [f.Required.CODE_EMPTY], 'transactions.3': [Trytes.CODE_NOT_TRYTES], 'transactions.5': [f.Type.CODE_WRONG_TYPE], 'transactions.6': [Trytes.CODE_WRONG_FORMAT], }, ) def test_fail_tips_wrong_type(self): """ ``tips`` is not an array. """ self.assertFilterErrors( { 'tips': TransactionHash(self.trytes2), 'transactions': [TransactionHash(self.trytes1)], }, { 'tips': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_tips_contents_invalid(self): """ ``tips`` contains invalid values. """ self.assertFilterErrors( { 'tips': [ b'', True, None, b'not valid trytes', # This is actually valid; I just added it to make sure the # filter isn't cheating! TryteString(self.trytes1), 2130706433, b'9' * 82, ], 'transactions': [TransactionHash(self.trytes1)], }, { 'tips.0': [f.Required.CODE_EMPTY], 'tips.1': [f.Type.CODE_WRONG_TYPE], 'tips.2': [f.Required.CODE_EMPTY], 'tips.3': [Trytes.CODE_NOT_TRYTES], 'tips.5': [f.Type.CODE_WRONG_TYPE], 'tips.6': [Trytes.CODE_WRONG_FORMAT], }, )
class GetInputsCommandTestCase(TestCase): # noinspection SpellCheckingInspection def setUp(self): super(GetInputsCommandTestCase, self).setUp() self.adapter = MockAdapter() self.command = GetInputsCommand(self.adapter) # Define some valid tryte sequences that we can reuse between # tests. self.addy0 =\ Address( trytes = b'TESTVALUE9DONTUSEINPRODUCTION99999FIODSG' b'IC9CCIFCNBTBDFIEHHE9RBAEVGK9JECCLCPBIINAX', key_index = 0, ) self.addy1 =\ Address( trytes = b'TESTVALUE9DONTUSEINPRODUCTION999999EPCNH' b'MBTEH9KDVFMHHESDOBTFFACCGBFGACEDCDDCGICIL', key_index = 1, ) self.addy2 =\ Address( trytes = b'TESTVALUE9DONTUSEINPRODUCTION99999YDOHWF' b'U9PFOFHGKFACCCBGDALGI9ZBEBABFAMBPDSEQ9XHJ', key_index = 2, ) def test_wireup(self): """ Verify that the command is wired up correctly. """ self.assertIsInstance( Iota(self.adapter).getInputs, GetInputsCommand, ) def test_stop_threshold_met(self): """ ``stop`` provided, balance meets ``threshold``. """ self.adapter.seed_response('getBalances', { 'balances': [42, 29], }) # 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 = 71, ) self.assertEqual(response['totalBalance'], 71) self.assertEqual(len(response['inputs']), 2) input0 = response['inputs'][0] self.assertIsInstance(input0, Address) self.assertEqual(input0, self.addy0) self.assertEqual(input0.balance, 42) self.assertEqual(input0.key_index, 0) input1 = response['inputs'][1] self.assertIsInstance(input1, Address) self.assertEqual(input1, self.addy1) self.assertEqual(input1.balance, 29) self.assertEqual(input1.key_index, 1) def test_stop_threshold_not_met(self): """ ``stop`` provided, balance does not meet ``threshold``. """ self.adapter.seed_response('getBalances', { 'balances': [42, 29], }) # 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, ): with self.assertRaises(BadApiResponse): self.command( seed = Seed.random(), stop = 2, threshold = 72, ) 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_stop_no_threshold(self): """ ``stop`` provided, no ``threshold``. """ self.adapter.seed_response('getBalances', { 'balances': [42, 29], }) # 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(), start = 0, stop = 2, ) self.assertEqual(response['totalBalance'], 71) self.assertEqual(len(response['inputs']), 2) input0 = response['inputs'][0] self.assertIsInstance(input0, Address) self.assertEqual(input0, self.addy0) self.assertEqual(input0.balance, 42) self.assertEqual(input0.key_index, 0) input1 = response['inputs'][1] self.assertIsInstance(input1, Address) self.assertEqual(input1, self.addy1) self.assertEqual(input1.balance, 29) self.assertEqual(input1.key_index, 1) def test_no_stop_threshold_met(self): """ No ``stop`` provided, balance meets ``threshold``. """ self.adapter.seed_response('getBalances', { 'balances': [42, 29], }) # ``getInputs`` uses ``findTransactions`` to identify unused # addresses. # noinspection SpellCheckingInspection self.adapter.seed_response('findTransactions', { 'hashes': [ TransactionHash( b'TESTVALUE9DONTUSEINPRODUCTION99999WBL9KD' b'EIZDMEDFPEYDIIA9LEMEUCC9MFPBY9TEVCUGSEGGN' ), ], }) # noinspection SpellCheckingInspection self.adapter.seed_response('findTransactions', { 'hashes': [ TransactionHash( b'TESTVALUE9DONTUSEINPRODUCTION99999YFXGOD' b'GISBJAX9PDJIRDMDV9DCRDCAEG9FN9KECCBDDFZ9H' ), ], }) self.adapter.seed_response('findTransactions', { 'hashes': [], }) # 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. # noinspection PyUnusedLocal def mock_address_generator(ag, start, step=1): for addy in [self.addy0, self.addy1, self.addy2][start::step]: yield addy # When ``stop`` is None, the command uses a generator internally. with mock.patch( 'iota.crypto.addresses.AddressGenerator.create_iterator', mock_address_generator, ): response = self.command( seed = Seed.random(), threshold = 71, ) self.assertEqual(response['totalBalance'], 71) self.assertEqual(len(response['inputs']), 2) input0 = response['inputs'][0] self.assertIsInstance(input0, Address) self.assertEqual(input0, self.addy0) self.assertEqual(input0.balance, 42) self.assertEqual(input0.key_index, 0) input1 = response['inputs'][1] self.assertIsInstance(input1, Address) self.assertEqual(input1, self.addy1) self.assertEqual(input1.balance, 29) self.assertEqual(input1.key_index, 1) def test_no_stop_threshold_not_met(self): """ No ``stop`` provided, balance does not meet ``threshold``. """ self.adapter.seed_response('getBalances', { 'balances': [42, 29, 0], }) # 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. # noinspection PyUnusedLocal def mock_address_generator(ag, start, step=1): for addy in [self.addy0, self.addy1, self.addy2][start::step]: yield addy # When ``stop`` is None, the command uses a generator internally. with mock.patch( 'iota.crypto.addresses.AddressGenerator.create_iterator', mock_address_generator, ): with self.assertRaises(BadApiResponse): self.command( seed = Seed.random(), threshold = 72, ) def test_no_stop_threshold_zero(self): """ No ``stop`` provided, ``threshold`` is 0. """ # Note that the first address has a zero balance. self.adapter.seed_response('getBalances', { 'balances': [0, 1], }) # ``getInputs`` uses ``findTransactions`` to identify unused # addresses. # noinspection SpellCheckingInspection self.adapter.seed_response('findTransactions', { 'hashes': [ TransactionHash( b'TESTVALUE9DONTUSEINPRODUCTION99999WBL9KD' b'EIZDMEDFPEYDIIA9LEMEUCC9MFPBY9TEVCUGSEGGN' ), ], }) # noinspection SpellCheckingInspection self.adapter.seed_response('findTransactions', { 'hashes': [ TransactionHash( b'TESTVALUE9DONTUSEINPRODUCTION99999YFXGOD' b'GISBJAX9PDJIRDMDV9DCRDCAEG9FN9KECCBDDFZ9H' ), ], }) self.adapter.seed_response('findTransactions', { 'hashes': [], }) # 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. # noinspection PyUnusedLocal def mock_address_generator(ag, start, step=1): for addy in [self.addy0, self.addy1, self.addy2][start::step]: yield addy # When ``stop`` is None, the command uses a generator internally. with mock.patch( 'iota.crypto.addresses.AddressGenerator.create_iterator', mock_address_generator, ): response = self.command( seed = Seed.random(), threshold = 0, ) self.assertEqual(response['totalBalance'], 1) self.assertEqual(len(response['inputs']), 1) # Because the first address had a zero balance, it was skipped. 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_no_stop_no_threshold(self): """ No ``stop`` provided, no ``threshold``. """ self.adapter.seed_response('getBalances', { 'balances': [42, 29], }) # ``getInputs`` uses ``findTransactions`` to identify unused # addresses. # noinspection SpellCheckingInspection self.adapter.seed_response('findTransactions', { 'hashes': [ TransactionHash( b'TESTVALUE9DONTUSEINPRODUCTION99999WBL9KD' b'EIZDMEDFPEYDIIA9LEMEUCC9MFPBY9TEVCUGSEGGN' ), ], }) # noinspection SpellCheckingInspection self.adapter.seed_response('findTransactions', { 'hashes': [ TransactionHash( b'TESTVALUE9DONTUSEINPRODUCTION99999YFXGOD' b'GISBJAX9PDJIRDMDV9DCRDCAEG9FN9KECCBDDFZ9H' ), ], }) self.adapter.seed_response('findTransactions', { 'hashes': [], }) # 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. # noinspection PyUnusedLocal def mock_address_generator(ag, start, step=1): for addy in [self.addy0, self.addy1, self.addy2][start::step]: yield addy # When ``stop`` is None, the command uses a generator internally. with mock.patch( 'iota.crypto.addresses.AddressGenerator.create_iterator', mock_address_generator, ): response = self.command( seed = Seed.random(), ) self.assertEqual(response['totalBalance'], 71) self.assertEqual(len(response['inputs']), 2) input0 = response['inputs'][0] self.assertIsInstance(input0, Address) self.assertEqual(input0, self.addy0) self.assertEqual(input0.balance, 42) self.assertEqual(input0.key_index, 0) input1 = response['inputs'][1] self.assertIsInstance(input1, Address) self.assertEqual(input1, self.addy1) self.assertEqual(input1.balance, 29) self.assertEqual(input1.key_index, 1) def test_start(self): """ Using ``start`` to offset the key range. """ self.adapter.seed_response('getBalances', { 'balances': [86], }) # ``getInputs`` uses ``findTransactions`` to identify unused # addresses. # noinspection SpellCheckingInspection self.adapter.seed_response('findTransactions', { 'hashes': [ TransactionHash( b'TESTVALUE9DONTUSEINPRODUCTION99999YFXGOD' b'GISBJAX9PDJIRDMDV9DCRDCAEG9FN9KECCBDDFZ9H' ), ], }) self.adapter.seed_response('findTransactions', { 'hashes': [], }) # 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. # noinspection PyUnusedLocal def mock_address_generator(ag, start, step=1): # If ``start`` has the wrong value, return garbage to make the # test asplode. for addy in [None, self.addy1, self.addy2][start::step]: yield addy # When ``stop`` is None, the command uses a generator internally. with mock.patch( 'iota.crypto.addresses.AddressGenerator.create_iterator', mock_address_generator, ): response = self.command( seed = Seed.random(), start = 1, ) self.assertEqual(response['totalBalance'], 86) self.assertEqual(len(response['inputs']), 1) input0 = response['inputs'][0] self.assertIsInstance(input0, Address) self.assertEqual(input0, self.addy1) self.assertEqual(input0.balance, 86) self.assertEqual(input0.key_index, 1)
class GetNewAddressesCommandTestCase(TestCase): # noinspection SpellCheckingInspection def setUp(self): super(GetNewAddressesCommandTestCase, self).setUp() self.adapter = MockAdapter() self.command = GetNewAddressesCommand(self.adapter) self.seed =\ Seed( b'TESTVALUE9DONTUSEINPRODUCTION99999ZDCCUF' b'CBBIQCLGMEXAVFQEOF9DRAB9VCEBAGXAF9VF9FLHP', ) self.addy_1 =\ Address( b'NYMWLBUJEISSACZZBRENC9HEHYQXHCGQHSNHVCEA' b'ZDCTEVNGSDUEKTSYBSQGMVJRIEDHWDYSEYCFAZAH9', ) self.addy_2 =\ Address( b'NTPSEVZHQITARYWHIRTSIFSERINLRYVXLGIQKKHY' b'IWYTLQUUHDWSOVXLIKVJTYZBFKLABWRBFYVSMD9NB', ) self.addy_1_checksum =\ Address( b'NYMWLBUJEISSACZZBRENC9HEHYQXHCGQHSNHVCEA' b'ZDCTEVNGSDUEKTSYBSQGMVJRIEDHWDYSEYCFAZAH' b'9T9FPJROTW', ) def test_wireup(self): """ Verify that the command is wired up correctly. """ self.assertIsInstance( Iota(self.adapter).getNewAddresses, GetNewAddressesCommand, ) def test_get_addresses_offline(self): """ Generate addresses in offline mode (without filtering used addresses). """ response =\ self.command( count = 2, index = 0, seed = self.seed, ) self.assertDictEqual( response, {'addresses': [self.addy_1, self.addy_2]}, ) # No API requests were made. self.assertListEqual(self.adapter.requests, []) def test_security_level(self): """ Generating addresses with a different security level. """ response =\ self.command( count = 2, index = 0, securityLevel = 1, seed = self.seed, ) # noinspection SpellCheckingInspection self.assertDictEqual( response, { 'addresses': [ Address( b'ERBTZTPT9SKDQEGETKMZLYNRQMZYZIDENGWCSGRF' b'9TLURIEFVKUBSWOIMLMWTWMWTTHSUREPISXDPLCQC', ), Address( b'QVHEMGYHVMCFAISJKTWPFSKDAFRZHXQZK9E9KOUQ' b'LOLVBN9BFAZDDY9O9EYYMHMDWZAKXI9OPBPEYM9FC', ), ], }, ) def test_get_addresses_online(self): """ Generate address in online mode (filtering used addresses). """ # Pretend that ``self.addy1`` has already been used, but not # ``self.addy2``. # noinspection SpellCheckingInspection self.adapter.seed_response('findTransactions', { 'duration': 18, 'hashes': [ 'TESTVALUE9DONTUSEINPRODUCTION99999ITQLQN' 'LPPG9YNAARMKNKYQO9GSCSBIOTGMLJUFLZWSY9999', ], }) self.adapter.seed_response('findTransactions', { 'duration': 1, 'hashes': [], }) response =\ self.command( # If ``count`` is missing or ``None``, the command will operate # in online mode. # count = None, index = 0, seed = self.seed, ) # The command determined that ``self.addy1`` was already used, so # it skipped that one. self.assertDictEqual(response, {'addresses': [self.addy_2]}) self.assertListEqual( self.adapter.requests, # The command issued two `findTransactions` API requests: one for # each address generated, until it found an unused address. [ { 'command': 'findTransactions', 'addresses': [self.addy_1], }, { 'command': 'findTransactions', 'addresses': [self.addy_2], }, ], ) def test_new_address_checksum(self): """ Generate address with a checksum. """ response =\ self.command( checksum = True, count = 1, index = 0, seed = self.seed, ) self.assertDictEqual( response, {'addresses': [self.addy_1_checksum]}, )
class BroadcastTransactionsRequestFilterTestCase(BaseFilterTestCase): filter_type = BroadcastTransactionsCommand( MockAdapter()).get_request_filter print_var_type_n_val(var001=filter_type, pointer="#23456FESDFDdsdfd") #23456FESDFDdsdfd # Value: # # <bound method BroadcastTransactionsCommand.get_request_filter of <iota.commands.core.broadcast_transactions.BroadcastTransactionsCommand object at 0x00000173E70A88D0>> # Type: <class 'method'> skip_value_check = True # noinspection SpellCheckingInspection def setUp(self): super(BroadcastTransactionsRequestFilterTestCase, self).setUp() # Define a few valid values that we can reuse across tests. self.trytes1 = TransactionTrytes('RBTC9D9DCDQAEASBYBCCKBFA') self.trytes2 =\ TransactionTrytes( 'CCPCBDVC9DTCEAKDXC9D9DEARCWCPCBDVCTCEAHDWCTCEAKDCDFD9DSCSA' ) print_var_type_n_val(var001=self.trytes2, pointer="#R43EDFdfsSDFDtre") #R43EDFdfsSDFDtre # Value: CCPCBDVC9DTCEAKDXC9D9DEARCWCPCBDVCTCEAHDWCTCEAKDCDFD9DSCSA99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 # Type: <class 'iota.transaction.types.TransactionTrytes'> def test_pass_happy_path(self): """ The incoming request is valid. """ request = { 'trytes': [ text_type(self.trytes1), text_type(self.trytes2), ], } filter_ = self._filter(request) self.assertFilterPasses(filter_) self.assertDictEqual(filter_.cleaned_data, request) def test_pass_compatible_types(self): """ The incoming request contains values that can be converted into the expected types. """ # Any values that can be converted into TryteStrings are accepted. filter_ = self._filter({ 'trytes': [ binary_type(self.trytes1), self.trytes2, ], }) print_var_type_n_val( var001=filter_, pointer="#SDFTREzertg123498xcvb") #SDFTREzertg123498xcvb # Value: # # BroadcastTransactionsRequestFilter(FilterChain(Type(Mapping, allow_subclass=True) | FilterMapper(trytes=FilterChain(Required(allow_none=False) | Array(Sequence, allow_subclass=True) | FilterRepeater(FilterChain(Required(allow_none=False) | Trytes() | Unicode(encoding='ascii'))))))) # Type: <class 'filters.handlers.FilterRunner'> self.assertFilterPasses(filter_) self.assertDictEqual( filter_.cleaned_data, { 'trytes': [ # Raw trytes are extracted to match the IRI's JSON protocol. text_type(self.trytes1), text_type(self.trytes2), ], }, ) def test_fail_empty(self): """ The incoming request is empty. """ self.assertFilterErrors( {}, { 'trytes': [f.FilterMapper.CODE_MISSING_KEY], }, ) def test_fail_unexpected_parameters(self): """ The incoming value contains unexpected parameters. """ self.assertFilterErrors( { 'trytes': [TryteString(self.trytes1)], # Alright buddy, let's see some ID. 'foo': 'bar', }, { 'foo': [f.FilterMapper.CODE_EXTRA_KEY], }, ) def test_fail_trytes_null(self): """ ``trytes`` is null. """ self.assertFilterErrors( { 'trytes': None, }, { 'trytes': [f.Required.CODE_EMPTY], }, ) def test_fail_trytes_wrong_type(self): """ ``trytes`` is not an array. """ self.assertFilterErrors( { # ``trytes`` has to be an array, even if there's only one # TryteString. 'trytes': TryteString(self.trytes1), }, { 'trytes': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_trytes_empty(self): """ ``trytes`` is an array, but it's empty. """ self.assertFilterErrors( { 'trytes': [], }, { 'trytes': [f.Required.CODE_EMPTY], }, ) def test_trytes_contents_invalid(self): """ ``trytes`` is an array, but it contains invalid values. """ self.assertFilterErrors( { 'trytes': [ b'', True, None, b'not valid trytes', # This is actually valid; I just added it to make sure the # filter isn't cheating! TryteString(self.trytes2), 2130706433, b'9' * (TransactionTrytes.LEN + 1), ], }, { 'trytes.0': [f.NotEmpty.CODE_EMPTY], 'trytes.1': [f.Type.CODE_WRONG_TYPE], 'trytes.2': [f.Required.CODE_EMPTY], 'trytes.3': [Trytes.CODE_NOT_TRYTES], 'trytes.5': [f.Type.CODE_WRONG_TYPE], 'trytes.6': [Trytes.CODE_WRONG_FORMAT], }, )
class TraverseBundleCommandTestCase(TestCase): def setUp(self): super(TraverseBundleCommandTestCase, self).setUp() self.adapter = MockAdapter() self.command = TraverseBundleCommand(self.adapter) 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.traverse_bundle.TraverseBundleCommand.__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.traverse_bundle('tail') self.assertTrue(mocked_command.called) self.assertEqual(response, 'You found me!') @async_test async def test_wireup(self): """ Verify that the command is wired up correctly. (async) The API method indeed calls the appropiate command. """ with patch( 'iota.commands.extended.traverse_bundle.TraverseBundleCommand.__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.traverse_bundle('tail') self.assertTrue(mocked_command.called) self.assertEqual(response, 'You found me!') @async_test async def test_single_transaction(self): """ Getting a bundle that contains a single transaction. """ transaction =\ Transaction( current_index = 0, last_index = 0, tag = Tag(b''), timestamp = 1484960990, value = 0, attachment_timestamp = 1484960990, attachment_timestamp_lower_bound = 12, attachment_timestamp_upper_bound = 0, # These values are not relevant for 0-value transactions. nonce = Nonce(b''), signature_message_fragment = Fragment(b''), # This value is computed automatically, so it has to be real. hash_ = TransactionHash( b'XPJIYZWPF9LBCYZPNBFARDRCSUGJGF9TWZT9K9PX' b'VYDFPZOZBGXUCKLTJEUCFBEKQQ9VCSQVQDMMJQAY9', ), address = Address( b'TESTVALUE9DONTUSEINPRODUCTION99999OCSGVF' b'IBQA99KGTCPCZ9NHR9VGLGADDDIEGGPCGBDEDDTBC', ), bundle_hash = BundleHash( b'TESTVALUE9DONTUSEINPRODUCTION99999DIOAZD' b'M9AIUHXGVGBC9EMGI9SBVBAIXCBFJ9EELCPDRAD9U', ), branch_transaction_hash = TransactionHash( b'TESTVALUE9DONTUSEINPRODUCTION99999BBCEDI' b'ZHUDWBYDJEXHHAKDOCKEKDFIMB9AMCLFW9NBDEOFV', ), trunk_transaction_hash = TransactionHash( b'TESTVALUE9DONTUSEINPRODUCTION999999ARAYA' b'MHCB9DCFEIWEWDLBCDN9LCCBQBKGDDAECFIAAGDAS', ), ) self.adapter.seed_response('getTrytes', { 'trytes': [transaction.as_tryte_string()], }) response = await self.command(transaction=transaction.hash) bundle = response['bundles'][0] # type: Bundle self.assertEqual(len(bundle), 1) self.maxDiff = None self.assertDictEqual( bundle[0].as_json_compatible(), transaction.as_json_compatible(), ) @async_test async def test_multiple_transactions(self): """ Getting a bundle that contains multiple transactions. """ bundle = Bundle.from_tryte_strings([ TransactionTrytes( b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999WUQXEGBVIECGIWO9IGSYKWWPYCIVUJJGSJPWGIAFJPYSF9NSQOHWAHS9P' b'9PWQHOBXNNQIF9IRHVQXKPZW999999999999999999999999999XZUIENOTTBKJMDP' b'RXWGQYG9PWGTHNLFMVD99A99999999A99999999PDQWLVVDPUU9VIBODGMRIAZPGQX' b'DOGSEXIHKIBWSLDAWUKZCZMK9Z9YZSPCKBDJSVDPRQLJSTKUMTNVSXBGUEHHGAIWWQ' b'BCJZHZAQOWZMAIDAFUZBVMUVPWQJLUGGQKNKLMGTWXXNZKUCBJLEDAMYVRGABAWBY9' b'999MYIYBTGIOQYYZFJBLIAWMPSZEFFTXUZPCDIXSLLQDQSFYGQSQOGSPKCZNLVSZ9L' b'MCUWVNGEN9EJEW9999XZUIENOTTBKJMDPRXWGQYG9PWGTXUO9AXMP9FLMDRMADLRPW' b'CZCJBROYCDRJMYU9HDYJM9NDBFUPIZVTR'), # Well, it was bound to happen sooner or later... the ASCII # representation of this tryte sequence contains a very naughty # phrase. But I don't feel like doing another POW, so... enjoy. TransactionTrytes( b'NBTCPCFDEACCPCBDVC9DTCQAJ9RBTC9D9DCDQAEAKDCDFD9DSCFAJ9VBCDJDTCQAJ9' b'ZBMDYBCCKB99999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999SYRABNN9JD9PNDL' b'IKUNCECUELTOHNLFMVD99999999999A99999999PDQWLVVDPUU9VIBODGMRIAZPGQX' b'DOGSEXIHKIBWSLDAWUKZCZMK9Z9YZSPCKBDJSVDPRQLJSTKUMTNVSXFSEWUNJOEGNU' b'I9QOCRFMYSIFAZLJHKZBPQZZYFG9ORYCRDX9TOMJPFCRB9R9KPUUGFPVOWYXFIWEW9' b'999BGUEHHGAIWWQBCJZHZAQOWZMAIDAFUZBVMUVPWQJLUGGQKNKLMGTWXXNZKUCBJL' b'EDAMYVRGABAWBY9999SYRABNN9JD9PNDLIKUNCECUELTOQZPSBDILVHJQVCEOICFAD' b'YKZVGMOAXJRQNTCKMHGTAUMPGJJMX9LNF'), ]) for txn in bundle: self.adapter.seed_response('getTrytes', { 'trytes': [txn.as_tryte_string()], }) self.adapter.seed_response( 'getTrytes', { 'trytes': [ 'SPAMSPAMSPAM999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999JECDITWO9999999' '999999999999ONLFMVD99999999999999999999VVCHSQSRVFKSBONDWB9EAQEMQOY' 'YRBIZHTBJLYNAVDHZPUZAZ9LYHXWKBEJ9IPR9FAMFLT9EEOHVYWUPRHHSRCILCLWFD' 'GBYBFFOKMCSAPVD9VGZZRRGBLGMZMXD9RMZQDBLMGN9BATWZGULRBCYQEIKIRBPHC9' '999KTLTRSYOWBD9HVNP9GCUABARNGMYXUZKXWRPGOPETZLKYYC9Z9EYXIWVARUBMBM' 'BPXGORN9WPBLY99999ZRBVQWULRFXDNDYZKRKIXPZQT9JJJH9FZU9PVWZJWLXBPODP' 'EHMKTTAGEPLPHUQCZNLDSHERONOMHJCOI' ], }) response = await self.command(transaction=TransactionHash( b'TOYJPHKMLQNDVLDHDILARUJCCIUMQBLUSWPCTIVA' b'DRXICGYDGSVPXFTILFFGAPICYHGGJ9OHXINFX9999'), ) self.maxDiff = None self.assertListEqual( response['bundles'][0].as_json_compatible(), bundle.as_json_compatible(), ) @async_test async def test_non_tail_transaction(self): """ Trying to get a bundle for a non-tail transaction. This is not valid; you have to start with a tail transaction. """ self.adapter.seed_response( 'getTrytes', { 'trytes': [ b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999999999999999999999999999999999999999999999999999999999999' b'999999999WUQXEGBVIECGIWO9IGSYKWWPYCIVUJJGSJPWGIAFJPYSF9NSQOHWAHS9P' b'9PWQHOBXNNQIF9IRHVQXKPZW999999999999999999999999999999999999999999' b'999999999999HNLFMVD99A99999999A99999999PDQWLVVDPUU9VIBODGMRIAZPGQX' b'DOGSEXIHKIBWSLDAWUKZCZMK9Z9YZSPCKBDJSVDPRQLJSTKUMTNVSXBGUEHHGAIWWQ' b'BCJZHZAQOWZMAIDAFUZBVMUVPWQJLUGGQKNKLMGTWXXNZKUCBJLEDAMYVRGABAWBY9' b'999MYIYBTGIOQYYZFJBLIAWMPSZEFFTXUZPCDIXSLLQDQSFYGQSQOGSPKCZNLVSZ9L' b'MCUWVNGEN9EJEW9999XZUIENOTTBKJMDPRXWGQYG9PWGTXUO9AXMP9FLMDRMADLRPW' b'CZCJBROYCDRJMYU9HDYJM9NDBFUPIZVTR' ], }) with self.assertRaises(BadApiResponse): await self.command(transaction=TransactionHash( b'FSEWUNJOEGNUI9QOCRFMYSIFAZLJHKZBPQZZYFG9' b'ORYCRDX9TOMJPFCRB9R9KPUUGFPVOWYXFIWEW9999'), ) @async_test async def test_missing_transaction(self): """ Unable to find the requested transaction. """ self.adapter.seed_response('getTrytes', {'trytes': []}) with self.assertRaises(BadApiResponse): await self.command(transaction=TransactionHash( b'FSEWUNJOEGNUI9QOCRFMYSIFAZLJHKZBPQZZYFG9' b'ORYCRDX9TOMJPFCRB9R9KPUUGFPVOWYXFIWEW9999'), ) @async_test async def test_missing_transaction_zero_trytes(self): """ Unable to find the requested transaction. getTrytes returned only zeros, no tx was found. """ zero_trytes = TransactionTrytes('') self.adapter.seed_response('getTrytes', {'trytes': [zero_trytes]}) with self.assertRaises(BadApiResponse): await self.command(transaction=TransactionHash( b'FSEWUNJOEGNUI9QOCRFMYSIFAZLJHKZBPQZZYFG9' b'ORYCRDX9TOMJPFCRB9R9KPUUGFPVOWYXFIWEW9999'), )
def setUp(self): super(BroadcastTransactionsCommandTestCase, self).setUp() self.adapter = MockAdapter()
class TraverseBundleRequestFilterTestCase(BaseFilterTestCase): filter_type = TraverseBundleCommand(MockAdapter()).get_request_filter skip_value_check = True def setUp(self): super(TraverseBundleRequestFilterTestCase, self).setUp() self.transaction = ('TESTVALUE9DONTUSEINPRODUCTION99999KPZOTR' 'VDB9GZDJGZSSDCBIX9QOK9PAV9RMDBGDXLDTIZTWQ') def test_pass_happy_path(self): """ Request is valid. """ # Raw trytes are extracted to match the IRI's JSON protocol. request = { 'transaction': self.transaction, } filter_ = self._filter(request) self.assertFilterPasses(filter_) self.assertDictEqual(filter_.cleaned_data, request) def test_pass_compatible_types(self): """ Request contains values that can be converted to the expected types. """ filter_ = self._filter({ # Any TrytesCompatible value will work here. 'transaction': TransactionHash(self.transaction), }) self.assertFilterPasses(filter_) self.assertDictEqual( filter_.cleaned_data, { 'transaction': self.transaction, }, ) def test_fail_empty(self): """ Request is empty. """ self.assertFilterErrors( {}, { 'transaction': [f.FilterMapper.CODE_MISSING_KEY], }, ) def test_fail_unexpected_parameters(self): """ Request contains unexpected parameters. """ self.assertFilterErrors( { 'transaction': TransactionHash(self.transaction), # SAY "WHAT" AGAIN! 'what': 'augh!', }, { 'what': [f.FilterMapper.CODE_EXTRA_KEY], }, ) def test_fail_transaction_wrong_type(self): """ ``transaction`` is not a TrytesCompatible value. """ self.assertFilterErrors( { 'transaction': 42, }, { 'transaction': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_transaction_not_trytes(self): """ ``transaction`` contains invalid characters. """ self.assertFilterErrors( { 'transaction': b'not valid; must contain only uppercase and "9"', }, { 'transaction': [Trytes.CODE_NOT_TRYTES], }, )
class GetLatestInclusionCommandTestCase(TestCase): # noinspection SpellCheckingInspection def setUp(self): super(GetLatestInclusionCommandTestCase, self).setUp() self.adapter = MockAdapter() self.command = GetLatestInclusionCommand(self.adapter) # Define some tryte sequences that we can re-use across tests. self.milestone =\ TransactionHash( b'TESTVALUE9DONTUSEINPRODUCTION99999W9KDIH' b'BALAYAFCADIDU9HCXDKIXEYDNFRAKHN9IEIDZFWGJ' ) self.hash1 =\ TransactionHash( b'TESTVALUE9DONTUSEINPRODUCTION99999TBPDM9' b'ADFAWCKCSFUALFGETFIFG9UHIEFE9AYESEHDUBDDF' ) self.hash2 =\ TransactionHash( b'TESTVALUE9DONTUSEINPRODUCTION99999CIGCCF' b'KIUFZF9EP9YEYGQAIEXDTEAAUGAEWBBASHYCWBHDX' ) def test_wireup(self): """ Verify that the command is wired up correctly. """ self.assertIsInstance( Iota(self.adapter).getLatestInclusion, GetLatestInclusionCommand, ) def test_happy_path(self): """ Successfully requesting latest inclusion state. """ self.adapter.seed_response( 'getNodeInfo', { # ``getNodeInfo`` returns lots of info, but the only value that # matters for this test is ``latestSolidSubtangleMilestone``. 'latestSolidSubtangleMilestone': self.milestone, }, ) self.adapter.seed_response('getInclusionStates', { 'states': [True, False], }) response = self.command(hashes=[self.hash1, self.hash2]) self.assertDictEqual(response, { 'states': { self.hash1: True, self.hash2: False, }, })
class CustomCommandTestCase(TestCase): def setUp(self): super(CustomCommandTestCase, self).setUp() self.name = 'helloWorld' self.adapter = MockAdapter() self.command = CustomCommand(self.adapter, self.name) def test_call(self): """ Sending a custom command. """ expected_response = {'message': 'Hello, IOTA!'} self.adapter.seed_response('helloWorld', expected_response) response = self.command() self.assertEqual(response, expected_response) self.assertTrue(self.command.called) self.assertListEqual( self.adapter.requests, [{'command': 'helloWorld'}], ) def test_call_with_parameters(self): """ Sending a custom command with parameters. """ expected_response = {'message': 'Hello, IOTA!'} self.adapter.seed_response('helloWorld', expected_response) response = self.command(foo='bar', baz='luhrmann') self.assertEqual(response, expected_response) self.assertTrue(self.command.called) self.assertListEqual( self.adapter.requests, [{'command': 'helloWorld', 'foo': 'bar', 'baz': 'luhrmann'}], ) def test_call_error_already_called(self): """ A command can only be called once. """ self.adapter.seed_response('helloWorld', {}) self.command() with self.assertRaises(RuntimeError): self.command(extra='params') self.assertDictEqual(self.command.request, {'command': 'helloWorld'}) def test_call_reset(self): """ Resetting a command allows it to be called more than once. """ self.adapter.seed_response('helloWorld', {'message': 'Hello, IOTA!'}) self.command() self.command.reset() self.assertFalse(self.command.called) self.assertIsNone(self.command.request) self.assertIsNone(self.command.response) expected_response = {'message': 'Welcome back!'} self.adapter.seed_response('helloWorld', expected_response) response = self.command(foo='bar') self.assertDictEqual(response, expected_response) self.assertDictEqual(self.command.response, expected_response) self.assertDictEqual( self.command.request, { 'command': 'helloWorld', 'foo': 'bar', }, )
class GetAccountDataRequestFilterTestCase(BaseFilterTestCase): filter_type = GetAccountDataCommand(MockAdapter()).get_request_filter skip_value_check = True # noinspection SpellCheckingInspection def setUp(self): super(GetAccountDataRequestFilterTestCase, self).setUp() # Define a few tryte sequences that we can re-use between tests. self.seed = b'HELLOIOTA' def test_pass_happy_path(self): """ Request is valid. """ request = { 'seed': Seed(self.seed), 'start': 0, 'stop': 10, 'inclusionStates': True, } filter_ = self._filter(request) self.assertFilterPasses(filter_) self.assertDictEqual(filter_.cleaned_data, request) def test_pass_compatible_types(self): """ The request contains values that can be converted to the expected types. """ filter_ = self._filter({ # ``seed`` can be any value that is convertible into a # TryteString. 'seed': binary_type(self.seed), # These values must still be integers/bools, however. 'start': 42, 'stop': 86, 'inclusionStates': True, }) self.assertFilterPasses(filter_) self.assertDictEqual( filter_.cleaned_data, { 'seed': Seed(self.seed), 'start': 42, 'stop': 86, 'inclusionStates': True, }, ) def test_pass_optional_parameters_excluded(self): """ The request contains only required parameters. """ filter_ = self._filter({ 'seed': Seed(self.seed), }) self.assertFilterPasses(filter_) self.assertDictEqual( filter_.cleaned_data, { 'seed': Seed(self.seed), 'start': 0, 'stop': None, 'inclusionStates': False, }) def test_fail_empty_request(self): """ The request is empty. """ self.assertFilterErrors( {}, { 'seed': [f.FilterMapper.CODE_MISSING_KEY], }, ) def test_fail_unexpected_parameters(self): """ The request contains unexpected parameters. """ self.assertFilterErrors( { 'seed': Seed(self.seed), # Your rules are really beginning to annoy me. 'foo': 'bar', }, { 'foo': [f.FilterMapper.CODE_EXTRA_KEY], }, ) def test_fail_seed_null(self): """ ``seed`` is null. """ self.assertFilterErrors( { 'seed': None, }, { 'seed': [f.Required.CODE_EMPTY], }, ) def test_fail_seed_wrong_type(self): """ ``seed`` cannot be converted into a TryteString. """ self.assertFilterErrors( { 'seed': text_type(self.seed, 'ascii'), }, { 'seed': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_seed_malformed(self): """ ``seed`` has the correct type, but it contains invalid characters. """ self.assertFilterErrors( { 'seed': b'not valid; seeds can only contain uppercase and "9".', }, { 'seed': [Trytes.CODE_NOT_TRYTES], }, ) def test_fail_start_string(self): """ ``start`` is a string. """ self.assertFilterErrors( { # Not valid; it must be an int. 'start': '0', 'seed': Seed(self.seed), }, { 'start': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_start_float(self): """ ``start`` is a float. """ self.assertFilterErrors( { # Even with an empty fpart, floats are not valid. # It's gotta be an int. 'start': 8.0, 'seed': Seed(self.seed), }, { 'start': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_start_too_small(self): """ ``start`` is less than 0. """ self.assertFilterErrors( { 'start': -1, 'seed': Seed(self.seed), }, { 'start': [f.Min.CODE_TOO_SMALL], }, ) def test_fail_stop_string(self): """ ``stop`` is a string. """ self.assertFilterErrors( { # Not valid; it must be an int. 'stop': '0', 'seed': Seed(self.seed), }, { 'stop': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_stop_float(self): """ ``stop`` is a float. """ self.assertFilterErrors( { # Even with an empty fpart, floats are not valid. # It's gotta be an int. 'stop': 8.0, 'seed': Seed(self.seed), }, { 'stop': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_stop_too_small(self): """ ``stop`` is less than 0. """ self.assertFilterErrors( { 'stop': -1, 'seed': Seed(self.seed), }, { 'stop': [f.Min.CODE_TOO_SMALL], }, ) def test_fail_stop_occurs_before_start(self): """ ``stop`` is less than ``start``. """ self.assertFilterErrors( { 'start': 1, 'stop': 0, 'seed': Seed(self.seed), }, { 'start': [GetAccountDataRequestFilter.CODE_INTERVAL_INVALID], }, ) def test_fail_interval_too_large(self): """ ``stop`` is way more than ``start``. """ self.assertFilterErrors( { 'start': 0, 'stop': GetAccountDataRequestFilter.MAX_INTERVAL + 1, 'seed': Seed(self.seed), }, { 'stop': [GetAccountDataRequestFilter.CODE_INTERVAL_TOO_BIG], }, ) def test_fail_inclusion_states_wrong_type(self): """ ``inclusionStates`` is not a boolean. """ self.assertFilterErrors( { 'inclusionStates': '1', 'seed': Seed(self.seed), }, { 'inclusionStates': [f.Type.CODE_WRONG_TYPE], }, )
class IsPromotableRequestFilterTestCase(BaseFilterTestCase): filter_type = IsPromotableCommand(MockAdapter()).get_request_filter skip_value_check = True def setUp(self): super(IsPromotableRequestFilterTestCase, self).setUp() self.hash1 = ( 'TESTVALUE9DONTUSEINPRODUCTION99999DXSCAD' 'YBVDCTTBLHFYQATFZPYPCBG9FOUKIGMYIGLHM9NEZ' ) self.hash2 = ( 'TESTVALUE9DONTUSEINPRODUCTION99999EMFYSM' 'HWODIAPUTTFDLQRLYIDAUIPJXXEXZZSBVKZEBWGAN' ) def test_pass_happy_path(self): """ Request is valid. """ request = { # Raw trytes are extracted to match the IRI's JSON protocol. 'tails': [self.hash1, self.hash2], } filter_ = self._filter(request) self.assertFilterPasses(filter_) self.assertDictEqual(filter_.cleaned_data, request) def test_pass_compatible_types(self): """ Request contains values that can be converted to the expected types. """ filter_ = self._filter({ 'tails': [ # Any TrytesCompatible value can be used here. TransactionHash(self.hash1), bytearray(self.hash2.encode('ascii')), ], }) self.assertFilterPasses(filter_) self.assertDictEqual( filter_.cleaned_data, { # Raw trytes are extracted to match the IRI's JSON protocol. 'tails': [self.hash1, self.hash2], }, ) def test_fail_empty(self): """ Request is empty. """ self.assertFilterErrors( {}, { 'tails': [f.FilterMapper.CODE_MISSING_KEY], }, ) def test_fail_unexpected_parameters(self): """ Request contains unexpected parameters. """ self.assertFilterErrors( { 'tails': [TransactionHash(self.hash1)], 'foo': 'bar', }, { 'foo': [f.FilterMapper.CODE_EXTRA_KEY], }, ) def test_fail_tails_null(self): """ ``tails`` is null. """ self.assertFilterErrors( { 'tails': None, }, { 'tails': [f.Required.CODE_EMPTY], }, ) def test_fail_tails_wrong_type(self): """ ``tails`` is not an array. """ self.assertFilterErrors( { # It's gotta be an array, even if there's only one hash. 'tails': TransactionHash(self.hash1), }, { 'tails': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_tails_empty(self): """ ``tails`` is an array, but it is empty. """ self.assertFilterErrors( { 'tails': [], }, { 'tails': [f.Required.CODE_EMPTY], }, ) def test_fail_tails_contents_invalid(self): """ ``tails`` is a non-empty array, but it contains invalid values. """ self.assertFilterErrors( { 'tails': [ b'', True, None, b'not valid trytes', # This is actually valid; I just added it to make sure the # filter isn't cheating! TryteString(self.hash1), 2130706433, b'9' * 82, ], }, { 'tails.0': [f.Required.CODE_EMPTY], 'tails.1': [f.Type.CODE_WRONG_TYPE], 'tails.2': [f.Required.CODE_EMPTY], 'tails.3': [Trytes.CODE_NOT_TRYTES], 'tails.5': [f.Type.CODE_WRONG_TYPE], 'tails.6': [Trytes.CODE_WRONG_FORMAT], }, )
def setUp(self): super(SendTransferCommandTestCase, self).setUp() self.adapter = MockAdapter() self.command = SendTransferCommand(self.adapter)
class IsPromotableCommandTestCase(TestCase): def setUp(self): super(IsPromotableCommandTestCase, self).setUp() self.adapter = MockAdapter() self.command = IsPromotableCommand(self.adapter) # Define some tryte sequences that we can re-use across tests. self.trytes1 = TransactionTrytes( 'CCGCVADBEACCWCXCGDEAXCGDEAPCEAHDTCGDHDEAHDFDPCBDGDPCRCHDXCCDBDE' 'ACDBD9DMDSA9999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999ETTEXDKDEUALTLRJVX' 'RHCPRJDLGPJCEQBJOMOAGBZWZCWLNUEWHAUSYJMYPEZPYNBTPSPGUIPQ9VOUNQ9' '999999999999999999999999999JVPROMOTABLETEST99999999999USHRPBD99' '999999999999999999XFVLEXEJPTYI9TUA9ULFNHXBGDUCOEPDIBKSZFXEBO9HF' 'EGLENBCOVKHZ99IWZVCVSTUGKTIBEOVFBJPCDYHBDEIIBLHRVQX9KVVRTUIQMOF' 'XUUETRIQCCCLSMVREZSNEXLIZCIUYIYRBJIBOKNJCQAJTAHGNZ9999DYHBDEIIB' 'LHRVQX9KVVRTUIQMOFXUUETRIQCCCLSMVREZSNEXLIZCIUYIYRBJIBOKNJCQAJT' 'AHGNZ9999ISPROMOTABLETEST9999999999999BFQOIOF999999999MMMMMMMMM' 'EL999999999AG99999999999999' ) self.hash1 = TransactionHash( 'MHNBILKFU9CADOPNWSFYOMILGKJAHEU9GSSOYUEAPBGOOLAIKGBYSACXMFQRJZE' 'PBSHI9SDKMBRK99999' ) self.trytes2 = TransactionTrytes( 'CCGCVADBEACCWCXCGDEAXCGDEAPCEAHDTCGDHDEAHDFDPCBDGDPCRCHDXCCDBDEA' 'CDBD9DMDSA999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '99999999999ETTEXDKDEUALTLRJVXRHCPRJDLGPJCEQBJOMOAGBZWZCWLNUEWHAU' 'SYJMYPEZPYNBTPSPGUIPQ9VOUNQ9999999999999999999999999999JVPROMOTA' 'BLETEST99999999999USHRPBD99999999999999999999XFVLEXEJPTYI9TUA9UL' 'FNHXBGDUCOEPDIBKSZFXEBO9HFEGLENBCOVKHZ99IWZVCVSTUGKTIBEOVFBJPCDA' 'WCMHRLDQPBBGISNENMIXOGGYSRYXGAFEJC9FOLXLYIQVUHFCMVRPBIEAXDUYYPYN' 'EZPHH9KB9HZ9999DAWCMHRLDQPBBGISNENMIXOGGYSRYXGAFEJC9FOLXLYIQVUHF' 'CMVRPBIEAXDUYYPYNEZPHH9KB9HZ9999ISPROMOTABLETEST99999999999IOCFQ' 'OIOF999999999MMMMMMMMMCAA9999999UYA99999999999999' ) self.hash2 = TransactionHash( 'FLNPRAOEYMBIXZBBFMQGCEWLRKTZTMWWTVUQRNUNMZR9EMVKETRMWHRMBFWHJHX' 'ZOIMUWZALX9IVZ9999' ) # Tuesday, October 29, 2019 4:19:43.600 PM GMT+01:00 self.valid_now = 1572362383600 """ Timestamp that is just greater than the later timestamp in self.trytes. """ 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.is_promotable.IsPromotableCommand.__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.is_promotable('tails') self.assertTrue(mocked_command.called) self.assertEqual( response, 'You found me!' ) @async_test 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.is_promotable.IsPromotableCommand.__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.is_promotable('tails') self.assertTrue(mocked_command.called) self.assertEqual( response, 'You found me!' ) @async_test async def test_happy_path(self): """ Successfully checking promotability. """ self.adapter.seed_response('checkConsistency', { 'state': True, }) self.adapter.seed_response('getTrytes', { 'trytes': [self.trytes1, self.trytes2] }) with mock.patch('iota.commands.extended.is_promotable.get_current_ms', mock.MagicMock(return_value=self.valid_now)): response = await self.command(tails=[self.hash1, self.hash2]) self.assertDictEqual( response, { 'promotable': True, } ) @async_test async def test_not_consistent(self): """ One of the tails is not consistent. """ self.adapter.seed_response('checkConsistency', { 'state': False, 'info': 'Oops, something went wrong.', }) # No need for mokcing `getTrytes` becasue we should not # reach that part response = await self.command(tails=[self.hash1, self.hash2]) self.assertDictEqual( response, { 'promotable': False, 'info': 'Oops, something went wrong.', } ) @async_test async def test_one_timestamp_invalid(self): """ Test invalid timestamp in one of the transactions. """ # Note that self.trytes2 will have the original and # therefore invalid (too old) timestamp tx = Transaction.from_tryte_string(self.trytes1) tx.attachment_timestamp = get_current_ms() self.trytes1 = tx.as_tryte_string() self.adapter.seed_response('checkConsistency', { 'state': True, }) self.adapter.seed_response('getTrytes', { 'trytes': [self.trytes1, self.trytes2] }) # Here we don`t mock get_current_ms. # Tx 1 will have updated, passing timestamp. # Tx 2 has the old one, so should fail. response = await self.command(tails=[self.hash1, self.hash2]) self.assertDictEqual( response, { 'promotable': False, 'info': ['Transaction {tx_hash} is above max depth.'.format( tx_hash=self.hash2 )], } ) def test_is_within_depth(self): """ Test ``is_within_depth`` helper method. """ # Timestamp is too old (depth=6) now = get_current_ms() old_timestamp = now - (6 * MILESTONE_INTERVAL - ONE_WAY_DELAY) self.assertEqual( is_within_depth(old_timestamp, now), False ) # Timestamp points to the future (any number would do) future_timestamp = now + 10 self.assertEqual( is_within_depth(future_timestamp, now), False ) # Timestamp is valid ( appr. one second 'old') timestamp = now - 1000 self.assertEqual( is_within_depth(timestamp, now), True )
class GetTransfersCommandTestCase(TestCase): def setUp(self): super(GetTransfersCommandTestCase, self).setUp() self.adapter = MockAdapter() self.command = GetTransfersCommand(self.adapter) # Define some tryte sequences we can re-use between tests. self.addy1 =\ Address( b'TESTVALUEONE9DONTUSEINPRODUCTION99999YDZ' b'E9TAFAJGJA9CECKDAEPHBICDR9LHFCOFRBQDHC9IG' ) self.addy2 =\ Address( b'TESTVALUETWO9DONTUSEINPRODUCTION99999TES' b'GINEIDLEEHRAOGEBMDLENFDAFCHEIHZ9EBZDD9YHL' ) def test_wireup(self): """ Verify that the command is wired up correctly. """ self.assertIsInstance( Iota(self.adapter).getTransfers, GetTransfersCommand, ) def test_full_scan(self): """ Scanning the Tangle for all transfers. """ # To speed up the test, we will mock the address generator. # :py:class:`iota.crypto.addresses.AddressGenerator` already has # its own test case, so this does not impact the stability of the # codebase. # noinspection PyUnusedLocal def create_generator(ag, start, step=1): for addy in [self.addy1, self.addy2][start::step]: yield addy # The first address received IOTA. self.adapter.seed_response( 'findTransactions', { 'duration': 42, 'hashes': [ 'TESTVALUEFIVE9DONTUSEINPRODUCTION99999VH' 'YHRHJETGYCAFZGABTEUBWCWAS9WF99UHBHRHLIOFJ', ], }, ) # The second address is unused. self.adapter.seed_response( 'findTransactions', { 'duration': 1, 'hashes': [], }, ) self.adapter.seed_response( 'getTrytes', { 'duration': 99, # Thankfully, we do not have to seed a realistic response for # ``getTrytes``, as we will be mocking the ``getBundles`` # command that uses on it. 'trytes': [''], }, ) bundle = Bundle([ Transaction( address = self.addy1, timestamp = 1483033814, # These values are not relevant to the test. hash_ = None, signature_message_fragment = None, value = 42, tag = Tag(b''), current_index = 0, last_index = 0, bundle_hash = None, trunk_transaction_hash = None, branch_transaction_hash = None, attachment_timestamp = 1483033814, attachment_timestamp_lower_bound = 12, attachment_timestamp_upper_bound = 0, nonce = None, ) ]) mock_get_bundles =\ mock.Mock(return_value={ 'bundles': [bundle], }) with mock.patch( 'iota.crypto.addresses.AddressGenerator.create_iterator', create_generator, ): with mock.patch( 'iota.commands.extended.get_bundles.GetBundlesCommand._execute', mock_get_bundles, ): response = self.command(seed=Seed.random()) self.assertDictEqual( response, { 'bundles': [bundle], }, ) def test_no_transactions(self): """ There are no transactions for the specified seed. """ # To speed up the test, we will mock the address generator. # :py:class:`iota.crypto.addresses.AddressGenerator` already has # its own test case, so this does not impact the stability of the # codebase. # noinspection PyUnusedLocal def create_generator(ag, start, step=1): for addy in [self.addy1][start::step]: yield addy self.adapter.seed_response( 'findTransactions', { 'duration': 1, 'hashes': [], }, ) with mock.patch( 'iota.crypto.addresses.AddressGenerator.create_iterator', create_generator, ): response = self.command(seed=Seed.random()) self.assertDictEqual(response, {'bundles': []}) def test_start(self): """ Scanning the Tangle for all transfers, with start index. """ # noinspection PyUnusedLocal def create_generator(ag, start, step=1): # Inject an invalid value into the generator, to ensure it is # skipped. for addy in [None, self.addy1, self.addy2][start::step]: yield addy # The first address received IOTA. self.adapter.seed_response( 'findTransactions', { 'duration': 42, 'hashes': [ 'TESTVALUEFIVE9DONTUSEINPRODUCTION99999VH' 'YHRHJETGYCAFZGABTEUBWCWAS9WF99UHBHRHLIOFJ', ], }, ) # The second address is unused. self.adapter.seed_response( 'findTransactions', { 'duration': 1, 'hashes': [], }, ) self.adapter.seed_response( 'getTrytes', { 'duration': 99, 'trytes': [''], }, ) bundle = Bundle([ Transaction( address = self.addy1, timestamp = 1483033814, # These values are not relevant to the test. hash_ = None, signature_message_fragment = None, value = 42, tag = Tag(b''), current_index = 0, last_index = 0, bundle_hash = None, trunk_transaction_hash = None, branch_transaction_hash = None, attachment_timestamp = 1483033814, attachment_timestamp_lower_bound = 12, attachment_timestamp_upper_bound = 0, nonce = None, ) ]) mock_get_bundles = mock.Mock(return_value={ 'bundles': [bundle], }) with mock.patch( 'iota.crypto.addresses.AddressGenerator.create_iterator', create_generator, ): with mock.patch( 'iota.commands.extended.get_bundles.GetBundlesCommand._execute', mock_get_bundles, ): response = self.command(seed=Seed.random(), start=1) self.assertDictEqual( response, { 'bundles': [bundle], }, ) def test_stop(self): """ Scanning the Tangle for all transfers, with stop index. """ # noinspection PyUnusedLocal def create_generator(ag, start, step=1): # Inject an invalid value into the generator, to ensure it is # skipped. for addy in [self.addy1, None][start::step]: yield addy # The first address received IOTA. self.adapter.seed_response( 'findTransactions', { 'duration': 42, 'hashes': [ 'TESTVALUEFIVE9DONTUSEINPRODUCTION99999VH' 'YHRHJETGYCAFZGABTEUBWCWAS9WF99UHBHRHLIOFJ', ], }, ) self.adapter.seed_response( 'getTrytes', { 'duration': 99, 'trytes': [''], }, ) bundle = Bundle([ Transaction( address = self.addy1, timestamp = 1483033814, # These values are not relevant to the test. hash_ = None, signature_message_fragment = None, value = 42, tag = Tag(b''), current_index = 0, last_index = 0, bundle_hash = None, trunk_transaction_hash = None, branch_transaction_hash = None, attachment_timestamp = 1483033814, attachment_timestamp_lower_bound = 12, attachment_timestamp_upper_bound = 0, nonce = None, ) ]) mock_get_bundles = mock.Mock(return_value={ 'bundles': [bundle], }) with mock.patch( 'iota.crypto.addresses.AddressGenerator.create_iterator', create_generator, ): with mock.patch( 'iota.commands.extended.get_bundles.GetBundlesCommand._execute', mock_get_bundles, ): response = self.command(seed=Seed.random(), stop=1) self.assertDictEqual( response, { 'bundles': [bundle], }, ) def test_get_inclusion_states(self): """ Fetching inclusion states with transactions. """ # noinspection PyUnusedLocal def create_generator(ag, start, step=1): for addy in [self.addy1][start::step]: yield addy # The first address received IOTA. self.adapter.seed_response( 'findTransactions', { 'duration': 42, 'hashes': [ 'TESTVALUEFIVE9DONTUSEINPRODUCTION99999VH' 'YHRHJETGYCAFZGABTEUBWCWAS9WF99UHBHRHLIOFJ', ], }, ) # For this test, we have to generate a real TryteString. transaction_trytes =\ TryteString( b'KMYUMNEUAYODAQSNGWTAERRRHNZBZCOLMVVOBTVWLOFYCJKYMGRAMH9RQ9MTZOSZMH' b'QNZFHFEJEDFQ99HSUNVOTULDJGXEDULS9ZHABVDZODJUMCNWVCPNSCUVKVYWCEXBHW' b'RBZBSWFPQLWZWMUPGQIGAEGOVE9DDXBVCIPKQYCFZFBELTSMVFSIXLPTACTKAFMCTK' b'CPYD9BWDJMLKWAOBDSJNQYAHS9GFIQKZCROLFZJVUEIVXVNBRRLEIWTYVHURUXHSCG' b'DKEIEGPOCXKCYWIBUG9ABYCALYJVFLBNGMS9ARHGTQXBZFLENXCJVKHPVKD9KSAEOL' b'FFVAJCNKLDVHOCDARWUNKARDYMVKFKRSMUTYOUXSBFFYTKRREBDJZTLVUROQFCBXQN' b'SXDDYTZTEBRSXOBMLXHJKSJAVOOVCXATOWNQDWHT9CCUAAJUJKDOQLMAEZACSNFKXZ' b'IGWDQEUEFRZYAOSDNVMSXWYLVDAUXZSHNHAIBEMNPFUGORYUETNJK9UCEMSUJYBBDK' b'BHIPKEINQCGOVYCPKUPJMUCUVZOJSIWYRFMFXYUVSMOUALAQBWIMXBUBXSAETGKJRP' b'AHVAXHQJDMEVSRFYEXUSIEBKMGYCUKFD9JPGUV9AIYUVCRUURKMYUHMVE9OJCYYWTQ' b'WUWFMTBZYFXASHHVCMSWXKBRQFHHQVEQMEULJRWZKLWFFSGGKEHUZZFNDNITSRAUH9' b'PQK9OGLYMVBSHXQLLZHOBBIM9KVUWDLHZRDKQQVLQXGWYXEEVQPDZUO9PVXMALOMRQ' b'VCTHGIZLILSCFKTBRESYZGBZKHXEODNDJZ9GK9ROWYXNGFHZCCBHHZEYEOGWXRGSUD' b'SUZFUAUBXVXZHCUVJSYBWTCYCEDYKZNGWFZYKSQLW9FUYMWDVXKZEWT9SCVMQCODZK' b'DRNKTINTPNOJOLGQJDAJMFWRFSWZJLYZGSTSIDSXLUJBZRZNLEDNBKAUNGTCYUPDRW' b'JOCEBQ9YG9IZLLRMJITISJOTLQMOGXVQIZXHMTJVMMWM9FOIOT9KFZMANEPOEOV9HX' b'JNEGURUKRWDGYNPVGAWMWQVABIJNL9MDXKONEPMYACOZ9BE9UZMAFTKYWPFWIQWAPK' b'GUXQTOQVWYYVZYGQDLBIQDVOZIWGOMGOBAUARICQZVNXD9UVEFBBAJKQBHRHXTBUOW' b'VBFKYQWZWTMMXVKZRIZUBVPQ9XHLJHFHWFZUIZVSNAKBDHDFGJCYQETOMEDTOXIUT9' b'OAJVIHWAGTCNPEZTERMMN9EZEWSJHKQAUMXPBZTNQOEQCVXIMAAYO9NIUFLTCFIMK9' b'9AFAGWJFA9VOFPUDJLRAMORGSUDBLWWKXEDZ9XPQUZSGANGESHKKGGQSGSYDCRLHZD' b'PKA9HKYBKLKKCXYRQQIPXCFETJJDZYPCLUNHGBKEJDRCIHEXKCQQNOV9QFHLGFXOCR' b'HPAFCUTPMY9NOZVQHROYJSCMGRSVMOBWADAZNFIAHWGIQUUZBOVODSFAUNRTXSDU9W' b'EIRBXQNRSJXFRAQGHA9DYOQJGLVZUJKAQ9CTUOTT9ZKQOQNNLJDUPDXZJYPRCVLRZT' b'UCZPNBREYCCKHK9FUWGITAJATFPUOFLZDHPNJYUTXFGNYJOBRD9BVHKZENFXIUYDTL' b'CE9JYIIYMXMCXMWTHOLTQFKFHDLVPGMQNITEUXSYLAQULCZOJVBIPYP9M9X9QCNKBX' b'W9DVJEQFFY9KQVMKNVTAHQVRXUKEM9FZOJLHAGEECZBUHOQFZOSPRXKZOCCKAOHMSV' b'QCFG9CWAHKVWNA9QTLYQI9NKOSHWJCNGPJBLEQPUIWJBIOAWKLBXUCERTSL9FVCLYN' b'ADPYTPKJOIEMAQGWBVGSRCZINXEJODUDCT9FHOUMQM9ZHRMBJYSOMPNMEAJGEHICJI' b'PVXRKCYX9RZVT9TDZIMXGZJAIYJRGIVMSOICSUINRBQILMJOUQYXCYNJ9WGGJFHYTU' b'LWOIPUXXFNTIFNOJRZFSQQNAWBQZOLHHLVGHEPWTKKQEVIPVWZUN9ZBICZ9DZZBVII' b'BF9EPHARZJUFJGBQXQFQIBUECAWRSEKYJNYKNSVBCOWTFBZ9NAHFSAMRBPEYGPRGKW' b'WTWACZOAPEOECUO9OTMGABJVAIICIPXGSXACVINSYEQFTRCQPCEJXZCY9XZWVWVJRZ' b'CYEYNFUUBKPWCHICGJZXKE9GSUDXZYUAPLHAKAHYHDXNPHENTERYMMBQOPSQIDENXK' b'LKCEYCPVTZQLEEJVYJZV9BWU999999999999999999999999999FFL999999999999' b'9999999999999RJQGVD99999999999A99999999USGBXHGJUEWAUAKNPPRHJXDDMQV' b'YDSYZJSDWFYLOQVFGBOSLE9KHFDLDYHUYTXVSFAFCOCLQUHJXTEIQRNBTLHEGJFGVF' b'DJCE9IKAOCSYHLCLWPVVNWNESKLYAJG9FGGZOFXCEYOTWLVIJUHGY9QCU9FMZJY999' b'9999HYBUYQKKRNAVDPVGYBTVDZ9SVQBLCCVLJTPEQWWOIG9CQZIFQKCROH9YHUCNJT' b'SYPBVZVBNESX999999D9TARGPQTNIYRZURQGVHCAWEDRBJIIEJIUZYENVE9LLJQMXH' b'GSUUYUCPSOWBCXVFDCHHAZUDC9LUODYWO' ) self.adapter.seed_response( 'getTrytes', { 'duration': 99, 'trytes': [binary_type(transaction_trytes)], }, ) transaction = Transaction.from_tryte_string(transaction_trytes) mock_get_bundles = mock.Mock(return_value={ 'bundles': [Bundle([transaction])], }) mock_get_latest_inclusion = mock.Mock(return_value={ 'states': { transaction.hash: True, }, }) with mock.patch( 'iota.crypto.addresses.AddressGenerator.create_iterator', create_generator, ): with mock.patch( 'iota.commands.extended.get_bundles.GetBundlesCommand._execute', mock_get_bundles, ): with mock.patch( 'iota.commands.extended.get_latest_inclusion.GetLatestInclusionCommand._execute', mock_get_latest_inclusion, ): response = self.command( seed = Seed.random(), inclusionStates = True, # To keep the test focused, only retrieve a single # transaction. start = 0, stop = 1, ) bundle = response['bundles'][0] # type: Bundle self.assertTrue(bundle[0].is_confirmed)
class GetNewAddressesRequestFilterTestCase(BaseFilterTestCase): filter_type = GetNewAddressesCommand(MockAdapter()).get_request_filter skip_value_check = True # noinspection SpellCheckingInspection def setUp(self): super(GetNewAddressesRequestFilterTestCase, self).setUp() # Define a few tryte sequences that we can re-use between tests. self.seed = b'HELLOIOTA' def test_pass_happy_path(self): """ Request is valid. """ request = { 'seed': Seed(self.seed), 'index': 1, 'count': 1, } filter_ = self._filter(request) self.assertFilterPasses(filter_) self.assertDictEqual(filter_.cleaned_data, request) def test_pass_optional_parameters_excluded(self): """ Request omits ``index`` and ``count``. """ filter_ = self._filter({ 'seed': Seed(self.seed), }) self.assertFilterPasses(filter_) self.assertDictEqual( filter_.cleaned_data, { 'seed': Seed(self.seed), 'index': 0, 'count': None, }, ) def test_pass_compatible_types(self): """ Request contains values that can be converted to the expected types. """ filter_ = self._filter({ # ``seed`` can be any value that is convertible to TryteString. 'seed': binary_type(self.seed), # These values must be integers, however. 'index': 100, 'count': 8, }) self.assertFilterPasses(filter_) self.assertDictEqual( filter_.cleaned_data, { 'seed': Seed(self.seed), 'index': 100, 'count': 8, }, ) def test_fail_empty(self): """ Request is empty. """ self.assertFilterErrors( {}, { 'seed': [f.FilterMapper.CODE_MISSING_KEY], }, ) def test_fail_unexpected_parameters(self): """ Request contains unexpected parameters. """ self.assertFilterErrors( { 'seed': Seed(self.seed), 'index': None, 'count': 1, # Some men just want to watch the world burn. 'foo': 'bar', }, { 'foo': [f.FilterMapper.CODE_EXTRA_KEY], }, ) def test_fail_seed_null(self): """ ``seed`` is null. """ self.assertFilterErrors( { 'seed': None, }, { 'seed': [f.Required.CODE_EMPTY], }, ) def test_fail_seed_wrong_type(self): """ ``seed`` cannot be converted into a TryteString. """ self.assertFilterErrors( { 'seed': text_type(self.seed, 'ascii'), }, { 'seed': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_seed_malformed(self): """ ``seed`` has the correct type, but it contains invalid characters. """ self.assertFilterErrors( { 'seed': b'not valid; seeds can only contain uppercase and "9".', }, { 'seed': [Trytes.CODE_NOT_TRYTES], }, ) def test_fail_count_string(self): """ ``count`` is a string value. """ self.assertFilterErrors( { # Not valid; it must be an int. 'count': '42', 'seed': Seed(self.seed), }, { 'count': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_count_float(self): """ ``count`` is a float value. """ self.assertFilterErrors( { # Not valid, even with an empty fpart; it must be an int. 'count': 42.0, 'seed': Seed(self.seed), }, { 'count': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_count_too_small(self): """ ``count`` is less than 1. """ self.assertFilterErrors( { 'count': 0, 'seed': Seed(self.seed), }, { 'count': [f.Min.CODE_TOO_SMALL], }, ) def test_fail_index_string(self): """ ``index`` is a string value. """ self.assertFilterErrors( { # Not valid; it must be an int. 'index': '42', 'seed': Seed(self.seed), }, { 'index': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_index_float(self): """ ``index`` is a float value. """ self.assertFilterErrors( { # Not valid, even with an empty fpart; it must be an int. 'index': 42.0, 'seed': Seed(self.seed), }, { 'index': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_index_too_small(self): """ ``index`` is less than 0. """ self.assertFilterErrors( { 'index': -1, 'seed': Seed(self.seed), }, { 'index': [f.Min.CODE_TOO_SMALL], }, )
class PromoteTransactionRequestFilterTestCase(BaseFilterTestCase): filter_type = PromoteTransactionCommand(MockAdapter()).get_request_filter skip_value_check = True # noinspection SpellCheckingInspection def setUp(self): super(PromoteTransactionRequestFilterTestCase, self).setUp() self.trytes1 = (b'TESTVALUEONE9DONTUSEINPRODUCTION99999DAU' b'9WFSFWBSFT9QATCXFIIKDVFLHIIJGGFCDYENBEDCF') def test_pass_happy_path(self): """ Request is valid. """ request = { 'depth': 100, 'minWeightMagnitude': 18, 'transaction': TransactionHash(self.trytes1), } filter_ = self._filter(request) self.assertFilterPasses(filter_) self.assertDictEqual(filter_.cleaned_data, request) def test_pass_compatible_types(self): """ Request contains values that can be converted to the expected types. """ filter_ = self._filter({ # This can be any TrytesCompatible value. 'transaction': binary_type(self.trytes1), # These values must still be ints, however. 'depth': 100, 'minWeightMagnitude': 18, }) self.assertFilterPasses(filter_) self.assertDictEqual( filter_.cleaned_data, { 'depth': 100, 'minWeightMagnitude': 18, 'transaction': TransactionHash(self.trytes1), }, ) def test_fail_empty(self): """ Request is empty. """ self.assertFilterErrors( {}, { 'depth': [f.FilterMapper.CODE_MISSING_KEY], 'minWeightMagnitude': [f.FilterMapper.CODE_MISSING_KEY], 'transaction': [f.FilterMapper.CODE_MISSING_KEY], }, ) def test_fail_unexpected_parameters(self): """ Request contains unexpected parameters. """ self.assertFilterErrors( { 'depth': 100, 'minWeightMagnitude': 18, 'transaction': TransactionHash(self.trytes1), # That's a real nasty habit you got there. 'foo': 'bar', }, { 'foo': [f.FilterMapper.CODE_EXTRA_KEY], }, ) def test_fail_transaction_null(self): """ ``transaction`` is null. """ self.assertFilterErrors( { 'transaction': None, 'depth': 100, 'minWeightMagnitude': 18, }, { 'transaction': [f.Required.CODE_EMPTY], }, ) def test_fail_transaction_wrong_type(self): """ ``transaction`` is not a TrytesCompatible value. """ self.assertFilterErrors( { 'transaction': 42, 'depth': 100, 'minWeightMagnitude': 18, }, { 'transaction': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_transaction_not_trytes(self): """ ``transaction`` contains invalid characters. """ self.assertFilterErrors( { 'transaction': b'not valid; must contain only uppercase and "9"', 'depth': 100, 'minWeightMagnitude': 18, }, { 'transaction': [Trytes.CODE_NOT_TRYTES], }, ) def test_fail_depth_null(self): """ ``depth`` is null. """ self.assertFilterErrors( { 'depth': None, 'minWeightMagnitude': 18, 'transaction': TransactionHash(self.trytes1), }, { 'depth': [f.Required.CODE_EMPTY], }, ) def test_fail_depth_string(self): """ ``depth`` is a string. """ self.assertFilterErrors( { # Too ambiguous; it's gotta be an int. 'depth': '4', 'minWeightMagnitude': 18, 'transaction': TransactionHash(self.trytes1), }, { 'depth': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_depth_float(self): """ ``depth`` is a float. """ self.assertFilterErrors( { # Even with an empty fpart, float value is not valid. 'depth': 8.0, 'minWeightMagnitude': 18, 'transaction': TransactionHash(self.trytes1), }, { 'depth': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_depth_too_small(self): """ ``depth`` is < 1. """ self.assertFilterErrors( { 'depth': 0, 'minWeightMagnitude': 18, 'transaction': TransactionHash(self.trytes1), }, { 'depth': [f.Min.CODE_TOO_SMALL], }, ) def test_fail_min_weight_magnitude_null(self): """ ``minWeightMagnitude`` is null. """ self.assertFilterErrors( { 'minWeightMagnitude': None, 'depth': 100, 'transaction': TransactionHash(self.trytes1), }, { 'minWeightMagnitude': [f.Required.CODE_EMPTY], }, ) def test_fail_min_weight_magnitude_string(self): """ ``minWeightMagnitude`` is a string. """ self.assertFilterErrors( { # It's gotta be an int! 'minWeightMagnitude': '18', 'depth': 100, 'transaction': TransactionHash(self.trytes1), }, { 'minWeightMagnitude': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_min_weight_magnitude_float(self): """ ``minWeightMagnitude`` is a float. """ self.assertFilterErrors( { # Even with an empty fpart, float values are not valid. 'minWeightMagnitude': 18.0, 'depth': 100, 'transaction': TransactionHash(self.trytes1), }, { 'minWeightMagnitude': [f.Type.CODE_WRONG_TYPE], }, ) def test_fail_min_weight_magnitude_too_small(self): """ ``minWeightMagnitude`` is < 1. """ self.assertFilterErrors( { 'minWeightMagnitude': 0, 'depth': 100, 'transaction': TransactionHash(self.trytes1), }, { 'minWeightMagnitude': [f.Min.CODE_TOO_SMALL], }, )
def setUp(self): super(IsReattachableCommandTestCase, self).setUp() self.adapter = MockAdapter()
class PromoteTransactionCommandTestCase(TestCase): def setUp(self): super(PromoteTransactionCommandTestCase, self).setUp() self.adapter = MockAdapter() self.command = PromoteTransactionCommand(self.adapter) self.trytes1 = b'RBTC9D9DCDQAEASBYBCCKBFA' self.trytes2 =\ b'CCPCBDVC9DTCEAKDXC9D9DEARCWCPCBDVCTCEAHDWCTCEAKDCDFD9DSCSA' self.hash1 = TransactionHash( b'TESTVALUE9DONTUSEINPRODUCTION99999TBPDM9' b'ADFAWCKCSFUALFGETFIFG9UHIEFE9AYESEHDUBDDF') def test_wireup(self): """ Verifies that the command is wired-up correctly. """ self.assertIsInstance( Iota(self.adapter).promoteTransaction, PromoteTransactionCommand, ) 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_not_promotable(self): """ Bundle isn't promotable. """ self.adapter.seed_response('checkConsistency', { 'state': False, }) with self.assertRaises(BadApiResponse): response = self.command( transaction=self.hash1, depth=3, minWeightMagnitude=16, )
def setUp(self): super(IsPromotableCommandTestCase, self).setUp() self.adapter = MockAdapter() self.command = IsPromotableCommand(self.adapter) # Define some tryte sequences that we can re-use across tests. self.trytes1 = TransactionTrytes( 'CCGCVADBEACCWCXCGDEAXCGDEAPCEAHDTCGDHDEAHDFDPCBDGDPCRCHDXCCDBDE' 'ACDBD9DMDSA9999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999999999999999999999' '999999999999999999999999999999999999999999999ETTEXDKDEUALTLRJVX' 'RHCPRJDLGPJCEQBJOMOAGBZWZCWLNUEWHAUSYJMYPEZPYNBTPSPGUIPQ9VOUNQ9' '999999999999999999999999999JVPROMOTABLETEST99999999999USHRPBD99' '999999999999999999XFVLEXEJPTYI9TUA9ULFNHXBGDUCOEPDIBKSZFXEBO9HF' 'EGLENBCOVKHZ99IWZVCVSTUGKTIBEOVFBJPCDYHBDEIIBLHRVQX9KVVRTUIQMOF' 'XUUETRIQCCCLSMVREZSNEXLIZCIUYIYRBJIBOKNJCQAJTAHGNZ9999DYHBDEIIB' 'LHRVQX9KVVRTUIQMOFXUUETRIQCCCLSMVREZSNEXLIZCIUYIYRBJIBOKNJCQAJT' 'AHGNZ9999ISPROMOTABLETEST9999999999999BFQOIOF999999999MMMMMMMMM' 'EL999999999AG99999999999999' ) self.hash1 = TransactionHash( 'MHNBILKFU9CADOPNWSFYOMILGKJAHEU9GSSOYUEAPBGOOLAIKGBYSACXMFQRJZE' 'PBSHI9SDKMBRK99999' ) self.trytes2 = TransactionTrytes( 'CCGCVADBEACCWCXCGDEAXCGDEAPCEAHDTCGDHDEAHDFDPCBDGDPCRCHDXCCDBDEA' 'CDBD9DMDSA999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '9999999999999999999999999999999999999999999999999999999999999999' '99999999999ETTEXDKDEUALTLRJVXRHCPRJDLGPJCEQBJOMOAGBZWZCWLNUEWHAU' 'SYJMYPEZPYNBTPSPGUIPQ9VOUNQ9999999999999999999999999999JVPROMOTA' 'BLETEST99999999999USHRPBD99999999999999999999XFVLEXEJPTYI9TUA9UL' 'FNHXBGDUCOEPDIBKSZFXEBO9HFEGLENBCOVKHZ99IWZVCVSTUGKTIBEOVFBJPCDA' 'WCMHRLDQPBBGISNENMIXOGGYSRYXGAFEJC9FOLXLYIQVUHFCMVRPBIEAXDUYYPYN' 'EZPHH9KB9HZ9999DAWCMHRLDQPBBGISNENMIXOGGYSRYXGAFEJC9FOLXLYIQVUHF' 'CMVRPBIEAXDUYYPYNEZPHH9KB9HZ9999ISPROMOTABLETEST99999999999IOCFQ' 'OIOF999999999MMMMMMMMMCAA9999999UYA99999999999999' ) self.hash2 = TransactionHash( 'FLNPRAOEYMBIXZBBFMQGCEWLRKTZTMWWTVUQRNUNMZR9EMVKETRMWHRMBFWHJHX' 'ZOIMUWZALX9IVZ9999' ) # Tuesday, October 29, 2019 4:19:43.600 PM GMT+01:00 self.valid_now = 1572362383600 """
class GetNewAddressesCommandTestCase(TestCase): def setUp(self): super(GetNewAddressesCommandTestCase, self).setUp() self.adapter = MockAdapter() self.command = GetNewAddressesCommand(self.adapter) # Create a few TryteStrings we can reuse across tests. self.addy1 =\ Address( b'ADDYONE999AHHKVD9SBEYWQFNVQSNTGYQSQ9AGWD' b'JDZKBYCVTODUHFEVVMNMPQMIXOVXVCZRUENAWYNTO' ) self.addy2 =\ Address( b'ADDYTWO999AGAQKYXHRMSFAQNPWCIYUYTXPWUEUR' b'VNZTCTFUPQ9ESTKNSSLLIZWDQISJVEWIJDVGIECXF' ) def test_wireup(self): """ Verify that the command is wired up correctly. """ self.assertIsInstance( Iota(self.adapter).getNewAddresses, GetNewAddressesCommand, ) def test_get_addresses_offline(self): """ Generate addresses in offline mode (without filtering used addresses). """ # To speed up the test, we will mock the address generator. # :py:class:`iota.crypto.addresses.AddressGenerator` already has # its own test case, so this does not impact the stability of the # codebase. # noinspection PyUnusedLocal def create_generator(ag, start, step=1): for addy in [self.addy1, self.addy2][start::step]: yield addy with patch( target= 'iota.crypto.addresses.AddressGenerator.create_generator', new=create_generator, ): response = self.command( count=2, index=0, seed=b'TESTSEED9DONTUSEINPRODUCTION99999', ) self.assertDictEqual(response, {'addresses': [self.addy1, self.addy2]}) # No API requests were made. self.assertListEqual(self.adapter.requests, []) def test_get_addresses_online(self): """ Generate address in online mode (filtering used addresses). """ # Pretend that ``self.addy1`` has already been used, but not # ``self.addy2``. self.adapter.seed_response( 'findTransactions', { 'duration': 18, 'hashes': [ 'ZJVYUGTDRPDYFGFXMKOTV9ZWSGFK9CFPXTITQLQN' 'LPPG9YNAARMKNKYQO9GSCSBIOTGMLJUFLZWSY9999', ], }) self.adapter.seed_response('findTransactions', { 'duration': 1, 'hashes': [], }) # To speed up the test, we will mock the address generator. # :py:class:`iota.crypto.addresses.AddressGenerator` already has # its own test case, so this does not impact the stability of the # codebase. # noinspection PyUnusedLocal def create_generator(ag, start, step=1): for addy in [self.addy1, self.addy2][start::step]: yield addy with patch( target= 'iota.crypto.addresses.AddressGenerator.create_generator', new=create_generator, ): response = self.command( # If ``count`` is missing or ``None``, the command will operate # in online mode. # count = None, index=0, seed=b'TESTSEED9DONTUSEINPRODUCTION99999', ) # The command determined that ``self.addy1`` was already used, so # it skipped that one. self.assertDictEqual(response, {'addresses': [self.addy2]}) self.assertListEqual( self.adapter.requests, # The command issued two `findTransactions` API requests: one for # each address generated, until it found an unused address. [ { 'command': 'findTransactions', 'addresses': [self.addy1], 'approvees': [], 'bundles': [], 'tags': [], }, { 'command': 'findTransactions', 'addresses': [self.addy2], 'approvees': [], 'bundles': [], 'tags': [], }, ], )
def setUp(self): super(GetMissingTransactionsCommandTestCase, self).setUp() self.adapter = MockAdapter()
class GetLatestInclusionCommandTestCase(TestCase): # noinspection SpellCheckingInspection def setUp(self): super(GetLatestInclusionCommandTestCase, self).setUp() self.adapter = MockAdapter() self.command = GetLatestInclusionCommand(self.adapter) # Define some tryte sequences that we can re-use across tests. self.milestone =\ TransactionHash( b'TESTVALUE9DONTUSEINPRODUCTION99999W9KDIH' b'BALAYAFCADIDU9HCXDKIXEYDNFRAKHN9IEIDZFWGJ' ) self.hash1 =\ TransactionHash( b'TESTVALUE9DONTUSEINPRODUCTION99999TBPDM9' b'ADFAWCKCSFUALFGETFIFG9UHIEFE9AYESEHDUBDDF' ) self.hash2 =\ TransactionHash( b'TESTVALUE9DONTUSEINPRODUCTION99999CIGCCF' b'KIUFZF9EP9YEYGQAIEXDTEAAUGAEWBBASHYCWBHDX' ) def test_wireup(self): """ Verify that the command is wired up correctly. """ self.assertIsInstance( Iota(self.adapter).getLatestInclusion, GetLatestInclusionCommand, ) def test_happy_path(self): """ Successfully requesting latest inclusion state. """ self.adapter.seed_response('getNodeInfo', { # ``getNodeInfo`` returns lots of info, but the only value that # matters for this test is ``latestSolidSubtangleMilestone``. 'latestSolidSubtangleMilestone': self.milestone, }, ) self.adapter.seed_response('getInclusionStates', { 'states': [True, False], }) response = self.command(hashes=[self.hash1, self.hash2]) self.assertDictEqual( response, { 'states': { self.hash1: True, self.hash2: False, }, } )