Ejemplo n.º 1
0
 def setUp(self):
     self.tender_id = uuid.uuid4().hex
     self.award_id = uuid.uuid4().hex
     self.qualification_id = uuid.uuid4().hex
     self.document_id = generate_doc_id()
     self.process_tracker = ProcessTracker(db=MagicMock())
     self.process_tracker.set_item(self.tender_id, self.award_id, 1)
     self.upload_to_tender_queue = Queue(10)
     self.url = 'http://127.0.0.1:20604'
     self.sleep_change_value = APIRateController()
     self.data = Data(self.tender_id, self.award_id, '12345678', 'awards', {
         'meta': {
             'id': self.document_id
         },
         'test_data': 'test_data'
     })
     self.qualification_data = Data(self.tender_id, self.qualification_id,
                                    '12345678', 'qualifications', {
                                        'meta': {
                                            'id': self.document_id
                                        },
                                        'test_data': 'test_data'
                                    })
     self.client = MagicMock()
     self.worker = UploadFileToTender(self.client,
                                      self.upload_to_tender_queue,
                                      self.process_tracker, MagicMock(),
                                      self.sleep_change_value)
     self.worker.retry_upload_to_tender_queue = Queue(10)
Ejemplo n.º 2
0
 def setUp(self):
     super(EndToEndTest, self).setUp()
     self.filtered_tender_ids_queue = Queue(10)
     self.edrpou_codes_queue = Queue(10)
     self.process_tracker = ProcessTracker()
     self.tender_id = uuid.uuid4().hex
     self.sleep_change_value = APIRateController()
     self.worker = EdrDataBridge(config)
Ejemplo n.º 3
0
 def setUp(self):
     self.tender_id = uuid.uuid4().hex
     self.award_id = uuid.uuid4().hex
     self.qualification_id = uuid.uuid4().hex
     self.document_id = generate_doc_id()
     self.process_tracker = ProcessTracker(db=MagicMock())
     self.process_tracker.set_item(self.tender_id, self.award_id, 1)
     self.upload_to_doc_service_queue = Queue(10)
     self.upload_to_tender_queue = Queue(10)
     self.sleep_change_value = APIRateController()
     self.sna = event.Event()
     self.sna.set()
     self.tender_data = Data(self.tender_id, self.award_id, '12345678',
                             'awards', {
                                 'meta': {
                                     'id': self.document_id
                                 },
                                 'test_data': 'test_data'
                             })
     self.data = ({
         'meta': {
             'id': self.document_id
         },
         'test_data': 'test_data'
     }, [self.tender_data])
     self.qualification_data = Data(self.tender_id, self.qualification_id,
                                    '12345678', 'qualifications', {
                                        'meta': {
                                            'id': self.document_id
                                        },
                                        'test_data': 'test_data'
                                    })
     self.doc_service_client = DocServiceClient(host='127.0.0.1',
                                                port='80',
                                                user='',
                                                password='')
     self.worker = UploadFileToDocService(self.upload_to_doc_service_queue,
                                          self.upload_to_tender_queue,
                                          self.process_tracker,
                                          self.doc_service_client, self.sna,
                                          self.sleep_change_value)
     self.url = '{url}'.format(url=self.doc_service_client.url)
Ejemplo n.º 4
0
 def setUp(self):
     self.process_tracker = ProcessTracker(
         MagicMock(has=MagicMock(return_value=False)))
     self.tenders_id = [uuid.uuid4().hex for _ in range(4)]
     self.sleep_change_value = APIRateController()
     self.client = MagicMock()
     self.tender_queue = Queue(10)
     self.sna = event.Event()
     self.sna.set()
     self.worker = Scanner.spawn(self.client, self.tender_queue, self.sna,
                                 self.process_tracker,
                                 self.sleep_change_value)
Ejemplo n.º 5
0
 def setUp(self):
     self.filtered_tender_ids_queue = Queue(10)
     self.edrpou_codes_queue = Queue(10)
     self.process_tracker = ProcessTracker()
     self.tender_id = uuid.uuid4().hex
     self.filtered_tender_ids_queue.put(self.tender_id)
     self.sleep_change_value = APIRateController()
     self.client = MagicMock()
     self.sna = event.Event()
     self.sna.set()
     self.worker = FilterTenders.spawn(self.client, self.filtered_tender_ids_queue, self.edrpou_codes_queue,
                                       self.process_tracker, self.sna, self.sleep_change_value)
     self.bid_ids = [uuid.uuid4().hex for _ in range(5)]
     self.qualification_ids = [uuid.uuid4().hex for _ in range(5)]
     self.award_ids = [uuid.uuid4().hex for _ in range(5)]
     self.request_ids = [generate_request_id() for _ in range(2)]
     self.response = ResponseMock({'X-Request-ID': self.request_ids[0]},
                                  munchify({'prev_page': {'offset': '123'},
                                            'next_page': {'offset': '1234'},
                                            'data': {'status': tender_status,
                                                     'id': self.tender_id,
                                                     'procurementMethodType': 'aboveThresholdEU',
                                                     'awards': [self.awards(0, 0, AWARD_STATUS, CODES[0])]}}))
Ejemplo n.º 6
0
 def setUp(self):
     self.process_tracker = ProcessTracker(self.db)
     self.tender_id = "111"
     self.award_id = "222"
     self.document_id = "333"
