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)
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)
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])
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)
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())
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())
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')