Esempio n. 1
0
def test_process_lots_failed(bot, logger, mocker):
    result = bot.process_lots(None)
    assert result is None

    lots = [{'data':
        {
            'status': 'dissolved',
            'id': 'fd122ba678174a19affcb3a0edc96e0e',
            'assets': ["a107b69548b54eb293ad82b36c6936a1"]
        }
    }]
    mock_assets_available = mocker.patch.object(bot, 'check_lot_assets', autospec=True)
    mock_assets_available.side_effect = RequestFailed()

    bot.process_lots(lots)

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[0] == "Could not get any lots"
    assert log_strings[1] == "Got lots"
    assert log_strings[2] == "Processing lot fd122ba678174a19affcb3a0edc96e0e"
    assert log_strings[3] == "Due to fail in getting assets, lot fd122ba678174a19affcb3a0edc96e0e is skipped"
Esempio n. 2
0
    def check_assets(self, lot, status='pending'):
        """
        Makes GET request to openregistry for every asset id in assets list
        from lot object, passed as parameter, with client specified in
        configuration file.

        Args:
            lot: dictionary which contains some fields of lot
                 document from db: id, rev, status, assets, lotID.
            status (str): status, in which assets are considered
                          as available. Defaults to 'pending'.

        Returns:
            bool: True if request was successful and conditions were
                  satisfied, False otherwise.

        Raises:
            RequestFailed: if RequestFailed was raised during request.
        """
        for asset_id in lot['assets']:
            try:
                asset = self.assets_client.get_asset(asset_id).data
                logger.info('Successfully got asset {}'.format(asset_id))
            except ResourceNotFound as e:
                logger.error('Failed to get asset {0}: {1}'.format(
                    asset_id, e.message))
                return False
            except RequestFailed as e:
                logger.error(
                    'Failed to get asset {0}. Status code: {1}'.format(
                        asset_id, e.status_code))
                raise RequestFailed('Failed to get assets')
            if asset.assetType not in self.allowed_asset_types:
                return False
            related_lot_check = 'relatedLot' in asset and asset.relatedLot != lot[
                'id']
            if related_lot_check or asset.status != status:
                return False
        return True
Esempio n. 3
0
def test_patch_assets_failed(bot, logger, mock_client):
    lot = {'data':
        {
            'status': 'waiting',
            'id': 'dd36079db10f4b77b8dd77ca64299e95',
            'assets': [
                "137738e77e1c4a968a2f1c4226639854",  # status: pending
                "b30136280e2a4d8f8c3572d52b155741",  # status: pending
            ]
        }
    }

    with open(ROOT + 'assets.json') as assets_data:
        assets = munchify(load(assets_data))

    asset = assets['137738e77e1c4a968a2f1c4226639854']
    asset.data.status = 'active'

    bot.assets_client.patch_asset.side_effect = [
        str(asset),
        RequestFailed()
    ]
    result = bot.patch_assets(lot, 'active', lot['data']['id'])
    assert result is False

    bot.assets_client.patch_asset.side_effect = InvalidResponse()
    result = bot.patch_assets(lot, 'active', lot['data']['id'])
    assert result is False

    bot.assets_client.patch_asset.side_effect = Forbidden()
    result = bot.patch_assets(lot, 'active', lot['data']['id'])
    assert result is False

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[0] == "Successfully patched asset 137738e77e1c4a968a2f1c4226639854 to active"
    assert log_strings[1] == "Failed to patch asset b30136280e2a4d8f8c3572d52b155741 to active (Not described error yet.)"
    assert log_strings[2] == "Failed to patch asset 137738e77e1c4a968a2f1c4226639854 to active (Not described error yet.)"
    assert log_strings[3] == "Failed to patch asset 137738e77e1c4a968a2f1c4226639854 to active (Not described error yet.)"
Esempio n. 4
0
def test_check_lot_asset_request_failed(bot, logger, mock_client):
    lot = {'data':
        {
            'status': 'waiting',
            'id': 'dd36079db10f4b77b8dd77ca64299e95',
            'assets': [
                "137738e77e1c4a968a2f1c4226639854",  # status: pending
            ]
        }
    }

    with open(ROOT + 'assets.json') as assets_data:
        assets = munchify(load(assets_data))

    bot.assets_client.get_asset.side_effect = [
        RequestFailed()
    ]

    with pytest.raises(RequestFailed):
        bot.check_lot_assets(lot)

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[0] == "Falied to get asset: Not described error yet."
Esempio n. 5
0
    def test__get_resource_item_from_public(self, mock_api_client):
        item = {
            'id': uuid.uuid4().hex,
            'dateModified': datetime.datetime.utcnow().isoformat()
        }
        api_clients_queue = Queue()
        client_dict = {
            'id': uuid.uuid4().hex,
            'request_interval': 0.02,
            'client': mock_api_client
        }
        api_clients_queue.put(client_dict)
        api_clients_info =\
            {client_dict['id']: {'destroy': False, 'request_durations': {}}}
        retry_queue = Queue()
        return_dict = {
            'data': {
                'id': item['id'],
                'dateModified': datetime.datetime.utcnow().isoformat()
            }
        }
        mock_api_client.get_resource_item.return_value = return_dict
        worker = ResourceItemWorker(api_clients_queue=api_clients_queue,
                                    config_dict=self.worker_config,
                                    retry_resource_items_queue=retry_queue,
                                    api_clients_info=api_clients_info)

        # Success test
        self.assertEqual(worker.api_clients_queue.qsize(), 1)
        api_client = worker._get_api_client_dict()
        self.assertEqual(api_client['request_interval'], 0.02)
        self.assertEqual(worker.api_clients_queue.qsize(), 0)
        public_item = worker._get_resource_item_from_public(api_client, item)
        self.assertEqual(worker.retry_resource_items_queue.qsize(), 0)
        self.assertEqual(public_item, return_dict['data'])

        # Not actual document form public
        item['dateModified'] = datetime.datetime.utcnow().isoformat()
        api_client = worker._get_api_client_dict()
        self.assertEqual(worker.api_clients_queue.qsize(), 0)
        self.assertEqual(api_client['request_interval'], 0)
        public_item = worker._get_resource_item_from_public(api_client, item)
        self.assertEqual(public_item, None)
        sleep(worker.config['retry_default_timeout'] * 2)
        self.assertEqual(worker.retry_resource_items_queue.qsize(), 1)
        self.assertEqual(worker.api_clients_queue.qsize(), 1)

        # InvalidResponse
        mock_api_client.get_resource_item.side_effect =\
            InvalidResponse('invalid response')
        self.assertEqual(worker.retry_resource_items_queue.qsize(), 1)
        api_client = worker._get_api_client_dict()
        self.assertEqual(worker.api_clients_queue.qsize(), 0)
        public_item = worker._get_resource_item_from_public(api_client, item)
        self.assertEqual(public_item, None)
        sleep(worker.config['retry_default_timeout'] * 2)
        self.assertEqual(worker.retry_resource_items_queue.qsize(), 2)
        self.assertEqual(worker.api_clients_queue.qsize(), 1)

        # RequestFailed status_code=429
        mock_api_client.get_resource_item.side_effect = RequestFailed(
            munchify({'status_code': 429}))
        api_client = worker._get_api_client_dict()
        self.assertEqual(worker.api_clients_queue.qsize(), 0)
        self.assertEqual(api_client['request_interval'], 0)
        public_item = worker._get_resource_item_from_public(api_client, item)
        self.assertEqual(public_item, None)
        sleep(worker.config['retry_default_timeout'] * 2)
        self.assertEqual(worker.retry_resource_items_queue.qsize(), 3)
        self.assertEqual(worker.api_clients_queue.qsize(), 1)
        api_client = worker._get_api_client_dict()
        self.assertEqual(worker.api_clients_queue.qsize(), 0)
        self.assertEqual(api_client['request_interval'],
                         worker.config['client_inc_step_timeout'])

        # RequestFailed status_code=429 with drop cookies
        api_client['request_interval'] = 2
        public_item = worker._get_resource_item_from_public(api_client, item)
        sleep(api_client['request_interval'])
        self.assertEqual(worker.api_clients_queue.qsize(), 1)
        self.assertEqual(public_item, None)
        self.assertEqual(api_client['request_interval'], 0)
        sleep(worker.config['retry_default_timeout'] * 2)
        self.assertEqual(worker.retry_resource_items_queue.qsize(), 4)

        # RequestFailed with status_code not equal 429
        mock_api_client.get_resource_item.side_effect = RequestFailed(
            munchify({'status_code': 404}))
        api_client = worker._get_api_client_dict()
        self.assertEqual(worker.api_clients_queue.qsize(), 0)
        public_item = worker._get_resource_item_from_public(api_client, item)
        self.assertEqual(public_item, None)
        self.assertEqual(worker.api_clients_queue.qsize(), 1)
        self.assertEqual(api_client['request_interval'], 0)
        sleep(worker.config['retry_default_timeout'] * 2)
        self.assertEqual(worker.retry_resource_items_queue.qsize(), 5)

        # ResourceNotFound
        mock_api_client.get_resource_item.side_effect = RNF(
            munchify({'status_code': 404}))
        api_client = worker._get_api_client_dict()
        self.assertEqual(worker.api_clients_queue.qsize(), 0)
        public_item = worker._get_resource_item_from_public(api_client, item)
        self.assertEqual(public_item, None)
        self.assertEqual(worker.api_clients_queue.qsize(), 1)
        self.assertEqual(api_client['request_interval'], 0)
        sleep(worker.config['retry_default_timeout'] * 2)
        self.assertEqual(worker.retry_resource_items_queue.qsize(), 6)

        # Exception
        api_client = worker._get_api_client_dict()
        mock_api_client.get_resource_item.side_effect =\
            Exception('text except')
        public_item = worker._get_resource_item_from_public(api_client, item)
        self.assertEqual(public_item, None)
        self.assertEqual(api_client['request_interval'], 0)
        sleep(worker.config['retry_default_timeout'] * 2)
        self.assertEqual(worker.retry_resource_items_queue.qsize(), 7)

        del worker