Ejemplo n.º 7
0
class TestUtils(TestCase):
    relative_to = os.path.dirname(__file__)  # crafty line
    redis = None
    redis_process = None
    PORT = 16379
    db = Db(config)

    @classmethod
    def setUpClass(cls):
        cls.redis_process = subprocess.Popen(
            ['redis-server', '--port',
             str(cls.PORT), '--logfile /dev/null'])
        sleep(0.1)
        cls.redis = StrictRedis(port=cls.PORT)

    def setUp(self):
        self.process_tracker = ProcessTracker(self.db)
        self.tender_id = "111"
        self.award_id = "222"
        self.document_id = "333"

    @classmethod
    def tearDownClass(cls):
        cls.redis_process.terminate()
        cls.redis_process.wait()

    def tearDown(self):
        self.redis.flushall()

    def test_db_init(self):
        self.assertEqual(self.db._backend, "redis")
        self.assertEqual(self.db._db_name, 0)
        self.assertEqual(self.db._port, "16379")
        self.assertEqual(self.db._host, "127.0.0.1")

    def test_db_get(self):
        self.assertIsNone(self.db.get("111"))
        self.db.put("111", "test data")
        self.assertEqual(self.db.get("111"), "test data")

    def test_db_set(self):
        self.db.put("111", "test data")
        self.assertEqual(self.db.get("111"), "test data")

    def test_db_has(self):
        self.assertFalse(self.db.has("111"))
        self.db.put("111", "test data")
        self.assertTrue(self.db.has("111"))

    def test_set_item(self):
        self.assertEqual(self.process_tracker.processing_items, {})
        self.assertEqual(self.process_tracker.tender_documents_to_process, {})
        self.process_tracker.set_item(self.tender_id, self.award_id, 1)
        self.assertEqual(self.process_tracker.processing_items,
                         {item_key(self.tender_id, self.award_id): 1})
        self.assertEqual(self.process_tracker.tender_documents_to_process,
                         {db_key(self.tender_id): 1})

    def test_add_docs_amount_to_tender(self):
        self.assertEqual(self.process_tracker.tender_documents_to_process, {})
        self.process_tracker._add_docs_amount_to_tender(self.tender_id, 2)
        self.assertEqual(self.process_tracker.tender_documents_to_process,
                         {db_key(self.tender_id): 2})
        self.process_tracker._add_docs_amount_to_tender(self.tender_id, 3)
        self.assertEqual(self.process_tracker.tender_documents_to_process,
                         {db_key(self.tender_id): 5})

    def test_remove_docs_amount_from_tender(self):
        self.assertEqual(self.process_tracker.tender_documents_to_process, {})
        self.process_tracker.tender_documents_to_process = {
            db_key(self.tender_id): 2
        }
        self.assertEqual(self.process_tracker.tender_documents_to_process,
                         {db_key(self.tender_id): 2})
        self.process_tracker._remove_docs_amount_from_tender(self.tender_id)
        self.assertEqual(self.process_tracker.tender_documents_to_process,
                         {db_key(self.tender_id): 1})
        self.process_tracker._remove_docs_amount_from_tender(self.tender_id)
        self.assertEqual(self.process_tracker.tender_documents_to_process, {})

    def test_check_processing_item(self):
        self.assertEqual(self.process_tracker.processing_items, {})
        self.assertFalse(
            self.process_tracker.check_processing_item(self.tender_id,
                                                       self.award_id))
        self.process_tracker.set_item(self.tender_id, self.award_id)
        self.assertTrue(
            self.process_tracker.check_processing_item(self.tender_id,
                                                       self.award_id))

    def test_check_processed_item(self):
        self.assertEqual(self.process_tracker.processed_items, {})
        self.assertFalse(
            self.process_tracker.check_processed_item(self.tender_id,
                                                      self.award_id))
        self.process_tracker.set_item(self.tender_id, self.award_id)
        self.process_tracker.update_items_and_tender(self.tender_id,
                                                     self.award_id,
                                                     self.document_id)
        self.assertTrue(
            self.process_tracker.check_processed_item(self.tender_id,
                                                      self.award_id))

    def test_check_processed_tender(self):
        self.assertFalse(
            self.process_tracker.check_processed_tenders(self.tender_id))
        self.redis.set(self.tender_id, "333")
        self.assertTrue(
            self.process_tracker.check_processed_tenders(self.tender_id))

    def test_update_processing_items(self):
        self.process_tracker.processing_items = {
            item_key(self.tender_id, self.award_id): 2
        }
        self.assertEqual(self.process_tracker.processing_items,
                         {item_key(self.tender_id, self.award_id): 2})
        self.process_tracker._update_processing_items(self.tender_id,
                                                      self.award_id,
                                                      self.document_id)
        self.assertEqual(self.process_tracker.processing_items,
                         {item_key(self.tender_id, self.award_id): 1})
        self.process_tracker._update_processing_items(self.tender_id,
                                                      self.award_id,
                                                      self.document_id)
        self.assertEqual(self.process_tracker.processing_items, {})

    def test_check_412_function(self):
        func = check_412(
            MagicMock(side_effect=ResourceError(
                http_code=412, response=MagicMock(headers={'Set-Cookie': 1}))))
        with self.assertRaises(ResourceError):
            func(MagicMock(headers={'Cookie': 1}))
        func = check_412(
            MagicMock(side_effect=ResourceError(
                http_code=403, response=MagicMock(headers={'Set-Cookie': 1}))))
        with self.assertRaises(ResourceError):
            func(MagicMock(headers={'Cookie': 1}))
        f = check_412(MagicMock(side_effect=[1]))
        self.assertEqual(f(1), 1)

    @given(integers())
    def test_to_base36(self, input):
        self.assertEqual(to_base36(11), "B")
        self.assertEqual(to_base36(35), "Z")
        self.assertEqual(to_base36(36), "10")
        to_base36(input)

    @patch("bot.dfs.bridge.utils.datetime")
    @given(integers(), datetimes())
    def test_file_name(self, datetime_mock, code, h_date):
        datetime_mock.now = MagicMock(return_value=h_date)
        sample_name = "ieK{}{}{}{}{}1.xml".format(code, FORM_NAME,
                                                  to_base36(h_date.month),
                                                  to_base36(h_date.day),
                                                  h_date.year)
        self.assertEqual(sample_name, sfs_file_name(code, 1))

    def test_item_key(self):
        tender_id = '123'
        award_id = '456'
        self.assertEqual(item_key(tender_id, award_id),
                         '{}_{}'.format(tender_id, award_id))

    def test_journal_context(self):
        params = {'text': '123'}
        self.assertTrue(journal_context(params=params))

    def test_generate_req_id(self):
        self.assertTrue(isinstance(generate_req_id(), str))

    def test_generate_doc_id(self):
        self.assertTrue(isinstance(generate_doc_id(), str))

    def test_is_no_document_in_edr(self):
        response = MagicMock(headers={'Set-Cookie': 1})
        res_json = {
            'errors': [{
                'description': [{
                    'error': {
                        'code': 'notFound'
                    }
                }]
            }]
        }
        self.assertFalse(is_no_document_in_edr(response, res_json))

    def test_should_process_item(self):
        item = {
            'status': 'active',
            'documents': [{
                'documentType': 'registerExtract'
            }]
        }
        self.assertFalse(should_process_item(item))

    def test_is_code_invalid(self):
        code = 123
        self.assertFalse(is_code_invalid(code))

    def test_more_tenders(self):
        params = {'offset': '123', 'descending': 1}
        response = MagicMock(headers={'Set-Cookie': 1})
        self.assertTrue(more_tenders(params, response))

    def test_valid_qualification_tender(self):
        tender = {
            'status': "active.qualification",
            'procurementMethodType': 'aboveThresholdUA'
        }
        self.assertTrue(valid_qualification_tender(tender))

    @patch('bot.dfs.bridge.utils.datetime')
    def test_business_date_checker_business_date(self, datetime_mock):
        datetime_mock.now = MagicMock(
            return_value=datetime(2017, 10, 10, 12, 00, 00, 000000))
        self.assertTrue(business_date_checker())

    @patch('bot.dfs.bridge.utils.datetime')
    def test_business_date_checker_weekend(self, datetime_mock):
        datetime_mock.now = MagicMock(
            return_value=datetime(2017, 10, 16, 12, 00, 00, 000000))
        self.assertFalse(business_date_checker())

    @patch('bot.dfs.bridge.utils.datetime')
    def test_business_date_checker_free_time(self, datetime_mock):
        datetime_mock.now = MagicMock(
            return_value=datetime(2017, 10, 10, 06, 00, 00, 000000))
        self.assertFalse(business_date_checker())
