예제 #1
0
    def test___init___with_defaults(self):
        """
        Test the __init__() method when passing no parameters.
        """
        report = progress.SyncProgressReport()

        # Make sure all the appropriate attributes were set
        self.assertEqual(report.conduit, None)
        self.assertEqual(report._state, progress.SyncProgressReport.STATE_NOT_STARTED)

        # The state_times attribute should be a dictionary with only the time the not started
        # state was entered
        self.assertTrue(isinstance(report.state_times, dict))
        self.assertEqual(len(report.state_times), 1)
        self.assertTrue(
            isinstance(report.state_times[progress.SyncProgressReport.STATE_NOT_STARTED],
                       datetime))

        self.assertEqual(report.error_message, None)
        self.assertEqual(report.traceback, None)
        self.assertEqual(report.num_isos, None)
        self.assertEqual(report.num_isos_finished, 0)
        self.assertEqual(report.iso_error_messages, [])
        self.assertEqual(report.total_bytes, None)
        self.assertEqual(report.finished_bytes, 0)
예제 #2
0
    def test_build_progress_report(self):
        """
        Test the build_progress_report() method.
        """
        state = progress.SyncProgressReport.STATE_ISOS_IN_PROGRESS
        state_times = {progress.SyncProgressReport.STATE_ISOS_IN_PROGRESS: datetime.utcnow()}
        num_isos = 5
        num_isos_finished = 3
        iso_error_messages = {'an.iso': "No!"}
        error_message = 'This is an error message.'
        traceback = 'This is a traceback.'
        total_bytes = 1024
        finished_bytes = 512
        report = progress.SyncProgressReport(
            self.conduit, state=state, state_times=state_times, num_isos=num_isos,
            num_isos_finished=num_isos_finished, iso_error_messages=iso_error_messages,
            error_message=error_message, traceback=traceback, total_bytes=total_bytes,
            finished_bytes=finished_bytes)

        report = report.build_progress_report()

        # Make sure all the appropriate attributes were set
        self.assertEqual(report['state'], state)
        expected_state_times = {}
        for key, value in state_times.items():
            expected_state_times[key] = format_iso8601_datetime(value)
        self.assertTrue(report['state_times'], expected_state_times)
        self.assertEqual(report['num_isos'], num_isos)
        self.assertEqual(report['num_isos_finished'], num_isos_finished)
        self.assertEqual(report['iso_error_messages'], iso_error_messages)
        self.assertEqual(report['error_message'], error_message)
        self.assertEqual(report['traceback'], traceback)
        self.assertEqual(report['total_bytes'], total_bytes)
        self.assertEqual(report['finished_bytes'], finished_bytes)
