diff --git a/airship_tempest_plugin/hacking/checks.py b/airship_tempest_plugin/hacking/checks.py index 7108543..3f687e3 100644 --- a/airship_tempest_plugin/hacking/checks.py +++ b/airship_tempest_plugin/hacking/checks.py @@ -144,7 +144,7 @@ def no_rbac_rule_validation_decorator(physical_line, filename): """ global have_rbac_decorator - if ("airship_tempest_plugin/tests/api/rbac" in filename or + if ("airship_tempest_plugin/tests/api/shipyard/rbac" in filename or "airship_tempest_plugin/tests/scenario" in filename): if RULE_VALIDATION_DECORATOR.match(physical_line): @@ -163,7 +163,7 @@ def no_rbac_suffix_in_test_filename(filename): """Check that RBAC filenames end with "_rbac" suffix. P101 """ - if "airship_tempest_plugin/tests/api" in filename: + if "airship_tempest_plugin/tests/api/shipyard/rbac" in filename: if filename.endswith('rbac_base.py'): return @@ -176,7 +176,7 @@ def no_rbac_test_suffix_in_test_class_name(physical_line, filename): """Check that RBAC class names end with "RbacTest" P102 """ - if "airship_tempest_plugin/tests/api/rbac/" in filename: + if "airship_tempest_plugin/tests/api/shipyard/rbac" in filename: if filename.endswith('rbac_base.py'): return @@ -190,7 +190,7 @@ def no_client_alias_in_test_cases(logical_line, filename): """Check that test cases don't use "self.client" to define a client. P103 """ - if "airship_tempest_plugin/tests/api" in filename: + if "airship_tempest_plugin/tests/api/" in filename: if "self.client" in logical_line or "cls.client" in logical_line: return 0, "Do not use 'self.client' as a service client alias" diff --git a/airship_tempest_plugin/services/shipyard/json/actions_client.py b/airship_tempest_plugin/services/shipyard/json/actions_client.py index 1cd3a50..084968b 100644 --- a/airship_tempest_plugin/services/shipyard/json/actions_client.py +++ b/airship_tempest_plugin/services/shipyard/json/actions_client.py @@ -22,6 +22,7 @@ from tempest.lib.common import rest_client + # NOTE(rb560u): The following will need to be rewritten in the future if # functional testing is desired: # - 'def create_action` @@ -37,7 +38,10 @@ def list_actions(self): resp, body = self.get('actions') self.expected_success(200, resp.status) body = json.loads(body) - return rest_client.ResponseBody(resp, body) + if isinstance(body, list): + return rest_client.ResponseBodyList(resp, body) + else: + return rest_client.ResponseBody(resp, body) def create_action(self, action=None): url = 'actions' diff --git a/airship_tempest_plugin/services/shipyard/json/airflow_monitoring_client.py b/airship_tempest_plugin/services/shipyard/json/airflow_monitoring_client.py index e419fdb..7b0d487 100644 --- a/airship_tempest_plugin/services/shipyard/json/airflow_monitoring_client.py +++ b/airship_tempest_plugin/services/shipyard/json/airflow_monitoring_client.py @@ -19,7 +19,6 @@ """ from oslo_serialization import jsonutils as json - from tempest.lib.common import rest_client @@ -30,7 +29,10 @@ def list_workflows(self): resp, body = self.get('workflows') self.expected_success(200, resp.status) body = json.loads(body) - return rest_client.ResponseBody(resp, body) + if isinstance(body, list): + return rest_client.ResponseBodyList(resp, body) + else: + return rest_client.ResponseBody(resp, body) def get_workflow(self, workflow_id=None): resp, body = self.get('workflows/%s' % workflow_id) diff --git a/airship_tempest_plugin/services/shipyard/json/document_staging_client.py b/airship_tempest_plugin/services/shipyard/json/document_staging_client.py index 2f33140..e0014db 100644 --- a/airship_tempest_plugin/services/shipyard/json/document_staging_client.py +++ b/airship_tempest_plugin/services/shipyard/json/document_staging_client.py @@ -19,9 +19,9 @@ """ from oslo_serialization import jsonutils as json - from tempest.lib.common import rest_client + # NOTE(rb560u): The following will need to be rewritten in the future if # functional testing is desired: # - 'def create_configdocs` @@ -37,7 +37,10 @@ def get_configdocs_status(self): resp, body = self.get('configdocs') self.expected_success(200, resp.status) body = json.loads(body) - return rest_client.ResponseBody(resp, body) + if isinstance(body, list): + return rest_client.ResponseBodyList(resp, body) + else: + return rest_client.ResponseBody(resp, body) def create_configdocs(self, collection_id=None): url = "configdocs/%s" % collection_id @@ -52,13 +55,30 @@ def get_configdocs(self, collection_id=None): resp, body = self.get('configdocs/%s' % collection_id) self.expected_success(200, resp.status) body = json.loads(body) - return rest_client.ResponseBody(resp, body) + if isinstance(body, list): + return rest_client.ResponseBodyList(resp, body) + else: + return rest_client.ResponseBody(resp, body) + + def get_configdocs_version(self, collection_id=None, version_arg=None): + resp, body = self.get('configdocs/%s?version=%s' % + (collection_id, version_arg)) + self.expected_success(200, resp.status) + return rest_client.ResponseBodyData(resp, body) def get_renderedconfigdocs(self): resp, body = self.get('renderedconfigdocs') self.expected_success(200, resp.status) body = json.loads(body) - return rest_client.ResponseBody(resp, body) + if isinstance(body, list): + return rest_client.ResponseBodyList(resp, body) + else: + return rest_client.ResponseBody(resp, body) + + def get_renderedconfigdocs_version(self, version_arg=None): + resp, body = self.get('renderedconfigdocs?version=%s' % version_arg) + self.expected_success(200, resp.status) + return rest_client.ResponseBodyData(resp, body) def commit_configdocs(self, force=False, dryrun=False): post_body = json.dumps({"force": force, "dryrun": dryrun}) @@ -66,3 +86,12 @@ def commit_configdocs(self, force=False, dryrun=False): self.expected_success(200, resp.status) body = json.loads(body) return rest_client.ResponseBody(resp, body) + + def get_configdocs_compare_two(self, version_arg=None): + resp, body = self.get('configdocs?%s' % version_arg) + self.expected_success(200, resp.status) + body = json.loads(body) + if isinstance(body, list): + return rest_client.ResponseBodyList(resp, body) + else: + return rest_client.ResponseBody(resp, body) diff --git a/airship_tempest_plugin/services/shipyard/json/log_retrieval_client.py b/airship_tempest_plugin/services/shipyard/json/log_retrieval_client.py index d36d0b1..217bfc0 100644 --- a/airship_tempest_plugin/services/shipyard/json/log_retrieval_client.py +++ b/airship_tempest_plugin/services/shipyard/json/log_retrieval_client.py @@ -18,8 +18,6 @@ http://airship-shipyard.readthedocs.io/en/latest/API.html#airflow-monitoring-api """ -from oslo_serialization import jsonutils as json - from tempest.lib.common import rest_client @@ -30,5 +28,4 @@ def get_action_step_logs(self, action_id=None, step_id=None): resp, body = \ self.get('actions/%s/steps/%s/logs' % (action_id, step_id)) self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) + return rest_client.ResponseBodyData(resp, body) diff --git a/airship_tempest_plugin/services/shipyard/json/site_statuses_client.py b/airship_tempest_plugin/services/shipyard/json/site_statuses_client.py index 67146a6..51696d7 100644 --- a/airship_tempest_plugin/services/shipyard/json/site_statuses_client.py +++ b/airship_tempest_plugin/services/shipyard/json/site_statuses_client.py @@ -19,8 +19,8 @@ """ from oslo_serialization import jsonutils as json - from tempest.lib.common import rest_client +from tempest.lib import decorators class SiteStatusesClient(rest_client.RestClient): @@ -32,3 +32,8 @@ def get_site_statuses(self): self.expected_success(200, resp.status) body = json.loads(body) return rest_client.ResponseBody(resp, body) + + def get_site_statuses_arg(self, args=None): + resp, body = self.get('site_statuses?filters=%s' % args) + self.expected_success(200, resp.status) + return rest_client.ResponseBodyData(resp, body) diff --git a/airship_tempest_plugin/tests/api/shipyard/test_actions.py b/airship_tempest_plugin/tests/api/shipyard/test_actions.py index 272d225..5e316c5 100644 --- a/airship_tempest_plugin/tests/api/shipyard/test_actions.py +++ b/airship_tempest_plugin/tests/api/shipyard/test_actions.py @@ -15,17 +15,14 @@ # from airship_tempest_plugin.tests.api.shipyard import base - from tempest.lib import decorators class ActionsTest(base.BaseShipyardTest): - def _get_action_id(self): resp = self.shipyard_actions_client.list_actions() self.assertTrue(len(resp[1]) > 0, 'No actions available, nothing to test') - # get the response body return resp[1]['id'] def _get_action_step_id(self): @@ -48,6 +45,7 @@ def test_get_action(self): """Get actions, Successful with response status 200""" resp = self.shipyard_actions_client.get_action(action_id) self.assertEqual(resp.response['status'], '200') + self.assertEqual(resp.values()[0][0]['action_id'], action_id) @decorators.idempotent_id('a8bc9e6b-bfa3-4635-a1ec-0b9ddc9cb03f') def test_get_action_step(self): @@ -55,3 +53,4 @@ def test_get_action_step(self): action_id, step_id = self._get_action_step_id() resp = self.shipyard_actions_client.get_action_step(action_id, step_id) self.assertEqual(resp.response['status'], '200') + self.assertEqual(resp['task_id'], step_id) diff --git a/airship_tempest_plugin/tests/api/shipyard/test_airflow_monitoring.py b/airship_tempest_plugin/tests/api/shipyard/test_airflow_monitoring.py new file mode 100644 index 0000000..272386b --- /dev/null +++ b/airship_tempest_plugin/tests/api/shipyard/test_airflow_monitoring.py @@ -0,0 +1,41 @@ +# Copyright 2018 AT&T Corp +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +from airship_tempest_plugin.tests.api.shipyard import base +from tempest.lib import decorators + + +class AirflowMonitoringTest(base.BaseShipyardTest): + def _get_workflows_id(self): + resp = self.shipyard_airflow_monitoring_client.list_workflows() + self.assertTrue(len(resp[0]) > 0, + 'No configdocs available, nothing to test') + return resp[0]['workflow_id'] + + @decorators.idempotent_id('5a41bb54-c010-4d09-9d68-eece565e66f3') + def test_get_workflows_list(self): + """List of workflows, Successful with response status 200""" + response = self.shipyard_airflow_monitoring_client.list_workflows() + self.assertEqual(response.response['status'], '200') + + @decorators.idempotent_id('7e4fb56b-6637-48bf-808d-c166ee5f804f') + def test_get_workflow(self): + """A particular workflow detail, Successful with response status 200""" + workflow_id = self._get_workflows_id() + response = self.shipyard_airflow_monitoring_client. \ + get_workflow(workflow_id) + self.assertEqual(response.response['status'], '200') + self.assertEqual(response['workflow_id'], workflow_id) diff --git a/airship_tempest_plugin/tests/api/shipyard/test_document_staging.py b/airship_tempest_plugin/tests/api/shipyard/test_document_staging.py new file mode 100644 index 0000000..451bdf8 --- /dev/null +++ b/airship_tempest_plugin/tests/api/shipyard/test_document_staging.py @@ -0,0 +1,192 @@ +# Copyright 2018 AT&T Corp +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +import logging +from airship_tempest_plugin.tests.api.shipyard import base +from tempest.lib import decorators +from tempest.lib import exceptions + +logger = logging.getLogger(__name__) +handler = logging.FileHandler('testLog/shipyard_api.log') +handler.setLevel(logging.INFO) +formatter = logging.Formatter('%(asctime)s - %(name)s - %(funcName)s - \ + %(levelname)s - %(message)s') +handler.setFormatter(formatter) +logger.addHandler(handler) + + +class DocumentStagingTest(base.BaseShipyardTest): + def _get_collection_id(self): + resp = self.shipyard_document_staging_client.get_configdocs_status() + self.assertTrue(len(resp[0]) > 0, + 'No configdocs available, nothing to test') + return resp[0]['collection_name'] + + @decorators.idempotent_id('db351ee5-a608-4492-b705-6e6c654a60e7') + def test_get_collection_list(self): + """Config docs status, Successful with response status 200""" + response = self.shipyard_document_staging_client. \ + get_configdocs_status() + self.assertEqual(response.response['status'], '200') + + @decorators.idempotent_id('743ab304-be35-4e45-ad47-e124dce3b9dc') + def test_get_collection(self): + """Get Config docs for a particular collection, Successful with + response status 200. + In case document does not found, return 404 Not Found + """ + collection_id = self._get_collection_id() + try: + response = self.shipyard_document_staging_client. \ + get_configdocs(collection_id) + self.assertEqual(response.response['status'], '200') + self.assertTrue(len(response[0]) > 0, + 'No configdocs available, nothing to test') + except exceptions.NotFound: + logger.info("The Shipyard buffer does not contain this collection") + pass + + @decorators.idempotent_id('bd138747-582e-4c2e-9f26-09c3fccad96f') + def test_get_collection_version_buffer(self): + """Get Config docs of buffer version, + Successful with response status 200 + In case document does not found, return 404 Not Found + """ + collection_id = self._get_collection_id() + try: + response = self.shipyard_document_staging_client. \ + get_configdocs_version(collection_id, "buffer") + self.assertEqual(response.response['status'], '200') + self.assertTrue(len(response.data) > 0, 'No configdocs of \ + buffer version available') + except exceptions.NotFound: + logger.info("The Shipyard buffer does not contain this collection") + pass + + @decorators.idempotent_id('d42c691a-07a2-41cc-91a6-9d02be8f2649') + def test_get_collection_version_committed(self): + """Get Config docs of committed version, + Successful with response status 200 + """ + collection_id = self._get_collection_id() + response = self.shipyard_document_staging_client. \ + get_configdocs_version(collection_id, "committed") + self.assertEqual(response.response['status'], '200') + self.assertTrue(len(response.data) > 0, 'No configdocs of \ + committed version available') + + @decorators.idempotent_id('2940492a-47b0-4218-859a-b9cb556f480b') + def test_get_collection_version_successful_site_action(self): + """Get Config docs of successful_site_action version, + Successful with response status 200 + """ + collection_id = self._get_collection_id() + response = self.shipyard_document_staging_client. \ + get_configdocs_version(collection_id, "successful_site_action") + self.assertEqual(response.response['status'], '200') + self.assertTrue(len(response.data) > 0, 'No configdocs of \ + successful_site_action version available') + + @decorators.idempotent_id('f6b86b85-5797-4664-95a9-0b6d242b50b7') + def test_get_collection_version_last_site_action(self): + """Get Config docs of last_site_action, + Successful with response status 200 + """ + collection_id = self._get_collection_id() + response = self.shipyard_document_staging_client. \ + get_configdocs_version(collection_id, "last_site_action") + self.assertEqual(response.response['status'], '200') + self.assertTrue(len(response.data) > 0, 'No configdocs of \ + last_site_action version available') + + @decorators.idempotent_id('2db31479-8d1f-4d95-a3a0-31b1bf726f39') + def test_get_renderedconfigdocs(self): + """Get RenderedConfig docs, Successful with response status 200 + In case document does not found, return 404 Not Found + """ + try: + response = self.shipyard_document_staging_client. \ + get_renderedconfigdocs() + self.assertEqual(response.response['status'], '200') + self.assertTrue(len(response[1]) > 0, 'No RenderedConfig docs available') + except exceptions.NotFound: + logger.info("buffer version does not exist") + pass + + @decorators.idempotent_id('ffd9d1d9-9846-4493-9f9e-e35f12ce56da') + def test_get_renderedconfigdocs_version_buffer(self): + """Get RenderedConfig docs of buffer version, + Successful with response status 200 + In case document does not found, return 404 Not Found + """ + try: + response = self.shipyard_document_staging_client. \ + get_renderedconfigdocs_version("buffer") + self.assertEqual(response.response['status'], '200') + self.assertTrue(len(response.data) > 0, 'No renderedconfigdocs of \ + buffer version available') + except exceptions.NotFound: + logger.info("buffer version does not exist") + pass + + @decorators.idempotent_id('353e9955-7f12-4561-a3c2-c9819f259775') + def test_get_renderedconfigdocs_version_committed(self): + """Get RenderedConfig docs of committed version, + Successful with response status 200 + """ + response = self.shipyard_document_staging_client. \ + get_renderedconfigdocs_version("committed") + self.assertEqual(response.response['status'], '200') + self.assertTrue(len(response.data) > 0, 'No renderedconfigdocs of \ + committed version available') + + @decorators.idempotent_id('3daac942-baec-4078-a632-71b66dca1e91') + def test_get_renderedconfigdocs_version_successful_site_action(self): + """Get RenderedConfig docs of successful_site_action version, + Successful with response status 200 + In case document does not found, return 404 Not Found + """ + try: + response = self.shipyard_document_staging_client. \ + get_renderedconfigdocs_version("successful_site_action") + self.assertEqual(response.response['status'], '200') + self.assertTrue(len(response.data) > 0, 'No renderedconfigdocs of \ + successful_site_action version available') + except exceptions.NotFound: + logger.info("This revision does not exist") + pass + + @decorators.idempotent_id('9af56232-eacf-4baa-85e9-cbb93772974d') + def test_get_renderedconfigdocs_version_last_site_action(self): + """Get RenderedConfig docs of last_site_action, + Successful with response status 200 + """ + response = self.shipyard_document_staging_client. \ + get_renderedconfigdocs_version("last_site_action") + self.assertEqual(response.response['status'], '200') + self.assertTrue(len(response.data) > 0, 'No renderedconfigdocs of \ + last_site_action version available') + + @decorators.idempotent_id('1aedf793-dde4-49df-a6d2-109bc11b6db5') + def test_get_collection_compare_two_revisions_doc(self): + """Get Config docs of two versions and compare in between, + Successful with response status 200 + """ + response = self.shipyard_document_staging_client. \ + get_configdocs_compare_two("committed%2Cbuffer") + self.assertEqual(response.response['status'], '200') + self.assertEqual(response[0]['new_version'], 'buffer') + self.assertEqual(response[0]['base_version'], 'committed') diff --git a/airship_tempest_plugin/tests/api/shipyard/test_log_retrieval.py b/airship_tempest_plugin/tests/api/shipyard/test_log_retrieval.py new file mode 100644 index 0000000..15f13e0 --- /dev/null +++ b/airship_tempest_plugin/tests/api/shipyard/test_log_retrieval.py @@ -0,0 +1,35 @@ +# Copyright 2018 AT&T Corp +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +from airship_tempest_plugin.tests.api.shipyard import base +from tempest.lib import decorators + + +class LogRetrievalTest(base.BaseShipyardTest): + def _get_action_step_id(self): + resp = self.shipyard_actions_client.list_actions() + self.assertTrue(len(resp[1]) > 0, + 'No actions available, nothing to test') + return resp[1]['id'], resp[1]['steps'][0]['id'] + + @decorators.idempotent_id('1a8e95fd-77cc-4576-99e1-4ebbb4d8469a') + def test_get_action_step_logs(self): + """Get actions step log, Successful with response status 200""" + action_id, step_id = self._get_action_step_id() + response = self.shipyard_log_retrieval_client. \ + get_action_step_logs(action_id, step_id) + self.assertEqual(response.response['status'], '200') + self.assertTrue(len(response.data) > 0, 'No actions step log available') diff --git a/airship_tempest_plugin/tests/api/shipyard/test_site_statuses.py b/airship_tempest_plugin/tests/api/shipyard/test_site_statuses.py new file mode 100644 index 0000000..5c4a690 --- /dev/null +++ b/airship_tempest_plugin/tests/api/shipyard/test_site_statuses.py @@ -0,0 +1,59 @@ +# Copyright 2018 AT&T Corp +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +from airship_tempest_plugin.tests.api.shipyard import base +from tempest.lib import decorators + + +class SiteStatusesTest(base.BaseShipyardTest): + @decorators.idempotent_id('c4c6fd0f-83dd-42ae-a4eb-430708490b71') + def test_get_site_statuses(self): + """Get Site status, Successful with response status 200""" + response = self.shipyard_site_statuses_client.get_site_statuses() + self.assertEqual(response.response['status'], '200') + self.assertEqual(response['nodes_provision_status'][0]['status'], 'Deployed') + self.assertEqual(response['machines_powerstate'][0]['power_state'], 'on') + + @decorators.idempotent_id('9cfbf0b9-e826-4a9d-b1d2-055adaa8ecc2') + def test_get_site_statuses_node_provision_status(self): + """Get Site status of Node Provision and + Successful with response status 200 + """ + response = self.shipyard_site_statuses_client. \ + get_site_statuses_arg('nodes-provision-status') + self.assertEqual(response.response['status'], '200') + self.assertEqual(response['nodes_provision_status'][0]['status'], 'Deployed') + + @decorators.idempotent_id('c329dbe8-4cb2-4a8b-9aa8-3a032c73102b') + def test_get_site_statuses_node_power_status(self): + """Get Site status of Node Power and + Successful with response status 200 + """ + response = self.shipyard_site_statuses_client. \ + get_site_statuses_arg('machines-power-state') + self.assertEqual(response.response['status'], '200') + self.assertEqual(response['machines_powerstate'][0]['power_state'], 'on') + + @decorators.idempotent_id('52a87dde-1458-45fd-92c6-edcd93eb0c14') + def test_get_site_statuses_both_filters_together(self): + """Get Site status of both filters together and + Successful with response status 200 + """ + response = self.shipyard_site_statuses_client. \ + get_site_statuses_arg('nodes-provision-status%2Cmachines-power-state') + self.assertEqual(response.response['status'], '200') + self.assertEqual(response['nodes_provision_status'][0]['status'], 'Deployed') + self.assertEqual(response['machines_powerstate'][0]['power_state'], 'on')