Exemple #1
0
 async def async_test_transition_to_hosts_uploaded_no_candidates(self):
     """Test the transition to hosts being uploaded."""
     self.report_record.ready_to_archive = True
     self.report_record.save()
     faulty_report = ReportSlice(
         account='987',
         report_platform_id=str(self.uuid2),
         report_slice_id=str(self.uuid),
         state=ReportSlice.NEW,
         report_json=json.dumps(self.report_json),
         state_info=json.dumps([ReportSlice.PENDING, ReportSlice.NEW]),
         last_update_time=datetime.now(pytz.utc),
         candidate_hosts=json.dumps({}),
         failed_hosts=json.dumps([]),
         hosts_count=10,
         retry_count=0)
     faulty_report.save()
     self.processor.report_or_slice = faulty_report
     self.processor.account_number = '987'
     self.processor.state = faulty_report.state
     self.processor.report_platform_id = self.uuid2
     self.processor.report_json = self.report_json
     self.processor.candidate_hosts = {}
     await self.processor.transition_to_hosts_uploaded()
     # assert the processor was reset
     self.check_variables_are_reset()
Exemple #2
0
    def setUp(self):
        """Create test setup."""
        self.payload_url = 'http://insights-upload.com/q/file_to_validate'
        self.uuid = uuid.uuid4()
        self.uuid2 = uuid.uuid4()
        self.uuid3 = uuid.uuid4()
        self.uuid4 = uuid.uuid4()
        self.uuid5 = uuid.uuid4()
        self.uuid6 = uuid.uuid4()
        self.uuid7 = uuid.uuid4()
        self.uuid8 = uuid.uuid4()
        self.fake_record = test_handler.KafkaMsg(msg_handler.QPC_TOPIC, 'http://internet.com')
        self.report_consumer = msg_handler.ReportConsumer()
        self.msg = self.report_consumer.unpack_consumer_record(self.fake_record)
        self.report_json = {
            'request_id': '234332',
            'report_id': 1,
            'report_type': 'insights',
            'report_version': '1.0.0.1b025b8',
            'status': 'completed',
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319',
            'hosts': [{'bios_uuid': 'value'},
                      {'invalid': 'value'}]}
        self.report_record = Report(
            request_id='234332',
            upload_srv_kafka_msg=json.dumps(self.msg),
            account='1234',
            state=Report.NEW,
            state_info=json.dumps([Report.NEW]),
            last_update_time=datetime.now(pytz.utc),
            retry_count=0,
            ready_to_archive=False,
            source='satellite',
            arrival_time=datetime.now(pytz.utc),
            processing_start_time=datetime.now(pytz.utc))
        self.report_record.save()

        self.report_slice = ReportSlice(
            report_platform_id=self.uuid,
            report_slice_id=self.uuid2,
            account='13423',
            report_json=json.dumps(self.report_json),
            state=ReportSlice.NEW,
            state_info=json.dumps([ReportSlice.NEW]),
            retry_count=0,
            last_update_time=datetime.now(pytz.utc),
            failed_hosts=[],
            candidate_hosts=[],
            report=self.report_record,
            ready_to_archive=True,
            hosts_count=2,
            source='satellite',
            creation_time=datetime.now(pytz.utc),
            processing_start_time=datetime.now(pytz.utc))
        self.report_slice.save()
        self.report_record.save()
        self.processor = report_slice_processor.ReportSliceProcessor()
        self.processor.report = self.report_slice
    def setUp(self):
        """Create test setup."""
        self.payload_url = 'http://insights-upload.com/q/file_to_validate'
        self.uuid = uuid.uuid4()
        self.uuid2 = uuid.uuid4()
        self.uuid3 = uuid.uuid4()
        self.fake_record = test_handler.KafkaMsg(msg_handler.MKT_TOPIC,
                                                 'http://internet.com')
        self.report_consumer = msg_handler.ReportConsumer()
        self.msg = self.report_consumer.unpack_consumer_record(
            self.fake_record)
        self.report_json = {
            'report_id': 1,
            'report_slice_id': str(self.uuid2),
            'report_type': 'insights',
            'status': 'completed',
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319'
        }
        self.report_record = Report(upload_srv_kafka_msg=json.dumps(self.msg),
                                    account='1234',
                                    state=Report.NEW,
                                    state_info=json.dumps([Report.NEW]),
                                    last_update_time=datetime.now(pytz.utc),
                                    retry_count=0,
                                    ready_to_archive=False,
                                    source=uuid.uuid4(),
                                    arrival_time=datetime.now(pytz.utc),
                                    processing_start_time=datetime.now(
                                        pytz.utc))
        self.report_record.save()

        self.report_slice = ReportSlice(
            report_platform_id=self.uuid,
            report_slice_id=self.uuid2,
            account='13423',
            report_json=json.dumps(self.report_json),
            state=ReportSlice.NEW,
            state_info=json.dumps([ReportSlice.NEW]),
            retry_count=0,
            last_update_time=datetime.now(pytz.utc),
            report=self.report_record,
            ready_to_archive=True,
            creation_time=datetime.now(pytz.utc),
            processing_start_time=datetime.now(pytz.utc))
        self.report_slice.save()

        self.processor = report_processor.ReportProcessor()
        self.processor.report = self.report_record
Exemple #4
0
class ReportSliceProcessorTests(TestCase):
    """Test Cases for the Message processor."""
    def setUp(self):
        """Create test setup."""
        self.payload_url = 'http://insights-upload.com/q/file_to_validate'
        self.uuid = uuid.uuid4()
        self.uuid2 = uuid.uuid4()
        self.uuid3 = uuid.uuid4()
        self.uuid4 = uuid.uuid4()
        self.uuid5 = uuid.uuid4()
        self.uuid6 = uuid.uuid4()
        self.uuid7 = uuid.uuid4()
        self.fake_record = test_handler.KafkaMsg(msg_handler.MKT_TOPIC,
                                                 'http://internet.com')
        self.report_consumer = msg_handler.ReportConsumer()
        self.msg = self.report_consumer.unpack_consumer_record(
            self.fake_record)
        self.report_json = {
            'report_id': 1,
            'report_type': 'insights',
            'status': 'completed',
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319'
        }
        self.report_record = Report(upload_srv_kafka_msg=json.dumps(self.msg),
                                    account='1234',
                                    state=Report.NEW,
                                    state_info=json.dumps([Report.NEW]),
                                    last_update_time=datetime.now(pytz.utc),
                                    retry_count=0,
                                    ready_to_archive=False,
                                    source=uuid.uuid4(),
                                    arrival_time=datetime.now(pytz.utc),
                                    processing_start_time=datetime.now(
                                        pytz.utc))
        self.report_record.save()

        self.report_slice = ReportSlice(
            report_platform_id=self.uuid,
            report_slice_id=self.uuid2,
            account='13423',
            report_json=json.dumps(self.report_json),
            state=ReportSlice.NEW,
            state_info=json.dumps([ReportSlice.NEW]),
            retry_count=0,
            last_update_time=datetime.now(pytz.utc),
            report=self.report_record,
            ready_to_archive=True,
            source=uuid.uuid4(),
            creation_time=datetime.now(pytz.utc),
            processing_start_time=datetime.now(pytz.utc))
        self.report_slice.save()
        self.report_record.save()
        self.processor = report_slice_processor.ReportSliceProcessor()
        self.processor.report = self.report_slice

    def check_variables_are_reset(self):
        """Check that report processor members have been cleared."""
        processor_attributes = [
            self.processor.report_platform_id, self.processor.report,
            self.processor.state, self.processor.account_number,
            self.processor.upload_message, self.processor.status,
            self.processor.report_json
        ]
        for attribute in processor_attributes:
            self.assertEqual(attribute, None)

    def test_assign_report_slice_new(self):
        """Test the assign report slice function with only a new report slice."""
        self.report_slice.state = ReportSlice.NEW
        self.report_slice.save()
        self.processor.report_or_slice = None
        self.processor.assign_object()
        self.assertEqual(self.processor.report_or_slice, self.report_slice)
        queued_slices = REGISTRY.get_sample_value('queued_report_slices')
        self.assertEqual(queued_slices, 1)

    def test_update_slice_state(self):
        """Test updating the slice state."""
        self.report_slice.save()
        report_json = {
            'report_id': 1,
            'report_type': 'deployments',
            'status': 'completed',
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319'
        }
        self.processor.report_or_slice = self.report_slice
        self.processor.next_state = ReportSlice.VALIDATED
        options = {'report_json': report_json}
        self.processor.update_object_state(options=options)
        self.assertEqual(json.loads(self.report_slice.report_json),
                         report_json)

    def test_transition_to_validated_general_exception(self):
        """Test that when a general exception is raised, we don't pass validation."""
        self.report_slice.state = ReportSlice.RETRY_VALIDATION
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice

        def validate_side_effect():
            """Transition the state to downloaded."""
            raise Exception('Test')

        with patch(
                'processor.report_slice_processor.'
                'ReportSliceProcessor._validate_report_details',
                side_effect=validate_side_effect):
            self.processor.transition_to_validated()
            self.assertEqual(self.report_slice.state,
                             ReportSlice.RETRY_VALIDATION)
            self.assertEqual(self.report_slice.retry_count, 1)

    def test_transition_to_validated(self):
        """Test that when a general exception is raised, we don't pass validation."""
        self.report_slice.state = ReportSlice.RETRY_VALIDATION
        report_json = {'report_slice_id': '384794738'}
        self.report_slice.report_json = json.dumps(report_json)
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice
        self.processor.transition_to_validated()
        self.assertEqual(self.report_slice.state, ReportSlice.VALIDATED)
        self.assertEqual(self.report_slice.retry_count, 0)

    def test_transition_to_validated_failed(self):
        """Test report missing slice id."""
        self.report_slice.state = ReportSlice.RETRY_VALIDATION
        report_json = {
            'report_id': 1,
            'status': 'completed',
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319'
        }
        self.report_slice.report_json = json.dumps(report_json)
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice
        self.processor.transition_to_validated()
        self.assertEqual(self.report_slice.state,
                         ReportSlice.FAILED_VALIDATION)
        self.assertEqual(self.report_slice.retry_count, 0)
        self.assertEqual(self.report_slice.ready_to_archive, True)

    def test_determine_retry_limit(self):
        """Test the determine retry method when the retry is at the limit."""
        self.report_slice.state = ReportSlice.VALIDATED
        self.report_slice.retry_count = 4
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice
        self.processor.determine_retry(ReportSlice.FAILED_METRICS_UPLOAD,
                                       ReportSlice.VALIDATED)
        self.assertEqual(self.report_slice.state,
                         ReportSlice.FAILED_METRICS_UPLOAD)

    def test_archive_report_and_slices_in_failed_state(self):
        """Test the archive method in a failed state."""
        self.report_record.ready_to_archive = True
        self.report_record.report_platform_id = str(self.uuid)
        self.report_record.save()
        self.report_slice.ready_to_archive = True
        self.report_slice.report_platform_id = str(self.uuid)
        self.report_slice.report_slice_id = str(self.uuid2)
        self.report_slice.state = ReportSlice.FAILED_METRICS_UPLOAD
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice
        self.processor.report_platform_id = str(self.uuid)

        self.processor.archive_report_and_slices()
        # assert the report doesn't exist
        with self.assertRaises(Report.DoesNotExist):
            Report.objects.get(id=self.report_record.id)
        # assert the report archive does exist
        archived = ReportArchive.objects.get(
            account=self.report_record.account)
        archived_slice = ReportSliceArchive.objects.get(
            report_slice_id=self.report_slice.report_slice_id)
        self.assertEqual(str(archived.report_platform_id), str(self.uuid))
        self.assertEqual(str(archived_slice.report_platform_id),
                         str(self.uuid))
        self.assertIsNotNone(archived_slice.processing_end_time)
        # assert the processor was reset
        self.check_variables_are_reset()

    def test_archive_report_and_slices_in_success_state(self):
        """Test the archive method in a failed state."""
        self.report_record.ready_to_archive = True
        self.report_record.report_platform_id = str(self.uuid)
        self.report_record.save()
        self.report_slice.ready_to_archive = True
        self.report_slice.report_platform_id = str(self.uuid)
        self.report_slice.report_slice_id = str(self.uuid2)
        self.report_slice.state = ReportSlice.METRICS_UPLOADED
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice
        self.processor.report_platform_id = str(self.uuid)

        self.processor.archive_report_and_slices()
        # assert the report doesn't exist
        with self.assertRaises(Report.DoesNotExist):
            Report.objects.get(id=self.report_record.id)
        # assert the report archive does exist
        archived = ReportArchive.objects.get(
            account=self.report_record.account)
        archived_slice = ReportSliceArchive.objects.get(
            report_slice_id=self.report_slice.report_slice_id)
        self.assertEqual(str(archived.report_platform_id), str(self.uuid))
        self.assertEqual(str(archived_slice.report_platform_id),
                         str(self.uuid))
        # assert the processor was reset
        self.check_variables_are_reset()

    def test_archive_report_and_slices_not_ready(self):
        """Test the archive method with slice not ready."""
        self.report_record.ready_to_archive = True
        self.report_record.report_platform_id = str(self.uuid)
        self.report_record.save()
        self.report_slice.ready_to_archive = False
        self.report_slice.report_platform_id = str(self.uuid)
        self.report_slice.report_slice_id = str(self.uuid2)
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice
        self.processor.report_platform_id = str(self.uuid)

        self.processor.archive_report_and_slices()
        # assert the report doesn't exist
        existing = Report.objects.get(id=self.report_record.id)
        # assert the report archive does exist
        with self.assertRaises(ReportArchive.DoesNotExist):
            ReportArchive.objects.get(account=self.report_record.account)
        with self.assertRaises(ReportSliceArchive.DoesNotExist):
            ReportSliceArchive.objects.get(
                report_slice_id=self.report_slice.report_slice_id)
        self.assertEqual(str(existing.report_platform_id), str(self.uuid))
        # assert the processor was reset
        self.check_variables_are_reset()

    def test_get_minio_client_not_configured(self):
        """Test getting minio client when not configured."""
        report_slice_processor.MINIO_ENDPOINT = None
        report_slice_processor.MINIO_ACCESS_KEY = None
        report_slice_processor.MINIO_SECRET_KEY = None
        processor = report_slice_processor.ReportSliceProcessor()
        minio_client = processor.get_minio_client()
        self.assertIsNone(minio_client)

    def test_get_minio_client_configured(self):
        """Test get minio client when configured."""
        report_slice_processor.MINIO_ENDPOINT = 'minio:9001'
        report_slice_processor.MINIO_ACCESS_KEY = 'access'
        report_slice_processor.MINIO_SECRET_KEY = 'secret'
        processor = report_slice_processor.ReportSliceProcessor()
        minio_client = processor.get_minio_client()
        self.assertIsNotNone(minio_client)

        # call again for branch path where already created
        self.assertIsNotNone(processor.get_minio_client())

    def test_upload_to_object_storage_none_client(self):
        """Test error raised when client is not configured."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(
            self.async_test_upload_to_objectstore_none_client)
        event_loop.run_until_complete(coro())
        event_loop.close()

    async def async_test_upload_to_objectstore_none_client(self):
        """Async setup for none client test."""
        report_slice_processor.MINIO_ENDPOINT = None
        report_slice_processor.MINIO_ACCESS_KEY = None
        report_slice_processor.MINIO_SECRET_KEY = None
        with self.assertRaises(
                report_slice_processor.RetryUploadTimeException):
            await self.processor._upload_to_object_storage()

    def test_upload_to_object_storage_no_bucket(self):
        """Test error raised when bucket does not exist."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(
            self.async_test_upload_to_objectstore_no_bucket)
        event_loop.run_until_complete(coro())
        event_loop.close()

    async def async_test_upload_to_objectstore_no_bucket(self):
        """Async setup for no bucket test."""
        mock_minio = Mock()
        mock_minio.bucket_exists.return_value = False
        with patch(
                'processor.report_slice_processor.'
                'ReportSliceProcessor.get_minio_client',
                return_value=mock_minio):
            with self.assertRaises(
                    report_slice_processor.RetryUploadTimeException):
                await self.processor._upload_to_object_storage()

    def test_upload_to_object_storage_upload_error(self):
        """Test error raised an upload error occurs."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(self.async_test_upload_to_objectstore_error)
        event_loop.run_until_complete(coro())
        event_loop.close()

    async def async_test_upload_to_objectstore_error(self):
        """Async setup for upload error test."""
        mock_minio = Mock()
        mock_minio.bucket_exists.return_value = True

        # test KafkaConnectionException
        def raise_error():
            """Raise a general error."""
            raise Exception('Test')

        mock_minio.fput_object.side_effect = raise_error
        with patch(
                'processor.report_slice_processor.'
                'ReportSliceProcessor.get_minio_client',
                return_value=mock_minio):
            with self.assertRaises(Exception):
                await self.processor._upload_to_object_storage()

    def test_upload_to_object_storage_upload_success(self):
        """Test upload success pass."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(self.async_test_upload_to_objectstore)
        event_loop.run_until_complete(coro())
        event_loop.close()

    async def async_test_upload_to_objectstore(self):
        """Async setup for upload error test."""
        mock_minio = Mock()
        mock_minio.bucket_exists.return_value = True
        mock_minio.fput_object.return_value = True
        report_json = {'report_slice_id': '384794738'}
        self.processor.report_or_slice = self.report_slice
        self.processor.report_or_slice.report_json = json.dumps(report_json)
        with patch(
                'processor.report_slice_processor.'
                'ReportSliceProcessor.get_minio_client',
                return_value=mock_minio):
            try:
                await self.processor._upload_to_object_storage()
            except Exception as err:  # pylint: disable=broad-except
                self.fail(f'Unexpected exception {err}')