예제 #3
0
    def test___init__with_non_defaults(self):
        """
        Test the __init__ method when passing in parameters.
        """
        state = progress.SyncProgressReport.STATE_ISOS_IN_PROGRESS
        state_times = {progress.SyncProgressReport.STATE_ISOS_IN_PROGRESS: datetime.utcnow()}
        num_isos = 5
        num_isos_finished = 3
        iso_error_messages = {'an.iso': "No!"}
        error_message = 'This is an error message.'
        traceback = 'This is a traceback.'
        total_bytes = 1024
        finished_bytes = 512

        report = progress.SyncProgressReport(
            self.conduit, state=state, state_times=state_times, num_isos=num_isos,
            num_isos_finished=num_isos_finished, iso_error_messages=iso_error_messages,
            error_message=error_message, traceback=traceback, total_bytes=total_bytes,
            finished_bytes=finished_bytes)

        # Make sure all the appropriate attributes were set
        self.assertEqual(report.conduit, self.conduit)
        self.assertEqual(report._state, state)
        self.assertEqual(report.state_times, state_times)
        self.assertEqual(report.num_isos, num_isos)
        self.assertEqual(report.num_isos_finished, num_isos_finished)
        self.assertEqual(report.iso_error_messages, iso_error_messages)
        self.assertEqual(report.error_message, error_message)
        self.assertEqual(report.traceback, traceback)
        self.assertEqual(report.total_bytes, total_bytes)
        self.assertEqual(report.finished_bytes, finished_bytes)
    def test__display_iso_sync_report_during_iso_stage_no_isos(self):
        """
        Test the ISOStatusRenderer._display_iso_sync_report method when the SyncProgressReport
        has entered the ISO retrieval stage (with no ISOs to download) from the manifest retrieval
        stage. It should just tell the user there is nothing to do.
        """
        conduit = mock.MagicMock()
        sync_report = progress.SyncProgressReport(
            conduit,
            num_isos=0,
            state=progress.SyncProgressReport.STATE_ISOS_IN_PROGRESS)
        renderer = status.ISOStatusRenderer(self.context)
        # Let's put the renderer in the manifest retrieval stage, simulating the
        # SyncProgressReport having
        # just left that stage
        renderer._sync_state = progress.SyncProgressReport.STATE_MANIFEST_IN_PROGRESS
        renderer.prompt.reset_mock()

        renderer._display_iso_sync_report(sync_report)

        self.assertEqual(renderer.prompt.render_success_message.call_count, 1)
        self.assertTrue('no ISOs' in renderer.prompt.render_success_message.
                        mock_calls[0][1][0])
        self.assertEqual(
            renderer.prompt.render_success_message.mock_calls[0][2]['tag'],
            'none_to_download')
        # The _sync_state should have been updated to reflect the ISO downloading stage being
        # complete
        self.assertEqual(renderer._sync_state,
                         progress.SyncProgressReport.STATE_COMPLETE)
    def test__display_manifest_sync_report_manifest_failed(self):
        """
        Test behavior from _display_manifest_sync_report when the manifest failed to be retrieved.
        """
        conduit = mock.MagicMock()
        error_message = 'It broke.'
        sync_report = progress.SyncProgressReport(
            conduit,
            error_message=error_message,
            state=progress.SyncProgressReport.STATE_MANIFEST_FAILED)
        renderer = status.ISOStatusRenderer(self.context)
        # Let's also put the renderer in the manifest retrieval stage
        renderer._sync_state = progress.SyncProgressReport.STATE_NOT_STARTED
        renderer.prompt.reset_mock()

        renderer._display_manifest_sync_report(sync_report)

        # There should be two calls to mock. One to report the manifest failure, and one to
        # report the reason.
        self.assertEqual(len(renderer.prompt.mock_calls), 2)
        self.assertEqual(renderer.prompt.mock_calls[0][2]['tag'],
                         'manifest_failed')

        # Make sure we told the user the error message
        self.assertEqual(renderer.prompt.mock_calls[1][2]['tag'],
                         'manifest_error_message')
        # The specific error message passed from the sync_report should have been printed
        self.assertTrue(error_message in renderer.prompt.mock_calls[1][1][0])
예제 #6
0
    def test_add_failed_iso(self):
        """
        Test the add_failed_iso() method.
        """
        report = progress.SyncProgressReport(self.conduit)
        iso = mock.MagicMock()
        iso.name = 'error.iso'
        error_message = 'error message'

        report.add_failed_iso(iso, error_message)

        self.assertEqual(report.iso_error_messages, [{'name': iso.name, 'error': error_message}])
    def test__display_iso_sync_report_during_complete_stage(self):
        """
        Test the ISOStatusRenderer._display_iso_sync_report method when the SyncProgressReport
        has entered the
        COMPLETE state (with three ISOs successfully downloaded). It should display completion
        progress to the user.
        """
        conduit = mock.MagicMock()
        finished_bytes = 1204
        total_bytes = 1204
        state_times = {
            progress.SyncProgressReport.STATE_MANIFEST_IN_PROGRESS:
            datetime.utcnow()
        }
        sync_report = progress.SyncProgressReport(
            conduit,
            num_isos=3,
            num_isos_finished=3,
            total_bytes=total_bytes,
            finished_bytes=finished_bytes,
            state=progress.SyncProgressReport.STATE_COMPLETE,
            state_times=state_times)
        renderer = status.ISOStatusRenderer(self.context)
        # Let's put the renderer in the manifest retrieval stage, simulating the
        # SyncProgressReport having
        # just left that stage
        renderer._sync_state = progress.SyncProgressReport.STATE_MANIFEST_IN_PROGRESS
        renderer.prompt.reset_mock()

        renderer._display_iso_sync_report(sync_report)

        renderer.prompt.write.assert_has_call('Downloading 3 ISOs.')
        # The _sync_state should have been updated to reflect the ISO downloading stage being
        # complete
        self.assertEqual(renderer._sync_state,
                         progress.SyncProgressReport.STATE_COMPLETE)
        # A progress bar should have been rendered
        self.assertEqual(renderer._sync_isos_bar.render.call_count, 1)
        args = renderer._sync_isos_bar.render.mock_calls[0][1]
        self.assertEqual(args[0], finished_bytes)
        self.assertEqual(args[1], total_bytes)

        # There should be one kwarg - message. It is non-deterministic, so let's just assert that
        #  it has some
        # of the right text in it
        kwargs = renderer._sync_isos_bar.render.mock_calls[0][2]
        self.assertEqual(len(kwargs), 1)
        self.assertTrue('ISOs: 3/3' in kwargs['message'])

        # A completion message should have been printed for the user
        self.assertEqual(
            renderer.prompt.render_success_message.mock_calls[0][2]['tag'],
            'download_success')
    def test__display_manifest_sync_report_not_started(self):
        """
        Before the download starts, the _display_manifest_sync_report() method should not do
        anything.
        """
        conduit = mock.MagicMock()
        sync_report = progress.SyncProgressReport(
            conduit, state=progress.SyncProgressReport.STATE_NOT_STARTED)
        renderer = status.ISOStatusRenderer(self.context)
        # Let's also put the renderer in the manifest retrieval stage
        renderer._sync_state = progress.SyncProgressReport.STATE_NOT_STARTED
        renderer.prompt.reset_mock()

        renderer._display_manifest_sync_report(sync_report)

        self.assertEqual(len(renderer.prompt.mock_calls), 0)