def test_check_assets(bot, logger, mocker):
    with open(ROOT + 'assets.json') as assets:
        assets = load(assets)

    with open(ROOT + 'lots.json') as lots:
        lots = load(lots)

    verification_lot = deepcopy(lots[0]['data'])
    verification_lot['assets'] = ['e519404fd0b94305b3b19ec60add05e7']
    dissolved_lot = deepcopy(lots[1]['data'])
    dissolved_lot['assets'] = ["0a7eba27b22a454180d3a49b02a1842f"]

    mock_get_asset = mocker.MagicMock()
    mock_get_asset.side_effect = [
        RequestFailed(response=munchify({
            "text": "Request failed.",
            "status_code": 502
        })),
        ResourceNotFound(
            response=munchify({"text": "Asset could not be found."})),
        munchify(assets[0]),
        munchify(assets[7])
    ]

    bot.assets_client.get_asset = mock_get_asset

    with pytest.raises(RequestFailed):
        bot.check_assets(verification_lot)

    result = bot.check_assets(verification_lot)
    assert result is False

    result = bot.check_assets(verification_lot)
    assert result is True

    result = bot.check_assets(dissolved_lot)
    assert result is False

    verification_lot = deepcopy(lots[5]['data'])
    basic_asset = deepcopy(assets[7])
    basic_asset['data']['status'] = 'pending'
    basic_asset['data']['relatedLot'] = verification_lot['id']
    basic_asset['data']['assetType'] = 'basic'

    wrong_asset = deepcopy(assets[9])
    wrong_asset['data']['status'] = 'pending'
    wrong_asset['data']['assetType'] = 'wrong'
    wrong_asset['data']['relatedLot'] = verification_lot['id']

    mock_get_asset.side_effect = [munchify(wrong_asset), munchify(basic_asset)]

    verification_lot['assets'] = [wrong_asset['data']['id']]
    result = bot.check_assets(verification_lot)
    assert result is False

    verification_lot['assets'] = [basic_asset['data']['id']]
    result = bot.check_assets(verification_lot)
    assert result is True

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        0] == "Failed to get asset e519404fd0b94305b3b19ec60add05e7. Status code: 502"
    assert log_strings[
        1] == "Failed to get asset e519404fd0b94305b3b19ec60add05e7: Asset could not be found."
    assert log_strings[
        2] == "Successfully got asset e519404fd0b94305b3b19ec60add05e7"
    assert log_strings[
        3] == "Successfully got asset 0a7eba27b22a454180d3a49b02a1842f"
    assert log_strings[4] == "Successfully got asset {}".format(
        wrong_asset['data']['id'])
    assert log_strings[5] == "Successfully got asset {}".format(
        basic_asset['data']['id'])
