def cli(ctx, verbose, insecure, json): """Stasis command-line client.""" logging.basicConfig( format='[%(asctime)-15s] [%(levelname)s] [%(name)-5s]: %(message)s', level=logging.getLevelName(logging.DEBUG if verbose else logging.INFO) ) if not verbose: # suppress warning as self-signed certs are unlikely to have a SAN urllib3.disable_warnings(urllib3.exceptions.SubjectAltNameWarning) # suppress logging warnings logging.getLogger("urllib3").setLevel(logging.ERROR) application_name = 'stasis-client' application_main_class = 'stasis.client.Main' config_file_name = 'client.conf' api_token_file_name = 'api-token' config = load_client_config(application_name=application_name, config_file_name=config_file_name) api_token = load_api_token(application_name=application_name, api_token_file_name=api_token_file_name) context = ctx.ensure_object(Context) context.api = create_client_api(config=config, api_token=api_token, insecure=insecure) context.init = create_init_api(config=config, insecure=insecure, client_api=context.api) context.service_binary = application_name context.service_main_class = application_main_class context.rendering = JsonWriter() if json else DefaultWriter()
def test_should_start_background_service(self, mock_sleep, mock_popen, mock_process_iter): context = Context() context.api = InactiveClientApi() context.init = MockInitApi(state_responses=[mock_data.INIT_STATE_PENDING, mock_data.INIT_STATE_SUCCESSFUL]) context.rendering = JsonWriter() context.service_binary = 'test-name' context.service_main_class = 'test.name.Main' mock_process_iter.return_value = [] mock_popen.return_value = None mock_sleep.return_value = None username = '******' password = '******' runner = Runner(cli) result = runner.invoke( args=['start', '--username', username, '--password', password], obj=context ) self.assertEqual(result.exit_code, 0, result.output) self.assertDictEqual(json.loads(result.output), {'successful': True}) mock_popen.assert_called_once() mock_sleep.assert_called_once() self.assertEqual(context.init.stats['state'], 2) self.assertEqual(context.init.stats['provide_credentials'], 1)
def test_should_poll_init_state_when_starting_background_service(self, mock_sleep, mock_popen, mock_process_iter): expected_retries = 10 state_responses = [mock_data.INIT_STATE_PENDING] * (expected_retries + 1) context = Context() context.api = InactiveClientApi() context.init = MockInitApi(state_responses=state_responses) context.rendering = JsonWriter() context.service_binary = 'test-name' context.service_main_class = 'test.name.Main' mock_process_iter.return_value = [] mock_popen.return_value = None mock_sleep.return_value = None username = '******' password = '******' runner = Runner(cli) result = runner.invoke( args=['start', '--username', username, '--password', password], obj=context ) self.assertEqual(result.exit_code, 0, result.output) self.assertDictEqual( json.loads(result.output), {'successful': False, 'failure': 'Initialization did not complete; last state received was [pending]'} ) mock_popen.assert_called_once() self.assertEqual(mock_sleep.call_count, expected_retries) self.assertEqual(context.init.stats['state'], expected_retries + 1) self.assertEqual(context.init.stats['provide_credentials'], 1)
def test_should_fail_define_backups_when_invalid_duration_specified(self): context = Context() context.api = MockClientApi() context.rendering = JsonWriter() runner = Runner(cli) result = runner.invoke(args=[ 'define', '--info', 'test', '--redundant-copies', 5, '--existing-versions-policy', 'at-most', '--existing-versions-duration', 'invalid', '--removed-versions-policy', 'all', '--removed-versions-duration', '5 hours', ], obj=context) self.assertEqual(result.exit_code, 2, result.output) self.assertIn('expected valid duration format', result.output)
def test_should_define_backups(self, mock_prompt): context = Context() context.api = MockClientApi() context.rendering = JsonWriter() mock_prompt.return_value = 5 runner = Runner(cli) result = runner.invoke(args=[ 'define', '--info', 'test', '--redundant-copies', 5, '--existing-versions-policy', 'at-most', '--existing-versions-duration', '30 days', '--removed-versions-policy', 'all', '--removed-versions-duration', '5 hours', ], obj=context) self.assertEqual(result.exit_code, 0, result.output) self.assertTrue(json.loads(result.output)) self.assertEqual(context.api.stats['device'], 1) self.assertEqual(context.api.stats['backup_define'], 1)
def test_should_follow_operations(self): context = Context() context.api = MockClientApi() context.rendering = JsonWriter() runner = Runner(cli) result = runner.invoke(args=['follow', str(uuid4())], obj=context) self.assertEqual(result.exit_code, 0, result.output) self.assertEqual(context.api.stats['operation_follow'], 1)
def test_should_start_backups(self): context = Context() context.api = MockClientApi() context.rendering = JsonWriter() runner = Runner(cli) result = runner.invoke(args=['start', str(uuid4())], obj=context) self.assertEqual(result.exit_code, 0, result.output) self.assertTrue(json.loads(result.output)) self.assertEqual(context.api.stats['backup_start'], 1)
def test_should_refresh_configured_schedules(self): context = Context() context.api = MockClientApi() context.rendering = JsonWriter() runner = Runner(cli) result = runner.invoke(args=['refresh'], obj=context) self.assertEqual(result.exit_code, 0, result.output) self.assertTrue(json.loads(result.output)) self.assertEqual(context.api.stats['schedules_configured_refresh'], 1)
def test_should_show_current_device(self): context = Context() context.api = MockClientApi() context.rendering = JsonWriter() runner = Runner(cli) result = runner.invoke(args=['status', 'device'], obj=context) self.assertEqual(result.exit_code, 0, result.output) self.assertTrue(json.loads(result.output)) self.assertEqual(context.api.stats['device'], 1)
def test_should_start_backups_and_follow_their_progress(self): context = Context() context.api = MockClientApi() context.rendering = JsonWriter() runner = Runner(cli) result = runner.invoke(args=['start', str(uuid4()), '--follow'], obj=context) self.assertEqual(result.exit_code, 0, result.output) self.assertEqual(context.api.stats['backup_start'], 1)
def test_should_support_skipping_confirmation_when_stopping_background_service(self): context = Context() context.api = MockClientApi() context.rendering = JsonWriter() context.service_binary = 'test-name' context.service_main_class = 'test.name.Main' runner = Runner(cli) result = runner.invoke(args=['stop', '--confirm'], obj=context) self.assertEqual(result.exit_code, 0, result.output) self.assertDictEqual(json.loads(result.output), {'successful': True}) self.assertEqual(context.api.stats['stop'], 1)
def test_should_search_metadata(self): context = Context() context.api = MockClientApi() context.rendering = JsonWriter() runner = Runner(cli) result = runner.invoke( args=['search', 'test.*', '-u', '2020-02-02 02:02:02'], obj=context) self.assertEqual(result.exit_code, 0, result.output) self.assertTrue(json.loads(result.output)) self.assertEqual(context.api.stats['dataset_metadata_search'], 1)
def test_should_stop_operations(self, mock_confirm): context = Context() context.api = MockClientApi() context.rendering = JsonWriter() mock_confirm.return_value = None runner = Runner(cli) result = runner.invoke(args=['stop', str(uuid4())], obj=context) self.assertEqual(result.exit_code, 0, result.output) self.assertTrue(json.loads(result.output)) self.assertEqual(context.api.stats['operation_stop'], 1)
def test_should_show_entries(self): context = Context() context.api = MockClientApi() context.rendering = JsonWriter() runner = Runner(cli) result = runner.invoke(args=['show', 'entries'], obj=context) self.assertEqual(result.exit_code, 0, result.output) self.assertTrue(json.loads(result.output)) self.assertEqual(context.api.stats['dataset_entries'], 1) self.assertEqual(context.api.stats['dataset_entries_for_definition'], 0)
def test_should_stop_background_service(self, mock_confirm): context = Context() context.api = MockClientApi() context.rendering = JsonWriter() context.service_binary = 'test-name' context.service_main_class = 'test.name.Main' mock_confirm.return_value = None runner = Runner(cli) result = runner.invoke(args=['stop'], obj=context) self.assertEqual(result.exit_code, 0, result.output) self.assertDictEqual(json.loads(result.output), {'successful': True}) self.assertEqual(context.api.stats['stop'], 1)
def test_should_stop_background_service_processes(self, mock_process_iter, mock_confirm): context = Context() context.api = InactiveClientApi() context.rendering = JsonWriter() context.service_binary = 'test-name' context.service_main_class = 'test.name.Main' process = MockProcess() mock_process_iter.return_value = [process] mock_confirm.return_value = None runner = Runner(cli) result = runner.invoke(args=['stop'], obj=context) self.assertEqual(result.exit_code, 0, result.output) self.assertDictEqual(json.loads(result.output), {'successful': True}) self.assertEqual(process.kill_count, 1)
def test_should_not_stop_background_service_when_not_running(self, mock_process_iter, mock_confirm): context = Context() context.api = InactiveClientApi() context.rendering = JsonWriter() context.service_binary = 'test-name' context.service_main_class = 'test.name.Main' mock_process_iter.return_value = [] mock_confirm.return_value = None runner = Runner(cli) result = runner.invoke(args=['stop'], obj=context) self.assertEqual(result.exit_code, 0, result.output) self.assertDictEqual( json.loads(result.output), {'successful': False, 'failure': 'Background service is not active'} )
def test_should_not_start_background_service_when_already_running(self): context = Context() context.api = MockClientApi() context.init = InactiveInitApi() context.rendering = JsonWriter() context.service_binary = 'test-name' context.service_main_class = 'test.name.Main' username = '******' password = '******' runner = Runner(cli) result = runner.invoke(args=['start', '--username', username, '--password', password], obj=context) self.assertEqual(result.exit_code, 0, result.output) self.assertDictEqual( json.loads(result.output), {'successful': False, 'failure': 'Background service is already active'} )
def test_should_fail_starting_background_service_if_init_already_failed( self, mock_sleep, mock_popen, mock_process_iter ): state_responses = [ mock_data.INIT_STATE_FAILED, ] context = Context() context.api = InactiveClientApi() context.init = MockInitApi(state_responses=state_responses) context.rendering = JsonWriter() context.service_binary = 'test-name' context.service_main_class = 'test.name.Main' mock_process_iter.return_value = [] mock_popen.return_value = None mock_sleep.return_value = None username = '******' password = '******' runner = Runner(cli) result = runner.invoke( args=['start', '--username', username, '--password', password], obj=context ) self.assertEqual(result.exit_code, 0, result.output) self.assertDictEqual( json.loads(result.output), {'successful': False, 'failure': 'No or invalid credentials provided'} ) mock_popen.assert_called_once() self.assertEqual(mock_sleep.call_count, 0) self.assertEqual(context.init.stats['state'], 1) self.assertEqual(context.init.stats['provide_credentials'], 0)
def test_should_not_start_background_service_when_process_already_running(self, mock_process_iter): context = Context() context.api = InactiveClientApi() context.init = MockInitApi() context.rendering = JsonWriter() context.service_binary = 'test-name' context.service_main_class = 'test.name.Main' process = MockProcess() mock_process_iter.return_value = [process] username = '******' password = '******' runner = Runner(cli) result = runner.invoke(args=['start', '--username', username, '--password', password], obj=context) self.assertEqual(result.exit_code, 0, result.output) self.assertDictEqual( json.loads(result.output), {'successful': False, 'failure': 'Unexpected background service process(es) found'} )
def test_should_show_metadata(self): context = Context() context.api = MockClientApi() context.rendering = JsonWriter() runner = Runner(cli) result_changes = runner.invoke( args=['show', 'metadata', str(uuid4()), 'changes'], obj=context) result_crates = runner.invoke( args=['show', 'metadata', str(uuid4()), 'crates'], obj=context) result_filesystem = runner.invoke( args=['show', 'metadata', str(uuid4()), 'fs'], obj=context) self.assertEqual(result_changes.exit_code, 0, result_changes.output) self.assertTrue(json.loads(result_changes.output)) self.assertEqual(result_crates.exit_code, 0, result_crates.output) self.assertTrue(json.loads(result_crates.output)) self.assertEqual(result_filesystem.exit_code, 0, result_filesystem.output) self.assertTrue(json.loads(result_filesystem.output)) self.assertEqual(context.api.stats['dataset_metadata'], 3)
def test_should_show_backup_rules(self): context = Context() context.api = MockClientApi() context.rendering = JsonWriter() runner = Runner(cli) result_matched_included = runner.invoke( args=['show', 'rules', 'included'], obj=context) result_matched_excluded = runner.invoke( args=['show', 'rules', 'excluded'], obj=context) result_unmatched = runner.invoke(args=['show', 'rules', 'unmatched'], obj=context) self.assertEqual(result_matched_included.exit_code, 0, result_matched_included.output) self.assertTrue(json.loads(result_matched_included.output)) self.assertEqual(result_matched_excluded.exit_code, 0, result_matched_excluded.output) self.assertTrue(json.loads(result_matched_excluded.output)) self.assertEqual(result_unmatched.exit_code, 0, result_unmatched.output) self.assertTrue(json.loads(result_unmatched.output)) self.assertEqual(context.api.stats['backup_rules'], 3)
def test_should_render_operation_response(self): self.assertTrue(JsonWriter().render_operation_response( response={ 'successful': True, 'operation': 'test-operation' }))
def test_should_render_operation_progress(self): self.assertTrue(JsonWriter().render_operation_progress( progress=mock_data.OPERATION_PROGRESS[-1]))
def test_should_render_backup_rules_matched(self): self.assertTrue(JsonWriter().render_backup_rules_matched( state='included', rules=mock_data.BACKUP_RULES)) self.assertTrue(JsonWriter().render_backup_rules_matched( state='excluded', rules=mock_data.BACKUP_RULES))
def test_should_render_backup_rules_unmatched(self): self.assertTrue(JsonWriter().render_backup_rules_unmatched( rules=mock_data.BACKUP_RULES))
def test_should_render_public_schedules(self): self.assertTrue(JsonWriter().render_public_schedules( public_schedules=mock_data.SCHEDULES_PUBLIC))
def test_should_render_configured_schedules(self): self.assertTrue(JsonWriter().render_configured_schedules( configured_schedules=mock_data.SCHEDULES_CONFIGURED))
def test_should_render_dataset_definitions(self): self.assertTrue(JsonWriter().render_dataset_definitions( definitions=mock_data.DEFINITIONS))
def test_should_render_user(self): self.assertTrue(JsonWriter().render_user(user=mock_data.USER))