예제 #9
0
    def test__set_state_iso_errors(self):
        """
        Test the state property as a setter for the situation when the state is marked as COMPLETE,
        but there are ISO errors. It should raise an exception with all the ISO errors.
        """
        report = progress.SyncProgressReport(
            self.conduit, iso_error_messages={'iso': 'error'},
            state=progress.SyncProgressReport.STATE_ISOS_IN_PROGRESS)

        # This should raise an Exception since there are ISO errors
        self.assertRaises(Exception, report._set_state, progress.SyncProgressReport.STATE_COMPLETE)

        self.assertEqual(report._state, progress.SyncProgressReport.STATE_ISOS_FAILED)
        self.assertTrue(report._state in report.state_times)
        self.assertTrue(isinstance(report.state_times[report._state], datetime))
        self.assertTrue(progress.SyncProgressReport.STATE_COMPLETE not in report.state_times)
        self.conduit.set_progress.assert_called_once_with(report.build_progress_report())
예제 #10
0
    def test__set_state_iso_errors(self):
        """
        Test the state property as a setter for the situation when the state is marked as COMPLETE,
        but there are ISO errors. It should automatically get set to ISOS_FAILED instead.
        """
        report = progress.SyncProgressReport(
            self.conduit, iso_error_messages={'iso': 'error'},
            state=progress.SyncProgressReport.STATE_ISOS_IN_PROGRESS)

        # This should trigger an automatic STATE_FAILED, since there are ISO errors
        report.state = progress.SyncProgressReport.STATE_COMPLETE

        self.assertEqual(report._state, progress.SyncProgressReport.STATE_ISOS_FAILED)
        self.assertTrue(report._state in report.state_times)
        self.assertTrue(isinstance(report.state_times[report._state], datetime))
        self.assertTrue(progress.SyncProgressReport.STATE_COMPLETE not in report.state_times)
        self.conduit.set_progress.assert_called_once_with(report.build_progress_report())