def test_process_lots(bot, logger, mocker):
    mock_get_asset = mocker.MagicMock()
    bot.assets_client.get_asset = mock_get_asset

    mock_check_lot = mocker.patch.object(bot, 'check_lot', autospec=True)
    # mock_check_lot.side_effect = iter([
    #     True,
    #     True,
    #     True,
    #     True,
    #     True,
    #     False,
    #     True,
    #     True,
    #     True,
    #     True,
    #     True,
    # ])

    mock_check_assets = mocker.patch.object(bot, 'check_assets', autospec=True)
    # mock_check_assets.side_effect = iter([
    #     True,
    #     True,
    #     False,
    #     RequestFailed(response=munchify({"text": "Request failed."})),
    #     True,
    #     True,
    # ])

    mock_patch_assets = mocker.patch.object(bot, 'patch_assets', autospec=True)
    # mock_patch_assets.side_effect = iter([
    #     (False, []),
    #     (True, []),
    #     (True, ['all_assets']),
    #     (True, ['all_assets']),
    #     (False, []),
    #     (True, ['all_assets']),
    #     (False, []),
    #     (True, ['all_assets']),
    #     (False, [])
    # ])

    mock_patch_lot = mocker.patch.object(bot, 'patch_lot', autospec=True)
    mock_patch_lot.return_value = True

    with open(ROOT + 'lots.json') as lots:
        lots = load(lots)

    with open(ROOT + 'assets.json') as assets:
        assets = load(assets)

    verification_lot = lots[0]['data']
    pending_dissolution_lot = lots[1]['data']

    # status == 'verification'
    mock_check_lot.side_effect = iter([True])
    mock_check_assets.side_effect = iter([True])
    mock_patch_assets.side_effect = iter([
        (False, []),
        (True, ['all_assets']),
    ])
    bot.process_lots(
        verification_lot
    )  # assets_available: True; patch_assets: [(False, []), (True, []]; check_lot: True

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        0] == 'Processing lot 9ee8f769438e403ebfb17b2240aedcf1 in status verification'

    assert mock_check_assets.call_count == 1
    assert mock_check_assets.call_args[0] == (verification_lot, )

    assert mock_check_lot.call_count == 1
    assert mock_check_lot.call_args[0] == (verification_lot, )

    assert mock_patch_assets.call_count == 1
    assert mock_patch_assets.call_args_list[0][0] == (verification_lot,
                                                      'verification',
                                                      verification_lot['id'])

    mock_check_lot.side_effect = iter([True])
    mock_check_assets.side_effect = iter([True])
    mock_patch_assets.side_effect = iter([
        (True, ['all_assets']),
        (True, ['all_assets']),
    ])
    bot.process_lots(
        verification_lot
    )  # assets_available: True; patch_assets: [(True, []), (True, [])]; check_lot: True

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        1] == 'Processing lot 9ee8f769438e403ebfb17b2240aedcf1 in status verification'

    assert mock_check_assets.call_count == 2
    assert mock_check_assets.call_args[0] == (verification_lot, )

    assert mock_check_lot.call_count == 2
    assert mock_check_lot.call_args[0] == (verification_lot, )

    assert mock_patch_assets.call_count == 3
    assert mock_patch_assets.call_args_list[1][0] == (verification_lot,
                                                      'verification',
                                                      verification_lot['id'])
    assert mock_patch_assets.call_args_list[2][0] == (verification_lot,
                                                      'active',
                                                      verification_lot['id'])

    assert mock_patch_lot.call_count == 1
    assert mock_patch_lot.call_args[0] == (verification_lot, 'active.salable')

    mock_check_lot.side_effect = iter([True])
    mock_check_assets.side_effect = iter([False])
    mock_patch_assets.side_effect = iter([])
    bot.process_lots(
        verification_lot
    )  # assets_available: False; patch_assets: None; check_lot: True

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        2] == 'Processing lot 9ee8f769438e403ebfb17b2240aedcf1 in status verification'

    assert mock_check_assets.call_count == 3
    assert mock_check_assets.call_args[0] == (verification_lot, )

    assert mock_check_lot.call_count == 3
    assert mock_check_lot.call_args[0] == (verification_lot, )

    assert mock_patch_lot.call_count == 2
    assert mock_patch_lot.call_args[0] == (verification_lot, 'pending')

    mock_check_lot.side_effect = iter([True])
    mock_check_assets.side_effect = iter(
        [RequestFailed(response=munchify({"text": "Request failed."}))])
    mock_patch_assets.side_effect = iter([])
    bot.process_lots(
        verification_lot
    )  # assets_available: raises exception; patch_assets: None; check_lot: True

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        3] == 'Processing lot 9ee8f769438e403ebfb17b2240aedcf1 in status verification'
    assert log_strings[
        4] == 'Due to fail in getting assets, lot 9ee8f769438e403ebfb17b2240aedcf1 is skipped'

    assert mock_check_assets.call_count == 4
    assert mock_check_assets.call_args[0] == (verification_lot, )

    assert mock_check_lot.call_count == 4
    assert mock_check_lot.call_args[0] == (verification_lot, )

    # status == 'pending.dissolution'
    mock_check_lot.side_effect = iter([True])
    mock_check_assets.side_effect = iter([None])
    mock_patch_assets.side_effect = iter([(True, ['all_assets'])])
    bot.process_lots(
        pending_dissolution_lot
    )  # assets_available: None; patch_assets: (True, []); check_lot: True

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        5] == 'Processing lot b844573afaa24e4fb098f3027e605c87 in status pending.dissolution'
    assert log_strings[
        6] == "Assets {} from lot {} will be patched to 'pending'".format(
            pending_dissolution_lot['assets'], pending_dissolution_lot['id'])

    assert mock_check_lot.call_count == 5
    assert mock_check_lot.call_args[0] == (pending_dissolution_lot, )

    # lot is not available
    mock_check_lot.side_effect = iter([False])
    mock_check_assets.side_effect = iter([])
    mock_patch_assets.side_effect = iter([])
    bot.process_lots(
        pending_dissolution_lot
    )  # assets_available: None; patch_assets: None; check_lot: False

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[7] == 'Skipping lot {}'.format(
        pending_dissolution_lot['id'])

    assert mock_check_lot.call_count == 6
    assert mock_check_lot.call_args[0] == (pending_dissolution_lot, )

    pending_dissolution_lot = lots[2]['data']
    mock_check_lot.side_effect = iter([True])
    mock_check_assets.side_effect = iter([False])
    mock_patch_assets.side_effect = iter([(False, []), (True, ['all_assets'])])
    bot.process_lots(pending_dissolution_lot)

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[9] == 'Not valid assets {} in lot {}'.format(
        pending_dissolution_lot['assets'], pending_dissolution_lot['id'])
    assert mock_check_lot.call_count == 7
    assert mock_check_lot.call_args[0] == (pending_dissolution_lot, )

    assert mock_check_assets.call_count == 4
    assert mock_patch_assets.call_args[0] == (pending_dissolution_lot,
                                              'pending')

    recomposed_lot = lots[3]['data']

    mock_check_lot.side_effect = iter([True])
    mock_check_assets.side_effect = iter([True])
    mock_patch_assets.side_effect = iter([
        (True, ['all_assets']),
    ])
    bot.process_lots(recomposed_lot)

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[10] == 'Processing lot {} in status recomposed'.format(
        recomposed_lot['id'])
    assert log_strings[
        11] == "Assets {} from lot {} will be patched to 'pending'".format(
            recomposed_lot['assets'], recomposed_lot['id'])
    assert mock_check_lot.call_count == 8
    assert mock_check_lot.call_args[0] == (recomposed_lot, )
    assert mock_patch_lot.call_args[0] == (recomposed_lot, 'pending')

    assert mock_check_assets.call_count == 4
    assert mock_patch_assets.call_args[0] == (recomposed_lot, 'pending')

    mock_check_lot.side_effect = iter([True])
    mock_check_assets.side_effect = iter([True])
    mock_patch_assets.side_effect = iter([
        (False, []),
        (True, ['all_assets']),
    ])
    bot.process_lots(recomposed_lot)

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[12] == 'Processing lot {} in status recomposed'.format(
        recomposed_lot['id'])
    assert log_strings[13] == 'Not valid assets {} in lot {}'.format(
        recomposed_lot['assets'], recomposed_lot['id'])
    assert mock_check_lot.call_count == 9
    assert mock_check_lot.call_args[0] == (recomposed_lot, )
    assert mock_patch_lot.call_args[0] == (recomposed_lot, 'pending')

    assert mock_check_assets.call_count == 4
    assert mock_patch_assets.call_args[0] == (recomposed_lot, 'pending')

    mock_check_lot.side_effect = iter([True])
    mock_check_assets.side_effect = iter([True])
    mock_patch_assets.side_effect = iter([
        (True, ['all_assets']),
    ])
    pending_sold_lot = lots[4]['data']

    bot.process_lots(pending_sold_lot)

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        14] == 'Processing lot {} in status pending.sold'.format(
            pending_sold_lot['id'])
    assert log_strings[
        15] == "Assets {} from lot {} will be patched to 'complete'".format(
            pending_sold_lot['assets'], pending_sold_lot['id'])
    assert mock_check_lot.call_count == 10
    assert mock_check_lot.call_args[0] == (pending_sold_lot, )
    assert mock_patch_lot.call_args[0] == (pending_sold_lot, 'sold')

    assert mock_check_assets.call_count == 4
    assert mock_patch_assets.call_args[0] == (pending_sold_lot, 'complete')

    mock_check_lot.side_effect = iter([True])
    mock_check_assets.side_effect = iter([True])
    mock_patch_assets.side_effect = iter([
        (False, []),
        (True, ['all_assets']),
    ])
    bot.process_lots(pending_sold_lot)

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        16] == 'Processing lot {} in status pending.sold'.format(
            pending_sold_lot['id'])
    assert log_strings[17] == 'Not valid assets {} in lot {}'.format(
        pending_sold_lot['assets'], pending_sold_lot['id'])
    assert mock_check_lot.call_count == 11
    assert mock_check_lot.call_args[0] == (pending_sold_lot, )
    assert mock_patch_lot.call_args[0] == (pending_sold_lot, 'sold')

    assert mock_check_assets.call_count == 4
    assert mock_patch_assets.call_args[0] == (pending_sold_lot, 'complete')

    # Test pending.deleted lot
    pending_deleted_lot = lots[6]['data']
    pending_deleted_lot['assets'] = [assets[9]]
    mock_check_lot.side_effect = iter([True])
    mock_check_assets.side_effect = iter([True])
    mock_patch_assets.side_effect = iter([
        (True, ['all_assets']),
        (True, ['all_assets']),
    ])
    mock_get_asset.side_effect = iter([munchify(assets[9])])
    bot.process_lots(pending_deleted_lot)

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        18] == 'Processing lot {} in status pending.deleted'.format(
            pending_deleted_lot['id'])
    assert mock_check_lot.call_count == 12
    assert mock_check_lot.call_args[0] == (pending_deleted_lot, )
    assert mock_patch_lot.call_args[0] == (pending_deleted_lot, 'deleted')

    assert mock_check_assets.call_count == 4
    assert mock_patch_assets.call_args[0] == (pending_deleted_lot, 'pending')