Ejemplo n.º 8
0
class TestUploadFileToTenderWorker(unittest.TestCase):
    __test__ = True

    def setUp(self):
        self.tender_id = uuid.uuid4().hex
        self.award_id = uuid.uuid4().hex
        self.qualification_id = uuid.uuid4().hex
        self.document_id = generate_doc_id()
        self.process_tracker = ProcessTracker(db=MagicMock())
        self.process_tracker.set_item(self.tender_id, self.award_id, 1)
        self.upload_to_tender_queue = Queue(10)
        self.url = 'http://127.0.0.1:20604'
        self.sleep_change_value = APIRateController()
        self.data = Data(self.tender_id, self.award_id, '12345678', 'awards', {
            'meta': {
                'id': self.document_id
            },
            'test_data': 'test_data'
        })
        self.qualification_data = Data(self.tender_id, self.qualification_id,
                                       '12345678', 'qualifications', {
                                           'meta': {
                                               'id': self.document_id
                                           },
                                           'test_data': 'test_data'
                                       })
        self.client = MagicMock()
        self.worker = UploadFileToTender(self.client,
                                         self.upload_to_tender_queue,
                                         self.process_tracker, MagicMock(),
                                         self.sleep_change_value)
        self.worker.retry_upload_to_tender_queue = Queue(10)

    def tearDown(self):
        del self.worker
        del self.upload_to_tender_queue

    @staticmethod
    def get_tender():
        return {
            'data': {
                'id': uuid.uuid4().hex,
                'documentOf': 'tender',
                'documentType': DOC_TYPE,
                'url': 'url'
            }
        }

    def is_working(self, worker):
        return self.upload_to_tender_queue.qsize(
        ) or worker.retry_upload_to_tender_queue.qsize()

    def shutdown_when_done(self, worker):
        worker.start()
        while self.is_working(worker):
            sleep(0.1)
        worker.shutdown()

    @patch('gevent.sleep')
    def test_upload_to_tender_429(self, gevent_sleep):
        gevent_sleep.side_effect = custom_sleep
        self.client._create_tender_resource_item = MagicMock(side_effect=[
            ResourceError(http_code=429),
            ResourceError(http_code=429),
            ResourceError(http_code=403)
        ])
        self.upload_to_tender_queue.put(self.data)
        self.shutdown_when_done(self.worker)
        self.assertEqual(self.upload_to_tender_queue.qsize(), 0,
                         'Queue should be empty')
        self.assertEqual(self.worker.sleep_change_value.time_between_requests,
                         1)

    @patch('gevent.sleep')
    def test_upload_to_tender_exception(self, gevent_sleep):
        gevent_sleep.side_effect = custom_sleep
        self.upload_to_tender_queue.put(self.data)
        self.client._create_tender_resource_item = MagicMock(
            side_effect=[Exception()])
        self.worker.do_upload_to_tender_with_retry = MagicMock(
            side_effect=ResourceError(http_code=403))
        self.shutdown_when_done(self.worker)
        self.assertEqual(self.upload_to_tender_queue.qsize(), 0,
                         'Queue should be empty')
        self.assertEqual(self.worker.sleep_change_value.time_between_requests,
                         0)

    @patch('gevent.sleep')
    def test_upload_to_tender_exception_status_int_none(self, gevent_sleep):
        gevent_sleep.side_effect = custom_sleep
        self.upload_to_tender_queue.put(self.data)
        client = MagicMock()
        client._create_tender_resource_item = MagicMock(
            side_effect=[Unauthorized()])
        self.shutdown_when_done(self.worker)
        self.assertEqual(self.upload_to_tender_queue.qsize(), 0,
                         'Queue should be empty')
        self.assertEqual(self.worker.sleep_change_value.time_between_requests,
                         0)

    @patch('gevent.sleep')
    def test_retry_upload_to_tender(self, gevent_sleep):
        gevent_sleep.side_effect = custom_sleep
        self.client._create_tender_resource_item.side_effect = [
            Unauthorized(http_code=401),
            Unauthorized(http_code=403),
            Unauthorized(http_code=429),
            self.get_tender()
        ]
        self.upload_to_tender_queue.put(self.data)
        self.assertItemsEqual(self.process_tracker.processing_items.keys(),
                              [item_key(self.tender_id, self.award_id)])
        self.assertEqual(self.upload_to_tender_queue.qsize(), 1)
        self.shutdown_when_done(self.worker)
        self.assertEqual(self.upload_to_tender_queue.qsize(), 0,
                         'Queue should be empty')
        self.assertEqual(self.process_tracker.processing_items,
                         {})  # test that item removed from processing_items
        self.assertEqual(self.client._create_tender_resource_item.call_count,
                         4)  # check upload to tender

    @patch('gevent.sleep')
    def test_retry_upload_to_tender_422(self, gevent_sleep):
        gevent_sleep.side_effect = custom_sleep
        self.client_upload_to_tender = MagicMock(side_effect=ResourceError(
            http_code=422))
        self.worker.retry_upload_to_tender_queue = Queue(10)
        self.worker.retry_upload_to_tender_queue.put(self.data)
        self.shutdown_when_done(self.worker)
        self.assertEqual(self.upload_to_tender_queue.qsize(), 0,
                         'Queue should be empty')

    @patch('gevent.sleep')
    def test_retry_upload_to_tender_429(self, gevent_sleep):
        gevent_sleep.side_effect = custom_sleep
        self.client.client_upload_to_tender = MagicMock(side_effect=[
            ResourceError(http_code=429),
            ResourceError(http_code=403)
        ])
        self.worker.retry_upload_to_tender_queue = Queue(10)
        self.worker.retry_upload_to_tender_queue.put(self.data)
        self.shutdown_when_done(self.worker)
        self.assertEqual(self.upload_to_tender_queue.qsize(), 0,
                         'Queue should be empty')

    @patch('gevent.sleep')
    def test_retry_upload_to_tender_exception(self, gevent_sleep):
        gevent_sleep.side_effect = custom_sleep
        self.worker.do_upload_to_tender_with_retry = MagicMock(
            side_effect=[Exception(),
                         ResourceError(http_code=403)])
        self.worker.retry_upload_to_tender_queue.put(self.data)
        self.shutdown_when_done(self.worker)
        self.assertEqual(self.upload_to_tender_queue.qsize(), 0,
                         'Queue should be empty')

    @patch('gevent.sleep')
    def test_upload_to_tender_queue_loop_exit(self, gevent_sleep):
        """ Test LoopExit for upload_to_tender_queue """
        gevent_sleep.side_effect = custom_sleep
        self.client._create_tender_resource_item.side_effect = [
            self.get_tender() for _ in range(2)
        ]
        self.process_tracker.set_item(self.tender_id, self.award_id, 2)
        self.worker.upload_to_tender_queue = MagicMock()
        self.worker.upload_to_tender_queue.peek.side_effect = generate_answers(
            answers=[LoopExit(), self.datum(),
                     self.datum()],
            default=LoopExit())
        self.worker.start()
        sleep(1)
        self.worker.shutdown()
        self.assertEqual(self.process_tracker.processing_items, {})
        self.assertIsNotNone(
            self.client.request_history[0].headers['X-Client-Request-ID'])
        self.assertIsNotNone(
            self.client.request_history[1].headers['X-Client-Request-ID'])
        self.assertEqual(self.client._create_tender_resource_item.call_count,
                         2)  # check that processed just 1 request

    def datum(self):
        return Data(
            self.tender_id, self.award_id, '12345678', 'awards', {
                u'meta': {
                    u'id': self.document_id
                },
                u'url':
                u'http://docs-sandbox.openprocurement.org/get/8ccbfde0c6804143b119d9168452cb6f',
                u'format': u'application/yaml',
                u'hash': u'md5:9a0364b9e99bb480dd25e1f0284c8555',
                u'title': file_name
            })

    @patch('gevent.sleep')
    def test_retry_upload_to_tender_queue_loop_exit(self, gevent_sleep):
        """ Test LoopExit for retry_upload_to_tender_queue """
        gevent_sleep.side_effect = custom_sleep
        self.client._create_tender_resource_item.side_effect = [
            self.get_tender() for _ in range(2)
        ]
        self.worker.retry_upload_to_tender_queue = MagicMock()
        self.worker.retry_upload_to_tender_queue.peek.side_effect = generate_answers(
            answers=[LoopExit(), self.datum(),
                     self.datum()],
            default=LoopExit())
        self.process_tracker.set_item(self.tender_id, self.award_id, 2)
        self.worker.start()
        sleep(1)
        self.worker.shutdown()
        self.assertEqual(self.process_tracker.processing_items, {})
        self.assertIsNotNone(
            self.client.request_history[0].headers['X-Client-Request-ID'])
        self.assertIsNotNone(
            self.client.request_history[1].headers['X-Client-Request-ID'])
        self.assertEqual(self.client._create_tender_resource_item.call_count,
                         2)  # check that processed just 1 request

    @patch('gevent.sleep')
    def test_request_failed_in_retry_item_status(self, gevent_sleep):
        gevent_sleep.side_effect = custom_sleep
        self.client._create_tender_resource_item.side_effect = [
            ResourceError(http_code=429)
        ] + [ResourceError(http_code=403) for _ in range(4)]
        self.worker.retry_upload_to_tender_queue.put(self.data)
        self.shutdown_when_done(self.worker)
        self.assertEqual(self.upload_to_tender_queue.qsize(), 0,
                         'Queue should be empty')

    @patch('gevent.sleep')
    def test_request_failed_in_retry(self, gevent_sleep):
        gevent_sleep.side_effect = custom_sleep
        self.worker.do_upload_to_tender_with_retry = MagicMock()
        self.worker.do_upload_to_tender_with_retry.side_effect = [
            ResourceError(http_code=429) for _ in range(5)
        ] + [ResourceError(http_code=403)]
        self.sleep_change_value.increment_step = 3
        self.sleep_change_value.decrement_step = 1.5
        self.worker.retry_upload_to_tender_queue.put(self.data)
        self.shutdown_when_done(self.worker)
        self.assertEqual(self.upload_to_tender_queue.qsize(), 0,
                         'Queue should be empty')
        self.assertEqual(self.worker.sleep_change_value.time_between_requests,
                         13.5)

    @patch('gevent.sleep')
    def test_process_412(self, gevent_sleep):
        gevent_sleep.side_effect = custom_sleep
        api_server_bottle = Bottle()
        api_server = WSGIServer(('127.0.0.1', 20604),
                                api_server_bottle,
                                log=None)
        setup_routing(api_server_bottle, response_spore)
        setup_routing(api_server_bottle,
                      response_412,
                      path='/api/2.3/tenders/{}/awards/{}/documents'.format(
                          self.tender_id, self.award_id),
                      method='POST')
        api_server.start()
        self.worker.client = TendersClient('',
                                           host_url='http://127.0.0.1:20604',
                                           api_version='2.3')
        setup_routing(api_server_bottle,
                      generate_response,
                      path='/api/2.3/tenders/{}/awards/{}/documents'.format(
                          self.tender_id, self.award_id),
                      method='POST')
        self.assertEqual(self.worker.client.headers['Cookie'],
                         'SERVER_ID={}'.format(SPORE_COOKIES))
        self.upload_to_tender_queue.put(self.data)
        self.assertItemsEqual(self.process_tracker.processing_items.keys(),
                              [item_key(self.tender_id, self.award_id)])
        self.assertEqual(self.upload_to_tender_queue.qsize(), 1)
        self.shutdown_when_done(self.worker)
        self.assertEqual(self.worker.client.headers['Cookie'],
                         'SERVER_ID={}'.format(COOKIES_412))
        self.assertEqual(self.upload_to_tender_queue.qsize(), 0,
                         'Queue should be empty')
        self.assertEqual(self.worker.retry_upload_to_tender_queue.qsize(), 0,
                         'Queue should be empty')
        self.assertItemsEqual(self.process_tracker.processing_items.keys(), [])
        api_server.stop()

    @patch('gevent.sleep')
    def test_upload_worker(self, gevent_sleep):
        gevent_sleep.side_effect = custom_sleep
        self.worker.services_not_available = MagicMock(wait=MagicMock())
        self.worker.try_peek_data_and_upload_to_tender = MagicMock()
        with patch.object(self.worker, 'exit', AlmostAlwaysFalse()):
            self.worker.upload_worker()
        self.worker.services_not_available.wait.assert_called_once()
        self.worker.try_peek_data_and_upload_to_tender.assert_called_once_with(
            False)

    @patch('gevent.sleep')
    def test_retry_upload_worker(self, gevent_sleep):
        gevent_sleep.side_effect = custom_sleep
        self.worker.services_not_available = MagicMock(wait=MagicMock())
        self.worker.try_peek_data_and_upload_to_tender = MagicMock()
        with patch.object(self.worker, 'exit', AlmostAlwaysFalse()):
            self.worker.retry_upload_worker()
        self.worker.services_not_available.wait.assert_called_once()
        self.worker.try_peek_data_and_upload_to_tender.assert_called_once_with(
            True)

    def test_peek_from_tender_queue(self):
        self.worker.upload_to_tender_queue.put(self.data)
        self.assertEqual(self.worker.peek_from_tender_queue(False), self.data)

    def test_peek_from_tender_queue_retry(self):
        self.worker.retry_upload_to_tender_queue.put(self.data)
        self.assertEqual(self.worker.peek_from_tender_queue(True), self.data)

    def test_peek_from_tender_queue_empty(self):
        self.worker.upload_to_tender_queue = MagicMock(peek=MagicMock(
            side_effect=LoopExit))
        with self.assertRaises(LoopExit):
            self.worker.peek_from_tender_queue(False)

    def test_peek_from_tender_queue_retry_empty(self):
        self.worker.retry_upload_to_tender_queue = MagicMock(peek=MagicMock(
            side_effect=LoopExit))
        with self.assertRaises(LoopExit):
            self.worker.peek_from_tender_queue(True)

    def test_try_peek_data_and_upload_to_tender(self):
        self.worker.upload_to_tender_queue.put(self.data)
        self.worker.try_upload_to_tender = MagicMock()
        self.worker.try_peek_data_and_upload_to_tender(False)
        self.worker.try_upload_to_tender.assert_called_once_with(
            self.data, False)

    def test_try_peek_data_and_upload_to_tender_retry(self):
        self.worker.retry_upload_to_tender_queue.put(self.data)
        self.worker.try_upload_to_tender = MagicMock()
        self.worker.try_peek_data_and_upload_to_tender(True)
        self.worker.try_upload_to_tender.assert_called_once_with(
            self.data, True)

    def test_try_upload_to_tender(self):
        self.worker.update_headers_and_upload_to_tender = MagicMock()
        self.worker.successfully_uploaded_to_tender = MagicMock()
        self.worker.try_upload_to_tender(self.data, False)
        self.worker.update_headers_and_upload_to_tender.assert_called_once_with(
            self.data, False)
        self.worker.successfully_uploaded_to_tender.assert_called_once_with(
            self.data, False)

    def test_try_upload_to_tender_retry(self):
        self.worker.update_headers_and_upload_to_tender = MagicMock()
        self.worker.successfully_uploaded_to_tender = MagicMock()
        self.worker.try_upload_to_tender(self.data, True)
        self.worker.update_headers_and_upload_to_tender.assert_called_once_with(
            self.data, True)
        self.worker.successfully_uploaded_to_tender.assert_called_once_with(
            self.data, True)

    def test_try_upload_to_tender_no_mock(self):
        self.upload_to_tender_queue.put(self.data)
        self.worker.try_upload_to_tender(self.data, False)
        self.assertEqual(self.upload_to_tender_queue.qsize(), 0)
        self.assertEqual(self.process_tracker.processing_items, {})

    def test_try_upload_to_tender_no_mock_retry(self):
        self.worker.retry_upload_to_tender_queue.put(self.data)
        self.worker.try_upload_to_tender(self.data, True)
        self.assertEqual(self.upload_to_tender_queue.qsize(), 0)
        self.assertEqual(self.process_tracker.processing_items, {})

    def test_try_upload_to_tender_resource_error(self):
        re = ResourceError("test resource error")
        self.worker.update_headers_and_upload_to_tender = MagicMock(
            side_effect=re)
        self.worker.remove_data_or_increase_wait = MagicMock()
        self.worker.try_upload_to_tender(self.data, False)
        self.worker.remove_data_or_increase_wait.assert_called_once_with(
            re, self.data, False)

    def test_try_upload_to_tender_exception(self):
        e = Exception("exception")
        self.worker.update_headers_and_upload_to_tender = MagicMock(
            side_effect=e)
        self.worker.handle_error = MagicMock()
        self.worker.try_upload_to_tender(self.data, False)
        self.worker.handle_error.assert_called_once_with(e, self.data, False)

    def test_update_headers_and_upload_to_tender(self):
        self.worker.do_upload_to_tender = MagicMock()
        self.worker.update_headers_and_upload_to_tender(self.data, False)
        self.worker.do_upload_to_tender.assert_called_once_with(self.data)

    def test_update_headers_and_upload_to_tender_retry(self):
        self.worker.do_upload_to_tender_with_retry = MagicMock()
        self.worker.update_headers_and_upload_to_tender(self.data, True)
        self.worker.do_upload_to_tender_with_retry.assert_called_once_with(
            self.data)

    def test_do_upload_to_tender(self):
        api_server_bottle = Bottle()
        api_server = WSGIServer(('127.0.0.1', 20604),
                                api_server_bottle,
                                log=None)
        setup_routing(api_server_bottle, response_spore)
        api_server.start()
        self.worker.client = TendersClientSync(
            '', host_url='http://127.0.0.1:20604', api_version='2.3')
        setup_routing(api_server_bottle,
                      response_get_tender,
                      path='/api/2.3/tenders/{}/awards/{}/documents'.format(
                          self.tender_id, self.award_id),
                      method='POST')
        self.worker.do_upload_to_tender(self.data)
        api_server.stop()

    def test_do_upload_to_tender_failure(self):
        api_server_bottle = Bottle()
        api_server = WSGIServer(('127.0.0.1', 20604),
                                api_server_bottle,
                                log=None)
        setup_routing(api_server_bottle, response_spore)
        api_server.start()
        self.worker.client = TendersClientSync(
            '', host_url='http://127.0.0.1:20604', api_version='2.3')
        setup_routing(api_server_bottle,
                      response_412,
                      path='/api/2.3/tenders/{}/awards/{}/documents'.format(
                          self.tender_id, self.award_id),
                      method='POST')
        with self.assertRaises(ResourceError):
            self.worker.do_upload_to_tender(self.data)
        api_server.stop()

    def test_do_upload_to_tender_with_retry(self):
        api_server_bottle = Bottle()
        api_server = WSGIServer(('127.0.0.1', 20604),
                                api_server_bottle,
                                log=None)
        setup_routing(api_server_bottle, response_spore)
        api_server.start()
        self.worker.client = TendersClientSync(
            '', host_url='http://127.0.0.1:20604', api_version='2.3')
        setup_routing(api_server_bottle,
                      response_get_tender,
                      path='/api/2.3/tenders/{}/awards/{}/documents'.format(
                          self.tender_id, self.award_id),
                      method='POST')
        self.worker.do_upload_to_tender_with_retry(self.data)
        api_server.stop()

    def test_do_upload_to_tender_with_retry_fail_then_success(self):
        api_server_bottle = Bottle()
        api_server = WSGIServer(('127.0.0.1', 20604),
                                api_server_bottle,
                                log=None)
        setup_routing(api_server_bottle, response_spore)
        api_server.start()
        self.worker.client = TendersClientSync(
            '', host_url='http://127.0.0.1:20604', api_version='2.3')
        setup_routing(api_server_bottle,
                      generate_response_retry,
                      path='/api/2.3/tenders/{}/awards/{}/documents'.format(
                          self.tender_id, self.award_id),
                      method='POST')
        self.worker.do_upload_to_tender_with_retry(self.data)
        api_server.stop()

    def test_do_upload_to_tender_with_retry_fail(self):
        api_server_bottle = Bottle()
        api_server = WSGIServer(('127.0.0.1', 20604),
                                api_server_bottle,
                                log=None)
        setup_routing(api_server_bottle, response_spore)
        api_server.start()
        self.worker.client = TendersClientSync(
            '', host_url='http://127.0.0.1:20604', api_version='2.3')
        setup_routing(api_server_bottle,
                      response_412,
                      path='/api/2.3/tenders/{}/awards/{}/documents'.format(
                          self.tender_id, self.award_id),
                      method='POST')
        with self.assertRaises(ResourceError):
            self.worker.do_upload_to_tender_with_retry(self.data)
        api_server.stop()

    def test_remove_data_or_increase_wait(self):
        re = ResourceError("error")
        self.worker.removing_data = MagicMock()
        self.worker.remove_data_or_increase_wait(re, self.data, False)
        self.worker.removing_data.assert_called_once_with(re, self.data, False)

    def test_remove_data_or_increase_wait_429(self):
        re = ResourceError("error", http_code=429)
        self.worker.decrease_request_frequency = MagicMock()
        self.worker.remove_data_or_increase_wait(re, self.data, False)
        self.worker.decrease_request_frequency.assert_called_once_with(
            re, self.data)

    def test_remove_data_or_increase_wait_else(self):
        re = ResourceError("error", http_code=404)
        self.worker.handle_error = MagicMock()
        self.worker.remove_data_or_increase_wait(re, self.data, False)
        self.worker.handle_error.assert_called_once_with(re, self.data, False)

    def test_removing_data(self):
        re = ResourceError("error")
        self.worker.sleep_change_value.time_between_requests = 1
        self.worker.upload_to_tender_queue.put(self.data)
        self.worker.removing_data(re, self.data, False)
        self.assertEqual(self.worker.process_tracker.processing_items, {})
        self.assertEqual(self.worker.upload_to_tender_queue.qsize(), 0)
        self.assertEqual(self.worker.sleep_change_value.time_between_requests,
                         0)

    def test_removing_data_retry(self):
        re = ResourceError("error")
        self.worker.sleep_change_value.time_between_requests = 1
        self.worker.retry_upload_to_tender_queue.put(self.data)
        self.worker.removing_data(re, self.data, True)
        self.assertEqual(self.worker.process_tracker.processing_items, {})
        self.assertEqual(self.worker.upload_to_tender_queue.qsize(), 0)
        self.assertEqual(self.worker.retry_upload_to_tender_queue.qsize(), 0)
        self.assertEqual(self.worker.sleep_change_value.time_between_requests,
                         0)

    def test_decrease_request_frequency(self):
        re = ResourceError("error", 429)
        self.worker.decrease_request_frequency(re, self.data)
        self.assertEqual(self.worker.sleep_change_value.time_between_requests,
                         1)

    def test_handle_error(self):
        re = ResourceError("error", 404)
        self.worker.upload_to_tender_queue.put(self.data)
        self.worker.handle_error(re, self.data, False)
        self.assertEqual(self.worker.upload_to_tender_queue.qsize(), 0)
        self.assertEqual(self.worker.retry_upload_to_tender_queue.get(),
                         self.data)
        self.assertEqual(self.worker.retry_upload_to_tender_queue.qsize(), 0)

    def test_handle_error_retry(self):
        re = ResourceError("error", 404)
        self.worker.upload_to_tender_queue.put(self.data)
        self.worker.handle_error(re, self.data, True)
        self.assertEqual(self.worker.upload_to_tender_queue.qsize(), 1)
        self.assertEqual(self.worker.retry_upload_to_tender_queue.qsize(), 0)

    def test_successfully_uploaded_to_tender(self):
        self.worker.upload_to_tender_queue.put(self.data)
        self.assertEqual(self.worker.process_tracker.processing_items,
                         {item_key(self.tender_id, self.award_id): 1})
        self.worker.successfully_uploaded_to_tender(self.data, False)
        self.assertEqual(self.worker.upload_to_tender_queue.qsize(), 0)
        self.assertEqual(self.worker.process_tracker.processing_items, {})

    def test_successfully_uploaded_to_tender_retry(self):
        self.worker.retry_upload_to_tender_queue.put(self.data)
        self.assertEqual(self.worker.process_tracker.processing_items,
                         {item_key(self.tender_id, self.award_id): 1})
        self.worker.successfully_uploaded_to_tender(self.data, True)
        self.assertEqual(self.worker.retry_upload_to_tender_queue.qsize(), 0)
        self.assertEqual(self.worker.process_tracker.processing_items, {})

    def test_run(self):
        self.worker.delay = 1
        upload_worker, retry_upload_worker = MagicMock(), MagicMock()
        self.worker.upload_worker = upload_worker
        self.worker.retry_upload_worker = retry_upload_worker
        with patch.object(self.worker, 'exit', AlmostAlwaysFalse()):
            self.worker._run()
        self.assertEqual(self.worker.upload_worker.call_count, 1)
        self.assertEqual(self.worker.retry_upload_worker.call_count, 1)

    @patch('gevent.killall')
    @patch('gevent.sleep')
    def test_run_exception(self, gevent_sleep, killlall):
        gevent_sleep.side_effect = custom_sleep
        self.worker._start_jobs = MagicMock(return_value={"a": 1})
        self.worker.check_and_revive_jobs = MagicMock(
            side_effect=Exception("test error"))
        self.worker._run()
        killlall.assert_called_once_with([1], timeout=5)

    @patch('gevent.killall')
    def test_run_exception(self, killlall):
        self.worker.delay = 1
        self.worker._start_jobs = MagicMock(return_value={"a": 1})
        self.worker.check_and_revive_jobs = MagicMock(
            side_effect=Exception("test error"))
        self.worker._run()
        killlall.assert_called_once_with([1], timeout=5)