예제 #11
0
    def test__set_state_uncancelled(self):
        """
        We had a bug[0] wherein a cancelled sync would get set to complete after the transition to
        cancelled. Due to the nature of sync.py being able to set the state to cancelled
        asynchonously, it was difficult to avoid race conditions in sync.py itself. It turns out
        that it is much easier to ensure in the progress report that once STATE_CANCELLED is
        entered, it cannot be left. This test ensures that that is true.

        [0] https://bugzilla.redhat.com/show_bug.cgi?id=950772#c3
        """
        report = progress.SyncProgressReport(
            self.conduit, iso_error_messages={'iso': 'error'},
            state=progress.SyncProgressReport.STATE_CANCELLED)

        # This should not change the state away from cancelled
        report.state = progress.SyncProgressReport.STATE_COMPLETE

        self.assertEqual(report._state, progress.SyncProgressReport.STATE_CANCELLED)
        self.assertTrue(progress.SyncProgressReport.STATE_COMPLETE not in report.state_times)
    def test__display_iso_sync_report_during_manifest_stage(self):
        """
        Test the ISOStatusRenderer._display_iso_sync_report method when the SyncProgressReport is
        in the
        manifest retrieval stage. It should not display anything to the user.
        """
        conduit = mock.MagicMock()
        sync_report = progress.SyncProgressReport(
            conduit,
            state=progress.SyncProgressReport.STATE_MANIFEST_IN_PROGRESS)
        renderer = status.ISOStatusRenderer(self.context)
        # Let's also put the renderer in the manifest retrieval stage
        renderer._sync_state = progress.SyncProgressReport.STATE_MANIFEST_IN_PROGRESS
        renderer.prompt.reset_mock()

        renderer._display_iso_sync_report(sync_report)

        # Because we are in the manifest state, this method should not do anything with the prompt
        self.assertEqual(renderer.prompt.mock_calls, [])
    def test__display_manifest_sync_report_manifest_in_progress(self):
        """
        Test behavior from _display_manifest_sync_report when the manifest is currently in progress.
        """
        sync_report = progress.SyncProgressReport(
            None, state=progress.SyncProgressReport.STATE_MANIFEST_IN_PROGRESS)
        renderer = status.ISOStatusRenderer(self.context)
        # Let's also put the renderer in the manifest retrieval stage
        renderer._sync_state = progress.SyncProgressReport.STATE_NOT_STARTED
        renderer.prompt.reset_mock()

        renderer._display_manifest_sync_report(sync_report)

        # There should be one message printed to the user that tells them the manifest is being
        # downloaded
        self.assertEqual(len(renderer.prompt.mock_calls), 1)
        self.assertEqual(renderer.prompt.mock_calls[0][2]['tag'],
                         'downloading_manifest')
        # The renderer state should have been advanced to STATE_MANIFEST_IN_PROGRESS
        self.assertEqual(
            renderer._sync_state,
            progress.SyncProgressReport.STATE_MANIFEST_IN_PROGRESS)
    def test__display_manifest_sync_report_manifest_complete(self):
        """
        Test behavior from _display_manifest_sync_report when the manifest is complete.
        """
        sync_report = progress.SyncProgressReport(
            None, state=progress.SyncProgressReport.STATE_ISOS_IN_PROGRESS)
        renderer = status.ISOStatusRenderer(self.context)
        # Let's also put the renderer in the manifest retrieval stage
        renderer._sync_state = progress.SyncProgressReport.STATE_NOT_STARTED
        renderer.prompt.reset_mock()

        renderer._display_manifest_sync_report(sync_report)

        # There should be one message printed to the user that tells them the manifest is complete
        self.assertEqual(len(renderer.prompt.mock_calls), 1)
        self.assertEqual(renderer.prompt.mock_calls[0][2]['tag'],
                         'manifest_downloaded')
        # The renderer state should have been advanced to STATE_MANIFEST_IN_PROGRESS,
        # but not beyond, as
        # _display_iso_sync_report will move it into the next state
        self.assertEqual(
            renderer._sync_state,
            progress.SyncProgressReport.STATE_MANIFEST_IN_PROGRESS)
    def test__display_iso_sync_report_during_isos_failed_state(self):
        """
        Test the ISOStatusRenderer._display_iso_sync_report method when the SyncProgressReport has
        entered STATE_ISOS_FAILED (with two ISOs successfully downloaded). It should display an
        error message to the user.
        """
        conduit = mock.MagicMock()
        finished_bytes = 1204
        total_bytes = 908
        iso_error_messages = [{
            'name':
            'bad.iso',
            'error':
            'Sorry, I will not tell you what happened.'
        }]
        state_times = {
            progress.SyncProgressReport.STATE_MANIFEST_IN_PROGRESS:
            datetime.utcnow()
        }
        sync_report = progress.SyncProgressReport(
            conduit,
            num_isos=3,
            num_isos_finished=2,
            total_bytes=total_bytes,
            finished_bytes=finished_bytes,
            state=progress.SyncProgressReport.STATE_ISOS_FAILED,
            state_times=state_times,
            iso_error_messages=iso_error_messages)
        renderer = status.ISOStatusRenderer(self.context)
        # Let's put the renderer in the manifest retrieval stage, simulating the SyncProgressReport
        # having just left that stage
        renderer._sync_state = progress.SyncProgressReport.STATE_MANIFEST_IN_PROGRESS
        renderer.prompt.reset_mock()

        renderer._display_iso_sync_report(sync_report)

        renderer.prompt.write.assert_has_call('Downloading 3 ISOs.')
        # The _sync_state should have been updated to reflect the ISO downloading stage having
        # failed
        self.assertEqual(renderer._sync_state,
                         progress.SyncProgressReport.STATE_ISOS_FAILED)
        # A progress bar should have been rendered
        self.assertEqual(renderer._sync_isos_bar.render.call_count, 1)
        args = renderer._sync_isos_bar.render.mock_calls[0][1]
        self.assertEqual(args[0], finished_bytes)
        self.assertEqual(args[1], total_bytes)

        # There should be one kwarg - message. It is non-deterministic, so let's just assert that it
        # has some of the right text in it
        kwargs = renderer._sync_isos_bar.render.mock_calls[0][2]
        self.assertEqual(len(kwargs), 1)
        self.assertTrue('ISOs: 2/3' in kwargs['message'])

        # A completion message should have been printed for the user
        self.assertEqual(
            renderer.prompt.render_failure_message.mock_calls[0][2]['tag'],
            'download_failed')

        # The individual ISO that failed should have had its error message printed to screen
        self.assertTrue(iso_error_messages[0]['error'] in renderer.prompt.
                        render_failure_message.mock_calls[1][1][0])
        self.assertEqual(
            renderer.prompt.render_failure_message.mock_calls[1][2]['tag'],
            'iso_error_msg')