def test_patch_assets_pending_fail(bot, logger, mocker):
    mock_patch_asset = mocker.MagicMock()
    bot.assets_client.patch_asset = mock_patch_asset

    with open(ROOT + 'lots.json') as lots:
        lots = load(lots)

    with open(ROOT + 'assets.json') as assets:
        assets = load(assets)

    lot = lots[1]['data']
    status = 'pending'

    mock_patch_asset.side_effect = [
        munchify(assets[4]),
        RequestFailed(response=munchify({
            "text": "Bad Gateway",
            "status_code": 502
        })),
        RequestFailed(response=munchify({
            "text": "Bad Gateway",
            "status_code": 502
        })),
        RequestFailed(response=munchify({
            "text": "Bad Gateway",
            "status_code": 502
        })),
        RequestFailed(response=munchify({
            "text": "Bad Gateway",
            "status_code": 502
        })),
        RequestFailed(response=munchify({
            "text": "Bad Gateway",
            "status_code": 502
        })),
        munchify(assets[6]),
        munchify(assets[7])
    ]

    result, patched_assets = bot.patch_assets(lot=lot, status=status)
    assert result is False
    assert patched_assets == [
        '8034c43e2d764006ad6e655e339e5fec', '0a7eba27b22a454180d3a49b02a1842f',
        '660cbb6e83c94c80baf47691732fd1b2'
    ]

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        0] == 'Successfully patched asset 8034c43e2d764006ad6e655e339e5fec to pending'
    assert log_strings[
        2] == 'Successfully patched asset 0a7eba27b22a454180d3a49b02a1842f to pending'
    assert log_strings[
        3] == 'Successfully patched asset 660cbb6e83c94c80baf47691732fd1b2 to pending'
    assert log_strings[
        1] == 'Failed to patch asset 5545b519045a4637ab880f032960e034 to pending (Server error: 502)'

    assert bot.assets_client.patch_asset.call_count == 8

    mock_patch_asset.side_effect = [
        Forbidden(response=munchify({"text": "Operation is forbidden."})),
        munchify(assets[5]),
        munchify(assets[6]),
        munchify(assets[7])
    ]

    result, patched_assets = bot.patch_assets(lot=lot, status=status)
    assert result is False
    assert patched_assets == [
        '5545b519045a4637ab880f032960e034', '0a7eba27b22a454180d3a49b02a1842f',
        '660cbb6e83c94c80baf47691732fd1b2'
    ]
    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        4] == 'Failed to patch asset 8034c43e2d764006ad6e655e339e5fec to pending (Operation is forbidden.)'

    assert bot.assets_client.patch_asset.call_count == 12
Esempio n. 9
0
    def test__run(self, mocked_logger, mock_get_from_public, mock_registry):
        self.queue = Queue()
        self.retry_queue = Queue()
        self.api_clients_queue = Queue()
        queue_item = (1, {
            'id': uuid.uuid4().hex,
            'procurementMethodType': 'closeFrameworkAgreementUA'
        })
        doc = {
            'id': queue_item[1],
            '_rev': '1-{}'.format(uuid.uuid4().hex),
            'dateModified': datetime.datetime.utcnow().isoformat(),
            'doc_type': 'Tender'
        }
        client = MagicMock()
        api_client_dict = {
            'id': uuid.uuid4().hex,
            'client': client,
            'request_interval': 0
        }
        client.session.headers = {'User-Agent': 'Test-Agent'}
        self.api_clients_info = {
            api_client_dict['id']: {
                'drop_cookies': False,
                'request_durations': []
            }
        }
        self.db = MagicMock()
        worker = AgreementWorker(api_clients_queue=self.api_clients_queue,
                                 resource_items_queue=self.queue,
                                 retry_resource_items_queue=self.retry_queue,
                                 db=self.db,
                                 api_clients_info=self.api_clients_info,
                                 config_dict=self.worker_config)
        worker.exit = MagicMock()
        worker.exit.__nonzero__.side_effect = [False, True]

        # Try get api client from clients queue
        self.assertEqual(self.queue.qsize(), 0)
        worker._run()
        self.assertEqual(self.queue.qsize(), 0)
        mocked_logger.critical.assert_called_once_with(
            'API clients queue is empty.')

        # Try get item from resource items queue with no handler
        self.api_clients_queue.put(api_client_dict)
        worker.exit.__nonzero__.side_effect = [False, True]
        mock_registry.get.return_value = ''
        self.queue.put(queue_item)
        mock_get_from_public.return_value = doc
        worker._run()
        self.assertEqual(mocked_logger.critical.call_args_list, [
            call('API clients queue is empty.'),
            call('Not found handler for procurementMethodType: {}, {} {}'.
                 format(doc['id']['procurementMethodType'],
                        self.worker_config['resource'][:-1], doc['id']['id']),
                 extra={
                     'JOURNAL_TENDER_ID': doc['id']['id'],
                     'MESSAGE_ID': 'bridge_worker_exception'
                 })
        ])

        # Try get item from resource items queue
        self.api_clients_queue.put(api_client_dict)
        worker.exit.__nonzero__.side_effect = [False, True]
        handler_mock = MagicMock()
        handler_mock.process_resource.return_value = None
        mock_registry.return_value = {
            'closeFrameworkAgreementUA': handler_mock
        }
        worker._run()
        self.assertEqual(mocked_logger.debug.call_args_list[2:], [
            call('GET API CLIENT: {} {} with requests interval: {}'.format(
                api_client_dict['id'],
                api_client_dict['client'].session.headers['User-Agent'],
                api_client_dict['request_interval']),
                 extra={
                     'REQUESTS_TIMEOUT': 0,
                     'MESSAGE_ID': 'get_client'
                 }),
            call('PUT API CLIENT: {}'.format(api_client_dict['id']),
                 extra={'MESSAGE_ID': 'put_client'}),
            call('Resource items queue is empty.')
        ])

        # Try get resource item from local storage
        self.queue.put(queue_item)
        mock_get_from_public.return_value = doc
        worker.exit.__nonzero__.side_effect = [False, True]
        worker._run()
        self.assertEqual(mocked_logger.debug.call_args_list[5:], [
            call('GET API CLIENT: {} {} with requests interval: {}'.format(
                api_client_dict['id'],
                api_client_dict['client'].session.headers['User-Agent'],
                api_client_dict['request_interval']),
                 extra={
                     'REQUESTS_TIMEOUT': 0,
                     'MESSAGE_ID': 'get_client'
                 }),
            call('Get tender {} from main queue.'.format(doc['id']['id']))
        ])

        # Try get local_resource_item with Exception
        self.api_clients_queue.put(api_client_dict)
        self.queue.put(queue_item)
        mock_get_from_public.return_value = doc
        self.db.get.side_effect = [Exception('Database Error')]
        worker.exit.__nonzero__.side_effect = [False, True]
        worker._run()
        self.assertEqual(mocked_logger.debug.call_args_list[7:], [
            call('GET API CLIENT: {} {} with requests interval: {}'.format(
                api_client_dict['id'],
                api_client_dict['client'].session.headers['User-Agent'],
                api_client_dict['request_interval']),
                 extra={
                     'REQUESTS_TIMEOUT': 0,
                     'MESSAGE_ID': 'get_client'
                 }),
            call('Get tender {} from main queue.'.format(doc['id']['id']))
        ])

        # Try process resource with Exception
        self.api_clients_queue.put(api_client_dict)
        self.queue.put(queue_item)
        mock_get_from_public.return_value = doc
        worker.exit.__nonzero__.side_effect = [False, True]

        mock_handler = MagicMock()
        mock_handler.process_resource.side_effect = (RequestFailed(), )
        mock_registry.get.return_value = mock_handler

        worker._run()
        self.assertEqual(mocked_logger.error.call_args_list, [
            call('Error while processing {} {}: {}'.format(
                self.worker_config['resource'][:-1], doc['id']['id'],
                'Not described error yet.'),
                 extra={
                     'JOURNAL_TENDER_ID': doc['id']['id'],
                     'MESSAGE_ID': 'bridge_worker_exception'
                 })
        ])
        check_queue_item = (queue_item[0] + 1, queue_item[1]
                            )  # priority is increased
        self.assertEquals(self.retry_queue.get(), check_queue_item)

        # Try process resource with Exception
        self.api_clients_queue.put(api_client_dict)
        self.queue.put(queue_item)
        mock_get_from_public.return_value = doc
        worker.exit.__nonzero__.side_effect = [False, True]

        mock_handler = MagicMock()
        mock_handler.process_resource.side_effect = (Exception(), )
        mock_registry.get.return_value = mock_handler
        worker._run()

        self.assertEqual(mocked_logger.error.call_args_list[1:], [
            call('Error while processing {} {}: {}'.format(
                self.worker_config['resource'][:-1], doc['id']['id'], ''),
                 extra={
                     'JOURNAL_TENDER_ID': doc['id']['id'],
                     'MESSAGE_ID': 'bridge_worker_exception'
                 })
        ])
        check_queue_item = (queue_item[0] + 1, queue_item[1]
                            )  # priority is increased
        self.assertEquals(self.retry_queue.get(), check_queue_item)

        #  No resource item
        self.api_clients_queue.put(api_client_dict)
        self.queue.put(queue_item)
        mock_get_from_public.return_value = None
        worker.exit.__nonzero__.side_effect = [False, True]

        mock_handler = MagicMock()
        mock_handler.process_resource.side_effect = (Exception(), )
        mock_registry.get.return_value = mock_handler
        worker._run()

        self.assertEquals(self.queue.empty(), True)
        self.assertEquals(self.retry_queue.empty(), True)
