def test_sync_with_graceful_fail(self): # Setup sync_config = {'bruce': 'hulk', 'tony': 'ironman'} self.repo_manager.create_repo('repo-1') self.importer_manager.set_importer('repo-1', 'mock-importer', sync_config) mock_plugins.MOCK_IMPORTER.sync_repo.return_value = SyncReport( False, 10, 5, 1, 'Summary of the sync', 'Details of the sync') # Test self.assertRaises(PulpExecutionException, self.sync_manager.sync, 'repo-1') # Verify history = list(RepoSyncResult.get_collection().find( {'repo_id': 'repo-1'})) self.assertEqual(1, len(history)) self.assertEqual('repo-1', history[0]['repo_id']) self.assertEqual(RepoSyncResult.RESULT_FAILED, history[0]['result']) self.assertEqual('mock-importer', history[0]['importer_id']) self.assertEqual('mock-importer', history[0]['importer_type_id']) self.assertTrue(history[0]['started'] is not None) self.assertTrue(history[0]['completed'] is not None) # Cleanup mock_plugins.reset()
def build_cancel_report(self, summary, details): """ Creates the SyncReport instance that needs to be returned to the Pulp server at the end of a sync_repo call. The report built in this fashion will indicate the sync has been cancelled. The added, updated, and removed unit count fields will be populated with the tracking counters maintained by the conduit based on calls into it. If these are inaccurate for a given plugin's implementation, the counts can be changed in the returned report before returning it to Pulp. This data will capture how far it got before building the report and should be overridden if the plugin attempts to do some form of rollback due to the cancellation. @param summary: short log of the sync; may be None but probably shouldn't be @type summary: any serializable @param details: potentially longer log of the sync; may be None @type details: any serializable """ r = SyncReport(False, self._added_count, self._updated_count, self._removed_count, summary, details) r.canceled_flag = True return r
def build_success_report(self, summary, details): """ Creates the SyncReport instance that needs to be returned to the Pulp server at the end of a successful sync_repo call. The added, updated, and removed unit count fields will be populated with the tracking counters maintained by the conduit based on calls into it. If these are inaccurate for a given plugin's implementation, the counts can be changed in the returned report before returning it to Pulp. @param summary: short log of the sync; may be None but probably shouldn't be @type summary: any serializable @param details: potentially longer log of the sync; may be None @type details: any serializable """ r = SyncReport(True, self._added_count, self._updated_count, self._removed_count, summary, details) return r
def build_success_report(summary, details): return SyncReport(True, sync_conduit._added_count, sync_conduit._updated_count, sync_conduit._removed_count, summary, details)
def build_failure_report(summary, details): return SyncReport(False, sync_conduit._added_count, sync_conduit._updated_count, sync_conduit._removed_count, summary, details)
def build_failure_report(self, summary, details): return SyncReport(False, -1, -1, -1, summary, details)
def build_success_report(self, summary, details): return SyncReport(True, -1, -1, -1, summary, details)
def install(): """ Called during test setup to monkey patch the plugin loader for testing. """ # -- update plugin loader inventory --------------------------------------- plugin_api._create_manager() plugin_api._MANAGER.importers.add_plugin('mock-importer', MockImporter, {}) plugin_api._MANAGER.group_importers.add_plugin('mock-group-importer', MockGroupImporter, {}) plugin_api._MANAGER.distributors.add_plugin('mock-distributor', MockDistributor, {}) plugin_api._MANAGER.distributors.add_plugin('mock-distributor-2', MockDistributor, {}) plugin_api._MANAGER.group_distributors.add_plugin('mock-group-distributor', MockGroupDistributor, {}) plugin_api._MANAGER.group_distributors.add_plugin('mock-group-distributor-2', MockGroupDistributor, {}) plugin_api._MANAGER.profilers.add_plugin('mock-profiler', MockProfiler, {}) plugin_api._MANAGER.profilers.add_plugin('mock-rpm-profiler', MockRpmProfiler, {}) # -- return mock instances instead of ephemeral ones ---------------------- # Save the state of the original plugin loader so it can be reverted global _ORIG_GET_DISTRIBUTOR_BY_ID global _ORIG_GET_GROUP_DISTRIBUTOR_BY_ID global _ORIG_GET_IMPORTER_BY_ID global _ORIG_GET_GROUP_IMPORTER_BY_ID global _ORIG_GET_PROFILER_BY_TYPE _ORIG_GET_DISTRIBUTOR_BY_ID = plugin_api.get_distributor_by_id _ORIG_GET_GROUP_DISTRIBUTOR_BY_ID = plugin_api.get_group_distributor_by_id _ORIG_GET_IMPORTER_BY_ID = plugin_api.get_importer_by_id _ORIG_GET_GROUP_IMPORTER_BY_ID = plugin_api.get_group_importer_by_id _ORIG_GET_PROFILER_BY_TYPE = plugin_api.get_profiler_by_type # Setup the importer/distributor mappings that return the mock instances global DISTRIBUTOR_MAPPINGS DISTRIBUTOR_MAPPINGS = { 'mock-distributor' : MOCK_DISTRIBUTOR, 'mock-distributor-2' : MOCK_DISTRIBUTOR_2, } global GROUP_DISTRIBUTOR_MAPPINGS GROUP_DISTRIBUTOR_MAPPINGS = { 'mock-group-distributor' : MOCK_GROUP_DISTRIBUTOR, 'mock-group-distributor-2' : MOCK_GROUP_DISTRIBUTOR_2, } global IMPORTER_MAPPINGS IMPORTER_MAPPINGS = { 'mock-importer' : MOCK_IMPORTER } global GROUP_IMPORTER_MAPPINGS GROUP_IMPORTER_MAPPINGS = { 'mock-group-importer' : MOCK_GROUP_IMPORTER } global PROFILER_MAPPINGS PROFILER_MAPPINGS = {} for profiler in MOCK_PROFILERS: for t in profiler.metadata()['types']: PROFILER_MAPPINGS[t] = profiler # Return the mock instance; eventually can enhance this to support # multiple IDs and instances def mock_get_distributor_by_id(id): if id not in DISTRIBUTOR_MAPPINGS: raise plugin_exceptions.PluginNotFound() return DISTRIBUTOR_MAPPINGS[id], {} def mock_get_group_distributor_by_id(id): if id not in GROUP_DISTRIBUTOR_MAPPINGS: raise plugin_exceptions.PluginNotFound() return GROUP_DISTRIBUTOR_MAPPINGS[id], {} def mock_get_importer_by_id(id): if id not in IMPORTER_MAPPINGS: raise plugin_exceptions.PluginNotFound() return IMPORTER_MAPPINGS[id], {} def mock_get_group_importer_by_id(id): if id not in GROUP_IMPORTER_MAPPINGS: raise plugin_exceptions.PluginNotFound() return GROUP_IMPORTER_MAPPINGS[id], {} def mock_get_profiler_by_type(type): if type not in PROFILER_MAPPINGS: raise plugin_exceptions.PluginNotFound() return PROFILER_MAPPINGS[type], {} # Monkey patch in the mock methods plugin_api.get_distributor_by_id = mock_get_distributor_by_id plugin_api.get_group_distributor_by_id = mock_get_group_distributor_by_id plugin_api.get_importer_by_id = mock_get_importer_by_id plugin_api.get_group_importer_by_id = mock_get_group_importer_by_id plugin_api.get_profiler_by_type = mock_get_profiler_by_type # -- configure the mock instances ----------------------------------------- # By default, have the plugins indicate configurations are valid MOCK_IMPORTER.validate_config.return_value = True, None MOCK_IMPORTER.sync_repo.return_value = SyncReport(True, 10, 5, 1, 'Summary of the sync', 'Details of the sync') MOCK_GROUP_IMPORTER.validate_config.return_value = True, None MOCK_DISTRIBUTOR.validate_config.return_value = True, None MOCK_DISTRIBUTOR.publish_repo.return_value = PublishReport(True, 'Summary of the publish', 'Details of the publish') MOCK_DISTRIBUTOR_2.validate_config.return_value = True, None MOCK_DISTRIBUTOR_2.publish_repo.return_value = PublishReport(True, 'Summary of the publish', 'Details of the publish') MOCK_GROUP_DISTRIBUTOR.validate_config.return_value = True, None MOCK_GROUP_DISTRIBUTOR_2.validate_config.return_value = True, None for profiler in MOCK_PROFILERS: profiler.update_profile = \ mock.Mock(side_effect=lambda consumer,content_type,profile,config: profile) profiler.install_units = \ mock.Mock(side_effect=lambda i,u,o,c,x: sorted(u)) profiler.update_units = \ mock.Mock(side_effect=lambda i,u,o,c,x: sorted(u)) profiler.uninstall_units = \ mock.Mock(side_effect=lambda i,u,o,c,x: sorted(u)) profiler.calculate_applicable_units = \ mock.Mock(side_effect=lambda t,p,r,c,x: ['mocked-unit1', 'mocked-unit2'])
def sync_repo(self, *args, **kwargs): return SyncReport(True, 10, 5, 1, 'Summary of the sync', 'Details of the sync')