Exemple #5
0
class ReportSliceProcessorTests(TestCase):
    """Test Cases for the Message processor."""

    def setUp(self):
        """Create test setup."""
        self.payload_url = 'http://insights-upload.com/q/file_to_validate'
        self.uuid = uuid.uuid4()
        self.uuid2 = uuid.uuid4()
        self.uuid3 = uuid.uuid4()
        self.uuid4 = uuid.uuid4()
        self.uuid5 = uuid.uuid4()
        self.uuid6 = uuid.uuid4()
        self.uuid7 = uuid.uuid4()
        self.uuid8 = uuid.uuid4()
        self.fake_record = test_handler.KafkaMsg(msg_handler.QPC_TOPIC, 'http://internet.com')
        self.report_consumer = msg_handler.ReportConsumer()
        self.msg = self.report_consumer.unpack_consumer_record(self.fake_record)
        self.report_json = {
            'request_id': '234332',
            'report_id': 1,
            'report_type': 'insights',
            'report_version': '1.0.0.1b025b8',
            'status': 'completed',
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319',
            'hosts': [{'bios_uuid': 'value'},
                      {'invalid': 'value'}]}
        self.report_record = Report(
            request_id='234332',
            upload_srv_kafka_msg=json.dumps(self.msg),
            account='1234',
            state=Report.NEW,
            state_info=json.dumps([Report.NEW]),
            last_update_time=datetime.now(pytz.utc),
            retry_count=0,
            ready_to_archive=False,
            source='satellite',
            arrival_time=datetime.now(pytz.utc),
            processing_start_time=datetime.now(pytz.utc))
        self.report_record.save()

        self.report_slice = ReportSlice(
            report_platform_id=self.uuid,
            report_slice_id=self.uuid2,
            account='13423',
            report_json=json.dumps(self.report_json),
            state=ReportSlice.NEW,
            state_info=json.dumps([ReportSlice.NEW]),
            retry_count=0,
            last_update_time=datetime.now(pytz.utc),
            failed_hosts=[],
            candidate_hosts=[],
            report=self.report_record,
            ready_to_archive=True,
            hosts_count=2,
            source='satellite',
            creation_time=datetime.now(pytz.utc),
            processing_start_time=datetime.now(pytz.utc))
        self.report_slice.save()
        self.report_record.save()
        self.processor = report_slice_processor.ReportSliceProcessor()
        self.processor.report = self.report_slice

    def check_variables_are_reset(self):
        """Check that report processor members have been cleared."""
        processor_attributes = [self.processor.report_platform_id,
                                self.processor.report,
                                self.processor.state,
                                self.processor.account_number,
                                self.processor.upload_message,
                                self.processor.status,
                                self.processor.report_json,
                                self.processor.candidate_hosts,
                                self.processor.failed_hosts]
        for attribute in processor_attributes:
            self.assertEqual(attribute, None)

    def test_assign_report_slice_new(self):
        """Test the assign report slice function with only a new report slice."""
        self.report_slice.state = ReportSlice.NEW
        self.report_slice.save()
        self.processor.report_or_slice = None
        self.processor.assign_object()
        self.assertEqual(self.processor.report_or_slice, self.report_slice)
        queued_slices = REGISTRY.get_sample_value('queued_report_slices')
        self.assertEqual(queued_slices, 1)

    async def async_test_delegate_state(self):
        """Set up the test for delegate state."""
        self.report_slice.state = ReportSlice.VALIDATED
        self.report_slice.report_platform_id = self.uuid
        self.report_slice.candidate_hosts = json.dumps([
            {str(self.uuid3): {'ip_addresses': 'value', 'name': 'value'},
             'cause': report_slice_processor.FAILED_UPLOAD}])
        self.report_slice.failed_hosts = json.dumps(
            [{str(self.uuid2): {'ip_addresses': 'value', 'name': 'value'},
              'cause': abstract_processor.FAILED_VALIDATION}])
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice

        def upload_side_effect():
            """Transition the state to uploaded."""
            self.processor.state = ReportSlice.HOSTS_UPLOADED
            self.report_slice.state = ReportSlice.HOSTS_UPLOADED
            self.report_slice.save()

        with patch(
                'processor.report_slice_processor.'
                'ReportSliceProcessor.transition_to_hosts_uploaded',
                side_effect=upload_side_effect):
            await self.processor.delegate_state()
            self.check_variables_are_reset()

        # test pending state for delegate
        self.report_slice.state = ReportSlice.PENDING
        self.processor.report_or_slice = self.report_slice
        await self.processor.delegate_state()
        self.check_variables_are_reset()

    def test_run_delegate(self):
        """Test the async function delegate state."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(self.async_test_delegate_state)
        event_loop.run_until_complete(coro())
        event_loop.close()

    def test_update_slice_state(self):
        """Test updating the slice state."""
        self.report_slice.failed_hosts = json.dumps([])
        self.report_slice.save()
        report_json = {
            'request_id': '234332',
            'report_id': 1,
            'report_type': 'deployments',
            'report_version': '1.0.0.1b025b8',
            'status': 'completed',
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319',
            'hosts': {str(self.uuid): {'key': 'value'}}}
        failed_hosts = [{str(self.uuid6): {'etc_machine_id': 'value'}},
                        {str(self.uuid7): {'subscription_manager_id': 'value'}}]
        self.processor.report_or_slice = self.report_slice
        self.processor.next_state = ReportSlice.VALIDATED
        options = {'report_json': report_json,
                   'failed_hosts': failed_hosts}
        self.processor.update_object_state(options=options)
        self.assertEqual(json.loads(self.report_slice.report_json), report_json)
        self.assertEqual(json.loads(self.report_slice.failed_hosts), failed_hosts)

    def test_transition_to_validated_general_exception(self):
        """Test that when a general exception is raised, we don't pass validation."""
        self.report_slice.state = ReportSlice.RETRY_VALIDATION
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice

        def validate_side_effect():
            """Transition the state to downloaded."""
            raise Exception('Test')

        with patch('processor.report_slice_processor.'
                   'ReportSliceProcessor._validate_report_details',
                   side_effect=validate_side_effect):
            self.processor.transition_to_validated()
            self.assertEqual(self.report_slice.state, ReportSlice.RETRY_VALIDATION)
            self.assertEqual(self.report_slice.retry_count, 1)

    def test_transition_to_validated(self):
        """Test that when a general exception is raised, we don't pass validation."""
        self.report_slice.state = ReportSlice.RETRY_VALIDATION
        report_json = {
            'request_id': '234332',
            'report_slice_id': '384794738',
            'hosts': [{'ip_addresses': 'value'}]}
        self.report_slice.report_json = json.dumps(report_json)
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice
        self.processor.transition_to_validated()
        self.assertEqual(self.report_slice.state, ReportSlice.VALIDATED)
        self.assertEqual(self.report_slice.retry_count, 0)

    def test_transition_to_validated_failed(self):
        """Test report missing slice id."""
        self.report_slice.state = ReportSlice.RETRY_VALIDATION
        report_json = {
            'request_id': '234332',
            'report_id': 1,
            'report_type': 'insights',
            'report_version': '1.0.0.1b025b8',
            'status': 'completed',
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319',
            'hosts': {str(self.uuid): {'ip_addresses': 'value'}}}
        self.report_slice.report_json = json.dumps(report_json)
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice
        self.processor.transition_to_validated()
        self.assertEqual(self.report_slice.state, ReportSlice.FAILED_VALIDATION)
        self.assertEqual(self.report_slice.retry_count, 0)
        self.assertEqual(self.report_slice.ready_to_archive, True)

    def test_moved_candidates_to_failed(self):
        """Test that we reset candidates after moving them to failed."""
        candidates = [{self.uuid: {'bios_uuid': 'value', 'name': 'value'}}]
        self.processor.candidate_hosts = candidates
        self.processor.failed_hosts = [
            {self.uuid2: {'bios_uuid': 'value', 'name': 'value'},
             'cause': abstract_processor.FAILED_VALIDATION}]
        self.processor.move_candidates_to_failed()
        self.assertEqual(self.processor.candidate_hosts, [])
        for host in candidates:
            self.assertIn(host, self.processor.failed_hosts)

    def test_determine_retry_limit(self):
        """Test the determine retry method when the retry is at the limit."""
        candidates = [{str(self.uuid3): {'ip_addresses': 'value', 'name': 'value'},
                       'cause': report_slice_processor.FAILED_UPLOAD}]
        self.report_slice.state = ReportSlice.VALIDATED
        self.report_slice.retry_count = 4
        self.report_slice.candidate_hosts = json.dumps(candidates)
        self.report_slice.failed_hosts = json.dumps([])
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice
        self.processor.candidate_hosts = candidates
        self.processor.failed_hosts = []
        self.processor.determine_retry(ReportSlice.FAILED_HOSTS_UPLOAD,
                                       ReportSlice.VALIDATED)
        self.assertEqual(self.report_slice.state, ReportSlice.FAILED_HOSTS_UPLOAD)
        self.assertEqual(json.loads(self.report_slice.candidate_hosts), [])
        for host in candidates:
            self.assertIn(host, json.loads(self.report_slice.failed_hosts))

    async def async_test_transition_to_hosts_uploaded(self):
        """Test the transition to hosts being uploaded."""
        hosts = [{str(self.uuid): {'bios_uuid': str(self.uuid), 'name': 'value',
                                   'system_platform_id': str(self.uuid)}},
                 {str(self.uuid2): {'insights_client_id': 'value', 'name': 'foo',
                                    'system_platform_id': str(self.uuid2)}},
                 {str(self.uuid3): {'ip_addresses': 'value', 'name': 'foo',
                                    'system_platform_id': str(self.uuid3)}},
                 {str(self.uuid4): {'mac_addresses': 'value', 'name': 'foo',
                                    'system_platform_id': str(self.uuid4)}},
                 {str(self.uuid5): {'vm_uuid': 'value', 'name': 'foo',
                                    'system_platform_id': str(self.uuid5)}},
                 {str(self.uuid6): {'etc_machine_id': 'value',
                                    'system_platform_id': str(self.uuid6)}},
                 {str(self.uuid7): {'subscription_manager_id': 'value',
                                    'system_platform_id': str(self.uuid7)}}]
        self.report_slice.failed_hosts = []
        self.report_slice.candidate_hosts = json.dumps(hosts)
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice
        self.processor.candidate_hosts = hosts
        self.processor._upload_to_host_inventory_via_kafka = CoroutineMock(
            return_value=[])
        await self.processor.transition_to_hosts_uploaded()
        self.assertEqual(json.loads(self.report_slice.candidate_hosts), [])
        self.assertEqual(self.report_slice.state, ReportSlice.HOSTS_UPLOADED)

    def test_transition_to_hosts_uploaded(self):
        """Test the async hosts uploaded successful."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(self.async_test_transition_to_hosts_uploaded)
        event_loop.run_until_complete(coro())
        event_loop.close()

    async def async_test_transition_to_hosts_uploaded_kafka_mode(self):
        """Test the transition to hosts being uploaded."""
        hosts = [{str(self.uuid): {'bios_uuid': str(self.uuid), 'name': 'value',
                                   'system_platform_id': str(self.uuid)}},
                 {str(self.uuid2): {'insights_client_id': 'value', 'name': 'foo',
                                    'system_platform_id': str(self.uuid2)}},
                 {str(self.uuid3): {'ip_addresses': 'value', 'name': 'foo',
                                    'system_platform_id': str(self.uuid3)}},
                 {str(self.uuid4): {'mac_addresses': 'value', 'name': 'foo',
                                    'system_platform_id': str(self.uuid4)}},
                 {str(self.uuid5): {'vm_uuid': 'value', 'name': 'foo',
                                    'system_platform_id': str(self.uuid5)}},
                 {str(self.uuid6): {'etc_machine_id': 'value',
                                    'system_platform_id': str(self.uuid6)}},
                 {str(self.uuid7): {'subscription_manager_id': 'value',
                                    'system_platform_id': str(self.uuid7)}}]
        self.report_slice.failed_hosts = []
        self.report_slice.candidate_hosts = json.dumps(hosts)
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice
        self.processor.candidate_hosts = hosts
        self.processor._upload_to_host_inventory_via_kafka = CoroutineMock(
            return_value=[])
        await self.processor.transition_to_hosts_uploaded()
        self.assertEqual(json.loads(self.report_slice.candidate_hosts), [])
        self.assertEqual(self.report_slice.state, ReportSlice.HOSTS_UPLOADED)

    def test_transition_to_hosts_uploaded_kafka_mode(self):
        """Test the async hosts uploaded successful."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(self.async_test_transition_to_hosts_uploaded)
        event_loop.run_until_complete(coro())
        event_loop.close()

    async def async_test_transition_to_hosts_uploaded_no_candidates(self):
        """Test the transition to hosts being uploaded."""
        self.report_record.ready_to_archive = True
        self.report_record.save()
        faulty_report = ReportSlice(
            account='987',
            report_platform_id=str(self.uuid2),
            report_slice_id=str(self.uuid),
            state=ReportSlice.NEW,
            report_json=json.dumps(self.report_json),
            state_info=json.dumps([ReportSlice.PENDING, ReportSlice.NEW]),
            last_update_time=datetime.now(pytz.utc),
            candidate_hosts=json.dumps({}),
            failed_hosts=json.dumps([]),
            hosts_count=10,
            retry_count=0)
        faulty_report.save()
        self.processor.report_or_slice = faulty_report
        self.processor.account_number = '987'
        self.processor.state = faulty_report.state
        self.processor.report_platform_id = self.uuid2
        self.processor.report_json = self.report_json
        self.processor.candidate_hosts = {}
        await self.processor.transition_to_hosts_uploaded()
        # assert the processor was reset
        self.check_variables_are_reset()

    def test_test_transition_to_hosts_uploaded_no_candidates(self):
        """Test the async hosts uploaded no candidates."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(self.async_test_transition_to_hosts_uploaded_no_candidates)
        event_loop.run_until_complete(coro())
        event_loop.close()

    async def async_test_transition_to_hosts_uploaded_exception(self):
        """Test the transition to hosts being uploaded."""
        hosts = {str(self.uuid): {'bios_uuid': str(self.uuid), 'name': 'value'},
                 str(self.uuid2): {'insights_client_id': 'value', 'name': 'foo'},
                 str(self.uuid3): {'ip_addresses': 'value', 'name': 'foo'},
                 str(self.uuid4): {'mac_addresses': 'value', 'name': 'foo'},
                 str(self.uuid5): {'vm_uuid': 'value', 'name': 'foo'},
                 str(self.uuid6): {'etc_machine_id': 'value'},
                 str(self.uuid7): {'subscription_manager_id': 'value'}}
        self.processor.candidate_hosts = hosts
        self.processor.report_or_slice = self.report_slice

        def hosts_upload_side_effect():
            raise Exception('Test')

        with patch(
                'processor.report_slice_processor.'
                'ReportSliceProcessor._upload_to_host_inventory_via_kafka',
                side_effect=hosts_upload_side_effect):
            await self.processor.transition_to_hosts_uploaded()
            self.assertEqual(self.report_slice.state, Report.VALIDATED)
            self.assertEqual(self.report_slice.retry_count, 1)

    def test_test_transition_to_hosts_uploaded_exception(self):
        """Test the async hosts uploaded exception."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(self.async_test_transition_to_hosts_uploaded_exception)
        event_loop.run_until_complete(coro())
        event_loop.close()

    async def async_test_upload_to_host_inventory_via_kafka(self):
        """Test uploading to inventory via kafka."""
        self.processor.report_or_slice = self.report_slice
        hosts = {
            str(self.uuid): {'bios_uuid': str(self.uuid), 'name': 'value'},
            str(self.uuid2): {'insights_client_id': 'value', 'name': 'foo'},
            str(self.uuid3): {'ip_addresses': 'value', 'name': 'foo'},
            str(self.uuid4): {'mac_addresses': 'value', 'name': 'foo'},
            str(self.uuid5): {'vm_uuid': 'value', 'name': 'foo'},
            str(self.uuid6): {'etc_machine_id': 'value'},
            str(self.uuid7): {'subscription_manager_id': 'value'},
            str(self.uuid8): {'system_profile': {'os_release': '7',
                                                 'os_kernel_version': '2.6.32'}
                              }}
        test_producer = AIOKafkaProducer(
            loop=report_slice_processor.SLICE_PROCESSING_LOOP,
            bootstrap_servers=report_slice_processor.INSIGHTS_KAFKA_ADDRESS
        )
        test_producer.start = CoroutineMock()
        test_producer.send = CoroutineMock()
        test_producer.stop = CoroutineMock()
        with patch('processor.report_slice_processor.AIOKafkaProducer',
                   return_value=test_producer):
            with patch('processor.report_slice_processor.asyncio.wait',
                       side_effect=None):
                # all though we are not asserting any results, the test here is
                # that no error was raised
                await self.processor._upload_to_host_inventory_via_kafka(hosts)

    def test_upload_to_host_inventory_via_kafka(self):
        """Test the async hosts uploaded exception."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(self.async_test_upload_to_host_inventory_via_kafka)
        event_loop.run_until_complete(coro())
        event_loop.close()

    async def async_test_upload_to_host_inventory_via_kafka_exception(self):
        """Test uploading to inventory via kafka."""
        self.processor.report_or_slice = self.report_slice
        hosts = {str(self.uuid): {'bios_uuid': str(self.uuid), 'name': 'value'},
                 str(self.uuid2): {'insights_client_id': 'value', 'name': 'foo'},
                 str(self.uuid3): {'ip_addresses': 'value', 'name': 'foo'},
                 str(self.uuid4): {'mac_addresses': 'value', 'name': 'foo'},
                 str(self.uuid5): {'vm_uuid': 'value', 'name': 'foo'},
                 str(self.uuid6): {'etc_machine_id': 'value'},
                 str(self.uuid7): {'subscription_manager_id': 'value'}}
        test_producer = AIOKafkaProducer(
            loop=report_slice_processor.SLICE_PROCESSING_LOOP,
            bootstrap_servers=report_slice_processor.INSIGHTS_KAFKA_ADDRESS
        )

        # test KafkaConnectionException
        def raise_kafka_error():
            """Raise a kafka error."""
            raise KafkaConnectionError('Test')

        test_producer.start = CoroutineMock(side_effect=raise_kafka_error)
        test_producer.send = CoroutineMock()
        test_producer.stop = CoroutineMock()
        with self.assertRaises(msg_handler.KafkaMsgHandlerError):
            with patch('processor.report_slice_processor.AIOKafkaProducer',
                       return_value=test_producer):
                await self.processor._upload_to_host_inventory_via_kafka(hosts)

    def test_upload_to_host_inventory_via_kafka_exception(self):
        """Test the async hosts uploaded exception."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(
            self.async_test_upload_to_host_inventory_via_kafka_exception)
        event_loop.run_until_complete(coro())
        event_loop.close()

    async def async_test_upload_to_host_inventory_via_kafka_send_exception(self):
        """Test uploading to inventory via kafka."""
        self.processor.report_or_slice = self.report_slice
        hosts = {str(self.uuid): {'bios_uuid': str(self.uuid), 'name': 'value'},
                 str(self.uuid2): {'insights_client_id': 'value', 'name': 'foo'},
                 str(self.uuid3): {'ip_addresses': 'value', 'name': 'foo'},
                 str(self.uuid4): {'mac_addresses': 'value', 'name': 'foo'},
                 str(self.uuid5): {'vm_uuid': 'value', 'name': 'foo'},
                 str(self.uuid6): {'etc_machine_id': 'value'},
                 str(self.uuid7): {'subscription_manager_id': 'value'}}
        test_producer = AIOKafkaProducer(
            loop=report_slice_processor.SLICE_PROCESSING_LOOP,
            bootstrap_servers=report_slice_processor.INSIGHTS_KAFKA_ADDRESS
        )

        # test KafkaConnectionException
        def raise_error():
            """Raise a general error."""
            raise Exception('Test')

        test_producer.start = CoroutineMock()
        test_producer.send = CoroutineMock(side_effect=raise_error)
        test_producer.stop = CoroutineMock()
        with self.assertRaises(msg_handler.KafkaMsgHandlerError):
            with patch('processor.report_slice_processor.AIOKafkaProducer',
                       return_value=test_producer):
                await self.processor._upload_to_host_inventory_via_kafka(hosts)

    def test_upload_to_host_inventory_via_kafka_send_exception(self):
        """Test the async hosts uploaded exception."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(
            self.async_test_upload_to_host_inventory_via_kafka_send_exception)
        event_loop.run_until_complete(coro())
        event_loop.close()

    def test_archive_report_and_slices_in_failed_state(self):
        """Test the archive method in a failed state."""
        self.report_record.ready_to_archive = True
        self.report_record.report_platform_id = str(self.uuid)
        self.report_record.save()
        self.report_slice.ready_to_archive = True
        self.report_slice.report_platform_id = str(self.uuid)
        self.report_slice.report_slice_id = str(self.uuid2)
        self.report_slice.state = ReportSlice.FAILED_HOSTS_UPLOAD
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice
        self.processor.report_platform_id = str(self.uuid)

        self.processor.archive_report_and_slices()
        # assert the report doesn't exist
        with self.assertRaises(Report.DoesNotExist):
            Report.objects.get(id=self.report_record.id)
        # assert the report archive does exist
        archived = ReportArchive.objects.get(account=self.report_record.account)
        archived_slice = ReportSliceArchive.objects.get(
            report_slice_id=self.report_slice.report_slice_id)
        self.assertEqual(str(archived.report_platform_id), str(self.uuid))
        self.assertEqual(str(archived_slice.report_platform_id), str(self.uuid))
        self.assertIsNotNone(archived_slice.processing_end_time)
        # assert the processor was reset
        self.check_variables_are_reset()

    def test_archive_report_and_slices_in_success_state(self):
        """Test the archive method in a failed state."""
        self.report_record.ready_to_archive = True
        self.report_record.report_platform_id = str(self.uuid)
        self.report_record.save()
        self.report_slice.ready_to_archive = True
        self.report_slice.report_platform_id = str(self.uuid)
        self.report_slice.report_slice_id = str(self.uuid2)
        self.report_slice.state = ReportSlice.HOSTS_UPLOADED
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice
        self.processor.report_platform_id = str(self.uuid)

        self.processor.archive_report_and_slices()
        # assert the report doesn't exist
        with self.assertRaises(Report.DoesNotExist):
            Report.objects.get(id=self.report_record.id)
        # assert the report archive does exist
        archived = ReportArchive.objects.get(account=self.report_record.account)
        archived_slice = ReportSliceArchive.objects.get(
            report_slice_id=self.report_slice.report_slice_id)
        self.assertEqual(str(archived.report_platform_id), str(self.uuid))
        self.assertEqual(str(archived_slice.report_platform_id), str(self.uuid))
        # assert the processor was reset
        self.check_variables_are_reset()

    def test_archive_report_and_slices_not_ready(self):
        """Test the archive method with slice not ready."""
        self.report_record.ready_to_archive = True
        self.report_record.report_platform_id = str(self.uuid)
        self.report_record.save()
        self.report_slice.ready_to_archive = False
        self.report_slice.report_platform_id = str(self.uuid)
        self.report_slice.report_slice_id = str(self.uuid2)
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice
        self.processor.report_platform_id = str(self.uuid)

        self.processor.archive_report_and_slices()
        # assert the report doesn't exist
        existing = Report.objects.get(id=self.report_record.id)
        # assert the report archive does exist
        with self.assertRaises(ReportArchive.DoesNotExist):
            ReportArchive.objects.get(account=self.report_record.account)
        with self.assertRaises(ReportSliceArchive.DoesNotExist):
            ReportSliceArchive.objects.get(
                report_slice_id=self.report_slice.report_slice_id)
        self.assertEqual(str(existing.report_platform_id), str(self.uuid))
        # assert the processor was reset
        self.check_variables_are_reset()

    def test_get_stale_time(self):
        """Test the get stale time method."""
        self.processor.report_or_slice = self.report_record
        self.processor.report_or_slice.source = 'satellite'
        self.processor.report_or_slice.save()
        current_time = datetime.utcnow()
        stale_time = current_time + timedelta(hours=int(SATELLITE_HOST_TTL))
        expected = stale_time.strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z'
        actual = self.processor.get_stale_time()
        # the format looks like this: 2019-11-14T19:58:13.037Z
        # by cutting off the last 13 i am comparing 2019-11-14T
        # which is the year/month/day
        self.assertEqual(expected[:-13], actual[:-13])

    def test_transform_os_release(self):
        """Test transform host os_release."""
        host = {'system_profile': {
            'os_release': 'Red Hat Enterprise Linux Server 6.10 (Santiago)'
        }}
        host = self.processor._transform_single_host(
            self.report_record.request_id, '123', host
        )
        self.assertEqual(host, {'system_profile': {'operating_system': {
            'major': '6', 'minor': '10', 'name': 'RHEL'}, 'os_release': '6.10'}})

    def test_do_not_transform_when_only_version(self):
        """Test do not transform os_release when only version."""
        host = {'system_profile': {'os_release': '7'}}
        host = self.processor._transform_single_host(
            self.report_record.request_id, '123', host
        )
        self.assertEqual(host, {'system_profile': {'os_release': '7'}})

    def test_remove_os_release_when_no_version(self):
        """Test remove host os_release."""
        host = {
            'system_profile': {
                'os_release': 'Red Hat Enterprise Linux Server'}}
        host = self.processor._transform_single_host(
            self.report_record.request_id, '123', host
        )
        self.assertEqual(host, {'system_profile': {}})

    def test_remove_os_release_when_no_version_with_parentheses(self):
        """Test remove host os_release when include empty parentheses."""
        host = {'system_profile': {'os_release': '  ()'}}
        host = self.processor._transform_single_host(
            self.report_record.request_id, '123', host
        )
        self.assertEqual(host, {'system_profile': {}})

    def test_remove_os_release_when_only_string_in_parentheses(self):
        """Test remove host os_release when only string in parentheses."""
        host = {'system_profile': {'os_release': '  (Core)'}}
        host = self.processor._transform_single_host(
            self.report_record.request_id, '123', host
        )
        self.assertEqual(host, {'system_profile': {}})

    def test_remove_os_release_when_empty_string(self):
        """Test remove host os_release when empty string."""
        host = {'system_profile': {'os_release': ''}}
        host = self.processor._transform_single_host(
            self.report_record.request_id, '123', host
        )
        self.assertEqual(host, {'system_profile': {}})

    def test_transform_os_release_when_non_rhel_os(self):
        """Test transform host os_release when non rhel."""
        host = {'system_profile': {'os_release': 'openSUSE Leap 15.3'}}
        host = self.processor._transform_single_host(
            self.report_record.request_id, '123', host
        )
        self.assertEqual(host, {'system_profile': {'os_release': '15.3'}})

    def test_transform_os_release_when_centos(self):
        """Test transform host os_release when centos."""
        host = {'system_profile': {'os_release': 'CentOS Linux 7 (Core)'}}
        host = self.processor._transform_single_host(
            self.report_record.request_id, '123', host
        )
        self.assertEqual(host, {'system_profile': {'operating_system': {
            'major': '7', 'minor': '0', 'name': 'CentOS'}, 'os_release': '7'}})

    def test_transform_os_fields(self):
        """Test transform os fields."""
        host = {'system_profile': {
            'os_release': '7', 'os_kernel_version': '3.10.0-1127.el7.x86_64'
        }}
        host = self.processor._transform_single_host(
            self.report_record.request_id, '123', host
        )
        self.assertEqual(
            host,
            {'system_profile': {
                'os_release': '7', 'os_kernel_version': '3.10.0'}})

    def test_do_not_tranform_os_fields(self):
        """Test do not transform os fields when already in format."""
        host = {'system_profile': {
            'os_release': '7', 'os_kernel_version': '2.6.32'}}
        host = self.processor._transform_single_host(
            self.report_record.request_id, '123', host
        )
        self.assertEqual(
            host, {'system_profile': {
                'os_release': '7', 'os_kernel_version': '2.6.32'}})

    def test_do_not_tranform_os_release_with_number_field(self):
        """Test do not transform os release when passed as number."""
        host = {'system_profile': {'os_release': 7}}
        host = self.processor._transform_single_host(
            self.report_record.request_id, '123', host
        )
        self.assertEqual(
            host,
            {'system_profile': {'os_release': 7}}
        )

    def test_match_regex_and_find_os_details(self):
        """Test match Regex with os_release and return os_version."""
        host = {'system_profile': {
            'os_release': 'Red Hat Enterprise Linux Server 7'}}
        host_os_version = '7'
        os_version = self.processor._match_regex_and_find_os_details(
            host['system_profile']['os_release'])
        self.assertEqual(host_os_version, os_version['major'])

    def test_remove_display_name(self):
        """Test remove host display_name."""
        host = {'display_name': 'test.example.com'}
        host, _ = self.processor._remove_display_name(host)
        self.assertEqual(host, {})

    def test_remove_empty_ip_addresses(self):
        """Test remove host ip_addresses."""
        host = {
            'ip_addresses': []}
        host, _ = self.processor._remove_empty_ip_addresses(host)
        self.assertEqual(host, {})

    def test_transform_mac_addresses(self):
        """Test transform mac_addresses."""
        host = {
            'mac_addresses': []}
        host, _ = self.processor._transform_mac_addresses(host)
        self.assertEqual(host, {})

    def test_remove_both_empty_ip_mac_addresses(self):
        """Test remove both empty ip and mac addresses."""
        host = {}
        host, _ = self.processor._remove_empty_ip_addresses(host)
        host, _ = self.processor._transform_mac_addresses(host)
        self.assertEqual(host, {})

    def test_do_not_remove_set_ip_addresses(self):
        """Test do not remove set host ip_addresses."""
        host = {
            'ip_addresses': ['192.168.10.10']}
        host, _ = self.processor._remove_empty_ip_addresses(host)
        self.assertEqual(host, {'ip_addresses': ['192.168.10.10']})

    def test_do_not_remove_set_mac_addresses(self):
        """Test do not remove set host mac_addresses."""
        host = {
            'mac_addresses': ['aa:bb:00:11:22:33']}
        host, _ = self.processor._transform_mac_addresses(host)
        self.assertEqual(host, {'mac_addresses': ['aa:bb:00:11:22:33']})

    def test_transform_mtu_to_integer(self):
        """Test mtu transformation for host."""
        host = {
            'system_profile': {
                'network_interfaces': [
                    {'ipv4_addresses': [], 'ipv6_addresses': [],
                     'mtu': 1400, 'name': 'eth0'},
                    {'ipv4_addresses': [], 'ipv6_addresses': [],
                     'mtu': '1500', 'name': 'eth1'}]
            }}
        host = self.processor._transform_single_host(
            self.report_record.request_id, '123', host
        )
        self.assertEqual(
            host,
            {
                'system_profile': {
                    'network_interfaces': [
                        {'ipv4_addresses': [], 'ipv6_addresses': [],
                         'mtu': 1400, 'name': 'eth0'},
                        {'ipv4_addresses': [], 'ipv6_addresses': [],
                         'mtu': 1500, 'name': 'eth1'}]
                }
            })

    def test_do_not_run_mtu_transformation_when_none(self):
        """Test not to run mtu transformation when it is None."""
        host = {
            'system_profile': {
                'network_interfaces': [
                    {'ipv4_addresses': [], 'ipv6_addresses': [],
                     'mtu': None, 'name': 'eth0'}]
            }}

        host = self.processor._transform_single_host(
            self.report_record.request_id, '123', host
        )
        self.assertEqual(
            host,
            {
                'system_profile': {
                    'network_interfaces': [
                        {'ipv4_addresses': [], 'ipv6_addresses': [],
                         'mtu':None, 'name':'eth0'}]
                }
            })

    def test_do_not_run_mtu_transformation_when_not_exists(self):
        """Test not to run mtu transformation when it doesn't exist."""
        host = {
            'system_profile': {
                'network_interfaces': [
                    {'ipv4_addresses': [], 'ipv6_addresses': [],
                     'name': 'eth0'}]
            }}

        host = self.processor._transform_single_host(
            self.report_record.request_id, '123', host
        )
        self.assertEqual(
            host,
            {
                'system_profile': {
                    'network_interfaces': [
                        {'ipv4_addresses': [], 'ipv6_addresses': [],
                         'name':'eth0'}]
                }
            })

    def test_remove_nic_when_empty_string_in_name(self):
        """Test to remove network_interface when name is empty."""
        host = {
            'system_profile': {
                'network_interfaces': [
                    {'ipv4_addresses': [], 'ipv6_addresses': [], 'name': ''},
                    {'ipv4_addresses': [], 'ipv6_addresses': []},
                    {'ipv4_addresses': [],
                     'ipv6_addresses': [], 'name': 'eth0'}
                ]
            }}

        host = self.processor._transform_single_host(
            self.report_record.request_id, '123', host
        )
        self.assertEqual(
            host,
            {
                'system_profile': {
                    'network_interfaces': [
                        {'ipv4_addresses': [], 'ipv6_addresses': [],
                         'name':'eth0'}]
                }
            })

    def test_remove_empty_strings_in_ipv6_addresses(self):
        """Test to verify transformation for 'ipv6 addresses' in host."""
        ipv6_address = '2021:0db8:85a3:0000:0000:8a2e:0370:7335'
        host = {
            'system_profile': {
                'network_interfaces': [
                    {'ipv4_addresses': [],
                     'ipv6_addresses': ['', ipv6_address, ''],
                     'name':'eth0'},
                    {'ipv4_addresses': [],
                     'ipv6_addresses': [''], 'name':'eth1'}]
            }}

        host = self.processor._transform_single_host(
            self.report_record.request_id, '123', host
        )
        self.assertEqual(
            host,
            {
                'system_profile': {
                    'network_interfaces': [
                        {'ipv4_addresses': [],
                         'ipv6_addresses': [ipv6_address],
                         'name':'eth0'},
                        {'ipv4_addresses': [],
                         'ipv6_addresses': [], 'name':'eth1'}]
                }
            })
        nics = host['system_profile']['network_interfaces']
        self.assertEqual(len(nics), 2)
        filtered_nics = [nic for nic in nics if nic.get('name') == 'eth0']
        self.assertTrue(len(filtered_nics))
        self.assertEqual(len(filtered_nics[0]['ipv6_addresses']), 1)

    def test_remove_invalid_bios_uuid(self):
        """Test remove invalid bios UUID."""
        host = {
            'fqdn': 'virt-who.example.com',
            'bios_uuid': '45AA7104-5CB0-4A75-945D-7173C8DC5744443'
        }
        host, _ = self.processor._remove_invalid_bios_uuid(host)
        self.assertEqual(host, {'fqdn': 'virt-who.example.com'})

    def test_remove_invalid_bios_uuid_of_boolean_type(self):
        """Test remove invalid bios UUID of boolean type."""
        host = {
            'fqdn': 'virt-who.example.com',
            'bios_uuid': True
        }
        host, _ = self.processor._remove_invalid_bios_uuid(host)
        self.assertEqual(host, {'fqdn': 'virt-who.example.com'})

    def test_remove_invalid_bios_uuid_of_number_type(self):
        """Test remove invalid bios UUID of number type."""
        host = {
            'fqdn': 'virt-who.example.com',
            'bios_uuid': 100
        }
        host, _ = self.processor._remove_invalid_bios_uuid(host)
        self.assertEqual(host, {'fqdn': 'virt-who.example.com'})

    def test_remove_empty_bios_uuid(self):
        """Test remove empty bios UUID field."""
        host = {
            'fqdn': 'virt-who.example.com',
            'bios_uuid': ''
        }
        host, _ = self.processor._remove_invalid_bios_uuid(host)
        self.assertEqual(host, {'fqdn': 'virt-who.example.com'})

    def test_do_not_remove_valid_bios_uuid(self):
        """Test do not remove valid bios UUID."""
        host = {
            'fqdn': 'virt-who.example.com',
            'bios_uuid': '123e4567-e89b-12d3-a456-426614174000'
        }
        new_host, _ = self.processor._remove_invalid_bios_uuid(host)
        self.assertEqual(new_host, host)

    def test_bios_uuid_validation_should_be_case_insensitive(self):
        """Test bios UUID validation should be case insensitive."""
        host = {
            'fqdn': 'virt-who.example.com',
            'bios_uuid': '801CA199-9402-41CE-98DC-F3AA6E5BC6B3'
        }
        new_host, _ = self.processor._remove_invalid_bios_uuid(host)
        self.assertEqual(new_host, host)

    def test_transform_tags_value_to_string(self):
        """Test tags transformation for host."""
        host = {'tags': [
            {
                'namespace': 'satellite_parameter',
                'key': 'host_registration_insights',
                'value': True
            },
            {
                'namespace': 'satellite_parameter',
                'key': 'host_registration_remote_execution',
                'value': False
            },
            {
                'namespace': 'satellite',
                'key': 'organization_id',
                'value': 1
            }
        ]}
        host = self.processor._transform_single_host(
            self.report_record.request_id, '123', host
        )
        self.assertEqual(
            host,
            {'tags': [
                {
                    'namespace': 'satellite_parameter',
                    'key': 'host_registration_insights',
                    'value': 'true'
                },
                {
                    'namespace': 'satellite_parameter',
                    'key': 'host_registration_remote_execution',
                    'value': 'false'
                },
                {
                    'namespace': 'satellite',
                    'key': 'organization_id',
                    'value': '1'
                }
            ]}
        )

    def test_remove_installed_packages(self):
        """Test remove installed_packages when message size exceeds."""
        host = {
            'system_profile': {
                'installed_packages': [
                    'pkg1', 'pkg2', 'pkg3'
                ]
            }
        }
        host_request_size = bytes(json.dumps(host), 'utf-8')
        if len(host_request_size) >= KAFKA_PRODUCER_OVERRIDE_MAX_REQUEST_SIZE:
            host, _ = self.processor._remove_installed_packages(host)
            self.assertEqual(
                host,
                {
                    'system_profile': {}
                }
            )
        else:
            self.assertEqual(
                host,
                {
                    'system_profile': {
                        'installed_packages': ['pkg1', 'pkg2', 'pkg3']
                    }
                }
            )