Esempio n. 10
0
    def test__action_resource_item_from_cdb(self, mock_api_client):
        item = {
            'id': uuid.uuid4().hex,
            'dateModified': datetime.datetime.utcnow().isoformat(),
            'resource': 'tenders'
        }
        api_clients_queue = Queue()
        api_clients_queue.put({
            'client': mock_api_client,
            'request_interval': 0.02})
        retry_queue = Queue()
        return_dict = {
            'data': {
                'id': item['id'],
                'dateModified': datetime.datetime.utcnow().isoformat()
            }
        }
        mock_api_client.get_resource_dump.return_value = return_dict
        worker = ArchiveWorker(api_clients_queue=api_clients_queue,
                               config_dict=self.worker_config,
                               retry_resource_items_queue=retry_queue,
                               log_dict=self.log_dict)

        # Success test
        self.assertEqual(worker.api_clients_queue.qsize(), 1)
        api_client = worker._get_api_client_dict()
        self.assertEqual(api_client['request_interval'], 0.02)
        self.assertEqual(worker.api_clients_queue.qsize(), 0)
        public_item = worker._action_resource_item_from_cdb(api_client, item)
        self.assertEqual(worker.retry_resource_items_queue.qsize(), 0)
        self.assertEqual(public_item, return_dict['data'])

        # InvalidResponse
        mock_api_client.get_resource_dump.side_effect = InvalidResponse('invalid response')
        self.assertEqual(self.log_dict['exceptions_count'], 0)
        self.assertEqual(worker.retry_resource_items_queue.qsize(), 0)
        api_client = worker._get_api_client_dict()
        self.assertEqual(worker.api_clients_queue.qsize(), 0)
        public_item = worker._action_resource_item_from_cdb(api_client, item)
        self.assertEqual(public_item, None)
        self.assertEqual(worker.log_dict['exceptions_count'], 1)
        self.assertEqual(worker.log_dict['add_to_retry'], 1)
        sleep(worker.config['retry_default_timeout'] * 2)
        self.assertEqual(worker.retry_resource_items_queue.qsize(), 1)
        self.assertEqual(worker.api_clients_queue.qsize(), 1)

        # RequestFailed status_code=429
        mock_api_client.get_resource_dump.side_effect = RequestFailed(
            munchify({'status_code': 429}))
        api_client = worker._get_api_client_dict()
        self.assertEqual(worker.api_clients_queue.qsize(), 0)
        self.assertEqual(api_client['request_interval'], 0)
        public_item = worker._action_resource_item_from_cdb(api_client, item)
        self.assertEqual(public_item, None)
        self.assertEqual(worker.log_dict['exceptions_count'], 2)
        self.assertEqual(worker.log_dict['add_to_retry'], 2)
        sleep(worker.config['retry_default_timeout'] * 2)
        self.assertEqual(worker.retry_resource_items_queue.qsize(), 2)
        self.assertEqual(worker.api_clients_queue.qsize(), 1)
        api_client = worker._get_api_client_dict()
        self.assertEqual(worker.api_clients_queue.qsize(), 0)
        self.assertEqual(api_client['request_interval'], worker.config['client_inc_step_timeout'])

        # RequestFailed status_code=429 with drop cookies
        api_client['request_interval'] = 2
        public_item = worker._action_resource_item_from_cdb(api_client, item)
        sleep(api_client['request_interval'])
        self.assertEqual(worker.api_clients_queue.qsize(), 1)
        self.assertEqual(public_item, None)
        self.assertEqual(api_client['request_interval'], 0)
        self.assertEqual(worker.log_dict['exceptions_count'], 3)
        self.assertEqual(worker.log_dict['add_to_retry'], 3)
        sleep(worker.config['retry_default_timeout'] * 2)
        self.assertEqual(worker.retry_resource_items_queue.qsize(), 3)

        # RequestFailed with status_code not equal 429
        mock_api_client.get_resource_dump.side_effect = RequestFailed(
            munchify({'status_code': 404}))
        api_client = worker._get_api_client_dict()
        self.assertEqual(worker.api_clients_queue.qsize(), 0)
        public_item = worker._action_resource_item_from_cdb(api_client, item)
        self.assertEqual(public_item, None)
        self.assertEqual(worker.api_clients_queue.qsize(), 1)
        self.assertEqual(api_client['request_interval'], 0)
        self.assertEqual(worker.log_dict['exceptions_count'], 4)
        self.assertEqual(worker.log_dict['add_to_retry'], 4)
        sleep(worker.config['retry_default_timeout'] * 2)
        self.assertEqual(worker.retry_resource_items_queue.qsize(), 4)

        # ResourceNotFound
        mock_api_client.get_resource_dump.side_effect = RNF(
            munchify({'status_code': 404}))
        api_client = worker._get_api_client_dict()
        self.assertEqual(worker.api_clients_queue.qsize(), 0)
        public_item = worker._action_resource_item_from_cdb(api_client, item)
        self.assertEqual(public_item, None)
        self.assertEqual(worker.api_clients_queue.qsize(), 1)
        self.assertEqual(api_client['request_interval'], 0)
        self.assertEqual(worker.log_dict['exceptions_count'], 4)
        self.assertEqual(worker.log_dict['add_to_retry'], 4)
        self.assertEqual(worker.log_dict['not_found_count'], 1)
        sleep(worker.config['retry_default_timeout'] * 2)
        self.assertEqual(worker.retry_resource_items_queue.qsize(), 4)

        # Exception
        api_client = worker._get_api_client_dict()
        mock_api_client.get_resource_dump.side_effect = Exception('text except')
        public_item = worker._action_resource_item_from_cdb(api_client, item)
        self.assertEqual(public_item, None)
        self.assertEqual(api_client['request_interval'], 0)
        self.assertEqual(worker.log_dict['exceptions_count'], 5)
        self.assertEqual(worker.log_dict['add_to_retry'], 5)
        sleep(worker.config['retry_default_timeout'] * 2)
        self.assertEqual(worker.retry_resource_items_queue.qsize(), 5)

        del worker
