diff --git a/README.rst b/README.rst index 4db0eed..748dc96 100644 --- a/README.rst +++ b/README.rst @@ -97,6 +97,12 @@ We've created an "easy button" for Ubuntu, Centos, RHEL and openSuSe. `upload` command, you can also override the RefStack API server uploaded to with the `--url` option. + Alternatively, you can use the 'upload-subunit' command to upload results + using an existing subunit file. This requires that you pass in the Keystone + endpoint URL for the cloud that was tested to generate the subunit data: + + `./refstack-client upload-subunit --keystone-endpoint http://some.url:5000/v3 ` + **Note:** a. Adding `-i ` option will upload test results with diff --git a/refstack_client/refstack_client.py b/refstack_client/refstack_client.py index 79f670b..57a6874 100755 --- a/refstack_client/refstack_client.py +++ b/refstack_client/refstack_client.py @@ -280,6 +280,12 @@ class RefstackClient: else: return inp.lower() in ('yes', 'y') + def _upload_prompt(self, upload_content): + if self._user_query('Test results will be uploaded to %s. ' + 'Ok?' % self.args.url): + self.post_results(self.args.url, upload_content, + sign_with=self.args.priv_key) + def get_passed_tests(self, result_file): '''Get a list of tests IDs that passed Tempest from a subunit file.''' subunit_processor = SubunitProcessor(result_file) @@ -407,10 +413,23 @@ class RefstackClient: json_file = open(self.upload_file) json_data = json.load(json_file) json_file.close() - if self._user_query('Test results will be uploaded to %s. ' - 'Ok?' % self.args.url): - self.post_results(self.args.url, json_data, - sign_with=self.args.priv_key) + self._upload_prompt(json_data) + + def upload_subunit(self): + '''Perform upload to RefStack URL from a subunit file.''' + self._prep_upload() + + cpid = self._generate_cpid_from_endpoint(self.args.keystone_endpoint) + # Forgo the duration for direct subunit uploads. + duration = 0 + + # Formulate JSON from subunit + results = self.get_passed_tests(self.upload_file) + self.logger.info('Number of passed tests in given subunit ' + 'file: %d ' % len(results)) + + content = self._form_result_content(cpid, duration, results) + self._upload_prompt(content) def yield_results(self, url, start_page=1, start_date='', end_date='', cpid=''): @@ -542,7 +561,7 @@ def parse_cli_args(args=None): # Upload command parser_upload = subparsers.add_parser( 'upload', parents=[shared_args, network_args], - help='Upload an existing result file.' + help='Upload an existing result JSON file.' ) parser_upload.add_argument('file', @@ -551,6 +570,28 @@ def parse_cli_args(args=None): parser_upload.set_defaults(func="upload") + # Upload-subunit command + parser_subunit_upload = subparsers.add_parser( + 'upload-subunit', parents=[shared_args, network_args], + help='Upload results from a subunit file.' + ) + + parser_subunit_upload.add_argument('file', + type=str, + help='Path of subunit file.') + + parser_subunit_upload.add_argument('--keystone-endpoint', + action='store', + required=True, + dest='keystone_endpoint', + type=str, + help='The Keystone URL of the cloud ' + 'the subunit results belong to. ' + 'This is used to generate a Cloud ' + 'Provider ID.') + + parser_subunit_upload.set_defaults(func="upload_subunit") + # Test command parser_test = subparsers.add_parser( 'test', parents=[shared_args, network_args], diff --git a/refstack_client/tests/unit/test_client.py b/refstack_client/tests/unit/test_client.py index 9dde12a..f62653d 100755 --- a/refstack_client/tests/unit/test_client.py +++ b/refstack_client/tests/unit/test_client.py @@ -551,6 +551,26 @@ class TestRefstackClient(unittest.TestCase): mock_input.return_value = 'yes' self.assertTrue(client._user_query('42?')) + def test_upload_prompt(self): + """ + Test the _upload_prompt method. + """ + client = rc.RefstackClient(rc.parse_cli_args(self.mock_argv())) + + # When user says yes. + client._user_query = MagicMock(return_value=True) + client.post_results = MagicMock() + client._upload_prompt({'some': 'data'}) + client.post_results.assert_called_with( + 'http://127.0.0.1', {'some': 'data'}, sign_with=None + ) + + # When user says no. + client._user_query = MagicMock(return_value=False) + client.post_results = MagicMock() + client._upload_prompt({'some': 'data'}) + self.assertFalse(client.post_results.called) + def test_post_results(self): """ Test the post_results method, ensuring a requests call is made. @@ -809,6 +829,31 @@ class TestRefstackClient(unittest.TestCase): expected_json, sign_with='rsa_key') + def test_subunit_upload(self): + """ + Test that the subunit upload command runs as expected. + """ + upload_file_path = self.test_path + "/.testrepository/0" + args = rc.parse_cli_args( + self.mock_argv(command='upload-subunit', priv_key='rsa_key') + + ['--keystone-endpoint', 'http://0.0.0.0:5000/v2.0'] + + [upload_file_path]) + client = rc.RefstackClient(args) + client.post_results = MagicMock() + client.upload_subunit() + expected_json = { + 'duration_seconds': 0, + 'cpid': hashlib.md5('0.0.0.0').hexdigest(), + 'results': [ + {'name': 'tempest.passed.test'}, + {'name': 'tempest.tagged_passed.test', + 'uuid': '0146f675-ffbd-4208-b3a4-60eb628dbc5e'} + ] + } + client.post_results.assert_called_with('http://127.0.0.1', + expected_json, + sign_with='rsa_key') + def test_upload_nonexisting_file(self): """ Test when the file to be uploaded does not exist.