class ReportProcessorTests(TransactionTestCase):
    """Test Cases for the Message processor."""
    def setUp(self):
        """Create test setup."""
        self.payload_url = 'http://insights-upload.com/q/file_to_validate'
        self.uuid = uuid.uuid4()
        self.uuid2 = uuid.uuid4()
        self.uuid3 = uuid.uuid4()
        self.fake_record = test_handler.KafkaMsg(msg_handler.MKT_TOPIC,
                                                 'http://internet.com')
        self.report_consumer = msg_handler.ReportConsumer()
        self.msg = self.report_consumer.unpack_consumer_record(
            self.fake_record)
        self.report_json = {
            'report_id': 1,
            'report_slice_id': str(self.uuid2),
            'report_type': 'insights',
            'status': 'completed',
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319'
        }
        self.report_record = Report(upload_srv_kafka_msg=json.dumps(self.msg),
                                    account='1234',
                                    state=Report.NEW,
                                    state_info=json.dumps([Report.NEW]),
                                    last_update_time=datetime.now(pytz.utc),
                                    retry_count=0,
                                    ready_to_archive=False,
                                    source=uuid.uuid4(),
                                    arrival_time=datetime.now(pytz.utc),
                                    processing_start_time=datetime.now(
                                        pytz.utc))
        self.report_record.save()

        self.report_slice = ReportSlice(
            report_platform_id=self.uuid,
            report_slice_id=self.uuid2,
            account='13423',
            report_json=json.dumps(self.report_json),
            state=ReportSlice.NEW,
            state_info=json.dumps([ReportSlice.NEW]),
            retry_count=0,
            last_update_time=datetime.now(pytz.utc),
            report=self.report_record,
            ready_to_archive=True,
            creation_time=datetime.now(pytz.utc),
            processing_start_time=datetime.now(pytz.utc))
        self.report_slice.save()

        self.processor = report_processor.ReportProcessor()
        self.processor.report = self.report_record

    def check_variables_are_reset(self):
        """Check that report processor members have been cleared."""
        processor_attributes = [
            self.processor.report_platform_id, self.processor.report,
            self.processor.state, self.processor.account_number,
            self.processor.upload_message, self.processor.status,
            self.processor.report_json
        ]
        for attribute in processor_attributes:
            self.assertEqual(attribute, None)

    def test_archiving_report(self):
        """Test archiving creates archive, deletes current rep, and resets processor."""
        report_to_archive = Report(upload_srv_kafka_msg=json.dumps(self.msg),
                                   account='4321',
                                   report_platform_id=self.uuid2,
                                   state=Report.NEW,
                                   state_info=json.dumps([Report.NEW]),
                                   last_update_time=datetime.now(pytz.utc),
                                   retry_count=0,
                                   ready_to_archive=True,
                                   arrival_time=datetime.now(pytz.utc),
                                   processing_start_time=datetime.now(
                                       pytz.utc))
        report_to_archive.save()
        self.processor.report_or_slice = report_to_archive
        self.processor.account_number = '4321'
        self.processor.upload_message = self.msg
        self.processor.state = report_to_archive.state
        self.processor.report_platform_id = self.uuid
        self.processor.status = report_processor.SUCCESS_CONFIRM_STATUS

        self.processor.archive_report_and_slices()
        # assert the report doesn't exist
        with self.assertRaises(Report.DoesNotExist):
            Report.objects.get(id=report_to_archive.id)
        # assert the report archive does exist
        archived = ReportArchive.objects.get(account='4321')
        self.assertEqual(json.loads(archived.state_info), [Report.NEW])
        self.assertIsNotNone(archived.processing_end_time)
        # assert the processor was reset
        self.check_variables_are_reset()

    def test_archiving_report_not_ready(self):
        """Test that archiving fails if report not ready to archive."""
        report_to_archive = Report(upload_srv_kafka_msg=json.dumps(self.msg),
                                   account='4321',
                                   report_platform_id=self.uuid2,
                                   state=Report.NEW,
                                   state_info=json.dumps([Report.NEW]),
                                   last_update_time=datetime.now(pytz.utc),
                                   retry_count=0,
                                   ready_to_archive=False)
        report_to_archive.save()
        self.processor.report_or_slice = report_to_archive
        self.processor.account_number = '4321'
        self.processor.upload_message = self.msg
        self.processor.state = report_to_archive.state
        self.processor.report_platform_id = self.uuid
        self.processor.status = report_processor.SUCCESS_CONFIRM_STATUS

        self.processor.archive_report_and_slices()
        # assert the report still exist
        existing_report = Report.objects.get(id=report_to_archive.id)
        self.assertEqual(existing_report, report_to_archive)
        # assert the report archive does not exist
        with self.assertRaises(ReportArchive.DoesNotExist):
            ReportArchive.objects.get(account='4321')
        # assert the processor was reset
        self.check_variables_are_reset()

    def test_deduplicating_report(self):
        """Test that archiving creates archive rep, deletes report, and resets the processor."""
        self.report_record.report_platform_id = self.uuid
        self.report_record.save()
        report_to_dedup = Report(upload_srv_kafka_msg=json.dumps(self.msg),
                                 account='4321',
                                 report_platform_id=self.uuid,
                                 state=Report.NEW,
                                 upload_ack_status='success',
                                 state_info=json.dumps([Report.NEW]),
                                 last_update_time=datetime.now(pytz.utc),
                                 retry_count=0,
                                 ready_to_archive=True,
                                 arrival_time=datetime.now(pytz.utc),
                                 processing_start_time=datetime.now(pytz.utc))
        report_to_dedup.save()
        self.processor.report_or_slice = report_to_dedup
        self.processor.account_number = '4321'
        self.processor.upload_message = self.msg
        self.processor.state = report_to_dedup.state
        self.processor.report_platform_id = self.uuid
        self.processor.status = report_processor.SUCCESS_CONFIRM_STATUS

        self.processor.deduplicate_reports()
        # assert the report doesn't exist
        with self.assertRaises(Report.DoesNotExist):
            Report.objects.get(id=report_to_dedup.id)
        # assert the report archive does exist
        archived = ReportArchive.objects.get(account='4321')
        self.assertEqual(json.loads(archived.state_info), [Report.NEW])
        # assert the processor was reset
        self.check_variables_are_reset()

    def test_determine_retry_limit(self):
        """Test the determine retry method when the retry is at the limit."""
        self.report_record.state = Report.STARTED
        self.report_record.retry_count = 4
        self.report_record.save()
        self.processor.report_or_slice = self.report_record
        self.processor.determine_retry(Report.FAILED_DOWNLOAD, Report.STARTED)
        self.assertEqual(self.report_record.state, Report.FAILED_DOWNLOAD)
        self.assertEqual(self.report_record.ready_to_archive, True)

    def test_update_report_state(self):
        """Test updating the report state."""
        # set the base line values
        self.report_record.retry_count = 0
        self.report_record.save()
        self.processor.next_state = Report.STARTED
        # set the values we will update with
        self.processor.report_or_slice = self.report_record
        options = {
            'retry': abstract_processor.RETRY.increment,
            'retry_type': Report.GIT_COMMIT,
            'report_platform_id': self.uuid3
        }
        self.processor.update_object_state(options=options)
        self.assertEqual(self.report_record.retry_count, 1)
        self.assertEqual(self.report_record.retry_type, Report.GIT_COMMIT)
        self.assertEqual(self.report_record.report_platform_id, self.uuid3)

    async def async_test_run_method(self):
        """Test the run method."""
        self.report_record.state = Report.NEW
        self.report_record.save()
        self.processor.report_or_slice = None
        self.processor.should_run = True

        def transition_side_effect():
            self.processor.should_run = False

        with patch(
                'processor.abstract_processor.'
                'AbstractProcessor.transition_to_started',
                side_effect=transition_side_effect):
            await self.processor.run()
            self.assertEqual(self.processor.report_or_slice,
                             self.report_record)

    def test_run_method(self):
        """Test the async run function."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(self.async_test_run_method)
        event_loop.run_until_complete(coro())
        event_loop.close()

    def test_assign_report_new(self):
        """Test the assign report function with only a new report."""
        self.report_record.state = Report.NEW
        self.report_record.save()
        self.processor.report = None
        self.processor.assign_object()
        self.assertEqual(self.processor.report_or_slice, self.report_record)

    def test_assign_report_oldest_time(self):
        """Test the assign report function with older report."""
        current_time = datetime.now(pytz.utc)
        hours_old_time = current_time - timedelta(hours=9)
        older_report = Report(upload_srv_kafka_msg=json.dumps(self.msg),
                              account='4321',
                              report_platform_id=self.uuid2,
                              state=Report.NEW,
                              state_info=json.dumps([Report.NEW]),
                              last_update_time=hours_old_time,
                              retry_count=1)
        older_report.save()
        self.report_record.state = Report.NEW
        self.report_record.save()
        self.processor.report_or_slice = None
        self.processor.assign_object()
        self.assertEqual(self.processor.report_or_slice, older_report)
        # delete the older report object
        Report.objects.get(id=older_report.id).delete()

    def test_assign_report_not_old_enough(self):
        """Test the assign report function with young report."""
        # delete the report record
        Report.objects.get(id=self.report_record.id).delete()
        self.processor.report_or_slice = None
        current_time = datetime.now(pytz.utc)
        min_old_time = current_time - timedelta(minutes=1)
        older_report = Report(upload_srv_kafka_msg=json.dumps(self.msg),
                              account='4321',
                              report_platform_id=self.uuid2,
                              state=Report.STARTED,
                              state_info=json.dumps([Report.NEW]),
                              last_update_time=min_old_time,
                              retry_count=1)
        older_report.save()
        self.processor.assign_object()
        self.assertEqual(self.processor.report_or_slice, None)
        # delete the older report object
        Report.objects.get(id=older_report.id).delete()

    def test_assign_report_oldest_commit(self):
        """Test the assign report function with retry type as commit."""
        current_time = datetime.now(pytz.utc)
        twentyminold_time = current_time - timedelta(minutes=20)
        older_report = Report(upload_srv_kafka_msg=json.dumps(self.msg),
                              account='4321',
                              report_platform_id=self.uuid2,
                              state=Report.DOWNLOADED,
                              state_info=json.dumps(
                                  [Report.NEW, Report.DOWNLOADED]),
                              last_update_time=twentyminold_time,
                              retry_count=1,
                              retry_type=Report.GIT_COMMIT,
                              git_commit='1234')
        older_report.save()
        self.report_record.state = Report.DOWNLOADED
        self.report_record.save()
        self.processor.report_or_slice = None
        # the commit should always be different from 1234
        self.processor.assign_object()
        self.assertEqual(self.processor.report_or_slice, older_report)
        self.assertEqual(self.processor.report_or_slice.state,
                         Report.DOWNLOADED)
        # delete the older report object
        Report.objects.get(id=older_report.id).delete()

    def test_assign_report_no_reports(self):
        """Test the assign report method with no reports."""
        # delete the report record
        Report.objects.get(id=self.report_record.id).delete()
        self.processor.report_or_slice = None
        self.processor.assign_object()
        self.assertEqual(self.processor.report_or_slice, None)

    async def async_test_delegate_state(self):
        """Set up the test for delegate state."""
        self.report_record.state = Report.STARTED
        self.report_record.report_platform_id = self.uuid
        self.report_record.upload_ack_status = report_processor.SUCCESS_CONFIRM_STATUS
        self.report_record.save()
        self.processor.report_or_slice = self.report_record

        def download_side_effect():
            """Transition the state to downloaded."""
            self.processor.state = Report.DOWNLOADED
            self.report_record.state = Report.DOWNLOADED
            self.report_record.save()

        with patch(
                'processor.report_processor.'
                'ReportProcessor.transition_to_downloaded',
                side_effect=download_side_effect):
            await self.processor.delegate_state()
            self.assertEqual(self.processor.report_platform_id,
                             self.report_record.report_platform_id)
            # self.assertEqual(self.processor.report_or_slice.state, Report.DOWNLOADED)
            self.assertEqual(self.processor.status,
                             self.processor.report.upload_ack_status)

        # test the async function call state
        self.report_record.state = Report.VALIDATED
        self.report_record.save()

        def validation_reported_side_effect():
            """Side effect for async transition method."""
            self.report_record.state = Report.VALIDATION_REPORTED
            self.report_record.save()

        self.processor.transition_to_validation_reported = CoroutineMock(
            side_effect=validation_reported_side_effect)
        await self.processor.delegate_state()

    def test_run_delegate(self):
        """Test the async function delegate state."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(self.async_test_delegate_state)
        event_loop.run_until_complete(coro())
        event_loop.close()

    async def async_test_delegate_state_exception(self):
        """Set up the test for delegate state with exception."""
        self.report_record.state = Report.STARTED
        self.report_record.report_platform_id = self.uuid
        self.report_record.upload_ack_status = report_processor.SUCCESS_CONFIRM_STATUS
        self.report_record.save()
        self.processor.report_or_slice = self.report_record

        def delegate_side_effect():
            """Transition the state to downloaded."""
            self.processor.should_run = False
            raise Exception('Test')

        with patch('processor.report_processor.ReportProcessor.delegate_state',
                   side_effect=delegate_side_effect):
            await self.processor.run()
            self.check_variables_are_reset()

    def test_run_delegate_exception(self):
        """Test the async function delegate state."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(self.async_test_delegate_state_exception)
        event_loop.run_until_complete(coro())
        event_loop.close()

    def test_reinit_variables(self):
        """Test that reinitting the variables clears the values."""
        # make sure that the variables have values
        self.processor.report_platform_id = self.uuid
        self.processor.report_or_slice = self.report_record
        self.processor.state = Report.NEW
        self.processor.account_number = '1234'
        self.processor.upload_message = self.msg
        self.processor.report_json = {}
        self.processor.status = report_processor.SUCCESS_CONFIRM_STATUS
        self.assertEqual(self.processor.report_or_slice, self.report_record)
        self.assertEqual(self.processor.report_platform_id, self.uuid)
        self.assertEqual(self.processor.state, Report.NEW)
        self.assertEqual(self.processor.account_number, '1234')
        self.assertEqual(self.processor.upload_message, self.msg)
        self.assertEqual(self.processor.status,
                         report_processor.SUCCESS_CONFIRM_STATUS)

        # check all of the variables are None after reinitting
        self.processor.reset_variables()
        self.check_variables_are_reset()

    def test_transition_to_started(self):
        """Test the transition to started state."""
        self.report_record.state = Report.NEW
        self.processor.report_or_slice = self.report_record
        self.processor.transition_to_started()
        self.assertEqual(self.report_record.state, Report.STARTED)
        self.assertEqual(json.loads(self.report_record.state_info),
                         [Report.NEW, Report.STARTED])

    def test_transition_to_downloaded(self):
        """Test that the transition to download works successfully."""
        metadata_json = {
            'report_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319',
            'source': str(uuid.uuid4()),
            'report_slices': {
                str(self.uuid): {}
            }
        }
        report_json = {
            'report_slice_id': str(self.uuid),
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319'
        }

        report_files = {
            '%s.json' % str(self.uuid): report_json,
            'metadata.json': metadata_json
        }
        self.processor.upload_message = {
            'url': self.payload_url,
            'rh_account': '00001'
        }
        self.processor.report_or_slice = self.report_record
        self.processor.account_number = '0001'
        buffer_content = test_handler.create_tar_buffer(report_files)
        with requests_mock.mock() as mock_req:
            mock_req.get(self.payload_url, content=buffer_content)
            self.processor.transition_to_downloaded()
            self.assertEqual(self.report_record.state, Report.DOWNLOADED)

    def test_transition_to_downloaded_exception_retry(self):
        """Test that the transition to download with retry exception."""
        self.processor.upload_message = {
            'url': self.payload_url,
            'rh_account': '00001'
        }
        self.report_record.state = Report.STARTED
        self.report_record.save()
        self.processor.report_or_slice = self.report_record
        with requests_mock.mock() as mock_req:
            mock_req.get(self.payload_url, exc=requests.exceptions.HTTPError)
            self.processor.transition_to_downloaded()
            self.assertEqual(self.report_record.state, Report.STARTED)
            self.assertEqual(self.report_record.retry_count, 1)

    def test_transition_to_downloaded_exception_fail(self):
        """Test that the transition to download with fail exception."""
        self.processor.upload_message = {
            'url': self.payload_url,
            'rh_account': '00001'
        }
        self.report_record.state = Report.STARTED
        self.report_record.save()
        self.processor.report_or_slice = self.report_record

        def download_side_effect():
            """Raise a FailDownloadException."""
            raise report_processor.FailDownloadException()

        with patch(
                'processor.report_processor.ReportProcessor._download_report',
                side_effect=download_side_effect):
            self.processor.transition_to_downloaded()
            self.assertEqual(self.report_record.state, Report.FAILED_DOWNLOAD)

    def test_transition_to_validated_report_exception(self):
        """Test that a report with no report_slice_id is still marked as validated."""
        self.report_record.state = Report.DOWNLOADED
        self.report_record.save()
        report_json = {
            'report_id': 1,
            'report_type': 'insights',
            'status': 'completed',
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319'
        }
        self.report_slice.state = ReportSlice.PENDING
        self.report_slice.report_json = json.dumps(report_json)
        self.report_slice.save()
        self.processor.report_or_slice = self.report_record
        self.processor.transition_to_validated()
        self.assertEqual(self.report_record.state, Report.VALIDATED)
        self.assertEqual(self.report_record.upload_ack_status,
                         report_processor.FAILURE_CONFIRM_STATUS)
        self.assertEqual(self.report_record.retry_count, 0)

    def test_transition_to_validated_general_exception(self):
        """Test that exceptions are validated as failure (if no slices are valid)."""
        self.report_record.state = Report.DOWNLOADED
        self.report_record.save()
        self.processor.report_or_slice = self.report_record

        def validate_side_effect():
            """Transition the state to downloaded."""
            raise Exception('Test')

        with patch(
                'processor.report_processor.'
                'ReportProcessor._validate_report_details',
                side_effect=validate_side_effect):
            self.processor.transition_to_validated()
            self.assertEqual(self.report_record.state, Report.VALIDATED)
            self.assertEqual(self.processor.status,
                             report_processor.FAILURE_CONFIRM_STATUS)

    async def async_test_transition_to_validation_reported(self):
        """Set up the test for transitioning to validation reported."""
        self.report_record.state = Report.VALIDATED
        self.report_record.report_platform_id = self.uuid
        self.report_record.upload_ack_status = report_processor.SUCCESS_CONFIRM_STATUS
        self.report_record.save()
        self.processor.report_or_slice = self.report_record
        self.processor.status = report_processor.SUCCESS_CONFIRM_STATUS
        self.processor.upload_message = {'request_id': self.uuid}

        self.processor._send_confirmation = CoroutineMock()
        await self.processor.transition_to_validation_reported()
        self.assertEqual(self.processor.report.state,
                         Report.VALIDATION_REPORTED)

    def test_transition_to_validation_reported(self):
        """Test the async function to transition to validation reported."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(
            self.async_test_transition_to_validation_reported)
        event_loop.run_until_complete(coro())
        event_loop.close()

    async def async_test_transition_to_validation_reported_exception(self):
        """Set up the test for transitioning to validation reported."""
        self.report_record.state = Report.VALIDATED
        self.report_record.retry_count = 0
        self.report_record.report_platform_id = self.uuid
        self.report_record.upload_ack_status = report_processor.SUCCESS_CONFIRM_STATUS
        self.report_record.save()
        self.processor.report_or_slice = self.report_record
        self.processor.status = report_processor.SUCCESS_CONFIRM_STATUS
        self.processor.upload_message = {'hash': self.uuid}

        def report_side_effect():
            """Transition the state to validation_reported."""
            raise Exception('Test')

        self.processor._send_confirmation = CoroutineMock(
            side_effect=report_side_effect)
        await self.processor.transition_to_validation_reported()
        self.assertEqual(self.report_record.state, Report.VALIDATED)
        self.assertEqual(self.report_record.retry_count, 1)
        self.check_variables_are_reset()

    def test_transition_to_validation_reported_exception(self):
        """Test the async function to transition to validation reported."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(
            self.async_test_transition_to_validation_reported_exception)
        event_loop.run_until_complete(coro())
        event_loop.close()

    async def async_transition_to_validation_reported_failure_status(self):
        """Set up the test for transitioning to validation reported failure status."""
        report_to_archive = Report(upload_srv_kafka_msg=json.dumps(self.msg),
                                   account='43214',
                                   report_platform_id=self.uuid2,
                                   state=Report.VALIDATED,
                                   state_info=json.dumps([Report.NEW]),
                                   last_update_time=datetime.now(pytz.utc),
                                   retry_count=0,
                                   retry_type=Report.TIME,
                                   ready_to_archive=True,
                                   arrival_time=datetime.now(pytz.utc),
                                   processing_start_time=datetime.now(
                                       pytz.utc))
        report_to_archive.upload_ack_status = report_processor.FAILURE_CONFIRM_STATUS
        report_to_archive.save()
        self.processor.report_or_slice = report_to_archive
        self.processor.report_platform_id = self.uuid2
        self.processor.account_number = '43214'
        self.processor.state = Report.VALIDATED
        self.processor.status = report_processor.FAILURE_CONFIRM_STATUS
        self.processor.upload_message = {'request_id': self.uuid}
        self.processor._send_confirmation = CoroutineMock()
        await self.processor.transition_to_validation_reported()
        with self.assertRaises(Report.DoesNotExist):
            Report.objects.get(id=report_to_archive.id)
        archived = ReportArchive.objects.get(account='43214')
        self.assertEqual(archived.state, Report.VALIDATION_REPORTED)
        self.assertEqual(archived.upload_ack_status,
                         report_processor.FAILURE_CONFIRM_STATUS)
        # assert the processor was reset
        self.check_variables_are_reset()

    def test_transition_to_validation_reported_failure(self):
        """Test the async function for reporting failure status."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(
            self.async_transition_to_validation_reported_failure_status)
        event_loop.run_until_complete(coro())
        event_loop.close()

    # Tests for the functions that carry out the work ie (download/upload)
    def test_validate_report_success(self):
        """Test that a MKT report with the correct structure passes validation."""
        self.processor.account_number = '123'
        self.processor.report_or_slice = self.report_record
        self.processor.report_json = {
            'report_id': 1,
            'report_slice_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319-1',
            'report_type': 'insights',
            'status': 'completed',
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319'
        }
        valid = self.processor._validate_report_details()
        self.assertEqual(valid, True)

    def test_validate_report_missing_slice_id(self):
        """Test to verify a MKT report with no report_slice_id is failed."""
        self.processor.report_json = {
            'report_id': 1,
            'report_type': 'insights',
            'status': 'completed',
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319'
        }
        self.processor.report_or_slice = self.report_record

        with self.assertRaises(msg_handler.MKTReportException):
            self.processor._validate_report_details()

    def test_update_slice_exception(self):
        """Test udpating the slice with invalid data."""
        # test that not providing a state inside options causes
        # an exception to be raised and slice is not updated
        self.report_slice.state = ReportSlice.PENDING
        self.report_slice.save()
        self.processor.update_slice_state({}, self.report_slice)
        self.report_slice.refresh_from_db()
        self.assertEqual(self.report_slice.state, ReportSlice.PENDING)

    def test_extract_and_create_slices_success(self):
        """Testing the extract method with valid buffer content."""
        source_uuid = str(uuid.uuid4())
        metadata_json = {
            'report_id': 1,
            'source': source_uuid,
            'source_metadata': {
                'foo': 'bar'
            },
            'report_slices': {
                str(self.uuid): {}
            }
        }
        report_json = {'report_slice_id': str(self.uuid)}
        report_files = {
            'metadata.json': metadata_json,
            '%s.json' % str(self.uuid): report_json
        }
        self.processor.report_or_slice = self.report_record
        self.processor.account_number = '0001'
        buffer_content = test_handler.create_tar_buffer(report_files)
        result = self.processor._extract_and_create_slices(buffer_content)
        expected_result = {
            'report_platform_id': 1,
            'source': source_uuid,
            'source_metadata': {
                'foo': 'bar'
            }
        }
        self.assertEqual(result, expected_result)

    def test_extract_and_create_slices_mismatch(self):
        """Testing the extract method with mismatched metadata content."""
        metadata_json = {
            'report_id': 1,
            'source': str(uuid.uuid4()),
            'source_metadata': {
                'foo': 'bar'
            },
            'report_slices': {
                str(self.uuid): {
                    'number_hosts': 5
                }
            }
        }
        report_json = {'report_slice_id': '1234556'}
        report_files = {
            'metadata.json': metadata_json,
            '%s.json' % str(self.uuid): report_json
        }
        self.processor.report_or_slice = self.report_record
        self.processor.account_number = '0001'
        buffer_content = test_handler.create_tar_buffer(report_files)
        with self.assertRaises(report_processor.FailExtractException):
            self.processor._extract_and_create_slices(buffer_content)

    def test_extract_and_create_slices_metadata_fail(self):
        """Testing the extract method with invalid metadata buffer content."""
        metadata_json = 'myfakeencodedstring'
        slice_uuid = str(self.uuid)
        report_json = {'report_slice_id': slice_uuid}
        report_files = {
            'metadata.json': metadata_json,
            '%s.json' % slice_uuid: report_json
        }
        self.processor.report_or_slice = self.report_record
        self.processor.account_number = '0001'
        buffer_content = test_handler.create_tar_buffer(report_files,
                                                        meta_encoding='utf-16')
        with self.assertRaises(report_processor.FailExtractException):
            self.processor._extract_and_create_slices(buffer_content)

    def test_extract_and_create_slices_slice_fail(self):
        """Testing the extract method with bad slice."""
        metadata_json = {
            'report_id': 1,
            'source': str(uuid.uuid4()),
            'source_metadata': {
                'foo': 'bar'
            },
            'report_slices': {
                str(self.uuid): {}
            }
        }
        report_json = 'myfakeencodedstring'
        report_files = {
            'metadata.json': metadata_json,
            '%s.json' % str(self.uuid): report_json
        }
        self.processor.report_or_slice = self.report_record
        self.processor.account_number = '0001'
        buffer_content = test_handler.create_tar_buffer(report_files,
                                                        encoding='utf-16',
                                                        meta_encoding='utf-8')
        with self.assertRaises(report_processor.FailExtractException):
            self.processor._extract_and_create_slices(buffer_content)

    def test_create_slice_invalid(self):
        """Test the create slice method with an invalid slice."""
        report_json = None
        slice_id = '1234556'
        with self.assertRaises(Exception):
            options = {
                'report_json': report_json,
                'report_slice_id': slice_id,
                'source': str(uuid.uuid4()),
            }
            self.processor.create_report_slice(options)

    def test_extract_and_create_slices_two_reps(self):
        """Testing the extract method with valid buffer content."""
        source_uuid = str(uuid.uuid4())
        metadata_json = {
            'source': source_uuid,
            'report_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319',
            'report_slices': {
                str(self.uuid): {}
            }
        }
        report_json = {'report_slice_id': str(self.uuid)}

        report_files = {
            'metadata.json': metadata_json,
            '%s.json' % str(self.uuid): report_json
        }
        self.processor.report_or_slice = self.report_record
        self.processor.account_number = '0001'
        buffer_content = test_handler.create_tar_buffer(report_files)
        result = self.processor._extract_and_create_slices(buffer_content)
        expected_result = {
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319',
            'source': source_uuid,
        }
        self.assertEqual(result, expected_result)

    def test_extract_and_create_slices_failure(self):
        """Testing the extract method failure no matching report_slice."""
        metadata_json = {
            'report_id': 1,
            'report_type': 'insights',
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319',
            'report_slices': {
                str(self.uuid): {}
            }
        }
        report_files = {'metadata.json': metadata_json}
        buffer_content = test_handler.create_tar_buffer(report_files)
        with self.assertRaises(report_processor.FailExtractException):
            self.processor._extract_and_create_slices(buffer_content)

    def test_extract_and_create_slices_failure_invalid_metadata(self):
        """Testing the extract method failure no valid metadata."""
        metadata_json = {
            'report_id': 1,
            'report_type': 'deployments',
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319',
            'report_slices': {
                str(self.uuid): {}
            }
        }
        report_json = {
            'report_slice_id': str(self.uuid),
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319'
        }
        report_files = {
            'metadata.json': metadata_json,
            '%s.json' % str(self.uuid): report_json
        }
        buffer_content = test_handler.create_tar_buffer(report_files)
        with self.assertRaises(report_processor.FailExtractException):
            self.processor._extract_and_create_slices(buffer_content)

    def test_extract_and_create_slices_failure_no_metadata(self):
        """Testing the extract method failure no json file."""
        report_json = {
            'report_slice_id': '2345322',
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319'
        }
        report_files = {'2345322.json': report_json}
        buffer_content = test_handler.create_tar_buffer(report_files)
        with self.assertRaises(report_processor.FailExtractException):
            self.processor._extract_and_create_slices(buffer_content)

    def test__extract_and_create_slices_failure_invalid_json(self):
        """Testing the extract method failure invalid json."""
        metadata_json = {
            'report_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319',
            'source': str(uuid.uuid4()),
            'report_slices': {
                '2345322': {}
            }
        }
        report_json = 'This is not JSON.'
        report_files = {
            '2345322.json': report_json,
            'metadata.json': metadata_json
        }
        buffer_content = test_handler.create_tar_buffer(report_files)
        with self.assertRaises(report_processor.RetryExtractException):
            self.processor._extract_and_create_slices(buffer_content)

    def test__extract_and_create_slices_failure_no_json(self):
        """Testing the extract method failure invalid json."""
        metadata_json = {
            'report_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319',
            'source': str(uuid.uuid4()),
            'report_slices': {
                '2345322': {}
            }
        }
        report_json = None
        report_files = {
            '2345322.json': report_json,
            'metadata.json': metadata_json
        }
        buffer_content = test_handler.create_tar_buffer(report_files)
        with self.assertRaises(report_processor.FailExtractException):
            self.processor._extract_and_create_slices(buffer_content)

    def test_download_response_content_bad_url(self):
        """Test to verify download exceptions are handled."""
        with requests_mock.mock() as mock_req:
            mock_req.get(self.payload_url, exc=requests.exceptions.HTTPError)
            with self.assertRaises(report_processor.RetryDownloadException):
                self.processor.upload_message = {'url': self.payload_url}
                self.processor._download_report()

    def test_download_response_content_missing_url(self):
        """Test case where url is missing."""
        with self.assertRaises(report_processor.FailDownloadException):
            self.processor.upload_message = {}
            self.processor._download_report()

    def test_download_report_success(self):
        """Test to verify extracting contents is successful."""
        metadata_json = {
            'report_id': 1,
            'report_type': 'insights',
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319',
            'report_slices': {
                '2345322': {}
            }
        }
        report_json = {
            'report_slice_id': '2345322',
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319'
        }
        report_files = {
            'metadata.json': metadata_json,
            '2345322.json': report_json
        }
        self.processor.upload_message = {
            'url': self.payload_url,
            'rh_account': '00001'
        }
        buffer_content = test_handler.create_tar_buffer(report_files)
        with requests_mock.mock() as mock_req:
            mock_req.get(self.payload_url, content=buffer_content)
            content = self.processor._download_report()
            self.assertEqual(buffer_content, content)

    def test_download_and_validate_contents_invalid_report(self):
        """Test to verify extracting contents fails when report is invalid."""
        self.processor.report_json = {
            'report_type': 'insights',
            'status': 'completed',
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319'
        }
        self.processor.report_or_slice = self.report_record
        with self.assertRaises(msg_handler.MKTReportException):
            _, _ = self.processor._validate_report_details()

    def test_download_contents_raises_error(self):
        """Test to verify downloading contents fails when error is raised."""
        report_json = {
            'report_id': 1,
            'report_type': 'insights',
            'status': 'completed',
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319'
        }
        self.processor.upload_message = {
            'url': self.payload_url,
            'rh_account': '00001'
        }
        report_files = {'report.json': report_json}
        buffer_content = test_handler.create_tar_buffer(report_files)
        with requests_mock.mock() as mock_req:
            mock_req.get(self.payload_url, content=buffer_content)
            with patch('requests.get',
                       side_effect=requests.exceptions.HTTPError):
                with self.assertRaises(
                        report_processor.RetryDownloadException):
                    content = self.processor._download_report()
                    self.assertEqual(content, buffer_content)

    def test_download_with_404(self):
        """Test downloading a URL and getting 404."""
        with requests_mock.mock() as mock_req:
            mock_req.get(self.payload_url, status_code=404)
            with self.assertRaises(report_processor.RetryDownloadException):
                self.processor.upload_message = {'url': self.payload_url}
                self.processor._download_report()

    def test_value_error__extract_and_create_slices(self):
        """Testing value error when extracting json from tar.gz."""
        invalid_json = '["report_id": 1]'
        tar_buffer = io.BytesIO()
        with tarfile.open(fileobj=tar_buffer, mode='w:gz') as tar_file:
            file_name = 'file.json'
            file_content = invalid_json
            file_buffer = io.BytesIO(file_content.encode('utf-8'))
            info = tarfile.TarInfo(name=file_name)
            info.size = len(file_buffer.getvalue())
            tar_file.addfile(tarinfo=info, fileobj=file_buffer)
        tar_buffer.seek(0)
        buffer_content = tar_buffer.getvalue()
        with self.assertRaises(report_processor.FailExtractException):
            self.processor._extract_and_create_slices(buffer_content)

    def test_no_json_files__extract_and_create_slices(self):
        """Testing no json files found in tar.gz."""
        invalid_json = '["report_id": 1]'
        tar_buffer = io.BytesIO()
        with tarfile.open(fileobj=tar_buffer, mode='w:gz') as tar_file:
            file_name = 'file.csv'
            file_content = invalid_json
            file_buffer = io.BytesIO(file_content.encode('utf-8'))
            info = tarfile.TarInfo(name=file_name)
            info.size = len(file_buffer.getvalue())
            tar_file.addfile(tarinfo=info, fileobj=file_buffer)
        tar_buffer.seek(0)
        buffer_content = tar_buffer.getvalue()
        with self.assertRaises(report_processor.FailExtractException):
            self.processor._extract_and_create_slices(buffer_content)

    def test__extract_and_create_slices_general_except(self):
        """Testing general exception raises retry exception."""
        def extract_side_effect():
            """Raise general error."""
            raise Exception('Test')

        with patch('processor.report_processor.tarfile.open',
                   side_effect=extract_side_effect):
            with self.assertRaises(report_processor.RetryExtractException):
                self.processor._extract_and_create_slices(None)

    def test_calculating_queued_reports(self):
        """Test the calculate_queued_reports method."""
        status_info = Status()
        current_time = datetime.now(pytz.utc)
        self.report_record.state = Report.NEW
        self.report_record.save()
        reports_to_process = self.processor.calculate_queued_objects(
            current_time, status_info)
        self.assertEqual(reports_to_process, 1)

        min_old_time = current_time - timedelta(hours=8)
        older_report = Report(upload_srv_kafka_msg=json.dumps(self.msg),
                              account='4321',
                              report_platform_id=self.uuid2,
                              state=Report.STARTED,
                              state_info=json.dumps([Report.NEW]),
                              last_update_time=min_old_time,
                              retry_count=1,
                              retry_type=Report.TIME)
        older_report.save()

        retry_commit_report = Report(upload_srv_kafka_msg=json.dumps(self.msg),
                                     account='4321',
                                     report_platform_id=self.uuid2,
                                     state=Report.DOWNLOADED,
                                     state_info=json.dumps([Report.NEW]),
                                     last_update_time=min_old_time,
                                     git_commit='3948384729',
                                     retry_type=Report.GIT_COMMIT,
                                     retry_count=1)
        retry_commit_report.save()

        # create some reports that should not be counted
        not_old_enough = current_time - timedelta(hours=1)
        too_young_report = Report(upload_srv_kafka_msg=json.dumps(self.msg),
                                  account='4321',
                                  report_platform_id=self.uuid2,
                                  state=Report.DOWNLOADED,
                                  state_info=json.dumps([Report.NEW]),
                                  last_update_time=not_old_enough,
                                  git_commit='3948384729',
                                  retry_type=Report.TIME,
                                  retry_count=1)
        too_young_report.save()

        same_commit_report = Report(upload_srv_kafka_msg=json.dumps(self.msg),
                                    account='4321',
                                    report_platform_id=self.uuid2,
                                    state=Report.DOWNLOADED,
                                    state_info=json.dumps([Report.NEW]),
                                    last_update_time=min_old_time,
                                    git_commit=status_info.git_commit,
                                    retry_type=Report.GIT_COMMIT,
                                    retry_count=1)
        same_commit_report.save()

        reports_to_process = self.processor.calculate_queued_objects(
            current_time, status_info)
        self.assertEqual(reports_to_process, 3)

        # delete the older report object
        Report.objects.get(id=older_report.id).delete()
        Report.objects.get(id=retry_commit_report.id).delete()
        Report.objects.get(id=too_young_report.id).delete()
        Report.objects.get(id=same_commit_report.id).delete()

    def test_state_to_metric(self):
        """Test the state_to_metric function."""
        self.processor.state = Report.FAILED_DOWNLOAD
        self.processor.account_number = '1234'
        failed_download_before = \
            REGISTRY.get_sample_value(
                'failed_download', {'account_number': '1234'}) or 0.0
        self.processor.record_failed_state_metrics()
        failed_download_after = REGISTRY.get_sample_value(
            'failed_download', {'account_number': '1234'})
        self.assertEqual(1.0,
                         float(failed_download_after) - failed_download_before)