def test_create_auction(bot, logger, mocker):
    mock_dict_from_object = mocker.patch.object(bot,
                                                '_dict_from_object',
                                                autospec=True)
    mock_get_next_auction = mocker.patch.object(bot,
                                                'get_next_auction',
                                                autospec=True)
    mock_post_auction = mocker.patch.object(bot,
                                            '_post_auction',
                                            autospec=True)

    dict_with_value = {'value': 'value'}
    mock_dict_from_object.return_value = dict_with_value

    auction_obj = 'auction'

    with open(ROOT + 'lots.json') as lots:
        lots = load(lots)

    active_salable_lot = lots[7]['data']

    # With first auction
    mock_post_auction.side_effect = iter([auction_obj])
    auction = active_salable_lot['auctions'][0]
    mock_get_next_auction.side_effect = iter([auction])

    result = bot._create_auction(active_salable_lot)

    assert result == (auction_obj, auction['id'])

    assert mock_dict_from_object.call_count == 1
    mock_dict_from_object.assert_called_with(KEYS_FOR_AUCTION_CREATE,
                                             active_salable_lot,
                                             auction['tenderAttempts'] - 1)

    assert mock_get_next_auction.call_count == 1
    mock_get_next_auction.assert_called_with(active_salable_lot)

    assert mock_post_auction.call_count == 1
    mock_post_auction.assert_called_with(dict_with_value,
                                         active_salable_lot['id'])

    # Tender attempts more than 1
    mock_post_auction.side_effect = iter([auction_obj])
    data_with_tender_period = deepcopy(dict_with_value)

    auction = active_salable_lot['auctions'][1]
    mock_datetime = mocker.patch(
        'openregistry.concierge.loki.processing.datetime', autospec=True)
    mock_get_next_auction.side_effect = iter([auction])

    start_date = datetime.now()
    end_date = start_date + parse_duration(
        active_salable_lot['auctions'][1]['tenderingDuration'])
    data_with_tender_period['tenderPeriod'] = {
        'startDate': start_date,
        'endDate': end_date
    }

    mock_datetime.now.return_value = start_date

    result = bot._create_auction(active_salable_lot)

    assert result == (auction_obj, auction['id'])

    assert mock_dict_from_object.call_count == 2
    mock_dict_from_object.assert_called_with(KEYS_FOR_AUCTION_CREATE,
                                             active_salable_lot,
                                             auction['tenderAttempts'] - 1)

    assert mock_get_next_auction.call_count == 2
    mock_get_next_auction.assert_called_with(active_salable_lot)

    assert mock_post_auction.call_count == 2
    mock_post_auction.assert_called_with(data_with_tender_period,
                                         active_salable_lot['id'])

    # When you get error
    auction = active_salable_lot['auctions'][0]
    mock_get_next_auction.side_effect = iter([auction])

    mock_post_auction.side_effect = iter([
        RequestFailed(response=munchify({
            "text": "Request failed.",
            "status_code": 502
        })),
    ])
    result = bot._create_auction(active_salable_lot)

    assert result is None

    assert mock_dict_from_object.call_count == 3
    mock_dict_from_object.assert_called_with(KEYS_FOR_AUCTION_CREATE,
                                             active_salable_lot,
                                             auction['tenderAttempts'] - 1)

    assert mock_get_next_auction.call_count == 3
    mock_get_next_auction.assert_called_with(active_salable_lot)

    assert mock_post_auction.call_count == 3
    mock_post_auction.assert_called_with(data_with_tender_period,
                                         active_salable_lot['id'])

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        0] == 'Failed to create auction from lot {} (Server error: 502)'.format(
            active_salable_lot['id'])
