def test_on_user_introduction(self, store_patch, api_patch):
        # We'll be introducer the user to the bank. So remove user from the bank
        self.api_bank.db.delete(self.user)

        self.assertFalse(store_patch.called)

        # Set them as false to override the defaults
        store = update = forward = False
        message_name = u"introduce_user"
        candidate = LoopbackCandidate()

        self.community.send_introduce_user([self.user.type],
                                           {self.user.type: self.user},
                                           candidate)

        self.assertTrue(store_patch.called)
        args, _ = store_patch.call_args
        self.assertEqual(type(args[0]), list)
        message = args[0][0]
        self.assertEqual(message.name, message_name)

        # Receive the user as the bank and check if it is found in the database.
        self.assertIsNone(self.api_bank._get_user(self.user))

        # Send it to the bank
        self.assertFalse(api_patch.called)
        self.community_bank.on_user_introduction([message])
        self.assertTrue(api_patch.called)
        # Check if received
        args, _ = api_patch.call_args
        self.assertEqual(self.user.id, args[1].id)
    def test_check_add_genesis_block(self):
        """
        This test checks the functionality of adding a block to an empty blockchain.
        """

        # Check if there are already blocks in the blockchain, if not add genesis block
        self.db.check_add_genesis_block()
        # Get the genesis block
        genesis_block = self.db.create_genesis_block()

        meta = self.community.get_meta_message(u"signed_confirm")
        message = meta.impl(
            authentication=([self.member, self.member_bank], ),
            distribution=(self.community.claim_global_time(), ),
            payload=self.payload,
            destination=(LoopbackCandidate(), ))

        block = DatabaseBlock.from_signed_confirm_message(message)

        # Add the block to the blockchain
        self.db.add_block(block)
        # Get the block by the hash of the block
        result = self.db.get_by_hash(block.hash_block)

        # Check whether the genesis block and the first block are added correctly
        self.assertEqual(result.previous_hash, genesis_block.hash_block)
    def test_from_signed_confirmed(self):
        """
        This test checks the functionality of making a block with the payload from a message.
        """
        meta = self.community.get_meta_message(u"signed_confirm")
        message = meta.impl(
            authentication=([self.member, self.member_bank], ),
            distribution=(self.community.claim_global_time(), ),
            payload=self.payload,
            destination=(LoopbackCandidate(), ))

        block = DatabaseBlock.from_signed_confirm_message(message)

        self.assertEqual(block.benefactor, message.payload.benefactor)
        self.assertEqual(block.beneficiary, message.payload.beneficiary)
        self.assertEqual(DatabaseModel.decode(block.agreement_benefactor),
                         message.payload.agreement_benefactor)
        self.assertEqual(DatabaseModel.decode(block.agreement_beneficiary),
                         message.payload.agreement_beneficiary)
        self.assertEqual(block.sequence_number_benefactor,
                         message.payload.sequence_number_benefactor)
        self.assertEqual(block.sequence_number_beneficiary,
                         message.payload.sequence_number_beneficiary)
        self.assertEqual(block.previous_hash_benefactor,
                         message.payload.previous_hash_benefactor)
        self.assertEqual(block.previous_hash_beneficiary,
                         message.payload.previous_hash_beneficiary)
        self.assertEqual(block.insert_time, message.payload.insert_time)
    def test_update_block_with_beneficiary(self):
        """
        This test checks the functionality of updating a block in the blockchain.
        """

        meta = self.community.get_meta_message(u"signed_confirm")
        message_no_ben = meta.impl(
            authentication=([self.member, self.member_bank], ),
            distribution=(self.community.claim_global_time(), ),
            payload=self.payload2,
            destination=(LoopbackCandidate(), ))

        message_ben = meta.impl(
            authentication=([self.member, self.member_bank], ),
            distribution=(self.community.claim_global_time(), ),
            payload=self.payload,
            destination=(LoopbackCandidate(), ))

        # Add the block with only the information from benefactor to the blockchain
        self.community.persist_signature(message_no_ben)
        # Create the block manually for assertions
        block_benefactor = DatabaseBlock.from_signed_confirm_message(
            message_no_ben)

        # Update the block with the information from the beneficiary
        self.community.update_signature(message_ben)
        # Create the block manually for assertions
        block_beneficiary = DatabaseBlock.from_signed_confirm_message(
            message_ben)

        # Get the updated block by the hash of the block
        result = self.db.get_by_hash(block_beneficiary.hash_block)

        self.assertEqualBlocks(block_beneficiary, result)
        # Get the updated block by the public key and the sequence number
        result_benefactor = self.db.get_by_public_key_and_sequence_number(
            message_ben.payload.benefactor,
            block_benefactor.sequence_number_benefactor)
        result_beneficiary = self.db.get_by_public_key_and_sequence_number(
            message_ben.payload.beneficiary,
            block_beneficiary.sequence_number_beneficiary)

        # Check whether the block was updated correctly
        self.assertEqualBlocks(result_benefactor, result_beneficiary)
        self.assertEqualBlocks(result_benefactor, result)
        self.assertEqualBlocks(result_beneficiary, result)
    def test_add_multiple_blocks(self):
        """
        This test checks the functionality of adding two blocks to the blockchain.
        """

        meta = self.community.get_meta_message(u"signed_confirm")
        message1 = meta.impl(
            authentication=([self.member, self.member_bank], ),
            distribution=(self.community.claim_global_time(), ),
            payload=self.payload,
            destination=(LoopbackCandidate(), ))

        message2 = meta.impl(
            authentication=([self.member, self.member_bank], ),
            distribution=(self.community.claim_global_time(), ),
            payload=self.payload2,
            destination=(LoopbackCandidate(), ))

        block1 = DatabaseBlock.from_signed_confirm_message(message1)
        block2 = DatabaseBlock.from_signed_confirm_message(message2)

        # Add the blocks to the blockchain
        self.db.add_block(block1)
        self.bank_db.add_block(block1)

        self.db.add_block(block2)
        self.bank_db.add_block(block2)

        # Get the blocks by the hash of the block
        result1 = self.db.get_by_hash(block1.hash_block)
        result2 = self.db.get_by_hash(block2.hash_block)

        # Get the latest hash
        latest_hash_benefactor = self.db.get_latest_hash()
        latest_hash_beneficiary = self.bank_db.get_latest_hash()

        # Check whether the blocks were added correctly
        self.assertEqualBlocks(block1, result1)
        self.assertEqualBlocks(block2, result2)
        self.assertNotEqual(block1.hash_block, block2.hash_block)
        self.assertEqual(latest_hash_benefactor, latest_hash_beneficiary)
        self.assertEqual(latest_hash_benefactor, block2.hash_block)
        self.assertEqual(latest_hash_beneficiary, block2.hash_block)
        self.assertNotEqual(latest_hash_benefactor, block1.hash_block)
        self.assertNotEqual(latest_hash_beneficiary, block1.hash_block)
    def test_signature_request_flow(self, persist, update, next_seq, next_hash,
                                    create_sig):
        persist.return_value = True
        update.return_value = True
        next_seq.return_value = 1
        next_hash.return_value = 'hasdhashdsa'
        create_sig.return_value = True

        # Attempt to sign without having a user candidate
        self.assertFalse(
            self.community_bank.publish_signed_confirm_request_message(
                self.user.id, self.mortgage))

        # Set the candidate for the user
        candidate = LoopbackCandidate()
        candidate.associate(self.member)
        self.api_bank.user_candidate[self.user.id] = candidate

        # Attempt to sign without having a user candidate
        self.assertTrue(
            self.community_bank.publish_signed_confirm_request_message(
                self.user.id, self.mortgage))
        self.assertTrue(create_sig.called)
    def test_encode_signed_confirm(self):
        payload_list = []
        for k in range(1, 12):
            payload_list.append(None)

        payload_list[0] = self.user.id  # benefactor, 0
        payload_list[1] = self.bank.id  # beneficiary, 1
        payload_list[2] = self.loan_request
        payload_list[3] = None  # agreement beneficiary
        payload_list[4] = 0
        payload_list[5] = 0  # sequence number beneficiary
        payload_list[6] = 'hashsas'
        payload_list[7] = 'asdasdas'  # previous hash beneficiary
        payload_list[8] = 'sig1'  # Signature benefactor
        payload_list[9] = 'sig2'  # Signature beneficiary
        payload_list[10] = 324325252

        meta = self.community.get_meta_message(u"signed_confirm")
        loop = LoopbackCandidate()
        message = meta.impl(
            authentication=([self.member, self.member], ),
            distribution=(self.community.claim_global_time(), ),
            payload=tuple(payload_list))

        encoded_message = self.conversion._encode_signed_confirm(message)[0]
        decoded_payload = self.conversion._decode_signed_confirm(
            message, 0, encoded_message)[1]

        p1 = message.payload
        p2 = decoded_payload

        assert isinstance(p1, SignedConfirmPayload.Implementation)
        assert isinstance(p2, SignedConfirmPayload.Implementation)

        self.assertEqual(p1.agreement_benefactor, p2.agreement_benefactor)
        self.assertEqual(p1.agreement_beneficiary, p2.agreement_beneficiary)
        self.assertEqual(p1.benefactor, p2.benefactor)
        self.assertEqual(p1.beneficiary, p2.beneficiary)
        self.assertEqual(p1.previous_hash_benefactor,
                         p2.previous_hash_benefactor)
        self.assertEqual(p1.previous_hash_beneficiary,
                         p2.previous_hash_beneficiary)
        self.assertEqual(p1.sequence_number_benefactor,
                         p2.sequence_number_benefactor)
        self.assertEqual(p1.sequence_number_beneficiary,
                         p2.sequence_number_beneficiary)
        self.assertEqual(p1.signature_beneficiary, p2.signature_beneficiary)
        self.assertEqual(p1.signature_benefactor, p1.signature_benefactor)
        self.assertEqual(p1.insert_time, p2.insert_time)
    def test_encode_introduce_user(self):
        meta = self.community.get_meta_message(u"introduce_user")
        message = meta.impl(
            authentication=(self.member, ),
            distribution=(self.community.claim_global_time(), ),
            payload=([self.user.type], {
                self.user.type: self.user
            }),
            destination=(LoopbackCandidate(), ))

        encoded_message = self.conversion._encode_model(message)[0]
        decoded_payload = self.conversion._decode_model(
            message, 0, encoded_message)[1]

        self.assertEqual(message.payload.fields, decoded_payload.fields)
        self.assertEqual(message.payload.models, decoded_payload.models)
    def test_encode_api_request_candidate(self):
        meta = self.community.get_meta_message(u"api_message_candidate")
        message = meta.impl(
            authentication=(self.member, ),
            distribution=(self.community.claim_global_time(), ),
            payload=(
                APIMessage.MORTGAGE_OFFER.value,
                [self.user.type],
                {
                    self.user.type: self.user
                },
            ),
            destination=(LoopbackCandidate(), ))

        encoded_message = self.conversion._encode_api_message(message)[0]
        decoded_payload = self.conversion._decode_api_message(
            message, 0, encoded_message)[1]

        self.assertEqual(message.payload.models, decoded_payload.models)
    def test_add_get(self):
        """
        This test checks the functionality of adding a block to the blockchain then retrieving it.
        """

        meta = self.community.get_meta_message(u"signed_confirm")
        message = meta.impl(
            authentication=([self.member, self.member_bank], ),
            distribution=(self.community.claim_global_time(), ),
            payload=self.payload,
            destination=(LoopbackCandidate(), ))

        block = DatabaseBlock.from_signed_confirm_message(message)

        # Add the block to the blockchain
        self.db.add_block(block)
        # Get the block by the hash of the block
        result = self.db.get_by_hash(block.hash_block)

        # Check whether the block was added correctly
        self.assertEqualBlocks(block, result)
    def test_send_introduce_user(self, patch):
        self.assertFalse(patch.called)

        # Set them as false to override the defaults
        store = update = forward = False
        message_name = u"introduce_user"
        candidate = LoopbackCandidate()

        self.community.send_introduce_user([self.user.type],
                                           {self.user.type: self.user},
                                           candidate, store, update, forward)

        self.assertTrue(patch.called)
        args, kwargs = patch.call_args
        self.assertEqual(type(args[0]), list)

        message = args[0][0]

        self.assertEqual(message.name, message_name)
        self.assertEqual(args[1], store)
        self.assertEqual(args[2], update)
        self.assertEqual(args[3], forward)
    def test_send_candidate_message(self, patch):
        self.assertFalse(patch.called)

        # Set them as false to override the defaults
        store = update = forward = False
        message_name = APIMessage.MORTGAGE_OFFER.value
        candidates = (LoopbackCandidate(), )

        self.community.send_api_message_candidate(
            message_name, [self.loan_request.type],
            {self.loan_request.type: self.loan_request}, candidates, store,
            update, forward)

        self.assertTrue(patch.called)
        args, kwargs = patch.call_args
        self.assertEqual(type(args[0]), list)

        message = args[0][0]

        self.assertEqual(message.payload.request, message_name)
        self.assertEqual(args[1], store)
        self.assertEqual(args[2], update)
        self.assertEqual(args[3], forward)
    def test_create_signed_confirm_request_message(self, persist, update,
                                                   next_seq, next_hash,
                                                   create_sig):
        persist.return_value = True
        update.return_value = True
        next_seq.return_value = 1
        next_hash.return_value = 'hasdhashdsa'
        create_sig.return_value = True

        # Save the agreement for the user
        self.mortgage.post_or_put(self.api.db)
        self.loan_request.post_or_put(self.api_bank.db)

        # Set the candidate for the user
        candidate = LoopbackCandidate()
        candidate.associate(self.member)
        self.api_bank.user_candidate[self.user.id] = candidate

        # Attempt to sign without having a user candidate
        message = self.community_bank.create_signed_confirm_request_message(
            candidate, self.mortgage)

        self.assertEqual(message.name, u"signed_confirm")
        self.assertEqual(message.payload.agreement_benefactor, self.mortgage)
        self.assertEqual(message.payload.benefactor, self.bank.id)
        self.assertTrue(next_hash.called)
        self.assertTrue(next_seq.called)
        self.assertTrue(persist.called)
        self.assertFalse(update.called)

        persist.reset_mock()
        next_hash.reset_mock()
        next_seq.reset_mock()

        message2 = self.community.allow_signed_confirm_request(message)

        self.assertTrue(next_hash.called)
        self.assertTrue(next_seq.called)
        self.assertTrue(persist.called)
        self.assertFalse(update.called)

        self.assertEqual(message.name, message2.name)
        self.assertEqual(message.payload.benefactor,
                         message2.payload.benefactor)
        self.assertNotEqual(message.payload.beneficiary,
                            message2.payload.beneficiary)

        # Finally check if the update call works
        persist.reset_mock()
        next_hash.reset_mock()
        next_seq.reset_mock()

        self.assertTrue(
            self.community_bank.allow_signed_confirm_response(
                message, message2, True))
        self.assertFalse(next_hash.called)
        self.assertFalse(next_seq.called)
        self.assertFalse(persist.called)
        self.assertFalse(update.called)

        self.community_bank.received_signed_confirm_response([message2])

        self.assertTrue(update.called)