Ejemplo n.º 9
0
class TestUploadFileWorker(unittest.TestCase):
    __test__ = True

    def setUp(self):
        self.tender_id = uuid.uuid4().hex
        self.award_id = uuid.uuid4().hex
        self.qualification_id = uuid.uuid4().hex
        self.document_id = generate_doc_id()
        self.process_tracker = ProcessTracker(db=MagicMock())
        self.process_tracker.set_item(self.tender_id, self.award_id, 1)
        self.upload_to_doc_service_queue = Queue(10)
        self.upload_to_tender_queue = Queue(10)
        self.sleep_change_value = APIRateController()
        self.sna = event.Event()
        self.sna.set()
        self.tender_data = Data(self.tender_id, self.award_id, '12345678',
                                'awards', {
                                    'meta': {
                                        'id': self.document_id
                                    },
                                    'test_data': 'test_data'
                                })
        self.data = ({
            'meta': {
                'id': self.document_id
            },
            'test_data': 'test_data'
        }, [self.tender_data])
        self.qualification_data = Data(self.tender_id, self.qualification_id,
                                       '12345678', 'qualifications', {
                                           'meta': {
                                               'id': self.document_id
                                           },
                                           'test_data': 'test_data'
                                       })
        self.doc_service_client = DocServiceClient(host='127.0.0.1',
                                                   port='80',
                                                   user='',
                                                   password='')
        self.worker = UploadFileToDocService(self.upload_to_doc_service_queue,
                                             self.upload_to_tender_queue,
                                             self.process_tracker,
                                             self.doc_service_client, self.sna,
                                             self.sleep_change_value)
        self.url = '{url}'.format(url=self.doc_service_client.url)

    @staticmethod
    def stat_200():
        return {
            'data': {
                'url':
                'http://docs-sandbox.openprocurement.org/get/8ccbfde0c6804143b119d9168452cb6f',
                'format': 'application/yaml',
                'hash': 'md5:9a0364b9e99bb480dd25e1f0284c8555',
                'title': file_name
            }
        }

    @staticmethod
    def get_tender():
        return {
            'data': {
                'id': uuid.uuid4().hex,
                'documentOf': 'tender',
                'documentType': DOC_TYPE,
                'url': 'url'
            }
        }

    def tearDown(self):
        del self.worker

    def is_working(self, worker):
        return self.upload_to_doc_service_queue.qsize(
        ) or worker.retry_upload_to_doc_service_queue.qsize()

    def shutdown_when_done(self, worker):
        worker.start()
        while self.is_working(worker):
            sleep(0.1)
        worker.shutdown()

    def test_init(self):
        worker = UploadFileToDocService.spawn(None, None, None, None, self.sna,
                                              None)
        self.assertGreater(datetime.datetime.now().isoformat(),
                           worker.start_time.isoformat())
        self.assertEqual(worker.upload_to_doc_service_queue, None)
        self.assertEqual(worker.upload_to_tender_queue, None)
        self.assertEqual(worker.process_tracker, None)
        self.assertEqual(worker.doc_service_client, None)
        self.assertEqual(worker.services_not_available, self.sna)
        self.assertEqual(worker.sleep_change_value, None)
        self.assertEqual(worker.delay, 15)
        self.assertEqual(worker.exit, False)
        worker.shutdown()
        self.assertEqual(worker.exit, True)
        del worker

    @requests_mock.Mocker()
    @patch('gevent.sleep')
    def test_successful_upload(self, mrequest, gevent_sleep):
        gevent_sleep.side_effect = custom_sleep
        mrequest.post(self.url, json=self.stat_200(), status_code=200)
        self.upload_to_doc_service_queue.put(self.data)
        self.assertItemsEqual(self.process_tracker.processing_items.keys(),
                              [item_key(self.tender_id, self.award_id)])
        self.assertEqual(self.upload_to_doc_service_queue.qsize(), 1)
        self.shutdown_when_done(self.worker)
        self.assertEqual(self.upload_to_doc_service_queue.qsize(), 0,
                         'Queue should be empty')
        self.assertEqual(self.upload_to_tender_queue.qsize(), 1,
                         'Queue should be have 1 element')
        self.assertEqual(mrequest.call_count, 1)
        self.assertEqual(mrequest.request_history[0].url,
                         u'127.0.0.1:80/upload')
        self.assertIsNotNone(
            mrequest.request_history[0].headers['X-Client-Request-ID'])
        self.assertItemsEqual(self.process_tracker.processing_items.keys(),
                              [item_key(self.tender_id, self.award_id)])

    @requests_mock.Mocker()
    @patch('gevent.sleep')
    def test_retry_doc_service(self, mrequest, gevent_sleep):
        gevent_sleep.side_effect = custom_sleep
        doc_service_client = DocServiceClient(host='127.0.0.1',
                                              port='80',
                                              user='',
                                              password='')
        mrequest.post(self.url, [{
            'text': '',
            'status_code': 401
        } for _ in range(6)] + [{
            'json': {
                'data': {
                    'url': 'test url',
                    'format': 'application/yaml',
                    'hash': 'md5:9a0364b9e99bb480dd25e1f0284c8555',
                    'title': file_name
                }
            },
            'status_code': 200
        }])
        self.upload_to_doc_service_queue.put(self.data)
        self.assertItemsEqual(self.process_tracker.processing_items.keys(),
                              [item_key(self.tender_id, self.award_id)])
        self.assertEqual(self.upload_to_doc_service_queue.qsize(), 1)
        self.shutdown_when_done(self.worker)
        self.assertEqual(self.upload_to_doc_service_queue.qsize(), 0,
                         'Queue should be empty')
        self.assertEqual(self.upload_to_tender_queue.qsize(), 1,
                         'Queue should be have 1 element')
        self.assertEqual(mrequest.call_count, 7)
        self.assertEqual(mrequest.request_history[0].url,
                         u'127.0.0.1:80/upload')
        self.assertIsNotNone(
            mrequest.request_history[0].headers['X-Client-Request-ID'])

    @requests_mock.Mocker()
    @patch('gevent.sleep')
    def test_request_failed(self, mrequest, gevent_sleep):
        gevent_sleep.side_effect = custom_sleep
        mrequest.post(self.url, json=self.stat_200(), status_code=200)
        self.upload_to_doc_service_queue.put(self.data)
        self.shutdown_when_done(self.worker)
        self.assertEqual(self.upload_to_doc_service_queue.qsize(), 0,
                         'Queue should be empty')
        self.assertEqual(self.upload_to_tender_queue.get(), self.tender_data)
        self.assertEqual(self.process_tracker.processing_items,
                         {item_key(self.tender_id, self.award_id): 1})
        self.assertEqual(mrequest.call_count, 1)
        self.assertEqual(mrequest.request_history[0].url,
                         u'127.0.0.1:80/upload')
        self.assertIsNotNone(
            mrequest.request_history[0].headers['X-Client-Request-ID'])

    @requests_mock.Mocker()
    @patch('gevent.sleep')
    def test_request_failed_item_status_change(self, mrequest, gevent_sleep):
        gevent_sleep.side_effect = custom_sleep
        mrequest.post(self.url, json=self.stat_200(), status_code=200)
        self.process_tracker.set_item(self.tender_id, self.qualification_id, 1)
        self.upload_to_doc_service_queue.put(self.data)
        self.shutdown_when_done(self.worker)
        self.assertEqual(self.upload_to_doc_service_queue.qsize(), 0,
                         'Queue should be empty')
        self.assertEqual(self.upload_to_tender_queue.get(), self.tender_data)
        self.assertEqual(mrequest.call_count, 1)
        self.assertEqual(mrequest.request_history[0].url,
                         u'127.0.0.1:80/upload')
        self.assertIsNotNone(
            mrequest.request_history[0].headers['X-Client-Request-ID'])
        self.assertEqual(
            self.process_tracker.processing_items, {
                item_key(self.tender_id, self.award_id): 1,
                item_key(self.tender_id, self.qualification_id): 1
            })

    @requests_mock.Mocker()
    @patch('gevent.sleep')
    def test_processing_items(self, mrequest, gevent_sleep):
        gevent_sleep.side_effect = custom_sleep
        mrequest.post(self.url, [{
            'json': self.stat_200(),
            'status_code': 200
        } for _ in range(2)])
        self.process_tracker.set_item(self.tender_id, self.award_id, 2)
        self.upload_to_doc_service_queue.put(self.data)
        self.upload_to_doc_service_queue.put(self.data)
        self.shutdown_when_done(self.worker)
        self.assertEqual(self.upload_to_tender_queue.get(), self.tender_data)
        self.assertEqual(self.upload_to_tender_queue.get(), self.tender_data)
        self.assertEqual(self.upload_to_tender_queue.qsize(), 0)
        self.assertEqual(mrequest.request_history[0].url,
                         u'127.0.0.1:80/upload')
        self.assertIsNotNone(
            mrequest.request_history[0].headers['X-Client-Request-ID'])

    @requests_mock.Mocker()
    @patch('gevent.sleep')
    def test_processing_items_several_tenders(self, mrequest, gevent_sleep):
        gevent_sleep.side_effect = custom_sleep
        mrequest.post(self.url, [{
            'json': self.stat_200(),
            'status_code': 200
        } for _ in range(2)])
        self.process_tracker.set_item(self.tender_id, self.award_id, 2)
        data = ({
            'meta': {
                'id': self.document_id
            },
            'test_data': 'test_data'
        }, [self.tender_data, self.tender_data, self.tender_data])
        self.upload_to_doc_service_queue.put(data)
        self.shutdown_when_done(self.worker)
        self.assertEqual(self.upload_to_tender_queue.get(), self.tender_data)
        self.assertEqual(self.upload_to_tender_queue.get(), self.tender_data)
        self.assertEqual(self.upload_to_tender_queue.get(), self.tender_data)
        self.assertEqual(self.upload_to_tender_queue.qsize(), 0)
        self.assertEqual(mrequest.request_history[0].url,
                         u'127.0.0.1:80/upload')
        self.assertIsNotNone(
            mrequest.request_history[0].headers['X-Client-Request-ID'])

    @requests_mock.Mocker()
    @patch('gevent.sleep')
    def test_upload_to_doc_service_queue_loop_exit(self, mrequest,
                                                   gevent_sleep):
        """ Test LoopExit for upload_to_doc_service_queue """
        gevent_sleep.side_effect = custom_sleep
        self.process_tracker.set_item(self.tender_id, self.award_id, 2)
        self.worker.upload_to_doc_service_queue = MagicMock()
        self.worker.upload_to_doc_service_queue.peek.side_effect = generate_answers(
            answers=[LoopExit(), self.data, self.data], default=LoopExit())
        mrequest.post(self.url, [{
            'json': self.stat_200(),
            'status_code': 200
        } for _ in range(2)])
        self.worker.start()
        sleep(1)
        self.assertEqual(self.upload_to_tender_queue.get(), self.tender_data)
        self.assertEqual(self.upload_to_tender_queue.get(), self.tender_data)
        self.assertIsNotNone(
            mrequest.request_history[0].headers['X-Client-Request-ID'])
        self.assertIsNotNone(
            mrequest.request_history[1].headers['X-Client-Request-ID'])
        self.assertEqual(self.process_tracker.processing_items,
                         {item_key(self.tender_id, self.award_id): 2})

    @requests_mock.Mocker()
    @patch('gevent.sleep')
    def test_retry_upload_to_doc_service_queue_loop_exit(
            self, mrequest, gevent_sleep):
        """ Test LoopExit for retry_upload_to_doc_service_queue """
        gevent_sleep.side_effect = custom_sleep
        mrequest.post(self.url, [{
            'json': self.stat_200(),
            'status_code': 200
        } for _ in range(2)])
        self.process_tracker.set_item(self.tender_id, self.award_id, 2)
        self.worker.retry_upload_to_doc_service_queue = MagicMock()
        self.worker.retry_upload_to_doc_service_queue.peek.side_effect = generate_answers(
            answers=[LoopExit(), self.data, self.data], default=LoopExit())
        self.worker.start()
        sleep(1)
        self.worker.shutdown()
        self.assertEqual(self.upload_to_tender_queue.get(), self.tender_data)
        self.assertEqual(self.upload_to_tender_queue.get(), self.tender_data)
        self.assertEqual(self.process_tracker.processing_items,
                         {item_key(self.tender_id, self.award_id): 2})
        self.assertEqual(mrequest.request_history[0].url,
                         u'127.0.0.1:80/upload')
        self.assertIsNotNone(
            mrequest.request_history[0].headers['X-Client-Request-ID'])

    def test_remove_bad_data(self):
        self.worker.upload_to_doc_service_queue = MagicMock(get=MagicMock())
        self.worker.process_tracker = MagicMock(
            update_items_and_tender=MagicMock())

        self.worker.remove_bad_data(self.data, Exception("test message"),
                                    False)

        self.worker.upload_to_doc_service_queue.get.assert_called_once()
        self.assertEqual(self.worker.retry_upload_to_doc_service_queue.get(),
                         self.data)

    def test_remove_bad_data_retry(self):
        self.worker.retry_upload_to_doc_service_queue = MagicMock(
            get=MagicMock())
        self.worker.process_tracker = MagicMock(
            update_items_and_tender=MagicMock())

        with self.assertRaises(Exception):
            self.worker.remove_bad_data(self.data, Exception("test message"),
                                        True)

        self.worker.retry_upload_to_doc_service_queue.get.assert_called_once()
        self.worker.process_tracker.update_items_and_tender.assert_called_with(
            self.tender_data.tender_id, self.tender_data.award_id,
            self.document_id)

    def test_try_upload_to_doc_service(self):
        e = Exception("test error")
        self.worker.update_headers_and_upload = MagicMock(side_effect=e)
        self.worker.remove_bad_data = MagicMock()

        self.worker.try_upload_to_doc_service(self.data, False)

        self.worker.update_headers_and_upload.assert_called_once()
        self.worker.remove_bad_data.assert_called_once_with(
            self.data, e, False)

    def test_try_upload_to_doc_service_retry(self):
        e = Exception("test error")
        self.worker.update_headers_and_upload = MagicMock(side_effect=e)
        self.worker.remove_bad_data = MagicMock()

        self.worker.try_upload_to_doc_service(self.data, True)

        self.worker.update_headers_and_upload.assert_called_once()
        self.worker.remove_bad_data.assert_called_with(self.data, e, True)

    def test_run(self):
        self.worker.delay = 1
        upload_worker, retry_upload_worker = MagicMock(), MagicMock()
        self.worker.upload_worker = upload_worker
        self.worker.retry_upload_worker = retry_upload_worker
        with patch.object(self.worker, 'exit', AlmostAlwaysFalse()):
            self.worker._run()
        self.assertEqual(self.worker.upload_worker.call_count, 1)
        self.assertEqual(self.worker.retry_upload_worker.call_count, 1)

    @patch('gevent.killall')
    def test_run_exception(self, killlall):
        self.worker.delay = 1
        self.worker._start_jobs = MagicMock(return_value={"a": 1})
        self.worker.check_and_revive_jobs = MagicMock(
            side_effect=Exception("test error"))
        self.worker._run()
        killlall.assert_called_once_with([1], timeout=5)

    @patch('gevent.killall')
    @patch('gevent.sleep')
    def test_run_exception(self, gevent_sleep, killlall):
        gevent_sleep.side_effect = custom_sleep
        self.worker._start_jobs = MagicMock(return_value={"a": 1})
        self.worker.check_and_revive_jobs = MagicMock(
            side_effect=Exception("test error"))

        self.worker._run()

        killlall.assert_called_once_with([1], timeout=5)