def test_process_lots(bot, logger, mocker):
    mock_get_asset = mocker.MagicMock()
    bot.assets_client.get_asset = mock_get_asset

    mock_check_lot = mocker.patch.object(bot, 'check_lot', autospec=True)
    mock_patch_auction = mocker.patch.object(bot,
                                             '_patch_auction',
                                             autospec=True)
    # mock_check_lot.side_effect = iter([
    #     True,
    #     True,
    #     True,
    #     True,
    #     True,
    #     False,
    #     True,
    #     True,
    #     True,
    #     True,
    #     True,
    # ])

    mock_check_assets = mocker.patch.object(bot, 'check_assets', autospec=True)
    # mock_check_assets.side_effect = iter([
    #     True,
    #     True,
    #     False,
    #     RequestFailed(response=munchify({"text": "Request failed."})),
    #     True,
    #     True,
    # ])

    mock_patch_assets = mocker.patch.object(bot, 'patch_assets', autospec=True)
    # mock_patch_assets.side_effect = iter([
    #     (False, []),
    #     (True, []),
    #     (True, ['all_assets']),
    #     (True, ['all_assets']),
    #     (False, []),
    #     (True, ['all_assets']),
    #     (False, []),
    #     (True, ['all_assets']),
    #     (False, [])
    # ])

    mock_patch_lot = mocker.patch.object(bot, 'patch_lot', autospec=True)
    mock_patch_lot.return_value = True

    with open(ROOT + 'lots.json') as lots:
        lots = load(lots)

    with open(ROOT + 'assets.json') as assets:
        assets = load(assets)

    verification_lot = lots[0]['data']
    pending_dissolution_lot = lots[1]['data']

    # status == 'verification'
    mock_check_lot.side_effect = iter([True])
    mock_check_assets.side_effect = iter([True])
    mock_patch_assets.side_effect = iter([
        (False, []),
        (True, ['all_assets']),
    ])
    bot.process_lots(
        verification_lot
    )  # assets_available: True; patch_assets: [(False, []), (True, []]; check_lot: True

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        0] == 'Processing lot 9ee8f769438e403ebfb17b2240aedcf1 in status verification'

    assert mock_check_assets.call_count == 1
    assert mock_check_assets.call_args[0] == (verification_lot, )

    assert mock_check_lot.call_count == 1
    assert mock_check_lot.call_args[0] == (verification_lot, )

    assert mock_patch_assets.call_count == 1
    assert mock_patch_assets.call_args_list[0][0] == (verification_lot,
                                                      'verification',
                                                      verification_lot['id'])

    mock_check_lot.side_effect = iter([True])
    mock_check_assets.side_effect = iter([True])
    mock_patch_assets.side_effect = iter([
        (True, ['all_assets']),
        (True, ['all_assets']),
    ])
    mock_get_asset.side_effect = iter([munchify(assets[9])])

    to_compare = {
        l_key: assets[9]['data'].get(a_key, None)
        for a_key, l_key in KEYS_FOR_LOKI_PATCH.items()
    }
    asset_decision = deepcopy(assets[9]['data']['decisions'][0])
    asset_decision['relatedItem'] = assets[9]['data']['id']
    to_compare['decisions'] = [
        verification_lot['decisions'][0], asset_decision
    ]

    bot.process_lots(
        verification_lot
    )  # assets_available: True; patch_assets: [(True, []), (True, [])]; check_lot: True

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        1] == 'Processing lot 9ee8f769438e403ebfb17b2240aedcf1 in status verification'

    assert mock_check_assets.call_count == 2
    assert mock_check_assets.call_args[0] == (verification_lot, )

    assert mock_check_lot.call_count == 2
    assert mock_check_lot.call_args[0] == (verification_lot, )

    assert mock_patch_assets.call_count == 3
    assert mock_patch_assets.call_args_list[1][0] == (verification_lot,
                                                      'verification',
                                                      verification_lot['id'])
    assert mock_patch_assets.call_args_list[2][0] == (verification_lot,
                                                      'active',
                                                      verification_lot['id'])

    assert mock_patch_lot.call_count == 1
    assert mock_patch_lot.call_args[0] == (verification_lot, 'pending',
                                           to_compare)

    mock_check_lot.side_effect = iter([True])
    mock_check_assets.side_effect = iter([False])
    mock_patch_assets.side_effect = iter([])
    bot.process_lots(
        verification_lot
    )  # assets_available: False; patch_assets: None; check_lot: True

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        2] == 'Processing lot 9ee8f769438e403ebfb17b2240aedcf1 in status verification'

    assert mock_check_assets.call_count == 3
    assert mock_check_assets.call_args[0] == (verification_lot, )

    assert mock_check_lot.call_count == 3
    assert mock_check_lot.call_args[0] == (verification_lot, )

    assert mock_patch_lot.call_count == 2
    assert mock_patch_lot.call_args[0] == (verification_lot, 'invalid')

    mock_check_lot.side_effect = iter([True])
    mock_check_assets.side_effect = iter(
        [RequestFailed(response=munchify({"text": "Request failed."}))])
    mock_patch_assets.side_effect = iter([])
    bot.process_lots(
        verification_lot
    )  # assets_available: raises exception; patch_assets: None; check_lot: True

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        3] == 'Processing lot 9ee8f769438e403ebfb17b2240aedcf1 in status verification'
    assert log_strings[
        4] == 'Due to fail in getting assets, lot 9ee8f769438e403ebfb17b2240aedcf1 is skipped'

    assert mock_check_assets.call_count == 4
    assert mock_check_assets.call_args[0] == (verification_lot, )

    assert mock_patch_lot.call_count == 2

    assert mock_check_lot.call_count == 4
    assert mock_check_lot.call_args[0] == (verification_lot, )

    # status == 'pending.dissolution'
    mock_check_lot.side_effect = iter([True])
    mock_check_assets.side_effect = iter([None])
    mock_patch_assets.side_effect = iter([(True, ['all_assets'])])
    bot.process_lots(
        pending_dissolution_lot
    )  # assets_available: None; patch_assets: (True, []); check_lot: True

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        5] == 'Processing lot b844573afaa24e4fb098f3027e605c87 in status pending.dissolution'
    assert log_strings[
        6] == "Assets {} from lot {} will be patched to 'pending'".format(
            pending_dissolution_lot['assets'], pending_dissolution_lot['id'])

    assert mock_patch_lot.call_count == 3
    assert mock_patch_lot.call_args[0] == (pending_dissolution_lot,
                                           'dissolved')

    assert mock_check_lot.call_count == 5
    assert mock_check_lot.call_args[0] == (pending_dissolution_lot, )

    # lot is not available
    mock_check_lot.side_effect = iter([False])
    mock_check_assets.side_effect = iter([])
    mock_patch_assets.side_effect = iter([])
    bot.process_lots(
        pending_dissolution_lot
    )  # assets_available: None; patch_assets: None; check_lot: False

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[7] == 'Skipping lot {}'.format(
        pending_dissolution_lot['id'])

    assert mock_patch_lot.call_count == 3

    assert mock_check_lot.call_count == 6
    assert mock_check_lot.call_args[0] == (pending_dissolution_lot, )

    # Pending dissolution
    pending_dissolution_lot = lots[2]['data']
    mock_check_lot.side_effect = iter([True])
    mock_check_assets.side_effect = iter([False])
    mock_patch_assets.side_effect = iter([(False, []), (True, ['all_assets'])])
    bot.process_lots(pending_dissolution_lot)

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[9] == 'Not valid assets {} in lot {}'.format(
        pending_dissolution_lot['assets'], pending_dissolution_lot['id'])
    assert mock_check_lot.call_count == 7
    assert mock_check_lot.call_args[0] == (pending_dissolution_lot, )

    assert mock_patch_lot.call_count == 4

    assert mock_check_assets.call_count == 4
    assert mock_patch_assets.call_args[0] == (pending_dissolution_lot,
                                              'pending')

    # Pending sold lot
    mock_check_lot.side_effect = iter([True])
    mock_check_assets.side_effect = iter([True])
    mock_patch_assets.side_effect = iter([
        (True, ['all_assets']),
    ])
    pending_sold_lot = lots[4]['data']

    bot.process_lots(pending_sold_lot)

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        10] == 'Processing lot {} in status pending.sold'.format(
            pending_sold_lot['id'])
    assert log_strings[
        11] == "Assets {} from lot {} will be patched to 'complete'".format(
            pending_sold_lot['assets'], pending_sold_lot['id'])
    assert mock_check_lot.call_count == 8
    assert mock_check_lot.call_args[0] == (pending_sold_lot, )

    assert mock_patch_lot.call_count == 5
    assert mock_patch_lot.call_args[0] == (pending_sold_lot, 'sold')

    assert mock_check_assets.call_count == 4
    assert mock_patch_assets.call_args[0] == (pending_sold_lot, 'complete')

    mock_check_lot.side_effect = iter([True])
    mock_check_assets.side_effect = iter([True])
    mock_patch_assets.side_effect = iter([
        (False, []),
        (True, ['all_assets']),
    ])
    bot.process_lots(pending_sold_lot)

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        12] == 'Processing lot {} in status pending.sold'.format(
            pending_sold_lot['id'])
    assert log_strings[13] == 'Not valid assets {} in lot {}'.format(
        pending_sold_lot['assets'], pending_sold_lot['id'])
    assert mock_check_lot.call_count == 9
    assert mock_check_lot.call_args[0] == (pending_sold_lot, )

    assert mock_patch_lot.call_count == 6
    assert mock_patch_lot.call_args[0] == (pending_sold_lot, 'sold')

    assert mock_check_assets.call_count == 4
    assert mock_patch_assets.call_args[0] == (pending_sold_lot, 'complete')

    # Verification lot
    loki_verfication_lot = lots[5]['data']
    mock_check_lot.side_effect = iter([True])
    mock_check_assets.side_effect = iter([True])
    mock_patch_assets.side_effect = iter([
        (True, ['all_assets']),
        (True, ['all_assets']),
    ])
    mock_get_asset.side_effect = iter([munchify(assets[9])])
    asset_decision = assets[9]['data']['decisions'][0]
    asset_decision['relatedItem'] = assets[9]['data']['id']
    to_compare = {
        l_key: assets[9]['data'].get(a_key, None)
        for a_key, l_key in KEYS_FOR_LOKI_PATCH.items()
    }
    to_compare['decisions'] = [
        loki_verfication_lot['decisions'][0],
        assets[9]['data']['decisions'][0],
    ]
    bot.process_lots(loki_verfication_lot)

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        14] == 'Processing lot {} in status verification'.format(
            loki_verfication_lot['id'])
    assert mock_check_lot.call_count == 10
    assert mock_check_lot.call_args[0] == (loki_verfication_lot, )

    assert mock_patch_lot.call_count == 7
    assert mock_patch_lot.call_args[0] == (loki_verfication_lot, 'pending',
                                           to_compare)

    assert mock_check_assets.call_count == 5
    assert mock_patch_assets.call_args[0] == (loki_verfication_lot, 'active',
                                              loki_verfication_lot['id'])

    # When something wrong
    loki_verfication_lot = lots[5]['data']
    mock_check_lot.side_effect = iter([True])
    mock_check_assets.side_effect = iter([False])
    mock_patch_assets.side_effect = iter([(False, [])])
    mock_get_asset.side_effect = iter([munchify(assets[9])])
    bot.process_lots(loki_verfication_lot)

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        15] == 'Processing lot {} in status verification'.format(
            loki_verfication_lot['id'])
    assert mock_check_lot.call_count == 11
    assert mock_check_lot.call_args[0] == (loki_verfication_lot, )

    assert mock_patch_lot.call_count == 8
    assert mock_patch_lot.call_args[0] == (loki_verfication_lot, 'invalid')

    assert mock_check_assets.call_count == 6
    assert mock_patch_assets.call_args[0] == (loki_verfication_lot, 'active',
                                              loki_verfication_lot['id'])

    # Test pending.deleted lot
    pending_deleted_lot = lots[6]['data']
    pending_deleted_lot['assets'] = [assets[9]]
    mock_check_lot.side_effect = iter([True])
    mock_check_assets.side_effect = iter([True])
    mock_patch_assets.side_effect = iter([
        (True, ['all_assets']),
        (True, ['all_assets']),
    ])
    mock_get_asset.side_effect = iter([munchify(assets[9])])
    bot.process_lots(pending_deleted_lot)

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        16] == 'Processing lot {} in status pending.deleted'.format(
            pending_deleted_lot['id'])
    assert mock_check_lot.call_count == 12
    assert mock_check_lot.call_args[0] == (pending_deleted_lot, )

    assert mock_patch_lot.call_count == 9
    assert mock_patch_lot.call_args[0] == (pending_deleted_lot, 'deleted')

    assert mock_check_assets.call_count == 6
    assert mock_patch_assets.call_args[0] == (pending_deleted_lot, 'pending')

    # Test active.salable lot
    mock_create_auction = mocker.patch.object(bot,
                                              '_create_auction',
                                              autospec=True)
    mock_check_previous_auction = mocker.patch.object(bot,
                                                      'check_previous_auction',
                                                      autospec=True)

    active_salable_lot = lots[7]['data']
    active_salable_lot['assets'] = [assets[9]]

    created_auction = munchify(
        {'data': deepcopy(active_salable_lot['auctions'][0])})
    auction_id = 'id_of_auction'
    internal_id = '1' * 32
    created_auction.data.auctionID = auction_id
    lot_auction_id = '2' * 32
    created_auction.data.id = internal_id
    mock_create_auction.return_value = (created_auction, lot_auction_id)

    mock_check_lot.side_effect = iter([True])
    mock_check_assets.side_effect = iter([True])
    mock_patch_assets.side_effect = iter([])
    mock_get_asset.side_effect = iter([munchify(assets[9])])
    bot.process_lots(active_salable_lot)

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        18] == 'Processing lot {} in status active.salable'.format(
            active_salable_lot['id'])

    assert mock_check_lot.call_count == 13
    assert mock_check_lot.call_args[0] == (active_salable_lot, )

    patched_data = {'auctionID': created_auction.data.id, 'status': 'active'}

    assert mock_patch_lot.call_count == 9

    assert mock_patch_auction.call_count == 1
    mock_patch_auction.assert_called_with(patched_data,
                                          active_salable_lot['id'],
                                          lot_auction_id)

    assert mock_create_auction.call_count == 1
    mock_create_auction.assert_called_with(active_salable_lot)

    assert mock_check_assets.call_count == 7
    assert mock_check_assets.call_args[0] == (active_salable_lot, 'active')

    assert mock_check_previous_auction.call_count == 1
    mock_check_previous_auction.assert_called_with(active_salable_lot)

    # Test active.salable lot when it contain not valid auctions
    active_salable_lot['auctions'][0]['status'] = 'cancelled'
    active_salable_lot = lots[7]['data']
    active_salable_lot['assets'] = [assets[9]]
    mock_check_lot.side_effect = iter([True])
    mock_check_assets.side_effect = iter([True])
    mock_patch_assets.side_effect = iter([])
    mock_get_asset.side_effect = iter([munchify(assets[9])])
    bot.process_lots(active_salable_lot)

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        19] == 'Processing lot {} in status active.salable'.format(
            active_salable_lot['id'])

    assert mock_check_lot.call_count == 14
    assert mock_check_lot.call_args[0] == (active_salable_lot, )

    assert mock_patch_lot.call_count == 9

    assert mock_create_auction.call_count == 1
    mock_create_auction.assert_called_with(active_salable_lot)

    assert mock_check_assets.call_count == 8
    assert mock_check_assets.call_args[0] == (active_salable_lot, 'active')

    assert mock_check_previous_auction.call_count == 1
    mock_check_previous_auction.assert_called_with(active_salable_lot)