Exemple #7
0
class ReportSliceProcessorTests(TestCase):
    """Test Cases for the Message processor."""
    def setUp(self):
        """Create test setup."""
        self.payload_url = 'http://insights-upload.com/q/file_to_validate'
        self.uuid = uuid.uuid4()
        self.uuid2 = uuid.uuid4()
        self.uuid3 = uuid.uuid4()
        self.uuid4 = uuid.uuid4()
        self.uuid5 = uuid.uuid4()
        self.uuid6 = uuid.uuid4()
        self.uuid7 = uuid.uuid4()
        self.fake_record = test_handler.KafkaMsg(msg_handler.QPC_TOPIC,
                                                 'http://internet.com')
        self.report_consumer = msg_handler.ReportConsumer()
        self.msg = self.report_consumer.unpack_consumer_record(
            self.fake_record)
        self.report_json = {
            'report_id': 1,
            'report_type': 'insights',
            'report_version': '1.0.0.1b025b8',
            'status': 'completed',
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319',
            'hosts': [{
                'bios_uuid': 'value'
            }, {
                'invalid': 'value'
            }]
        }
        self.report_record = Report(upload_srv_kafka_msg=json.dumps(self.msg),
                                    account='1234',
                                    state=Report.NEW,
                                    state_info=json.dumps([Report.NEW]),
                                    last_update_time=datetime.now(pytz.utc),
                                    retry_count=0,
                                    ready_to_archive=False,
                                    source='satellite',
                                    arrival_time=datetime.now(pytz.utc),
                                    processing_start_time=datetime.now(
                                        pytz.utc))
        self.report_record.save()

        self.report_slice = ReportSlice(
            report_platform_id=self.uuid,
            report_slice_id=self.uuid2,
            account='13423',
            report_json=json.dumps(self.report_json),
            state=ReportSlice.NEW,
            state_info=json.dumps([ReportSlice.NEW]),
            retry_count=0,
            last_update_time=datetime.now(pytz.utc),
            failed_hosts=[],
            candidate_hosts=[],
            report=self.report_record,
            ready_to_archive=True,
            hosts_count=2,
            source='satellite',
            creation_time=datetime.now(pytz.utc),
            processing_start_time=datetime.now(pytz.utc))
        self.report_slice.save()
        self.report_record.save()
        self.processor = report_slice_processor.ReportSliceProcessor()
        self.processor.report = self.report_slice

    def check_variables_are_reset(self):
        """Check that report processor members have been cleared."""
        processor_attributes = [
            self.processor.report_platform_id, self.processor.report,
            self.processor.state, self.processor.account_number,
            self.processor.upload_message, self.processor.status,
            self.processor.report_json, self.processor.candidate_hosts,
            self.processor.failed_hosts
        ]
        for attribute in processor_attributes:
            self.assertEqual(attribute, None)

    def test_assign_report_slice_new(self):
        """Test the assign report slice function with only a new report slice."""
        self.report_slice.state = ReportSlice.NEW
        self.report_slice.save()
        self.processor.report_or_slice = None
        self.processor.assign_object()
        self.assertEqual(self.processor.report_or_slice, self.report_slice)
        queued_slices = REGISTRY.get_sample_value('queued_report_slices')
        self.assertEqual(queued_slices, 1)

    async def async_test_delegate_state(self):
        """Set up the test for delegate state."""
        self.report_slice.state = ReportSlice.VALIDATED
        self.report_slice.report_platform_id = self.uuid
        self.report_slice.candidate_hosts = json.dumps([{
            str(self.uuid3): {
                'ip_addresses': 'value',
                'name': 'value'
            },
            'cause':
            report_slice_processor.FAILED_UPLOAD
        }])
        self.report_slice.failed_hosts = json.dumps([{
            str(self.uuid2): {
                'ip_addresses': 'value',
                'name': 'value'
            },
            'cause':
            abstract_processor.FAILED_VALIDATION
        }])
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice

        def upload_side_effect():
            """Transition the state to uploaded."""
            self.processor.state = ReportSlice.HOSTS_UPLOADED
            self.report_slice.state = ReportSlice.HOSTS_UPLOADED
            self.report_slice.save()

        with patch(
                'processor.report_slice_processor.'
                'ReportSliceProcessor.transition_to_hosts_uploaded',
                side_effect=upload_side_effect):
            await self.processor.delegate_state()
            self.check_variables_are_reset()

        # test pending state for delegate
        self.report_slice.state = ReportSlice.PENDING
        self.processor.report_or_slice = self.report_slice
        await self.processor.delegate_state()
        self.check_variables_are_reset()

    def test_run_delegate(self):
        """Test the async function delegate state."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(self.async_test_delegate_state)
        event_loop.run_until_complete(coro())
        event_loop.close()

    def test_update_slice_state(self):
        """Test updating the slice state."""
        self.report_slice.failed_hosts = json.dumps([])
        self.report_slice.save()
        report_json = {
            'report_id': 1,
            'report_type': 'deployments',
            'report_version': '1.0.0.1b025b8',
            'status': 'completed',
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319',
            'hosts': {
                str(self.uuid): {
                    'key': 'value'
                }
            }
        }
        failed_hosts = [{
            str(self.uuid6): {
                'etc_machine_id': 'value'
            }
        }, {
            str(self.uuid7): {
                'subscription_manager_id': 'value'
            }
        }]
        self.processor.report_or_slice = self.report_slice
        self.processor.next_state = ReportSlice.VALIDATED
        options = {'report_json': report_json, 'failed_hosts': failed_hosts}
        self.processor.update_object_state(options=options)
        self.assertEqual(json.loads(self.report_slice.report_json),
                         report_json)
        self.assertEqual(json.loads(self.report_slice.failed_hosts),
                         failed_hosts)

    def test_transition_to_validated_general_exception(self):
        """Test that when a general exception is raised, we don't pass validation."""
        self.report_slice.state = ReportSlice.RETRY_VALIDATION
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice

        def validate_side_effect():
            """Transition the state to downloaded."""
            raise Exception('Test')

        with patch(
                'processor.report_slice_processor.'
                'ReportSliceProcessor._validate_report_details',
                side_effect=validate_side_effect):
            self.processor.transition_to_validated()
            self.assertEqual(self.report_slice.state,
                             ReportSlice.RETRY_VALIDATION)
            self.assertEqual(self.report_slice.retry_count, 1)

    def test_transition_to_validated(self):
        """Test that when a general exception is raised, we don't pass validation."""
        self.report_slice.state = ReportSlice.RETRY_VALIDATION
        report_json = {
            'report_slice_id': '384794738',
            'hosts': [{
                'ip_addresses': 'value'
            }]
        }
        self.report_slice.report_json = json.dumps(report_json)
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice
        self.processor.transition_to_validated()
        self.assertEqual(self.report_slice.state, ReportSlice.VALIDATED)
        self.assertEqual(self.report_slice.retry_count, 0)

    def test_transition_to_validated_failed(self):
        """Test report missing slice id."""
        self.report_slice.state = ReportSlice.RETRY_VALIDATION
        report_json = {
            'report_id': 1,
            'report_type': 'insights',
            'report_version': '1.0.0.1b025b8',
            'status': 'completed',
            'report_platform_id': '5f2cc1fd-ec66-4c67-be1b-171a595ce319',
            'hosts': {
                str(self.uuid): {
                    'ip_addresses': 'value'
                }
            }
        }
        self.report_slice.report_json = json.dumps(report_json)
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice
        self.processor.transition_to_validated()
        self.assertEqual(self.report_slice.state,
                         ReportSlice.FAILED_VALIDATION)
        self.assertEqual(self.report_slice.retry_count, 0)
        self.assertEqual(self.report_slice.ready_to_archive, True)

    def test_moved_candidates_to_failed(self):
        """Test that we reset candidates after moving them to failed."""
        candidates = [{self.uuid: {'bios_uuid': 'value', 'name': 'value'}}]
        self.processor.candidate_hosts = candidates
        self.processor.failed_hosts = [{
            self.uuid2: {
                'bios_uuid': 'value',
                'name': 'value'
            },
            'cause':
            abstract_processor.FAILED_VALIDATION
        }]
        self.processor.move_candidates_to_failed()
        self.assertEqual(self.processor.candidate_hosts, [])
        for host in candidates:
            self.assertIn(host, self.processor.failed_hosts)

    def test_determine_retry_limit(self):
        """Test the determine retry method when the retry is at the limit."""
        candidates = [{
            str(self.uuid3): {
                'ip_addresses': 'value',
                'name': 'value'
            },
            'cause': report_slice_processor.FAILED_UPLOAD
        }]
        self.report_slice.state = ReportSlice.VALIDATED
        self.report_slice.retry_count = 4
        self.report_slice.candidate_hosts = json.dumps(candidates)
        self.report_slice.failed_hosts = json.dumps([])
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice
        self.processor.candidate_hosts = candidates
        self.processor.failed_hosts = []
        self.processor.determine_retry(ReportSlice.FAILED_HOSTS_UPLOAD,
                                       ReportSlice.VALIDATED)
        self.assertEqual(self.report_slice.state,
                         ReportSlice.FAILED_HOSTS_UPLOAD)
        self.assertEqual(json.loads(self.report_slice.candidate_hosts), [])
        for host in candidates:
            self.assertIn(host, json.loads(self.report_slice.failed_hosts))

    async def async_test_transition_to_hosts_uploaded(self):
        """Test the transition to hosts being uploaded."""
        hosts = [{
            str(self.uuid): {
                'bios_uuid': 'value',
                'name': 'value',
                'system_platform_id': str(self.uuid)
            }
        }, {
            str(self.uuid2): {
                'insights_client_id': 'value',
                'name': 'foo',
                'system_platform_id': str(self.uuid2)
            }
        }, {
            str(self.uuid3): {
                'ip_addresses': 'value',
                'name': 'foo',
                'system_platform_id': str(self.uuid3)
            }
        }, {
            str(self.uuid4): {
                'mac_addresses': 'value',
                'name': 'foo',
                'system_platform_id': str(self.uuid4)
            }
        }, {
            str(self.uuid5): {
                'vm_uuid': 'value',
                'name': 'foo',
                'system_platform_id': str(self.uuid5)
            }
        }, {
            str(self.uuid6): {
                'etc_machine_id': 'value',
                'system_platform_id': str(self.uuid6)
            }
        }, {
            str(self.uuid7): {
                'subscription_manager_id': 'value',
                'system_platform_id': str(self.uuid7)
            }
        }]
        self.report_slice.failed_hosts = []
        self.report_slice.candidate_hosts = json.dumps(hosts)
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice
        self.processor.candidate_hosts = hosts
        self.processor._upload_to_host_inventory_via_kafka = CoroutineMock(
            return_value=[])
        await self.processor.transition_to_hosts_uploaded()
        self.assertEqual(json.loads(self.report_slice.candidate_hosts), [])
        self.assertEqual(self.report_slice.state, ReportSlice.HOSTS_UPLOADED)

    def test_transition_to_hosts_uploaded(self):
        """Test the async hosts uploaded successful."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(self.async_test_transition_to_hosts_uploaded)
        event_loop.run_until_complete(coro())
        event_loop.close()

    async def async_test_transition_to_hosts_uploaded_kafka_mode(self):
        """Test the transition to hosts being uploaded."""
        hosts = [{
            str(self.uuid): {
                'bios_uuid': 'value',
                'name': 'value',
                'system_platform_id': str(self.uuid)
            }
        }, {
            str(self.uuid2): {
                'insights_client_id': 'value',
                'name': 'foo',
                'system_platform_id': str(self.uuid2)
            }
        }, {
            str(self.uuid3): {
                'ip_addresses': 'value',
                'name': 'foo',
                'system_platform_id': str(self.uuid3)
            }
        }, {
            str(self.uuid4): {
                'mac_addresses': 'value',
                'name': 'foo',
                'system_platform_id': str(self.uuid4)
            }
        }, {
            str(self.uuid5): {
                'vm_uuid': 'value',
                'name': 'foo',
                'system_platform_id': str(self.uuid5)
            }
        }, {
            str(self.uuid6): {
                'etc_machine_id': 'value',
                'system_platform_id': str(self.uuid6)
            }
        }, {
            str(self.uuid7): {
                'subscription_manager_id': 'value',
                'system_platform_id': str(self.uuid7)
            }
        }]
        self.report_slice.failed_hosts = []
        self.report_slice.candidate_hosts = json.dumps(hosts)
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice
        self.processor.candidate_hosts = hosts
        self.processor._upload_to_host_inventory_via_kafka = CoroutineMock(
            return_value=[])
        await self.processor.transition_to_hosts_uploaded()
        self.assertEqual(json.loads(self.report_slice.candidate_hosts), [])
        self.assertEqual(self.report_slice.state, ReportSlice.HOSTS_UPLOADED)

    def test_transition_to_hosts_uploaded_kafka_mode(self):
        """Test the async hosts uploaded successful."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(self.async_test_transition_to_hosts_uploaded)
        event_loop.run_until_complete(coro())
        event_loop.close()

    async def async_test_transition_to_hosts_uploaded_no_candidates(self):
        """Test the transition to hosts being uploaded."""
        self.report_record.ready_to_archive = True
        self.report_record.save()
        faulty_report = ReportSlice(
            account='987',
            report_platform_id=str(self.uuid2),
            report_slice_id=str(self.uuid),
            state=ReportSlice.NEW,
            report_json=json.dumps(self.report_json),
            state_info=json.dumps([ReportSlice.PENDING, ReportSlice.NEW]),
            last_update_time=datetime.now(pytz.utc),
            candidate_hosts=json.dumps({}),
            failed_hosts=json.dumps([]),
            hosts_count=10,
            retry_count=0)
        faulty_report.save()
        self.processor.report_or_slice = faulty_report
        self.processor.account_number = '987'
        self.processor.state = faulty_report.state
        self.processor.report_platform_id = self.uuid2
        self.processor.report_json = self.report_json
        self.processor.candidate_hosts = {}
        await self.processor.transition_to_hosts_uploaded()
        # assert the processor was reset
        self.check_variables_are_reset()

    def test_test_transition_to_hosts_uploaded_no_candidates(self):
        """Test the async hosts uploaded no candidates."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(
            self.async_test_transition_to_hosts_uploaded_no_candidates)
        event_loop.run_until_complete(coro())
        event_loop.close()

    async def async_test_transition_to_hosts_uploaded_exception(self):
        """Test the transition to hosts being uploaded."""
        hosts = {
            str(self.uuid): {
                'bios_uuid': 'value',
                'name': 'value'
            },
            str(self.uuid2): {
                'insights_client_id': 'value',
                'name': 'foo'
            },
            str(self.uuid3): {
                'ip_addresses': 'value',
                'name': 'foo'
            },
            str(self.uuid4): {
                'mac_addresses': 'value',
                'name': 'foo'
            },
            str(self.uuid5): {
                'vm_uuid': 'value',
                'name': 'foo'
            },
            str(self.uuid6): {
                'etc_machine_id': 'value'
            },
            str(self.uuid7): {
                'subscription_manager_id': 'value'
            }
        }
        self.processor.candidate_hosts = hosts
        self.processor.report_or_slice = self.report_slice

        def hosts_upload_side_effect():
            raise Exception('Test')

        with patch(
                'processor.report_slice_processor.'
                'ReportSliceProcessor._upload_to_host_inventory_via_kafka',
                side_effect=hosts_upload_side_effect):
            await self.processor.transition_to_hosts_uploaded()
            self.assertEqual(self.report_slice.state, Report.VALIDATED)
            self.assertEqual(self.report_slice.retry_count, 1)

    def test_test_transition_to_hosts_uploaded_exception(self):
        """Test the async hosts uploaded exception."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(
            self.async_test_transition_to_hosts_uploaded_exception)
        event_loop.run_until_complete(coro())
        event_loop.close()

    async def async_test_upload_to_host_inventory_via_kafka(self):
        """Test uploading to inventory via kafka."""
        self.processor.report_or_slice = self.report_slice
        hosts = {
            str(self.uuid): {
                'bios_uuid': 'value',
                'name': 'value'
            },
            str(self.uuid2): {
                'insights_client_id': 'value',
                'name': 'foo'
            },
            str(self.uuid3): {
                'ip_addresses': 'value',
                'name': 'foo'
            },
            str(self.uuid4): {
                'mac_addresses': 'value',
                'name': 'foo'
            },
            str(self.uuid5): {
                'vm_uuid': 'value',
                'name': 'foo'
            },
            str(self.uuid6): {
                'etc_machine_id': 'value'
            },
            str(self.uuid7): {
                'subscription_manager_id': 'value'
            }
        }
        test_producer = AIOKafkaProducer(
            loop=report_slice_processor.SLICE_PROCESSING_LOOP,
            bootstrap_servers=report_slice_processor.INSIGHTS_KAFKA_ADDRESS)
        test_producer.start = CoroutineMock()
        test_producer.send = CoroutineMock()
        test_producer.stop = CoroutineMock()
        with patch('processor.report_slice_processor.AIOKafkaProducer',
                   return_value=test_producer):
            with patch('processor.report_slice_processor.asyncio.wait',
                       side_effect=None):
                # all though we are not asserting any results, the test here is
                # that no error was raised
                await self.processor._upload_to_host_inventory_via_kafka(hosts)

    def test_upload_to_host_inventory_via_kafka(self):
        """Test the async hosts uploaded exception."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(
            self.async_test_upload_to_host_inventory_via_kafka)
        event_loop.run_until_complete(coro())
        event_loop.close()

    async def async_test_upload_to_host_inventory_via_kafka_exception(self):
        """Test uploading to inventory via kafka."""
        self.processor.report_or_slice = self.report_slice
        hosts = {
            str(self.uuid): {
                'bios_uuid': 'value',
                'name': 'value'
            },
            str(self.uuid2): {
                'insights_client_id': 'value',
                'name': 'foo'
            },
            str(self.uuid3): {
                'ip_addresses': 'value',
                'name': 'foo'
            },
            str(self.uuid4): {
                'mac_addresses': 'value',
                'name': 'foo'
            },
            str(self.uuid5): {
                'vm_uuid': 'value',
                'name': 'foo'
            },
            str(self.uuid6): {
                'etc_machine_id': 'value'
            },
            str(self.uuid7): {
                'subscription_manager_id': 'value'
            }
        }
        test_producer = AIOKafkaProducer(
            loop=report_slice_processor.SLICE_PROCESSING_LOOP,
            bootstrap_servers=report_slice_processor.INSIGHTS_KAFKA_ADDRESS)

        # test KafkaConnectionException
        def raise_kafka_error():
            """Raise a kafka error."""
            raise KafkaConnectionError('Test')

        test_producer.start = CoroutineMock(side_effect=raise_kafka_error)
        test_producer.send = CoroutineMock()
        test_producer.stop = CoroutineMock()
        with self.assertRaises(msg_handler.KafkaMsgHandlerError):
            with patch('processor.report_slice_processor.AIOKafkaProducer',
                       return_value=test_producer):
                await self.processor._upload_to_host_inventory_via_kafka(hosts)

    def test_upload_to_host_inventory_via_kafka_exception(self):
        """Test the async hosts uploaded exception."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(
            self.async_test_upload_to_host_inventory_via_kafka_exception)
        event_loop.run_until_complete(coro())
        event_loop.close()

    async def async_test_upload_to_host_inventory_via_kafka_send_exception(
            self):
        """Test uploading to inventory via kafka."""
        self.processor.report_or_slice = self.report_slice
        hosts = {
            str(self.uuid): {
                'bios_uuid': 'value',
                'name': 'value'
            },
            str(self.uuid2): {
                'insights_client_id': 'value',
                'name': 'foo'
            },
            str(self.uuid3): {
                'ip_addresses': 'value',
                'name': 'foo'
            },
            str(self.uuid4): {
                'mac_addresses': 'value',
                'name': 'foo'
            },
            str(self.uuid5): {
                'vm_uuid': 'value',
                'name': 'foo'
            },
            str(self.uuid6): {
                'etc_machine_id': 'value'
            },
            str(self.uuid7): {
                'subscription_manager_id': 'value'
            }
        }
        test_producer = AIOKafkaProducer(
            loop=report_slice_processor.SLICE_PROCESSING_LOOP,
            bootstrap_servers=report_slice_processor.INSIGHTS_KAFKA_ADDRESS)

        # test KafkaConnectionException
        def raise_error():
            """Raise a general error."""
            raise Exception('Test')

        test_producer.start = CoroutineMock()
        test_producer.send = CoroutineMock(side_effect=raise_error)
        test_producer.stop = CoroutineMock()
        with self.assertRaises(msg_handler.KafkaMsgHandlerError):
            with patch('processor.report_slice_processor.AIOKafkaProducer',
                       return_value=test_producer):
                await self.processor._upload_to_host_inventory_via_kafka(hosts)

    def test_upload_to_host_inventory_via_kafka_send_exception(self):
        """Test the async hosts uploaded exception."""
        event_loop = asyncio.new_event_loop()
        asyncio.set_event_loop(event_loop)
        coro = asyncio.coroutine(
            self.async_test_upload_to_host_inventory_via_kafka_send_exception)
        event_loop.run_until_complete(coro())
        event_loop.close()

    def test_archive_report_and_slices_in_failed_state(self):
        """Test the archive method in a failed state."""
        self.report_record.ready_to_archive = True
        self.report_record.report_platform_id = str(self.uuid)
        self.report_record.save()
        self.report_slice.ready_to_archive = True
        self.report_slice.report_platform_id = str(self.uuid)
        self.report_slice.report_slice_id = str(self.uuid2)
        self.report_slice.state = ReportSlice.FAILED_HOSTS_UPLOAD
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice
        self.processor.report_platform_id = str(self.uuid)

        self.processor.archive_report_and_slices()
        # assert the report doesn't exist
        with self.assertRaises(Report.DoesNotExist):
            Report.objects.get(id=self.report_record.id)
        # assert the report archive does exist
        archived = ReportArchive.objects.get(
            account=self.report_record.account)
        archived_slice = ReportSliceArchive.objects.get(
            report_slice_id=self.report_slice.report_slice_id)
        self.assertEqual(str(archived.report_platform_id), str(self.uuid))
        self.assertEqual(str(archived_slice.report_platform_id),
                         str(self.uuid))
        self.assertIsNotNone(archived_slice.processing_end_time)
        # assert the processor was reset
        self.check_variables_are_reset()

    def test_archive_report_and_slices_in_success_state(self):
        """Test the archive method in a failed state."""
        self.report_record.ready_to_archive = True
        self.report_record.report_platform_id = str(self.uuid)
        self.report_record.save()
        self.report_slice.ready_to_archive = True
        self.report_slice.report_platform_id = str(self.uuid)
        self.report_slice.report_slice_id = str(self.uuid2)
        self.report_slice.state = ReportSlice.HOSTS_UPLOADED
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice
        self.processor.report_platform_id = str(self.uuid)

        self.processor.archive_report_and_slices()
        # assert the report doesn't exist
        with self.assertRaises(Report.DoesNotExist):
            Report.objects.get(id=self.report_record.id)
        # assert the report archive does exist
        archived = ReportArchive.objects.get(
            account=self.report_record.account)
        archived_slice = ReportSliceArchive.objects.get(
            report_slice_id=self.report_slice.report_slice_id)
        self.assertEqual(str(archived.report_platform_id), str(self.uuid))
        self.assertEqual(str(archived_slice.report_platform_id),
                         str(self.uuid))
        # assert the processor was reset
        self.check_variables_are_reset()

    def test_archive_report_and_slices_not_ready(self):
        """Test the archive method with slice not ready."""
        self.report_record.ready_to_archive = True
        self.report_record.report_platform_id = str(self.uuid)
        self.report_record.save()
        self.report_slice.ready_to_archive = False
        self.report_slice.report_platform_id = str(self.uuid)
        self.report_slice.report_slice_id = str(self.uuid2)
        self.report_slice.save()
        self.processor.report_or_slice = self.report_slice
        self.processor.report_platform_id = str(self.uuid)

        self.processor.archive_report_and_slices()
        # assert the report doesn't exist
        existing = Report.objects.get(id=self.report_record.id)
        # assert the report archive does exist
        with self.assertRaises(ReportArchive.DoesNotExist):
            ReportArchive.objects.get(account=self.report_record.account)
        with self.assertRaises(ReportSliceArchive.DoesNotExist):
            ReportSliceArchive.objects.get(
                report_slice_id=self.report_slice.report_slice_id)
        self.assertEqual(str(existing.report_platform_id), str(self.uuid))
        # assert the processor was reset
        self.check_variables_are_reset()

    def test_get_stale_time(self):
        """Test the get stale date method."""
        self.processor.report_or_slice = self.report_record
        self.processor.report_or_slice.source = 'satellite'
        self.processor.report_or_slice.save()
        current_time = datetime.utcnow()
        stale_time = current_time + timedelta(days=int(SATELLITE_HOST_TTL))
        expected = stale_time.strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z'
        actual = self.processor.get_stale_date()
        # the format looks like this: 2019-11-14T19:58:13.037Z
        # by cutting off the last 13 i am comparing 2019-11-14T
        # which is the year/month/day
        self.assertEqual(expected[:-13], actual[:-13])