def test_patch_auction(bot, logger, mocker):
    with open(ROOT + 'lots.json') as lots:
        lots = load(lots)

    lot = lots[7]['data']

    mock_lots_client = bot.lots_client
    auction = 'auction'

    auction_id = '1' * 32
    # Test when patch is success
    patched_data = {'auctionID': auction_id, 'status': 'active'}
    mock_lots_client.patch_resource_item_subitem.side_effect = iter([auction])

    result = bot._patch_auction(patched_data, lot['id'], auction_id)

    assert result == auction

    assert mock_lots_client.patch_resource_item_subitem.call_count == 1
    mock_lots_client.patch_resource_item_subitem.assert_called_with(
        resource_item_id=lot['id'],
        patch_data={'data': patched_data},
        subitem_name='auctions',
        subitem_id=auction_id)

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        0] == "Successfully patched auction {} from lot {})".format(
            auction_id, lot['id'])

    # Test when post is failed
    mock_lots_client.patch_resource_item_subitem.side_effect = iter([
        RequestFailed(response=munchify({
            "text": "Bad Gateway",
            "status_code": 502
        })),
        RequestFailed(response=munchify({
            "text": "Bad Gateway",
            "status_code": 502
        })),
        RequestFailed(response=munchify({
            "text": "Bad Gateway",
            "status_code": 502
        })),
        RequestFailed(response=munchify({
            "text": "Bad Gateway",
            "status_code": 502
        })),
        RequestFailed(response=munchify({
            "text": "Bad Gateway",
            "status_code": 502
        })),
    ])

    try:
        bot._patch_auction(patched_data, lot['id'], auction_id)
    except RequestFailed as ex:
        pass

    assert isinstance(ex, RequestFailed) is True
    assert mock_lots_client.patch_resource_item_subitem.call_count == 6
    mock_lots_client.patch_resource_item_subitem.assert_called_with(
        resource_item_id=lot['id'],
        patch_data={'data': patched_data},
        subitem_name='auctions',
        subitem_id='1' * 32)
def test_patch_assets_pending_fail(bot, logger, mocker):
    mock_patch_asset = mocker.MagicMock()
    bot.assets_client.patch_asset = mock_patch_asset

    with open(ROOT + 'lots.json') as lots:
        lots = load(lots)

    with open(ROOT + 'assets.json') as assets:
        assets = load(assets)

    lot = lots[1]['data']
    status = 'pending'

    mock_patch_asset.side_effect = [
        munchify(assets[4]),
        RequestFailed(response=munchify({
            "text": "Bad Gateway",
            "status_code": 502
        })),
        RequestFailed(response=munchify({
            "text": "Bad Gateway",
            "status_code": 502
        })),
        RequestFailed(response=munchify({
            "text": "Bad Gateway",
            "status_code": 502
        })),
        RequestFailed(response=munchify({
            "text": "Bad Gateway",
            "status_code": 502
        })),
        RequestFailed(response=munchify({
            "text": "Bad Gateway",
            "status_code": 502
        })),
    ]

    result, patched_assets = bot.patch_assets(lot=lot, status=status)
    assert result is True
    assert patched_assets == ['8034c43e2d764006ad6e655e339e5fec']

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        0] == 'Successfully patched asset 8034c43e2d764006ad6e655e339e5fec to pending'

    result, patched_assets = bot.patch_assets(lot=lot, status=status)
    assert result is False
    assert patched_assets == []

    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        1] == 'Failed to patch asset 8034c43e2d764006ad6e655e339e5fec to pending (Server error: 502)'

    assert bot.assets_client.patch_asset.call_count == 6

    mock_patch_asset.side_effect = [
        Forbidden(response=munchify({"text": "Operation is forbidden."})),
        munchify(assets[4]),
    ]

    result, patched_assets = bot.patch_assets(lot=lot, status=status)
    assert result is False
    assert patched_assets == []
    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        2] == 'Failed to patch asset 8034c43e2d764006ad6e655e339e5fec to pending (Operation is forbidden.)'

    result, patched_assets = bot.patch_assets(lot=lot, status=status)
    assert result is True
    assert patched_assets == ['8034c43e2d764006ad6e655e339e5fec']
    log_strings = logger.log_capture_string.getvalue().split('\n')
    assert log_strings[
        3] == 'Successfully patched asset 8034c43e2d764006ad6e655e339e5fec to pending'

    assert bot.assets_client.patch_asset.call_count == 8