diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 449e62c2d..000000000 --- a/.coveragerc +++ /dev/null @@ -1,4 +0,0 @@ -[run] -branch = True -source = tempest -omit = tempest/tests/*,tempest/scenario/test_*.py,tempest/api/* diff --git a/.gitignore b/.gitignore deleted file mode 100644 index 287db4cf5..000000000 --- a/.gitignore +++ /dev/null @@ -1,31 +0,0 @@ -AUTHORS -ChangeLog -*.pyc -__pycache__/ -etc/accounts.yaml -etc/tempest.conf -etc/tempest.conf.sample -etc/logging.conf -include/swift_objects/swift_small -include/swift_objects/swift_medium -include/swift_objects/swift_large -*.log -*.swp -*.swo -*.egg* -.tox -.venv -dist -build -.testrepository -.idea -.project -.pydevproject -.coverage* -!.coveragerc -cover/ -doc/source/_static/tempest.conf.sample -doc/source/plugin-registry.rst - -# Files created by releasenotes build -releasenotes/build diff --git a/.gitreview b/.gitreview deleted file mode 100644 index 84b5114f5..000000000 --- a/.gitreview +++ /dev/null @@ -1,4 +0,0 @@ -[gerrit] -host=review.openstack.org -port=29418 -project=openstack/tempest.git diff --git a/.mailmap b/.mailmap deleted file mode 100644 index 3ea6ab0d5..000000000 --- a/.mailmap +++ /dev/null @@ -1,27 +0,0 @@ - - - -Adam Gandelman -Andrea Frittoli -Andrea Frittoli -Daryl Walleck -David Kranz David Kranz -Ghanshyam -Ghanshyam -Jay Pipes -Joe Gordon -Ken'ichi Ohmichi -Ken'ichi Ohmichi -Marc Koderer -Masayuki Igawa -Masayuki Igawa -Masayuki Igawa -Matthew Treinish -Nayna Patel -ravikumar-venkatesan -ravikumar-venkatesan -Rohit Karajgi -Sean Dague -Sean Dague -Yuiko Takada -Zhi Kun Liu diff --git a/.testr.conf b/.testr.conf deleted file mode 100644 index 95a4fb4d2..000000000 --- a/.testr.conf +++ /dev/null @@ -1,9 +0,0 @@ -[DEFAULT] -test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \ - OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \ - OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-500} \ - OS_TEST_LOCK_PATH=${OS_TEST_LOCK_PATH:-${TMPDIR:-'/tmp'}} \ - ${PYTHON:-python} -m subunit.run discover -t ${OS_TOP_LEVEL:-./} ${OS_TEST_PATH:-./tempest/test_discover} $LISTOPT $IDOPTION -test_id_option=--load-list $IDFILE -test_list_option=--list -group_regex=([^\.]*\.)* diff --git a/HACKING.rst b/HACKING.rst deleted file mode 100644 index e5f45ac1b..000000000 --- a/HACKING.rst +++ /dev/null @@ -1,403 +0,0 @@ -Tempest Coding Guide -==================== - -- Step 1: Read the OpenStack Style Commandments - https://docs.openstack.org/hacking/latest/ -- Step 2: Read on - -Tempest Specific Commandments ------------------------------- - -- [T102] Cannot import OpenStack python clients in tempest/api & - tempest/scenario tests -- [T104] Scenario tests require a services decorator -- [T105] Tests cannot use setUpClass/tearDownClass -- [T106] vim configuration should not be kept in source files. -- [T107] Check that a service tag isn't in the module path -- [T108] Check no hyphen at the end of rand_name() argument -- [T109] Cannot use testtools.skip decorator; instead use - decorators.skip_because from tempest.lib -- [T110] Check that service client names of GET should be consistent -- [T111] Check that service client names of DELETE should be consistent -- [T112] Check that tempest.lib should not import local tempest code -- [T113] Check that tests use data_utils.rand_uuid() instead of uuid.uuid4() -- [T114] Check that tempest.lib does not use tempest config -- [T115] Check that admin tests should exist under admin path -- [N322] Method's default argument shouldn't be mutable - -Test Data/Configuration ------------------------ -- Assume nothing about existing test data -- Tests should be self contained (provide their own data) -- Clean up test data at the completion of each test -- Use configuration files for values that will vary by environment - - -Exception Handling ------------------- -According to the ``The Zen of Python`` the -``Errors should never pass silently.`` -Tempest usually runs in special environment (jenkins gate jobs), in every -error or failure situation we should provide as much error related -information as possible, because we usually do not have the chance to -investigate the situation after the issue happened. - -In every test case the abnormal situations must be very verbosely explained, -by the exception and the log. - -In most cases the very first issue is the most important information. - -Try to avoid using ``try`` blocks in the test cases, as both the ``except`` -and ``finally`` blocks could replace the original exception, -when the additional operations leads to another exception. - -Just letting an exception to propagate, is not a bad idea in a test case, -at all. - -Try to avoid using any exception handling construct which can hide the errors -origin. - -If you really need to use a ``try`` block, please ensure the original -exception at least logged. When the exception is logged you usually need -to ``raise`` the same or a different exception anyway. - -Use of ``self.addCleanup`` is often a good way to avoid having to catch -exceptions and still ensure resources are correctly cleaned up if the -test fails part way through. - -Use the ``self.assert*`` methods provided by the unit test framework. -This signals the failures early on. - -Avoid using the ``self.fail`` alone, its stack trace will signal -the ``self.fail`` line as the origin of the error. - -Avoid constructing complex boolean expressions for assertion. -The ``self.assertTrue`` or ``self.assertFalse`` without a ``msg`` argument, -will just tell you the single boolean value, and you will not know anything -about the values used in the formula, the ``msg`` argument might be good enough -for providing more information. - -Most other assert method can include more information by default. -For example ``self.assertIn`` can include the whole set. - -It is recommended to use testtools `matcher`_ for the more tricky assertions. -You can implement your own specific `matcher`_ as well. - -.. _matcher: http://testtools.readthedocs.org/en/latest/for-test-authors.html#matchers - -If the test case fails you can see the related logs and the information -carried by the exception (exception class, backtrack and exception info). -This and the service logs are your only guide to finding the root cause of flaky -issues. - -Test cases are independent --------------------------- -Every ``test_method`` must be callable individually and MUST NOT depends on, -any other ``test_method`` or ``test_method`` ordering. - -Test cases MAY depend on commonly initialized resources/facilities, like -credentials management, testresources and so on. These facilities, MUST be able -to work even if just one ``test_method`` is selected for execution. - -Service Tagging ---------------- -Service tagging is used to specify which services are exercised by a particular -test method. You specify the services with the ``tempest.test.services`` -decorator. For example: - -@services('compute', 'image') - -Valid service tag names are the same as the list of directories in tempest.api -that have tests. - -For scenario tests having a service tag is required. For the API tests service -tags are only needed if the test method makes an API call (either directly or -indirectly through another service) that differs from the parent directory -name. For example, any test that make an API call to a service other than Nova -in ``tempest.api.compute`` would require a service tag for those services, -however they do not need to be tagged as ``compute``. - -Test fixtures and resources ---------------------------- -Test level resources should be cleaned-up after the test execution. Clean-up -is best scheduled using `addCleanup` which ensures that the resource cleanup -code is always invoked, and in reverse order with respect to the creation -order. - -Test class level resources should be defined in the `resource_setup` method of -the test class, except for any credential obtained from the credentials -provider, which should be set-up in the `setup_credentials` method. - -The test base class `BaseTestCase` defines Tempest framework for class level -fixtures. `setUpClass` and `tearDownClass` are defined here and cannot be -overwritten by subclasses (enforced via hacking rule T105). - -Set-up is split in a series of steps (setup stages), which can be overwritten -by test classes. Set-up stages are: - -- `skip_checks` -- `setup_credentials` -- `setup_clients` -- `resource_setup` - -Tear-down is also split in a series of steps (teardown stages), which are -stacked for execution only if the corresponding setup stage had been -reached during the setup phase. Tear-down stages are: - -- `clear_credentials` (defined in the base test class) -- `resource_cleanup` - -Skipping Tests --------------- -Skipping tests should be based on configuration only. If that is not possible, -it is likely that either a configuration flag is missing, or the test should -fail rather than be skipped. -Using discovery for skipping tests is generally discouraged. - -When running a test that requires a certain "feature" in the target -cloud, if that feature is missing we should fail, because either the test -configuration is invalid, or the cloud is broken and the expected "feature" is -not there even if the cloud was configured with it. - -Negative Tests --------------- -Error handling is an important aspect of API design and usage. Negative -tests are a way to ensure that an application can gracefully handle -invalid or unexpected input. However, as a black box integration test -suite, Tempest is not suitable for handling all negative test cases, as -the wide variety and complexity of negative tests can lead to long test -runs and knowledge of internal implementation details. The bulk of -negative testing should be handled with project function tests. -All negative tests should be based on `API-WG guideline`_ . Such negative -tests can block any changes from accurate failure code to invalid one. - -.. _API-WG guideline: http://specs.openstack.org/openstack/api-wg/guidelines/http.html#failure-code-clarifications - -If facing some gray area which is not clarified on the above guideline, propose -a new guideline to the API-WG. With a proposal to the API-WG we will be able to -build a consensus across all OpenStack projects and improve the quality and -consistency of all the APIs. - -In addition, we have some guidelines for additional negative tests. - -- About BadRequest(HTTP400) case: We can add a single negative tests of - BadRequest for each resource and method(POST, PUT). - Please don't implement more negative tests on the same combination of - resource and method even if API request parameters are different from - the existing test. -- About NotFound(HTTP404) case: We can add a single negative tests of - NotFound for each resource and method(GET, PUT, DELETE, HEAD). - Please don't implement more negative tests on the same combination - of resource and method. - -The above guidelines don't cover all cases and we will grow these guidelines -organically over time. Patches outside of the above guidelines are left up to -the reviewers' discretion and if we face some conflicts between reviewers, we -will expand the guideline based on our discussion and experience. - -Test skips because of Known Bugs --------------------------------- -If a test is broken because of a bug it is appropriate to skip the test until -bug has been fixed. You should use the ``skip_because`` decorator so that -Tempest's skip tracking tool can watch the bug status. - -Example:: - - @skip_because(bug="980688") - def test_this_and_that(self): - ... - -Guidelines ----------- -- Do not submit changesets with only testcases which are skipped as - they will not be merged. -- Consistently check the status code of responses in testcases. The - earlier a problem is detected the easier it is to debug, especially - where there is complicated setup required. - -Parallel Test Execution ------------------------ -Tempest by default runs its tests in parallel this creates the possibility for -interesting interactions between tests which can cause unexpected failures. -Dynamic credentials provides protection from most of the potential race -conditions between tests outside the same class. But there are still a few of -things to watch out for to try to avoid issues when running your tests in -parallel. - -- Resources outside of a project scope still have the potential to conflict. This - is a larger concern for the admin tests since most resources and actions that - require admin privileges are outside of projects. - -- Races between methods in the same class are not a problem because - parallelization in Tempest is at the test class level, but if there is a json - and xml version of the same test class there could still be a race between - methods. - -- The rand_name() function from tempest.lib.common.utils.data_utils should be - used anywhere a resource is created with a name. Static naming should be - avoided to prevent resource conflicts. - -- If the execution of a set of tests is required to be serialized then locking - can be used to perform this. See usage of ``LockFixture`` for examples of - using locking. - -Sample Configuration File -------------------------- -The sample config file is autogenerated using a script. If any changes are made -to the config variables in tempest/config.py then the sample config file must be -regenerated. This can be done running:: - - tox -e genconfig - -Unit Tests ----------- -Unit tests are a separate class of tests in Tempest. They verify Tempest -itself, and thus have a different set of guidelines around them: - -1. They can not require anything running externally. All you should need to - run the unit tests is the git tree, python and the dependencies installed. - This includes running services, a config file, etc. - -2. The unit tests cannot use setUpClass, instead fixtures and testresources - should be used for shared state between tests. - - -.. _TestDocumentation: - -Test Documentation ------------------- -For tests being added we need to require inline documentation in the form of -docstrings to explain what is being tested. In API tests for a new API a class -level docstring should be added to an API reference doc. If one doesn't exist -a TODO comment should be put indicating that the reference needs to be added. -For individual API test cases a method level docstring should be used to -explain the functionality being tested if the test name isn't descriptive -enough. For example:: - - def test_get_role_by_id(self): - """Get a role by its id.""" - -the docstring there is superfluous and shouldn't be added. but for a method -like:: - - def test_volume_backup_create_get_detailed_list_restore_delete(self): - pass - -a docstring would be useful because while the test title is fairly descriptive -the operations being performed are complex enough that a bit more explanation -will help people figure out the intent of the test. - -For scenario tests a class level docstring describing the steps in the scenario -is required. If there is more than one test case in the class individual -docstrings for the workflow in each test methods can be used instead. A good -example of this would be:: - - class TestVolumeBootPattern(manager.ScenarioTest): - """ - This test case attempts to reproduce the following steps: - - * Create in Cinder some bootable volume importing a Glance image - * Boot an instance from the bootable volume - * Write content to the volume - * Delete an instance and Boot a new instance from the volume - * Check written content in the instance - * Create a volume snapshot while the instance is running - * Boot an additional instance from the new snapshot based volume - * Check written content in the instance booted from snapshot - """ - -Test Identification with Idempotent ID --------------------------------------- - -Every function that provides a test must have an ``idempotent_id`` decorator -that is a unique ``uuid-4`` instance. This ID is used to complement the fully -qualified test name and track test functionality through refactoring. The -format of the metadata looks like:: - - @decorators.idempotent_id('585e934c-448e-43c4-acbf-d06a9b899997') - def test_list_servers_with_detail(self): - # The created server should be in the detailed list of all servers - ... - -Tempest.lib includes a ``check-uuid`` tool that will test for the existence -and uniqueness of idempotent_id metadata for every test. If you have -Tempest installed you run the tool against Tempest by calling from the -Tempest repo:: - - check-uuid - -It can be invoked against any test suite by passing a package name:: - - check-uuid --package - -Tests without an ``idempotent_id`` can be automatically fixed by running -the command with the ``--fix`` flag, which will modify the source package -by inserting randomly generated uuids for every test that does not have -one:: - - check-uuid --fix - -The ``check-uuid`` tool is used as part of the Tempest gate job -to ensure that all tests have an ``idempotent_id`` decorator. - -Branchless Tempest Considerations ---------------------------------- - -Starting with the OpenStack Icehouse release Tempest no longer has any stable -branches. This is to better ensure API consistency between releases because -the API behavior should not change between releases. This means that the stable -branches are also gated by the Tempest master branch, which also means that -proposed commits to Tempest must work against both the master and all the -currently supported stable branches of the projects. As such there are a few -special considerations that have to be accounted for when pushing new changes -to Tempest. - -1. New Tests for new features -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -When adding tests for new features that were not in previous releases of the -projects the new test has to be properly skipped with a feature flag. Whether -this is just as simple as using the @test.requires_ext() decorator to check -if the required extension (or discoverable optional API) is enabled or adding -a new config option to the appropriate section. If there isn't a method of -selecting the new **feature** from the config file then there won't be a -mechanism to disable the test with older stable releases and the new test won't -be able to merge. - -2. Bug fix on core project needing Tempest changes -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -When trying to land a bug fix which changes a tested API you'll have to use the -following procedure:: - - 1. Propose change to the project, get a +2 on the change even with failing - 2. Propose skip on Tempest which will only be approved after the - corresponding change in the project has a +2 on change - 3. Land project change in master and all open stable branches (if required) - 4. Land changed test in Tempest - -Otherwise the bug fix won't be able to land in the project. - -Handily, `Zuul’s cross-repository dependencies -`_. -can be leveraged to do without step 2 and to have steps 3 and 4 happen -"atomically". To do that, make the patch written in step 1 to depend (refer to -Zuul's documentation above) on the patch written in step 4. The commit message -for the Tempest change should have a link to the Gerrit review that justifies -that change. - -3. New Tests for existing features -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -If a test is being added for a feature that exists in all the current releases -of the projects then the only concern is that the API behavior is the same -across all the versions of the project being tested. If the behavior is not -consistent the test will not be able to merge. - -API Stability -------------- - -For new tests being added to Tempest the assumption is that the API being -tested is considered stable and adheres to the OpenStack API stability -guidelines. If an API is still considered experimental or in development then -it should not be tested by Tempest until it is considered stable. diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 68c771a09..000000000 --- a/LICENSE +++ /dev/null @@ -1,176 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - diff --git a/README b/README new file mode 100644 index 000000000..8fcd2b2f8 --- /dev/null +++ b/README @@ -0,0 +1,14 @@ +This project is no longer maintained. + +The contents of this repository are still available in the Git +source code management system. To see the contents of this +repository before it reached its end of life, please check out the +previous commit with "git checkout HEAD^1". + +For ongoing work on maintaining OpenStack packages in the Debian +distribution, please see the Debian OpenStack packaging team at +https://wiki.debian.org/OpenStack/. + +For any further questions, please email +openstack-dev@lists.openstack.org or join #openstack-dev on +Freenode. diff --git a/README.rst b/README.rst deleted file mode 100644 index 2e13fec5a..000000000 --- a/README.rst +++ /dev/null @@ -1,268 +0,0 @@ -======================== -Team and repository tags -======================== - -.. image:: http://governance.openstack.org/badges/tempest.svg - :target: http://governance.openstack.org/reference/tags/index.html - -.. Change things from this point on - -Tempest - The OpenStack Integration Test Suite -============================================== - -The documentation for Tempest is officially hosted at: -https://docs.openstack.org/tempest/latest/ - -This is a set of integration tests to be run against a live OpenStack -cluster. Tempest has batteries of tests for OpenStack API validation, -Scenarios, and other specific tests useful in validating an OpenStack -deployment. - -Design Principles ------------------ -Tempest Design Principles that we strive to live by. - -- Tempest should be able to run against any OpenStack cloud, be it a - one node DevStack install, a 20 node LXC cloud, or a 1000 node KVM - cloud. -- Tempest should be explicit in testing features. It is easy to auto - discover features of a cloud incorrectly, and give people an - incorrect assessment of their cloud. Explicit is always better. -- Tempest uses OpenStack public interfaces. Tests in Tempest should - only touch public OpenStack APIs. -- Tempest should not touch private or implementation specific - interfaces. This means not directly going to the database, not - directly hitting the hypervisors, not testing extensions not - included in the OpenStack base. If there are some features of - OpenStack that are not verifiable through standard interfaces, this - should be considered a possible enhancement. -- Tempest strives for complete coverage of the OpenStack API and - common scenarios that demonstrate a working cloud. -- Tempest drives load in an OpenStack cloud. By including a broad - array of API and scenario tests Tempest can be reused in whole or in - parts as load generation for an OpenStack cloud. -- Tempest should attempt to clean up after itself, whenever possible - we should tear down resources when done. -- Tempest should be self-testing. - -Quickstart ----------- - -To run Tempest, you first need to create a configuration file that will tell -Tempest where to find the various OpenStack services and other testing behavior -switches. Where the configuration file lives and how you interact with it -depends on how you'll be running Tempest. There are 2 methods of using Tempest. -The first, which is a newer and recommended workflow treats Tempest as a system -installed program. The second older method is to run Tempest assuming your -working dir is the actually Tempest source repo, and there are a number of -assumptions related to that. For this section we'll only cover the newer method -as it is simpler, and quicker to work with. - -#. You first need to install Tempest. This is done with pip after you check out - the Tempest repo:: - - $ git clone http://git.openstack.org/openstack/tempest - $ pip install tempest/ - - This can be done within a venv, but the assumption for this guide is that - the Tempest CLI entry point will be in your shell's PATH. - -#. Installing Tempest may create a ``/etc/tempest dir``, however if one isn't - created you can create one or use ``~/.tempest/etc`` or ``~/.config/tempest`` in - place of ``/etc/tempest``. If none of these dirs are created Tempest will create - ``~/.tempest/etc`` when it's needed. The contents of this dir will always - automatically be copied to all ``etc/`` dirs in local workspaces as an initial - setup step. So if there is any common configuration you'd like to be shared - between local Tempest workspaces it's recommended that you pre-populate it - before running ``tempest init``. - -#. Setup a local Tempest workspace. This is done by using the tempest init - command:: - - $ tempest init cloud-01 - - which also works the same as:: - - $ mkdir cloud-01 && cd cloud-01 && tempest init - - This will create a new directory for running a single Tempest configuration. - If you'd like to run Tempest against multiple OpenStack deployments the idea - is that you'll create a new working directory for each to maintain separate - configuration files and local artifact storage for each. - -#. Then ``cd`` into the newly created working dir and also modify the local - config files located in the ``etc/`` subdir created by the ``tempest init`` - command. Tempest is expecting a ``tempest.conf`` file in etc/ so if only a - sample exists you must rename or copy it to tempest.conf before making - any changes to it otherwise Tempest will not know how to load it. For - details on configuring Tempest refer to the :ref:`tempest-configuration`. - -#. Once the configuration is done you're now ready to run Tempest. This can - be done using the :ref:`tempest_run` command. This can be done by either - running:: - - $ tempest run - - from the Tempest workspace directory. Or you can use the ``--workspace`` - argument to run in the workspace you created regardless of your current - working directory. For example:: - - $ tempest run --workspace cloud-01 - - There is also the option to use testr directly, or any `testr`_ based test - runner, like `ostestr`_. For example, from the workspace dir run:: - - $ ostestr --regex '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario))' - - will run the same set of tests as the default gate jobs. - -.. _testr: https://testrepository.readthedocs.org/en/latest/MANUAL.html -.. _ostestr: https://docs.openstack.org/os-testr/latest/ - -Library -------- -Tempest exposes a library interface. This interface is a stable interface and -should be backwards compatible (including backwards compatibility with the -old tempest-lib package, with the exception of the import). If you plan to -directly consume Tempest in your project you should only import code from the -Tempest library interface, other pieces of Tempest do not have the same -stable interface and there are no guarantees on the Python API unless otherwise -stated. - -For more details refer to the library documentation here: :ref:`library` - -Release Versioning ------------------- -`Tempest Release Notes `_ -shows what changes have been released on each version. - -Tempest's released versions are broken into 2 sets of information. Depending on -how you intend to consume Tempest you might need - -The version is a set of 3 numbers: - -X.Y.Z - -While this is almost `semver`_ like, the way versioning is handled is slightly -different: - -X is used to represent the supported OpenStack releases for Tempest tests -in-tree, and to signify major feature changes to Tempest. It's a monotonically -increasing integer where each version either indicates a new supported OpenStack -release, the drop of support for an OpenStack release (which will coincide with -the upstream stable branch going EOL), or a major feature lands (or is removed) -from Tempest. - -Y.Z is used to represent library interface changes. This is treated the same -way as minor and patch versions from `semver`_ but only for the library -interface. When Y is incremented we've added functionality to the library -interface and when Z is incremented it's a bug fix release for the library. -Also note that both Y and Z are reset to 0 at each increment of X. - -.. _semver: http://semver.org/ - -Configuration -------------- - -Detailed configuration of Tempest is beyond the scope of this -document see :ref:`tempest-configuration` for more details on configuring -Tempest. The ``etc/tempest.conf.sample`` attempts to be a self-documenting -version of the configuration. - -You can generate a new sample tempest.conf file, run the following -command from the top level of the Tempest directory:: - - $ tox -e genconfig - -The most important pieces that are needed are the user ids, OpenStack -endpoints, and basic flavors and images needed to run tests. - -Unit Tests ----------- - -Tempest also has a set of unit tests which test the Tempest code itself. These -tests can be run by specifying the test discovery path:: - - $ OS_TEST_PATH=./tempest/tests testr run --parallel - -By setting OS_TEST_PATH to ./tempest/tests it specifies that test discover -should only be run on the unit test directory. The default value of OS_TEST_PATH -is OS_TEST_PATH=./tempest/test_discover which will only run test discover on the -Tempest suite. - -Alternatively, there are the py27 and py35 tox jobs which will run the unit -tests with the corresponding version of python. - -Python 2.6 ----------- - -Starting in the Kilo release the OpenStack services dropped all support for -python 2.6. This change has been mirrored in Tempest, starting after the -tempest-2 tag. This means that proposed changes to Tempest which only fix -python 2.6 compatibility will be rejected, and moving forward more features not -present in python 2.6 will be used. If you're running your OpenStack services -on an earlier release with python 2.6 you can easily run Tempest against it -from a remote system running python 2.7. (or deploy a cloud guest in your cloud -that has python 2.7) - -Python 3.x ----------- - -Starting during the Pike cycle Tempest has a gating CI job that runs Tempest -with Python 3. Any Tempest release after 15.0.0 should fully support running -under Python 3 as well as Python 2.7. - -Legacy run method ------------------ - -The legacy method of running Tempest is to just treat the Tempest source code -as a python unittest repository and run directly from the source repo. When -running in this way you still start with a Tempest config file and the steps -are basically the same except that it expects you know where the Tempest code -lives on your system and requires a bit more manual interaction to get Tempest -running. For example, when running Tempest this way things like a lock file -directory do not get generated automatically and the burden is on the user to -create and configure that. - -To start you need to create a configuration file. The easiest way to create a -configuration file is to generate a sample in the ``etc/`` directory :: - - $ cd $TEMPEST_ROOT_DIR - $ oslo-config-generator --config-file \ - tempest/cmd/config-generator.tempest.conf \ - --output-file etc/tempest.conf - -After that, open up the ``etc/tempest.conf`` file and edit the -configuration variables to match valid data in your environment. -This includes your Keystone endpoint, a valid user and credentials, -and reference data to be used in testing. - -.. note:: - - If you have a running DevStack environment, Tempest will be - automatically configured and placed in ``/opt/stack/tempest``. It - will have a configuration file already set up to work with your - DevStack installation. - -Tempest is not tied to any single test runner, but `testr`_ is the most commonly -used tool. Also, the nosetests test runner is **not** recommended to run Tempest. - -After setting up your configuration file, you can execute the set of Tempest -tests by using ``testr`` :: - - $ testr run --parallel - -To run one single test serially :: - - $ testr run tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_reboot_non_existent_server - -Tox also contains several existing job configurations. For example:: - - $ tox -e full - -which will run the same set of tests as the OpenStack gate. (it's exactly how -the gate invokes Tempest) Or:: - - $ tox -e smoke - -to run the tests tagged as smoke. diff --git a/REVIEWING.rst b/REVIEWING.rst deleted file mode 100644 index 7d28320b4..000000000 --- a/REVIEWING.rst +++ /dev/null @@ -1,128 +0,0 @@ -Reviewing Tempest Code -====================== - -To start read the `OpenStack Common Review Checklist -`_ - - -Ensuring code is executed -------------------------- - -For any new or change to a test it has to be verified in the gate. This means -that the first thing to check with any change is that a gate job actually runs -it. Tests which aren't executed either because of configuration or skips should -not be accepted. - -If a new test is added that depends on a new config option (like a feature -flag), the commit message must reference a change in DevStack or DevStack-Gate -that enables the execution of this newly introduced test. This reference could -either be a `Cross-Repository Dependency `_ or a simple link -to a Gerrit review. - - -Execution time --------------- -While checking in the job logs that a new test is actually executed, also -pay attention to the execution time of that test. Keep in mind that each test -is going to be executed hundreds of time each day, because Tempest tests -run in many OpenStack projects. It's worth considering how important/critical -the feature under test is with how costly the new test is. - - -Unit Tests ----------- - -For any change that adds new functionality to either common functionality or an -out-of-band tool unit tests are required. This is to ensure we don't introduce -future regressions and to test conditions which we may not hit in the gate runs. -Tests, and service clients aren't required to have unit tests since they should -be self verifying by running them in the gate. - - -API Stability -------------- -Tests should only be added for a published stable APIs. If a patch contains -tests for an API which hasn't been marked as stable or for an API that which -doesn't conform to the `API stability guidelines -`_ then it -should not be approved. - - -Reject Copy and Paste Test Code -------------------------------- -When creating new tests that are similar to existing tests it is tempting to -simply copy the code and make a few modifications. This increases code size and -the maintenance burden. Such changes should not be approved if it is easy to -abstract the duplicated code into a function or method. - - -Tests overlap -------------- -When a new test is being proposed, question whether this feature is not already -tested with Tempest. Tempest has more than 1200 tests, spread amongst many -directories, so it's easy to introduce test duplication. For example, testing -volume attachment to a server could be a compute test or a volume test, depending -on how you see it. So one must look carefully in the entire code base for possible -overlap. As a rule of thumb, the older a feature is, the more likely it's -already tested. - - -Being explicit --------------- -When tests are being added that depend on a configurable feature or extension, -polling the API to discover that it is enabled should not be done. This will -just result in bugs being masked because the test can be skipped automatically. -Instead the config file should be used to determine whether a test should be -skipped or not. Do not approve changes that depend on an API call to determine -whether to skip or not. - - -Configuration Options ---------------------- -With the introduction of the Tempest external test plugin interface we needed -to provide a stable contract for Tempest's configuration options. This means -we can no longer simply remove a configuration option when it's no longer used. -Patches proposed that remove options without a deprecation cycle should not -be approved. Similarly when changing default values with configuration we need -to similarly be careful that we don't break existing functionality. Also, when -adding options, just as before, we need to weigh the benefit of adding an -additional option against the complexity and maintenance overhead having it -costs. - - -Test Documentation ------------------- -When a new test is being added refer to the :ref:`TestDocumentation` section in -hacking to see if the requirements are being met. With the exception of a class -level docstring linking to the API ref doc in the API tests and a docstring for -scenario tests this is up to the reviewers discretion whether a docstring is -required or not. - -Release Notes -------------- -Release notes are how we indicate to users and other consumers of Tempest what -has changed in a given release. Since Tempest 10.0.0 we've been using `reno`_ -to manage and build the release notes. There are certain types of changes that -require release notes and we should not approve them without including a release -note. These include but aren't limited to, any addition, deprecation or removal -from the lib interface, any change to configuration options (including -deprecation), CLI additions or deprecations, major feature additions, and -anything backwards incompatible or would require a user to take note or do -something extra. - -.. _reno: https://docs.openstack.org/reno/latest/ - -Deprecated Code ---------------- -Sometimes we have some bugs in deprecated code. Basically, we leave it. Because -we don't need to maintain it. However, if the bug is critical, we might need to -fix it. When it will happen, we will deal with it on a case-by-case basis. - -When to approve ---------------- - * Every patch needs two +2s before being approved. - * Its ok to hold off on an approval until a subject matter expert reviews it - * If a patch has already been approved but requires a trivial rebase to merge, - you do not have to wait for a second +2, since the patch has already had - two +2s. diff --git a/bindep.txt b/bindep.txt deleted file mode 100644 index 8914adecf..000000000 --- a/bindep.txt +++ /dev/null @@ -1,13 +0,0 @@ -# This file contains runtime (non-python) dependencies -# More info at: http://docs.openstack.org/infra/bindep/readme.html - -libffi-dev [platform:dpkg] -libffi-devel [platform:rpm] -gcc [platform:rpm] -gcc [platform:dpkg] -python-dev [platform:dpkg] -python-devel [platform:rpm] -python3-dev [platform:dpkg] -python3-devel [platform:rpm] -openssl-devel [platform:rpm] -libssl-dev [platform:dpkg] diff --git a/data/tempest-plugins-registry.header b/data/tempest-plugins-registry.header deleted file mode 100644 index 9821e8e70..000000000 --- a/data/tempest-plugins-registry.header +++ /dev/null @@ -1,23 +0,0 @@ -.. - Note to patch submitters: this file is covered by a periodic proposal - job. You should edit the files data/tempest-plugins-registry.footer - and data/tempest-plugins-registry.header instead of this one. - -========================== - Tempest Plugin Registry -========================== - -Since we've created the external plugin mechanism, it's gotten used by -a lot of projects. The following is a list of plugins that currently -exist. - -Detected Plugins -================ - -The following are plugins that a script has found in the openstack/ -namespace, which includes but is not limited to official OpenStack -projects. - -+----------------------------+-------------------------------------------------------------------------+ -|Plugin Name |URL | -+----------------------------+-------------------------------------------------------------------------+ diff --git a/doc/source/HACKING.rst b/doc/source/HACKING.rst deleted file mode 120000 index a2f06b723..000000000 --- a/doc/source/HACKING.rst +++ /dev/null @@ -1 +0,0 @@ -../../HACKING.rst \ No newline at end of file diff --git a/doc/source/REVIEWING.rst b/doc/source/REVIEWING.rst deleted file mode 120000 index 841e042c5..000000000 --- a/doc/source/REVIEWING.rst +++ /dev/null @@ -1 +0,0 @@ -../../REVIEWING.rst \ No newline at end of file diff --git a/doc/source/_static/.keep b/doc/source/_static/.keep deleted file mode 100644 index e69de29bb..000000000 diff --git a/doc/source/account_generator.rst b/doc/source/account_generator.rst deleted file mode 100644 index 032a20dbc..000000000 --- a/doc/source/account_generator.rst +++ /dev/null @@ -1,5 +0,0 @@ --------------------------------------- -Tempest Test-Account Generator Utility --------------------------------------- - -.. automodule:: tempest.cmd.account_generator diff --git a/doc/source/cleanup.rst b/doc/source/cleanup.rst deleted file mode 100644 index acd016c3f..000000000 --- a/doc/source/cleanup.rst +++ /dev/null @@ -1,5 +0,0 @@ --------------------------------- -Post Tempest Run Cleanup Utility --------------------------------- - -.. automodule:: tempest.cmd.cleanup \ No newline at end of file diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100644 index 201d3877b..000000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,203 +0,0 @@ -# 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. - -# Tempest documentation build configuration file, created by -# sphinx-quickstart on Tue May 21 17:43:32 2013. -# -# This file is execfile()d with the current directory set to its containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -import sys -import os -import subprocess -import warnings - -import openstackdocstheme - -# Build the plugin registry -def build_plugin_registry(app): - root_dir = os.path.dirname( - os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) - subprocess.call(['tools/generate-tempest-plugins-list.sh'], cwd=root_dir) - -def setup(app): - if os.getenv('GENERATE_TEMPEST_PLUGIN_LIST', 'true').lower() == 'true': - app.connect('builder-inited', build_plugin_registry) - - - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ----------------------------------------------------- - -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['sphinx.ext.autodoc', - 'sphinx.ext.todo', - 'sphinx.ext.viewcode', - 'openstackdocstheme', - 'oslo_config.sphinxconfiggen', - ] - -config_generator_config_file = '../../tempest/cmd/config-generator.tempest.conf' -sample_config_basename = '_static/tempest' - -todo_include_todos = True - -# openstackdocstheme options -repository_name = 'openstack/tempest' -bug_project = 'tempest' -bug_tag = '' - -# Must set this variable to include year, month, day, hours, and minutes. -html_last_updated_fmt = '%Y-%m-%d %H:%M' - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -#source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'Tempest' -copyright = u'2013, OpenStack QA Team' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -add_module_names = False - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -modindex_common_prefix = ['tempest.'] - - -# -- Options for HTML output --------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'openstackdocs' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -html_use_smartypants = False - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -html_domain_indices = False - -# If false, no index is generated. -html_use_index = False - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# A list of warning types to suppress arbitrary warning messages. -suppress_warnings = ['image.nonlocal_uri'] diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst deleted file mode 100644 index 8f2865ad5..000000000 --- a/doc/source/configuration.rst +++ /dev/null @@ -1,439 +0,0 @@ -.. _tempest-configuration: - -Tempest Configuration Guide -=========================== - -This guide is a starting point for configuring Tempest. It aims to elaborate -on and explain some of the mandatory and common configuration settings and how -they are used in conjunction. The source of truth on each option is the sample -config file which explains the purpose of each individual option. You can see -the sample config file here: :ref:`tempest-sampleconf` - -.. _tempest_cred_provider_conf: - -Test Credentials ----------------- - -Tempest allows for configuring a set of admin credentials in the ``auth`` -section, via the following parameters: - - #. ``admin_username`` - #. ``admin_password`` - #. ``admin_project_name`` - #. ``admin_domain_name`` - -Admin credentials are not mandatory to run Tempest, but when provided they -can be used to: - -- Run tests for admin APIs -- Generate test credentials on the fly (see `Dynamic Credentials`_) - -When Keystone uses a policy that requires domain scoped tokens for admin -actions, the flag ``admin_domain_scope`` must be set to ``True``. -The admin user configured, if any, must have a role assigned to the domain to -be usable. - -Tempest allows for configuring pre-provisioned test credentials as well. -This can be done using the accounts.yaml file (see -`Pre-Provisioned Credentials`_). This file is used to specify an arbitrary -number of users available to run tests with. -You can specify the location of the file in the ``auth`` section in the -tempest.conf file. To see the specific format used in the file please refer to -the ``accounts.yaml.sample`` file included in Tempest. - -Keystone Connection Info -^^^^^^^^^^^^^^^^^^^^^^^^ -In order for Tempest to be able to talk to your OpenStack deployment you need -to provide it with information about how it communicates with keystone. -This involves configuring the following options in the ``identity`` section: - - - ``auth_version`` - - ``uri`` - - ``uri_v3`` - -The ``auth_version`` option is used to tell Tempest whether it should be using -Keystone's v2 or v3 api for communicating with Keystone. The two uri options are -used to tell Tempest the url of the keystone endpoint. The ``uri`` option is -used for Keystone v2 request and ``uri_v3`` is used for Keystone v3. You want to -ensure that which ever version you set for ``auth_version`` has its uri option -defined. - -Credential Provider Mechanisms -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Tempest currently has two different internal methods for providing authentication -to tests: dynamic credentials and pre-provisioned credentials. -Depending on which one is in use the configuration of Tempest is slightly different. - -Dynamic Credentials -""""""""""""""""""" -Dynamic Credentials (formerly known as Tenant isolation) was originally created -to enable running Tempest in parallel. For each test class it creates a unique -set of user credentials to use for the tests in the class. It can create up to -three sets of username, password, and project names for a primary user, -an admin user, and an alternate user. To enable and use dynamic credentials you -only need to configure two things: - - #. A set of admin credentials with permissions to create users and - projects. This is specified in the ``auth`` section with the - ``admin_username``, ``admin_project_name``, ``admin_domain_name`` and - ``admin_password`` options - #. To enable dynamic credentials in the ``auth`` section with the - ``use_dynamic_credentials`` option. - -This is also currently the default credential provider enabled by Tempest, due -to its common use and ease of configuration. - -It is worth pointing out that depending on your cloud configuration you might -need to assign a role to each of the users created by Tempest's dynamic -credentials. This can be set using the ``tempest_roles`` option. It takes in a -list of role names each of which will be assigned to each of the users created -by dynamic credentials. This option will not have any effect when Tempest is not -configured to use dynamic credentials. - -When the ``admin_domain_scope`` option is set to ``True``, provisioned admin -accounts will be assigned a role on domain configured in -``default_credentials_domain_name``. This will make the accounts provisioned -usable in a cloud where domain scoped tokens are required by Keystone for -admin operations. Note that the initial pre-provision admin accounts, -configured in tempest.conf, must have a role on the same domain as well, for -Dynamic Credentials to work. - - -Pre-Provisioned Credentials -""""""""""""""""""""""""""" - -For a long time using dynamic credentials was the only method available if you -wanted to enable parallel execution of Tempest tests. However, this was -insufficient for certain use cases because of the admin credentials requirement -to create the credential sets on demand. To get around that the accounts.yaml -file was introduced and with that a new internal credential provider to enable -using the list of credentials instead of creating them on demand. With locking -test accounts each test class will reserve a set of credentials from the -accounts.yaml before executing any of its tests so that each class is isolated -like with dynamic credentials. - -To enable and use locking test accounts you need do a few things: - - #. Create an accounts.yaml file which contains the set of pre-existing - credentials to use for testing. To make sure you don't have a credentials - starvation issue when running in parallel make sure you have at least two - times the number of worker processes you are using to execute Tempest - available in the file. (If running serially the worker count is 1.) - - You can check the accounts.yaml.sample file packaged in Tempest for the yaml - format. - #. Provide Tempest with the location of your accounts.yaml file with the - ``test_accounts_file`` option in the ``auth`` section - - *NOTE: Be sure to use a full path for the file; otherwise Tempest will - likely not find it.* - - #. Set ``use_dynamic_credentials = False`` in the ``auth`` group - -It is worth pointing out that each set of credentials in the accounts.yaml -should have a unique project. This is required to provide proper isolation -to the tests using the credentials, and failure to do this will likely cause -unexpected failures in some tests. Also, ensure that these projects and users -used do not have any pre-existing resources created. Tempest assumes all -tenants it's using are empty and may sporadically fail if there are unexpected -resources present. - -When the Keystone in the target cloud requires domain scoped tokens to -perform admin actions, all pre-provisioned admin users must have a role -assigned on the domain where test accounts a provisioned. -The option ``admin_domain_scope`` is used to tell Tempest that domain scoped -tokens shall be used. ``default_credentials_domain_name`` is the domain where -test accounts are expected to be provisioned if no domain is specified. - -Note that if credentials are pre-provisioned via ``tempest account-generator`` -the role on the domain will be assigned automatically for you, as long as -``admin_domain_scope`` as ``default_credentials_domain_name`` are configured -properly in tempest.conf. - -Pre-Provisioned Credentials are also known as accounts.yaml or accounts file. - -Compute -------- - -Flavors -^^^^^^^ -For Tempest to be able to create servers you need to specify flavors that it -can use to boot the servers with. There are two options in the Tempest config -for doing this: - - #. ``flavor_ref`` - #. ``flavor_ref_alt`` - -Both of these options are in the ``compute`` section of the config file and take -in the flavor id (not the name) from Nova. The ``flavor_ref`` option is what -will be used for booting almost all of the guests; ``flavor_ref_alt`` is only -used in tests where two different-sized servers are required (for example, a -resize test). - -Using a smaller flavor is generally recommended. When larger flavors are used, -the extra time required to bring up servers will likely affect total run time -and probably require tweaking timeout values to ensure tests have ample time to -finish. - -Images -^^^^^^ -Just like with flavors, Tempest needs to know which images to use for booting -servers. There are two options in the compute section just like with flavors: - - #. ``image_ref`` - #. ``image_ref_alt`` - -Both options are expecting an image id (not name) from Nova. The ``image_ref`` -option is what will be used for booting the majority of servers in Tempest. -``image_ref_alt`` is used for tests that require two images such as rebuild. If -two images are not available you can set both options to the same image id and -those tests will be skipped. - -There are also options in the ``scenario`` section for images: - - #. ``img_file`` - #. ``img_dir`` - #. ``aki_img_file`` - #. ``ari_img_file`` - #. ``ami_img_file`` - #. ``img_container_format`` - #. ``img_disk_format`` - -However, unlike the other image options, these are used for a very small subset -of scenario tests which are uploading an image. These options are used to tell -Tempest where an image file is located and describe its metadata for when it is -uploaded. - -The behavior of these options is a bit convoluted (which will likely be fixed in -future versions). You first need to specify ``img_dir``, which is the directory -in which Tempest will look for the image files. First it will check if the -filename set for ``img_file`` could be found in ``img_dir``. If it is found then -the ``img_container_format`` and ``img_disk_format`` options are used to upload -that image to glance. However, if it is not found, Tempest will look for the -three uec image file name options as a fallback. If neither is found, the tests -requiring an image to upload will fail. - -It is worth pointing out that using `cirros`_ is a very good choice for running -Tempest. It's what is used for upstream testing, they boot quickly and have a -small footprint. - -.. _cirros: https://launchpad.net/cirros - -Networking ----------- -OpenStack has a myriad of different networking configurations possible and -depending on which of the two network backends, nova-network or Neutron, you are -using things can vary drastically. Due to this complexity Tempest has to provide -a certain level of flexibility in its configuration to ensure it will work -against any cloud. This ends up causing a large number of permutations in -Tempest's config around network configuration. - - -Enabling Remote Access to Created Servers -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. _tempest_conf_network_allocation: - -Network Creation/Usage for Servers -"""""""""""""""""""""""""""""""""" -When Tempest creates servers for testing, some tests require being able to -connect those servers. Depending on the configuration of the cloud, the methods -for doing this can be different. In certain configurations it is required to -specify a single network with server create calls. Accordingly, Tempest provides -a few different methods for providing this information in configuration to try -and ensure that regardless of the cloud's configuration it'll still be able to -run. This section covers the different methods of configuring Tempest to provide -a network when creating servers. - -Fixed Network Name -'''''''''''''''''' -This is the simplest method of specifying how networks should be used. You can -just specify a single network name/label to use for all server creations. The -limitation with this is that all projects and users must be able to see -that network name/label if they are to perform a network list and be able to use -it. - -If no network name is assigned in the config file and none of the below -alternatives are used, then Tempest will not specify a network on server -creations, which depending on the cloud configuration might prevent them from -booting. - -To set a fixed network name simply: - - #. Set the ``fixed_network_name`` option in the ``compute`` group - -In the case that the configured fixed network name can not be found by a user -network list call, it will be treated like one was not provided except that a -warning will be logged stating that it couldn't be found. - - -Accounts File -''''''''''''' -If you are using an accounts file to provide credentials for running Tempest -then you can leverage it to also specify which network should be used with -server creations on a per project and user pair basis. This provides -the necessary flexibility to work with more intricate networking configurations -by enabling the user to specify exactly which network to use for which -projects. You can refer to the accounts.yaml.sample file included in -the Tempest repo for the syntax around specifying networks in the file. - -However, specifying a network is not required when using an accounts file. If -one is not specified you can use a fixed network name to specify the network to -use when creating servers just as without an accounts file. However, any network -specified in the accounts file will take precedence over the fixed network name -provided. If no network is provided in the accounts file and a fixed network -name is not set then no network will be included in create server requests. - -If a fixed network is provided and the accounts.yaml file also contains networks -this has the benefit of enabling a couple more tests which require a static -network to perform operations like server lists with a network filter. If a -fixed network name is not provided these tests are skipped. Additionally, if a -fixed network name is provided it will serve as a fallback in case of a -misconfiguration or a missing network in the accounts file. - - -With Dynamic Credentials -'''''''''''''''''''''''' -With dynamic credentials enabled and using nova-network, your only option for -configuration is to either set a fixed network name or not. However, in most -cases it shouldn't matter because nova-network should have no problem booting a -server with multiple networks. If this is not the case for your cloud then using -an accounts file is recommended because it provides the necessary flexibility to -describe your configuration. Dynamic credentials is not able to dynamically -allocate things as necessary if Neutron is not enabled. - -With Neutron and dynamic credentials enabled there should not be any additional -configuration necessary to enable Tempest to create servers with working -networking, assuming you have properly configured the ``network`` section to -work for your cloud. Tempest will dynamically create the Neutron resources -necessary to enable using servers with that network. Also, just as with the -accounts file, if you specify a fixed network name while using Neutron and -dynamic credentials it will enable running tests which require a static network -and it will additionally be used as a fallback for server creation. However, -unlike accounts.yaml this should never be triggered. - -However, there is an option ``create_isolated_networks`` to disable dynamic -credentials's automatic provisioning of network resources. If this option is set -to ``False`` you will have to either rely on there only being a single/default -network available for the server creation, or use ``fixed_network_name`` to -inform Tempest which network to use. - -SSH Connection Configuration -"""""""""""""""""""""""""""" -There are also several different ways to actually establish a connection and -authenticate/login on the server. After a server is booted with a provided -network there are still details needed to know how to actually connect to -the server. The ``validation`` group gathers all the options regarding -connecting to and remotely accessing the created servers. - -To enable remote access to servers, there are 3 options at a minimum that are used: - - #. ``run_validation`` - #. ``connect_method`` - #. ``auth_method`` - -The ``run_validation`` is used to enable or disable ssh connectivity for -all tests (with the exception of scenario tests which do not have a flag for -enabling or disabling ssh) To enable ssh connectivity this needs be set to ``True``. - -The ``connect_method`` option is used to tell Tempest what kind of IP to use for -establishing a connection to the server. Two methods are available: ``fixed`` -and ``floating``, the later being set by default. If this is set to floating -Tempest will create a floating ip for the server before attempted to connect -to it. The IP for the floating ip is what is used for the connection. - -For the ``auth_method`` option there is currently, only one valid option, -``keypair``. With this set to ``keypair`` Tempest will create an ssh keypair -and use that for authenticating against the created server. - -Configuring Available Services ------------------------------- -OpenStack is really a constellation of several different projects which -are running together to create a cloud. However which projects you're running -is not set in stone, and which services are running is up to the deployer. -Tempest however needs to know which services are available so it can figure -out which tests it is able to run and certain setup steps which differ based -on the available services. - -The ``service_available`` section of the config file is used to set which -services are available. It contains a boolean option for each service (except -for Keystone which is a hard requirement) set it to ``True`` if the service is -available or ``False`` if it is not. - -Service Catalog -^^^^^^^^^^^^^^^ -Each project which has its own REST API contains an entry in the service -catalog. Like most things in OpenStack this is also completely configurable. -However, for Tempest to be able to figure out which endpoints should get REST -API calls for each service, it needs to know how that project is defined in the -service catalog. There are three options for each service section to accomplish -this: - - #. ``catalog_type`` - #. ``endpoint_type`` - #. ``region`` - -Setting ``catalog_type`` and ``endpoint_type`` should normally give Tempest -enough information to determine which endpoint it should pull from the service -catalog to use for talking to that particular service. However, if your cloud -has multiple regions available and you need to specify a particular one to use a -service you can set the ``region`` option in that service's section. - -It should also be noted that the default values for these options are set -to what DevStack uses (which is a de facto standard for service catalog -entries). So often nothing actually needs to be set on these options to enable -communication to a particular service. It is only if you are either not using -the same ``catalog_type`` as DevStack or you want Tempest to talk to a different -endpoint type instead of ``publicURL`` for a service that these need to be -changed. - -.. note:: - - Tempest does not serve all kinds of fancy URLs in the service catalog. The - service catalog should be in a standard format (which is going to be - standardized at the Keystone level). - Tempest expects URLs in the Service catalog in the following format: - - * ``http://example.com:1234/`` - - Examples: - - * Good - ``http://example.com:1234/v2.0`` - * Wouldn’t work - ``http://example.com:1234/xyz/v2.0/`` - (adding prefix/suffix around version etc) - -Service Feature Configuration ------------------------------ - -OpenStack provides its deployers a myriad of different configuration options to -enable anyone deploying it to create a cloud tailor-made for any individual use -case. It provides options for several different backend types, databases, -message queues, etc. However, the downside to this configurability is that -certain operations and features aren't supported depending on the configuration. -These features may or may not be discoverable from the API so the burden is -often on the user to figure out what is supported by the cloud they're talking -to. Besides the obvious interoperability issues with this it also leaves -Tempest in an interesting situation trying to figure out which tests are -expected to work. However, Tempest tests do not rely on dynamic API discovery -for a feature (assuming one exists). Instead Tempest has to be explicitly -configured as to which optional features are enabled. This is in order to -prevent bugs in the discovery mechanisms from masking failures. - -The service ``feature-enabled`` config sections are how Tempest addresses the -optional feature question. Each service that has tests for optional features -contains one of these sections. The only options in it are boolean options -with the name of a feature which is used. If it is set to false any test which -depends on that functionality will be skipped. For a complete list of all these -options refer to the sample config file. - - -API Extensions -^^^^^^^^^^^^^^ -The service feature-enabled sections often contain an ``api-extensions`` option -(or in the case of Swift a ``discoverable_apis`` option). This is used to tell -Tempest which api extensions (or configurable middleware) is used in your -deployment. It has two valid config states: either it contains a single value -``all`` (which is the default) which means that every api extension is assumed -to be enabled, or it is set to a list of each individual extension that is -enabled for that service. diff --git a/doc/source/field_guide/api.rst b/doc/source/field_guide/api.rst deleted file mode 120000 index ce0f6b722..000000000 --- a/doc/source/field_guide/api.rst +++ /dev/null @@ -1 +0,0 @@ -../../../tempest/api/README.rst \ No newline at end of file diff --git a/doc/source/field_guide/index.rst b/doc/source/field_guide/index.rst deleted file mode 120000 index 6f24b575c..000000000 --- a/doc/source/field_guide/index.rst +++ /dev/null @@ -1 +0,0 @@ -../../../tempest/README.rst \ No newline at end of file diff --git a/doc/source/field_guide/scenario.rst b/doc/source/field_guide/scenario.rst deleted file mode 120000 index 19ce39e2e..000000000 --- a/doc/source/field_guide/scenario.rst +++ /dev/null @@ -1 +0,0 @@ -../../../tempest/scenario/README.rst \ No newline at end of file diff --git a/doc/source/field_guide/unit_tests.rst b/doc/source/field_guide/unit_tests.rst deleted file mode 120000 index 67a8b2035..000000000 --- a/doc/source/field_guide/unit_tests.rst +++ /dev/null @@ -1 +0,0 @@ -../../../tempest/tests/README.rst \ No newline at end of file diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index f5628507d..000000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,86 +0,0 @@ -======================= -Tempest Testing Project -======================= - -Overview -======== - -.. toctree:: - :maxdepth: 2 - - overview - -Field Guides -============ -Tempest contains tests of many different types, the field guides -attempt to explain these in a way that makes it easy to understand -where your test contributions should go. - -.. toctree:: - :maxdepth: 1 - - field_guide/index - field_guide/api - field_guide/scenario - field_guide/unit_tests - -Users Guide -=========== - -Tempest Configuration Guide ---------------------------- - -.. toctree:: - :maxdepth: 2 - - configuration - sampleconf - -Command Documentation ---------------------- - -.. toctree:: - :maxdepth: 1 - - account_generator - cleanup - subunit_describe_calls - workspace - run - -Developers Guide -================ - -Development ------------ - -.. toctree:: - :maxdepth: 2 - - HACKING - REVIEWING - microversion_testing - test_removal - write_tests - -Plugins -------- - -.. toctree:: - :maxdepth: 2 - - plugin - plugin-registry - -Library -------- - -.. toctree:: - :maxdepth: 2 - - library - -Indices and tables -================== - -* :ref:`search` diff --git a/doc/source/library.rst b/doc/source/library.rst deleted file mode 100644 index a461a0fc0..000000000 --- a/doc/source/library.rst +++ /dev/null @@ -1,71 +0,0 @@ -.. _library: - -Tempest Library Documentation -============================= - -Tempest provides a stable library interface that provides external tools or -test suites an interface for reusing pieces of tempest code. Any public -interface that lives in tempest/lib in the tempest repo is treated as a stable -public interface and it should be safe to external consume that. Every effort -goes into maintaining backwards compatibility with any change. -The library is self contained and doesn't have any dependency on -other tempest internals outside of lib (including no usage of tempest -configuration). - -Stability ---------- -Any code that lives in tempest/lib will be treated as a stable interface. -This means that any public interface under the tempest/lib directory is -expected to be a stable interface suitable for public consumption. However, for -any interfaces outside of tempest/lib in the tempest tree (unless otherwise -noted) or any private interfaces the same stability guarantees don't apply. - -Adding Interfaces -''''''''''''''''' -When adding an interface to tempest/lib we have to make sure there are no -dependencies on any pieces of tempest outside of tempest/lib. This means if -for example there is a dependency on the configuration file we need remove that. -The other aspect when adding an interface is to make sure it's really an -interface ready for external consumption and something we want to commit to -supporting. - -Making changes -'''''''''''''' -When making changes to tempest/lib you have to be conscious of the effect of -any changes on external consumers. If your proposed changeset will change the -default behaviour of any interface, or make something which previously worked -not after your change, then it is not acceptable. Every effort needs to go into -preserving backwards compatibility in changes. - -Reviewing -''''''''' -When reviewing a proposed change to tempest/lib code we need to be careful to -ensure that we don't break backwards compatibility. For patches that change -existing interfaces we have to be careful to make sure we don't break any -external consumers. Some common red flags are: - - * a change to an existing API requires a change outside the library directory - where the interface is being consumed - * a unit test has to be significantly changed to make the proposed change pass - -Testing -''''''' -When adding a new interface to the library we need to at a minimum have unit -test coverage. A proposed change to add an interface to tempest/lib that -doesn't have unit tests shouldn't be accepted. Ideally these unit tests will -provide sufficient coverage to ensure a stable interface moving forward. - -Current Library APIs --------------------- - -.. toctree:: - :maxdepth: 2 - - library/cli - library/decorators - library/rest_client - library/utils - library/api_microversion_testing - library/auth - library/clients - library/credential_providers diff --git a/doc/source/library/api_microversion_testing.rst b/doc/source/library/api_microversion_testing.rst deleted file mode 100644 index 8be924d0a..000000000 --- a/doc/source/library/api_microversion_testing.rst +++ /dev/null @@ -1,29 +0,0 @@ -.. _api_microversion_testing: - -API Microversion Testing Support in Tempest -=========================================== - ---------------------------------------------- -Framework to support API Microversion testing ---------------------------------------------- - -Many of the OpenStack components have implemented API microversions. -It is important to test those microversions in Tempest or external plugins. -Tempest now provides stable interfaces to support to test the API microversions. -Based on the microversion range coming from the combination of both configuration -and each test case, APIs request will be made with selected microversion. - -This document explains the interfaces needed for microversion testing. - - -The api_version_request module -"""""""""""""""""""""""""""""" - -.. automodule:: tempest.lib.common.api_version_request - :members: - -The api_version_utils module -"""""""""""""""""""""""""""" - -.. automodule:: tempest.lib.common.api_version_utils - :members: diff --git a/doc/source/library/auth.rst b/doc/source/library/auth.rst deleted file mode 100644 index e1d92edb4..000000000 --- a/doc/source/library/auth.rst +++ /dev/null @@ -1,11 +0,0 @@ -.. _auth: - -Authentication Framework Usage -============================== - ---------------- -The auth module ---------------- - -.. automodule:: tempest.lib.auth - :members: diff --git a/doc/source/library/cli.rst b/doc/source/library/cli.rst deleted file mode 100644 index 6bd78810d..000000000 --- a/doc/source/library/cli.rst +++ /dev/null @@ -1,18 +0,0 @@ -.. _cli: - -CLI Testing Framework Usage -=========================== - -------------------- -The cli.base module -------------------- - -.. automodule:: tempest.lib.cli.base - :members: - ----------------------------- -The cli.output_parser module ----------------------------- - -.. automodule:: tempest.lib.cli.output_parser - :members: diff --git a/doc/source/library/clients.rst b/doc/source/library/clients.rst deleted file mode 100644 index 0f4ba4c1a..000000000 --- a/doc/source/library/clients.rst +++ /dev/null @@ -1,33 +0,0 @@ -.. _clients: - -Service Clients Usage -===================== - -Tests make requests against APIs using service clients. Service clients are -specializations of the ``RestClient`` class. The service clients that cover the -APIs exposed by a service should be grouped in a service clients module. -A service clients module is python module where all service clients are -defined. If major API versions are available, submodules should be defined, -one for each version. - -The ``ClientsFactory`` class helps initializing all clients of a specific -service client module from a set of shared parameters. - -The ``ServiceClients`` class provides a convenient way to get access to all -available service clients initialized with a provided set of credentials. - ------------------------------ -The clients management module ------------------------------ - -.. automodule:: tempest.lib.services.clients - :members: - ------------------------------- -Compute service client modules ------------------------------- - -.. toctree:: - :maxdepth: 2 - - service_clients/compute_clients diff --git a/doc/source/library/credential_providers.rst b/doc/source/library/credential_providers.rst deleted file mode 100644 index 7e831cc9a..000000000 --- a/doc/source/library/credential_providers.rst +++ /dev/null @@ -1,148 +0,0 @@ -.. _cred_providers: - -Credential Providers -==================== - -These library interfaces are used to deal with allocating credentials on demand -either dynamically by calling keystone to allocate new credentials, or from -a list of preprovisioned credentials. These 2 modules are implementations of -the same abstract credential providers class and can be used interchangably. -However, each implementation has some additional parameters that are used to -influence the behavior of the modules. The API reference at the bottom of this -doc shows the interface definitions for both modules, however that may be a bit -opaque. You can see some examples of how to leverage this interface below. - -Initialization Example ----------------------- -This example is from Tempest itself (from tempest/common/credentials_factory.py -just modified slightly) and is how it initializes the credential provider based -on config:: - - from tempest import config - from tempest.lib.common import dynamic_creds - from tempest.lib.common import preprov_creds - - CONF = config.CONF - - def get_credentials_provider(name, network_resources=None, - force_tenant_isolation=False, - identity_version=None): - # If a test requires a new account to work, it can have it via forcing - # dynamic credentials. A new account will be produced only for that test. - # In case admin credentials are not available for the account creation, - # the test should be skipped else it would fail. - identity_version = identity_version or CONF.identity.auth_version - if CONF.auth.use_dynamic_credentials or force_tenant_isolation: - admin_creds = get_configured_admin_credentials( - fill_in=True, identity_version=identity_version) - return dynamic_creds.DynamicCredentialProvider( - name=name, - network_resources=network_resources, - identity_version=identity_version, - admin_creds=admin_creds, - identity_admin_domain_scope=CONF.identity.admin_domain_scope, - identity_admin_role=CONF.identity.admin_role, - extra_roles=CONF.auth.tempest_roles, - neutron_available=CONF.service_available.neutron, - project_network_cidr=CONF.network.project_network_cidr, - project_network_mask_bits=CONF.network.project_network_mask_bits, - public_network_id=CONF.network.public_network_id, - create_networks=(CONF.auth.create_isolated_networks and not - CONF.network.shared_physical_network), - resource_prefix=CONF.resources_prefix, - credentials_domain=CONF.auth.default_credentials_domain_name, - admin_role=CONF.identity.admin_role, - identity_uri=CONF.identity.uri_v3, - identity_admin_endpoint_type=CONF.identity.v3_endpoint_type) - else: - if CONF.auth.test_accounts_file: - # Most params are not relevant for pre-created accounts - return preprov_creds.PreProvisionedCredentialProvider( - name=name, identity_version=identity_version, - accounts_lock_dir=lockutils.get_lock_path(CONF), - test_accounts_file=CONF.auth.test_accounts_file, - object_storage_operator_role=CONF.object_storage.operator_role, - object_storage_reseller_admin_role=reseller_admin_role, - credentials_domain=CONF.auth.default_credentials_domain_name, - admin_role=CONF.identity.admin_role, - identity_uri=CONF.identity.uri_v3, - identity_admin_endpoint_type=CONF.identity.v3_endpoint_type) - else: - raise exceptions.InvalidConfiguration( - 'A valid credential provider is needed') - -This function just returns an initialized credential provider class based on the -config file. The consumer of this function treats the output as the same -regardless of whether it's a dynamic or preprovisioned provider object. - -Dealing with Credentials ------------------------- - -Once you have a credential provider object created the access patterns for -allocating and removing credentials are the same across both the dynamic -and preprovisioned credentials. These are defined in the abstract -CredentialProvider class. At a high level the credentials provider enables -you to get 3 basic types of credentials at once (per object): a primary, alt, -and admin. You're also able to allocate a credential by role. These credentials -are tracked by the provider object and delete must manually be called otherwise -the created resources will not be deleted (or returned to the pool in the case -of preprovisioned creds) - -Examples -'''''''' - -Continuing from the example above, to allocate credentials by the 3 basic types -you can do the following:: - - provider = get_credentials_provider('my_tests') - primary_creds = provider.get_primary_creds() - alt_creds = provider.get_alt_creds() - admin_creds = provider.get_admin_creds() - # Make sure to delete the credentials when you're finished - provider.clear_creds() - -To create and interact with credentials by role you can do the following:: - - provider = get_credentials_provider('my_tests') - my_role_creds = provider.get_creds_by_role({'roles': ['my_role']}) - # provider.clear_creds() will clear all creds including those allocated by - # role - provider.clear_creds() - -When multiple roles are specified a set of creds with all the roles assigned -will be allocated:: - - provider = get_credentials_provider('my_tests') - my_role_creds = provider.get_creds_by_role({'roles': ['my_role', - 'my_other_role']}) - # provider.clear_creds() will clear all creds including those allocated by - # role - provider.clear_creds() - -If you need multiple sets of credentials with the same roles you can also do -this by leveraging the ``force_new`` kwarg:: - - provider = get_credentials_provider('my_tests') - my_role_creds = provider.get_creds_by_role({'roles': ['my_role']}) - my_role_other_creds = provider.get_creds_by_role({'roles': ['my_role']}, - force_new=True) - # provider.clear_creds() will clear all creds including those allocated by - # role - provider.clear_creds() - -API Reference -============= - ------------------------------- -The dynamic credentials module ------------------------------- - -.. automodule:: tempest.lib.common.dynamic_creds - :members: - --------------------------------------- -The pre-provisioned credentials module --------------------------------------- - -.. automodule:: tempest.lib.common.preprov_creds - :members: diff --git a/doc/source/library/decorators.rst b/doc/source/library/decorators.rst deleted file mode 100644 index a1739678e..000000000 --- a/doc/source/library/decorators.rst +++ /dev/null @@ -1,13 +0,0 @@ -.. _decorators: - -Decorators Usage Guide -====================== - ---------------------- -The decorators module ---------------------- - -.. automodule:: tempest.lib.decorators - :members: - - diff --git a/doc/source/library/rest_client.rst b/doc/source/library/rest_client.rst deleted file mode 100644 index 3045694f5..000000000 --- a/doc/source/library/rest_client.rst +++ /dev/null @@ -1,11 +0,0 @@ -.. _rest_client: - -Rest Client Usage -================= - ----------------------- -The rest_client module ----------------------- - -.. automodule:: tempest.lib.common.rest_client - :members: diff --git a/doc/source/library/service_clients/compute_clients.rst b/doc/source/library/service_clients/compute_clients.rst deleted file mode 100644 index 4ca55d418..000000000 --- a/doc/source/library/service_clients/compute_clients.rst +++ /dev/null @@ -1,7 +0,0 @@ -.. _servers_client: - -Compute Client Usage -==================== - -.. automodule:: tempest.lib.services.compute.servers_client - :members: diff --git a/doc/source/library/utils.rst b/doc/source/library/utils.rst deleted file mode 100644 index bc2f79b06..000000000 --- a/doc/source/library/utils.rst +++ /dev/null @@ -1,11 +0,0 @@ -.. _utils: - -Utils Usage -=========== - ---------------- -The misc module ---------------- - -.. automodule:: tempest.lib.common.utils.misc - :members: diff --git a/doc/source/microversion_testing.rst b/doc/source/microversion_testing.rst deleted file mode 100644 index 60f4f365a..000000000 --- a/doc/source/microversion_testing.rst +++ /dev/null @@ -1,341 +0,0 @@ -================================= -Microversion Testing With Tempest -================================= - -Many OpenStack Services provide their APIs with `microversion`_ -support and want to test them in Tempest. - -.. _microversion: http://specs.openstack.org/openstack/api-wg/guidelines/microversion_specification.html - -This document covers how to test microversions for each project and -whether tests should live in Tempest or on project side. - -Tempest Scope For Microversion Testing -"""""""""""""""""""""""""""""""""""""" -APIs microversions for any OpenStack service grow rapidly and -testing each and every microversion in Tempest is not feasible and -efficient way. -Also not every API microversion changes the complete system behavior -and many of them only change the API or DB layer to accept and return more -data on API. - -Tempest is an integration test suite, but not all API microversion testing fall under this category. -As a result, Tempest mainly covers integration test cases for microversions, Other testing coverage -for microversion should be hosted on project side as functional tests or via Tempest plugin as per -project guidelines. - -.. note:: Integration tests are those tests which involve more than one service to - verify the expected behavior by single or combination of API requests. - If a test is just to verify the API behavior as success and failure cases - or verify its expected response object, then it does not fall under integration - tests. - -Tempest will cover only integration testing of applicable microversions with -below exceptions: - - #. Test covers a feature which is important for interoperability. This covers tests requirement - from Defcore. - #. Test needed to fill Schema gaps. - Tempest validates API responses with defined JSON schema. API responses can be different on - each microversion and the JSON schemas need to be defined separately for the microversion. - While implementing new integration tests for a specific microversion, there - may be a gap in the JSON schemas (caused by previous microversions) implemented - in Tempest. - Filling that gap while implementing the new integration test cases is not efficient due to - many reasons: - - * Hard to review - * Sync between multiple integration tests patches which try to fill the same schema gap at same - time - * Might delay the microversion change on project side where project team wants Tempest - tests to verify the results. - - Tempest will allow to fill the schema gaps at the end of each cycle, or more - often if required. - Schema gap can be filled with testing those with a minimal set of tests. Those - tests might not be integration tests and might be already covered on project - side also. - This exception is needed because: - - * Allow to create microversion response schema in Tempest at the same time that projects are - implementing their API microversions. This will make implementation easier for adding - required tests before a new microversion change can be merged in the corresponding project - and hence accelerate the development of microversions. - * New schema must be verified by at least one test case which exercises such schema. - - For example: - If any projects implemented 4 API microversion say- v2.3, v2.4, v2.5, v2.6 - Assume microversion v2.3, v2.4, v2.6 change the API Response which means Tempest - needs to add JSON schema for v2.3, v2.4, v2.6. - In that case if only 1 or 2 tests can verify all new schemas then we do not need - separate tests for each new schemas. In worst case, we have to add 3 separate tests. - #. Test covers service behavior at large scale with involvement of more deep layer like hypervisor - etc not just API/DB layer. This type of tests will be added case by case basis and - with project team consultation about why it cannot be covered on project side and worth to test - in Tempest. - -Project Scope For Microversion Testing -"""""""""""""""""""""""""""""""""""""" -All microversions testing which are not covered under Tempest as per above section, should be -tested on project side as functional tests or as Tempest plugin as per project decision. - - -Configuration options for Microversion -"""""""""""""""""""""""""""""""""""""" - -* Add configuration options for specifying test target Microversions. - We need to specify test target Microversions because the supported - Microversions may be different between OpenStack clouds. For operating - multiple Microversion tests in a single Tempest operation, configuration - options should represent the range of test target Microversions. - New configuration options are: - - * min_microversion - * max_microversion - - Those should be defined under respective section of each service. - For example: - - .. code-block:: ini - - [compute] - min_microversion = None - max_microversion = latest - - -How To Implement Microversion Tests -""""""""""""""""""""""""""""""""""" - -Tempest provides stable interfaces to test API Microversion. -For Details, see: `API Microversion testing Framework`_ -This document explains how to implement Microversion tests using those -interfaces. - -.. _API Microversion testing Framework: https://docs.openstack.org/tempest/latest/library/api_microversion_testing.html - - -Step1: Add skip logic based on configured Microversion range -'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' - -Add logic to skip the tests based on Tests class and configured Microversion -range. -api_version_utils.check_skip_with_microversion function can be used -to automatically skip the tests which do not fall under configured -Microversion range. -For example: - -.. code-block:: python - - class BaseTestCase1(api_version_utils.BaseMicroversionTest): - - [..] - @classmethod - def skip_checks(cls): - super(BaseTestCase1, cls).skip_checks() - api_version_utils.check_skip_with_microversion(cls.min_microversion, - cls.max_microversion, - CONF.compute.min_microversion, - CONF.compute.max_microversion) - -Skip logic can be added in tests base class or any specific test class depends on -tests class structure. - -Step2: Selected API request microversion -'''''''''''''''''''''''''''''''''''''''' - -Select appropriate Microversion which needs to be used -to send with API request. -api_version_utils.select_request_microversion function can be used -to select the appropriate Microversion which will be used for API request. -For example: - -.. code-block:: python - - @classmethod - def resource_setup(cls): - super(BaseTestCase1, cls).resource_setup() - cls.request_microversion = ( - api_version_utils.select_request_microversion( - cls.min_microversion, - CONF.compute.min_microversion)) - - -Step3: Set Microversion on Service Clients -'''''''''''''''''''''''''''''''''''''''''' - -Microversion selected by Test Class in previous step needs to be set on -service clients so that APIs can be requested with selected Microversion. - -Microversion can be defined as global variable on service clients which -can be set using fixture. -Also Microversion header name needs to be defined on service clients which -should be constant because it is not supposed to be changed by project -as per API contract. -For example: - -.. code-block:: python - - COMPUTE_MICROVERSION = None - - class BaseClient1(rest_client.RestClient): - api_microversion_header_name = 'X-OpenStack-Nova-API-Version' - -Now test class can set the selected Microversion on required service clients -using fixture which can take care of resetting the same once tests is completed. -For example: - -.. code-block:: python - - def setUp(self): - super(BaseTestCase1, self).setUp() - self.useFixture(api_microversion_fixture.APIMicroversionFixture( - self.request_microversion)) - -Service clients needs to add set Microversion in API request header which -can be done by overriding the get_headers() method of rest_client. -For example: - -.. code-block:: python - - COMPUTE_MICROVERSION = None - - class BaseClient1(rest_client.RestClient): - api_microversion_header_name = 'X-OpenStack-Nova-API-Version' - - def get_headers(self): - headers = super(BaseClient1, self).get_headers() - if COMPUTE_MICROVERSION: - headers[self.api_microversion_header_name] = COMPUTE_MICROVERSION - return headers - - -Step4: Separate Test classes for each Microversion -'''''''''''''''''''''''''''''''''''''''''''''''''' - -This is last step to implement Microversion test class. - -For any Microversion tests, basically we need to implement a -separate test class. In addition, each test class defines its -Microversion range with class variable like min_microversion -and max_microversion. Tests will be valid for that defined range. -If that range is out of configured Microversion range then, test -will be skipped. - -.. note:: Microversion testing is supported at test class level not at - individual test case level. - -For example: - -Below test is applicable for Microversion from 2.2 till 2.9: - -.. code-block:: python - - class BaseTestCase1(api_version_utils.BaseMicroversionTest, - tempest.test.BaseTestCase): - - [..] - - - class Test1(BaseTestCase1): - min_microversion = '2.2' - max_microversion = '2.9' - - [..] - -Below test is applicable for Microversion from 2.10 till latest: - -.. code-block:: python - - class Test2(BaseTestCase1): - min_microversion = '2.10' - max_microversion = 'latest' - - [..] - - -Notes about Compute Microversion Tests -"""""""""""""""""""""""""""""""""""""" - -Some of the compute Microversion tests have been already implemented -with the Microversion testing framework. So for further tests only -step 4 is needed. - -Along with that JSON response schema might need versioning if needed. - -Compute service clients strictly validate the response against defined JSON -schema and does not allow additional elements in response. -So if that Microversion changed the API response then schema needs to be versioned. -New JSON schema file needs to be defined with new response attributes and service -client methods will select the schema based on requested microversion. - -If Microversion tests are implemented randomly meaning not -in sequence order(v2.20 tests added and previous Microversion tests are not yet added) -then, still schema might need to be version for older Microversion if they changed -the response. -This is because Nova Microversion includes all the previous Microversions behavior. - -For Example: - Implementing the v2.20 Microversion tests before v2.9 and 2.19- - v2.20 API request will respond as latest behavior of Nova till v2.20, - and in v2.9 and 2.19, server response has been changed so response schema needs - to be versioned accordingly. - -That can be done by using the get_schema method in below module: - -The base_compute_client module -'''''''''''''''''''''''''''''' - -.. automodule:: tempest.lib.services.compute.base_compute_client - :members: - - -Microversion tests implemented in Tempest -""""""""""""""""""""""""""""""""""""""""" - -* Compute - - * `2.1`_ - - .. _2.1: https://docs.openstack.org/nova/latest/api_microversion_history.html#id1 - - * `2.2`_ - - .. _2.2: http://docs.openstack.org/nova/latest/api_microversion_history.html#id2 - - * `2.10`_ - - .. _2.10: http://docs.openstack.org/nova/latest/api_microversion_history.html#id9 - - * `2.20`_ - - .. _2.20: http://docs.openstack.org/nova/latest/api_microversion_history.html#id18 - - * `2.25`_ - - .. _2.25: http://docs.openstack.org/nova/latest/api_microversion_history.html#maximum-in-mitaka - - * `2.32`_ - - .. _2.32: http://docs.openstack.org/nova/latest/api_microversion_history.html#id29 - - * `2.37`_ - - .. _2.37: http://docs.openstack.org/nova/latest/api_microversion_history.html#id34 - - * `2.42`_ - - .. _2.42: http://docs.openstack.org/nova/latest/api_microversion_history.html#maximum-in-ocata - - * `2.47`_ - - .. _2.47: http://docs.openstack.org/nova/latest/api_microversion_history.html#id42 - - * `2.48`_ - - .. _2.48: http://docs.openstack.org/nova/latest/api_microversion_history.html#id43 - -* Volume - - * `3.3`_ - - .. _3.3: https://docs.openstack.org/cinder/latest/devref/api_microversion_history.html#id4 diff --git a/doc/source/overview.rst b/doc/source/overview.rst deleted file mode 120000 index c768ff7d9..000000000 --- a/doc/source/overview.rst +++ /dev/null @@ -1 +0,0 @@ -../../README.rst \ No newline at end of file diff --git a/doc/source/plugin.rst b/doc/source/plugin.rst deleted file mode 100644 index b3af92f16..000000000 --- a/doc/source/plugin.rst +++ /dev/null @@ -1,346 +0,0 @@ -.. _tempest_plugin: - -============================= -Tempest Test Plugin Interface -============================= - -Tempest has an external test plugin interface which enables anyone to integrate -an external test suite as part of a tempest run. This will let any project -leverage being run with the rest of the tempest suite while not requiring the -tests live in the tempest tree. - -Creating a plugin -================= - -Creating a plugin is fairly straightforward and doesn't require much additional -effort on top of creating a test suite using tempest.lib. One thing to note with -doing this is that the interfaces exposed by tempest are not considered stable -(with the exception of configuration variables which ever effort goes into -ensuring backwards compatibility). You should not need to import anything from -tempest itself except where explicitly noted. - -Stable Tempest APIs plugins may use ------------------------------------ - -As noted above, several tempest APIs are acceptable to use from plugins, while -others are not. A list of stable APIs available to plugins is provided below: - -* tempest.lib.* -* tempest.config -* tempest.test_discover.plugins - -If there is an interface from tempest that you need to rely on in your plugin -which is not listed above, it likely needs to be migrated to tempest.lib. In -that situation, file a bug, push a migration patch, etc. to expedite providing -the interface in a reliable manner. - -Plugin Cookiecutter -------------------- - -In order to create the basic structure with base classes and test directories -you can use the tempest-plugin-cookiecutter project:: - - > pip install -U cookiecutter && cookiecutter https://git.openstack.org/openstack/tempest-plugin-cookiecutter - - Cloning into 'tempest-plugin-cookiecutter'... - remote: Counting objects: 17, done. - remote: Compressing objects: 100% (13/13), done. - remote: Total 17 (delta 1), reused 14 (delta 1) - Unpacking objects: 100% (17/17), done. - Checking connectivity... done. - project (default is "sample")? foo - testclass (default is "SampleTempestPlugin")? FooTempestPlugin - -This would create a folder called ``foo_tempest_plugin/`` with all necessary -basic classes. You only need to move/create your test in -``foo_tempest_plugin/tests``. - -Entry Point ------------ - -Once you've created your plugin class you need to add an entry point to your -project to enable tempest to find the plugin. The entry point must be added -to the "tempest.test_plugins" namespace. - -If you are using pbr this is fairly straightforward, in the setup.cfg just add -something like the following: - -.. code-block:: ini - - [entry_points] - tempest.test_plugins = - plugin_name = module.path:PluginClass - -Standalone Plugin vs In-repo Plugin ------------------------------------ - -Since all that's required for a plugin to be detected by tempest is a valid -setuptools entry point in the proper namespace there is no difference from the -tempest perspective on either creating a separate python package to -house the plugin or adding the code to an existing python project. However, -there are tradeoffs to consider when deciding which approach to take when -creating a new plugin. - -If you create a separate python project for your plugin this makes a lot of -things much easier. Firstly it makes packaging and versioning much simpler, you -can easily decouple the requirements for the plugin from the requirements for -the other project. It lets you version the plugin independently and maintain a -single version of the test code across project release boundaries (see the -`Branchless Tempest Spec`_ for more details on this). It also greatly -simplifies the install time story for external users. Instead of having to -install the right version of a project in the same python namespace as tempest -they simply need to pip install the plugin in that namespace. It also means -that users don't have to worry about inadvertently installing a tempest plugin -when they install another package. - -.. _Branchless Tempest Spec: http://specs.openstack.org/openstack/qa-specs/specs/tempest/implemented/branchless-tempest.html - -The sole advantage to integrating a plugin into an existing python project is -that it enables you to land code changes at the same time you land test changes -in the plugin. This reduces some of the burden on contributors by not having -to land 2 changes to add a new API feature and then test it and doing it as a -single combined commit. - - -Plugin Class -============ - -To provide tempest with all the required information it needs to be able to run -your plugin you need to create a plugin class which tempest will load and call -to get information when it needs. To simplify creating this tempest provides an -abstract class that should be used as the parent for your plugin. To use this -you would do something like the following: - -.. code-block:: python - - from tempest.test_discover import plugins - - class MyPlugin(plugins.TempestPlugin): - -Then you need to ensure you locally define all of the mandatory methods in the -abstract class, you can refer to the api doc below for a reference of what that -entails. - -Abstract Plugin Class ---------------------- - -.. autoclass:: tempest.test_discover.plugins.TempestPlugin - :members: - -Plugin Structure -================ -While there are no hard and fast rules for the structure a plugin, there are -basically no constraints on what the plugin looks like as long as the 2 steps -above are done. However, there are some recommended patterns to follow to make -it easy for people to contribute and work with your plugin. For example, if you -create a directory structure with something like:: - - plugin_dir/ - config.py - plugin.py - tests/ - api/ - scenario/ - services/ - client.py - -That will mirror what people expect from tempest. The file - -* **config.py**: contains any plugin specific configuration variables -* **plugin.py**: contains the plugin class used for the entry point -* **tests**: the directory where test discovery will be run, all tests should - be under this dir -* **services**: where the plugin specific service clients are - -Additionally, when you're creating the plugin you likely want to follow all -of the tempest developer and reviewer documentation to ensure that the tests -being added in the plugin act and behave like the rest of tempest. - -Dealing with configuration options ----------------------------------- - -Historically Tempest didn't provide external guarantees on its configuration -options. However, with the introduction of the plugin interface this is no -longer the case. An external plugin can rely on using any configuration option -coming from Tempest, there will be at least a full deprecation cycle for any -option before it's removed. However, just the options provided by Tempest -may not be sufficient for the plugin. If you need to add any plugin specific -configuration options you should use the ``register_opts`` and -``get_opt_lists`` methods to pass them to Tempest when the plugin is loaded. -When adding configuration options the ``register_opts`` method gets passed the -CONF object from tempest. This enables the plugin to add options to both -existing sections and also create new configuration sections for new options. - -Service Clients ---------------- - -If a plugin defines a service client, it is beneficial for it to implement the -``get_service_clients`` method in the plugin class. All service clients which -are exposed via this interface will be automatically configured and be -available in any instance of the service clients class, defined in -``tempest.lib.services.clients.ServiceClients``. In case multiple plugins are -installed, all service clients from all plugins will be registered, making it -easy to write tests which rely on multiple APIs whose service clients are in -different plugins. - -Example implementation of ``get_service_clients``: - -.. code-block:: python - - def get_service_clients(self): - # Example implementation with two service clients - my_service1_config = config.service_client_config('my_service') - params_my_service1 = { - 'name': 'my_service_v1', - 'service_version': 'my_service.v1', - 'module_path': 'plugin_tempest_tests.services.my_service.v1', - 'client_names': ['API1Client', 'API2Client'], - } - params_my_service1.update(my_service_config) - my_service2_config = config.service_client_config('my_service') - params_my_service2 = { - 'name': 'my_service_v2', - 'service_version': 'my_service.v2', - 'module_path': 'plugin_tempest_tests.services.my_service.v2', - 'client_names': ['API1Client', 'API2Client'], - } - params_my_service2.update(my_service2_config) - return [params_my_service1, params_my_service2] - -Parameters: - -* **name**: Name of the attribute used to access the ``ClientsFactory`` from - the ``ServiceClients`` instance. See example below. -* **service_version**: Tempest enforces a single implementation for each - service client. Available service clients are held in a ``ClientsRegistry`` - singleton, and registered with ``service_version``, which means that - ``service_version`` must be unique and it should represent the service API - and version implemented by the service client. -* **module_path**: Relative to the service client module, from the root of the - plugin. -* **client_names**: Name of the classes that implement service clients in the - service clients module. - -Example usage of the service clients in tests: - -.. code-block:: python - - # my_creds is instance of tempest.lib.auth.Credentials - # identity_uri is v2 or v3 depending on the configuration - from tempest.lib.services import clients - - my_clients = clients.ServiceClients(my_creds, identity_uri) - my_service1_api1_client = my_clients.my_service_v1.API1Client() - my_service2_api1_client = my_clients.my_service_v2.API1Client(my_args='any') - -Automatic configuration and registration of service clients imposes some extra -constraints on the structure of the configuration options exposed by the -plugin. - -First ``service_version`` should be in the format `service_config[.version]`. -The `.version` part is optional, and should only be used if there are multiple -versions of the same API available. The `service_config` must match the name of -a configuration options group defined by the plugin. Different versions of one -API must share the same configuration group. - -Second the configuration options group `service_config` must contain the -following options: - -* `catalog_type`: corresponds to `service` in the catalog -* `endpoint_type` - -The following options will be honoured if defined, but they are not mandatory, -as they do not necessarily apply to all service clients. - -* `region`: default to identity.region -* `build_timeout` : default to compute.build_timeout -* `build_interval`: default to compute.build_interval - -Third the service client classes should inherit from ``RestClient``, should -accept generic keyword arguments, and should pass those arguments to the -``__init__`` method of ``RestClient``. Extra arguments can be added. For -instance: - -.. code-block:: python - - class MyAPIClient(rest_client.RestClient): - - def __init__(self, auth_provider, service, region, - my_arg, my_arg2=True, **kwargs): - super(MyAPIClient, self).__init__( - auth_provider, service, region, **kwargs) - self.my_arg = my_arg - self.my_args2 = my_arg - -Finally the service client should be structured in a python module, so that all -service client classes are importable from it. Each major API version should -have its own module. - -The following folder and module structure is recommended for a single major -API version:: - - plugin_dir/ - services/ - __init__.py - client_api_1.py - client_api_2.py - -The content of __init__.py module should be: - -.. code-block:: python - - from client_api_1.py import API1Client - from client_api_2.py import API2Client - - __all__ = ['API1Client', 'API2Client'] - -The following folder and module structure is recommended for multiple major -API version:: - - plugin_dir/ - services/ - v1/ - __init__.py - client_api_1.py - client_api_2.py - v2/ - __init__.py - client_api_1.py - client_api_2.py - -The content each of __init__.py module under vN should be: - -.. code-block:: python - - from client_api_1.py import API1Client - from client_api_2.py import API2Client - - __all__ = ['API1Client', 'API2Client'] - -Using Plugins -============= - -Tempest will automatically discover any installed plugins when it is run. So by -just installing the python packages which contain your plugin you'll be using -them with tempest, nothing else is really required. - -However, you should take care when installing plugins. By their very nature -there are no guarantees when running tempest with plugins enabled about the -quality of the plugin. Additionally, while there is no limitation on running -with multiple plugins it's worth noting that poorly written plugins might not -properly isolate their tests which could cause unexpected cross interactions -between plugins. - -Notes for using plugins with virtualenvs ----------------------------------------- - -When using a tempest inside a virtualenv (like when running under tox) you have -to ensure that the package that contains your plugin is either installed in the -venv too or that you have system site-packages enabled. The virtualenv will -isolate the tempest install from the rest of your system so just installing the -plugin package on your system and then running tempest inside a venv will not -work. - -Tempest also exposes a tox job, all-plugin, which will setup a tox virtualenv -with system site-packages enabled. This will let you leverage tox without -requiring to manually install plugins in the tox venv before running tests. diff --git a/doc/source/run.rst b/doc/source/run.rst deleted file mode 100644 index ce7f03ef9..000000000 --- a/doc/source/run.rst +++ /dev/null @@ -1,7 +0,0 @@ -.. _tempest_run: - ------------ -Tempest Run ------------ - -.. automodule:: tempest.cmd.run diff --git a/doc/source/sampleconf.rst b/doc/source/sampleconf.rst deleted file mode 100644 index c2901400d..000000000 --- a/doc/source/sampleconf.rst +++ /dev/null @@ -1,13 +0,0 @@ -.. _tempest-sampleconf: - -Sample Configuration File -========================== - -The following is a sample Tempest configuration for adaptation and use. It is -auto-generated from Tempest when this documentation is built, so -if you are having issues with an option, please compare your version of -Tempest with the version of this documentation. - -The sample configuration can also be viewed in `file form <_static/tempest.conf.sample>`_. - -.. literalinclude:: _static/tempest.conf.sample diff --git a/doc/source/subunit_describe_calls.rst b/doc/source/subunit_describe_calls.rst deleted file mode 100644 index 2bda50c23..000000000 --- a/doc/source/subunit_describe_calls.rst +++ /dev/null @@ -1,5 +0,0 @@ ------------------------------- -Subunit Describe Calls Utility ------------------------------- - -.. automodule:: tempest.cmd.subunit_describe_calls diff --git a/doc/source/test_removal.rst b/doc/source/test_removal.rst deleted file mode 100644 index 07c3046b0..000000000 --- a/doc/source/test_removal.rst +++ /dev/null @@ -1,188 +0,0 @@ -Tempest Test Removal Procedure -============================== - -Historically tempest was the only way of doing functional testing and -integration testing in OpenStack. This was mostly only an artifact of tempest -being the only proven pattern for doing this, not an artifact of a design -decision. However, moving forward as functional testing is being spun up in -each individual project we really only want tempest to be the integration test -suite it was intended to be; testing the high level interactions between -projects through REST API requests. In this model there are probably existing -tests that aren't the best fit living in tempest. However, since tempest is -largely still the only gating test suite in this space we can't carelessly rip -out everything from the tree. This document outlines the procedure which was -developed to ensure we minimize the risk for removing something of value from -the tempest tree. - -This procedure might seem overly conservative and slow paced, but this is by -design to try and ensure we don't remove something that is actually providing -value. Having potential duplication between testing is not a big deal -especially compared to the alternative of removing something which is actually -providing value and is actively catching bugs, or blocking incorrect patches -from landing. - -Proposing a test removal ------------------------- - -3 prong rule for removal -^^^^^^^^^^^^^^^^^^^^^^^^ - -In the proposal etherpad we'll be looking for answers to 3 questions - - #. The tests proposed for removal must have equiv. coverage in a different - project's test suite (whether this is another gating test project, or an in - tree functional test suite). For API tests preferably the other project will - have a similar source of friction in place to prevent breaking api changes - so that we don't regress and let breaking api changes slip through the - gate. - #. The test proposed for removal has a failure rate < 0.50% in the gate over - the past release (the value and interval will likely be adjusted in the - future) - - .. _`prong #3`: - #. There must not be an external user/consumer of tempest - that depends on the test proposed for removal - -The answers to 1 and 2 are easy to verify. For 1 just provide a link to the new -test location. If you are linking to the tempest removal patch please also put -a Depends-On in the commit message for the commit which moved the test into -another repo. - -For prong 2 you can use OpenStack-Health: - -Using OpenStack-Health -"""""""""""""""""""""" - -Go to: http://status.openstack.org/openstack-health and then navigate to a per -test page for six months. You'll end up with a page that will graph the success -and failure rates on the bottom graph. For example, something like `this URL`_. - -.. _this URL: http://status.openstack.org/openstack-health/#/test/tempest.scenario.test_volume_boot_pattern.TestVolumeBootPatternV2.test_volume_boot_pattern?groupKey=project&resolutionKey=day&duration=P6M - -The Old Way using subunit2sql directly -"""""""""""""""""""""""""""""""""""""" - -SELECT * from tests where test_id like "%test_id%"; -(where $test_id is the full test_id, but truncated to the class because of -setUpClass or tearDownClass failures) - -You can access the infra mysql subunit2sql db w/ read-only permissions with: - - * hostname: logstash.openstack.org - * username: query - * password: query - * db_name: subunit2sql - -For example if you were trying to remove the test with the id: -tempest.api.compute.admin.test_flavors_negative.FlavorsAdminNegativeTestJSON.test_get_flavor_details_for_deleted_flavor -you would run the following: - - #. run: "mysql -u query -p -h logstash.openstack.org subunit2sql" to connect - to the subunit2sql db - #. run the query: MySQL [subunit2sql]> select * from tests where test_id like - "tempest.api.compute.admin.test_flavors_negative.FlavorsAdminNegativeTestJSON%"; - which will return a table of all the tests in the class (but it will also - catch failures in setUpClass and tearDownClass) - #. paste the output table with numbers and the mysql command you ran to - generate it into the etherpad. - -Eventually a cli interface will be created to make that a bit more friendly. -Also a dashboard is in the works so we don't need to manually run the command. - -The intent of the 2nd prong is to verify that moving the test into a project -specific testing is preventing bugs (assuming the tempest tests were catching -issues) from bubbling up a layer into tempest jobs. If we're seeing failure -rates above a certain threshold in the gate checks that means the functional -testing isn't really being effective in catching that bug (and therefore -blocking it from landing) and having the testing run in tempest still has -value. - -However for the 3rd prong verification is a bit more subjective. The original -intent of this prong was mostly for refstack/defcore and also for things that -running on the stable branches. We don't want to remove any tests if that -would break our api consistency checking between releases, or something that -defcore/refstack is depending on being in tempest. It's worth pointing out -that if a test is used in defcore as part of interop testing then it will -probably have continuing value being in tempest as part of the -integration/integrated tests in general. This is one area where some overlap -is expected between testing in projects and tempest, which is not a bad thing. - -Discussing the 3rd prong -"""""""""""""""""""""""" - -There are 2 approaches to addressing the 3rd prong. Either it can be raised -during a qa meeting during the tempest discussion. Please put it on the agenda -well ahead of the scheduled meeting. Since the meeting time will be well known -ahead of time anyone who depends on the tests will have ample time beforehand -to outline any concerns on the before the meeting. To give ample time for -people to respond to removal proposals please add things to the agenda by the -Monday before the meeting. - -The other option is to raise the removal on the openstack-dev mailing list. -(for example see: http://lists.openstack.org/pipermail/openstack-dev/2016-February/086218.html ) -This will raise the issue to the wider community and attract at least the same -(most likely more) attention than discussing it during the irc meeting. The -only downside is that it might take more time to get a response, given the -nature of ML. - -Exceptions to this procedure ----------------------------- - -For the most part all tempest test removals have to go through this procedure -there are a couple of exceptions though: - - #. The class of testing has been decided to be outside the scope of tempest. - #. A revert for a patch which added a broken test, or testing which didn't - actually run in the gate (basically any revert for something which - shouldn't have been added) - #. Tests that would become out of scope as a consequence of an API change, - as described in `API Compatibility`_. - Such tests cannot live in Tempest because of the branchless nature of - Tempest. Such test must still honor `prong #3`_. - -For the first exception type the only types of testing in tree which have been -declared out of scope at this point are: - - * The CLI tests (which should be completely removed at this point) - * Neutron Adv. Services testing (which should be completely removed at this - point) - * XML API Tests (which should be completely removed at this point) - * EC2 API/boto tests (which should be completely removed at this point) - -For tests that fit into this category the only criteria for removal is that -there is equivalent testing elsewhere. - -Tempest Scope -^^^^^^^^^^^^^ - -Starting in the liberty cycle tempest has defined a set of projects which -are defined as in scope for direct testing in tempest. As of today that list -is: - - * Keystone - * Nova - * Glance - * Cinder - * Neutron - * Swift - -anything that lives in tempest which doesn't test one of these projects can be -removed assuming there is equivalent testing elsewhere. Preferably using the -`tempest plugin mechanism`_ -to maintain continuity after migrating the tests out of tempest. - -.. _tempest plugin mechanism: https://docs.openstack.org/tempest/latest/plugin.html - -API Compatibility -""""""""""""""""" - -If an API introduces a non-discoverable, backward incompatible change, and -such change is not backported to all versions supported by Tempest, tests for -that API cannot live in Tempest anymore. -This is because tests would not be able to know or control which API response -to expect, and thus would not be able to enforce a specific behavior. - -If a test exists in Tempest that would meet this criteria as consequence of a -change, the test must be removed according to the procedure discussed into -this document. The API change should not be merged until all conditions -required for test removal can be met. diff --git a/doc/source/workspace.rst b/doc/source/workspace.rst deleted file mode 100644 index 41325b228..000000000 --- a/doc/source/workspace.rst +++ /dev/null @@ -1,5 +0,0 @@ ------------------ -Tempest Workspace ------------------ - -.. automodule:: tempest.cmd.workspace diff --git a/doc/source/write_tests.rst b/doc/source/write_tests.rst deleted file mode 100644 index aec55e94c..000000000 --- a/doc/source/write_tests.rst +++ /dev/null @@ -1,311 +0,0 @@ -.. _tempest_test_writing: - -Tempest Test Writing Guide -########################## - -This guide serves as a starting point for developers working on writing new -Tempest tests. At a high level tests in Tempest are just tests that conform to -the standard python `unit test`_ framework. But there are several aspects of -that are unique to Tempest and its role as an integration test suite running -against a real cloud. - -.. _unit test: https://docs.python.org/3.6/library/unittest.html - -.. note:: This guide is for writing tests in the Tempest repository. While many - parts of this guide are also applicable to Tempest plugins, not all - the APIs mentioned are considered stable or recommended for use in - plugins. Please refer to :ref:`tempest_plugin` for details about - writing plugins - - -Adding a New TestCase -===================== - -The base unit of testing in Tempest is the `TestCase`_ (also called the test -class). Each TestCase contains test methods which are the individual tests that -will be executed by the test runner. But, the TestCase is the smallest self -contained unit for tests from the Tempest perspective. It's also the level at -which Tempest is parallel safe. In other words, multiple TestCases can be -executed in parallel, but individual test methods in the same TestCase can not. -Also, all test methods within a TestCase are assumed to be executed serially. As -such you can use the test case to store variables that are shared between -methods. - -.. _TestCase: https://docs.python.org/3.6/library/unittest.html#unittest.TestCase - -In standard unittest the lifecycle of a TestCase can be described in the -following phases: - - #. setUpClass - #. setUp - #. Test Execution - #. tearDown - #. doCleanups - #. tearDownClass - -setUpClass ----------- - -The setUpClass phase is the first phase executed by the test runner and is used -to perform any setup required for all the test methods to be executed. In -Tempest this is a very important step and will automatically do the necessary -setup for interacting with the configured cloud. - -To accomplish this you do **not** define a setUpClass function, instead there -are a number of predefined phases to setUpClass that are used. The phases are: - - * skip_checks - * setup_credentials - * setup_clients - * resource_setup - -which is executed in that order. An example of a TestCase which defines all -of these would be:: - - from tempest import config - from tempest import test - - CONF = config.CONF - - - class TestExampleCase(test.BaseTestCase): - - @classmethod - def skip_checks(cls): - """This section is used to evaluate config early and skip all test - methods based on these checks - """ - super(TestExampleCase, cls).skip_checks() - if not CONF.section.foo - cls.skip('A helpful message') - - @classmethod - def setup_credentials(cls): - """This section is used to do any manual credential allocation and also - in the case of dynamic credentials to override the default network - resource creation/auto allocation - """ - # This call is used to tell the credential allocator to not create any - # network resources for this test case. It also enables selective - # creation of other neutron resources. NOTE: it must go before the - # super call - cls.set_network_resources() - super(TestExampleCase, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - """This section is used to setup client aliases from the manager object - or to initialize any additional clients. Except in a few very - specific situations you should not need to use this. - """ - super(TestExampleCase, cls).setup_clients() - cls.servers_client = cls.os_primary.servers_client - - @classmethod - def resource_setup(cls): - """This section is used to create any resources or objects which are - going to be used and shared by **all** test methods in the - TestCase. Note then anything created in this section must also be - destroyed in the corresponding resource_cleanup() method (which will - be run during tearDownClass()) - """ - super(TestExampleCase, cls).resource_setup() - cls.shared_server = cls.servers_client.create_server(...) - -.. _credentials: - -Allocating Credentials -'''''''''''''''''''''' - -Since Tempest tests are all about testing a running cloud, every test will need -credentials to be able to make API requests against the cloud. Since this is -critical to operation and, when running in parallel, easy to make a mistake, -the base TestCase class will automatically allocate a regular user for each -TestCase during the setup_credentials() phase. During this process it will also -initialize a client manager object using those credentials, which will be your -entry point into interacting with the cloud. For more details on how credentials -are allocated the :ref:`tempest_cred_provider_conf` section of the Tempest -Configuration Guide provides more details on the operation of this. - -There are some cases when you need more than a single set of credentials, or -credentials with a more specialized set of roles. To accomplish this you have -to set a class variable ``credentials`` on the TestCase directly. For example:: - - from tempest import test - - class TestExampleAdmin(test.BaseTestCase): - - credentials = ['primary', 'admin'] - - @classmethod - def skip_checks(cls): - ... - -In this example the ``TestExampleAdmin`` TestCase will allocate 2 sets of -credentials, one regular user and one admin user. The corresponding manager -objects will be set as class variables ``cls.os_primary`` and ``cls.os_admin`` -respectively. You can also allocate a second user by putting **'alt'** in the -list too. A set of alt credentials are the same as primary but can be used -for tests cases that need a second user/project. - -You can also specify credentials with specific roles assigned. This is useful -for cases where there are specific RBAC requirements hard coded into an API. -The canonical example of this are swift tests which often want to test swift's -concepts of operator and reseller_admin. An actual example from Tempest on how -to do this is:: - - class PublicObjectTest(base.BaseObjectTest): - - credentials = [['operator', CONF.object_storage.operator_role], - ['operator_alt', CONF.object_storage.operator_role]] - - @classmethod - def setup_credentials(cls): - super(PublicObjectTest, cls).setup_credentials() - ... - -In this case the manager objects will be set to ``cls.os_roles_operator`` and -``cls.os_roles_operator_alt`` respectively. - - -There is no limit to how many credentials you can allocate in this manner, -however in almost every case you should **not** need more than 3 sets of -credentials per test case. - -To figure out the mapping of manager objects set on the TestCase and the -requested credentials you can reference: - -+-------------------+---------------------+ -| Credentials Entry | Manager Variable | -+===================+=====================+ -| primary | cls.os_primary | -+-------------------+---------------------+ -| admin | cls.os_admin | -+-------------------+---------------------+ -| alt | cls.os_alt | -+-------------------+---------------------+ -| [$label, $role] | cls.os_roles_$label | -+-------------------+---------------------+ - -By default cls.os_primary is available since it is allocated in the base Tempest test -class (located in tempest/test.py). If your TestCase inherits from a different -direct parent class (it'll still inherit from the BaseTestCase, just not -directly) be sure to check if that class overrides allocated credentials. - -Dealing with Network Allocation -''''''''''''''''''''''''''''''' - -When Neutron is enabled and a testing requires networking this isn't normally -automatically setup when a tenant is created. Since Tempest needs isolated -tenants to function properly it also needs to handle network allocation. By -default the base test class will allocate a network, subnet, and router -automatically (this depends on the configured credential provider, for more -details see: :ref:`tempest_conf_network_allocation`). However, there are -situations where you do no need all of these resources allocated (or your -TestCase inherits from a class that overrides the default in tempest/test.py). -There is a class level mechanism to override this allocation and specify which -resources you need. To do this you need to call `cls.set_network_resources()` -in the `setup_credentials()` method before the `super()`. For example:: - - from tempest import test - - - class TestExampleCase(test.BaseTestCase): - - @classmethod - def setup_credentials(cls): - cls.set_network_resources(network=True, subnet=True, router=False) - super(TestExampleCase, cls).setup_credentials() - -There are 2 quirks with the usage here. First for the set_network_resources -function to work properly it **must be called before super()**. This is so -that children classes' settings are always used instead of a parent classes'. -The other quirk here is that if you do not want to allocate any network -resources for your test class simply call `set_network_resources()` without -any arguments. For example:: - - from tempest import test - - - class TestExampleCase(test.BaseTestCase): - - @classmethod - def setup_credentials(cls): - cls.set_network_resources() - super(TestExampleCase, cls).setup_credentials() - -This will not allocate any networking resources. This is because by default all -the arguments default to False. - -It's also worth pointing out that it is common for base test classes for -different services (and scenario tests) to override this setting. When -inheriting from classes other than the base TestCase in tempest/test.py it is -worth checking the immediate parent for what is set to determine if your -class needs to override that setting. - -Interacting with Credentials and Clients -======================================== - -Once you have your basic TestCase setup you'll want to start writing tests. To -do that you need to interact with an OpenStack deployment. This section will -cover how credentials and clients are used inside of Tempest tests. - - -Manager Objects ---------------- - -The primary interface with which you interact with both credentials and -API clients is the client manager object. These objects are created -automatically by the base test class as part of credential setup (for more -details see the previous :ref:`credentials` section). Each manager object is -initialized with a set of credentials and has each client object already setup -to use that set of credentials for making all the API requests. Each client is -accessible as a top level attribute on the manager object. So to start making -API requests you just access the client's method for making that call and the -credentials are already setup for you. For example if you wanted to make an API -call to create a server in Nova:: - - from tempest import test - - - class TestExampleCase(test.BaseTestCase): - def test_example_create_server(self): - self.os_primary.servers_client.create_server(...) - -is all you need to do. As described previously, in the above example the -``self.os_primary`` is created automatically because the base test class sets the -``credentials`` attribute to allocate a primary credential set and initializes -the client manager as ``self.os_primary``. This same access pattern can be used -for all of the clients in Tempest. - -Credentials Objects -------------------- - -In certain cases you need direct access to the credentials (the most common -use case would be an API request that takes a user or project id in the request -body). If you're in a situation where you need to access this you'll need to -access the ``credentials`` object which is allocated from the configured -credential provider in the base test class. This is accessible from the manager -object via the manager's ``credentials`` attribute. For example:: - - from tempest import test - - - class TestExampleCase(test.BaseTestCase): - def test_example_create_server(self): - credentials = self.os_primary.credentials - -The credentials object provides access to all of the credential information you -would need to make API requests. For example, building off the previous -example:: - - from tempest import test - - - class TestExampleCase(test.BaseTestCase): - def test_example_create_server(self): - credentials = self.os_primary.credentials - username = credentials.username - user_id = credentials.user_id - password = credentials.password - tenant_id = credentials.tenant_id diff --git a/etc/accounts.yaml.sample b/etc/accounts.yaml.sample deleted file mode 100644 index 3dbed79e9..000000000 --- a/etc/accounts.yaml.sample +++ /dev/null @@ -1,62 +0,0 @@ -# The number of accounts required can be estimated as CONCURRENCY x 2 -# It is expected that each user provided here will be in a different tenant. -# This is required to provide isolation between test for running in parallel -# -# Valid fields for credentials are defined in the descendants of -# lib.auth.Credentials - see KeystoneV[2|3]Credentials.ATTRIBUTES -# -# The fields in KeystoneV3Credentials behave as follows: -# -# tenant_[id|name] also sets project_[id|name]. -# -# project_[id|name] also sets tenant_[id|name]. -# -# Providing distinct values for both tenant_[id|name] and project_[id|name] -# will result in an InvalidCredentials exception. -# -# The value of project_domain_[id|name] is used for user_domain_[id|name] if -# the latter is not specified. -# -# The value of user_domain_[id|name] is used for project_domain_[id|name] if -# the latter is not specified. -# -# The value of domain_[id|name] is used for project_domain_[id|name] if not -# specified and user_domain_[id|name] if not specified. - -- username: 'user_1' - tenant_name: 'test_tenant_1' - password: 'test_password' - -- username: 'user_2' - tenant_name: 'test_tenant_2' - password: 'test_password' - -# To specify which roles a user has list them under the roles field -- username: 'multi_role_user' - tenant_name: 'test_tenant_42' - password: 'test_password' - roles: - - 'fun_role' - - 'not_an_admin' - - 'an_admin' - -# To specify a user has a role specified in the config file you can use the -# type field to specify it, valid values are admin, operator, and reseller_admin -- username: 'swift_pseudo_admin_user_1' - tenant_name: 'admin_tenant_1' - password: 'test_password' - types: - - 'reseller_admin' - - 'operator' - -# Networks can be specified to tell tempest which network it should use when -# creating servers with an account - -- username: 'admin_user_1' - tenant_name: 'admin_tenant_1' - password: 'test_password' - types: - - 'admin' - resources: - network: 'public' - router: 'admin_tenant_1-router' diff --git a/etc/logging.conf.sample b/etc/logging.conf.sample deleted file mode 100644 index c131b07fa..000000000 --- a/etc/logging.conf.sample +++ /dev/null @@ -1,35 +0,0 @@ -[loggers] -keys=root - -[handlers] -keys=file,devel,syslog - -[formatters] -keys=simple,tests - -[logger_root] -level=DEBUG -handlers=file - -[handler_file] -class=FileHandler -level=DEBUG -args=('tempest.log', 'w+') -formatter=tests - -[handler_syslog] -class=handlers.SysLogHandler -level=ERROR -args = ('/dev/log', handlers.SysLogHandler.LOG_USER) - -[handler_devel] -class=StreamHandler -level=DEBUG -args=(sys.stdout,) -formatter=simple - -[formatter_tests] -class = oslo_log.formatters.ContextFormatter - -[formatter_simple] -format=%(asctime)s.%(msecs)03d %(process)d %(levelname)s: %(message)s diff --git a/etc/whitelist.yaml b/etc/whitelist.yaml deleted file mode 100644 index e69de29bb..000000000 diff --git a/releasenotes/notes/10/10.0-supported-openstack-releases-b88db468695348f6.yaml b/releasenotes/notes/10/10.0-supported-openstack-releases-b88db468695348f6.yaml deleted file mode 100644 index 217c2f6b6..000000000 --- a/releasenotes/notes/10/10.0-supported-openstack-releases-b88db468695348f6.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -other: - - OpenStack Releases Supported at this time are the same as in the - previous release 9, - **Kilo** and - **Liberty**. - - - The release under current development as of this tag is Mitaka, - meaning that every Tempest commit is also tested against master during - the Mitaka cycle. However, this does not necessarily mean that using - Tempest as of this tag will work against a Mitaka (or future releases) - cloud. diff --git a/releasenotes/notes/10/10.0.0-Tempest-library-interface-0eb680b810139a50.yaml b/releasenotes/notes/10/10.0.0-Tempest-library-interface-0eb680b810139a50.yaml deleted file mode 100644 index c1edd6316..000000000 --- a/releasenotes/notes/10/10.0.0-Tempest-library-interface-0eb680b810139a50.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -prelude: | - This release includes the addition of the stable library interface for - tempest. This behaves just as tempest-lib did prior to this, but instead - it lives directly in the tempest project. For more information refer to - the `library docs`_. - - .. _library docs: https://docs.openstack.org/tempest/latest/library.html#current-library-apis - -features: - - Tempest library interface diff --git a/releasenotes/notes/10/10.0.0-start-using-reno-ed9518126fd0e1a3.yaml b/releasenotes/notes/10/10.0.0-start-using-reno-ed9518126fd0e1a3.yaml deleted file mode 100644 index 0bc9af58a..000000000 --- a/releasenotes/notes/10/10.0.0-start-using-reno-ed9518126fd0e1a3.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -other: - - Start using reno for managing release notes. diff --git a/releasenotes/notes/11/11.0.0-api-microversion-testing-support-2ceddd2255670932.yaml b/releasenotes/notes/11/11.0.0-api-microversion-testing-support-2ceddd2255670932.yaml deleted file mode 100644 index e98671a52..000000000 --- a/releasenotes/notes/11/11.0.0-api-microversion-testing-support-2ceddd2255670932.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -features: - - Tempest library interface addition(API Microversion testing interfaces). \ No newline at end of file diff --git a/releasenotes/notes/11/11.0.0-compute-microversion-support-e0b23f960f894b9b.yaml b/releasenotes/notes/11/11.0.0-compute-microversion-support-e0b23f960f894b9b.yaml deleted file mode 100644 index de1b35ee1..000000000 --- a/releasenotes/notes/11/11.0.0-compute-microversion-support-e0b23f960f894b9b.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -features: - - Compute Microversion testing support in Service Clients. diff --git a/releasenotes/notes/11/11.0.0-supported-openstack-releases-1e5d7295d939d439.yaml b/releasenotes/notes/11/11.0.0-supported-openstack-releases-1e5d7295d939d439.yaml deleted file mode 100644 index 09ff15d14..000000000 --- a/releasenotes/notes/11/11.0.0-supported-openstack-releases-1e5d7295d939d439.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -prelude: > - This release is marking the start of Mitaka release support in tempest -other: - - OpenStack Releases Supported at this time are **Kilo**, **Liberty**, - **Mitaka** - - The release under current development as of this tag is Newton, - meaning that every Tempest commit is also tested against master during - the Newton cycle. However, this does not necessarily mean that using - Tempest as of this tag will work against a Newton (or future releases) - cloud. diff --git a/releasenotes/notes/12/12.0.0-supported-openstack-releases-f10aac381d933dd1.yaml b/releasenotes/notes/12/12.0.0-supported-openstack-releases-f10aac381d933dd1.yaml deleted file mode 100644 index 9baf0352a..000000000 --- a/releasenotes/notes/12/12.0.0-supported-openstack-releases-f10aac381d933dd1.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -prelude: > - This release is marking the end of Kilo release support in Tempest -other: - - OpenStack Releases Supported after this release are **Liberty** - and **Mitaka** - - The release under current development as of this tag is Newton, - meaning that every Tempest commit is also tested against master during - the Newton cycle. However, this does not necessarily mean that using - Tempest as of this tag will work against a Newton (or future releases) - cloud. diff --git a/releasenotes/notes/12/12.1.0-add-network-versions-client-d90e8334e1443f5c.yaml b/releasenotes/notes/12/12.1.0-add-network-versions-client-d90e8334e1443f5c.yaml deleted file mode 100644 index 07e3151ff..000000000 --- a/releasenotes/notes/12/12.1.0-add-network-versions-client-d90e8334e1443f5c.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - Adds a network version client for querying - Neutron's API version discovery URL ("GET /"). diff --git a/releasenotes/notes/12/12.1.0-add-scope-to-auth-b5a82493ea89f41e.yaml b/releasenotes/notes/12/12.1.0-add-scope-to-auth-b5a82493ea89f41e.yaml deleted file mode 100644 index 297279f99..000000000 --- a/releasenotes/notes/12/12.1.0-add-scope-to-auth-b5a82493ea89f41e.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - Tempest library auth interface now supports scope. Scope allows to control - the scope of tokens requested via the identity API. Identity V2 supports - unscoped and project scoped tokens, but only the latter are implemented. - Identity V3 supports unscoped, project and domain scoped token, all three - are available. \ No newline at end of file diff --git a/releasenotes/notes/12/12.1.0-add-tempest-run-3d0aaf69c2ca4115.yaml b/releasenotes/notes/12/12.1.0-add-tempest-run-3d0aaf69c2ca4115.yaml deleted file mode 100644 index 429bf52a5..000000000 --- a/releasenotes/notes/12/12.1.0-add-tempest-run-3d0aaf69c2ca4115.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - Adds the tempest run command to the unified tempest CLI. This new command - is used for running tempest tests. diff --git a/releasenotes/notes/12/12.1.0-add-tempest-workspaces-228a2ba4690b5589.yaml b/releasenotes/notes/12/12.1.0-add-tempest-workspaces-228a2ba4690b5589.yaml deleted file mode 100644 index 9a1cef6e1..000000000 --- a/releasenotes/notes/12/12.1.0-add-tempest-workspaces-228a2ba4690b5589.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - Adds tempest workspaces command and WorkspaceManager. - This is used to have a centralized repository for managing - different tempest configurations. diff --git a/releasenotes/notes/12/12.1.0-add_subunit_describe_calls-5498a37e6cd66c4b.yaml b/releasenotes/notes/12/12.1.0-add_subunit_describe_calls-5498a37e6cd66c4b.yaml deleted file mode 100644 index 092014e61..000000000 --- a/releasenotes/notes/12/12.1.0-add_subunit_describe_calls-5498a37e6cd66c4b.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -features: - - | - Adds subunit-describe-calls. A parser for subunit streams to determine what - REST API calls are made inside of a test and in what order they are called. - - * Input can be piped in or a file can be specified - * Output is shortened for stdout, the output file has more information diff --git a/releasenotes/notes/12/12.1.0-bug-1486834-7ebca15836ae27a9.yaml b/releasenotes/notes/12/12.1.0-bug-1486834-7ebca15836ae27a9.yaml deleted file mode 100644 index b2190f368..000000000 --- a/releasenotes/notes/12/12.1.0-bug-1486834-7ebca15836ae27a9.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - | - Tempest library auth interface now supports - filtering with catalog name. Note that filtering by - name is only successful if a known service type is - provided. diff --git a/releasenotes/notes/12/12.1.0-identity-clients-as-library-e663c6132fcac6c2.yaml b/releasenotes/notes/12/12.1.0-identity-clients-as-library-e663c6132fcac6c2.yaml deleted file mode 100644 index f9173a007..000000000 --- a/releasenotes/notes/12/12.1.0-identity-clients-as-library-e663c6132fcac6c2.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -features: - - | - Define identity service clients as libraries - The following identity service clients are defined as library interface, - so the other projects can use these modules as stable libraries without - any maintenance changes. - - * endpoints_client(v2) - * roles_client(v2) - * services_client(v2) - * tenants_client(v2) - * users_client(v2) diff --git a/releasenotes/notes/12/12.1.0-image-clients-as-library-86d17caa26ce3961.yaml b/releasenotes/notes/12/12.1.0-image-clients-as-library-86d17caa26ce3961.yaml deleted file mode 100644 index 1fa4dddc1..000000000 --- a/releasenotes/notes/12/12.1.0-image-clients-as-library-86d17caa26ce3961.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -features: - - | - Define image service clients as libraries - The following image service clients are defined as library interface, - so the other projects can use these modules as stable libraries - without any maintenance changes. - - * image_members_client(v1) - * images_client(v1) - * image_members_client(v2) - * images_client(v2) - * namespaces_client(v2) - * resource_types_client(v2) - * schemas_client(v2) diff --git a/releasenotes/notes/12/12.1.0-new-test-utils-module-adf34468c4d52719.yaml b/releasenotes/notes/12/12.1.0-new-test-utils-module-adf34468c4d52719.yaml deleted file mode 100644 index 55df2b386..000000000 --- a/releasenotes/notes/12/12.1.0-new-test-utils-module-adf34468c4d52719.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -features: - - A new `test_utils` module has been added to tempest.lib.common.utils. It - should hold any common utility functions that help writing Tempest tests. - - A new utility function called `call_and_ignore_notfound_exc` has been - added to the `test_utils` module. That function call another function - passed as parameter and ignore the NotFound exception if it raised. -deprecations: - - tempest.lib.common.utils.misc.find_test_caller has been moved into the - tempest.lib.common.utils.test_utils module. Calling the find_test_caller - function with its old location is deprecated. diff --git a/releasenotes/notes/12/12.1.0-remove-input-scenarios-functionality-01308e6d4307f580.yaml b/releasenotes/notes/12/12.1.0-remove-input-scenarios-functionality-01308e6d4307f580.yaml deleted file mode 100644 index 4ee883f60..000000000 --- a/releasenotes/notes/12/12.1.0-remove-input-scenarios-functionality-01308e6d4307f580.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -upgrade: - - The input scenarios functionality no longer exists in tempest. This caused - a large number of issues for limited benefit and was only used by a single - test, test_server_basic_ops. If you were using this functionality you'll - now have to do it manually with a script and/or tempest workspaces -deprecations: - - All the options in the input-scenario group are now deprecated. These were - only used in tree by the now removed input scenarios functionality in - test_server_basic_ops. They were only deprecated because there could be - external consumers via plugins. They will be removed during the Ocata cycle. diff --git a/releasenotes/notes/12/12.1.0-remove-integrated-horizon-bb57551c1e5f5be3.yaml b/releasenotes/notes/12/12.1.0-remove-integrated-horizon-bb57551c1e5f5be3.yaml deleted file mode 100644 index 294f6d9a5..000000000 --- a/releasenotes/notes/12/12.1.0-remove-integrated-horizon-bb57551c1e5f5be3.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -upgrade: - - The integrated dashboard scenario test has been - removed and is now in a separate tempest plugin - tempest-horizon. The removed test coverage can be - used by installing tempest-horizon on the server - where you run tempest. diff --git a/releasenotes/notes/12/12.1.0-remove-legacy-credential-providers-3d653ac3ba1ada2b.yaml b/releasenotes/notes/12/12.1.0-remove-legacy-credential-providers-3d653ac3ba1ada2b.yaml deleted file mode 100644 index 89b3f4133..000000000 --- a/releasenotes/notes/12/12.1.0-remove-legacy-credential-providers-3d653ac3ba1ada2b.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -upgrade: - - The deprecated legacy credential provider has been removed. The only way to - configure credentials in tempest now is to use the dynamic or preprovisioned - credential providers diff --git a/releasenotes/notes/12/12.1.0-remove-trove-tests-666522e9113549f9.yaml b/releasenotes/notes/12/12.1.0-remove-trove-tests-666522e9113549f9.yaml deleted file mode 100644 index 7a1fc367f..000000000 --- a/releasenotes/notes/12/12.1.0-remove-trove-tests-666522e9113549f9.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -upgrade: - - All tests for the Trove project have been removed from tempest. They now - live as a tempest plugin in the trove project. diff --git a/releasenotes/notes/12/12.1.0-routers-client-as-library-25a363379da351f6.yaml b/releasenotes/notes/12/12.1.0-routers-client-as-library-25a363379da351f6.yaml deleted file mode 100644 index 35cf2c487..000000000 --- a/releasenotes/notes/12/12.1.0-routers-client-as-library-25a363379da351f6.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - Define routers_client as stable library interface. - The routers_client module is defined as library interface, - so the other projects can use the module as stable library - without any maintenance changes. diff --git a/releasenotes/notes/12/12.1.0-support-chunked-encoding-d71f53225f68edf3.yaml b/releasenotes/notes/12/12.1.0-support-chunked-encoding-d71f53225f68edf3.yaml deleted file mode 100644 index eb45523fe..000000000 --- a/releasenotes/notes/12/12.1.0-support-chunked-encoding-d71f53225f68edf3.yaml +++ /dev/null @@ -1,9 +0,0 @@ ---- -features: - - The RestClient (in tempest.lib.common.rest_client) now supports POSTing - and PUTing data with chunked transfer encoding. Just pass an `iterable` - object as the `body` argument and set the `chunked` argument to `True`. - - A new generator called `chunkify` is added in - tempest.lib.common.utils.data_utils that yields fixed-size chunks (slices) - from a Python sequence. - diff --git a/releasenotes/notes/12/12.1.0-tempest-init-global-config-dir-location-changes-12260255871d3a2b.yaml b/releasenotes/notes/12/12.1.0-tempest-init-global-config-dir-location-changes-12260255871d3a2b.yaml deleted file mode 100644 index eeda92169..000000000 --- a/releasenotes/notes/12/12.1.0-tempest-init-global-config-dir-location-changes-12260255871d3a2b.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -upgrade: - - The location on disk that the *tempest init* command looks for has changed. - Previously it would attempt to use python packaging's data files to guess - where setuptools/distutils were installing data files, which was incredibly - unreliable and depended on how you installed tempest and which versions of - setuptools, distutils, and python you had installed. Instead, now it will - use either /etc/tempest, $XDG_CONFIG_PATH/.config/tempest, or - ~/.tempest/etc (attempted in that order). If none of these exist it will - create an empty ~/.tempest/etc directory. If you were relying on the - previous behavior and none of these directories were being used you will - need to move the files to live in one of these directories. diff --git a/releasenotes/notes/12/12.2.0-add-httptimeout-in-restclient-ax78061900e3f3d7.yaml b/releasenotes/notes/12/12.2.0-add-httptimeout-in-restclient-ax78061900e3f3d7.yaml deleted file mode 100644 index a360f8ed5..000000000 --- a/releasenotes/notes/12/12.2.0-add-httptimeout-in-restclient-ax78061900e3f3d7.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - RestClient now supports setting timeout in urllib3.poolmanager. - Clients will use CONF.service_clients.http_timeout for timeout - value to wait for http request to response. - - KeystoneAuthProvider will accept http_timeout and will use it in - get_credentials. diff --git a/releasenotes/notes/12/12.2.0-add-new-identity-clients-3c3afd674a395bde.yaml b/releasenotes/notes/12/12.2.0-add-new-identity-clients-3c3afd674a395bde.yaml deleted file mode 100644 index 3ec8b5678..000000000 --- a/releasenotes/notes/12/12.2.0-add-new-identity-clients-3c3afd674a395bde.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -features: - - | - Define identity service clients as libraries. - The following identity service clients are defined as library interface, - so the other projects can use these modules as stable libraries without - any maintenance changes. - - * endpoints_client(v3) - * policies_client (v3) - * regions_client(v3) - * services_client(v3) - * projects_client(v3) diff --git a/releasenotes/notes/12/12.2.0-clients_module-16f3025f515bf9ec.yaml b/releasenotes/notes/12/12.2.0-clients_module-16f3025f515bf9ec.yaml deleted file mode 100644 index d07448aa9..000000000 --- a/releasenotes/notes/12/12.2.0-clients_module-16f3025f515bf9ec.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -features: - - The Tempest plugin interface contains a new optional method, which allows - plugins to declare and automatically register any service client defined - in the plugin. - - tempest.lib exposes a new stable interface, the clients module and - ServiceClients class, which provides a convenient way for plugin tests to - access service clients defined in Tempest as well as service clients - defined in all loaded plugins. - The new ServiceClients class only exposes for now the service clients - which are in tempest.lib, i.e. compute, network and image. The remaining - service clients (identity, volume and object-storage) will be added in - future updates. -deprecations: - - The new clients module provides a stable alternative to tempest classes - manager.Manager and clients.Manager. manager.Manager only exists now - to smoothen the transition of plugins to the new interface, but it will - be removed shortly without further notice. diff --git a/releasenotes/notes/12/12.2.0-nova_cert_default-90eb7c1e3cde624a.yaml b/releasenotes/notes/12/12.2.0-nova_cert_default-90eb7c1e3cde624a.yaml deleted file mode 100644 index cfe97c5de..000000000 --- a/releasenotes/notes/12/12.2.0-nova_cert_default-90eb7c1e3cde624a.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -upgrade: - - - The ``nova_cert`` option default is changed to ``False``. The nova - certification management APIs were a hold over from ec2, and are - not used by any other parts of nova. They are deprecated for - removal in nova after the newton release. This makes false a more - sensible default going forward. \ No newline at end of file diff --git a/releasenotes/notes/12/12.2.0-plugin-service-client-registration-00b19a2dd4935ba0.yaml b/releasenotes/notes/12/12.2.0-plugin-service-client-registration-00b19a2dd4935ba0.yaml deleted file mode 100644 index 64f729ac2..000000000 --- a/releasenotes/notes/12/12.2.0-plugin-service-client-registration-00b19a2dd4935ba0.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -features: - - A new optional interface `TempestPlugin.get_service_clients` - is available to plugins. It allows them to declare - any service client they implement. For now this is used by - tempest only, for auto-registration of service clients - in the new class `ServiceClients`. - - A new singleton class `clients.ClientsRegistry` is - available. It holds the service clients registration data - from all plugins. It is used by `ServiceClients` for - auto-registration of the service clients implemented - in plugins. diff --git a/releasenotes/notes/12/12.2.0-remove-javelin-276f62d04f7e4a1d.yaml b/releasenotes/notes/12/12.2.0-remove-javelin-276f62d04f7e4a1d.yaml deleted file mode 100644 index 8e893b8dc..000000000 --- a/releasenotes/notes/12/12.2.0-remove-javelin-276f62d04f7e4a1d.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -upgrade: - - The previously deprecated Javelin utility has been removed from Tempest. - As an alternative Ansible can be used to construct similar yaml workflows - to what Javelin used to provide. diff --git a/releasenotes/notes/12/12.2.0-service_client_config-8a1d7b4de769c633.yaml b/releasenotes/notes/12/12.2.0-service_client_config-8a1d7b4de769c633.yaml deleted file mode 100644 index 3e43f9a88..000000000 --- a/releasenotes/notes/12/12.2.0-service_client_config-8a1d7b4de769c633.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - A new helper method `service_client_config` has been added - to the stable module config.py that returns extracts from - configuration into a dictionary the configuration settings - relevant for the initisialisation of a service client. diff --git a/releasenotes/notes/12/12.2.0-volume-clients-as-library-9a3444dd63c134b3.yaml b/releasenotes/notes/12/12.2.0-volume-clients-as-library-9a3444dd63c134b3.yaml deleted file mode 100644 index cf504ad08..000000000 --- a/releasenotes/notes/12/12.2.0-volume-clients-as-library-9a3444dd63c134b3.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -features: - - | - Define volume service clients as libraries - The following volume service clients are defined as library interface, - so the other projects can use these modules as stable libraries - without any maintenance changes. - - * availability_zone_client(v1) - * availability_zone_client(v2) - * extensions_client(v1) - * extensions_client(v2) - * hosts_client(v1) - * hosts_client(v2) - * quotas_client(v1) - * quotas_client(v2) - * services_client(v1) - * services_client(v2) diff --git a/releasenotes/notes/13/13.0.0-add-new-identity-clients-as-library-5f7ndha733nwdsn9.yaml b/releasenotes/notes/13/13.0.0-add-new-identity-clients-as-library-5f7ndha733nwdsn9.yaml deleted file mode 100644 index 9e828f69b..000000000 --- a/releasenotes/notes/13/13.0.0-add-new-identity-clients-as-library-5f7ndha733nwdsn9.yaml +++ /dev/null @@ -1,15 +0,0 @@ ---- -features: - - | - Define identity service clients as libraries. - Add new service clients to the library interface so the other projects can use these modules as stable libraries without - any maintenance changes. - - * identity_client(v2) - * groups_client(v3) - * trusts_client(v3) - * users_client(v3) - * identity_client(v3) - * roles_client(v3) - * inherited_roles_client(v3) - * credentials_client(v3) diff --git a/releasenotes/notes/13/13.0.0-add-volume-clients-as-a-library-d05b6bc35e66c6ef.yaml b/releasenotes/notes/13/13.0.0-add-volume-clients-as-a-library-d05b6bc35e66c6ef.yaml deleted file mode 100644 index 9cfce0df0..000000000 --- a/releasenotes/notes/13/13.0.0-add-volume-clients-as-a-library-d05b6bc35e66c6ef.yaml +++ /dev/null @@ -1,16 +0,0 @@ ---- -features: - - | - Define volume service clients as libraries. - The following volume service clients are defined as library interface, - so the other projects can use these modules as stable libraries without - any maintenance changes. - - * backups_client - * encryption_types_client (v1) - * encryption_types_client (v2) - * qos_clients (v1) - * qos_clients (v2) - * snapshots_client (v1) - * snapshots_client (v2) - diff --git a/releasenotes/notes/13/13.0.0-deprecate-get_ipv6_addr_by_EUI64-4673f07677289cf6.yaml b/releasenotes/notes/13/13.0.0-deprecate-get_ipv6_addr_by_EUI64-4673f07677289cf6.yaml deleted file mode 100644 index 0884cfa91..000000000 --- a/releasenotes/notes/13/13.0.0-deprecate-get_ipv6_addr_by_EUI64-4673f07677289cf6.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -deprecations: - - Oslo.utils provides same method get_ipv6_addr_by_EUI64, - so deprecate it in Newton and remove it in Ocata. diff --git a/releasenotes/notes/13/13.0.0-move-call-until-true-to-tempest-lib-c9ea70dd6fe9bd15.yaml b/releasenotes/notes/13/13.0.0-move-call-until-true-to-tempest-lib-c9ea70dd6fe9bd15.yaml deleted file mode 100644 index 52c04afc1..000000000 --- a/releasenotes/notes/13/13.0.0-move-call-until-true-to-tempest-lib-c9ea70dd6fe9bd15.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -deprecations: - - The ``call_until_true`` function is moved from the ``tempest.test`` module - to the ``tempest.lib.common.utils.test_utils`` module. Backward - compatibility is preserved until Ocata. diff --git a/releasenotes/notes/13/13.0.0-start-of-newton-support-3ebb274f300f28eb.yaml b/releasenotes/notes/13/13.0.0-start-of-newton-support-3ebb274f300f28eb.yaml deleted file mode 100644 index b9b6fb581..000000000 --- a/releasenotes/notes/13/13.0.0-start-of-newton-support-3ebb274f300f28eb.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -prelude: > - This release is marking the start of Newton release support in Tempest -other: - - | - OpenStack releases supported at this time are **Liberty**, **Mitaka**, - and **Newton**. - - The release under current development as of this tag is Ocata, - meaning that every Tempest commit is also tested against master during - the Ocata cycle. However, this does not necessarily mean that using - Tempest as of this tag will work against a Ocata (or future releases) - cloud. diff --git a/releasenotes/notes/13/13.0.0-tempest-cleanup-nostandalone-39df2aafb2545d35.yaml b/releasenotes/notes/13/13.0.0-tempest-cleanup-nostandalone-39df2aafb2545d35.yaml deleted file mode 100644 index 813e47f8a..000000000 --- a/releasenotes/notes/13/13.0.0-tempest-cleanup-nostandalone-39df2aafb2545d35.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -upgrade: - - the already deprecated tempest-cleanup standalone command has been - removed. The corresponding functionalities can be accessed through - the unified `tempest` command (`tempest cleanup`). diff --git a/releasenotes/notes/13/13.0.0-volume-clients-as-library-660811011be29d1a.yaml b/releasenotes/notes/13/13.0.0-volume-clients-as-library-660811011be29d1a.yaml deleted file mode 100644 index 9e9eff66d..000000000 --- a/releasenotes/notes/13/13.0.0-volume-clients-as-library-660811011be29d1a.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Define the v1 and v2 types_client clients for the volume service as - library interfaces, allowing other projects to use these modules as - stable libraries without maintenance changes. diff --git a/releasenotes/notes/14/14.0.0-add-cred-provider-abstract-class-to-lib-70ff513221f8a871.yaml b/releasenotes/notes/14/14.0.0-add-cred-provider-abstract-class-to-lib-70ff513221f8a871.yaml deleted file mode 100644 index 6f7a41188..000000000 --- a/releasenotes/notes/14/14.0.0-add-cred-provider-abstract-class-to-lib-70ff513221f8a871.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - The cred_provider abstract class which serves as the basis for both - of tempest's cred providers, pre-provisioned credentials and dynamic - credentials, is now a library interface. This provides the common signature - required for building a credential provider. diff --git a/releasenotes/notes/14/14.0.0-add-cred_client-to-tempest.lib-4d4af33f969c576f.yaml b/releasenotes/notes/14/14.0.0-add-cred_client-to-tempest.lib-4d4af33f969c576f.yaml deleted file mode 100644 index 432a6b155..000000000 --- a/releasenotes/notes/14/14.0.0-add-cred_client-to-tempest.lib-4d4af33f969c576f.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - The cred_client module was added to tempest.lib. This module provides a - wrapper to the keystone services client which provides a uniform - interface that abstracts out the differences between keystone api versions. diff --git a/releasenotes/notes/14/14.0.0-add-error-code-translation-to-versions-clients-acbc78292e24b014.yaml b/releasenotes/notes/14/14.0.0-add-error-code-translation-to-versions-clients-acbc78292e24b014.yaml deleted file mode 100644 index 57bf47c56..000000000 --- a/releasenotes/notes/14/14.0.0-add-error-code-translation-to-versions-clients-acbc78292e24b014.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -upgrade: - - Add an error translation to list_versions() of versions_client of both - compute and network. This can affect users who are expecting that these - clients return error status code instead of the exception. It is needed - to change the code for handling the exception like the other clients code. diff --git a/releasenotes/notes/14/14.0.0-add-image-clients-af94564fb34ddca6.yaml b/releasenotes/notes/14/14.0.0-add-image-clients-af94564fb34ddca6.yaml deleted file mode 100644 index 7e40fd4d6..000000000 --- a/releasenotes/notes/14/14.0.0-add-image-clients-af94564fb34ddca6.yaml +++ /dev/null @@ -1,9 +0,0 @@ ---- -features: - - | - As in the [doc]: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html, - there are some apis are not included, add them. - - * namespace_properties_client(v2) - diff --git a/releasenotes/notes/14/14.0.0-add-role-assignments-client-as-a-library-d34b4fdf376984ad.yaml b/releasenotes/notes/14/14.0.0-add-role-assignments-client-as-a-library-d34b4fdf376984ad.yaml deleted file mode 100644 index a1edcc5c3..000000000 --- a/releasenotes/notes/14/14.0.0-add-role-assignments-client-as-a-library-d34b4fdf376984ad.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - Define the identity service role_assignments_client as a library. - Add role_assignments_client to the library interface so the other - projects can use this module as a stable library without any - maintenance changes. diff --git a/releasenotes/notes/14/14.0.0-add-service-provider-client-cbba77d424a30dd3.yaml b/releasenotes/notes/14/14.0.0-add-service-provider-client-cbba77d424a30dd3.yaml deleted file mode 100644 index b504c789a..000000000 --- a/releasenotes/notes/14/14.0.0-add-service-provider-client-cbba77d424a30dd3.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - A Neutron Service Providers client is added to deal with resources - of the '/service-providers' route. diff --git a/releasenotes/notes/14/14.0.0-add-ssh-port-parameter-to-client-6d16c374ac4456c1.yaml b/releasenotes/notes/14/14.0.0-add-ssh-port-parameter-to-client-6d16c374ac4456c1.yaml deleted file mode 100644 index b2ad1995a..000000000 --- a/releasenotes/notes/14/14.0.0-add-ssh-port-parameter-to-client-6d16c374ac4456c1.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - A new optional parameter `port` for ssh client (`tempest.lib.common.ssh.Client`) - to specify destination port for a host. The default value is 22. diff --git a/releasenotes/notes/14/14.0.0-deprecate-nova-api-extensions-df16b02485dae203.yaml b/releasenotes/notes/14/14.0.0-deprecate-nova-api-extensions-df16b02485dae203.yaml deleted file mode 100644 index c2d9a9bc9..000000000 --- a/releasenotes/notes/14/14.0.0-deprecate-nova-api-extensions-df16b02485dae203.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -deprecations: - - The *api_extensions* config option in the *compute-feature-enabled* group is - now deprecated. This option will be removed from tempest when all the - OpenStack releases supported by tempest no longer support the API extensions - mechanism. This was removed from Nova during the Newton cycle, so this will - be removed at the Mitaka EOL. diff --git a/releasenotes/notes/14/14.0.0-move-cinder-v3-to-lib-service-be3ba0c20753b594.yaml b/releasenotes/notes/14/14.0.0-move-cinder-v3-to-lib-service-be3ba0c20753b594.yaml deleted file mode 100644 index 9223ba566..000000000 --- a/releasenotes/notes/14/14.0.0-move-cinder-v3-to-lib-service-be3ba0c20753b594.yaml +++ /dev/null @@ -1,7 +0,0 @@ -features: - - | - Define the Volume v3 service clients as library interfaces, - allowing other projects to use these modules as stable - libraries without maintenance changes. - - * messages_client(v3) diff --git a/releasenotes/notes/14/14.0.0-new-volume-limit-client-517c17d9090f4df4.yaml b/releasenotes/notes/14/14.0.0-new-volume-limit-client-517c17d9090f4df4.yaml deleted file mode 100644 index 033e14788..000000000 --- a/releasenotes/notes/14/14.0.0-new-volume-limit-client-517c17d9090f4df4.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -features: - - The volume_limits client was added to tempest.lib. diff --git a/releasenotes/notes/14/14.0.0-remo-stress-tests-81052b211ad95d2e.yaml b/releasenotes/notes/14/14.0.0-remo-stress-tests-81052b211ad95d2e.yaml deleted file mode 100644 index 389b29f76..000000000 --- a/releasenotes/notes/14/14.0.0-remo-stress-tests-81052b211ad95d2e.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -prelude: > - This release is marking the end of Liberty release support in Tempest -upgrade: - - The Stress tests framework and all the stress tests have been removed. -other: - - | - OpenStack releases supported at this time are **Mitaka** and **Newton**. - - The release under current development as of this tag is Ocata, meaning that - every Tempest commit is also tested against master during the Ocata cycle. - However, this does not necessarily mean that using Tempest as of this tag - will work against a Ocata (or future releases) cloud. diff --git a/releasenotes/notes/14/14.0.0-remove-baremetal-tests-65186d9e15d5b8fb.yaml b/releasenotes/notes/14/14.0.0-remove-baremetal-tests-65186d9e15d5b8fb.yaml deleted file mode 100644 index ca2635e16..000000000 --- a/releasenotes/notes/14/14.0.0-remove-baremetal-tests-65186d9e15d5b8fb.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -upgrade: - - All tests for the Ironic project have been removed from Tempest. Those - exist as a Tempest plugin in the Ironic project. diff --git a/releasenotes/notes/14/14.0.0-remove-bootable-option-024f8944c056a3e0.yaml b/releasenotes/notes/14/14.0.0-remove-bootable-option-024f8944c056a3e0.yaml deleted file mode 100644 index e6e53aff2..000000000 --- a/releasenotes/notes/14/14.0.0-remove-bootable-option-024f8944c056a3e0.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -deprecations: - - The *bootable* config option in the *volume_feature_enabled* group is - removed because the corresponding feature os-set_bootable has been - implemented 2.5 years ago and all OpenStack versions which are supported - by Tempest should support the feature. diff --git a/releasenotes/notes/14/14.0.0-remove-negative-test-generator-1653f4c0f86ccf75.yaml b/releasenotes/notes/14/14.0.0-remove-negative-test-generator-1653f4c0f86ccf75.yaml deleted file mode 100644 index a734d1555..000000000 --- a/releasenotes/notes/14/14.0.0-remove-negative-test-generator-1653f4c0f86ccf75.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -upgrade: - - The Negative Tests Generator has been removed (it was not used by any - Tempest tests). diff --git a/releasenotes/notes/14/14.0.0-remove-sahara-tests-1532c47c7df80e3a.yaml b/releasenotes/notes/14/14.0.0-remove-sahara-tests-1532c47c7df80e3a.yaml deleted file mode 100644 index b541cf902..000000000 --- a/releasenotes/notes/14/14.0.0-remove-sahara-tests-1532c47c7df80e3a.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -upgrade: - - All tests for the Sahara project have been removed from Tempest. They now - live as a Tempest plugin in the ``openstack/sahara-tests`` repository. diff --git a/releasenotes/notes/14/14.0.0-volume-clients-as-library-309030c7a16e62ab.yaml b/releasenotes/notes/14/14.0.0-volume-clients-as-library-309030c7a16e62ab.yaml deleted file mode 100644 index 6babd93f5..000000000 --- a/releasenotes/notes/14/14.0.0-volume-clients-as-library-309030c7a16e62ab.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -features: - - | - Define volume service clients as libraries. - The following volume service clients are defined as library interface, - so the other projects can use these modules as stable libraries without - any maintenance changes. - - * volumes_client(v1) - * volumes_client(v2) - * capabilities_client(v2) - * scheduler_stats_client(v2) diff --git a/releasenotes/notes/15/15.0.0-add-identity-v3-clients-as-a-library-d34b4fdf376984ad.yaml b/releasenotes/notes/15/15.0.0-add-identity-v3-clients-as-a-library-d34b4fdf376984ad.yaml deleted file mode 100644 index 1af193948..000000000 --- a/releasenotes/notes/15/15.0.0-add-identity-v3-clients-as-a-library-d34b4fdf376984ad.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - Define the identity v3 service client domains_client as a library. - Add domains_client to the library interface so the other - projects can use this module as a stable library without any - maintenance changes. diff --git a/releasenotes/notes/15/15.0.0-add-image-clients-tests-49dbc0a0a4281a77.yaml b/releasenotes/notes/15/15.0.0-add-image-clients-tests-49dbc0a0a4281a77.yaml deleted file mode 100644 index eaab1f0b8..000000000 --- a/releasenotes/notes/15/15.0.0-add-image-clients-tests-49dbc0a0a4281a77.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -features: - - | - As in the [doc]: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html, - there are some apis are not included, add them. - - * namespace_objects_client(v2) - * namespace_tags_client(v2) - diff --git a/releasenotes/notes/15/15.0.0-add-implied-roles-to-roles-client-library-edf96408ad9ba82e.yaml b/releasenotes/notes/15/15.0.0-add-implied-roles-to-roles-client-library-edf96408ad9ba82e.yaml deleted file mode 100644 index 9116ef8b3..000000000 --- a/releasenotes/notes/15/15.0.0-add-implied-roles-to-roles-client-library-edf96408ad9ba82e.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add the implied roles feature API to the roles_client library. This - feature enables the possibility to create inferences rules between - roles (a role being implied by another role). diff --git a/releasenotes/notes/15/15.0.0-add-snapshot-manage-client-as-library-a76ffdba9d8d01cb.yaml b/releasenotes/notes/15/15.0.0-add-snapshot-manage-client-as-library-a76ffdba9d8d01cb.yaml deleted file mode 100644 index 9a4e6b195..000000000 --- a/releasenotes/notes/15/15.0.0-add-snapshot-manage-client-as-library-a76ffdba9d8d01cb.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -features: - - | - Define v2 snapshot_manage_client client for the volume service as - library interfaces, allowing other projects to use this module as - stable libraries without maintenance changes. - - * snapshot_manage_client(v2) diff --git a/releasenotes/notes/15/15.0.0-deprecate-allow_port_security_disabled-option-2d3d87f6bd11d03a.yaml b/releasenotes/notes/15/15.0.0-deprecate-allow_port_security_disabled-option-2d3d87f6bd11d03a.yaml deleted file mode 100644 index 4acdc6d2b..000000000 --- a/releasenotes/notes/15/15.0.0-deprecate-allow_port_security_disabled-option-2d3d87f6bd11d03a.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -upgrade: - - The default value for the ``allow_port_security_disabled`` option in the - ``compute-feature-enabled`` section has been changed from ``False`` - to ``True``. -deprecations: - - The ``allow_port_security_disabled`` option in the - ``compute-feature-enabled`` section is now deprecated. diff --git a/releasenotes/notes/15/15.0.0-deprecate-identity-feature-enabled.reseller-84800a8232fe217f.yaml b/releasenotes/notes/15/15.0.0-deprecate-identity-feature-enabled.reseller-84800a8232fe217f.yaml deleted file mode 100644 index c0a06d16a..000000000 --- a/releasenotes/notes/15/15.0.0-deprecate-identity-feature-enabled.reseller-84800a8232fe217f.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -upgrade: - - The default value for the ``reseller`` option in the - ``identity-feature-enabled`` section has been changed from ``False`` - to ``True``. -deprecations: - - The ``reseller`` option in the ``identity-feature-enabled`` section is now - deprecated. diff --git a/releasenotes/notes/15/15.0.0-deprecate-volume_feature_enabled.volume_services-dbe024ea067d5ab2.yaml b/releasenotes/notes/15/15.0.0-deprecate-volume_feature_enabled.volume_services-dbe024ea067d5ab2.yaml deleted file mode 100644 index c80f159d3..000000000 --- a/releasenotes/notes/15/15.0.0-deprecate-volume_feature_enabled.volume_services-dbe024ea067d5ab2.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -upgrade: - - The default value for the ``volume_services`` option in the - ``volume_feature_enabled`` section has been changed from ``False`` - to ``True``. -deprecations: - - The ``volume_services`` option in the ``volume_feature_enabled`` section - is now deprecated. diff --git a/releasenotes/notes/15/15.0.0-jsonschema-validator-2377ba131e12d3c7.yaml b/releasenotes/notes/15/15.0.0-jsonschema-validator-2377ba131e12d3c7.yaml deleted file mode 100644 index 8817ed438..000000000 --- a/releasenotes/notes/15/15.0.0-jsonschema-validator-2377ba131e12d3c7.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - Added customized JSON schema format checker for 'date-time' format. - Compute response schema will be validated against customized format - checker. diff --git a/releasenotes/notes/15/15.0.0-remove-deprecated-compute-microversion-config-options-eaee6a7d2f8390a8.yaml b/releasenotes/notes/15/15.0.0-remove-deprecated-compute-microversion-config-options-eaee6a7d2f8390a8.yaml deleted file mode 100644 index b1c0c6230..000000000 --- a/releasenotes/notes/15/15.0.0-remove-deprecated-compute-microversion-config-options-eaee6a7d2f8390a8.yaml +++ /dev/null @@ -1,9 +0,0 @@ ---- -upgrade: - - The deprecated compute microversion config options from - 'compute-feature-enabled' group have been removed. Those config options - are available under 'compute' group to configure the min and max - microversion for compute service. - - * CONF.compute.min_microversion - * CONF.compute.max_microversion diff --git a/releasenotes/notes/15/15.0.0-remove-deprecated-compute-validation-config-options-e3d1b89ce074d71c.yaml b/releasenotes/notes/15/15.0.0-remove-deprecated-compute-validation-config-options-e3d1b89ce074d71c.yaml deleted file mode 100644 index 104bf2792..000000000 --- a/releasenotes/notes/15/15.0.0-remove-deprecated-compute-validation-config-options-e3d1b89ce074d71c.yaml +++ /dev/null @@ -1,25 +0,0 @@ ---- -prelude: > - This release is marking the start of Ocata release support in Tempest -upgrade: - - | - Below deprecated config options from compute group have been removed. - Corresponding config options already been available in validation group. - - - ``compute.use_floatingip_for_ssh`` (available as ``validation.connect_method``) - - ``compute.ssh_auth_method`` (available as ``validation.auth_method``) - - ``compute.image_ssh_password`` (available as ``validation.image_ssh_password``) - - ``compute.ssh_shell_prologue`` (available as ``validation.ssh_shell_prologue``) - - ``compute.ping_size `` (available as ``validation.ping_size``) - - ``compute.ping_count `` (available as ``validation.ping_count``) - - ``compute.floating_ip_range `` (available as ``validation.floating_ip_range``) -other: - - | - OpenStack releases supported at this time are **Mitaka**, **Newton**, - and **Ocata**. - - The release under current development as of this tag is Pike, - meaning that every Tempest commit is also tested against master during - the Pike cycle. However, this does not necessarily mean that using - Tempest as of this tag will work against a Pike (or future releases) - cloud. diff --git a/releasenotes/notes/15/15.0.0-remove-deprecated-input-scenario-config-options-414e0c5442e967e9.yaml b/releasenotes/notes/15/15.0.0-remove-deprecated-input-scenario-config-options-414e0c5442e967e9.yaml deleted file mode 100644 index 371c0614a..000000000 --- a/releasenotes/notes/15/15.0.0-remove-deprecated-input-scenario-config-options-414e0c5442e967e9.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -upgrade: - - The deprecated input-scenario config options and group - have been removed. - The input scenarios functionality already being removed from tempest - and from this release, their corresponding config options too. diff --git a/releasenotes/notes/15/15.0.0-remove-deprecated-network-config-options-f9ce276231578fe6.yaml b/releasenotes/notes/15/15.0.0-remove-deprecated-network-config-options-f9ce276231578fe6.yaml deleted file mode 100644 index e445fb3ff..000000000 --- a/releasenotes/notes/15/15.0.0-remove-deprecated-network-config-options-f9ce276231578fe6.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -upgrade: - - | - Below deprecated network config options have been removed. - Those config options already been renamed to below meaningful names. - - - ``tenant_network_cidr`` (removed) -> ``project_network_cidr`` - - ``tenant_network_mask_bits`` (removed) -> ``project_network_mask_bits`` - - ``tenant_network_v6_cidr`` (removed) -> ``project_network_v6_cidr`` - - ``tenant_network_v6_mask_bits`` (removed) -> ``project_network_v6_mask_bits`` - - ``tenant_networks_reachable`` (removed) -> ``project_networks_reachable`` diff --git a/releasenotes/notes/16/16.0.0-add-OAUTH-Consumer-Client-tempest-tests-db1df7aae4a9fd4e.yaml b/releasenotes/notes/16/16.0.0-add-OAUTH-Consumer-Client-tempest-tests-db1df7aae4a9fd4e.yaml deleted file mode 100644 index 6b4566605..000000000 --- a/releasenotes/notes/16/16.0.0-add-OAUTH-Consumer-Client-tempest-tests-db1df7aae4a9fd4e.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -features: - - Add a new client to handle the OAUTH consumers feature from the identity API. diff --git a/releasenotes/notes/16/16.0.0-add-additional-methods-to-roles-client-library-178d4a6000dec72d.yaml b/releasenotes/notes/16/16.0.0-add-additional-methods-to-roles-client-library-178d4a6000dec72d.yaml deleted file mode 100644 index 01136c6af..000000000 --- a/releasenotes/notes/16/16.0.0-add-additional-methods-to-roles-client-library-178d4a6000dec72d.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - | - Add missing API call, list all role inference rules, - to the roles_client library. This feature enables the - possibility of listing all role inference rules in the - system. diff --git a/releasenotes/notes/16/16.0.0-add-cascade-parameter-to-volumes-client-ff4f7f12795003a4.yaml b/releasenotes/notes/16/16.0.0-add-cascade-parameter-to-volumes-client-ff4f7f12795003a4.yaml deleted file mode 100644 index 6801858f8..000000000 --- a/releasenotes/notes/16/16.0.0-add-cascade-parameter-to-volumes-client-ff4f7f12795003a4.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - | - Add cascade parameter to volumes_client. - This option provides the ability to delete a volume and have Cinder - handle deletion of snapshots associated with that volume by passing - an additional argument to volume delete, "cascade=True". diff --git a/releasenotes/notes/16/16.0.0-add-compute-server-evaculate-client-as-a-library-ed76baf25f02c3ca.yaml b/releasenotes/notes/16/16.0.0-add-compute-server-evaculate-client-as-a-library-ed76baf25f02c3ca.yaml deleted file mode 100644 index 848a21bca..000000000 --- a/releasenotes/notes/16/16.0.0-add-compute-server-evaculate-client-as-a-library-ed76baf25f02c3ca.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -features: - - Define the compute server evacuate client method in the servers_client library. diff --git a/releasenotes/notes/16/16.0.0-add-content-type-without-spaces-b2c9b91b257814f3.yaml b/releasenotes/notes/16/16.0.0-add-content-type-without-spaces-b2c9b91b257814f3.yaml deleted file mode 100644 index 0075a361e..000000000 --- a/releasenotes/notes/16/16.0.0-add-content-type-without-spaces-b2c9b91b257814f3.yaml +++ /dev/null @@ -1,9 +0,0 @@ ---- -upgrade: - - The ``JSON_ENC`` and ``TXT_ENC`` option in the ``_error_checker`` - section have been added with additional content-type which are - defined in RFC7231 but missing in the currnt rest_client.py file. - The lack of these additional content-type will cause defcore test - to fail for OpenStack public cloud which uses tomcat module in the - api gateway. The additions are ``application/json;charset=utf-8``, - ``text/html;charset=utf-8``,``text/plain;charset=utf-8`` \ No newline at end of file diff --git a/releasenotes/notes/16/16.0.0-add-list-auth-project-client-5905076d914a3943.yaml b/releasenotes/notes/16/16.0.0-add-list-auth-project-client-5905076d914a3943.yaml deleted file mode 100644 index 471f8f0c0..000000000 --- a/releasenotes/notes/16/16.0.0-add-list-auth-project-client-5905076d914a3943.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add the list auth projects API to the identity client library. This feature - enables the possibility to list projects that are available to be scoped - to based on the X-Auth-Token provided in the request. diff --git a/releasenotes/notes/16/16.0.0-add-list-glance-api-versions-ec5fc8081fc8a0ae.yaml b/releasenotes/notes/16/16.0.0-add-list-glance-api-versions-ec5fc8081fc8a0ae.yaml deleted file mode 100644 index acc7a4187..000000000 --- a/releasenotes/notes/16/16.0.0-add-list-glance-api-versions-ec5fc8081fc8a0ae.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add versions_client module for image service. - This new module provides list_versions() method which shows API versions - from Image service. diff --git a/releasenotes/notes/16/16.0.0-add-list-security-groups-by-servers-to-servers-client-library-088df48f6d81f4be.yaml b/releasenotes/notes/16/16.0.0-add-list-security-groups-by-servers-to-servers-client-library-088df48f6d81f4be.yaml deleted file mode 100644 index 67f954107..000000000 --- a/releasenotes/notes/16/16.0.0-add-list-security-groups-by-servers-to-servers-client-library-088df48f6d81f4be.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add the list security groups by server API to the servers_client - library. This feature enables the possibility to list security - groups for a server instance. diff --git a/releasenotes/notes/16/16.0.0-add-list-version-to-identity-client-944cb7396088a575.yaml b/releasenotes/notes/16/16.0.0-add-list-version-to-identity-client-944cb7396088a575.yaml deleted file mode 100644 index dd66ff5b6..000000000 --- a/releasenotes/notes/16/16.0.0-add-list-version-to-identity-client-944cb7396088a575.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add versions_client module for identity service. - This new module provides list_versions() method which shows API versions - from Identity service. diff --git a/releasenotes/notes/16/16.0.0-add-list-version-to-volume-client-4769dd1bd4ab9c5e.yaml b/releasenotes/notes/16/16.0.0-add-list-version-to-volume-client-4769dd1bd4ab9c5e.yaml deleted file mode 100644 index 233cc287e..000000000 --- a/releasenotes/notes/16/16.0.0-add-list-version-to-volume-client-4769dd1bd4ab9c5e.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add versions_client module for volume service. - This new module provides list_versions() method which shows API versions - from Volume service. diff --git a/releasenotes/notes/16/16.0.0-add-quota-sets-detail-kwarg-74b72183295b3ce7.yaml b/releasenotes/notes/16/16.0.0-add-quota-sets-detail-kwarg-74b72183295b3ce7.yaml deleted file mode 100644 index 06f4fcd05..000000000 --- a/releasenotes/notes/16/16.0.0-add-quota-sets-detail-kwarg-74b72183295b3ce7.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Interface show_quota_set of compute quotas_client has been extended to include the - argument "detail", which allows for detailed quota set information for a project to be - retrieved, if set to True. diff --git a/releasenotes/notes/16/16.0.0-add-tempest-lib-remote-client-adbeb3f42a36910b.yaml b/releasenotes/notes/16/16.0.0-add-tempest-lib-remote-client-adbeb3f42a36910b.yaml deleted file mode 100644 index 1b8cda2b8..000000000 --- a/releasenotes/notes/16/16.0.0-add-tempest-lib-remote-client-adbeb3f42a36910b.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -features: - - | - Add remote_client under tempest.lib. - This remote_client under tempest.lib is defined as stable - interface, and now this module provides the following - essential methods. - - - exec_command - - validate_authentication - - ping_host diff --git a/releasenotes/notes/16/16.0.0-add-tempest-run-combine-option-e94c1049ba8985d5.yaml b/releasenotes/notes/16/16.0.0-add-tempest-run-combine-option-e94c1049ba8985d5.yaml deleted file mode 100644 index 73900ca60..000000000 --- a/releasenotes/notes/16/16.0.0-add-tempest-run-combine-option-e94c1049ba8985d5.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Adds a new cli option to tempest run, --combine, which is used to indicate - you want the subunit stream output combined with the previous run's in - the testr repository diff --git a/releasenotes/notes/16/16.0.0-add-update-encryption-type-to-encryption-types-client-f3093532a0bcf9a1.yaml b/releasenotes/notes/16/16.0.0-add-update-encryption-type-to-encryption-types-client-f3093532a0bcf9a1.yaml deleted file mode 100644 index c95e77c90..000000000 --- a/releasenotes/notes/16/16.0.0-add-update-encryption-type-to-encryption-types-client-f3093532a0bcf9a1.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add update encryption type API to the v2 encryption_types_client library. - This feature enables the possibility to update an encryption type for an - existing volume type. diff --git a/releasenotes/notes/16/16.0.0-add-volume-manage-client-as-library-78ab198a1dc1bd41.yaml b/releasenotes/notes/16/16.0.0-add-volume-manage-client-as-library-78ab198a1dc1bd41.yaml deleted file mode 100644 index 34530501b..000000000 --- a/releasenotes/notes/16/16.0.0-add-volume-manage-client-as-library-78ab198a1dc1bd41.yaml +++ /dev/null @@ -1,9 +0,0 @@ ---- -features: - - | - Add the unmanage volume API service method in v2 volumes_client library. - Define v2 volume_manage_client client for the volume service as library - interfaces, allowing other projects to use this module as stable libraries - without maintenance changes. - - * volume_manage_client(v2) diff --git a/releasenotes/notes/16/16.0.0-create-server-tags-client-8c0042a77e859af6.yaml b/releasenotes/notes/16/16.0.0-create-server-tags-client-8c0042a77e859af6.yaml deleted file mode 100644 index 992797189..000000000 --- a/releasenotes/notes/16/16.0.0-create-server-tags-client-8c0042a77e859af6.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -features: - - | - Add server tags APIs to the servers_client library. - This feature enables the possibility of upating, deleting - and checking existence of a tag on a server, as well - as updating and deleting all tags on a server. - diff --git a/releasenotes/notes/16/16.0.0-deprecate-deactivate_image-config-7a282c471937bbcb.yaml b/releasenotes/notes/16/16.0.0-deprecate-deactivate_image-config-7a282c471937bbcb.yaml deleted file mode 100644 index 69c6bb6b4..000000000 --- a/releasenotes/notes/16/16.0.0-deprecate-deactivate_image-config-7a282c471937bbcb.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -deprecations: - - | - The ``deactivate_image`` configuration switch from the ``config`` module - is deprecated. It was added to support the older-than-kilo releases - which we don't support anymore. diff --git a/releasenotes/notes/16/16.0.0-deprecate-dvr_extra_resources-config-8c319d6dab7f7e5c.yaml b/releasenotes/notes/16/16.0.0-deprecate-dvr_extra_resources-config-8c319d6dab7f7e5c.yaml deleted file mode 100644 index c3e43ee77..000000000 --- a/releasenotes/notes/16/16.0.0-deprecate-dvr_extra_resources-config-8c319d6dab7f7e5c.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -deprecations: - - | - The ``dvr_extra_resources`` configuration switch from the ``config`` module - is deprecated. It was added to support the Liberty Release which we don't - support anymore. - diff --git a/releasenotes/notes/16/16.0.0-deprecate-glance-api-version-config-options-8370b63aea8e14cf.yaml b/releasenotes/notes/16/16.0.0-deprecate-glance-api-version-config-options-8370b63aea8e14cf.yaml deleted file mode 100644 index 788bc9590..000000000 --- a/releasenotes/notes/16/16.0.0-deprecate-glance-api-version-config-options-8370b63aea8e14cf.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -deprecations: - - | - Glance v1 APIs are deprecated and v2 are current. - Tempest should tests only v2 APIs. - Below API version selection config options - for glance have been deprecated and will be removed in future. - - * CONF.image_feature_enabled.api_v2 - * CONF.image_feature_enabled.api_v1 diff --git a/releasenotes/notes/16/16.0.0-deprecate-resources-prefix-option-ad490c0a30a0266b.yaml b/releasenotes/notes/16/16.0.0-deprecate-resources-prefix-option-ad490c0a30a0266b.yaml deleted file mode 100644 index f6792086b..000000000 --- a/releasenotes/notes/16/16.0.0-deprecate-resources-prefix-option-ad490c0a30a0266b.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -upgrade: - - The default value of rand_name()'s prefix argument is changed - to 'tempest' from None to identify resources are created by - Tempest. -deprecations: - - The resources_prefix is marked as deprecated because it is - enough to set 'tempest' as the prefix on rand_name() to - ideintify resources which are created by Tempest and no - projects set this option on OpenStack dev community. diff --git a/releasenotes/notes/16/16.0.0-deprecate-skip_unless_attr-decorator-450a1ed727494724.yaml b/releasenotes/notes/16/16.0.0-deprecate-skip_unless_attr-decorator-450a1ed727494724.yaml deleted file mode 100644 index 4d8b94157..000000000 --- a/releasenotes/notes/16/16.0.0-deprecate-skip_unless_attr-decorator-450a1ed727494724.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -deprecations: - - The ``skip_unless_attr`` decorator in lib/decorators.py has been deprecated, - please use the standard ``testtools.skipUnless`` and ``testtools.skipIf`` - decorators. diff --git a/releasenotes/notes/16/16.0.0-deprecate-skip_unless_config-decorator-64c32d588043ab12.yaml b/releasenotes/notes/16/16.0.0-deprecate-skip_unless_config-decorator-64c32d588043ab12.yaml deleted file mode 100644 index 6285ea6a2..000000000 --- a/releasenotes/notes/16/16.0.0-deprecate-skip_unless_config-decorator-64c32d588043ab12.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -deprecations: - - The ``skip_unless_config`` and ``skip_if_config`` decorators in the - ``config`` module have been deprecated and will be removed in the Queens - dev cycle. Use the ``testtools.skipUnless`` (or a variation of) instead. diff --git a/releasenotes/notes/16/16.0.0-deprecated-cinder-api-v1-option-df7d5a54d93db5cf.yaml b/releasenotes/notes/16/16.0.0-deprecated-cinder-api-v1-option-df7d5a54d93db5cf.yaml deleted file mode 100644 index 0660d9c1c..000000000 --- a/releasenotes/notes/16/16.0.0-deprecated-cinder-api-v1-option-df7d5a54d93db5cf.yaml +++ /dev/null @@ -1,12 +0,0 @@ ---- -deprecations: - - | - Volume v1 API is deprecated and the v3 are CURRENT. - Tempest doesn't need to test the v1 API as the default. - The volume config option 'api_v1' has been marked as - deprecated. -upgrade: - - | - The volume config option 'api_v1' default is changed to - ``False`` because the volume v1 API has been deprecated - since Juno release. diff --git a/releasenotes/notes/16/16.0.0-dreprecate_client_parameters-cb8d069e62957f7e.yaml b/releasenotes/notes/16/16.0.0-dreprecate_client_parameters-cb8d069e62957f7e.yaml deleted file mode 100644 index 4081f6a4f..000000000 --- a/releasenotes/notes/16/16.0.0-dreprecate_client_parameters-cb8d069e62957f7e.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -deprecations: - - | - Deprecate the client_parameters argument in - `tempest.lib.services.clients.ServiceClients`. The parameter is actually - not honoured already - see https://bugs.launchpad.net/tempest/+bug/1680915 diff --git a/releasenotes/notes/16/16.0.0-fix-volume-v2-service-clients-bugfix-1667354-73d2c3c8fedc08bf.yaml b/releasenotes/notes/16/16.0.0-fix-volume-v2-service-clients-bugfix-1667354-73d2c3c8fedc08bf.yaml deleted file mode 100644 index 6d3157648..000000000 --- a/releasenotes/notes/16/16.0.0-fix-volume-v2-service-clients-bugfix-1667354-73d2c3c8fedc08bf.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -fixes: - - | - Fix below volume v2 service clients to make v2 API call: Bug#1667354 - - - SchedulerStatsClient - - CapabilitiesClient diff --git a/releasenotes/notes/16/16.0.0-mitaka-eol-88ff8355fff81b55.yaml b/releasenotes/notes/16/16.0.0-mitaka-eol-88ff8355fff81b55.yaml deleted file mode 100644 index 24ec51274..000000000 --- a/releasenotes/notes/16/16.0.0-mitaka-eol-88ff8355fff81b55.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -prelude: > - This release indicates end of support for Mitaka in Tempest. -other: - - | - OpenStack Releases Supported after this release are **Newton** - and **Ocata** - - The release under current development as of this tag is Pike, - meaning that every Tempest commit is also tested against master branch - during the Pike cycle. However, this does not necessarily mean that - using Tempest as of this tag will work against Pike (or future - releases) cloud. diff --git a/releasenotes/notes/16/16.0.0-remove-call_until_true-of-test-de9c13bc8f969921.yaml b/releasenotes/notes/16/16.0.0-remove-call_until_true-of-test-de9c13bc8f969921.yaml deleted file mode 100644 index 56708211c..000000000 --- a/releasenotes/notes/16/16.0.0-remove-call_until_true-of-test-de9c13bc8f969921.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -upgrade: - - The *call_until_true* of *test* module is removed because it was marked - as deprecated and Tempest provides it from *test_utils* as a stable - interface instead. Please switch to use *test_utils.call_until_true* if - necessary. diff --git a/releasenotes/notes/16/16.0.0-remove-cinder-v1-api-tests-71e266b8d55d475f.yaml b/releasenotes/notes/16/16.0.0-remove-cinder-v1-api-tests-71e266b8d55d475f.yaml deleted file mode 100644 index 710ad9ee3..000000000 --- a/releasenotes/notes/16/16.0.0-remove-cinder-v1-api-tests-71e266b8d55d475f.yaml +++ /dev/null @@ -1,5 +0,0 @@ -upgrade: - - Remove Cinder v1 API tests. - Cinder v1 API has been deprecated since Juno release, and Juno is - not supported by current Tempest. Then Cinder v1 API tests are - removed from Tempest. diff --git a/releasenotes/notes/16/16.0.0-remove-deprecated-allow_port_security_disabled-option-d0ffaeb2e7817707.yaml b/releasenotes/notes/16/16.0.0-remove-deprecated-allow_port_security_disabled-option-d0ffaeb2e7817707.yaml deleted file mode 100644 index 9d7102fe0..000000000 --- a/releasenotes/notes/16/16.0.0-remove-deprecated-allow_port_security_disabled-option-d0ffaeb2e7817707.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -upgrade: - - | - The deprecated config option 'allow_port_security_disabled' from compute_feature_enabled - group has been removed. diff --git a/releasenotes/notes/16/16.0.0-remove-deprecated-compute-validation-config-options-part-2-5cd17b6e0e6cb8a3.yaml b/releasenotes/notes/16/16.0.0-remove-deprecated-compute-validation-config-options-part-2-5cd17b6e0e6cb8a3.yaml deleted file mode 100644 index b4e4dd105..000000000 --- a/releasenotes/notes/16/16.0.0-remove-deprecated-compute-validation-config-options-part-2-5cd17b6e0e6cb8a3.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -upgrade: - - | - Below deprecated config options from compute group have been removed. - Corresponding config options already been available in validation group. - - - ``compute.image_ssh_user`` (available as ``validation.image_ssh_user``) - - ``compute.ssh_user`` (available as ``validation.image_ssh_user``) - - ``scenario.ssh_user`` (available as ``validation.image_ssh_user``) - - ``compute.network_for_ssh`` (available as ``validation.network_for_ssh``) - - ``compute.ping_timeout `` (available as ``validation.ping_timeout``) diff --git a/releasenotes/notes/16/16.0.0-remove-deprecated-dvr_extra_resources-option-e8c441c38eab7ddd.yaml b/releasenotes/notes/16/16.0.0-remove-deprecated-dvr_extra_resources-option-e8c441c38eab7ddd.yaml deleted file mode 100644 index 889e86275..000000000 --- a/releasenotes/notes/16/16.0.0-remove-deprecated-dvr_extra_resources-option-e8c441c38eab7ddd.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -upgrade: - - | - The deprecated config option 'dvr_extra_resources' from network group has been removed. - This option was for extra resources which were provisioned to bind a router to Neutron - L3 agent. The extra resources need to be provisioned in Liberty release or older, - and are not required since Mitaka release. Current Tempest doesn't support Liberty, so - this option has been removed from Tempest. diff --git a/releasenotes/notes/16/16.0.0-remove-deprecated-identity-reseller-option-4411c7e3951f1094.yaml b/releasenotes/notes/16/16.0.0-remove-deprecated-identity-reseller-option-4411c7e3951f1094.yaml deleted file mode 100644 index 8085694f8..000000000 --- a/releasenotes/notes/16/16.0.0-remove-deprecated-identity-reseller-option-4411c7e3951f1094.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -upgrade: - - | - The deprecated config option 'reseller' from identity_feature_enabled group has been removed. diff --git a/releasenotes/notes/16/16.0.0-remove-sahara-service-available-44a642aa9c634ab4.yaml b/releasenotes/notes/16/16.0.0-remove-sahara-service-available-44a642aa9c634ab4.yaml deleted file mode 100644 index c0dc7d71a..000000000 --- a/releasenotes/notes/16/16.0.0-remove-sahara-service-available-44a642aa9c634ab4.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -fixes: - - | - The 'sahara' config option in the 'service-available' group has been moved to the sahara plugin - (openstack/sahara-tests) along with tests and service client during the Ocata timeframe. - A 'sahara' config option was left over on Tempest side, and it's removed now. - As long as the sahara plugin is installed, this change as no impact on users of sahara tests. diff --git a/releasenotes/notes/16/16.0.0-remove-volume_feature_enabled.volume_services-c6aa142cc1021297.yaml b/releasenotes/notes/16/16.0.0-remove-volume_feature_enabled.volume_services-c6aa142cc1021297.yaml deleted file mode 100644 index fc15995a3..000000000 --- a/releasenotes/notes/16/16.0.0-remove-volume_feature_enabled.volume_services-c6aa142cc1021297.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -upgrade: - - | - The deprecated ``volume_services`` option in the ``volume_feature_enabled`` - section has now been removed. diff --git a/releasenotes/notes/16/16.0.0-use-keystone-v3-api-935860d30ddbb8e9.yaml b/releasenotes/notes/16/16.0.0-use-keystone-v3-api-935860d30ddbb8e9.yaml deleted file mode 100644 index dd6e92457..000000000 --- a/releasenotes/notes/16/16.0.0-use-keystone-v3-api-935860d30ddbb8e9.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -upgrade: - - Tempest now defaults to using Keystone v3 API for the - authentication, because Keystone v3 API is CURRENT and - the v2 API is deprecated. diff --git a/releasenotes/notes/16/16.0.0-volume-transfers-client-e5ed3f5464c0cdc0.yaml b/releasenotes/notes/16/16.0.0-volume-transfers-client-e5ed3f5464c0cdc0.yaml deleted file mode 100644 index e5e479bf9..000000000 --- a/releasenotes/notes/16/16.0.0-volume-transfers-client-e5ed3f5464c0cdc0.yaml +++ /dev/null @@ -1,18 +0,0 @@ ---- -features: - - | - Define volume transfers service clients as libraries. - The following volume transfers service clients are defined as library interface. - - * transfers_client(v2) -deprecations: - - | - Deprecate volume v2 transfers resource methods from volumes_client(v2) libraries. - Same methods are available in new transfers service client: transfers_client(v2) - The following methods of volume v2 volumes_clients have been deprecated: - - * create_volume_transfer (v2.volumes_client) - * show_volume_transfer (v2.volumes_client) - * list_volume_transfers (v2.volumes_client) - * delete_volume_transfer (v2.volumes_client) - * accept_volume_transfer (v2.volumes_client) diff --git a/releasenotes/notes/add-OAUTH-Token-Client-tempest-tests-6351eda451b95a86.yaml b/releasenotes/notes/add-OAUTH-Token-Client-tempest-tests-6351eda451b95a86.yaml deleted file mode 100644 index 9115f03a2..000000000 --- a/releasenotes/notes/add-OAUTH-Token-Client-tempest-tests-6351eda451b95a86.yaml +++ /dev/null @@ -1,3 +0,0 @@ ---- -features: - - Add a new client to handle the OAUTH token feature from the identity API. diff --git a/releasenotes/notes/add-compute-feature-serial-console-45583c4341e34fc9.yaml b/releasenotes/notes/add-compute-feature-serial-console-45583c4341e34fc9.yaml deleted file mode 100644 index 18fd5adfa..000000000 --- a/releasenotes/notes/add-compute-feature-serial-console-45583c4341e34fc9.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - | - A new boolean config option ``serial_console`` is added to the section - ``compute-feature-enabled``. If enabled, tests, which validate the - behavior of Nova's *serial console* feature (an alternative to VNC, - RDP, SPICE) can be executed. diff --git a/releasenotes/notes/add-domain-configuration-client-tempest-tests-e383efabdbb9ad03.yaml b/releasenotes/notes/add-domain-configuration-client-tempest-tests-e383efabdbb9ad03.yaml deleted file mode 100644 index 565368180..000000000 --- a/releasenotes/notes/add-domain-configuration-client-tempest-tests-e383efabdbb9ad03.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - | - Add a new client to handle the domain configuration feature from the - identity v3 API. diff --git a/releasenotes/notes/add-floating-ip-config-option-e5774bf77702ce9f.yaml b/releasenotes/notes/add-floating-ip-config-option-e5774bf77702ce9f.yaml deleted file mode 100644 index 8221d7882..000000000 --- a/releasenotes/notes/add-floating-ip-config-option-e5774bf77702ce9f.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - A new config option in the network-feature-enabled section, floating_ips, - to specify whether floating ips are available in the cloud under test. By - default this is set to True. diff --git a/releasenotes/notes/add-force-detach-volume-to-volumes-client-library-b2071f2954f8e8b1.yaml b/releasenotes/notes/add-force-detach-volume-to-volumes-client-library-b2071f2954f8e8b1.yaml deleted file mode 100644 index a0156a05f..000000000 --- a/releasenotes/notes/add-force-detach-volume-to-volumes-client-library-b2071f2954f8e8b1.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add force detach volume feature API to v2 volumes_client library. - This feature enables the possibility to force a volume to detach, and - roll back an unsuccessful detach operation after you disconnect the volume. diff --git a/releasenotes/notes/add-identity-v3-clients-for-os-ep-filter-api-endpoint-groups-3518a90bbb731d0f.yaml b/releasenotes/notes/add-identity-v3-clients-for-os-ep-filter-api-endpoint-groups-3518a90bbb731d0f.yaml deleted file mode 100644 index 1dc33aaf9..000000000 --- a/releasenotes/notes/add-identity-v3-clients-for-os-ep-filter-api-endpoint-groups-3518a90bbb731d0f.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - | - Defines the identity v3 OS-EP-FILTER EndPoint Groups API client. - This client manages Create, Get, Update, Check, List, and Delete - of EndPoint Group. - diff --git a/releasenotes/notes/add-identity-v3-clients-for-os-ep-filter-api-extensions-9cfd217fd2c6a61f.yaml b/releasenotes/notes/add-identity-v3-clients-for-os-ep-filter-api-extensions-9cfd217fd2c6a61f.yaml deleted file mode 100644 index 69320fb3e..000000000 --- a/releasenotes/notes/add-identity-v3-clients-for-os-ep-filter-api-extensions-9cfd217fd2c6a61f.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Defines the identity v3 OS-EP-FILTER extension API client. - This client manages associations between endpoints, projects - along with groups. diff --git a/releasenotes/notes/add-kwargs-to-delete-vol-of-vol-client-1ecde75beb62933c.yaml b/releasenotes/notes/add-kwargs-to-delete-vol-of-vol-client-1ecde75beb62933c.yaml deleted file mode 100644 index b8c9dfcdb..000000000 --- a/releasenotes/notes/add-kwargs-to-delete-vol-of-vol-client-1ecde75beb62933c.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - | - The ``delete_volume`` method of the ``VolumesClient`` class - now has an additional ``**params`` argument that enables passing - additional information in the query string of the HTTP request. - diff --git a/releasenotes/notes/add-list-volume-transfers-with-detail-to-transfers-client-80169bf78cf4fa66.yaml b/releasenotes/notes/add-list-volume-transfers-with-detail-to-transfers-client-80169bf78cf4fa66.yaml deleted file mode 100644 index 8e85d3a1b..000000000 --- a/releasenotes/notes/add-list-volume-transfers-with-detail-to-transfers-client-80169bf78cf4fa66.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - | - Add list volume transfers with details API to v2 transfers_client library. - This feature enables the possibility to list volume transfers with details. diff --git a/releasenotes/notes/add-manage-snapshot-ref-config-option-67efd04897335b67.yaml b/releasenotes/notes/add-manage-snapshot-ref-config-option-67efd04897335b67.yaml deleted file mode 100644 index bc7bcc8e6..000000000 --- a/releasenotes/notes/add-manage-snapshot-ref-config-option-67efd04897335b67.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - | - A new config option 'manage_snapshot_ref' is added in the volume section, - to specify snapshot ref parameter for different storage backend drivers - when managing an existing snapshot. By default it is set to fit the LVM - driver. diff --git a/releasenotes/notes/add-params-to-identity-v3-list-endpoints-958a155be4e17e5b.yaml b/releasenotes/notes/add-params-to-identity-v3-list-endpoints-958a155be4e17e5b.yaml deleted file mode 100644 index 46f3b49c4..000000000 --- a/releasenotes/notes/add-params-to-identity-v3-list-endpoints-958a155be4e17e5b.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - The ``list_endpoints`` method of the v3 ``EndPointsClient`` class now has - an additional ``**params`` argument that enables passing additional - information in the query string of the HTTP request. diff --git a/releasenotes/notes/add-params-to-v2-list-backups-api-c088d2b4bfe90247.yaml b/releasenotes/notes/add-params-to-v2-list-backups-api-c088d2b4bfe90247.yaml deleted file mode 100644 index cee2d7663..000000000 --- a/releasenotes/notes/add-params-to-v2-list-backups-api-c088d2b4bfe90247.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - The ``list_backups`` method of the v2 ``BackupsClient`` class now has - an additional ``**params`` argument that enables passing additional - information in the query string of the HTTP request. diff --git a/releasenotes/notes/add-save-state-option-5ea67858cbaca969.yaml b/releasenotes/notes/add-save-state-option-5ea67858cbaca969.yaml deleted file mode 100644 index 8fdf4f00a..000000000 --- a/releasenotes/notes/add-save-state-option-5ea67858cbaca969.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - | - Add --save-state option to allow saving state of cloud before tempest run. diff --git a/releasenotes/notes/add-server-diagnostics-validation-schema-b5a3c55b45aa718a.yaml b/releasenotes/notes/add-server-diagnostics-validation-schema-b5a3c55b45aa718a.yaml deleted file mode 100644 index e0ac87cd8..000000000 --- a/releasenotes/notes/add-server-diagnostics-validation-schema-b5a3c55b45aa718a.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -features: - - | - Add validation schema for Nova server diagnostics API \ No newline at end of file diff --git a/releasenotes/notes/add-show-host-to-hosts-client-library-c60c4eb49d139480.yaml b/releasenotes/notes/add-show-host-to-hosts-client-library-c60c4eb49d139480.yaml deleted file mode 100644 index 0de1803e6..000000000 --- a/releasenotes/notes/add-show-host-to-hosts-client-library-c60c4eb49d139480.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - | - Add show host API to the volume v2 hosts_client library. - This feature enables the possibility to show details for a host. diff --git a/releasenotes/notes/add-show-snapshot-metadata-item-api-to-v2-snapshots-client-bd3cbab3c7f0e0b3.yaml b/releasenotes/notes/add-show-snapshot-metadata-item-api-to-v2-snapshots-client-bd3cbab3c7f0e0b3.yaml deleted file mode 100644 index 140df609f..000000000 --- a/releasenotes/notes/add-show-snapshot-metadata-item-api-to-v2-snapshots-client-bd3cbab3c7f0e0b3.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add show snapshot metadata item API to v2 snapshots_client library. - This feature enables the possibility to show a snapshot's metadata for - a specific key. diff --git a/releasenotes/notes/add-show-volume-metadata-item-api-to-v2-volumes-client-47d59ecd999ca9df.yaml b/releasenotes/notes/add-show-volume-metadata-item-api-to-v2-volumes-client-47d59ecd999ca9df.yaml deleted file mode 100644 index 49a935cce..000000000 --- a/releasenotes/notes/add-show-volume-metadata-item-api-to-v2-volumes-client-47d59ecd999ca9df.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add show volume metadata item API to v2 volumes_client library. - This feature enables the possibility to show a volume's metadata for - a specific key. diff --git a/releasenotes/notes/add-show-volume-summary-api-to-v3-volumes-client-96e7b01abdb5c9c3.yaml b/releasenotes/notes/add-show-volume-summary-api-to-v3-volumes-client-96e7b01abdb5c9c3.yaml deleted file mode 100644 index 361e38754..000000000 --- a/releasenotes/notes/add-show-volume-summary-api-to-v3-volumes-client-96e7b01abdb5c9c3.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -features: - - | - Define v3 volumes_client for the volume service as a library interface, - allowing other projects to use this module as a stable library without - maintenance changes. - Add show volume summary API to v3 volumes_client library, min_microversion - of this API is 3.12. - - * volumes_client(v3) diff --git a/releasenotes/notes/add-update-backup-api-to-v3-backups-client-e8465b2b66617dc0.yaml b/releasenotes/notes/add-update-backup-api-to-v3-backups-client-e8465b2b66617dc0.yaml deleted file mode 100644 index 7cd6887ef..000000000 --- a/releasenotes/notes/add-update-backup-api-to-v3-backups-client-e8465b2b66617dc0.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -features: - - | - Define v3 backups_client for the volume service as a library interface, - allowing other projects to use this module as a stable library without - maintenance changes. - Add update backup API to v3 backups_client library, min_microversion - of this API is 3.9. - - * backups_client(v3) diff --git a/releasenotes/notes/add-volume-group-types-tempest-tests-1298ab8cb4fe8b7b.yaml b/releasenotes/notes/add-volume-group-types-tempest-tests-1298ab8cb4fe8b7b.yaml deleted file mode 100644 index 4fd3bee37..000000000 --- a/releasenotes/notes/add-volume-group-types-tempest-tests-1298ab8cb4fe8b7b.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - | - Add list_group_type and show_group_type in the group_types client for - the volume service. Add tests for create/delete/show/list group types. diff --git a/releasenotes/notes/add-volume-groups-tempest-tests-dd7b2abfe2b48427.yaml b/releasenotes/notes/add-volume-groups-tempest-tests-dd7b2abfe2b48427.yaml deleted file mode 100644 index 898d36678..000000000 --- a/releasenotes/notes/add-volume-groups-tempest-tests-dd7b2abfe2b48427.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add groups and group_types clients for the volume service as library. - Add tempest tests for create group, delete group, show group, and - list group volume APIs. diff --git a/releasenotes/notes/add-volume-quota-class-client-as-library-c4c2b22c36ff807e.yaml b/releasenotes/notes/add-volume-quota-class-client-as-library-c4c2b22c36ff807e.yaml deleted file mode 100644 index e6847ebf4..000000000 --- a/releasenotes/notes/add-volume-quota-class-client-as-library-c4c2b22c36ff807e.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -features: - - | - Define v2 quota_classes_client for the volume service as library - interfaces, allowing other projects to use this module as stable libraries - without maintenance changes. - - * quota_classes_client(v2) diff --git a/releasenotes/notes/api_v2_admin_flag-dea5ca9bc2ce63bc.yaml b/releasenotes/notes/api_v2_admin_flag-dea5ca9bc2ce63bc.yaml deleted file mode 100644 index 0c33b69ac..000000000 --- a/releasenotes/notes/api_v2_admin_flag-dea5ca9bc2ce63bc.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -features: - - | - A new configuration flag api_v2_admin is introduced in the identity - feature flag group to allow for enabling/disabling all identity v2 - admin tests. The new flag only applies when the existing api_v2 flag - is set to True diff --git a/releasenotes/notes/deprecate-compute-images-client-in-volume-tests-92b6dd55fcaba620.yaml b/releasenotes/notes/deprecate-compute-images-client-in-volume-tests-92b6dd55fcaba620.yaml deleted file mode 100644 index 1ae251cde..000000000 --- a/releasenotes/notes/deprecate-compute-images-client-in-volume-tests-92b6dd55fcaba620.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -deprecations: - - | - Image APIs in compute are deprecated, Image native APIs are recommended. - And Glance v1 APIs are deprecated and v2 APIs are current. Image client - compute_images_client and Glance v1 APIs are removed in volume tests. -upgrade: - - | - Switch to use Glance v2 APIs in volume tests, by adding the Glance v2 - client images_client. diff --git a/releasenotes/notes/deprecate-config-forbid_global_implied_dsr-e64cfa66e6e3ded5.yaml b/releasenotes/notes/deprecate-config-forbid_global_implied_dsr-e64cfa66e6e3ded5.yaml deleted file mode 100644 index 2b63402f3..000000000 --- a/releasenotes/notes/deprecate-config-forbid_global_implied_dsr-e64cfa66e6e3ded5.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -deprecations: - - The config option ``forbid_global_implied_dsr`` from the ``IdentityFeature`` - group is now deprecated. This feature flag was introduced to support - testing of old OpenStack versions which are not supported anymore. diff --git a/releasenotes/notes/deprecate-default-value-for-v3_endpoint_type-fb9e47c5ba1c719d.yaml b/releasenotes/notes/deprecate-default-value-for-v3_endpoint_type-fb9e47c5ba1c719d.yaml deleted file mode 100644 index c88522e73..000000000 --- a/releasenotes/notes/deprecate-default-value-for-v3_endpoint_type-fb9e47c5ba1c719d.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -deprecations: - - | - Deprecate default value for configuration parameter v3_endpoint_type - of identity section in OpenStack Pike and modify the default value to - publicURL in OpenStack Q release. diff --git a/releasenotes/notes/extra-compute-services-tests-92b6c0618972e02f.yaml b/releasenotes/notes/extra-compute-services-tests-92b6c0618972e02f.yaml deleted file mode 100644 index 414adf18b..000000000 --- a/releasenotes/notes/extra-compute-services-tests-92b6c0618972e02f.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add the ``disable_log_reason`` and the ``update_forced_down`` API endpoints - to the compute ``services_client``. - Add '2.11' compute validation schema for compute services API. diff --git a/releasenotes/notes/identity-token-client-8aaef74b1d61090a.yaml b/releasenotes/notes/identity-token-client-8aaef74b1d61090a.yaml deleted file mode 100644 index d94de3e60..000000000 --- a/releasenotes/notes/identity-token-client-8aaef74b1d61090a.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - Add additional API endpoints to the identity v2 client token API: - - list_endpoints_for_token - - check_token_existence diff --git a/releasenotes/notes/identity_client-635275d43abbb807.yaml b/releasenotes/notes/identity_client-635275d43abbb807.yaml deleted file mode 100644 index 6f984b74e..000000000 --- a/releasenotes/notes/identity_client-635275d43abbb807.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - | - Enhances the v3 identity client with the ``check_token_existence`` - endpoint, allowing users to check the existence of tokens diff --git a/releasenotes/notes/intermediate-pike-release-2ce492432ff8f012.yaml b/releasenotes/notes/intermediate-pike-release-2ce492432ff8f012.yaml deleted file mode 100644 index bfebcd9ed..000000000 --- a/releasenotes/notes/intermediate-pike-release-2ce492432ff8f012.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -prelude: > - This is an intermediate release during the Pike development cycle to - make new functionality available to plugins and other consumers. diff --git a/releasenotes/notes/migrate-dynamic-creds-ecebb47528080761.yaml b/releasenotes/notes/migrate-dynamic-creds-ecebb47528080761.yaml deleted file mode 100644 index c20cbc68d..000000000 --- a/releasenotes/notes/migrate-dynamic-creds-ecebb47528080761.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - | - The tempest module tempest.common.dynamic creds which is used for - dynamically allocating credentials has been migrated into tempest lib. diff --git a/releasenotes/notes/migrate-preprov-creds-ef61a046ee1ec604.yaml b/releasenotes/notes/migrate-preprov-creds-ef61a046ee1ec604.yaml deleted file mode 100644 index aa5f71a20..000000000 --- a/releasenotes/notes/migrate-preprov-creds-ef61a046ee1ec604.yaml +++ /dev/null @@ -1,11 +0,0 @@ ---- -features: - - The tempest module tempest.common.preprov_creds which is used to provide - credentials from a list of preprovisioned resources has been migrated into - tempest lib at tempest.lib.common.preprov_creds. - - The InvalidTestResource exception class from tempest.exceptions has been - migrated into tempest.lib.exceptions - - The tempest module tempest.common.fixed_network which provided utilities for - finding fixed networks by and helpers for picking the network to use when - multiple tenant networks are available has been migrated into tempest lib - at tempest.lib.common.fixed_network. diff --git a/releasenotes/notes/move-attr-decorator-to-lib-a1e80c42ba9c5392.yaml b/releasenotes/notes/move-attr-decorator-to-lib-a1e80c42ba9c5392.yaml deleted file mode 100644 index 58d45cc87..000000000 --- a/releasenotes/notes/move-attr-decorator-to-lib-a1e80c42ba9c5392.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - A new ``attr`` decorator has been added in the ``tempest.lib.decorators`` - module. For example, use it to tag specific tests, which could be leveraged - by test runners to run only a subset of Tempest tests. diff --git a/releasenotes/notes/move-related_bug-decorator-to-lib-dbfd5c543bbb2805.yaml b/releasenotes/notes/move-related_bug-decorator-to-lib-dbfd5c543bbb2805.yaml deleted file mode 100644 index 8c420c82c..000000000 --- a/releasenotes/notes/move-related_bug-decorator-to-lib-dbfd5c543bbb2805.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -features: - - | - A new ``related_bug`` decorator has been added to - ``tempest.lib.decorators``. Use it to decorate and tag a test that was - added in relation to a launchpad bug report. diff --git a/releasenotes/notes/move-volume-v3-base_client-to-volume-1edbz0f207c3b283.yaml b/releasenotes/notes/move-volume-v3-base_client-to-volume-1edbz0f207c3b283.yaml deleted file mode 100644 index ec81dc530..000000000 --- a/releasenotes/notes/move-volume-v3-base_client-to-volume-1edbz0f207c3b283.yaml +++ /dev/null @@ -1,15 +0,0 @@ -features: - - | - Move base_client from tempest.lib.services.volume.v3 to - tempest.lib.services.volume, so if we want to add new - interfaces based on a v2 client, we can make that v2 - client inherit from volume.base_client.BaseClient to - get microversion support, and then to make the new v3 - client inherit from the v2 client, thus to avoid the - multiple inheritance. -deprecations: - - | - Deprecate class BaseClient from volume.v3.base_client - and move it to volume.base_client. - ``tempest.lib.services.volume.v3.base_client.BaseClient`` - (new ``tempest.lib.services.volume.base_client.BaseClient``) diff --git a/releasenotes/notes/network-tag-client-f4614029af7927f0.yaml b/releasenotes/notes/network-tag-client-f4614029af7927f0.yaml deleted file mode 100644 index 9af57b117..000000000 --- a/releasenotes/notes/network-tag-client-f4614029af7927f0.yaml +++ /dev/null @@ -1,8 +0,0 @@ ---- -features: - - | - Define v2.0 ``tags_client`` for the network service as a library - interface, allowing other projects to use this module as a stable - library without maintenance changes. - - * tags_client(v2.0) diff --git a/releasenotes/notes/pause_teardown-45c9d60ffa889f7f.yaml b/releasenotes/notes/pause_teardown-45c9d60ffa889f7f.yaml deleted file mode 100644 index a540c7d45..000000000 --- a/releasenotes/notes/pause_teardown-45c9d60ffa889f7f.yaml +++ /dev/null @@ -1,9 +0,0 @@ ---- -features: - - | - Pause teardown - When pause_teardown flag in tempest.conf is set to True a pdb breakpoint - is added to tearDown and tearDownClass methods in test.py. - This allows to pause cleaning resources process, so that used resources - can be examined. Closer examination of used resources may lead to faster - debugging. diff --git a/releasenotes/notes/prevent-error-in-parse-resp-when-nullable-list-9898cd0f22180986.yaml b/releasenotes/notes/prevent-error-in-parse-resp-when-nullable-list-9898cd0f22180986.yaml deleted file mode 100644 index afb600688..000000000 --- a/releasenotes/notes/prevent-error-in-parse-resp-when-nullable-list-9898cd0f22180986.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -fixes: - - | - When receiving nullable list as a response body, tempest.lib - rest_client module raised an exception without valid json - deserialization. A new release fixes this bug. diff --git a/releasenotes/notes/remove-heat-tests-9efb42cac3e0b306.yaml b/releasenotes/notes/remove-heat-tests-9efb42cac3e0b306.yaml deleted file mode 100644 index 4d0f3ce06..000000000 --- a/releasenotes/notes/remove-heat-tests-9efb42cac3e0b306.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -upgrade: - - The Heat API tests have been removed from tempest, they were unmaintained. - The future direction of api test for heat is their in-tree Gabbi tests diff --git a/releasenotes/notes/set-cinder-api-v3-option-true-1b3e61e3129b7c00.yaml b/releasenotes/notes/set-cinder-api-v3-option-true-1b3e61e3129b7c00.yaml deleted file mode 100644 index 6959ca7da..000000000 --- a/releasenotes/notes/set-cinder-api-v3-option-true-1b3e61e3129b7c00.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -upgrade: - - | - The volume config option 'api_v3' default is changed to - ``True`` because the volume v3 API is CURRENT. diff --git a/releasenotes/notes/tempest-identity-catalog-client-f5c8589a9d7c1eb5.yaml b/releasenotes/notes/tempest-identity-catalog-client-f5c8589a9d7c1eb5.yaml deleted file mode 100644 index dcaaceb5f..000000000 --- a/releasenotes/notes/tempest-identity-catalog-client-f5c8589a9d7c1eb5.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - Add a new identity catalog client. At this point, the new client - contains a single functionality, "show_catalog", which returns a - catalog object. diff --git a/releasenotes/notes/tempest-workspace-delete-directory-feature-74d6d157a5a05561.yaml b/releasenotes/notes/tempest-workspace-delete-directory-feature-74d6d157a5a05561.yaml deleted file mode 100644 index ec21098fd..000000000 --- a/releasenotes/notes/tempest-workspace-delete-directory-feature-74d6d157a5a05561.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -features: - - | - Added tempest workspace remove --name --rmdir - feature to delete the workspace directory as well as entry. diff --git a/releasenotes/notes/use-cinder-v3-client-for-verify_tempest_config-2bf3d817b0070064.yaml b/releasenotes/notes/use-cinder-v3-client-for-verify_tempest_config-2bf3d817b0070064.yaml deleted file mode 100644 index 1c8fa77bd..000000000 --- a/releasenotes/notes/use-cinder-v3-client-for-verify_tempest_config-2bf3d817b0070064.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -upgrade: - - verify_tempest_config command starts using extension_client of - cinder v2 API only, because cinder v3 API is current and v2 and - v1 are deprecated and v3 extension API is the same as v2. Then - we can reuse the v2 client for v3 API also. diff --git a/releasenotes/source/_static/.placeholder b/releasenotes/source/_static/.placeholder deleted file mode 100644 index e69de29bb..000000000 diff --git a/releasenotes/source/_templates/.placeholder b/releasenotes/source/_templates/.placeholder deleted file mode 100644 index e69de29bb..000000000 diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py deleted file mode 100644 index 3137541df..000000000 --- a/releasenotes/source/conf.py +++ /dev/null @@ -1,286 +0,0 @@ -# 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. - -# Tempest Release Notes documentation build configuration file, created by -# sphinx-quickstart on Tue Nov 3 17:40:50 2015. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# sys.path.insert(0, os.path.abspath('.')) - -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'openstackdocstheme', - 'reno.sphinxext', -] - -# openstackdocstheme options -repository_name = 'openstack/tempest' -bug_project = 'tempest' -bug_tag = '' - -# Must set this variable to include year, month, day, hours, and minutes. -html_last_updated_fmt = '%Y-%m-%d %H:%M' - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# The suffix of source filenames. -source_suffix = '.rst' - -# The encoding of source files. -# source_encoding = 'utf-8-sig' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. -project = u'tempest Release Notes' -copyright = u'2016, tempest Developers' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The short X.Y version. -from tempest.version import version_info as tempest_version -# The full version, including alpha/beta/rc tags. -release = tempest_version.version_string_with_vcs() -# The short X.Y version. -version = tempest_version.canonical_version_string() - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -# today = '' -# Else, today_fmt is used as the format for a strftime call. -# today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -exclude_patterns = [] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -# default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -# add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -# add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -# show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# A list of ignored prefixes for module index sorting. -# modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -# keep_warnings = False - - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -html_theme = 'openstackdocs' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -# html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -# html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -# html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -# html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -# html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -# html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -# html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -# html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -# html_additional_pages = {} - -# If false, no module index is generated. -# html_domain_indices = True - -# If false, no index is generated. -# html_use_index = True - -# If true, the index is split into individual pages for each letter. -# html_split_index = False - -# If true, links to the reST sources are added to the pages. -# html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -# html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -# html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -# html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -# html_file_suffix = None - -# Output file base name for HTML help builder. -htmlhelp_basename = 'tempestReleaseNotesdoc' - - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # 'papersize': 'letterpaper', - - # The font size ('10pt', '11pt' or '12pt'). - # 'pointsize': '10pt', - - # Additional stuff for the LaTeX preamble. - # 'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('index', 'olso.configReleaseNotes.tex', - u'olso.config Release Notes Documentation', - u'tempest Developers', 'manual'), -] - -# The name of an image file (relative to this directory) to place at the top of -# the title page -# latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -# latex_use_parts = False - -# If true, show page references after internal links. -# latex_show_pagerefs = False - -# If true, show URL addresses after external links. -# latex_show_urls = False - -# Documents to append as an appendix to all manuals. -# latex_appendices = [] - -# If false, no module index is generated. -# latex_domain_indices = True - - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). -man_pages = [ - ('index', 'olso.configreleasenotes', - u'tempest Release Notes Documentation', - [u'tempest Developers'], 1) -] - -# If true, show URL addresses after external links. -# man_show_urls = False - - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) -texinfo_documents = [ - ('index', 'tempestReleaseNotes', - u'tempest Release Notes Documentation', - u'tempest Developers', 'olso.configReleaseNotes', - 'An OpenStack library for parsing configuration options from the command' - ' line and configuration files.', - 'Miscellaneous'), -] - -# Documents to append as an appendix to all manuals. -# texinfo_appendices = [] - -# If false, no module index is generated. -# texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -# texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -# texinfo_no_detailmenu = False - -# -- Options for Internationalization output ------------------------------ -locale_dirs = ['locale/'] diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst deleted file mode 100644 index db01da0a0..000000000 --- a/releasenotes/source/index.rst +++ /dev/null @@ -1,22 +0,0 @@ -=========================== - Tempest Release Notes -=========================== - - .. toctree:: - :maxdepth: 1 - - unreleased - v16.1.0 - v16.0.0 - v15.0.0 - v14.0.0 - v13.0.0 - v12.0.0 - v11.0.0 - v10.0.0 - -Indices and tables -================== - -* :ref:`genindex` -* :ref:`search` diff --git a/releasenotes/source/unreleased.rst b/releasenotes/source/unreleased.rst deleted file mode 100644 index 875030f9d..000000000 --- a/releasenotes/source/unreleased.rst +++ /dev/null @@ -1,5 +0,0 @@ -============================ -Current Series Release Notes -============================ - -.. release-notes:: diff --git a/releasenotes/source/v10.0.0.rst b/releasenotes/source/v10.0.0.rst deleted file mode 100644 index 38ed2efae..000000000 --- a/releasenotes/source/v10.0.0.rst +++ /dev/null @@ -1,6 +0,0 @@ -===================== -v10.0.0 Release Notes -===================== - -.. release-notes:: 10.0.0 Release Notes - :version: 10.0.0 diff --git a/releasenotes/source/v11.0.0.rst b/releasenotes/source/v11.0.0.rst deleted file mode 100644 index 84b145ded..000000000 --- a/releasenotes/source/v11.0.0.rst +++ /dev/null @@ -1,6 +0,0 @@ -===================== -v11.0.0 Release Notes -===================== - -.. release-notes:: 11.0.0 Release Notes - :version: 11.0.0 diff --git a/releasenotes/source/v12.0.0.rst b/releasenotes/source/v12.0.0.rst deleted file mode 100644 index 0bc8343b1..000000000 --- a/releasenotes/source/v12.0.0.rst +++ /dev/null @@ -1,6 +0,0 @@ -===================== -v12.0.0 Release Notes -===================== - -.. release-notes:: 12.0.0 Release Notes - :version: 12.0.0 diff --git a/releasenotes/source/v13.0.0.rst b/releasenotes/source/v13.0.0.rst deleted file mode 100644 index 39816e4b8..000000000 --- a/releasenotes/source/v13.0.0.rst +++ /dev/null @@ -1,6 +0,0 @@ -===================== -v13.0.0 Release Notes -===================== - -.. release-notes:: 13.0.0 Release Notes - :version: 13.0.0 diff --git a/releasenotes/source/v14.0.0.rst b/releasenotes/source/v14.0.0.rst deleted file mode 100644 index 440c85bed..000000000 --- a/releasenotes/source/v14.0.0.rst +++ /dev/null @@ -1,6 +0,0 @@ -===================== -v14.0.0 Release Notes -===================== - -.. release-notes:: 14.0.0 Release Notes - :version: 14.0.0 diff --git a/releasenotes/source/v15.0.0.rst b/releasenotes/source/v15.0.0.rst deleted file mode 100644 index 2ee189452..000000000 --- a/releasenotes/source/v15.0.0.rst +++ /dev/null @@ -1,6 +0,0 @@ -===================== -v15.0.0 Release Notes -===================== - -.. release-notes:: 15.0.0 Release Notes - :version: 15.0.0 diff --git a/releasenotes/source/v16.0.0.rst b/releasenotes/source/v16.0.0.rst deleted file mode 100644 index ae2959964..000000000 --- a/releasenotes/source/v16.0.0.rst +++ /dev/null @@ -1,6 +0,0 @@ -===================== -v16.0.0 Release Notes -===================== - -.. release-notes:: 16.0.0 Release Notes - :version: 16.0.0 \ No newline at end of file diff --git a/releasenotes/source/v16.1.0.rst b/releasenotes/source/v16.1.0.rst deleted file mode 100644 index e24a70fef..000000000 --- a/releasenotes/source/v16.1.0.rst +++ /dev/null @@ -1,6 +0,0 @@ -===================== -v16.1.0 Release Notes -===================== - -.. release-notes:: 16.1.0 Release Notes - :version: 16.1.0 diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index a74f5c265..000000000 --- a/requirements.txt +++ /dev/null @@ -1,25 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. -pbr!=2.1.0,>=2.0.0 # Apache-2.0 -cliff>=2.8.0 # Apache-2.0 -jsonschema!=2.5.0,<3.0.0,>=2.0.0 # MIT -testtools>=1.4.0 # MIT -paramiko>=2.0 # LGPLv2.1+ -netaddr!=0.7.16,>=0.7.13 # BSD -testrepository>=0.0.18 # Apache-2.0/BSD -oslo.concurrency>=3.8.0 # Apache-2.0 -oslo.config!=4.3.0,!=4.4.0,>=4.0.0 # Apache-2.0 -oslo.log>=3.22.0 # Apache-2.0 -oslo.serialization!=2.19.1,>=1.10.0 # Apache-2.0 -oslo.utils>=3.20.0 # Apache-2.0 -six>=1.9.0 # MIT -fixtures>=3.0.0 # Apache-2.0/BSD -PyYAML>=3.10.0 # MIT -python-subunit>=0.0.18 # Apache-2.0/BSD -stevedore>=1.20.0 # Apache-2.0 -PrettyTable<0.8,>=0.7.1 # BSD -os-testr>=0.8.0 # Apache-2.0 -urllib3>=1.21.1 # MIT -debtcollector>=1.2.0 # Apache-2.0 -unittest2 # BSD diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index f52137edf..000000000 --- a/setup.cfg +++ /dev/null @@ -1,58 +0,0 @@ -[metadata] -name = tempest -summary = OpenStack Integration Testing -description-file = - README.rst -author = OpenStack -author-email = openstack-dev@lists.openstack.org -home-page = https://docs.openstack.org/tempest/latest/ -classifier = - Intended Audience :: Information Technology - Intended Audience :: System Administrators - Intended Audience :: Developers - License :: OSI Approved :: Apache Software License - Operating System :: POSIX :: Linux - Programming Language :: Python - Programming Language :: Python :: 2 - Programming Language :: Python :: 2.7 - Programming Language :: Python :: 3 - Programming Language :: Python :: 3.4 - Programming Language :: Python :: 3.5 - -[files] -packages = - tempest -data_files = - etc/tempest = etc/* - -[entry_points] -console_scripts = - verify-tempest-config = tempest.cmd.verify_tempest_config:main - tempest-account-generator = tempest.cmd.account_generator:main - tempest = tempest.cmd.main:main - skip-tracker = tempest.lib.cmd.skip_tracker:main - check-uuid = tempest.lib.cmd.check_uuid:run - subunit-describe-calls = tempest.cmd.subunit_describe_calls:entry_point -tempest.cm = - account-generator = tempest.cmd.account_generator:TempestAccountGenerator - init = tempest.cmd.init:TempestInit - cleanup = tempest.cmd.cleanup:TempestCleanup - list-plugins = tempest.cmd.list_plugins:TempestListPlugins - verify-config = tempest.cmd.verify_tempest_config:TempestVerifyConfig - workspace_register = tempest.cmd.workspace:TempestWorkspaceRegister - workspace_rename = tempest.cmd.workspace:TempestWorkspaceRename - workspace_move = tempest.cmd.workspace:TempestWorkspaceMove - workspace_remove = tempest.cmd.workspace:TempestWorkspaceRemove - workspace_list = tempest.cmd.workspace:TempestWorkspaceList - run = tempest.cmd.run:TempestRun -oslo.config.opts = - tempest.config = tempest.config:list_opts - -[build_sphinx] -all-files = 1 -warning-is-error = 1 -build-dir = doc/build -source-dir = doc/source - -[wheel] -universal = 1 diff --git a/setup.py b/setup.py deleted file mode 100644 index 566d84432..000000000 --- a/setup.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# -# 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. - -# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT -import setuptools - -# In python < 2.7.4, a lazy loading of package `pbr` will break -# setuptools if some other modules registered functions in `atexit`. -# solution from: http://bugs.python.org/issue15881#msg170215 -try: - import multiprocessing # noqa -except ImportError: - pass - -setuptools.setup( - setup_requires=['pbr>=2.0.0'], - pbr=True) diff --git a/tempest/README.rst b/tempest/README.rst deleted file mode 100644 index 663653e4e..000000000 --- a/tempest/README.rst +++ /dev/null @@ -1,55 +0,0 @@ -============================ -Tempest Field Guide Overview -============================ - -Tempest is designed to be useful for a large number of different -environments. This includes being useful for gating commits to -OpenStack core projects, being used to validate OpenStack cloud -implementations for both correctness, as well as a burn in tool for -OpenStack clouds. - -As such Tempest tests come in many flavors, each with their own rules -and guidelines. Below is the overview of the Tempest respository structure -to make this clear. - -| tempest/ -| api/ - API tests -| scenario/ - complex scenario tests -| tests/ - unit tests for Tempest internals - -Each of these directories contains different types of tests. What -belongs in each directory, the rules and examples for good tests, are -documented in a README.rst file in the directory. - -:ref:`api_field_guide` ----------------------- - -API tests are validation tests for the OpenStack API. They should not -use the existing Python clients for OpenStack, but should instead use -the Tempest implementations of clients. Having raw clients let us -pass invalid JSON to the APIs and see the results, something we could -not get with the native clients. - -When it makes sense, API testing should be moved closer to the -projects themselves, possibly as functional tests in their unit test -frameworks. - - -:ref:`scenario_field_guide` ---------------------------- - -Scenario tests are complex "through path" tests for OpenStack -functionality. They are typically a series of steps where complicated -state requiring multiple services is set up exercised, and torn down. - -Scenario tests should not use the existing Python clients for OpenStack, -but should instead use the Tempest implementations of clients. - - -:ref:`unit_tests_field_guide` ------------------------------ - -Unit tests are the self checks for Tempest. They provide functional -verification and regression checking for the internal components of Tempest. -They should be used to just verify that the individual pieces of Tempest are -working as expected. diff --git a/tempest/__init__.py b/tempest/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/README.rst b/tempest/api/README.rst deleted file mode 100644 index a79692219..000000000 --- a/tempest/api/README.rst +++ /dev/null @@ -1,53 +0,0 @@ -.. _api_field_guide: - -Tempest Field Guide to API tests -================================ - - -What are these tests? ---------------------- - -One of Tempest's prime function is to ensure that your OpenStack cloud -works with the OpenStack API as documented. The current largest -portion of Tempest code is devoted to test cases that do exactly this. - -It's also important to test not only the expected positive path on -APIs, but also to provide them with invalid data to ensure they fail -in expected and documented ways. The latter type of tests is called -``negative tests`` in Tempest source code. Over the course of the OpenStack -project Tempest has discovered many fundamental bugs by doing just -this. - -In order for some APIs to return meaningful results, there must be -enough data in the system. This means these tests might start by -spinning up a server, image, etc, then operating on it. - - -Why are these tests in Tempest? -------------------------------- - -This is one of the core missions for the Tempest project, and where it -started. Many people use this bit of function in Tempest to ensure -their clouds haven't broken the OpenStack API. - -It could be argued that some of the negative testing could be done -back in the projects themselves, and we might evolve there over time, -but currently in the OpenStack gate this is a fundamentally important -place to keep things. - - -Scope of these tests --------------------- - -API tests should always use the Tempest implementation of the -OpenStack API, as we want to ensure that bugs aren't hidden by the -official clients. - -They should test specific API calls, and can build up complex state if -it's needed for the API call to be meaningful. - -They should send not only good data, but bad data at the API and look -for error codes. - -They should all be able to be run on their own, not depending on the -state created by a previous test. diff --git a/tempest/api/__init__.py b/tempest/api/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/compute/__init__.py b/tempest/api/compute/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/compute/admin/__init__.py b/tempest/api/compute/admin/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/compute/admin/test_agents.py b/tempest/api/compute/admin/test_agents.py deleted file mode 100644 index 69cbfb5da..000000000 --- a/tempest/api/compute/admin/test_agents.py +++ /dev/null @@ -1,110 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 tempest.api.compute import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class AgentsAdminTestJSON(base.BaseV2ComputeAdminTest): - """Tests Agents API""" - - @classmethod - def setup_clients(cls): - super(AgentsAdminTestJSON, cls).setup_clients() - cls.client = cls.os_admin.agents_client - - @classmethod - def resource_setup(cls): - super(AgentsAdminTestJSON, cls).resource_setup() - cls.params_agent = cls._param_helper( - hypervisor='common', os='linux', architecture='x86_64', - version='7.0', url='xxx://xxxx/xxx/xxx', - md5hash='add6bb58e139be103324d04d82d8f545') - - @staticmethod - def _param_helper(**kwargs): - rand_key = 'architecture' - if rand_key in kwargs: - # NOTE: The rand_name is for avoiding agent conflicts. - # If you try to create an agent with the same hypervisor, - # os and architecture as an existing agent, Nova will return - # an HTTPConflict or HTTPServerError. - kwargs[rand_key] = data_utils.rand_name(kwargs[rand_key]) - return kwargs - - @decorators.idempotent_id('1fc6bdc8-0b6d-4cc7-9f30-9b04fabe5b90') - def test_create_agent(self): - # Create an agent. - params = self._param_helper( - hypervisor='kvm', os='win', architecture='x86', - version='7.0', url='xxx://xxxx/xxx/xxx', - md5hash='add6bb58e139be103324d04d82d8f545') - body = self.client.create_agent(**params)['agent'] - self.addCleanup(self.client.delete_agent, body['agent_id']) - for expected_item, value in params.items(): - self.assertEqual(value, body[expected_item]) - - @decorators.idempotent_id('dc9ffd51-1c50-4f0e-a820-ae6d2a568a9e') - def test_update_agent(self): - # Create and update an agent. - body = self.client.create_agent(**self.params_agent)['agent'] - self.addCleanup(self.client.delete_agent, body['agent_id']) - agent_id = body['agent_id'] - params = self._param_helper( - version='8.0', url='xxx://xxxx/xxx/xxx2', - md5hash='add6bb58e139be103324d04d82d8f547') - body = self.client.update_agent(agent_id, **params)['agent'] - for expected_item, value in params.items(): - self.assertEqual(value, body[expected_item]) - - @decorators.idempotent_id('470e0b89-386f-407b-91fd-819737d0b335') - def test_delete_agent(self): - # Create an agent and delete it. - body = self.client.create_agent(**self.params_agent)['agent'] - self.client.delete_agent(body['agent_id']) - - # Verify the list doesn't contain the deleted agent. - agents = self.client.list_agents()['agents'] - self.assertNotIn(body['agent_id'], map(lambda x: x['agent_id'], - agents)) - - @decorators.idempotent_id('6a326c69-654b-438a-80a3-34bcc454e138') - def test_list_agents(self): - # Create an agent and list all agents. - body = self.client.create_agent(**self.params_agent)['agent'] - self.addCleanup(self.client.delete_agent, body['agent_id']) - agents = self.client.list_agents()['agents'] - self.assertNotEmpty(agents, 'Cannot get any agents.(%s)' % agents) - self.assertIn(body['agent_id'], map(lambda x: x['agent_id'], agents)) - - @decorators.idempotent_id('eabadde4-3cd7-4ec4-a4b5-5a936d2d4408') - def test_list_agents_with_filter(self): - # Create agents and list the agent builds by the filter. - body = self.client.create_agent(**self.params_agent)['agent'] - self.addCleanup(self.client.delete_agent, body['agent_id']) - params = self._param_helper( - hypervisor='xen', os='linux', architecture='x86', - version='7.0', url='xxx://xxxx/xxx/xxx1', - md5hash='add6bb58e139be103324d04d82d8f546') - agent_xen = self.client.create_agent(**params)['agent'] - self.addCleanup(self.client.delete_agent, agent_xen['agent_id']) - - agent_id_xen = agent_xen['agent_id'] - agents = (self.client.list_agents(hypervisor=agent_xen['hypervisor']) - ['agents']) - self.assertNotEmpty(agents, 'Cannot get any agents.(%s)' % agents) - self.assertIn(agent_id_xen, map(lambda x: x['agent_id'], agents)) - self.assertNotIn(body['agent_id'], map(lambda x: x['agent_id'], - agents)) diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py deleted file mode 100644 index 902ea9a4a..000000000 --- a/tempest/api/compute/admin/test_aggregates.py +++ /dev/null @@ -1,217 +0,0 @@ -# Copyright 2013 NEC Corporation. -# 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 testtools - -from tempest.api.compute import base -from tempest.common import tempest_fixtures as fixtures -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class AggregatesAdminTestJSON(base.BaseV2ComputeAdminTest): - """Tests Aggregates API that require admin privileges""" - - @classmethod - def setup_clients(cls): - super(AggregatesAdminTestJSON, cls).setup_clients() - cls.client = cls.os_admin.aggregates_client - - @classmethod - def resource_setup(cls): - super(AggregatesAdminTestJSON, cls).resource_setup() - cls.aggregate_name_prefix = 'test_aggregate' - cls.az_name_prefix = 'test_az' - - cls.host = None - hypers = cls.os_admin.hypervisor_client.list_hypervisors( - detail=True)['hypervisors'] - - if CONF.compute.hypervisor_type: - hypers = [hyper for hyper in hypers - if (hyper['hypervisor_type'] == - CONF.compute.hypervisor_type)] - - hosts_available = [hyper['service']['host'] for hyper in hypers - if (hyper['state'] == 'up' and - hyper['status'] == 'enabled')] - if hosts_available: - cls.host = hosts_available[0] - else: - msg = "no available compute node found" - if CONF.compute.hypervisor_type: - msg += " for hypervisor_type %s" % CONF.compute.hypervisor_type - raise testtools.TestCase.failureException(msg) - - def _create_test_aggregate(self, **kwargs): - if 'name' not in kwargs: - kwargs['name'] = data_utils.rand_name(self.aggregate_name_prefix) - aggregate = self.client.create_aggregate(**kwargs)['aggregate'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.client.delete_aggregate, aggregate['id']) - self.assertEqual(kwargs['name'], aggregate['name']) - - return aggregate - - @decorators.idempotent_id('0d148aa3-d54c-4317-aa8d-42040a475e20') - def test_aggregate_create_delete(self): - # Create and delete an aggregate. - aggregate = self._create_test_aggregate() - self.assertIsNone(aggregate['availability_zone']) - - self.client.delete_aggregate(aggregate['id']) - self.client.wait_for_resource_deletion(aggregate['id']) - - @decorators.idempotent_id('5873a6f8-671a-43ff-8838-7ce430bb6d0b') - def test_aggregate_create_delete_with_az(self): - # Create and delete an aggregate. - az_name = data_utils.rand_name(self.az_name_prefix) - aggregate = self._create_test_aggregate(availability_zone=az_name) - self.assertEqual(az_name, aggregate['availability_zone']) - - self.client.delete_aggregate(aggregate['id']) - self.client.wait_for_resource_deletion(aggregate['id']) - - @decorators.idempotent_id('68089c38-04b1-4758-bdf0-cf0daec4defd') - def test_aggregate_create_verify_entry_in_list(self): - # Create an aggregate and ensure it is listed. - aggregate = self._create_test_aggregate() - aggregates = self.client.list_aggregates()['aggregates'] - self.assertIn((aggregate['id'], aggregate['availability_zone']), - map(lambda x: (x['id'], x['availability_zone']), - aggregates)) - - @decorators.idempotent_id('36ec92ca-7a73-43bc-b920-7531809e8540') - def test_aggregate_create_update_metadata_get_details(self): - # Create an aggregate and ensure its details are returned. - aggregate = self._create_test_aggregate() - body = self.client.show_aggregate(aggregate['id'])['aggregate'] - self.assertEqual(aggregate['name'], body['name']) - self.assertEqual(aggregate['availability_zone'], - body['availability_zone']) - self.assertEqual({}, body["metadata"]) - - # set the metadata of the aggregate - meta = {"key": "value"} - body = self.client.set_metadata(aggregate['id'], metadata=meta) - self.assertEqual(meta, body['aggregate']["metadata"]) - - # verify the metadata has been set - body = self.client.show_aggregate(aggregate['id'])['aggregate'] - self.assertEqual(meta, body["metadata"]) - - @decorators.idempotent_id('4d2b2004-40fa-40a1-aab2-66f4dab81beb') - def test_aggregate_create_update_with_az(self): - # Update an aggregate and ensure properties are updated correctly - aggregate_name = data_utils.rand_name(self.aggregate_name_prefix) - az_name = data_utils.rand_name(self.az_name_prefix) - aggregate = self._create_test_aggregate( - name=aggregate_name, availability_zone=az_name) - - self.assertEqual(az_name, aggregate['availability_zone']) - self.assertIsNotNone(aggregate['id']) - - aggregate_id = aggregate['id'] - new_aggregate_name = aggregate_name + '_new' - new_az_name = az_name + '_new' - - resp_aggregate = self.client.update_aggregate( - aggregate_id, - name=new_aggregate_name, - availability_zone=new_az_name)['aggregate'] - self.assertEqual(new_aggregate_name, resp_aggregate['name']) - self.assertEqual(new_az_name, resp_aggregate['availability_zone']) - - aggregates = self.client.list_aggregates()['aggregates'] - self.assertIn((aggregate_id, new_aggregate_name, new_az_name), - map(lambda x: - (x['id'], x['name'], x['availability_zone']), - aggregates)) - - @decorators.idempotent_id('c8e85064-e79b-4906-9931-c11c24294d02') - def test_aggregate_add_remove_host(self): - # Add a host to the given aggregate and remove. - self.useFixture(fixtures.LockFixture('availability_zone')) - aggregate_name = data_utils.rand_name(self.aggregate_name_prefix) - aggregate = self._create_test_aggregate(name=aggregate_name) - - body = (self.client.add_host(aggregate['id'], host=self.host) - ['aggregate']) - self.assertEqual(aggregate_name, body['name']) - self.assertEqual(aggregate['availability_zone'], - body['availability_zone']) - self.assertIn(self.host, body['hosts']) - - body = (self.client.remove_host(aggregate['id'], host=self.host) - ['aggregate']) - self.assertEqual(aggregate_name, body['name']) - self.assertEqual(aggregate['availability_zone'], - body['availability_zone']) - self.assertNotIn(self.host, body['hosts']) - - @decorators.idempotent_id('7f6a1cc5-2446-4cdb-9baa-b6ae0a919b72') - def test_aggregate_add_host_list(self): - # Add a host to the given aggregate and list. - self.useFixture(fixtures.LockFixture('availability_zone')) - aggregate_name = data_utils.rand_name(self.aggregate_name_prefix) - aggregate = self._create_test_aggregate(name=aggregate_name) - - self.client.add_host(aggregate['id'], host=self.host) - self.addCleanup(self.client.remove_host, aggregate['id'], - host=self.host) - - aggregates = self.client.list_aggregates()['aggregates'] - aggs = [agg for agg in aggregates if agg['id'] == aggregate['id']] - self.assertEqual(1, len(aggs)) - agg = aggs[0] - self.assertEqual(aggregate_name, agg['name']) - self.assertIsNone(agg['availability_zone']) - self.assertIn(self.host, agg['hosts']) - - @decorators.idempotent_id('eeef473c-7c52-494d-9f09-2ed7fc8fc036') - def test_aggregate_add_host_get_details(self): - # Add a host to the given aggregate and get details. - self.useFixture(fixtures.LockFixture('availability_zone')) - aggregate_name = data_utils.rand_name(self.aggregate_name_prefix) - aggregate = self._create_test_aggregate(name=aggregate_name) - - self.client.add_host(aggregate['id'], host=self.host) - self.addCleanup(self.client.remove_host, aggregate['id'], - host=self.host) - - body = self.client.show_aggregate(aggregate['id'])['aggregate'] - self.assertEqual(aggregate_name, body['name']) - self.assertIsNone(body['availability_zone']) - self.assertIn(self.host, body['hosts']) - - @decorators.idempotent_id('96be03c7-570d-409c-90f8-e4db3c646996') - def test_aggregate_add_host_create_server_with_az(self): - # Add a host to the given aggregate and create a server. - self.useFixture(fixtures.LockFixture('availability_zone')) - az_name = data_utils.rand_name(self.az_name_prefix) - aggregate = self._create_test_aggregate(availability_zone=az_name) - - self.client.add_host(aggregate['id'], host=self.host) - self.addCleanup(self.client.remove_host, aggregate['id'], - host=self.host) - admin_servers_client = self.os_admin.servers_client - server = self.create_test_server(availability_zone=az_name, - wait_until='ACTIVE') - body = admin_servers_client.show_server(server['id'])['server'] - self.assertEqual(self.host, body['OS-EXT-SRV-ATTR:host']) diff --git a/tempest/api/compute/admin/test_aggregates_negative.py b/tempest/api/compute/admin/test_aggregates_negative.py deleted file mode 100644 index 41be620d4..000000000 --- a/tempest/api/compute/admin/test_aggregates_negative.py +++ /dev/null @@ -1,180 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD. -# 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 tempest.api.compute import base -from tempest.common import tempest_fixtures as fixtures -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class AggregatesAdminNegativeTestJSON(base.BaseV2ComputeAdminTest): - """Tests Aggregates API that require admin privileges""" - - @classmethod - def setup_clients(cls): - super(AggregatesAdminNegativeTestJSON, cls).setup_clients() - cls.client = cls.os_admin.aggregates_client - cls.user_client = cls.aggregates_client - - @classmethod - def resource_setup(cls): - super(AggregatesAdminNegativeTestJSON, cls).resource_setup() - cls.aggregate_name_prefix = 'test_aggregate' - - hosts_all = cls.os_admin.hosts_client.list_hosts()['hosts'] - hosts = ([host['host_name'] - for host in hosts_all if host['service'] == 'compute']) - cls.host = hosts[0] - - def _create_test_aggregate(self): - aggregate_name = data_utils.rand_name(self.aggregate_name_prefix) - aggregate = (self.client.create_aggregate(name=aggregate_name) - ['aggregate']) - self.addCleanup(self.client.delete_aggregate, aggregate['id']) - return aggregate - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('86a1cb14-da37-4a70-b056-903fd56dfe29') - def test_aggregate_create_as_user(self): - # Regular user is not allowed to create an aggregate. - aggregate_name = data_utils.rand_name(self.aggregate_name_prefix) - self.assertRaises(lib_exc.Forbidden, - self.user_client.create_aggregate, - name=aggregate_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('3b8a1929-3793-4e92-bcb4-dfa572ee6c1d') - def test_aggregate_create_aggregate_name_length_less_than_1(self): - # the length of aggregate name should >= 1 and <=255 - self.assertRaises(lib_exc.BadRequest, - self.client.create_aggregate, - name='') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('4c194563-543b-4e70-a719-557bbe947fac') - def test_aggregate_create_aggregate_name_length_exceeds_255(self): - # the length of aggregate name should >= 1 and <=255 - aggregate_name = 'a' * 256 - self.assertRaises(lib_exc.BadRequest, - self.client.create_aggregate, - name=aggregate_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9c23a291-b0b1-487b-b464-132e061151b3') - def test_aggregate_create_with_existent_aggregate_name(self): - # creating an aggregate with existent aggregate name is forbidden - aggregate = self._create_test_aggregate() - self.assertRaises(lib_exc.Conflict, - self.client.create_aggregate, - name=aggregate['name']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('cd6de795-c15d-45f1-8d9e-813c6bb72a3d') - def test_aggregate_delete_as_user(self): - # Regular user is not allowed to delete an aggregate. - aggregate = self._create_test_aggregate() - self.assertRaises(lib_exc.Forbidden, - self.user_client.delete_aggregate, - aggregate['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('b7d475a6-5dcd-4ff4-b70a-cd9de66a6672') - def test_aggregate_list_as_user(self): - # Regular user is not allowed to list aggregates. - self.assertRaises(lib_exc.Forbidden, - self.user_client.list_aggregates) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('557cad12-34c9-4ff4-95f0-22f0dfbaf7dc') - def test_aggregate_get_details_as_user(self): - # Regular user is not allowed to get aggregate details. - aggregate = self._create_test_aggregate() - self.assertRaises(lib_exc.Forbidden, - self.user_client.show_aggregate, - aggregate['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('c74f4bf1-4708-4ff2-95a0-f49eaca951bd') - def test_aggregate_delete_with_invalid_id(self): - # Delete an aggregate with invalid id should raise exceptions. - self.assertRaises(lib_exc.NotFound, - self.client.delete_aggregate, -1) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('3c916244-2c46-49a4-9b55-b20bb0ae512c') - def test_aggregate_get_details_with_invalid_id(self): - # Get aggregate details with invalid id should raise exceptions. - self.assertRaises(lib_exc.NotFound, - self.client.show_aggregate, -1) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0ef07828-12b4-45ba-87cc-41425faf5711') - def test_aggregate_add_non_exist_host(self): - # Adding a non-exist host to an aggregate should raise exceptions. - hosts_all = self.os_admin.hosts_client.list_hosts()['hosts'] - hosts = map(lambda x: x['host_name'], hosts_all) - while True: - non_exist_host = data_utils.rand_name('nonexist_host') - if non_exist_host not in hosts: - break - aggregate = self._create_test_aggregate() - self.assertRaises(lib_exc.NotFound, self.client.add_host, - aggregate['id'], host=non_exist_host) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7324c334-bd13-4c93-8521-5877322c3d51') - def test_aggregate_add_host_as_user(self): - # Regular user is not allowed to add a host to an aggregate. - aggregate = self._create_test_aggregate() - self.assertRaises(lib_exc.Forbidden, - self.user_client.add_host, - aggregate['id'], host=self.host) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('19dd44e1-c435-4ee1-a402-88c4f90b5950') - def test_aggregate_add_existent_host(self): - self.useFixture(fixtures.LockFixture('availability_zone')) - aggregate = self._create_test_aggregate() - - self.client.add_host(aggregate['id'], host=self.host) - self.addCleanup(self.client.remove_host, aggregate['id'], - host=self.host) - - self.assertRaises(lib_exc.Conflict, self.client.add_host, - aggregate['id'], host=self.host) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7a53af20-137a-4e44-a4ae-e19260e626d9') - def test_aggregate_remove_host_as_user(self): - # Regular user is not allowed to remove a host from an aggregate. - self.useFixture(fixtures.LockFixture('availability_zone')) - aggregate = self._create_test_aggregate() - - self.client.add_host(aggregate['id'], host=self.host) - self.addCleanup(self.client.remove_host, aggregate['id'], - host=self.host) - - self.assertRaises(lib_exc.Forbidden, - self.user_client.remove_host, - aggregate['id'], host=self.host) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('95d6a6fa-8da9-4426-84d0-eec0329f2e4d') - def test_aggregate_remove_nonexistent_host(self): - aggregate = self._create_test_aggregate() - - self.assertRaises(lib_exc.NotFound, self.client.remove_host, - aggregate['id'], host='nonexist_host') diff --git a/tempest/api/compute/admin/test_auto_allocate_network.py b/tempest/api/compute/admin/test_auto_allocate_network.py deleted file mode 100644 index 83fe21531..000000000 --- a/tempest/api/compute/admin/test_auto_allocate_network.py +++ /dev/null @@ -1,208 +0,0 @@ -# Copyright 2016 IBM Corp. -# -# 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 oslo_log import log - -from tempest.api.compute import base -from tempest.common import compute -from tempest.common import credentials_factory as credentials -from tempest import config -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_excs -from tempest import test - -CONF = config.CONF -LOG = log.getLogger(__name__) - - -# NOTE(mriedem): This is in the admin directory only because it requires -# force_tenant_isolation=True, but doesn't extend BaseV2ComputeAdminTest -# because it doesn't actually use any admin credentials in the tests. -class AutoAllocateNetworkTest(base.BaseV2ComputeTest): - """Tests auto-allocating networks with the v2.37 microversion. - - These tests rely on Neutron being enabled. Also, the tenant must not have - any network resources available to it so we can make sure that Nova - calls to Neutron to automatically allocate the network topology. - """ - - force_tenant_isolation = True - - min_microversion = '2.37' - max_microversion = 'latest' - - @classmethod - def skip_checks(cls): - super(AutoAllocateNetworkTest, cls).skip_checks() - identity_version = cls.get_identity_version() - if not credentials.is_admin_available( - identity_version=identity_version): - msg = "Missing Identity Admin API credentials in configuration." - raise cls.skipException(msg) - if not CONF.service_available.neutron: - raise cls.skipException('Neutron is required') - if not test.is_extension_enabled('auto-allocated-topology', 'network'): - raise cls.skipException( - 'auto-allocated-topology extension is not available') - - @classmethod - def setup_credentials(cls): - # Do not create network resources for these tests. - cls.set_network_resources() - super(AutoAllocateNetworkTest, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(AutoAllocateNetworkTest, cls).setup_clients() - cls.networks_client = cls.os_primary.networks_client - cls.routers_client = cls.os_primary.routers_client - cls.subnets_client = cls.os_primary.subnets_client - cls.ports_client = cls.os_primary.ports_client - - @classmethod - def resource_setup(cls): - super(AutoAllocateNetworkTest, cls).resource_setup() - # Sanity check that there are no networks available to the tenant. - # This is essentially what Nova does for getting available networks. - tenant_id = cls.networks_client.tenant_id - # (1) Retrieve non-public network list owned by the tenant. - search_opts = {'tenant_id': tenant_id, 'shared': False} - nets = cls.networks_client.list_networks( - **search_opts).get('networks', []) - if nets: - raise lib_excs.TempestException( - 'Found tenant networks: %s' % nets) - # (2) Retrieve shared network list. - search_opts = {'shared': True} - nets = cls.networks_client.list_networks( - **search_opts).get('networks', []) - if nets: - raise lib_excs.TempestException( - 'Found shared networks: %s' % nets) - - @classmethod - def resource_cleanup(cls): - """Deletes any auto_allocated_network and it's associated resources.""" - - # Find the auto-allocated router for the tenant. - # This is a bit hacky since we don't have a great way to find the - # auto-allocated router given the private tenant network we have. - routers = cls.routers_client.list_routers().get('routers', []) - if len(routers) > 1: - # This indicates a race where nova is concurrently calling the - # neutron auto-allocated-topology API for multiple server builds - # at the same time (it's called from nova-compute when setting up - # networking for a server). Neutron will detect duplicates and - # automatically clean them up, but there is a window where the API - # can return multiple and we don't have a good way to filter those - # out right now, so we'll just handle them. - LOG.info('(%s) Found more than one router for tenant.', - test_utils.find_test_caller()) - - # Remove any networks, duplicate or otherwise, that these tests - # created. All such networks will be in the current tenant. Neutron - # will cleanup duplicate resources automatically, so ignore 404s. - search_opts = {'tenant_id': cls.networks_client.tenant_id} - networks = cls.networks_client.list_networks( - **search_opts).get('networks', []) - - for router in routers: - # Disassociate the subnets from the router. Because of the race - # mentioned above the subnets might not be associated with the - # router so ignore any 404. - for network in networks: - for subnet_id in network['subnets']: - test_utils.call_and_ignore_notfound_exc( - cls.routers_client.remove_router_interface, - router['id'], subnet_id=subnet_id) - - # Delete the router. - cls.routers_client.delete_router(router['id']) - - for network in networks: - # Get and delete the ports for the given network. - ports = cls.ports_client.list_ports( - network_id=network['id']).get('ports', []) - for port in ports: - test_utils.call_and_ignore_notfound_exc( - cls.ports_client.delete_port, port['id']) - - # Delete the subnets. - for subnet_id in network['subnets']: - test_utils.call_and_ignore_notfound_exc( - cls.subnets_client.delete_subnet, subnet_id) - - # Delete the network. - test_utils.call_and_ignore_notfound_exc( - cls.networks_client.delete_network, network['id']) - - @decorators.idempotent_id('5eb7b8fa-9c23-47a2-9d7d-02ed5809dd34') - def test_server_create_no_allocate(self): - """Tests that no networking is allocated for the server.""" - # create the server with no networking - server, _ = compute.create_test_server( - self.os_primary, networks='none', wait_until='ACTIVE') - self.addCleanup(self.delete_server, server['id']) - # get the server ips - addresses = self.servers_client.list_addresses( - server['id'])['addresses'] - # assert that there is no networking - self.assertEqual({}, addresses) - - @decorators.idempotent_id('2e6cf129-9e28-4e8a-aaaa-045ea826b2a6') - def test_server_multi_create_auto_allocate(self): - """Tests that networking is auto-allocated for multiple servers.""" - - # Create multiple servers with auto networking to make sure the - # automatic network allocation is atomic. Using a minimum of three - # servers is essential for this scenario because: - # - # - First request sees no networks for the tenant so it auto-allocates - # one from Neutron, let's call that net1. - # - Second request sees no networks for the tenant so it auto-allocates - # one from Neutron. Neutron creates net2 but sees it's a duplicate - # so it queues net2 for deletion and returns net1 from the API and - # Nova uses that for the second server request. - # - Third request sees net1 and net2 for the tenant and fails with a - # NetworkAmbiguous 400 error. - _, servers = compute.create_test_server( - self.os_primary, networks='auto', wait_until='ACTIVE', - min_count=3) - server_nets = set() - for server in servers: - self.addCleanup(self.delete_server, server['id']) - # get the server ips - addresses = self.servers_client.list_addresses( - server['id'])['addresses'] - # assert that there is networking (should only be one) - self.assertEqual(1, len(addresses)) - server_nets.add(list(addresses.keys())[0]) - # all servers should be on the same network - self.assertEqual(1, len(server_nets)) - - # List the networks for the tenant; we filter on admin_state_up=True - # because the auto-allocated-topology code in Neutron won't set that - # to True until the network is ready and is returned from the API. - # Duplicate networks created from a race should have - # admin_state_up=False. - search_opts = {'tenant_id': self.networks_client.tenant_id, - 'shared': False, - 'admin_state_up': True} - nets = self.networks_client.list_networks( - **search_opts).get('networks', []) - self.assertEqual(1, len(nets)) - # verify the single private tenant network is the one that the servers - # are using also - self.assertIn(nets[0]['name'], server_nets) diff --git a/tempest/api/compute/admin/test_availability_zone.py b/tempest/api/compute/admin/test_availability_zone.py deleted file mode 100644 index bbd39b685..000000000 --- a/tempest/api/compute/admin/test_availability_zone.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2013 NEC Corporation -# 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 tempest.api.compute import base -from tempest.lib import decorators - - -class AZAdminV2TestJSON(base.BaseV2ComputeAdminTest): - """Tests Availability Zone API List""" - - @classmethod - def setup_clients(cls): - super(AZAdminV2TestJSON, cls).setup_clients() - cls.client = cls.availability_zone_admin_client - - @decorators.idempotent_id('d3431479-8a09-4f76-aa2d-26dc580cb27c') - def test_get_availability_zone_list(self): - # List of availability zone - availability_zone = self.client.list_availability_zones() - self.assertNotEmpty(availability_zone['availabilityZoneInfo']) - - @decorators.idempotent_id('ef726c58-530f-44c2-968c-c7bed22d5b8c') - def test_get_availability_zone_list_detail(self): - # List of availability zones and available services - availability_zone = self.client.list_availability_zones(detail=True) - self.assertNotEmpty(availability_zone['availabilityZoneInfo']) diff --git a/tempest/api/compute/admin/test_availability_zone_negative.py b/tempest/api/compute/admin/test_availability_zone_negative.py deleted file mode 100644 index a58c22cb2..000000000 --- a/tempest/api/compute/admin/test_availability_zone_negative.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2013 NEC Corporation. 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 tempest.api.compute import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class AZAdminNegativeTestJSON(base.BaseV2ComputeAdminTest): - """Tests Availability Zone API List""" - - @classmethod - def setup_clients(cls): - super(AZAdminNegativeTestJSON, cls).setup_clients() - cls.non_adm_client = cls.availability_zone_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('bf34dca2-fdc3-4073-9c02-7648d9eae0d7') - def test_get_availability_zone_list_detail_with_non_admin_user(self): - # List of availability zones and available services with - # non-administrator user - self.assertRaises( - lib_exc.Forbidden, - self.non_adm_client.list_availability_zones, detail=True) diff --git a/tempest/api/compute/admin/test_create_server.py b/tempest/api/compute/admin/test_create_server.py deleted file mode 100644 index 3449aba2b..000000000 --- a/tempest/api/compute/admin/test_create_server.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 testtools - -from tempest.api.compute import base -from tempest.common.utils.linux import remote_client -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class ServersWithSpecificFlavorTestJSON(base.BaseV2ComputeAdminTest): - disk_config = 'AUTO' - - @classmethod - def setup_credentials(cls): - cls.prepare_instance_network() - super(ServersWithSpecificFlavorTestJSON, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(ServersWithSpecificFlavorTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - cls.set_validation_resources() - - super(ServersWithSpecificFlavorTestJSON, cls).resource_setup() - - @decorators.idempotent_id('b3c7bcfc-bb5b-4e22-b517-c7f686b802ca') - @testtools.skipUnless(CONF.validation.run_validation, - 'Instance validation tests are disabled.') - def test_verify_created_server_ephemeral_disk(self): - # Verify that the ephemeral disk is created when creating server - flavor_base = self.flavors_client.show_flavor( - self.flavor_ref)['flavor'] - - def create_flavor_with_ephemeral(ephem_disk): - name = 'flavor_with_ephemeral_%s' % ephem_disk - flavor_name = data_utils.rand_name(name) - - ram = flavor_base['ram'] - vcpus = flavor_base['vcpus'] - disk = flavor_base['disk'] - - # Create a flavor with ephemeral disk - flavor = self.create_flavor(name=flavor_name, ram=ram, vcpus=vcpus, - disk=disk, ephemeral=ephem_disk) - return flavor['id'] - - flavor_with_eph_disk_id = create_flavor_with_ephemeral(ephem_disk=1) - flavor_no_eph_disk_id = create_flavor_with_ephemeral(ephem_disk=0) - - admin_pass = self.image_ssh_password - - server_no_eph_disk = self.create_test_server( - validatable=True, - wait_until='ACTIVE', - adminPass=admin_pass, - flavor=flavor_no_eph_disk_id) - - # Get partition number of server without ephemeral disk. - server_no_eph_disk = self.client.show_server( - server_no_eph_disk['id'])['server'] - linux_client = remote_client.RemoteClient( - self.get_server_ip(server_no_eph_disk), - self.ssh_user, - admin_pass, - self.validation_resources['keypair']['private_key'], - server=server_no_eph_disk, - servers_client=self.client) - disks_num = len(linux_client.get_disks().split('\n')) - - # Explicit server deletion necessary for Juno compatibility - self.client.delete_server(server_no_eph_disk['id']) - - server_with_eph_disk = self.create_test_server( - validatable=True, - wait_until='ACTIVE', - adminPass=admin_pass, - flavor=flavor_with_eph_disk_id) - - server_with_eph_disk = self.client.show_server( - server_with_eph_disk['id'])['server'] - linux_client = remote_client.RemoteClient( - self.get_server_ip(server_with_eph_disk), - self.ssh_user, - admin_pass, - self.validation_resources['keypair']['private_key'], - server=server_with_eph_disk, - servers_client=self.client) - disks_num_eph = len(linux_client.get_disks().split('\n')) - self.assertEqual(disks_num + 1, disks_num_eph) diff --git a/tempest/api/compute/admin/test_delete_server.py b/tempest/api/compute/admin/test_delete_server.py deleted file mode 100644 index 83444b90d..000000000 --- a/tempest/api/compute/admin/test_delete_server.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class DeleteServersAdminTestJSON(base.BaseV2ComputeAdminTest): - # NOTE: Server creations of each test class should be under 10 - # for preventing "Quota exceeded for instances". - - @classmethod - def setup_clients(cls): - super(DeleteServersAdminTestJSON, cls).setup_clients() - cls.non_admin_client = cls.servers_client - cls.admin_client = cls.os_admin.servers_client - - @decorators.idempotent_id('99774678-e072-49d1-9d2a-49a59bc56063') - def test_delete_server_while_in_error_state(self): - # Delete a server while it's VM state is error - server = self.create_test_server(wait_until='ACTIVE') - self.admin_client.reset_state(server['id'], state='error') - # Verify server's state - server = self.non_admin_client.show_server(server['id'])['server'] - self.assertEqual(server['status'], 'ERROR') - self.non_admin_client.delete_server(server['id']) - waiters.wait_for_server_termination(self.servers_client, - server['id'], - ignore_error=True) - - @decorators.idempotent_id('73177903-6737-4f27-a60c-379e8ae8cf48') - def test_admin_delete_servers_of_others(self): - # Administrator can delete servers of others - server = self.create_test_server(wait_until='ACTIVE') - self.admin_client.delete_server(server['id']) - waiters.wait_for_server_termination(self.servers_client, server['id']) diff --git a/tempest/api/compute/admin/test_fixed_ips.py b/tempest/api/compute/admin/test_fixed_ips.py deleted file mode 100644 index 1e09eeb44..000000000 --- a/tempest/api/compute/admin/test_fixed_ips.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2013 IBM 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 tempest.api.compute import base -from tempest import config -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class FixedIPsTestJson(base.BaseV2ComputeAdminTest): - - @classmethod - def skip_checks(cls): - super(FixedIPsTestJson, cls).skip_checks() - if CONF.service_available.neutron: - msg = ("%s skipped as neutron is available" % cls.__name__) - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(FixedIPsTestJson, cls).setup_clients() - cls.client = cls.os_admin.fixed_ips_client - - @classmethod - def resource_setup(cls): - super(FixedIPsTestJson, cls).resource_setup() - server = cls.create_test_server(wait_until='ACTIVE') - server = cls.servers_client.show_server(server['id'])['server'] - for ip_set in server['addresses']: - for ip in server['addresses'][ip_set]: - if ip['OS-EXT-IPS:type'] == 'fixed': - cls.ip = ip['addr'] - break - if cls.ip: - break - - @decorators.idempotent_id('16b7d848-2f7c-4709-85a3-2dfb4576cc52') - @test.services('network') - def test_list_fixed_ip_details(self): - fixed_ip = self.client.show_fixed_ip(self.ip) - self.assertEqual(fixed_ip['fixed_ip']['address'], self.ip) - - @decorators.idempotent_id('5485077b-7e46-4cec-b402-91dc3173433b') - @test.services('network') - def test_set_reserve(self): - self.client.reserve_fixed_ip(self.ip, reserve="None") - - @decorators.idempotent_id('7476e322-b9ff-4710-bf82-49d51bac6e2e') - @test.services('network') - def test_set_unreserve(self): - self.client.reserve_fixed_ip(self.ip, unreserve="None") diff --git a/tempest/api/compute/admin/test_fixed_ips_negative.py b/tempest/api/compute/admin/test_fixed_ips_negative.py deleted file mode 100644 index a77011e6a..000000000 --- a/tempest/api/compute/admin/test_fixed_ips_negative.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright 2013 NEC Corporation. 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 tempest.api.compute import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class FixedIPsNegativeTestJson(base.BaseV2ComputeAdminTest): - - @classmethod - def skip_checks(cls): - super(FixedIPsNegativeTestJson, cls).skip_checks() - if CONF.service_available.neutron: - msg = ("%s skipped as neutron is available" % cls.__name__) - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(FixedIPsNegativeTestJson, cls).setup_clients() - cls.client = cls.os_admin.fixed_ips_client - cls.non_admin_client = cls.fixed_ips_client - - @classmethod - def resource_setup(cls): - super(FixedIPsNegativeTestJson, cls).resource_setup() - server = cls.create_test_server(wait_until='ACTIVE') - server = cls.servers_client.show_server(server['id'])['server'] - for ip_set in server['addresses']: - for ip in server['addresses'][ip_set]: - if ip['OS-EXT-IPS:type'] == 'fixed': - cls.ip = ip['addr'] - break - if cls.ip: - break - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9f17f47d-daad-4adc-986e-12370c93e407') - @test.services('network') - def test_list_fixed_ip_details_with_non_admin_user(self): - self.assertRaises(lib_exc.Forbidden, - self.non_admin_client.show_fixed_ip, self.ip) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ce60042c-fa60-4836-8d43-1c8e3359dc47') - @test.services('network') - def test_set_reserve_with_non_admin_user(self): - self.assertRaises(lib_exc.Forbidden, - self.non_admin_client.reserve_fixed_ip, - self.ip, reserve="None") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f1f7a35b-0390-48c5-9803-5f27461439db') - @test.services('network') - def test_set_unreserve_with_non_admin_user(self): - self.assertRaises(lib_exc.Forbidden, - self.non_admin_client.reserve_fixed_ip, - self.ip, unreserve="None") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f51cf464-7fc5-4352-bc3e-e75cfa2cb717') - @test.services('network') - def test_set_reserve_with_invalid_ip(self): - # NOTE(maurosr): since this exercises the same code snippet, we do it - # only for reserve action - # NOTE(eliqiao): in Juno, the exception is NotFound, but in master, we - # change the error code to BadRequest, both exceptions should be - # accepted by tempest - self.assertRaises((lib_exc.NotFound, lib_exc.BadRequest), - self.client.reserve_fixed_ip, - "my.invalid.ip", reserve="None") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('fd26ef50-f135-4232-9d32-281aab3f9176') - @test.services('network') - def test_fixed_ip_with_invalid_action(self): - self.assertRaises(lib_exc.BadRequest, - self.client.reserve_fixed_ip, - self.ip, invalid_action="None") diff --git a/tempest/api/compute/admin/test_flavors.py b/tempest/api/compute/admin/test_flavors.py deleted file mode 100644 index 36ebc252f..000000000 --- a/tempest/api/compute/admin/test_flavors.py +++ /dev/null @@ -1,225 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 uuid - -from tempest.api.compute import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - - -class FlavorsAdminTestJSON(base.BaseV2ComputeAdminTest): - """Tests Flavors API Create and Delete that require admin privileges""" - - @classmethod - def skip_checks(cls): - super(FlavorsAdminTestJSON, cls).skip_checks() - if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'): - msg = "OS-FLV-EXT-DATA extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(FlavorsAdminTestJSON, cls).resource_setup() - - cls.flavor_name_prefix = 'test_flavor_' - cls.ram = 512 - cls.vcpus = 1 - cls.disk = 10 - cls.ephemeral = 10 - cls.swap = 1024 - cls.rxtx = 2 - - @decorators.idempotent_id('8b4330e1-12c4-4554-9390-e6639971f086') - def test_create_flavor_with_int_id(self): - flavor_id = data_utils.rand_int_id(start=1000) - new_flavor_id = self.create_flavor(ram=self.ram, - vcpus=self.vcpus, - disk=self.disk, - id=flavor_id)['id'] - self.assertEqual(new_flavor_id, str(flavor_id)) - - @decorators.idempotent_id('94c9bb4e-2c2a-4f3c-bb1f-5f0daf918e6d') - def test_create_flavor_with_uuid_id(self): - flavor_id = data_utils.rand_uuid() - new_flavor_id = self.create_flavor(ram=self.ram, - vcpus=self.vcpus, - disk=self.disk, - id=flavor_id)['id'] - self.assertEqual(new_flavor_id, flavor_id) - - @decorators.idempotent_id('f83fe669-6758-448a-a85e-32d351f36fe0') - def test_create_flavor_with_none_id(self): - # If nova receives a request with None as flavor_id, - # nova generates flavor_id of uuid. - flavor_id = None - new_flavor_id = self.create_flavor(ram=self.ram, - vcpus=self.vcpus, - disk=self.disk, - id=flavor_id)['id'] - self.assertEqual(new_flavor_id, str(uuid.UUID(new_flavor_id))) - - @decorators.idempotent_id('8261d7b0-be58-43ec-a2e5-300573c3f6c5') - def test_create_flavor_verify_entry_in_list_details(self): - # Create a flavor and ensure it's details are listed - # This operation requires the user to have 'admin' role - flavor_name = data_utils.rand_name(self.flavor_name_prefix) - - # Create the flavor - self.create_flavor(name=flavor_name, - ram=self.ram, vcpus=self.vcpus, - disk=self.disk, - ephemeral=self.ephemeral, - swap=self.swap, - rxtx_factor=self.rxtx) - - # Check if flavor is present in list - flavors_list = self.admin_flavors_client.list_flavors( - detail=True)['flavors'] - self.assertIn(flavor_name, [f['name'] for f in flavors_list]) - - @decorators.idempotent_id('63dc64e6-2e79-4fdf-868f-85500d308d66') - def test_create_list_flavor_without_extra_data(self): - # Create a flavor and ensure it is listed - # This operation requires the user to have 'admin' role - - def verify_flavor_response_extension(flavor): - # check some extensions for the flavor create/show/detail response - self.assertEqual(flavor['swap'], '') - self.assertEqual(int(flavor['rxtx_factor']), 1) - self.assertEqual(flavor['OS-FLV-EXT-DATA:ephemeral'], 0) - self.assertEqual(flavor['os-flavor-access:is_public'], True) - - flavor_name = data_utils.rand_name(self.flavor_name_prefix) - new_flavor_id = data_utils.rand_int_id(start=1000) - - # Create the flavor - flavor = self.create_flavor(name=flavor_name, - ram=self.ram, vcpus=self.vcpus, - disk=self.disk, - id=new_flavor_id) - self.assertEqual(flavor['name'], flavor_name) - self.assertEqual(flavor['ram'], self.ram) - self.assertEqual(flavor['vcpus'], self.vcpus) - self.assertEqual(flavor['disk'], self.disk) - self.assertEqual(int(flavor['id']), new_flavor_id) - verify_flavor_response_extension(flavor) - - # Verify flavor is retrieved - flavor = self.admin_flavors_client.show_flavor(new_flavor_id)['flavor'] - self.assertEqual(flavor['name'], flavor_name) - verify_flavor_response_extension(flavor) - - # Check if flavor is present in list - flavors_list = [ - f for f in self.flavors_client.list_flavors(detail=True)['flavors'] - if f['name'] == flavor_name - ] - self.assertNotEmpty(flavors_list) - verify_flavor_response_extension(flavors_list[0]) - - @decorators.idempotent_id('be6cc18c-7c5d-48c0-ac16-17eaf03c54eb') - def test_list_non_public_flavor(self): - # Create a flavor with os-flavor-access:is_public false. - # The flavor should not be present in list_details as the - # tenant is not automatically added access list. - # This operation requires the user to have 'admin' role - flavor_name = data_utils.rand_name(self.flavor_name_prefix) - - # Create the flavor - self.create_flavor(name=flavor_name, - ram=self.ram, vcpus=self.vcpus, - disk=self.disk, - is_public="False") - # Verify flavor is not retrieved - flavors_list = self.admin_flavors_client.list_flavors( - detail=True)['flavors'] - self.assertNotIn(flavor_name, [f['name'] for f in flavors_list]) - - # Verify flavor is not retrieved with other user - flavors_list = self.flavors_client.list_flavors(detail=True)['flavors'] - self.assertNotIn(flavor_name, [f['name'] for f in flavors_list]) - - @decorators.idempotent_id('bcc418ef-799b-47cc-baa1-ce01368b8987') - def test_create_server_with_non_public_flavor(self): - # Create a flavor with os-flavor-access:is_public false - flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus, - disk=self.disk, - is_public="False") - - # Verify flavor is not used by other user - self.assertRaises(lib_exc.BadRequest, - self.os_primary.servers_client.create_server, - name='test', imageRef=self.image_ref, - flavorRef=flavor['id']) - - @decorators.idempotent_id('b345b196-bfbd-4231-8ac1-6d7fe15ff3a3') - def test_list_public_flavor_with_other_user(self): - # Create a Flavor with public access. - # Try to List/Get flavor with another user - flavor_name = data_utils.rand_name(self.flavor_name_prefix) - - # Create the flavor - self.create_flavor(name=flavor_name, - ram=self.ram, vcpus=self.vcpus, - disk=self.disk, - is_public="True") - # Verify flavor is retrieved with new user - flavors_list = self.flavors_client.list_flavors(detail=True)['flavors'] - self.assertIn(flavor_name, [f['name'] for f in flavors_list]) - - @decorators.idempotent_id('fb9cbde6-3a0e-41f2-a983-bdb0a823c44e') - def test_is_public_string_variations(self): - flavor_name_not_public = data_utils.rand_name(self.flavor_name_prefix) - flavor_name_public = data_utils.rand_name(self.flavor_name_prefix) - - # Create a non public flavor - self.create_flavor(name=flavor_name_not_public, - ram=self.ram, vcpus=self.vcpus, - disk=self.disk, - is_public="False") - - # Create a public flavor - self.create_flavor(name=flavor_name_public, - ram=self.ram, vcpus=self.vcpus, - disk=self.disk, - is_public="True") - - def _test_string_variations(variations, flavor_name): - for string in variations: - params = {'is_public': string} - flavors = (self.admin_flavors_client.list_flavors(detail=True, - **params) - ['flavors']) - self.assertIn(flavor_name, [f['name'] for f in flavors]) - - _test_string_variations(['f', 'false', 'no', '0'], - flavor_name_not_public) - - _test_string_variations(['t', 'true', 'yes', '1'], - flavor_name_public) - - @decorators.idempotent_id('3b541a2e-2ac2-4b42-8b8d-ba6e22fcd4da') - def test_create_flavor_using_string_ram(self): - new_flavor_id = data_utils.rand_int_id(start=1000) - - ram = "1024" - flavor = self.create_flavor(ram=ram, vcpus=self.vcpus, - disk=self.disk, - id=new_flavor_id) - self.assertEqual(flavor['ram'], int(ram)) - self.assertEqual(int(flavor['id']), new_flavor_id) diff --git a/tempest/api/compute/admin/test_flavors_access.py b/tempest/api/compute/admin/test_flavors_access.py deleted file mode 100644 index 2c236ec71..000000000 --- a/tempest/api/compute/admin/test_flavors_access.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright 2013 NEC Corporation. -# 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 tempest.api.compute import base -from tempest.lib import decorators -from tempest import test - - -class FlavorsAccessTestJSON(base.BaseV2ComputeAdminTest): - """Tests Flavor Access API extension. - - Add and remove Flavor Access require admin privileges. - """ - - @classmethod - def skip_checks(cls): - super(FlavorsAccessTestJSON, cls).skip_checks() - if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'): - msg = "OS-FLV-EXT-DATA extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(FlavorsAccessTestJSON, cls).resource_setup() - - # Non admin tenant ID - cls.tenant_id = cls.flavors_client.tenant_id - cls.ram = 512 - cls.vcpus = 1 - cls.disk = 10 - - @decorators.idempotent_id('ea2c2211-29fa-4db9-97c3-906d36fad3e0') - def test_flavor_access_list_with_private_flavor(self): - # Test to make sure that list flavor access on a newly created - # private flavor will return an empty access list - flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus, - disk=self.disk, is_public='False') - - flavor_access = (self.admin_flavors_client.list_flavor_access( - flavor['id'])['flavor_access']) - self.assertEmpty(flavor_access) - - @decorators.idempotent_id('59e622f6-bdf6-45e3-8ba8-fedad905a6b4') - def test_flavor_access_add_remove(self): - # Test to add and remove flavor access to a given tenant. - flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus, - disk=self.disk, is_public='False') - - # Add flavor access to a tenant. - resp_body = { - "tenant_id": str(self.tenant_id), - "flavor_id": str(flavor['id']), - } - add_body = (self.admin_flavors_client.add_flavor_access( - flavor['id'], self.tenant_id)['flavor_access']) - self.assertIn(resp_body, add_body) - - # The flavor is present in list. - flavors = self.flavors_client.list_flavors(detail=True)['flavors'] - self.assertIn(flavor['id'], map(lambda x: x['id'], flavors)) - - # Remove flavor access from a tenant. - remove_body = (self.admin_flavors_client.remove_flavor_access( - flavor['id'], self.tenant_id)['flavor_access']) - self.assertNotIn(resp_body, remove_body) - - # The flavor is not present in list. - flavors = self.flavors_client.list_flavors(detail=True)['flavors'] - self.assertNotIn(flavor['id'], map(lambda x: x['id'], flavors)) diff --git a/tempest/api/compute/admin/test_flavors_access_negative.py b/tempest/api/compute/admin/test_flavors_access_negative.py deleted file mode 100644 index be165cb2f..000000000 --- a/tempest/api/compute/admin/test_flavors_access_negative.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright 2013 IBM Corporation -# 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 tempest.api.compute import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - - -class FlavorsAccessNegativeTestJSON(base.BaseV2ComputeAdminTest): - """Tests Flavor Access API extension. - - Add and remove Flavor Access require admin privileges. - """ - - credentials = ['primary', 'admin', 'alt'] - - @classmethod - def skip_checks(cls): - super(FlavorsAccessNegativeTestJSON, cls).skip_checks() - if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'): - msg = "OS-FLV-EXT-DATA extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(FlavorsAccessNegativeTestJSON, cls).resource_setup() - - cls.tenant_id = cls.flavors_client.tenant_id - cls.ram = 512 - cls.vcpus = 1 - cls.disk = 10 - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0621c53e-d45d-40e7-951d-43e5e257b272') - def test_flavor_access_list_with_public_flavor(self): - # Test to list flavor access with exceptions by querying public flavor - flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus, - disk=self.disk, is_public='True') - self.assertRaises(lib_exc.NotFound, - self.admin_flavors_client.list_flavor_access, - flavor['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('41eaaade-6d37-4f28-9c74-f21b46ca67bd') - def test_flavor_non_admin_add(self): - # Test to add flavor access as a user without admin privileges. - flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus, - disk=self.disk, is_public='False') - self.assertRaises(lib_exc.Forbidden, - self.flavors_client.add_flavor_access, - flavor['id'], - self.tenant_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('073e79a6-c311-4525-82dc-6083d919cb3a') - def test_flavor_non_admin_remove(self): - # Test to remove flavor access as a user without admin privileges. - flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus, - disk=self.disk, is_public='False') - - # Add flavor access to a tenant. - self.admin_flavors_client.add_flavor_access(flavor['id'], - self.tenant_id) - self.addCleanup(self.admin_flavors_client.remove_flavor_access, - flavor['id'], self.tenant_id) - self.assertRaises(lib_exc.Forbidden, - self.flavors_client.remove_flavor_access, - flavor['id'], - self.tenant_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f3592cc0-0306-483c-b210-9a7b5346eddc') - def test_add_flavor_access_duplicate(self): - # Create a new flavor. - flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus, - disk=self.disk, is_public='False') - - # Add flavor access to a tenant. - self.admin_flavors_client.add_flavor_access(flavor['id'], - self.tenant_id) - self.addCleanup(self.admin_flavors_client.remove_flavor_access, - flavor['id'], self.tenant_id) - - # An exception should be raised when adding flavor access to the same - # tenant - self.assertRaises(lib_exc.Conflict, - self.admin_flavors_client.add_flavor_access, - flavor['id'], - self.tenant_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1f710927-3bc7-4381-9f82-0ca6e42644b7') - def test_remove_flavor_access_not_found(self): - # Create a new flavor. - flavor = self.create_flavor(ram=self.ram, vcpus=self.vcpus, - disk=self.disk, is_public='False') - - # An exception should be raised when flavor access is not found - self.assertRaises(lib_exc.NotFound, - self.admin_flavors_client.remove_flavor_access, - flavor['id'], - self.os_alt.servers_client.tenant_id) diff --git a/tempest/api/compute/admin/test_flavors_extra_specs.py b/tempest/api/compute/admin/test_flavors_extra_specs.py deleted file mode 100644 index 747cb42da..000000000 --- a/tempest/api/compute/admin/test_flavors_extra_specs.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.compute import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - - -class FlavorsExtraSpecsTestJSON(base.BaseV2ComputeAdminTest): - """Tests Flavor Extra Spec API extension. - - SET, UNSET, UPDATE Flavor Extra specs require admin privileges. - GET Flavor Extra specs can be performed even by without admin privileges. - """ - - @classmethod - def skip_checks(cls): - super(FlavorsExtraSpecsTestJSON, cls).skip_checks() - if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'): - msg = "OS-FLV-EXT-DATA extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(FlavorsExtraSpecsTestJSON, cls).resource_setup() - flavor_name = data_utils.rand_name('test_flavor') - ram = 512 - vcpus = 1 - disk = 10 - ephemeral = 10 - new_flavor_id = data_utils.rand_int_id(start=1000) - swap = 1024 - rxtx = 1 - # Create a flavor so as to set/get/unset extra specs - cls.flavor = cls.admin_flavors_client.create_flavor( - name=flavor_name, - ram=ram, vcpus=vcpus, - disk=disk, - id=new_flavor_id, - ephemeral=ephemeral, - swap=swap, - rxtx_factor=rxtx)['flavor'] - - @classmethod - def resource_cleanup(cls): - cls.admin_flavors_client.delete_flavor(cls.flavor['id']) - cls.admin_flavors_client.wait_for_resource_deletion(cls.flavor['id']) - super(FlavorsExtraSpecsTestJSON, cls).resource_cleanup() - - @decorators.idempotent_id('0b2f9d4b-1ca2-4b99-bb40-165d4bb94208') - def test_flavor_set_get_update_show_unset_keys(self): - # Test to SET, GET, UPDATE, SHOW, UNSET flavor extra - # spec as a user with admin privileges. - # Assigning extra specs values that are to be set - specs = {"key1": "value1", "key2": "value2"} - # SET extra specs to the flavor created in setUp - set_body = self.admin_flavors_client.set_flavor_extra_spec( - self.flavor['id'], **specs)['extra_specs'] - self.assertEqual(set_body, specs) - # GET extra specs and verify - get_body = (self.admin_flavors_client.list_flavor_extra_specs( - self.flavor['id'])['extra_specs']) - self.assertEqual(get_body, specs) - - # UPDATE the value of the extra specs key1 - update_body = \ - self.admin_flavors_client.update_flavor_extra_spec( - self.flavor['id'], "key1", key1="value") - self.assertEqual({"key1": "value"}, update_body) - - # GET extra specs and verify the value of the key2 - # is the same as before - get_body = self.admin_flavors_client.list_flavor_extra_specs( - self.flavor['id'])['extra_specs'] - self.assertEqual(get_body, {"key1": "value", "key2": "value2"}) - - # UNSET extra specs that were set in this test - self.admin_flavors_client.unset_flavor_extra_spec(self.flavor['id'], - "key1") - self.admin_flavors_client.unset_flavor_extra_spec(self.flavor['id'], - "key2") - get_body = self.admin_flavors_client.list_flavor_extra_specs( - self.flavor['id'])['extra_specs'] - self.assertEmpty(get_body) - - @decorators.idempotent_id('a99dad88-ae1c-4fba-aeb4-32f898218bd0') - def test_flavor_non_admin_get_all_keys(self): - specs = {"key1": "value1", "key2": "value2"} - self.admin_flavors_client.set_flavor_extra_spec(self.flavor['id'], - **specs) - body = (self.flavors_client.list_flavor_extra_specs( - self.flavor['id'])['extra_specs']) - - for key in specs: - self.assertEqual(body[key], specs[key]) - - @decorators.idempotent_id('12805a7f-39a3-4042-b989-701d5cad9c90') - def test_flavor_non_admin_get_specific_key(self): - body = self.admin_flavors_client.set_flavor_extra_spec( - self.flavor['id'], key1="value1", key2="value2")['extra_specs'] - self.assertEqual(body['key1'], 'value1') - self.assertIn('key2', body) - body = self.flavors_client.show_flavor_extra_spec( - self.flavor['id'], 'key1') - self.assertEqual(body['key1'], 'value1') - self.assertNotIn('key2', body) diff --git a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py b/tempest/api/compute/admin/test_flavors_extra_specs_negative.py deleted file mode 100644 index f39feb9e6..000000000 --- a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py +++ /dev/null @@ -1,134 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# All Rights Reserved. -# Copyright 2013 IBM Corp. -# -# 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 tempest.api.compute import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - - -class FlavorsExtraSpecsNegativeTestJSON(base.BaseV2ComputeAdminTest): - """Negative Tests Flavor Extra Spec API extension. - - SET, UNSET, UPDATE Flavor Extra specs require admin privileges. - """ - - @classmethod - def skip_checks(cls): - super(FlavorsExtraSpecsNegativeTestJSON, cls).skip_checks() - if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'): - msg = "OS-FLV-EXT-DATA extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(FlavorsExtraSpecsNegativeTestJSON, cls).resource_setup() - - flavor_name = data_utils.rand_name('test_flavor') - ram = 512 - vcpus = 1 - disk = 10 - ephemeral = 10 - new_flavor_id = data_utils.rand_int_id(start=1000) - swap = 1024 - rxtx = 1 - # Create a flavor - cls.flavor = cls.admin_flavors_client.create_flavor( - name=flavor_name, - ram=ram, vcpus=vcpus, - disk=disk, - id=new_flavor_id, - ephemeral=ephemeral, - swap=swap, - rxtx_factor=rxtx)['flavor'] - - @classmethod - def resource_cleanup(cls): - cls.admin_flavors_client.delete_flavor(cls.flavor['id']) - cls.admin_flavors_client.wait_for_resource_deletion(cls.flavor['id']) - super(FlavorsExtraSpecsNegativeTestJSON, cls).resource_cleanup() - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a00a3b81-5641-45a8-ab2b-4a8ec41e1d7d') - def test_flavor_non_admin_set_keys(self): - # Test to SET flavor extra spec as a user without admin privileges. - self.assertRaises(lib_exc.Forbidden, - self.flavors_client.set_flavor_extra_spec, - self.flavor['id'], - key1="value1", key2="value2") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1ebf4ef8-759e-48fe-a801-d451d80476fb') - def test_flavor_non_admin_update_specific_key(self): - # non admin user is not allowed to update flavor extra spec - body = self.admin_flavors_client.set_flavor_extra_spec( - self.flavor['id'], key1="value1", key2="value2")['extra_specs'] - self.assertEqual(body['key1'], 'value1') - self.assertRaises(lib_exc.Forbidden, - self.flavors_client. - update_flavor_extra_spec, - self.flavor['id'], - 'key1', - key1='value1_new') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('28f12249-27c7-44c1-8810-1f382f316b11') - def test_flavor_non_admin_unset_keys(self): - self.admin_flavors_client.set_flavor_extra_spec( - self.flavor['id'], key1="value1", key2="value2") - - self.assertRaises(lib_exc.Forbidden, - self.flavors_client.unset_flavor_extra_spec, - self.flavor['id'], - 'key1') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('440b9f3f-3c7f-4293-a106-0ceda350f8de') - def test_flavor_unset_nonexistent_key(self): - self.assertRaises(lib_exc.NotFound, - self.admin_flavors_client.unset_flavor_extra_spec, - self.flavor['id'], - 'nonexistent_key') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('329a7be3-54b2-48be-8052-bf2ce4afd898') - def test_flavor_get_nonexistent_key(self): - self.assertRaises(lib_exc.NotFound, - self.flavors_client.show_flavor_extra_spec, - self.flavor['id'], - "nonexistent_key") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('25b822b8-9f49-44f6-80de-d99f0482e5cb') - def test_flavor_update_mismatch_key(self): - # the key will be updated should be match the key in the body - self.assertRaises(lib_exc.BadRequest, - self.admin_flavors_client.update_flavor_extra_spec, - self.flavor['id'], - "key2", - key1="value") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f5889590-bf66-41cc-b4b1-6e6370cfd93f') - def test_flavor_update_more_key(self): - # there should be just one item in the request body - self.assertRaises(lib_exc.BadRequest, - self.admin_flavors_client.update_flavor_extra_spec, - self.flavor['id'], - "key1", - key1="value", - key2="value") diff --git a/tempest/api/compute/admin/test_floating_ips_bulk.py b/tempest/api/compute/admin/test_floating_ips_bulk.py deleted file mode 100644 index 496f11994..000000000 --- a/tempest/api/compute/admin/test_floating_ips_bulk.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright 2014 NEC Technologies India Ltd. -# 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 netaddr - -from tempest.api.compute import base -from tempest import config -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions -from tempest import test - -CONF = config.CONF - - -class FloatingIPsBulkAdminTestJSON(base.BaseV2ComputeAdminTest): - """Tests Floating IPs Bulk APIs that require admin privileges. - - API documentation - http://docs.openstack.org/api/openstack-compute/2/ - content/ext-os-floating-ips-bulk.html - """ - - @classmethod - def setup_clients(cls): - super(FloatingIPsBulkAdminTestJSON, cls).setup_clients() - cls.client = cls.os_admin.floating_ips_bulk_client - - @classmethod - def resource_setup(cls): - super(FloatingIPsBulkAdminTestJSON, cls).resource_setup() - cls.ip_range = CONF.validation.floating_ip_range - cls.verify_unallocated_floating_ip_range(cls.ip_range) - - @classmethod - def verify_unallocated_floating_ip_range(cls, ip_range): - # Verify whether configure floating IP range is not already allocated. - body = cls.client.list_floating_ips_bulk()['floating_ip_info'] - allocated_ips_list = map(lambda x: x['address'], body) - for ip_addr in netaddr.IPNetwork(ip_range).iter_hosts(): - if str(ip_addr) in allocated_ips_list: - msg = ("Configured unallocated floating IP range is already " - "allocated. Configure the correct unallocated range " - "as 'floating_ip_range'") - raise exceptions.InvalidConfiguration(msg) - return - - @decorators.idempotent_id('2c8f145f-8012-4cb8-ac7e-95a587f0e4ab') - @test.services('network') - def test_create_list_delete_floating_ips_bulk(self): - # Create, List and delete the Floating IPs Bulk - pool = 'test_pool' - # NOTE(GMann): Reserving the IP range but those are not attached - # anywhere. Using the below mentioned interface which is not ever - # expected to be used. Clean Up has been done for created IP range - interface = 'eth0' - body = (self.client.create_floating_ips_bulk(self.ip_range, - pool, - interface) - ['floating_ips_bulk_create']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.client.delete_floating_ips_bulk, self.ip_range) - self.assertEqual(self.ip_range, body['ip_range']) - ips_list = self.client.list_floating_ips_bulk()['floating_ip_info'] - self.assertNotEmpty(ips_list) - for ip in netaddr.IPNetwork(self.ip_range).iter_hosts(): - self.assertIn(str(ip), map(lambda x: x['address'], ips_list)) - body = (self.client.delete_floating_ips_bulk(self.ip_range) - ['floating_ips_bulk_delete']) - self.assertEqual(self.ip_range, body) diff --git a/tempest/api/compute/admin/test_hosts.py b/tempest/api/compute/admin/test_hosts.py deleted file mode 100644 index 0e1e7edf6..000000000 --- a/tempest/api/compute/admin/test_hosts.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# 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 tempest.api.compute import base -from tempest.common import tempest_fixtures as fixtures -from tempest.lib import decorators - - -class HostsAdminTestJSON(base.BaseV2ComputeAdminTest): - """Tests hosts API using admin privileges.""" - - @classmethod - def setup_clients(cls): - super(HostsAdminTestJSON, cls).setup_clients() - cls.client = cls.os_admin.hosts_client - - @decorators.idempotent_id('9bfaf98d-e2cb-44b0-a07e-2558b2821e4f') - def test_list_hosts(self): - hosts = self.client.list_hosts()['hosts'] - self.assertGreaterEqual(len(hosts), 2, str(hosts)) - - @decorators.idempotent_id('5dc06f5b-d887-47a2-bb2a-67762ef3c6de') - def test_list_hosts_with_zone(self): - self.useFixture(fixtures.LockFixture('availability_zone')) - hosts = self.client.list_hosts()['hosts'] - host = hosts[0] - hosts = self.client.list_hosts(zone=host['zone'])['hosts'] - self.assertNotEmpty(hosts) - self.assertIn(host, hosts) - - @decorators.idempotent_id('9af3c171-fbf4-4150-a624-22109733c2a6') - def test_list_hosts_with_a_blank_zone(self): - # If send the request with a blank zone, the request will be successful - # and it will return all the hosts list - hosts = self.client.list_hosts(zone='')['hosts'] - self.assertNotEmpty(hosts) - - @decorators.idempotent_id('c6ddbadb-c94e-4500-b12f-8ffc43843ff8') - def test_list_hosts_with_nonexistent_zone(self): - # If send the request with a nonexistent zone, the request will be - # successful and no hosts will be returned - hosts = self.client.list_hosts(zone='xxx')['hosts'] - self.assertEmpty(hosts) - - @decorators.idempotent_id('38adbb12-aee2-4498-8aec-329c72423aa4') - def test_show_host_detail(self): - hosts = self.client.list_hosts()['hosts'] - - hosts = [host for host in hosts if host['service'] == 'compute'] - self.assertNotEmpty(hosts) - - for host in hosts: - hostname = host['host_name'] - resources = self.client.show_host(hostname)['host'] - self.assertNotEmpty(resources) - host_resource = resources[0]['resource'] - self.assertIsNotNone(host_resource) - self.assertIsNotNone(host_resource['cpu']) - self.assertIsNotNone(host_resource['disk_gb']) - self.assertIsNotNone(host_resource['memory_mb']) - self.assertIsNotNone(host_resource['project']) - self.assertEqual(hostname, host_resource['host']) diff --git a/tempest/api/compute/admin/test_hosts_negative.py b/tempest/api/compute/admin/test_hosts_negative.py deleted file mode 100644 index 5bd810419..000000000 --- a/tempest/api/compute/admin/test_hosts_negative.py +++ /dev/null @@ -1,142 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD. -# -# 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 tempest.api.compute import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class HostsAdminNegativeTestJSON(base.BaseV2ComputeAdminTest): - """Tests hosts API using admin privileges.""" - - @classmethod - def setup_clients(cls): - super(HostsAdminNegativeTestJSON, cls).setup_clients() - cls.client = cls.os_admin.hosts_client - cls.non_admin_client = cls.os_primary.hosts_client - - @classmethod - def resource_setup(cls): - super(HostsAdminNegativeTestJSON, cls).resource_setup() - hosts = cls.client.list_hosts()['hosts'] - if not hosts: - raise lib_exc.NotFound("no host found") - cls.hostname = hosts[0]['host_name'] - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('dd032027-0210-4d9c-860e-69b1b8deed5f') - def test_list_hosts_with_non_admin_user(self): - self.assertRaises(lib_exc.Forbidden, - self.non_admin_client.list_hosts) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e75b0a1a-041f-47a1-8b4a-b72a6ff36d3f') - def test_show_host_detail_with_nonexistent_hostname(self): - self.assertRaises(lib_exc.NotFound, - self.client.show_host, 'nonexistent_hostname') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('19ebe09c-bfd4-4b7c-81a2-e2e0710f59cc') - def test_show_host_detail_with_non_admin_user(self): - self.assertRaises(lib_exc.Forbidden, - self.non_admin_client.show_host, - self.hostname) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e40c72b1-0239-4ed6-ba21-81a184df1f7c') - def test_update_host_with_non_admin_user(self): - self.assertRaises(lib_exc.Forbidden, - self.non_admin_client.update_host, - self.hostname, - status='enable', - maintenance_mode='enable') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('fbe2bf3e-3246-4a95-a59f-94e4e298ec77') - def test_update_host_with_invalid_status(self): - # 'status' can only be 'enable' or 'disable' - self.assertRaises(lib_exc.BadRequest, - self.client.update_host, - self.hostname, - status='invalid', - maintenance_mode='enable') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ab1e230e-5e22-41a9-8699-82b9947915d4') - def test_update_host_with_invalid_maintenance_mode(self): - # 'maintenance_mode' can only be 'enable' or 'disable' - self.assertRaises(lib_exc.BadRequest, - self.client.update_host, - self.hostname, - status='enable', - maintenance_mode='invalid') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0cd85f75-6992-4a4a-b1bd-d11e37fd0eee') - def test_update_host_without_param(self): - # 'status' or 'maintenance_mode' needed for host update - self.assertRaises(lib_exc.BadRequest, - self.client.update_host, - self.hostname) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('23c92146-2100-4d68-b2d6-c7ade970c9c1') - def test_update_nonexistent_host(self): - self.assertRaises(lib_exc.NotFound, - self.client.update_host, - 'nonexistent_hostname', - status='enable', - maintenance_mode='enable') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0d981ac3-4320-4898-b674-82b61fbb60e4') - def test_startup_nonexistent_host(self): - self.assertRaises(lib_exc.NotFound, - self.client.startup_host, - 'nonexistent_hostname') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9f4ebb7e-b2ae-4e5b-a38f-0fd1bb0ddfca') - def test_startup_host_with_non_admin_user(self): - self.assertRaises(lib_exc.Forbidden, - self.non_admin_client.startup_host, - self.hostname) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9e637444-29cf-4244-88c8-831ae82c31b6') - def test_shutdown_nonexistent_host(self): - self.assertRaises(lib_exc.NotFound, - self.client.shutdown_host, - 'nonexistent_hostname') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a803529c-7e3f-4d3c-a7d6-8e1c203d27f6') - def test_shutdown_host_with_non_admin_user(self): - self.assertRaises(lib_exc.Forbidden, - self.non_admin_client.shutdown_host, - self.hostname) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f86bfd7b-0b13-4849-ae29-0322e83ee58b') - def test_reboot_nonexistent_host(self): - self.assertRaises(lib_exc.NotFound, - self.client.reboot_host, - 'nonexistent_hostname') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('02d79bb9-eb57-4612-abf6-2cb38897d2f8') - def test_reboot_host_with_non_admin_user(self): - self.assertRaises(lib_exc.Forbidden, - self.non_admin_client.reboot_host, - self.hostname) diff --git a/tempest/api/compute/admin/test_hypervisor.py b/tempest/api/compute/admin/test_hypervisor.py deleted file mode 100644 index 0db802cf5..000000000 --- a/tempest/api/compute/admin/test_hypervisor.py +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright 2013 IBM Corporation -# 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 tempest.api.compute import base -from tempest.lib import decorators - - -class HypervisorAdminTestJSON(base.BaseV2ComputeAdminTest): - """Tests Hypervisors API that require admin privileges""" - - @classmethod - def setup_clients(cls): - super(HypervisorAdminTestJSON, cls).setup_clients() - cls.client = cls.os_admin.hypervisor_client - - def _list_hypervisors(self): - # List of hypervisors - hypers = self.client.list_hypervisors()['hypervisors'] - return hypers - - def assertHypervisors(self, hypers): - self.assertNotEmpty(hypers, "No hypervisors found: %s" % hypers) - - @decorators.idempotent_id('7f0ceacd-c64d-4e96-b8ee-d02943142cc5') - def test_get_hypervisor_list(self): - # List of hypervisor and available hypervisors hostname - hypers = self._list_hypervisors() - self.assertHypervisors(hypers) - - @decorators.idempotent_id('1e7fdac2-b672-4ad1-97a4-bad0e3030118') - def test_get_hypervisor_list_details(self): - # Display the details of the all hypervisor - hypers = self.client.list_hypervisors(detail=True)['hypervisors'] - self.assertHypervisors(hypers) - - @decorators.idempotent_id('94ff9eae-a183-428e-9cdb-79fde71211cc') - def test_get_hypervisor_show_details(self): - # Display the details of the specified hypervisor - hypers = self._list_hypervisors() - self.assertHypervisors(hypers) - - details = self.client.show_hypervisor(hypers[0]['id'])['hypervisor'] - self.assertNotEmpty(details) - self.assertEqual(details['hypervisor_hostname'], - hypers[0]['hypervisor_hostname']) - - @decorators.idempotent_id('e81bba3f-6215-4e39-a286-d52d2f906862') - def test_get_hypervisor_show_servers(self): - # Show instances about the specific hypervisors - hypers = self._list_hypervisors() - self.assertHypervisors(hypers) - - hostname = hypers[0]['hypervisor_hostname'] - hypervisors = (self.client.list_servers_on_hypervisor(hostname) - ['hypervisors']) - self.assertNotEmpty(hypervisors) - - @decorators.idempotent_id('797e4f28-b6e0-454d-a548-80cc77c00816') - def test_get_hypervisor_stats(self): - # Verify the stats of the all hypervisor - stats = (self.client.show_hypervisor_statistics() - ['hypervisor_statistics']) - self.assertNotEmpty(stats) - - @decorators.idempotent_id('91a50d7d-1c2b-4f24-b55a-a1fe20efca70') - def test_get_hypervisor_uptime(self): - # Verify that GET shows the specified hypervisor uptime - hypers = self._list_hypervisors() - - # Ironic will register each baremetal node as a 'hypervisor', - # so the hypervisor list can contain many hypervisors of type - # 'ironic'. If they are ALL ironic, skip this test since ironic - # doesn't support hypervisor uptime. Otherwise, remove them - # from the list of hypervisors to test. - ironic_only = True - hypers_without_ironic = [] - for hyper in hypers: - details = (self.client.show_hypervisor(hyper['id']) - ['hypervisor']) - if details['hypervisor_type'] != 'ironic': - hypers_without_ironic.append(hyper) - ironic_only = False - - if ironic_only: - raise self.skipException( - "Ironic does not support hypervisor uptime") - - has_valid_uptime = False - for hyper in hypers_without_ironic: - # because hypervisors might be disabled, this loops looking - # for any good hit. - try: - uptime = (self.client.show_hypervisor_uptime(hyper['id']) - ['hypervisor']) - if uptime: - has_valid_uptime = True - break - except Exception: - pass - self.assertTrue( - has_valid_uptime, - "None of the hypervisors had a valid uptime: %s" % hypers) - - @decorators.idempotent_id('d7e1805b-3b14-4a3b-b6fd-50ec6d9f361f') - def test_search_hypervisor(self): - hypers = self._list_hypervisors() - self.assertHypervisors(hypers) - hypers = self.client.search_hypervisor( - hypers[0]['hypervisor_hostname'])['hypervisors'] - self.assertHypervisors(hypers) diff --git a/tempest/api/compute/admin/test_hypervisor_negative.py b/tempest/api/compute/admin/test_hypervisor_negative.py deleted file mode 100644 index 431e823bb..000000000 --- a/tempest/api/compute/admin/test_hypervisor_negative.py +++ /dev/null @@ -1,139 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD. -# 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 tempest.api.compute import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class HypervisorAdminNegativeTestJSON(base.BaseV2ComputeAdminTest): - """Tests Hypervisors API that require admin privileges""" - - @classmethod - def setup_clients(cls): - super(HypervisorAdminNegativeTestJSON, cls).setup_clients() - cls.client = cls.os_admin.hypervisor_client - cls.non_adm_client = cls.hypervisor_client - - def _list_hypervisors(self): - # List of hypervisors - hypers = self.client.list_hypervisors()['hypervisors'] - return hypers - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('c136086a-0f67-4b2b-bc61-8482bd68989f') - def test_show_nonexistent_hypervisor(self): - nonexistent_hypervisor_id = data_utils.rand_uuid() - - self.assertRaises( - lib_exc.NotFound, - self.client.show_hypervisor, - nonexistent_hypervisor_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('51e663d0-6b89-4817-a465-20aca0667d03') - def test_show_hypervisor_with_non_admin_user(self): - hypers = self._list_hypervisors() - self.assertNotEmpty(hypers) - - self.assertRaises( - lib_exc.Forbidden, - self.non_adm_client.show_hypervisor, - hypers[0]['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('2a0a3938-832e-4859-95bf-1c57c236b924') - def test_show_servers_with_non_admin_user(self): - hypers = self._list_hypervisors() - self.assertNotEmpty(hypers) - - self.assertRaises( - lib_exc.Forbidden, - self.non_adm_client.list_servers_on_hypervisor, - hypers[0]['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('02463d69-0ace-4d33-a4a8-93d7883a2bba') - def test_show_servers_with_nonexistent_hypervisor(self): - nonexistent_hypervisor_id = data_utils.rand_uuid() - - self.assertRaises( - lib_exc.NotFound, - self.client.list_servers_on_hypervisor, - nonexistent_hypervisor_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e2b061bb-13f9-40d8-9d6e-d5bf17595849') - def test_get_hypervisor_stats_with_non_admin_user(self): - self.assertRaises( - lib_exc.Forbidden, - self.non_adm_client.show_hypervisor_statistics) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f60aa680-9a3a-4c7d-90e1-fae3a4891303') - def test_get_nonexistent_hypervisor_uptime(self): - nonexistent_hypervisor_id = data_utils.rand_uuid() - - self.assertRaises( - lib_exc.NotFound, - self.client.show_hypervisor_uptime, - nonexistent_hypervisor_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6c3461f9-c04c-4e2a-bebb-71dc9cb47df2') - def test_get_hypervisor_uptime_with_non_admin_user(self): - hypers = self._list_hypervisors() - self.assertNotEmpty(hypers) - - self.assertRaises( - lib_exc.Forbidden, - self.non_adm_client.show_hypervisor_uptime, - hypers[0]['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('51b3d536-9b14-409c-9bce-c6f7c794994e') - def test_get_hypervisor_list_with_non_admin_user(self): - # List of hypervisor and available services with non admin user - self.assertRaises( - lib_exc.Forbidden, - self.non_adm_client.list_hypervisors) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('dc02db05-e801-4c5f-bc8e-d915290ab345') - def test_get_hypervisor_list_details_with_non_admin_user(self): - # List of hypervisor details and available services with non admin user - self.assertRaises( - lib_exc.Forbidden, - self.non_adm_client.list_hypervisors, detail=True) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('19a45cc1-1000-4055-b6d2-28e8b2ec4faa') - def test_search_nonexistent_hypervisor(self): - self.assertRaises( - lib_exc.NotFound, - self.client.search_hypervisor, - 'nonexistent_hypervisor_name') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5b6a6c79-5dc1-4fa5-9c58-9c8085948e74') - def test_search_hypervisor_with_non_admin_user(self): - hypers = self._list_hypervisors() - self.assertNotEmpty(hypers) - - self.assertRaises( - lib_exc.Forbidden, - self.non_adm_client.search_hypervisor, - hypers[0]['hypervisor_hostname']) diff --git a/tempest/api/compute/admin/test_instance_usage_audit_log.py b/tempest/api/compute/admin/test_instance_usage_audit_log.py deleted file mode 100644 index e4a2ffdd2..000000000 --- a/tempest/api/compute/admin/test_instance_usage_audit_log.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2013 IBM Corporation -# 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 datetime - -from six.moves.urllib import parse as urllib - -from tempest.api.compute import base -from tempest.lib import decorators - - -class InstanceUsageAuditLogTestJSON(base.BaseV2ComputeAdminTest): - - @classmethod - def setup_clients(cls): - super(InstanceUsageAuditLogTestJSON, cls).setup_clients() - cls.adm_client = cls.os_admin.instance_usages_audit_log_client - - @decorators.idempotent_id('25319919-33d9-424f-9f99-2c203ee48b9d') - def test_list_instance_usage_audit_logs(self): - # list instance usage audit logs - body = (self.adm_client.list_instance_usage_audit_logs() - ["instance_usage_audit_logs"]) - expected_items = ['total_errors', 'total_instances', 'log', - 'num_hosts_running', 'num_hosts_done', - 'num_hosts', 'hosts_not_run', 'overall_status', - 'period_ending', 'period_beginning', - 'num_hosts_not_run'] - for item in expected_items: - self.assertIn(item, body) - - @decorators.idempotent_id('6e40459d-7c5f-400b-9e83-449fbc8e7feb') - def test_get_instance_usage_audit_log(self): - # Get instance usage audit log before specified time - now = datetime.datetime.now() - body = (self.adm_client.show_instance_usage_audit_log( - urllib.quote(now.strftime("%Y-%m-%d %H:%M:%S"))) - ["instance_usage_audit_log"]) - - expected_items = ['total_errors', 'total_instances', 'log', - 'num_hosts_running', 'num_hosts_done', 'num_hosts', - 'hosts_not_run', 'overall_status', 'period_ending', - 'period_beginning', 'num_hosts_not_run'] - for item in expected_items: - self.assertIn(item, body) diff --git a/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py b/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py deleted file mode 100644 index de8e221a5..000000000 --- a/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2013 IBM Corporation -# 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 datetime - -from six.moves.urllib import parse as urllib - -from tempest.api.compute import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class InstanceUsageAuditLogNegativeTestJSON(base.BaseV2ComputeAdminTest): - - @classmethod - def setup_clients(cls): - super(InstanceUsageAuditLogNegativeTestJSON, cls).setup_clients() - cls.adm_client = cls.os_admin.instance_usages_audit_log_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a9d33178-d2c9-4131-ad3b-f4ca8d0308a2') - def test_instance_usage_audit_logs_with_nonadmin_user(self): - # the instance_usage_audit_logs API just can be accessed by admin user - self.assertRaises(lib_exc.Forbidden, - self.instance_usages_audit_log_client. - list_instance_usage_audit_logs) - now = datetime.datetime.now() - self.assertRaises(lib_exc.Forbidden, - self.instance_usages_audit_log_client. - show_instance_usage_audit_log, - urllib.quote(now.strftime("%Y-%m-%d %H:%M:%S"))) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9b952047-3641-41c7-ba91-a809fc5974c8') - def test_get_instance_usage_audit_logs_with_invalid_time(self): - self.assertRaises(lib_exc.BadRequest, - self.adm_client.show_instance_usage_audit_log, - "invalid_time") diff --git a/tempest/api/compute/admin/test_keypairs_v210.py b/tempest/api/compute/admin/test_keypairs_v210.py deleted file mode 100644 index e24c7c100..000000000 --- a/tempest/api/compute/admin/test_keypairs_v210.py +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright 2016 NEC Corporation. -# 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 tempest.api.compute.keypairs import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class KeyPairsV210TestJSON(base.BaseKeypairTest): - credentials = ['primary', 'admin'] - min_microversion = '2.10' - - @classmethod - def setup_clients(cls): - super(KeyPairsV210TestJSON, cls).setup_clients() - cls.client = cls.os_admin.keypairs_client - cls.non_admin_client = cls.os_primary.keypairs_client - - def _create_and_check_keypairs(self, user_id): - key_list = list() - for _ in range(2): - k_name = data_utils.rand_name('keypair') - keypair = self.create_keypair(k_name, - keypair_type='ssh', - user_id=user_id) - self.assertEqual(k_name, keypair['name'], - "The created keypair name is not equal " - "to the requested name!") - self.assertEqual(user_id, keypair['user_id'], - "The created keypair is not for requested user!") - keypair.pop('private_key', None) - keypair.pop('user_id') - key_list.append(keypair) - return key_list - - @decorators.idempotent_id('3c8484af-cfb3-48f6-b8ba-d5d58bbf3eac') - def test_admin_manage_keypairs_for_other_users(self): - user_id = self.non_admin_client.user_id - key_list = self._create_and_check_keypairs(user_id) - first_keyname = key_list[0]['name'] - keypair_detail = self.client.show_keypair(first_keyname, - user_id=user_id)['keypair'] - self.assertEqual(first_keyname, keypair_detail['name']) - self.assertEqual(user_id, keypair_detail['user_id'], - "The fetched keypair is not for requested user!") - # Create a admin keypair - admin_keypair = self.create_keypair(keypair_type='ssh') - admin_keypair.pop('private_key', None) - admin_keypair.pop('user_id') - - # Admin fetch keypairs list of non admin user - keypairs = self.client.list_keypairs(user_id=user_id)['keypairs'] - fetched_list = [keypair['keypair'] for keypair in keypairs] - - # Check admin keypair is not present in non admin user keypairs list - self.assertNotIn(admin_keypair, fetched_list, - "The fetched user keypairs has admin keypair!") - - # Now check if all the created keypairs are in the fetched list - missing_kps = [kp for kp in key_list if kp not in fetched_list] - self.assertFalse(missing_kps, - "Failed to find keypairs %s in fetched list" - % ', '.join(m_key['name'] for m_key in missing_kps)) diff --git a/tempest/api/compute/admin/test_live_migration.py b/tempest/api/compute/admin/test_live_migration.py deleted file mode 100644 index 3f1bdce00..000000000 --- a/tempest/api/compute/admin/test_live_migration.py +++ /dev/null @@ -1,235 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 time - -from oslo_log import log as logging -import testtools - -from tempest.api.compute import base -from tempest.common import compute -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF -LOG = logging.getLogger(__name__) - - -class LiveMigrationTest(base.BaseV2ComputeAdminTest): - max_microversion = '2.24' - block_migration = None - - @classmethod - def skip_checks(cls): - super(LiveMigrationTest, cls).skip_checks() - - if not CONF.compute_feature_enabled.live_migration: - skip_msg = ("%s skipped as live-migration is " - "not available" % cls.__name__) - raise cls.skipException(skip_msg) - if CONF.compute.min_compute_nodes < 2: - raise cls.skipException( - "Less than 2 compute nodes, skipping migration test.") - - @classmethod - def setup_clients(cls): - super(LiveMigrationTest, cls).setup_clients() - cls.admin_migration_client = cls.os_admin.migrations_client - - def _migrate_server_to(self, server_id, dest_host, volume_backed=False): - kwargs = dict() - block_migration = getattr(self, 'block_migration', None) - if self.block_migration is None: - kwargs['disk_over_commit'] = False - block_migration = (CONF.compute_feature_enabled. - block_migration_for_live_migration and - not volume_backed) - self.admin_servers_client.live_migrate_server( - server_id, host=dest_host, block_migration=block_migration, - **kwargs) - - def _live_migrate(self, server_id, target_host, state, - volume_backed=False): - self._migrate_server_to(server_id, target_host, volume_backed) - waiters.wait_for_server_status(self.servers_client, server_id, state) - migration_list = (self.admin_migration_client.list_migrations() - ['migrations']) - - msg = ("Live Migration failed. Migrations list for Instance " - "%s: [" % server_id) - for live_migration in migration_list: - if (live_migration['instance_uuid'] == server_id): - msg += "\n%s" % live_migration - msg += "]" - self.assertEqual(target_host, self.get_host_for_server(server_id), - msg) - - def _test_live_migration(self, state='ACTIVE', volume_backed=False): - """Tests live migration between two hosts. - - Requires CONF.compute_feature_enabled.live_migration to be True. - - :param state: The vm_state the migrated server should be in before and - after the live migration. Supported values are 'ACTIVE' - and 'PAUSED'. - :param volume_backed: If the instance is volume backed or not. If - volume_backed, *block* migration is not used. - """ - # Live migrate an instance to another host - server_id = self.create_test_server(wait_until="ACTIVE", - volume_backed=volume_backed)['id'] - source_host = self.get_host_for_server(server_id) - destination_host = self.get_host_other_than(server_id) - - if state == 'PAUSED': - self.admin_servers_client.pause_server(server_id) - waiters.wait_for_server_status(self.admin_servers_client, - server_id, state) - - LOG.info("Live migrate from source %s to destination %s", - source_host, destination_host) - self._live_migrate(server_id, destination_host, state, volume_backed) - if CONF.compute_feature_enabled.live_migrate_back_and_forth: - # If live_migrate_back_and_forth is enabled it is a grenade job. - # Therefore test should validate whether LM is compatible in both - # ways, so live migrate VM back to the source host - LOG.info("Live migrate back to source %s", source_host) - self._live_migrate(server_id, source_host, state, volume_backed) - - @decorators.idempotent_id('1dce86b8-eb04-4c03-a9d8-9c1dc3ee0c7b') - def test_live_block_migration(self): - self._test_live_migration() - - @decorators.idempotent_id('1e107f21-61b2-4988-8f22-b196e938ab88') - @testtools.skipUnless(CONF.compute_feature_enabled.pause, - 'Pause is not available.') - def test_live_block_migration_paused(self): - self._test_live_migration(state='PAUSED') - - @decorators.skip_because(bug="1524898") - @decorators.idempotent_id('5071cf17-3004-4257-ae61-73a84e28badd') - @test.services('volume') - def test_volume_backed_live_migration(self): - self._test_live_migration(volume_backed=True) - - @decorators.idempotent_id('e19c0cc6-6720-4ed8-be83-b6603ed5c812') - @testtools.skipIf(not CONF.compute_feature_enabled. - block_migration_for_live_migration, - 'Block Live migration not available') - @testtools.skipIf(not CONF.compute_feature_enabled. - block_migrate_cinder_iscsi, - 'Block Live migration not configured for iSCSI') - def test_iscsi_volume(self): - server = self.create_test_server(wait_until="ACTIVE") - server_id = server['id'] - target_host = self.get_host_other_than(server_id) - - volume = self.create_volume() - - # Attach the volume to the server - self.attach_volume(server, volume, device='/dev/xvdb') - server = self.admin_servers_client.show_server(server_id)['server'] - volume_id1 = server["os-extended-volumes:volumes_attached"][0]["id"] - self._migrate_server_to(server_id, target_host) - waiters.wait_for_server_status(self.servers_client, - server_id, 'ACTIVE') - - server = self.admin_servers_client.show_server(server_id)['server'] - volume_id2 = server["os-extended-volumes:volumes_attached"][0]["id"] - - self.assertEqual(target_host, self.get_host_for_server(server_id)) - self.assertEqual(volume_id1, volume_id2) - - -class LiveMigrationRemoteConsolesV26Test(LiveMigrationTest): - min_microversion = '2.6' - max_microversion = 'latest' - - @decorators.idempotent_id('6190af80-513e-4f0f-90f2-9714e84955d7') - @testtools.skipUnless(CONF.compute_feature_enabled.serial_console, - 'Serial console not supported.') - @testtools.skipUnless( - test.is_scheduler_filter_enabled("DifferentHostFilter"), - 'DifferentHostFilter is not available.') - def test_live_migration_serial_console(self): - """Test the live-migration of an instance which has a serial console - - The serial console feature of an instance uses ports on the host. - These ports need to be updated when they are already in use by - another instance on the target host. This test checks if this - update behavior is correctly done, by connecting to the serial - consoles of the instances before and after the live migration. - """ - server01_id = self.create_test_server(wait_until='ACTIVE')['id'] - hints = {'different_host': server01_id} - server02_id = self.create_test_server(scheduler_hints=hints, - wait_until='ACTIVE')['id'] - host01_id = self.get_host_for_server(server01_id) - host02_id = self.get_host_for_server(server02_id) - self.assertNotEqual(host01_id, host02_id) - - # At this step we have 2 instances on different hosts, both with - # serial consoles, both with port 10000 (the default value). - # https://bugs.launchpad.net/nova/+bug/1455252 describes the issue - # when live-migrating in such a scenario. - - self._verify_console_interaction(server01_id) - self._verify_console_interaction(server02_id) - - self._migrate_server_to(server01_id, host02_id) - waiters.wait_for_server_status(self.servers_client, - server01_id, 'ACTIVE') - self.assertEqual(host02_id, self.get_host_for_server(server01_id)) - self._verify_console_interaction(server01_id) - # At this point, both instances have a valid serial console - # connection, which means the ports got updated. - - def _verify_console_interaction(self, server_id): - body = self.servers_client.get_remote_console(server_id, - console_type='serial', - protocol='serial') - console_url = body['remote_console']['url'] - data = "test_live_migration_serial_console" - console_output = '' - t = 0.0 - interval = 0.1 - - ws = compute.create_websocket(console_url) - try: - # NOTE (markus_z): It can take a long time until the terminal - # of the instance is available for interaction. Hence the - # long timeout value. - while data not in console_output and t <= 120.0: - try: - ws.send_frame(data) - recieved = ws.receive_frame() - console_output += recieved - except Exception: - # In case we had an issue with send/receive on the - # websocket connection, we create a new one. - ws = compute.create_websocket(console_url) - time.sleep(interval) - t += interval - finally: - ws.close() - self.assertIn(data, console_output) - - -class LiveAutoBlockMigrationV225Test(LiveMigrationTest): - min_microversion = '2.25' - max_microversion = 'latest' - block_migration = 'auto' diff --git a/tempest/api/compute/admin/test_live_migration_negative.py b/tempest/api/compute/admin/test_live_migration_negative.py deleted file mode 100644 index deabbc2d3..000000000 --- a/tempest/api/compute/admin/test_live_migration_negative.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class LiveMigrationNegativeTest(base.BaseV2ComputeAdminTest): - @classmethod - def skip_checks(cls): - super(LiveMigrationNegativeTest, cls).skip_checks() - if not CONF.compute_feature_enabled.live_migration: - raise cls.skipException("Live migration is not enabled") - - def _migrate_server_to(self, server_id, dest_host): - bmflm = CONF.compute_feature_enabled.block_migration_for_live_migration - self.admin_servers_client.live_migrate_server( - server_id, host=dest_host, block_migration=bmflm, - disk_over_commit=False) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7fb7856e-ae92-44c9-861a-af62d7830bcb') - def test_invalid_host_for_migration(self): - # Migrating to an invalid host should not change the status - target_host = data_utils.rand_name('host') - server = self.create_test_server(wait_until="ACTIVE") - - self.assertRaises(lib_exc.BadRequest, self._migrate_server_to, - server['id'], target_host) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'ACTIVE') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6e2f94f5-2ee8-4830-bef5-5bc95bb0795b') - def test_live_block_migration_suspended(self): - server = self.create_test_server(wait_until="ACTIVE") - - self.admin_servers_client.suspend_server(server['id']) - waiters.wait_for_server_status(self.servers_client, - server['id'], 'SUSPENDED') - - destination_host = self.get_host_other_than(server['id']) - - self.assertRaises(lib_exc.Conflict, self._migrate_server_to, - server['id'], destination_host) diff --git a/tempest/api/compute/admin/test_migrations.py b/tempest/api/compute/admin/test_migrations.py deleted file mode 100644 index a626ebb71..000000000 --- a/tempest/api/compute/admin/test_migrations.py +++ /dev/null @@ -1,138 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 testtools - -from tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions - -CONF = config.CONF - - -class MigrationsAdminTest(base.BaseV2ComputeAdminTest): - - @classmethod - def setup_clients(cls): - super(MigrationsAdminTest, cls).setup_clients() - cls.client = cls.os_admin.migrations_client - - @decorators.idempotent_id('75c0b83d-72a0-4cf8-a153-631e83e7d53f') - def test_list_migrations(self): - # Admin can get the migrations list - self.client.list_migrations() - - @decorators.idempotent_id('1b512062-8093-438e-b47a-37d2f597cd64') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize not available.') - def test_list_migrations_in_flavor_resize_situation(self): - # Admin can get the migrations list which contains the resized server - server = self.create_test_server(wait_until="ACTIVE") - server_id = server['id'] - - self.resize_server(server_id, self.flavor_ref_alt) - - body = self.client.list_migrations()['migrations'] - - instance_uuids = [x['instance_uuid'] for x in body] - self.assertIn(server_id, instance_uuids) - - def _flavor_clean_up(self, flavor_id): - try: - self.admin_flavors_client.delete_flavor(flavor_id) - self.admin_flavors_client.wait_for_resource_deletion(flavor_id) - except exceptions.NotFound: - pass - - @decorators.idempotent_id('33f1fec3-ba18-4470-8e4e-1d888e7c3593') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize not available.') - def test_resize_server_revert_deleted_flavor(self): - # Tests that we can revert the resize on an instance whose original - # flavor has been deleted. - - # First we have to create a flavor that we can delete so make a copy - # of the normal flavor from which we'd create a server. - flavor = self.admin_flavors_client.show_flavor( - self.flavor_ref)['flavor'] - flavor = self.admin_flavors_client.create_flavor( - name=data_utils.rand_name('test_resize_flavor_'), - ram=flavor['ram'], - disk=flavor['disk'], - vcpus=flavor['vcpus'] - )['flavor'] - self.addCleanup(self._flavor_clean_up, flavor['id']) - - # Now boot a server with the copied flavor. - server = self.create_test_server( - wait_until='ACTIVE', flavor=flavor['id']) - - # Delete the flavor we used to boot the instance. - self._flavor_clean_up(flavor['id']) - - # Now resize the server and wait for it to go into verify state. - self.servers_client.resize_server(server['id'], self.flavor_ref_alt) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'VERIFY_RESIZE') - - # Now revert the resize, it should be OK even though the original - # flavor used to boot the server was deleted. - self.servers_client.revert_resize_server(server['id']) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'ACTIVE') - - server = self.servers_client.show_server(server['id'])['server'] - self.assertEqual(flavor['id'], server['flavor']['id']) - - def _test_cold_migrate_server(self, revert=False): - if CONF.compute.min_compute_nodes < 2: - msg = "Less than 2 compute nodes, skipping multinode tests." - raise self.skipException(msg) - - server = self.create_test_server(wait_until="ACTIVE") - src_host = self.admin_servers_client.show_server( - server['id'])['server']['OS-EXT-SRV-ATTR:host'] - - self.admin_servers_client.migrate_server(server['id']) - - waiters.wait_for_server_status(self.servers_client, - server['id'], 'VERIFY_RESIZE') - - if revert: - self.servers_client.revert_resize_server(server['id']) - assert_func = self.assertEqual - else: - self.servers_client.confirm_resize_server(server['id']) - assert_func = self.assertNotEqual - - waiters.wait_for_server_status(self.servers_client, - server['id'], 'ACTIVE') - dst_host = self.admin_servers_client.show_server( - server['id'])['server']['OS-EXT-SRV-ATTR:host'] - assert_func(src_host, dst_host) - - @decorators.idempotent_id('4bf0be52-3b6f-4746-9a27-3143636fe30d') - @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration, - 'Cold migration not available.') - def test_cold_migration(self): - self._test_cold_migrate_server(revert=False) - - @decorators.idempotent_id('caa1aa8b-f4ef-4374-be0d-95f001c2ac2d') - @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration, - 'Cold migration not available.') - def test_revert_cold_migration(self): - self._test_cold_migrate_server(revert=True) diff --git a/tempest/api/compute/admin/test_networks.py b/tempest/api/compute/admin/test_networks.py deleted file mode 100644 index acb0d90d5..000000000 --- a/tempest/api/compute/admin/test_networks.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P. -# 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 tempest.api.compute import base -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class NetworksTest(base.BaseV2ComputeAdminTest): - """Tests Nova Networks API that usually requires admin privileges. - - API docs: - http://developer.openstack.org/api-ref-compute-v2-ext.html#ext-os-networks - """ - - @classmethod - def setup_clients(cls): - super(NetworksTest, cls).setup_clients() - cls.client = cls.os_admin.compute_networks_client - - @decorators.idempotent_id('d206d211-8912-486f-86e2-a9d090d1f416') - def test_get_network(self): - networks = self.client.list_networks()['networks'] - if CONF.compute.fixed_network_name: - configured_network = [x for x in networks if x['label'] == - CONF.compute.fixed_network_name] - self.assertEqual(1, len(configured_network), - "{0} networks with label {1}".format( - len(configured_network), - CONF.compute.fixed_network_name)) - elif CONF.network.public_network_id: - configured_network = [x for x in networks if x['id'] == - CONF.network.public_network_id] - else: - raise self.skipException( - "Environment has no known-for-sure existing network.") - configured_network = configured_network[0] - network = (self.client.show_network(configured_network['id']) - ['network']) - self.assertEqual(configured_network['label'], network['label']) - - @decorators.idempotent_id('df3d1046-6fa5-4b2c-ad0c-cfa46a351cb9') - def test_list_all_networks(self): - networks = self.client.list_networks()['networks'] - # Check the configured network is in the list - if CONF.compute.fixed_network_name: - configured_network = CONF.compute.fixed_network_name - self.assertIn(configured_network, [x['label'] for x in networks]) - else: - network_labels = [x['label'] for x in networks] - self.assertNotEmpty(network_labels) diff --git a/tempest/api/compute/admin/test_quotas.py b/tempest/api/compute/admin/test_quotas.py deleted file mode 100644 index 937540e2a..000000000 --- a/tempest/api/compute/admin/test_quotas.py +++ /dev/null @@ -1,187 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_log import log as logging -from testtools import matchers - -from tempest.api.compute import base -from tempest.common import tempest_fixtures as fixtures -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -LOG = logging.getLogger(__name__) - - -class QuotasAdminTestJSON(base.BaseV2ComputeAdminTest): - force_tenant_isolation = True - - def setUp(self): - # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests. - self.useFixture(fixtures.LockFixture('compute_quotas')) - super(QuotasAdminTestJSON, self).setUp() - - @classmethod - def setup_clients(cls): - super(QuotasAdminTestJSON, cls).setup_clients() - cls.adm_client = cls.os_admin.quotas_client - - @classmethod - def resource_setup(cls): - super(QuotasAdminTestJSON, cls).resource_setup() - - # NOTE(afazekas): these test cases should always create and use a new - # tenant most of them should be skipped if we can't do that - cls.demo_tenant_id = cls.quotas_client.tenant_id - - cls.default_quota_set = set(('injected_file_content_bytes', - 'metadata_items', 'injected_files', - 'ram', 'floating_ips', - 'fixed_ips', 'key_pairs', - 'injected_file_path_bytes', - 'instances', 'security_group_rules', - 'cores', 'security_groups')) - - @decorators.idempotent_id('3b0a7c8f-cf58-46b8-a60c-715a32a8ba7d') - def test_get_default_quotas(self): - # Admin can get the default resource quota set for a tenant - expected_quota_set = self.default_quota_set | set(['id']) - quota_set = self.adm_client.show_default_quota_set( - self.demo_tenant_id)['quota_set'] - self.assertEqual(quota_set['id'], self.demo_tenant_id) - for quota in expected_quota_set: - self.assertIn(quota, quota_set.keys()) - - @decorators.idempotent_id('55fbe2bf-21a9-435b-bbd2-4162b0ed799a') - def test_update_all_quota_resources_for_tenant(self): - # Admin can update all the resource quota limits for a tenant - default_quota_set = self.adm_client.show_default_quota_set( - self.demo_tenant_id)['quota_set'] - new_quota_set = {'injected_file_content_bytes': 20480, - 'metadata_items': 256, 'injected_files': 10, - 'ram': 10240, 'floating_ips': 20, 'fixed_ips': 10, - 'key_pairs': 200, 'injected_file_path_bytes': 512, - 'instances': 20, 'security_group_rules': 20, - 'cores': 2, 'security_groups': 20, - 'server_groups': 20, 'server_group_members': 20} - # Update limits for all quota resources - quota_set = self.adm_client.update_quota_set( - self.demo_tenant_id, - force=True, - **new_quota_set)['quota_set'] - - default_quota_set.pop('id') - self.addCleanup(self.adm_client.update_quota_set, - self.demo_tenant_id, **default_quota_set) - for quota in new_quota_set: - self.assertIn(quota, quota_set.keys()) - - # TODO(afazekas): merge these test cases - @decorators.idempotent_id('ce9e0815-8091-4abd-8345-7fe5b85faa1d') - def test_get_updated_quotas(self): - # Verify that GET shows the updated quota set of project - project_name = data_utils.rand_name('cpu_quota_project') - project_desc = project_name + '-desc' - project = self.identity_utils.create_project(name=project_name, - description=project_desc) - project_id = project['id'] - self.addCleanup(self.identity_utils.delete_project, project_id) - - self.adm_client.update_quota_set(project_id, ram='5120') - quota_set = self.adm_client.show_quota_set(project_id)['quota_set'] - self.assertEqual(5120, quota_set['ram']) - - # Verify that GET shows the updated quota set of user - user_name = data_utils.rand_name('cpu_quota_user') - password = data_utils.rand_password() - email = user_name + '@testmail.tm' - user = self.identity_utils.create_user(username=user_name, - password=password, - project=project, - email=email) - user_id = user['id'] - self.addCleanup(self.identity_utils.delete_user, user_id) - - self.adm_client.update_quota_set(project_id, - user_id=user_id, - ram='2048') - quota_set = self.adm_client.show_quota_set( - project_id, user_id=user_id)['quota_set'] - self.assertEqual(2048, quota_set['ram']) - - @decorators.idempotent_id('389d04f0-3a41-405f-9317-e5f86e3c44f0') - def test_delete_quota(self): - # Admin can delete the resource quota set for a project - project_name = data_utils.rand_name('ram_quota_project') - project_desc = project_name + '-desc' - project = self.identity_utils.create_project(name=project_name, - description=project_desc) - project_id = project['id'] - self.addCleanup(self.identity_utils.delete_project, project_id) - quota_set_default = (self.adm_client.show_quota_set(project_id) - ['quota_set']) - ram_default = quota_set_default['ram'] - - self.adm_client.update_quota_set(project_id, ram='5120') - - self.adm_client.delete_quota_set(project_id) - - quota_set_new = self.adm_client.show_quota_set(project_id)['quota_set'] - self.assertEqual(ram_default, quota_set_new['ram']) - - -class QuotaClassesAdminTestJSON(base.BaseV2ComputeAdminTest): - """Tests the os-quota-class-sets API to update default quotas.""" - - def setUp(self): - # All test cases in this class need to externally lock on doing - # anything with default quota values. - self.useFixture(fixtures.LockFixture('compute_quotas')) - super(QuotaClassesAdminTestJSON, self).setUp() - - @classmethod - def resource_setup(cls): - super(QuotaClassesAdminTestJSON, cls).resource_setup() - cls.adm_client = cls.os_admin.quota_classes_client - - def _restore_default_quotas(self, original_defaults): - LOG.debug("restoring quota class defaults") - self.adm_client.update_quota_class_set( - 'default', **original_defaults)['quota_class_set'] - - # NOTE(sdague): this test is problematic as it changes - # global state, and possibly needs to be part of a set of - # tests that get run all by themselves at the end under a - # 'danger' flag. - @decorators.idempotent_id('7932ab0f-5136-4075-b201-c0e2338df51a') - def test_update_default_quotas(self): - LOG.debug("get the current 'default' quota class values") - body = (self.adm_client.show_quota_class_set('default') - ['quota_class_set']) - self.assertIn('id', body) - self.assertEqual('default', body.pop('id')) - # restore the defaults when the test is done - self.addCleanup(self._restore_default_quotas, body.copy()) - # increment all of the values for updating the default quota class - for quota, default in body.items(): - # NOTE(sdague): we need to increment a lot, otherwise - # there is a real chance that we go from -1 (unlimited) - # to a very small number which causes issues. - body[quota] = default + 100 - LOG.debug("update limits for the default quota class set") - update_body = self.adm_client.update_quota_class_set( - 'default', **body)['quota_class_set'] - LOG.debug("assert that the response has all of the changed values") - self.assertThat(update_body.items(), - matchers.ContainsAll(body.items())) diff --git a/tempest/api/compute/admin/test_quotas_negative.py b/tempest/api/compute/admin/test_quotas_negative.py deleted file mode 100644 index 747f32032..000000000 --- a/tempest/api/compute/admin/test_quotas_negative.py +++ /dev/null @@ -1,133 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 tempest.api.compute import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class QuotasAdminNegativeTestJSON(base.BaseV2ComputeAdminTest): - force_tenant_isolation = True - - @classmethod - def setup_clients(cls): - super(QuotasAdminNegativeTestJSON, cls).setup_clients() - cls.client = cls.os_primary.quotas_client - cls.adm_client = cls.os_admin.quotas_client - cls.sg_client = cls.security_groups_client - cls.sgr_client = cls.security_group_rules_client - - @classmethod - def resource_setup(cls): - super(QuotasAdminNegativeTestJSON, cls).resource_setup() - # NOTE(afazekas): these test cases should always create and use a new - # tenant most of them should be skipped if we can't do that - cls.demo_tenant_id = cls.client.tenant_id - - def _update_quota(self, quota_item, quota_value): - quota_set = (self.adm_client.show_quota_set(self.demo_tenant_id) - ['quota_set']) - default_quota_value = quota_set[quota_item] - - self.adm_client.update_quota_set(self.demo_tenant_id, - force=True, - **{quota_item: quota_value}) - self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id, - **{quota_item: default_quota_value}) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('733abfe8-166e-47bb-8363-23dbd7ff3476') - def test_update_quota_normal_user(self): - self.assertRaises(lib_exc.Forbidden, - self.client.update_quota_set, - self.demo_tenant_id, - ram=0) - - # TODO(afazekas): Add dedicated tenant to the skipped quota tests. - # It can be moved into the setUpClass as well. - @decorators.attr(type=['negative']) - @decorators.idempotent_id('91058876-9947-4807-9f22-f6eb17140d9b') - def test_create_server_when_cpu_quota_is_full(self): - # Disallow server creation when tenant's vcpu quota is full - self._update_quota('cores', 0) - self.assertRaises((lib_exc.Forbidden, lib_exc.OverLimit), - self.create_test_server) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6fdd7012-584d-4327-a61c-49122e0d5864') - def test_create_server_when_memory_quota_is_full(self): - # Disallow server creation when tenant's memory quota is full - self._update_quota('ram', 0) - self.assertRaises((lib_exc.Forbidden, lib_exc.OverLimit), - self.create_test_server) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7c6be468-0274-449a-81c3-ac1c32ee0161') - def test_create_server_when_instances_quota_is_full(self): - # Once instances quota limit is reached, disallow server creation - self._update_quota('instances', 0) - self.assertRaises((lib_exc.Forbidden, lib_exc.OverLimit), - self.create_test_server) - - @decorators.skip_because(bug="1186354", - condition=CONF.service_available.neutron) - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7c6c8f3b-2bf6-4918-b240-57b136a66aa0') - @test.services('network') - def test_security_groups_exceed_limit(self): - # Negative test: Creation Security Groups over limit should FAIL - # Set the quota to number of used security groups - sg_quota = self.limits_client.show_limits()['limits']['absolute'][ - 'totalSecurityGroupsUsed'] - self._update_quota('security_groups', sg_quota) - - # Check we cannot create anymore - # A 403 Forbidden or 413 Overlimit (old behaviour) exception - # will be raised when out of quota - self.assertRaises((lib_exc.Forbidden, lib_exc.OverLimit), - self.sg_client.create_security_group, - name="sg-overlimit", description="sg-desc") - - @decorators.skip_because(bug="1186354", - condition=CONF.service_available.neutron) - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6e9f436d-f1ed-4f8e-a493-7275dfaa4b4d') - @test.services('network') - def test_security_groups_rules_exceed_limit(self): - # Negative test: Creation of Security Group Rules should FAIL - # when we reach limit maxSecurityGroupRules - self._update_quota('security_group_rules', 0) - - s_name = data_utils.rand_name('securitygroup') - s_description = data_utils.rand_name('description') - securitygroup = self.sg_client.create_security_group( - name=s_name, description=s_description)['security_group'] - self.addCleanup(self.sg_client.delete_security_group, - securitygroup['id']) - - secgroup_id = securitygroup['id'] - ip_protocol = 'tcp' - - # Check we cannot create SG rule anymore - # A 403 Forbidden or 413 Overlimit (old behaviour) exception - # will be raised when out of quota - self.assertRaises((lib_exc.OverLimit, lib_exc.Forbidden), - self.sgr_client.create_security_group_rule, - parent_group_id=secgroup_id, ip_protocol=ip_protocol, - from_port=1025, to_port=1025) diff --git a/tempest/api/compute/admin/test_security_group_default_rules.py b/tempest/api/compute/admin/test_security_group_default_rules.py deleted file mode 100644 index f2f3b573e..000000000 --- a/tempest/api/compute/admin/test_security_group_default_rules.py +++ /dev/null @@ -1,131 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 testtools - -from tempest.api.compute import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class SecurityGroupDefaultRulesTest(base.BaseV2ComputeAdminTest): - - @classmethod - # TODO(GMann): Once Bug# 1311500 is fixed, these test can run - # for Neutron also. - @testtools.skipIf(CONF.service_available.neutron, - "Skip as this functionality is not yet " - "implemented in Neutron. Related Bug#1311500") - def setup_credentials(cls): - # A network and a subnet will be created for these tests - cls.set_network_resources(network=True, subnet=True) - super(SecurityGroupDefaultRulesTest, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(SecurityGroupDefaultRulesTest, cls).setup_clients() - cls.adm_client = cls.os_admin.security_group_default_rules_client - - def _create_security_group_default_rules(self, ip_protocol='tcp', - from_port=22, to_port=22, - cidr='10.10.0.0/24'): - # Create Security Group default rule - rule = self.adm_client.create_security_default_group_rule( - ip_protocol=ip_protocol, - from_port=from_port, - to_port=to_port, - cidr=cidr)['security_group_default_rule'] - self.assertEqual(ip_protocol, rule['ip_protocol']) - self.assertEqual(from_port, rule['from_port']) - self.assertEqual(to_port, rule['to_port']) - self.assertEqual(cidr, rule['ip_range']['cidr']) - return rule - - @decorators.idempotent_id('6d880615-eec3-4d29-97c5-7a074dde239d') - def test_create_delete_security_group_default_rules(self): - # Create and delete Security Group default rule - ip_protocols = ['tcp', 'udp', 'icmp'] - for ip_protocol in ip_protocols: - rule = self._create_security_group_default_rules(ip_protocol) - # Delete Security Group default rule - self.adm_client.delete_security_group_default_rule(rule['id']) - self.assertRaises(lib_exc.NotFound, - self.adm_client.show_security_group_default_rule, - rule['id']) - - @decorators.idempotent_id('4d752e0a-33a1-4c3a-b498-ff8667ca22e5') - def test_create_security_group_default_rule_without_cidr(self): - ip_protocol = 'udp' - from_port = 80 - to_port = 80 - rule = self.adm_client.create_security_default_group_rule( - ip_protocol=ip_protocol, - from_port=from_port, - to_port=to_port)['security_group_default_rule'] - self.addCleanup(self.adm_client.delete_security_group_default_rule, - rule['id']) - self.assertNotEqual(0, rule['id']) - self.assertEqual('0.0.0.0/0', rule['ip_range']['cidr']) - - @decorators.idempotent_id('29f2d218-69b0-4a95-8f3d-6bd0ef732b3a') - def test_create_security_group_default_rule_with_blank_cidr(self): - ip_protocol = 'icmp' - from_port = 10 - to_port = 10 - cidr = '' - rule = self.adm_client.create_security_default_group_rule( - ip_protocol=ip_protocol, - from_port=from_port, - to_port=to_port, - cidr=cidr)['security_group_default_rule'] - self.addCleanup(self.adm_client.delete_security_group_default_rule, - rule['id']) - self.assertNotEqual(0, rule['id']) - self.assertEqual('0.0.0.0/0', rule['ip_range']['cidr']) - - @decorators.idempotent_id('6e6de55e-9146-4ae0-89f2-3569586e0b9b') - def test_security_group_default_rules_list(self): - ip_protocol = 'tcp' - from_port = 22 - to_port = 22 - cidr = '10.10.0.0/24' - rule = self._create_security_group_default_rules(ip_protocol, - from_port, - to_port, - cidr) - self.addCleanup(self.adm_client.delete_security_group_default_rule, - rule['id']) - rules = (self.adm_client.list_security_group_default_rules() - ['security_group_default_rules']) - self.assertNotEmpty(rules) - self.assertIn(rule, rules) - - @decorators.idempotent_id('15cbb349-86b4-4f71-a048-04b7ef3f150b') - def test_default_security_group_default_rule_show(self): - ip_protocol = 'tcp' - from_port = 22 - to_port = 22 - cidr = '10.10.0.0/24' - rule = self._create_security_group_default_rules(ip_protocol, - from_port, - to_port, - cidr) - self.addCleanup(self.adm_client.delete_security_group_default_rule, - rule['id']) - fetched_rule = self.adm_client.show_security_group_default_rule( - rule['id'])['security_group_default_rule'] - self.assertEqual(rule, fetched_rule) diff --git a/tempest/api/compute/admin/test_security_groups.py b/tempest/api/compute/admin/test_security_groups.py deleted file mode 100644 index 8abe03aac..000000000 --- a/tempest/api/compute/admin/test_security_groups.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2013 NTT Data -# 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 tempest.api.compute import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - - -class SecurityGroupsTestAdminJSON(base.BaseV2ComputeAdminTest): - - @classmethod - def setup_clients(cls): - super(SecurityGroupsTestAdminJSON, cls).setup_clients() - cls.adm_client = cls.os_admin.compute_security_groups_client - cls.client = cls.security_groups_client - - def _delete_security_group(self, securitygroup_id, admin=True): - if admin: - self.adm_client.delete_security_group(securitygroup_id) - else: - self.client.delete_security_group(securitygroup_id) - - @decorators.idempotent_id('49667619-5af9-4c63-ab5d-2cfdd1c8f7f1') - @test.services('network') - def test_list_security_groups_list_all_tenants_filter(self): - # Admin can list security groups of all tenants - # List of all security groups created - security_group_list = [] - # Create two security groups for a non-admin tenant - for _ in range(2): - name = data_utils.rand_name('securitygroup') - description = data_utils.rand_name('description') - securitygroup = self.client.create_security_group( - name=name, description=description)['security_group'] - self.addCleanup(self._delete_security_group, - securitygroup['id'], admin=False) - security_group_list.append(securitygroup) - - client_tenant_id = securitygroup['tenant_id'] - # Create two security groups for admin tenant - for _ in range(2): - name = data_utils.rand_name('securitygroup') - description = data_utils.rand_name('description') - adm_securitygroup = self.adm_client.create_security_group( - name=name, description=description)['security_group'] - self.addCleanup(self._delete_security_group, - adm_securitygroup['id']) - security_group_list.append(adm_securitygroup) - - # Fetch all security groups based on 'all_tenants' search filter - fetched_list = self.adm_client.list_security_groups( - all_tenants='true')['security_groups'] - sec_group_id_list = [sg['id'] for sg in fetched_list] - # Now check if all created Security Groups are present in fetched list - for sec_group in security_group_list: - self.assertIn(sec_group['id'], sec_group_id_list) - - # Fetch all security groups for non-admin user with 'all_tenants' - # search filter - fetched_list = (self.client.list_security_groups(all_tenants='true') - ['security_groups']) - # Now check if all created Security Groups are present in fetched list - for sec_group in fetched_list: - self.assertEqual(sec_group['tenant_id'], client_tenant_id, - "Failed to get all security groups for " - "non admin user.") diff --git a/tempest/api/compute/admin/test_server_diagnostics.py b/tempest/api/compute/admin/test_server_diagnostics.py deleted file mode 100644 index 005efddb8..000000000 --- a/tempest/api/compute/admin/test_server_diagnostics.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright 2017 Mirantis Inc. -# -# 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 time - -from tempest.api.compute import base -from tempest.lib import decorators - - -class ServerDiagnosticsTest(base.BaseV2ComputeAdminTest): - min_microversion = None - max_microversion = '2.47' - - @classmethod - def setup_clients(cls): - super(ServerDiagnosticsTest, cls).setup_clients() - cls.client = cls.os_admin.servers_client - - @decorators.idempotent_id('31ff3486-b8a0-4f56-a6c0-aab460531db3') - def test_get_server_diagnostics(self): - server_id = self.create_test_server(wait_until='ACTIVE')['id'] - diagnostics = self.client.show_server_diagnostics(server_id) - - # NOTE(snikitin): Before microversion 2.48 response data from each - # hypervisor (libvirt, xen, vmware) was different. None of the fields - # were equal. As this test is common for libvirt, xen and vmware CI - # jobs we can't check any field in the response because all fields are - # different. - self.assertNotEmpty(diagnostics) - - -class ServerDiagnosticsV248Test(base.BaseV2ComputeAdminTest): - min_microversion = '2.48' - max_microversion = 'latest' - - @classmethod - def setup_clients(cls): - super(ServerDiagnosticsV248Test, cls).setup_clients() - cls.client = cls.os_admin.servers_client - - @decorators.idempotent_id('64d0d48c-dff1-11e6-bf01-fe55135034f3') - def test_get_server_diagnostics(self): - server_id = self.create_test_server(wait_until='ACTIVE')['id'] - # Response status and filed types will be checked by json schema - self.client.show_server_diagnostics(server_id) - - # NOTE(snikitin): This is a special case for Xen hypervisor. In Xen - # case we're getting diagnostics stats from the RRDs which are updated - # every 5 seconds. It means that diagnostics information may be - # incomplete during first 5 seconds of VM life. In such cases methods - # which get diagnostics stats from Xen may raise exceptions or - # return `NaN` values. Such behavior must be handled correctly. - # Response must contain all diagnostics fields (may be with `None` - # values) and response status must be 200. Line above checks it by - # json schema. - time.sleep(10) - diagnostics = self.client.show_server_diagnostics(server_id) - - # NOTE(snikitin): After 10 seconds diagnostics fields must contain - # not None values. But we will check only "memory_details.maximum" - # field because only this field meets all the following conditions: - # 1) This field may be unset because of Xen 5 seconds timeout. - # 2) This field is present in responses from all three supported - # hypervisors (libvirt, xen, vmware). - self.assertIsNotNone(diagnostics['memory_details']['maximum']) diff --git a/tempest/api/compute/admin/test_server_diagnostics_negative.py b/tempest/api/compute/admin/test_server_diagnostics_negative.py deleted file mode 100644 index d5b66741c..000000000 --- a/tempest/api/compute/admin/test_server_diagnostics_negative.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2017 Mirantis Inc. -# -# 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 tempest.api.compute import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ServerDiagnosticsNegativeTest(base.BaseV2ComputeAdminTest): - min_microversion = None - max_microversion = '2.47' - - @classmethod - def setup_clients(cls): - super(ServerDiagnosticsNegativeTest, cls).setup_clients() - cls.client = cls.servers_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e84e2234-60d2-42fa-8b30-e2d3049724ac') - def test_get_server_diagnostics_by_non_admin(self): - # Non-admin user cannot view server diagnostics according to policy - server_id = self.create_test_server(wait_until='ACTIVE')['id'] - self.assertRaises(lib_exc.Forbidden, - self.client.show_server_diagnostics, server_id) - - -class ServerDiagnosticsNegativeV248Test(ServerDiagnosticsNegativeTest): - min_microversion = '2.48' - max_microversion = 'latest' diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py deleted file mode 100644 index d9a78009c..000000000 --- a/tempest/api/compute/admin/test_servers.py +++ /dev/null @@ -1,210 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# 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 tempest.api.compute import base -from tempest.common import compute -from tempest.common import waiters -from tempest.lib.common import fixed_network -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class ServersAdminTestJSON(base.BaseV2ComputeAdminTest): - """Tests Servers API using admin privileges""" - - @classmethod - def setup_clients(cls): - super(ServersAdminTestJSON, cls).setup_clients() - cls.client = cls.os_admin.servers_client - cls.non_admin_client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(ServersAdminTestJSON, cls).resource_setup() - - cls.s1_name = data_utils.rand_name(cls.__name__ + '-server') - server = cls.create_test_server(name=cls.s1_name) - cls.s1_id = server['id'] - - cls.s2_name = data_utils.rand_name(cls.__name__ + '-server') - server = cls.create_test_server(name=cls.s2_name, - wait_until='ACTIVE') - cls.s2_id = server['id'] - waiters.wait_for_server_status(cls.non_admin_client, - cls.s1_id, 'ACTIVE') - - @decorators.idempotent_id('06f960bb-15bb-48dc-873d-f96e89be7870') - def test_list_servers_filter_by_error_status(self): - # Filter the list of servers by server error status - params = {'status': 'error'} - self.client.reset_state(self.s1_id, state='error') - body = self.non_admin_client.list_servers(**params) - # Reset server's state to 'active' - self.client.reset_state(self.s1_id, state='active') - # Verify server's state - server = self.client.show_server(self.s1_id)['server'] - self.assertEqual(server['status'], 'ACTIVE') - servers = body['servers'] - # Verify error server in list result - self.assertIn(self.s1_id, map(lambda x: x['id'], servers)) - self.assertNotIn(self.s2_id, map(lambda x: x['id'], servers)) - - @decorators.idempotent_id('d56e9540-73ed-45e0-9b88-98fc419087eb') - def test_list_servers_detailed_filter_by_invalid_status(self): - params = {'status': 'invalid_status'} - body = self.client.list_servers(detail=True, **params) - servers = body['servers'] - self.assertEmpty(servers) - - @decorators.idempotent_id('51717b38-bdc1-458b-b636-1cf82d99f62f') - def test_list_servers_by_admin(self): - # Listing servers by admin user returns a list which doesn't - # contain the other tenants' server by default - body = self.client.list_servers(detail=True) - servers = body['servers'] - - # This case is for the test environments which contain - # the existing servers before testing - servers_name = [server['name'] for server in servers] - self.assertNotIn(self.s1_name, servers_name) - self.assertNotIn(self.s2_name, servers_name) - - @decorators.idempotent_id('9f5579ae-19b4-4985-a091-2a5d56106580') - def test_list_servers_by_admin_with_all_tenants(self): - # Listing servers by admin user with all tenants parameter - # Here should be listed all servers - params = {'all_tenants': ''} - body = self.client.list_servers(detail=True, **params) - servers = body['servers'] - servers_name = [server['name'] for server in servers] - - self.assertIn(self.s1_name, servers_name) - self.assertIn(self.s2_name, servers_name) - - @decorators.related_bug('1659811') - @decorators.idempotent_id('7e5d6b8f-454a-4ba1-8ae2-da857af8338b') - def test_list_servers_by_admin_with_specified_tenant(self): - # In nova v2, tenant_id is ignored unless all_tenants is specified - - # List the primary tenant but get nothing due to odd specified behavior - tenant_id = self.non_admin_client.tenant_id - params = {'tenant_id': tenant_id} - body = self.client.list_servers(detail=True, **params) - servers = body['servers'] - servers_name = [x['name'] for x in servers] - self.assertNotIn(self.s1_name, servers_name) - self.assertNotIn(self.s2_name, servers_name) - - # List the primary tenant with all_tenants is specified - params = {'all_tenants': '', 'tenant_id': tenant_id} - body = self.client.list_servers(detail=True, **params) - servers = body['servers'] - servers_name = [x['name'] for x in servers] - self.assertIn(self.s1_name, servers_name) - self.assertIn(self.s2_name, servers_name) - - # List the admin tenant shouldn't get servers created by other tenants - admin_tenant_id = self.client.tenant_id - params = {'all_tenants': '', 'tenant_id': admin_tenant_id} - body = self.client.list_servers(detail=True, **params) - servers = body['servers'] - servers_name = [x['name'] for x in servers] - self.assertNotIn(self.s1_name, servers_name) - self.assertNotIn(self.s2_name, servers_name) - - @decorators.idempotent_id('86c7a8f7-50cf-43a9-9bac-5b985317134f') - def test_list_servers_filter_by_exist_host(self): - # Filter the list of servers by existent host - name = data_utils.rand_name(self.__class__.__name__ + '-server') - network = self.get_tenant_network() - network_kwargs = fixed_network.set_networks_kwarg(network) - # We need to create the server as an admin, so we can't use - # self.create_test_server() here as this method creates the server - # in the "primary" (i.e non-admin) tenant. - test_server, _ = compute.create_test_server( - self.os_admin, wait_until="ACTIVE", name=name, **network_kwargs) - self.addCleanup(self.client.delete_server, test_server['id']) - server = self.client.show_server(test_server['id'])['server'] - self.assertEqual(server['status'], 'ACTIVE') - hostname = server['OS-EXT-SRV-ATTR:host'] - params = {'host': hostname} - body = self.client.list_servers(**params) - servers = body['servers'] - nonexistent_params = {'host': 'nonexistent_host'} - nonexistent_body = self.client.list_servers(**nonexistent_params) - nonexistent_servers = nonexistent_body['servers'] - self.assertIn(test_server['id'], map(lambda x: x['id'], servers)) - self.assertNotIn(test_server['id'], - map(lambda x: x['id'], nonexistent_servers)) - - @decorators.idempotent_id('ee8ae470-db70-474d-b752-690b7892cab1') - def test_reset_state_server(self): - # Reset server's state to 'error' - self.client.reset_state(self.s1_id, state='error') - - # Verify server's state - server = self.client.show_server(self.s1_id)['server'] - self.assertEqual(server['status'], 'ERROR') - - # Reset server's state to 'active' - self.client.reset_state(self.s1_id, state='active') - - # Verify server's state - server = self.client.show_server(self.s1_id)['server'] - self.assertEqual(server['status'], 'ACTIVE') - - @decorators.idempotent_id('682cb127-e5bb-4f53-87ce-cb9003604442') - def test_rebuild_server_in_error_state(self): - # The server in error state should be rebuilt using the provided - # image and changed to ACTIVE state - - # resetting vm state require admin privilege - self.client.reset_state(self.s1_id, state='error') - rebuilt_server = self.non_admin_client.rebuild_server( - self.s1_id, self.image_ref_alt)['server'] - self.addCleanup(waiters.wait_for_server_status, self.non_admin_client, - self.s1_id, 'ACTIVE') - self.addCleanup(self.non_admin_client.rebuild_server, self.s1_id, - self.image_ref) - - # Verify the properties in the initial response are correct - self.assertEqual(self.s1_id, rebuilt_server['id']) - rebuilt_image_id = rebuilt_server['image']['id'] - self.assertEqual(self.image_ref_alt, rebuilt_image_id) - self.assertEqual(self.flavor_ref, rebuilt_server['flavor']['id']) - waiters.wait_for_server_status(self.non_admin_client, - rebuilt_server['id'], 'ACTIVE', - raise_on_error=False) - # Verify the server properties after rebuilding - server = (self.non_admin_client.show_server(rebuilt_server['id']) - ['server']) - rebuilt_image_id = server['image']['id'] - self.assertEqual(self.image_ref_alt, rebuilt_image_id) - - @decorators.idempotent_id('7a1323b4-a6a2-497a-96cb-76c07b945c71') - def test_reset_network_inject_network_info(self): - # Reset Network of a Server - server = self.create_test_server(wait_until='ACTIVE') - self.client.reset_network(server['id']) - # Inject the Network Info into Server - self.client.inject_network_info(server['id']) - - @decorators.idempotent_id('fdcd9b33-0903-4e00-a1f7-b5f6543068d6') - def test_create_server_with_scheduling_hint(self): - # Create a server with scheduler hints. - hints = { - 'same_host': self.s1_id - } - self.create_test_server(scheduler_hints=hints, - wait_until='ACTIVE') diff --git a/tempest/api/compute/admin/test_servers_negative.py b/tempest/api/compute/admin/test_servers_negative.py deleted file mode 100644 index 36567707f..000000000 --- a/tempest/api/compute/admin/test_servers_negative.py +++ /dev/null @@ -1,134 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD. -# -# 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 testtools - -from tempest.api.compute import base -from tempest.common import tempest_fixtures as fixtures -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class ServersAdminNegativeTestJSON(base.BaseV2ComputeAdminTest): - """Tests Servers API using admin privileges""" - - @classmethod - def setup_clients(cls): - super(ServersAdminNegativeTestJSON, cls).setup_clients() - cls.client = cls.os_admin.servers_client - cls.quotas_client = cls.os_admin.quotas_client - - @classmethod - def resource_setup(cls): - super(ServersAdminNegativeTestJSON, cls).resource_setup() - cls.tenant_id = cls.client.tenant_id - - server = cls.create_test_server(wait_until='ACTIVE') - cls.s1_id = server['id'] - - @decorators.idempotent_id('28dcec23-f807-49da-822c-56a92ea3c687') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize not available.') - @decorators.attr(type=['negative']) - def test_resize_server_using_overlimit_ram(self): - # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests. - self.useFixture(fixtures.LockFixture('compute_quotas')) - quota_set = self.quotas_client.show_quota_set( - self.tenant_id)['quota_set'] - ram = quota_set['ram'] - if ram == -1: - raise self.skipException("ram quota set is -1," - " cannot test overlimit") - ram += 1 - vcpus = 1 - disk = 5 - flavor_ref = self.create_flavor(ram=ram, vcpus=vcpus, disk=disk) - self.assertRaises((lib_exc.Forbidden, lib_exc.OverLimit), - self.client.resize_server, - self.servers[0]['id'], - flavor_ref['id']) - - @decorators.idempotent_id('7368a427-2f26-4ad9-9ba9-911a0ec2b0db') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize not available.') - @decorators.attr(type=['negative']) - def test_resize_server_using_overlimit_vcpus(self): - # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests. - self.useFixture(fixtures.LockFixture('compute_quotas')) - quota_set = self.quotas_client.show_quota_set( - self.tenant_id)['quota_set'] - vcpus = quota_set['cores'] - if vcpus == -1: - raise self.skipException("cores quota set is -1," - " cannot test overlimit") - vcpus += 1 - ram = 512 - disk = 5 - flavor_ref = self.create_flavor(ram=ram, vcpus=vcpus, disk=disk) - self.assertRaises((lib_exc.Forbidden, lib_exc.OverLimit), - self.client.resize_server, - self.servers[0]['id'], - flavor_ref['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('b0b4d8af-1256-41ef-9ee7-25f1c19dde80') - def test_reset_state_server_invalid_state(self): - self.assertRaises(lib_exc.BadRequest, - self.client.reset_state, self.s1_id, - state='invalid') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('4cdcc984-fab0-4577-9a9d-6d558527ee9d') - def test_reset_state_server_invalid_type(self): - self.assertRaises(lib_exc.BadRequest, - self.client.reset_state, self.s1_id, - state=1) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e741298b-8df2-46f0-81cb-8f814ff2504c') - def test_reset_state_server_nonexistent_server(self): - self.assertRaises(lib_exc.NotFound, - self.client.reset_state, '999', state='error') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('46a4e1ca-87ae-4d28-987a-1b6b136a0221') - def test_migrate_non_existent_server(self): - # migrate a non existent server - self.assertRaises(lib_exc.NotFound, - self.client.migrate_server, - data_utils.rand_uuid()) - - @decorators.idempotent_id('b0b17f83-d14e-4fc4-8f31-bcc9f3cfa629') - @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration, - 'Cold migration not available.') - @testtools.skipUnless(CONF.compute_feature_enabled.suspend, - 'Suspend is not available.') - @decorators.attr(type=['negative']) - def test_migrate_server_invalid_state(self): - # create server. - server = self.create_test_server(wait_until='ACTIVE') - server_id = server['id'] - # suspend the server. - self.client.suspend_server(server_id) - waiters.wait_for_server_status(self.client, - server_id, 'SUSPENDED') - # migrate a suspended server should fail - self.assertRaises(lib_exc.Conflict, - self.client.migrate_server, - server_id) diff --git a/tempest/api/compute/admin/test_servers_on_multinodes.py b/tempest/api/compute/admin/test_servers_on_multinodes.py deleted file mode 100644 index 858998af9..000000000 --- a/tempest/api/compute/admin/test_servers_on_multinodes.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 testtools - -from tempest.api.compute import base -from tempest import config -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class ServersOnMultiNodesTest(base.BaseV2ComputeAdminTest): - - @classmethod - def resource_setup(cls): - super(ServersOnMultiNodesTest, cls).resource_setup() - cls.server01 = cls.create_test_server(wait_until='ACTIVE')['id'] - cls.host01 = cls._get_host(cls.server01) - - @classmethod - def skip_checks(cls): - super(ServersOnMultiNodesTest, cls).skip_checks() - - if CONF.compute.min_compute_nodes < 2: - raise cls.skipException( - "Less than 2 compute nodes, skipping multi-nodes test.") - - @classmethod - def _get_host(cls, server_id): - return cls.os_admin.servers_client.show_server( - server_id)['server']['OS-EXT-SRV-ATTR:host'] - - @decorators.idempotent_id('26a9d5df-6890-45f2-abc4-a659290cb130') - @testtools.skipUnless( - test.is_scheduler_filter_enabled("SameHostFilter"), - 'SameHostFilter is not available.') - def test_create_servers_on_same_host(self): - hints = {'same_host': self.server01} - server02 = self.create_test_server(scheduler_hints=hints, - wait_until='ACTIVE')['id'] - host02 = self._get_host(server02) - self.assertEqual(self.host01, host02) - - @decorators.idempotent_id('cc7ca884-6e3e-42a3-a92f-c522fcf25e8e') - @testtools.skipUnless( - test.is_scheduler_filter_enabled("DifferentHostFilter"), - 'DifferentHostFilter is not available.') - def test_create_servers_on_different_hosts(self): - hints = {'different_host': self.server01} - server02 = self.create_test_server(scheduler_hints=hints, - wait_until='ACTIVE')['id'] - host02 = self._get_host(server02) - self.assertNotEqual(self.host01, host02) - - @decorators.idempotent_id('7869cc84-d661-4e14-9f00-c18cdc89cf57') - @testtools.skipUnless( - test.is_scheduler_filter_enabled("DifferentHostFilter"), - 'DifferentHostFilter is not available.') - def test_create_servers_on_different_hosts_with_list_of_servers(self): - # This scheduler-hint supports list of servers also. - hints = {'different_host': [self.server01]} - server02 = self.create_test_server(scheduler_hints=hints, - wait_until='ACTIVE')['id'] - host02 = self._get_host(server02) - self.assertNotEqual(self.host01, host02) diff --git a/tempest/api/compute/admin/test_services.py b/tempest/api/compute/admin/test_services.py deleted file mode 100644 index f3eb597f9..000000000 --- a/tempest/api/compute/admin/test_services.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright 2013 NEC Corporation -# Copyright 2013 IBM 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 tempest.api.compute import base -from tempest.lib import decorators - - -class ServicesAdminTestJSON(base.BaseV2ComputeAdminTest): - """Tests Services API. List and Enable/Disable require admin privileges.""" - - @classmethod - def setup_clients(cls): - super(ServicesAdminTestJSON, cls).setup_clients() - cls.client = cls.os_admin.services_client - - @decorators.idempotent_id('5be41ef4-53d1-41cc-8839-5c2a48a1b283') - def test_list_services(self): - services = self.client.list_services()['services'] - self.assertNotEmpty(services) - - @decorators.idempotent_id('f345b1ec-bc6e-4c38-a527-3ca2bc00bef5') - def test_get_service_by_service_binary_name(self): - binary_name = 'nova-compute' - services = self.client.list_services(binary=binary_name)['services'] - self.assertNotEmpty(services) - for service in services: - self.assertEqual(binary_name, service['binary']) - - @decorators.idempotent_id('affb42d5-5b4b-43c8-8b0b-6dca054abcca') - def test_get_service_by_host_name(self): - services = self.client.list_services()['services'] - host_name = services[0]['host'] - services_on_host = [service for service in services if - service['host'] == host_name] - - services = self.client.list_services(host=host_name)['services'] - - # we could have a periodic job checkin between the 2 service - # lookups, so only compare binary lists. - s1 = map(lambda x: x['binary'], services) - s2 = map(lambda x: x['binary'], services_on_host) - - # sort the lists before comparing, to take out dependency - # on order. - self.assertEqual(sorted(s1), sorted(s2)) - - @decorators.idempotent_id('39397f6f-37b8-4234-8671-281e44c74025') - def test_get_service_by_service_and_host_name(self): - services = self.client.list_services()['services'] - host_name = services[0]['host'] - binary_name = services[0]['binary'] - - services = self.client.list_services(host=host_name, - binary=binary_name)['services'] - self.assertEqual(1, len(services)) - self.assertEqual(host_name, services[0]['host']) - self.assertEqual(binary_name, services[0]['binary']) diff --git a/tempest/api/compute/admin/test_services_negative.py b/tempest/api/compute/admin/test_services_negative.py deleted file mode 100644 index 201670ab2..000000000 --- a/tempest/api/compute/admin/test_services_negative.py +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2013 NEC Corporation. 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 tempest.api.compute import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ServicesAdminNegativeTestJSON(base.BaseV2ComputeAdminTest): - """Tests Services API. List and Enable/Disable require admin privileges.""" - - @classmethod - def setup_clients(cls): - super(ServicesAdminNegativeTestJSON, cls).setup_clients() - cls.client = cls.os_admin.services_client - cls.non_admin_client = cls.services_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1126d1f8-266e-485f-a687-adc547492646') - def test_list_services_with_non_admin_user(self): - self.assertRaises(lib_exc.Forbidden, - self.non_admin_client.list_services) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d0884a69-f693-4e79-a9af-232d15643bf7') - def test_get_service_by_invalid_params(self): - # return all services if send the request with invalid parameter - services = self.client.list_services()['services'] - services_xxx = (self.client.list_services(xxx='nova-compute') - ['services']) - self.assertEqual(len(services), len(services_xxx)) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1e966d4a-226e-47c7-b601-0b18a27add54') - def test_get_service_by_invalid_service_and_valid_host(self): - services = self.client.list_services()['services'] - host_name = services[0]['host'] - services = self.client.list_services(host=host_name, - binary='xxx')['services'] - self.assertEmpty(services) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('64e7e7fb-69e8-4cb6-a71d-8d5eb0c98655') - def test_get_service_with_valid_service_and_invalid_host(self): - services = self.client.list_services()['services'] - binary_name = services[0]['binary'] - services = self.client.list_services(host='xxx', - binary=binary_name)['services'] - self.assertEmpty(services) diff --git a/tempest/api/compute/admin/test_simple_tenant_usage.py b/tempest/api/compute/admin/test_simple_tenant_usage.py deleted file mode 100644 index d4c60b349..000000000 --- a/tempest/api/compute/admin/test_simple_tenant_usage.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2013 NEC Corporation -# 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 datetime - -from tempest.api.compute import base -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as e - -# Time that waits for until returning valid response -# TODO(takmatsu): Ideally this value would come from configuration. -VALID_WAIT = 30 - - -class TenantUsagesTestJSON(base.BaseV2ComputeAdminTest): - - @classmethod - def setup_clients(cls): - super(TenantUsagesTestJSON, cls).setup_clients() - cls.adm_client = cls.os_admin.tenant_usages_client - cls.client = cls.os_primary.tenant_usages_client - - @classmethod - def resource_setup(cls): - super(TenantUsagesTestJSON, cls).resource_setup() - cls.tenant_id = cls.client.tenant_id - - # Create a server in the demo tenant - cls.create_test_server(wait_until='ACTIVE') - - now = datetime.datetime.now() - cls.start = cls._parse_strtime(now - datetime.timedelta(days=1)) - cls.end = cls._parse_strtime(now + datetime.timedelta(days=1)) - - @classmethod - def _parse_strtime(cls, at): - # Returns formatted datetime - return at.strftime('%Y-%m-%dT%H:%M:%S.%f') - - def call_until_valid(self, func, duration, *args, **kwargs): - # Call until get valid response for "duration" - # because tenant usage doesn't become available immediately - # after create VM. - def is_valid(): - try: - self.resp = func(*args, **kwargs) - return True - except e.InvalidHTTPResponseBody: - return False - self.assertEqual(test_utils.call_until_true(is_valid, duration, 1), - True, "%s not return valid response in %s secs" % ( - func.__name__, duration)) - return self.resp - - @decorators.idempotent_id('062c8ae9-9912-4249-8b51-e38d664e926e') - def test_list_usage_all_tenants(self): - # Get usage for all tenants - tenant_usage = self.call_until_valid( - self.adm_client.list_tenant_usages, VALID_WAIT, - start=self.start, end=self.end, detailed="1")['tenant_usages'][0] - self.assertEqual(len(tenant_usage), 8) - - @decorators.idempotent_id('94135049-a4c5-4934-ad39-08fa7da4f22e') - def test_get_usage_tenant(self): - # Get usage for a specific tenant - tenant_usage = self.call_until_valid( - self.adm_client.show_tenant_usage, VALID_WAIT, - self.tenant_id, start=self.start, end=self.end)['tenant_usage'] - - self.assertEqual(len(tenant_usage), 8) - - @decorators.idempotent_id('9d00a412-b40e-4fd9-8eba-97b496316116') - def test_get_usage_tenant_with_non_admin_user(self): - # Get usage for a specific tenant with non admin user - tenant_usage = self.call_until_valid( - self.client.show_tenant_usage, VALID_WAIT, - self.tenant_id, start=self.start, end=self.end)['tenant_usage'] - self.assertEqual(len(tenant_usage), 8) diff --git a/tempest/api/compute/admin/test_simple_tenant_usage_negative.py b/tempest/api/compute/admin/test_simple_tenant_usage_negative.py deleted file mode 100644 index cb60b8d30..000000000 --- a/tempest/api/compute/admin/test_simple_tenant_usage_negative.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2013 NEC Corporation -# 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 datetime - -from tempest.api.compute import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class TenantUsagesNegativeTestJSON(base.BaseV2ComputeAdminTest): - - @classmethod - def setup_clients(cls): - super(TenantUsagesNegativeTestJSON, cls).setup_clients() - cls.adm_client = cls.os_admin.tenant_usages_client - cls.client = cls.os_primary.tenant_usages_client - - @classmethod - def resource_setup(cls): - super(TenantUsagesNegativeTestJSON, cls).resource_setup() - now = datetime.datetime.now() - cls.start = cls._parse_strtime(now - datetime.timedelta(days=1)) - cls.end = cls._parse_strtime(now + datetime.timedelta(days=1)) - - @classmethod - def _parse_strtime(cls, at): - # Returns formatted datetime - return at.strftime('%Y-%m-%dT%H:%M:%S.%f') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('8b21e135-d94b-4991-b6e9-87059609c8ed') - def test_get_usage_tenant_with_empty_tenant_id(self): - # Get usage for a specific tenant empty - params = {'start': self.start, - 'end': self.end} - self.assertRaises(lib_exc.NotFound, - self.adm_client.show_tenant_usage, - '', **params) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('4079dd2a-9e8d-479f-869d-6fa985ce45b6') - def test_get_usage_tenant_with_invalid_date(self): - # Get usage for tenant with invalid date - params = {'start': self.end, - 'end': self.start} - self.assertRaises(lib_exc.BadRequest, - self.adm_client.show_tenant_usage, - self.client.tenant_id, **params) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('bbe6fe2c-15d8-404c-a0a2-44fad0ad5cc7') - def test_list_usage_all_tenants_with_non_admin_user(self): - # Get usage for all tenants with non admin user - params = {'start': self.start, - 'end': self.end, - 'detailed': "1"} - self.assertRaises(lib_exc.Forbidden, - self.client.list_tenant_usages, **params) diff --git a/tempest/api/compute/admin/test_volume_swap.py b/tempest/api/compute/admin/test_volume_swap.py deleted file mode 100644 index 22a5bc48e..000000000 --- a/tempest/api/compute/admin/test_volume_swap.py +++ /dev/null @@ -1,123 +0,0 @@ -# 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 time - -from tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class TestVolumeSwap(base.BaseV2ComputeAdminTest): - """The test suite for swapping of volume with admin user. - - The following is the scenario outline: - 1. Create a volume "volume1" with non-admin. - 2. Create a volume "volume2" with non-admin. - 3. Boot an instance "instance1" with non-admin. - 4. Attach "volume1" to "instance1" with non-admin. - 5. Swap volume from "volume1" to "volume2" as admin. - 6. Check the swap volume is successful and "volume2" - is attached to "instance1" and "volume1" is in available state. - 7. Swap volume from "volume2" to "volume1" as admin. - 8. Check the swap volume is successful and "volume1" - is attached to "instance1" and "volume2" is in available state. - """ - - @classmethod - def skip_checks(cls): - super(TestVolumeSwap, cls).skip_checks() - if not CONF.compute_feature_enabled.swap_volume: - raise cls.skipException("Swapping volumes is not supported.") - - def _wait_for_server_volume_swap(self, server_id, old_volume_id, - new_volume_id): - """Waits for a server to swap the old volume to a new one.""" - volume_attachments = self.servers_client.list_volume_attachments( - server_id)['volumeAttachments'] - attached_volume_ids = [attachment['volumeId'] - for attachment in volume_attachments] - start = int(time.time()) - - while (old_volume_id in attached_volume_ids) \ - or (new_volume_id not in attached_volume_ids): - time.sleep(self.servers_client.build_interval) - volume_attachments = self.servers_client.list_volume_attachments( - server_id)['volumeAttachments'] - attached_volume_ids = [attachment['volumeId'] - for attachment in volume_attachments] - - if int(time.time()) - start >= self.servers_client.build_timeout: - old_vol_bdm_status = 'in BDM' \ - if old_volume_id in attached_volume_ids else 'not in BDM' - new_vol_bdm_status = 'in BDM' \ - if new_volume_id in attached_volume_ids else 'not in BDM' - message = ('Failed to swap old volume %(old_volume_id)s ' - '(current %(old_vol_bdm_status)s) to new volume ' - '%(new_volume_id)s (current %(new_vol_bdm_status)s)' - ' on server %(server_id)s within the required time ' - '(%(timeout)s s)' % - {'old_volume_id': old_volume_id, - 'old_vol_bdm_status': old_vol_bdm_status, - 'new_volume_id': new_volume_id, - 'new_vol_bdm_status': new_vol_bdm_status, - 'server_id': server_id, - 'timeout': self.servers_client.build_timeout}) - raise lib_exc.TimeoutException(message) - - @decorators.idempotent_id('1769f00d-a693-4d67-a631-6a3496773813') - @test.services('volume') - def test_volume_swap(self): - # Create two volumes. - # NOTE(gmann): Volumes are created before server creation so that - # volumes cleanup can happen successfully irrespective of which volume - # is attached to server. - volume1 = self.create_volume() - volume2 = self.create_volume() - # Boot server - server = self.create_test_server(wait_until='ACTIVE') - # Attach "volume1" to server - self.attach_volume(server, volume1) - # Swap volume from "volume1" to "volume2" - self.admin_servers_client.update_attached_volume( - server['id'], volume1['id'], volumeId=volume2['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume1['id'], 'available') - waiters.wait_for_volume_resource_status(self.volumes_client, - volume2['id'], 'in-use') - self._wait_for_server_volume_swap(server['id'], volume1['id'], - volume2['id']) - # Verify "volume2" is attached to the server - vol_attachments = self.servers_client.list_volume_attachments( - server['id'])['volumeAttachments'] - self.assertEqual(1, len(vol_attachments)) - self.assertIn(volume2['id'], vol_attachments[0]['volumeId']) - - # Swap volume from "volume2" to "volume1" - self.admin_servers_client.update_attached_volume( - server['id'], volume2['id'], volumeId=volume1['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume2['id'], 'available') - waiters.wait_for_volume_resource_status(self.volumes_client, - volume1['id'], 'in-use') - self._wait_for_server_volume_swap(server['id'], volume2['id'], - volume1['id']) - # Verify "volume1" is attached to the server - vol_attachments = self.servers_client.list_volume_attachments( - server['id'])['volumeAttachments'] - self.assertEqual(1, len(vol_attachments)) - self.assertIn(volume1['id'], vol_attachments[0]['volumeId']) diff --git a/tempest/api/compute/admin/test_volumes_negative.py b/tempest/api/compute/admin/test_volumes_negative.py deleted file mode 100644 index 4a7f36f2b..000000000 --- a/tempest/api/compute/admin/test_volumes_negative.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.api.compute import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class VolumesAdminNegativeTest(base.BaseV2ComputeAdminTest): - - @classmethod - def skip_checks(cls): - super(VolumesAdminNegativeTest, cls).skip_checks() - if not CONF.service_available.cinder: - skip_msg = ("%s skipped as Cinder is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def resource_setup(cls): - super(VolumesAdminNegativeTest, cls).resource_setup() - cls.server = cls.create_test_server(wait_until='ACTIVE') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('309b5ecd-0585-4a7e-a36f-d2b2bf55259d') - def test_update_attached_volume_with_nonexistent_volume_in_uri(self): - volume = self.create_volume() - nonexistent_volume = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.admin_servers_client.update_attached_volume, - self.server['id'], nonexistent_volume, - volumeId=volume['id']) - - @decorators.related_bug('1629110', status_code=400) - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7dcac15a-b107-46d3-a5f6-cb863f4e454a') - def test_update_attached_volume_with_nonexistent_volume_in_body(self): - volume = self.create_volume() - self.attach_volume(self.server, volume) - - nonexistent_volume = data_utils.rand_uuid() - self.assertRaises(lib_exc.BadRequest, - self.admin_servers_client.update_attached_volume, - self.server['id'], volume['id'], - volumeId=nonexistent_volume) diff --git a/tempest/api/compute/api_microversion_fixture.py b/tempest/api/compute/api_microversion_fixture.py deleted file mode 100644 index 695af5200..000000000 --- a/tempest/api/compute/api_microversion_fixture.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 fixtures - -from tempest.lib.services.compute import base_compute_client - - -class APIMicroversionFixture(fixtures.Fixture): - - def __init__(self, compute_microversion): - self.compute_microversion = compute_microversion - - def _setUp(self): - super(APIMicroversionFixture, self)._setUp() - base_compute_client.COMPUTE_MICROVERSION = self.compute_microversion - self.addCleanup(self._reset_compute_microversion) - - def _reset_compute_microversion(self): - base_compute_client.COMPUTE_MICROVERSION = None diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py deleted file mode 100644 index feabe35d1..000000000 --- a/tempest/api/compute/base.py +++ /dev/null @@ -1,507 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 time - -from oslo_log import log as logging - -from tempest.api.compute import api_microversion_fixture -from tempest.common import compute -from tempest.common import waiters -from tempest import config -from tempest import exceptions -from tempest.lib.common import api_version_request -from tempest.lib.common import api_version_utils -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import exceptions as lib_exc -import tempest.test - -CONF = config.CONF - -LOG = logging.getLogger(__name__) - - -class BaseV2ComputeTest(api_version_utils.BaseMicroversionTest, - tempest.test.BaseTestCase): - """Base test case class for all Compute API tests.""" - - force_tenant_isolation = False - - # TODO(andreaf) We should care also for the alt_manager here - # but only once client lazy load in the manager is done - credentials = ['primary'] - - @classmethod - def skip_checks(cls): - super(BaseV2ComputeTest, cls).skip_checks() - if not CONF.service_available.nova: - raise cls.skipException("Nova is not available") - cfg_min_version = CONF.compute.min_microversion - cfg_max_version = CONF.compute.max_microversion - api_version_utils.check_skip_with_microversion(cls.min_microversion, - cls.max_microversion, - cfg_min_version, - cfg_max_version) - - @classmethod - def setup_credentials(cls): - cls.set_network_resources() - super(BaseV2ComputeTest, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(BaseV2ComputeTest, cls).setup_clients() - cls.servers_client = cls.os_primary.servers_client - cls.server_groups_client = cls.os_primary.server_groups_client - cls.flavors_client = cls.os_primary.flavors_client - cls.compute_images_client = cls.os_primary.compute_images_client - cls.extensions_client = cls.os_primary.extensions_client - cls.floating_ip_pools_client = cls.os_primary.floating_ip_pools_client - cls.floating_ips_client = cls.os_primary.compute_floating_ips_client - cls.keypairs_client = cls.os_primary.keypairs_client - cls.security_group_rules_client = ( - cls.os_primary.compute_security_group_rules_client) - cls.security_groups_client =\ - cls.os_primary.compute_security_groups_client - cls.quotas_client = cls.os_primary.quotas_client - cls.compute_networks_client = cls.os_primary.compute_networks_client - cls.limits_client = cls.os_primary.limits_client - cls.volumes_extensions_client =\ - cls.os_primary.volumes_extensions_client - cls.snapshots_extensions_client =\ - cls.os_primary.snapshots_extensions_client - cls.interfaces_client = cls.os_primary.interfaces_client - cls.fixed_ips_client = cls.os_primary.fixed_ips_client - cls.availability_zone_client = cls.os_primary.availability_zone_client - cls.agents_client = cls.os_primary.agents_client - cls.aggregates_client = cls.os_primary.aggregates_client - cls.services_client = cls.os_primary.services_client - cls.instance_usages_audit_log_client = ( - cls.os_primary.instance_usages_audit_log_client) - cls.hypervisor_client = cls.os_primary.hypervisor_client - cls.certificates_client = cls.os_primary.certificates_client - cls.migrations_client = cls.os_primary.migrations_client - cls.security_group_default_rules_client = ( - cls.os_primary.security_group_default_rules_client) - cls.versions_client = cls.os_primary.compute_versions_client - - cls.volumes_client = cls.os_primary.volumes_v2_client - - @classmethod - def resource_setup(cls): - super(BaseV2ComputeTest, cls).resource_setup() - cls.request_microversion = ( - api_version_utils.select_request_microversion( - cls.min_microversion, - CONF.compute.min_microversion)) - cls.build_interval = CONF.compute.build_interval - cls.build_timeout = CONF.compute.build_timeout - cls.image_ref = CONF.compute.image_ref - cls.image_ref_alt = CONF.compute.image_ref_alt - cls.flavor_ref = CONF.compute.flavor_ref - cls.flavor_ref_alt = CONF.compute.flavor_ref_alt - cls.ssh_user = CONF.validation.image_ssh_user - cls.image_ssh_user = CONF.validation.image_ssh_user - cls.image_ssh_password = CONF.validation.image_ssh_password - cls.servers = [] - cls.images = [] - cls.security_groups = [] - cls.server_groups = [] - cls.volumes = [] - - @classmethod - def resource_cleanup(cls): - cls.clear_resources('images', cls.images, - cls.compute_images_client.delete_image) - cls.clear_servers() - cls.clear_resources('security groups', cls.security_groups, - cls.security_groups_client.delete_security_group) - cls.clear_resources('server groups', cls.server_groups, - cls.server_groups_client.delete_server_group) - cls.clear_volumes() - super(BaseV2ComputeTest, cls).resource_cleanup() - - @classmethod - def clear_servers(cls): - LOG.debug('Clearing servers: %s', ','.join( - server['id'] for server in cls.servers)) - for server in cls.servers: - try: - test_utils.call_and_ignore_notfound_exc( - cls.servers_client.delete_server, server['id']) - except Exception: - LOG.exception('Deleting server %s failed', server['id']) - - for server in cls.servers: - try: - waiters.wait_for_server_termination(cls.servers_client, - server['id']) - except Exception: - LOG.exception('Waiting for deletion of server %s failed', - server['id']) - - @classmethod - def server_check_teardown(cls): - """Checks is the shared server clean enough for subsequent test. - - Method will delete the server when it's dirty. - The setUp method is responsible for creating a new server. - Exceptions raised in tearDown class are fails the test case, - This method supposed to use only by tearDown methods, when - the shared server_id is stored in the server_id of the class. - """ - if getattr(cls, 'server_id', None) is not None: - try: - waiters.wait_for_server_status(cls.servers_client, - cls.server_id, 'ACTIVE') - except Exception as exc: - LOG.exception(exc) - cls.servers_client.delete_server(cls.server_id) - waiters.wait_for_server_termination(cls.servers_client, - cls.server_id) - cls.server_id = None - raise - - @classmethod - def clear_resources(cls, resource_name, resources, resource_del_func): - LOG.debug('Clearing %s: %s', resource_name, - ','.join(map(str, resources))) - for res_id in resources: - try: - test_utils.call_and_ignore_notfound_exc( - resource_del_func, res_id) - except Exception as exc: - LOG.exception('Exception raised deleting %s: %s', - resource_name, res_id) - LOG.exception(exc) - - @classmethod - def create_test_server(cls, validatable=False, volume_backed=False, - **kwargs): - """Wrapper utility that returns a test server. - - This wrapper utility calls the common create test server and - returns a test server. The purpose of this wrapper is to minimize - the impact on the code of the tests already using this - function. - - :param validatable: Whether the server will be pingable or sshable. - :param volume_backed: Whether the instance is volume backed or not. - """ - if 'name' not in kwargs: - kwargs['name'] = data_utils.rand_name(cls.__name__ + "-server") - - request_version = api_version_request.APIVersionRequest( - cls.request_microversion) - v2_37_version = api_version_request.APIVersionRequest('2.37') - - # NOTE(snikitin): since microversion v2.37 'networks' field is required - if request_version >= v2_37_version and 'networks' not in kwargs: - kwargs['networks'] = 'none' - - tenant_network = cls.get_tenant_network() - body, servers = compute.create_test_server( - cls.os_primary, - validatable, - validation_resources=cls.validation_resources, - tenant_network=tenant_network, - volume_backed=volume_backed, - **kwargs) - - cls.servers.extend(servers) - - return body - - @classmethod - def create_security_group(cls, name=None, description=None): - if name is None: - name = data_utils.rand_name(cls.__name__ + "-securitygroup") - if description is None: - description = data_utils.rand_name('description') - body = cls.security_groups_client.create_security_group( - name=name, description=description)['security_group'] - cls.security_groups.append(body['id']) - - return body - - @classmethod - def create_test_server_group(cls, name="", policy=None): - if not name: - name = data_utils.rand_name(cls.__name__ + "-Server-Group") - if policy is None: - policy = ['affinity'] - body = cls.server_groups_client.create_server_group( - name=name, policies=policy)['server_group'] - cls.server_groups.append(body['id']) - return body - - def wait_for(self, condition): - """Repeatedly calls condition() until a timeout.""" - start_time = int(time.time()) - while True: - try: - condition() - except Exception: - pass - else: - return - if int(time.time()) - start_time >= self.build_timeout: - condition() - return - time.sleep(self.build_interval) - - @staticmethod - def _delete_volume(volumes_client, volume_id): - """Deletes the given volume and waits for it to be gone.""" - try: - volumes_client.delete_volume(volume_id) - # TODO(mriedem): We should move the wait_for_resource_deletion - # into the delete_volume method as a convenience to the caller. - volumes_client.wait_for_resource_deletion(volume_id) - except lib_exc.NotFound: - LOG.warning("Unable to delete volume '%s' since it was not found. " - "Maybe it was already deleted?", volume_id) - - @classmethod - def prepare_instance_network(cls): - if (CONF.validation.auth_method != 'disabled' and - CONF.validation.connect_method == 'floating'): - cls.set_network_resources(network=True, subnet=True, router=True, - dhcp=True) - - @classmethod - def create_image_from_server(cls, server_id, **kwargs): - """Wrapper utility that returns an image created from the server.""" - name = kwargs.pop('name', - data_utils.rand_name(cls.__name__ + "-image")) - wait_until = kwargs.pop('wait_until', None) - wait_for_server = kwargs.pop('wait_for_server', True) - - image = cls.compute_images_client.create_image(server_id, name=name, - **kwargs) - image_id = data_utils.parse_image_id(image.response['location']) - cls.images.append(image_id) - - if wait_until is not None: - try: - waiters.wait_for_image_status(cls.compute_images_client, - image_id, wait_until) - except lib_exc.NotFound: - if wait_until.upper() == 'ACTIVE': - # If the image is not found after create_image returned - # that means the snapshot failed in nova-compute and nova - # deleted the image. There should be a compute fault - # recorded with the server in that case, so get the server - # and dump some details. - server = ( - cls.servers_client.show_server(server_id)['server']) - if 'fault' in server: - raise exceptions.SnapshotNotFoundException( - server['fault'], image_id=image_id) - else: - raise exceptions.SnapshotNotFoundException( - image_id=image_id) - else: - raise - image = cls.compute_images_client.show_image(image_id)['image'] - - if wait_until.upper() == 'ACTIVE': - if wait_for_server: - waiters.wait_for_server_status(cls.servers_client, - server_id, 'ACTIVE') - return image - - @classmethod - def rebuild_server(cls, server_id, validatable=False, **kwargs): - # Destroy an existing server and creates a new one - if server_id: - cls.delete_server(server_id) - - cls.password = data_utils.rand_password() - server = cls.create_test_server( - validatable, - wait_until='ACTIVE', - adminPass=cls.password, - **kwargs) - return server['id'] - - @classmethod - def delete_server(cls, server_id): - """Deletes an existing server and waits for it to be gone.""" - try: - cls.servers_client.delete_server(server_id) - waiters.wait_for_server_termination(cls.servers_client, - server_id) - except Exception: - LOG.exception('Failed to delete server %s', server_id) - - @classmethod - def resize_server(cls, server_id, new_flavor_id, **kwargs): - """resize and confirm_resize an server, waits for it to be ACTIVE.""" - cls.servers_client.resize_server(server_id, new_flavor_id, **kwargs) - waiters.wait_for_server_status(cls.servers_client, server_id, - 'VERIFY_RESIZE') - cls.servers_client.confirm_resize_server(server_id) - waiters.wait_for_server_status(cls.servers_client, server_id, 'ACTIVE') - - @classmethod - def delete_volume(cls, volume_id): - """Deletes the given volume and waits for it to be gone.""" - cls._delete_volume(cls.volumes_client, volume_id) - - @classmethod - def get_server_ip(cls, server): - """Get the server fixed or floating IP. - - Based on the configuration we're in, return a correct ip - address for validating that a guest is up. - """ - if CONF.validation.connect_method == 'floating': - return cls.validation_resources['floating_ip']['ip'] - elif CONF.validation.connect_method == 'fixed': - addresses = server['addresses'][CONF.validation.network_for_ssh] - for address in addresses: - if address['version'] == CONF.validation.ip_version_for_ssh: - return address['addr'] - raise exceptions.ServerUnreachable(server_id=server['id']) - else: - raise lib_exc.InvalidConfiguration() - - def setUp(self): - super(BaseV2ComputeTest, self).setUp() - self.useFixture(api_microversion_fixture.APIMicroversionFixture( - self.request_microversion)) - - @classmethod - def create_volume(cls, image_ref=None, **kwargs): - """Create a volume and wait for it to become 'available'. - - :param image_ref: Specify an image id to create a bootable volume. - :**kwargs: other parameters to create volume. - :returns: The available volume. - """ - if 'size' not in kwargs: - kwargs['size'] = CONF.volume.volume_size - if 'display_name' not in kwargs: - vol_name = data_utils.rand_name(cls.__name__ + '-volume') - kwargs['display_name'] = vol_name - if image_ref is not None: - kwargs['imageRef'] = image_ref - volume = cls.volumes_client.create_volume(**kwargs)['volume'] - cls.volumes.append(volume) - waiters.wait_for_volume_resource_status(cls.volumes_client, - volume['id'], 'available') - return volume - - @classmethod - def clear_volumes(cls): - LOG.debug('Clearing volumes: %s', ','.join( - volume['id'] for volume in cls.volumes)) - for volume in cls.volumes: - try: - test_utils.call_and_ignore_notfound_exc( - cls.volumes_client.delete_volume, volume['id']) - except Exception: - LOG.exception('Deleting volume %s failed', volume['id']) - - for volume in cls.volumes: - try: - cls.volumes_client.wait_for_resource_deletion(volume['id']) - except Exception: - LOG.exception('Waiting for deletion of volume %s failed', - volume['id']) - - def attach_volume(self, server, volume, device=None, check_reserved=False): - """Attaches volume to server and waits for 'in-use' volume status. - - The volume will be detached when the test tears down. - - :param server: The server to which the volume will be attached. - :param volume: The volume to attach. - :param device: Optional mountpoint for the attached volume. Note that - this is not guaranteed for all hypervisors and is not recommended. - :param check_reserved: Consider a status of reserved as valid for - completion. This is to handle new Cinder attach where we more - accurately use 'reserved' for things like attaching to a shelved - server. - """ - attach_kwargs = dict(volumeId=volume['id']) - if device: - attach_kwargs['device'] = device - - attachment = self.servers_client.attach_volume( - server['id'], **attach_kwargs)['volumeAttachment'] - # On teardown detach the volume and wait for it to be available. This - # is so we don't error out when trying to delete the volume during - # teardown. - self.addCleanup(waiters.wait_for_volume_resource_status, - self.volumes_client, volume['id'], 'available') - # Ignore 404s on detach in case the server is deleted or the volume - # is already detached. - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.servers_client.detach_volume, - server['id'], volume['id']) - statuses = ['in-use'] - if check_reserved: - statuses.append('reserved') - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], statuses) - return attachment - - -class BaseV2ComputeAdminTest(BaseV2ComputeTest): - """Base test case class for Compute Admin API tests.""" - - credentials = ['primary', 'admin'] - - @classmethod - def setup_clients(cls): - super(BaseV2ComputeAdminTest, cls).setup_clients() - cls.availability_zone_admin_client = ( - cls.os_admin.availability_zone_client) - cls.admin_flavors_client = cls.os_admin.flavors_client - cls.admin_servers_client = cls.os_admin.servers_client - - def create_flavor(self, ram, vcpus, disk, name=None, - is_public='True', **kwargs): - if name is None: - name = data_utils.rand_name(self.__class__.__name__ + "-flavor") - id = kwargs.pop('id', data_utils.rand_int_id(start=1000)) - client = self.admin_flavors_client - flavor = client.create_flavor( - ram=ram, vcpus=vcpus, disk=disk, name=name, - id=id, is_public=is_public, **kwargs)['flavor'] - self.addCleanup(client.wait_for_resource_deletion, flavor['id']) - self.addCleanup(client.delete_flavor, flavor['id']) - return flavor - - def get_host_for_server(self, server_id): - server_details = self.admin_servers_client.show_server(server_id) - return server_details['server']['OS-EXT-SRV-ATTR:host'] - - def get_host_other_than(self, server_id): - source_host = self.get_host_for_server(server_id) - - list_hosts_resp = self.os_admin.hosts_client.list_hosts()['hosts'] - hosts = [ - host_record['host_name'] - for host_record in list_hosts_resp - if host_record['service'] == 'compute' - ] - - for target_host in hosts: - if source_host != target_host: - return target_host diff --git a/tempest/api/compute/certificates/__init__.py b/tempest/api/compute/certificates/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/compute/certificates/test_certificates.py b/tempest/api/compute/certificates/test_certificates.py deleted file mode 100644 index a39fec95d..000000000 --- a/tempest/api/compute/certificates/test_certificates.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.compute import base -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class CertificatesV2TestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(CertificatesV2TestJSON, cls).skip_checks() - if not CONF.compute_feature_enabled.nova_cert: - raise cls.skipException("Nova cert is not available") - - @decorators.idempotent_id('c070a441-b08e-447e-a733-905909535b1b') - def test_create_root_certificate(self): - # create certificates - body = self.certificates_client.create_certificate()['certificate'] - self.assertIn('data', body) - self.assertIn('private_key', body) - - @decorators.idempotent_id('3ac273d0-92d2-4632-bdfc-afbc21d4606c') - def test_get_root_certificate(self): - # get the root certificate - body = (self.certificates_client.show_certificate('root') - ['certificate']) - self.assertIn('data', body) - self.assertIn('private_key', body) diff --git a/tempest/api/compute/flavors/__init__.py b/tempest/api/compute/flavors/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/compute/flavors/test_flavors.py b/tempest/api/compute/flavors/test_flavors.py deleted file mode 100644 index d5bb45ad9..000000000 --- a/tempest/api/compute/flavors/test_flavors.py +++ /dev/null @@ -1,126 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.compute import base -from tempest.lib import decorators - - -class FlavorsV2TestJSON(base.BaseV2ComputeTest): - _min_disk = 'minDisk' - _min_ram = 'minRam' - - @decorators.attr(type='smoke') - @decorators.idempotent_id('e36c0eaa-dff5-4082-ad1f-3f9a80aa3f59') - def test_list_flavors(self): - # List of all flavors should contain the expected flavor - flavors = self.flavors_client.list_flavors()['flavors'] - flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor'] - flavor_min_detail = {'id': flavor['id'], 'links': flavor['links'], - 'name': flavor['name']} - self.assertIn(flavor_min_detail, flavors) - - @decorators.idempotent_id('6e85fde4-b3cd-4137-ab72-ed5f418e8c24') - def test_list_flavors_with_detail(self): - # Detailed list of all flavors should contain the expected flavor - flavors = self.flavors_client.list_flavors(detail=True)['flavors'] - flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor'] - self.assertIn(flavor, flavors) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('1f12046b-753d-40d2-abb6-d8eb8b30cb2f') - def test_get_flavor(self): - # The expected flavor details should be returned - flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor'] - self.assertEqual(self.flavor_ref, flavor['id']) - - @decorators.idempotent_id('8d7691b3-6ed4-411a-abc9-2839a765adab') - def test_list_flavors_limit_results(self): - # Only the expected number of flavors should be returned - params = {'limit': 1} - flavors = self.flavors_client.list_flavors(**params)['flavors'] - self.assertEqual(1, len(flavors)) - - @decorators.idempotent_id('b26f6327-2886-467a-82be-cef7a27709cb') - def test_list_flavors_detailed_limit_results(self): - # Only the expected number of flavors (detailed) should be returned - params = {'limit': 1} - flavors = self.flavors_client.list_flavors(detail=True, - **params)['flavors'] - self.assertEqual(1, len(flavors)) - - @decorators.idempotent_id('e800f879-9828-4bd0-8eae-4f17189951fb') - def test_list_flavors_using_marker(self): - # The list of flavors should start from the provided marker - flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor'] - flavor_id = flavor['id'] - - params = {'marker': flavor_id} - flavors = self.flavors_client.list_flavors(**params)['flavors'] - self.assertEmpty([i for i in flavors if i['id'] == flavor_id], - 'The list of flavors did not start after the marker.') - - @decorators.idempotent_id('6db2f0c0-ddee-4162-9c84-0703d3dd1107') - def test_list_flavors_detailed_using_marker(self): - # The list of flavors should start from the provided marker - flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor'] - flavor_id = flavor['id'] - - params = {'marker': flavor_id} - flavors = self.flavors_client.list_flavors(detail=True, - **params)['flavors'] - self.assertEmpty([i for i in flavors if i['id'] == flavor_id], - 'The list of flavors did not start after the marker.') - - @decorators.idempotent_id('3df2743e-3034-4e57-a4cb-b6527f6eac79') - def test_list_flavors_detailed_filter_by_min_disk(self): - # The detailed list of flavors should be filtered by disk space - flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor'] - flavor_id = flavor['id'] - - params = {self._min_disk: flavor['disk'] + 1} - flavors = self.flavors_client.list_flavors(detail=True, - **params)['flavors'] - self.assertEmpty([i for i in flavors if i['id'] == flavor_id]) - - @decorators.idempotent_id('09fe7509-b4ee-4b34-bf8b-39532dc47292') - def test_list_flavors_detailed_filter_by_min_ram(self): - # The detailed list of flavors should be filtered by RAM - flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor'] - flavor_id = flavor['id'] - - params = {self._min_ram: flavor['ram'] + 1} - flavors = self.flavors_client.list_flavors(detail=True, - **params)['flavors'] - self.assertEmpty([i for i in flavors if i['id'] == flavor_id]) - - @decorators.idempotent_id('10645a4d-96f5-443f-831b-730711e11dd4') - def test_list_flavors_filter_by_min_disk(self): - # The list of flavors should be filtered by disk space - flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor'] - flavor_id = flavor['id'] - - params = {self._min_disk: flavor['disk'] + 1} - flavors = self.flavors_client.list_flavors(**params)['flavors'] - self.assertEmpty([i for i in flavors if i['id'] == flavor_id]) - - @decorators.idempotent_id('935cf550-e7c8-4da6-8002-00f92d5edfaa') - def test_list_flavors_filter_by_min_ram(self): - # The list of flavors should be filtered by RAM - flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor'] - flavor_id = flavor['id'] - - params = {self._min_ram: flavor['ram'] + 1} - flavors = self.flavors_client.list_flavors(**params)['flavors'] - self.assertEmpty([i for i in flavors if i['id'] == flavor_id]) diff --git a/tempest/api/compute/flavors/test_flavors_negative.py b/tempest/api/compute/flavors/test_flavors_negative.py deleted file mode 100644 index ebb9d2ec5..000000000 --- a/tempest/api/compute/flavors/test_flavors_negative.py +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright 2017 Red Hat, Inc. -# 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 random - -import six - -from tempest.api.compute import base -from tempest.common import image as common_image -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class FlavorsV2NegativeTest(base.BaseV2ComputeTest): - - @classmethod - def setup_clients(cls): - super(FlavorsV2NegativeTest, cls).setup_clients() - if CONF.image_feature_enabled.api_v1: - cls.images_client = cls.os_primary.image_client - elif CONF.image_feature_enabled.api_v2: - cls.images_client = cls.os_primary.image_client_v2 - else: - raise lib_exc.InvalidConfiguration( - 'Either api_v1 or api_v2 must be True in ' - '[image-feature-enabled].') - - @decorators.attr(type=['negative']) - @test.services('image') - @decorators.idempotent_id('90f0d93a-91c1-450c-91e6-07d18172cefe') - def test_boot_with_low_ram(self): - """Try boot a vm with lower than min ram - - Create an image with min_ram value - Try to create server with flavor of insufficient ram size from - that image - """ - flavor = self.flavors_client.show_flavor( - CONF.compute.flavor_ref)['flavor'] - min_img_ram = flavor['ram'] + 1 - size = random.randint(1024, 4096) - image_file = six.BytesIO(data_utils.random_bytes(size)) - params = { - 'name': data_utils.rand_name('image'), - 'container_format': CONF.image.container_formats[0], - 'disk_format': CONF.image.disk_formats[0], - 'min_ram': min_img_ram - } - - if CONF.image_feature_enabled.api_v1: - params.update({'is_public': False}) - params = {'headers': common_image.image_meta_to_headers(**params)} - else: - params.update({'visibility': 'private'}) - - image = self.images_client.create_image(**params) - image = image['image'] if 'image' in image else image - self.addCleanup(self.images_client.delete_image, image['id']) - - if CONF.image_feature_enabled.api_v1: - self.images_client.update_image(image['id'], data=image_file) - else: - self.images_client.store_image_file(image['id'], data=image_file) - - self.assertEqual(min_img_ram, image['min_ram']) - - # Try to create server with flavor of insufficient ram size - self.assertRaisesRegex(lib_exc.BadRequest, - "Flavor's memory is too small for " - "requested image", - self.create_test_server, - image_id=image['id'], - flavor=flavor['id']) diff --git a/tempest/api/compute/floating_ips/__init__.py b/tempest/api/compute/floating_ips/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/compute/floating_ips/base.py b/tempest/api/compute/floating_ips/base.py deleted file mode 100644 index 142eaec67..000000000 --- a/tempest/api/compute/floating_ips/base.py +++ /dev/null @@ -1,26 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# 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 tempest.api.compute import base - - -class BaseFloatingIPsTest(base.BaseV2ComputeTest): - - @classmethod - def setup_credentials(cls): - # Floating IP actions might need a full network configuration - cls.set_network_resources(network=True, subnet=True, - router=True, dhcp=True) - super(BaseFloatingIPsTest, cls).setup_credentials() diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions.py b/tempest/api/compute/floating_ips/test_floating_ips_actions.py deleted file mode 100644 index faa7b5d92..000000000 --- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py +++ /dev/null @@ -1,148 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 testtools - -from tempest.api.compute.floating_ips import base -from tempest import config -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class FloatingIPsTestJSON(base.BaseFloatingIPsTest): - server_id = None - floating_ip = None - - @classmethod - def skip_checks(cls): - super(FloatingIPsTestJSON, cls).skip_checks() - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - @classmethod - def setup_clients(cls): - super(FloatingIPsTestJSON, cls).setup_clients() - cls.client = cls.floating_ips_client - - @classmethod - def resource_setup(cls): - super(FloatingIPsTestJSON, cls).resource_setup() - cls.floating_ip_id = None - - # Server creation - server = cls.create_test_server(wait_until='ACTIVE') - cls.server_id = server['id'] - # Floating IP creation - body = cls.client.create_floating_ip( - pool=CONF.network.floating_network_name)['floating_ip'] - cls.floating_ip_id = body['id'] - cls.floating_ip = body['ip'] - - @classmethod - def resource_cleanup(cls): - # Deleting the floating IP which is created in this method - if cls.floating_ip_id: - cls.client.delete_floating_ip(cls.floating_ip_id) - super(FloatingIPsTestJSON, cls).resource_cleanup() - - @decorators.idempotent_id('f7bfb946-297e-41b8-9e8c-aba8e9bb5194') - @test.services('network') - def test_allocate_floating_ip(self): - # Positive test:Allocation of a new floating IP to a project - # should be successful - body = self.client.create_floating_ip( - pool=CONF.network.floating_network_name)['floating_ip'] - floating_ip_id_allocated = body['id'] - self.addCleanup(self.client.delete_floating_ip, - floating_ip_id_allocated) - floating_ip_details = self.client.show_floating_ip( - floating_ip_id_allocated)['floating_ip'] - # Checking if the details of allocated IP is in list of floating IP - body = self.client.list_floating_ips()['floating_ips'] - self.assertIn(floating_ip_details, body) - - @decorators.idempotent_id('de45e989-b5ca-4a9b-916b-04a52e7bbb8b') - @test.services('network') - def test_delete_floating_ip(self): - # Positive test:Deletion of valid floating IP from project - # should be successful - # Creating the floating IP that is to be deleted in this method - floating_ip_body = self.client.create_floating_ip( - pool=CONF.network.floating_network_name)['floating_ip'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.client.delete_floating_ip, floating_ip_body['id']) - # Deleting the floating IP from the project - self.client.delete_floating_ip(floating_ip_body['id']) - # Check it was really deleted. - self.client.wait_for_resource_deletion(floating_ip_body['id']) - - @decorators.idempotent_id('307efa27-dc6f-48a0-8cd2-162ce3ef0b52') - @test.services('network') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_associate_disassociate_floating_ip(self): - # Positive test:Associate and disassociate the provided floating IP - # to a specific server should be successful - - # Association of floating IP to fixed IP address - self.client.associate_floating_ip_to_server( - self.floating_ip, - self.server_id) - - # Check instance_id in the floating_ip body - body = (self.client.show_floating_ip(self.floating_ip_id) - ['floating_ip']) - self.assertEqual(self.server_id, body['instance_id']) - - # Disassociation of floating IP that was associated in this method - self.client.disassociate_floating_ip_from_server( - self.floating_ip, - self.server_id) - - @decorators.idempotent_id('6edef4b2-aaf1-4abc-bbe3-993e2561e0fe') - @test.services('network') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_associate_already_associated_floating_ip(self): - # positive test:Association of an already associated floating IP - # to specific server should change the association of the Floating IP - # Create server so as to use for Multiple association - body = self.create_test_server(wait_until='ACTIVE') - self.new_server_id = body['id'] - self.addCleanup(self.servers_client.delete_server, self.new_server_id) - - # Associating floating IP for the first time - self.client.associate_floating_ip_to_server( - self.floating_ip, - self.server_id) - # Associating floating IP for the second time - self.client.associate_floating_ip_to_server( - self.floating_ip, - self.new_server_id) - - self.addCleanup(self.client.disassociate_floating_ip_from_server, - self.floating_ip, - self.new_server_id) - - # Make sure no longer associated with old server - self.assertRaises((lib_exc.NotFound, - lib_exc.UnprocessableEntity, - lib_exc.Conflict), - self.client.disassociate_floating_ip_from_server, - self.floating_ip, self.server_id) diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py b/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py deleted file mode 100644 index 483bd953a..000000000 --- a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py +++ /dev/null @@ -1,133 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 testtools - -from tempest.api.compute.floating_ips import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class FloatingIPsNegativeTestJSON(base.BaseFloatingIPsTest): - - @classmethod - def skip_checks(cls): - super(FloatingIPsNegativeTestJSON, cls).skip_checks() - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - @classmethod - def setup_clients(cls): - super(FloatingIPsNegativeTestJSON, cls).setup_clients() - cls.client = cls.floating_ips_client - - @classmethod - def resource_setup(cls): - super(FloatingIPsNegativeTestJSON, cls).resource_setup() - - # Server creation - server = cls.create_test_server(wait_until='ACTIVE') - cls.server_id = server['id'] - # Generating a nonexistent floatingIP id - body = cls.client.list_floating_ips()['floating_ips'] - floating_ip_ids = [floating_ip['id'] for floating_ip in body] - while True: - if CONF.service_available.neutron: - cls.non_exist_id = data_utils.rand_uuid() - else: - cls.non_exist_id = data_utils.rand_int_id(start=999) - if cls.non_exist_id not in floating_ip_ids: - break - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6e0f059b-e4dd-48fb-8207-06e3bba5b074') - @test.services('network') - def test_allocate_floating_ip_from_nonexistent_pool(self): - # Negative test:Allocation of a new floating IP from a nonexistent_pool - # to a project should fail - self.assertRaises(lib_exc.NotFound, - self.client.create_floating_ip, - pool="non_exist_pool") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ae1c55a8-552b-44d4-bfb6-2a115a15d0ba') - @test.services('network') - def test_delete_nonexistent_floating_ip(self): - # Negative test:Deletion of a nonexistent floating IP - # from project should fail - - # Deleting the non existent floating IP - self.assertRaises(lib_exc.NotFound, self.client.delete_floating_ip, - self.non_exist_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('595fa616-1a71-4670-9614-46564ac49a4c') - @test.services('network') - def test_associate_nonexistent_floating_ip(self): - # Negative test:Association of a non existent floating IP - # to specific server should fail - # Associating non existent floating IP - self.assertRaises(lib_exc.NotFound, - self.client.associate_floating_ip_to_server, - "0.0.0.0", self.server_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0a081a66-e568-4e6b-aa62-9587a876dca8') - @test.services('network') - def test_dissociate_nonexistent_floating_ip(self): - # Negative test:Dissociation of a non existent floating IP should fail - # Dissociating non existent floating IP - self.assertRaises(lib_exc.NotFound, - self.client.disassociate_floating_ip_from_server, - "0.0.0.0", self.server_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('804b4fcb-bbf5-412f-925d-896672b61eb3') - @test.services('network') - def test_associate_ip_to_server_without_passing_floating_ip(self): - # Negative test:Association of empty floating IP to specific server - # should raise NotFound or BadRequest(In case of Nova V2.1) exception. - self.assertRaises((lib_exc.NotFound, lib_exc.BadRequest), - self.client.associate_floating_ip_to_server, - '', self.server_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('58a80596-ffb2-11e6-9393-fa163e4fa634') - @test.services('network') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_associate_ip_to_server_with_floating_ip(self): - # The VM have one port - # Associate floating IP A to the VM - # Associate floating IP B which is from same pool with floating IP A - # to the VM, should raise BadRequest exception - body = self.client.create_floating_ip( - pool=CONF.network.public_network_id)['floating_ip'] - self.addCleanup(self.client.delete_floating_ip, body['id']) - self.client.associate_floating_ip_to_server(body['ip'], self.server_id) - self.addCleanup(self.client.disassociate_floating_ip_from_server, - body['ip'], self.server_id) - - body = self.client.create_floating_ip( - pool=CONF.network.public_network_id)['floating_ip'] - self.addCleanup(self.client.delete_floating_ip, body['id']) - self.assertRaises(lib_exc.BadRequest, - self.client.associate_floating_ip_to_server, - body['ip'], self.server_id) diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips.py b/tempest/api/compute/floating_ips/test_list_floating_ips.py deleted file mode 100644 index 913b992da..000000000 --- a/tempest/api/compute/floating_ips/test_list_floating_ips.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.compute import base -from tempest import config -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class FloatingIPDetailsTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(FloatingIPDetailsTestJSON, cls).skip_checks() - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - @classmethod - def setup_clients(cls): - super(FloatingIPDetailsTestJSON, cls).setup_clients() - cls.client = cls.floating_ips_client - cls.pools_client = cls.floating_ip_pools_client - - @classmethod - def resource_setup(cls): - super(FloatingIPDetailsTestJSON, cls).resource_setup() - cls.floating_ip = [] - cls.floating_ip_id = [] - for _ in range(3): - body = cls.client.create_floating_ip( - pool=CONF.network.floating_network_name)['floating_ip'] - cls.floating_ip.append(body) - cls.floating_ip_id.append(body['id']) - - @classmethod - def resource_cleanup(cls): - for f_id in cls.floating_ip_id: - cls.client.delete_floating_ip(f_id) - super(FloatingIPDetailsTestJSON, cls).resource_cleanup() - - @decorators.idempotent_id('16db31c3-fb85-40c9-bbe2-8cf7b67ff99f') - @test.services('network') - def test_list_floating_ips(self): - # Positive test:Should return the list of floating IPs - body = self.client.list_floating_ips()['floating_ips'] - floating_ips = body - self.assertNotEmpty(floating_ips, - "Expected floating IPs. Got zero.") - for i in range(3): - self.assertIn(self.floating_ip[i], floating_ips) - - @decorators.idempotent_id('eef497e0-8ff7-43c8-85ef-558440574f84') - @test.services('network') - def test_get_floating_ip_details(self): - # Positive test:Should be able to GET the details of floatingIP - # Creating a floating IP for which details are to be checked - body = self.client.create_floating_ip( - pool=CONF.network.floating_network_name)['floating_ip'] - floating_ip_id = body['id'] - self.addCleanup(self.client.delete_floating_ip, - floating_ip_id) - floating_ip_instance_id = body['instance_id'] - floating_ip_ip = body['ip'] - floating_ip_fixed_ip = body['fixed_ip'] - body = self.client.show_floating_ip(floating_ip_id)['floating_ip'] - # Comparing the details of floating IP - self.assertEqual(floating_ip_instance_id, - body['instance_id']) - self.assertEqual(floating_ip_ip, body['ip']) - self.assertEqual(floating_ip_fixed_ip, - body['fixed_ip']) - self.assertEqual(floating_ip_id, body['id']) - - @decorators.idempotent_id('df389fc8-56f5-43cc-b290-20eda39854d3') - @test.services('network') - def test_list_floating_ip_pools(self): - # Positive test:Should return the list of floating IP Pools - floating_ip_pools = self.pools_client.list_floating_ip_pools() - self.assertNotEmpty(floating_ip_pools['floating_ip_pools'], - "Expected floating IP Pools. Got zero.") diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py b/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py deleted file mode 100644 index b5bbb8c69..000000000 --- a/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.compute import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class FloatingIPDetailsNegativeTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(FloatingIPDetailsNegativeTestJSON, cls).skip_checks() - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - @classmethod - def setup_clients(cls): - super(FloatingIPDetailsNegativeTestJSON, cls).setup_clients() - cls.client = cls.floating_ips_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7ab18834-4a4b-4f28-a2c5-440579866695') - @test.services('network') - def test_get_nonexistent_floating_ip_details(self): - # Negative test:Should not be able to GET the details - # of non-existent floating IP - # Creating a non-existent floatingIP id - if CONF.service_available.neutron: - non_exist_id = data_utils.rand_uuid() - else: - non_exist_id = data_utils.rand_int_id(start=999) - self.assertRaises(lib_exc.NotFound, - self.client.show_floating_ip, non_exist_id) diff --git a/tempest/api/compute/images/__init__.py b/tempest/api/compute/images/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/compute/images/test_image_metadata.py b/tempest/api/compute/images/test_image_metadata.py deleted file mode 100644 index 8d503dcb3..000000000 --- a/tempest/api/compute/images/test_image_metadata.py +++ /dev/null @@ -1,144 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 six - -from tempest.api.compute import base -from tempest.common import image as common_image -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions - -CONF = config.CONF - - -class ImagesMetadataTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(ImagesMetadataTestJSON, cls).skip_checks() - if not CONF.service_available.glance: - skip_msg = ("%s skipped as glance is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(ImagesMetadataTestJSON, cls).setup_clients() - # Check if glance v1 is available to determine which client to use. We - # prefer glance v1 for the compute API tests since the compute image - # API proxy was written for glance v1. - if CONF.image_feature_enabled.api_v1: - cls.glance_client = cls.os_primary.image_client - elif CONF.image_feature_enabled.api_v2: - cls.glance_client = cls.os_primary.image_client_v2 - else: - raise exceptions.InvalidConfiguration( - 'Either api_v1 or api_v2 must be True in ' - '[image-feature-enabled].') - cls.client = cls.compute_images_client - - @classmethod - def resource_setup(cls): - super(ImagesMetadataTestJSON, cls).resource_setup() - cls.image_id = None - - params = { - 'name': data_utils.rand_name('image'), - 'container_format': 'bare', - 'disk_format': 'raw' - } - if CONF.image_feature_enabled.api_v1: - params.update({'is_public': False}) - params = {'headers': common_image.image_meta_to_headers(**params)} - else: - params.update({'visibility': 'private'}) - - body = cls.glance_client.create_image(**params) - body = body['image'] if 'image' in body else body - cls.image_id = body['id'] - cls.images.append(cls.image_id) - image_file = six.BytesIO((b'*' * 1024)) - if CONF.image_feature_enabled.api_v1: - cls.glance_client.update_image(cls.image_id, data=image_file) - else: - cls.glance_client.store_image_file(cls.image_id, data=image_file) - waiters.wait_for_image_status(cls.client, cls.image_id, 'ACTIVE') - - def setUp(self): - super(ImagesMetadataTestJSON, self).setUp() - meta = {'os_version': 'value1', 'os_distro': 'value2'} - self.client.set_image_metadata(self.image_id, meta) - - @decorators.idempotent_id('37ec6edd-cf30-4c53-bd45-ae74db6b0531') - def test_list_image_metadata(self): - # All metadata key/value pairs for an image should be returned - resp_metadata = self.client.list_image_metadata(self.image_id) - expected = {'metadata': { - 'os_version': 'value1', 'os_distro': 'value2'}} - self.assertEqual(expected, resp_metadata) - - @decorators.idempotent_id('ece7befc-d3ce-42a4-b4be-c3067a418c29') - def test_set_image_metadata(self): - # The metadata for the image should match the new values - req_metadata = {'os_version': 'value2', 'architecture': 'value3'} - self.client.set_image_metadata(self.image_id, - req_metadata) - - resp_metadata = (self.client.list_image_metadata(self.image_id) - ['metadata']) - self.assertEqual(req_metadata, resp_metadata) - - @decorators.idempotent_id('7b491c11-a9d5-40fe-a696-7f7e03d3fea2') - def test_update_image_metadata(self): - # The metadata for the image should match the updated values - req_metadata = {'os_version': 'alt1', 'architecture': 'value3'} - self.client.update_image_metadata(self.image_id, - req_metadata) - - resp_metadata = self.client.list_image_metadata(self.image_id) - expected = {'metadata': { - 'os_version': 'alt1', - 'os_distro': 'value2', - 'architecture': 'value3'}} - self.assertEqual(expected, resp_metadata) - - @decorators.idempotent_id('4f5db52f-6685-4c75-b848-f4bb363f9aa6') - def test_get_image_metadata_item(self): - # The value for a specific metadata key should be returned - meta = self.client.show_image_metadata_item(self.image_id, - 'os_distro')['meta'] - self.assertEqual('value2', meta['os_distro']) - - @decorators.idempotent_id('f2de776a-4778-4d90-a5da-aae63aee64ae') - def test_set_image_metadata_item(self): - # The value provided for the given meta item should be set for - # the image - meta = {'os_version': 'alt'} - self.client.set_image_metadata_item(self.image_id, - 'os_version', meta) - resp_metadata = self.client.list_image_metadata(self.image_id) - expected = {'metadata': {'os_version': 'alt', 'os_distro': 'value2'}} - self.assertEqual(expected, resp_metadata) - - @decorators.idempotent_id('a013796c-ba37-4bb5-8602-d944511def14') - def test_delete_image_metadata_item(self): - # The metadata value/key pair should be deleted from the image - self.client.delete_image_metadata_item(self.image_id, - 'os_version') - resp_metadata = self.client.list_image_metadata(self.image_id) - expected = {'metadata': {'os_distro': 'value2'}} - self.assertEqual(expected, resp_metadata) diff --git a/tempest/api/compute/images/test_image_metadata_negative.py b/tempest/api/compute/images/test_image_metadata_negative.py deleted file mode 100644 index 03d078940..000000000 --- a/tempest/api/compute/images/test_image_metadata_negative.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 tempest.api.compute import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ImagesMetadataNegativeTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_clients(cls): - super(ImagesMetadataNegativeTestJSON, cls).setup_clients() - cls.client = cls.compute_images_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('94069db2-792f-4fa8-8bd3-2271a6e0c095') - def test_list_nonexistent_image_metadata(self): - # Negative test: List on nonexistent image - # metadata should not happen - self.assertRaises(lib_exc.NotFound, self.client.list_image_metadata, - data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a403ef9e-9f95-427c-b70a-3ce3388796f1') - def test_update_nonexistent_image_metadata(self): - # Negative test:An update should not happen for a non-existent image - meta = {'os_distro': 'alt1', 'os_version': 'alt2'} - self.assertRaises(lib_exc.NotFound, - self.client.update_image_metadata, - data_utils.rand_uuid(), meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('41ae052c-6ee6-405c-985e-5712393a620d') - def test_get_nonexistent_image_metadata_item(self): - # Negative test: Get on non-existent image should not happen - self.assertRaises(lib_exc.NotFound, - self.client.show_image_metadata_item, - data_utils.rand_uuid(), 'os_version') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('dc64f2ce-77e8-45b0-88c8-e15041d08eaf') - def test_set_nonexistent_image_metadata(self): - # Negative test: Metadata should not be set to a non-existent image - meta = {'os_distro': 'alt1', 'os_version': 'alt2'} - self.assertRaises(lib_exc.NotFound, self.client.set_image_metadata, - data_utils.rand_uuid(), meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('2154fd03-ab54-457c-8874-e6e3eb56e9cf') - def test_set_nonexistent_image_metadata_item(self): - # Negative test: Metadata item should not be set to a - # nonexistent image - meta = {'os_distro': 'alt'} - self.assertRaises(lib_exc.NotFound, - self.client.set_image_metadata_item, - data_utils.rand_uuid(), 'os_distro', - meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('848e157f-6bcf-4b2e-a5dd-5124025a8518') - def test_delete_nonexistent_image_metadata_item(self): - # Negative test: Shouldn't be able to delete metadata - # item from non-existent image - self.assertRaises(lib_exc.NotFound, - self.client.delete_image_metadata_item, - data_utils.rand_uuid(), 'os_distro') diff --git a/tempest/api/compute/images/test_images.py b/tempest/api/compute/images/test_images.py deleted file mode 100644 index 29bd6dae1..000000000 --- a/tempest/api/compute/images/test_images.py +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# -# 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 tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -import testtools - -CONF = config.CONF - - -class ImagesTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(ImagesTestJSON, cls).skip_checks() - if not CONF.service_available.glance: - skip_msg = ("%s skipped as glance is not available" % cls.__name__) - raise cls.skipException(skip_msg) - if not CONF.compute_feature_enabled.snapshot: - skip_msg = ("%s skipped as instance snapshotting is not supported" - % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(ImagesTestJSON, cls).setup_clients() - cls.client = cls.compute_images_client - - @decorators.idempotent_id('aa06b52b-2db5-4807-b218-9441f75d74e3') - def test_delete_saving_image(self): - server = self.create_test_server(wait_until='ACTIVE') - self.addCleanup(self.servers_client.delete_server, server['id']) - image = self.create_image_from_server(server['id'], - wait_until='SAVING') - self.client.delete_image(image['id']) - msg = ('The image with ID {image_id} failed to be deleted' - .format(image_id=image['id'])) - self.assertTrue(self.client.is_resource_deleted(image['id']), msg) - - @decorators.idempotent_id('aaacd1d0-55a2-4ce8-818a-b5439df8adc9') - def test_create_image_from_stopped_server(self): - server = self.create_test_server(wait_until='ACTIVE') - self.servers_client.stop_server(server['id']) - waiters.wait_for_server_status(self.servers_client, - server['id'], 'SHUTOFF') - self.addCleanup(self.servers_client.delete_server, server['id']) - snapshot_name = data_utils.rand_name('test-snap') - image = self.create_image_from_server(server['id'], - name=snapshot_name, - wait_until='ACTIVE', - wait_for_server=False) - self.addCleanup(self.client.delete_image, image['id']) - self.assertEqual(snapshot_name, image['name']) - - @decorators.idempotent_id('71bcb732-0261-11e7-9086-fa163e4fa634') - @testtools.skipUnless(CONF.compute_feature_enabled.pause, - 'Pause is not available.') - def test_create_image_from_paused_server(self): - server = self.create_test_server(wait_until='ACTIVE') - self.servers_client.pause_server(server['id']) - waiters.wait_for_server_status(self.servers_client, - server['id'], 'PAUSED') - self.addCleanup(self.servers_client.delete_server, server['id']) - - snapshot_name = data_utils.rand_name('test-snap') - image = self.create_image_from_server(server['id'], - name=snapshot_name, - wait_until='ACTIVE', - wait_for_server=False) - self.addCleanup(self.client.delete_image, image['id']) - self.assertEqual(snapshot_name, image['name']) - - @decorators.idempotent_id('8ca07fec-0262-11e7-907e-fa163e4fa634') - @testtools.skipUnless(CONF.compute_feature_enabled.suspend, - 'Suspend is not available.') - def test_create_image_from_suspended_server(self): - server = self.create_test_server(wait_until='ACTIVE') - self.servers_client.suspend_server(server['id']) - waiters.wait_for_server_status(self.servers_client, - server['id'], 'SUSPENDED') - self.addCleanup(self.servers_client.delete_server, server['id']) - - snapshot_name = data_utils.rand_name('test-snap') - image = self.create_image_from_server(server['id'], - name=snapshot_name, - wait_until='ACTIVE', - wait_for_server=False) - self.addCleanup(self.client.delete_image, image['id']) - self.assertEqual(snapshot_name, image['name']) diff --git a/tempest/api/compute/images/test_images_negative.py b/tempest/api/compute/images/test_images_negative.py deleted file mode 100644 index e29238968..000000000 --- a/tempest/api/compute/images/test_images_negative.py +++ /dev/null @@ -1,127 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# -# 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 tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class ImagesNegativeTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(ImagesNegativeTestJSON, cls).skip_checks() - if not CONF.service_available.glance: - skip_msg = ("%s skipped as glance is not available" % cls.__name__) - raise cls.skipException(skip_msg) - if not CONF.compute_feature_enabled.snapshot: - skip_msg = ("%s skipped as instance snapshotting is not supported" - % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(ImagesNegativeTestJSON, cls).setup_clients() - cls.client = cls.compute_images_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6cd5a89d-5b47-46a7-93bc-3916f0d84973') - def test_create_image_from_deleted_server(self): - # An image should not be created if the server instance is removed - server = self.create_test_server(wait_until='ACTIVE') - - # Delete server before trying to create image - self.servers_client.delete_server(server['id']) - waiters.wait_for_server_termination(self.servers_client, server['id']) - # Create a new image after server is deleted - meta = {'image_type': 'test'} - self.assertRaises(lib_exc.NotFound, - self.create_image_from_server, - server['id'], metadata=meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('82c5b0c4-9dbd-463c-872b-20c4755aae7f') - def test_create_image_from_invalid_server(self): - # An image should not be created with invalid server id - # Create a new image with invalid server id - meta = {'image_type': 'test'} - self.assertRaises(lib_exc.NotFound, self.create_image_from_server, - data_utils.rand_name('invalid'), metadata=meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ec176029-73dc-4037-8d72-2e4ff60cf538') - def test_create_image_specify_uuid_35_characters_or_less(self): - # Return an error if Image ID passed is 35 characters or less - snapshot_name = data_utils.rand_name('test-snap') - test_uuid = ('a' * 35) - self.assertRaises(lib_exc.NotFound, self.client.create_image, - test_uuid, name=snapshot_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('36741560-510e-4cc2-8641-55fe4dfb2437') - def test_create_image_specify_uuid_37_characters_or_more(self): - # Return an error if Image ID passed is 37 characters or more - snapshot_name = data_utils.rand_name('test-snap') - test_uuid = ('a' * 37) - self.assertRaises(lib_exc.NotFound, self.client.create_image, - test_uuid, name=snapshot_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('381acb65-785a-4942-94ce-d8f8c84f1f0f') - def test_delete_image_with_invalid_image_id(self): - # An image should not be deleted with invalid image id - self.assertRaises(lib_exc.NotFound, self.client.delete_image, - data_utils.rand_name('invalid')) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('137aef61-39f7-44a1-8ddf-0adf82511701') - def test_delete_non_existent_image(self): - # Return an error while trying to delete a non-existent image - - non_existent_image_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.delete_image, - non_existent_image_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e6e41425-af5c-4fe6-a4b5-7b7b963ffda5') - def test_delete_image_blank_id(self): - # Return an error while trying to delete an image with blank Id - self.assertRaises(lib_exc.NotFound, self.client.delete_image, '') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('924540c3-f1f1-444c-8f58-718958b6724e') - def test_delete_image_non_hex_string_id(self): - # Return an error while trying to delete an image with non hex id - invalid_image_id = data_utils.rand_uuid()[:-1] + "j" - self.assertRaises(lib_exc.NotFound, self.client.delete_image, - invalid_image_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('68e2c175-bd26-4407-ac0f-4ea9ce2139ea') - def test_delete_image_negative_image_id(self): - # Return an error while trying to delete an image with negative id - self.assertRaises(lib_exc.NotFound, self.client.delete_image, -1) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('b340030d-82cd-4066-a314-c72fb7c59277') - def test_delete_image_with_id_over_character_limit(self): - # Return an error while trying to delete image with id over limit - invalid_image_id = data_utils.rand_uuid() + "1" - self.assertRaises(lib_exc.NotFound, self.client.delete_image, - invalid_image_id) diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py deleted file mode 100644 index 5987d39f0..000000000 --- a/tempest/api/compute/images/test_images_oneserver.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.compute import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class ImagesOneServerTestJSON(base.BaseV2ComputeTest): - - @classmethod - def resource_setup(cls): - super(ImagesOneServerTestJSON, cls).resource_setup() - cls.server_id = cls.create_test_server(wait_until='ACTIVE')['id'] - - @classmethod - def skip_checks(cls): - super(ImagesOneServerTestJSON, cls).skip_checks() - if not CONF.service_available.glance: - skip_msg = ("%s skipped as glance is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - if not CONF.compute_feature_enabled.snapshot: - skip_msg = ("%s skipped as instance snapshotting is not supported" - % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(ImagesOneServerTestJSON, cls).setup_clients() - cls.client = cls.compute_images_client - - def _get_default_flavor_disk_size(self, flavor_id): - flavor = self.flavors_client.show_flavor(flavor_id)['flavor'] - return flavor['disk'] - - @decorators.idempotent_id('3731d080-d4c5-4872-b41a-64d0d0021314') - def test_create_delete_image(self): - # Create a new image - name = data_utils.rand_name('image') - meta = {'image_type': 'test'} - image = self.create_image_from_server(self.server_id, name=name, - metadata=meta, - wait_until='ACTIVE') - - # Verify the image was created correctly - self.assertEqual(name, image['name']) - self.assertEqual('test', image['metadata']['image_type']) - - original_image = self.client.show_image(self.image_ref)['image'] - - # Verify minRAM is the same as the original image - self.assertEqual(image['minRam'], original_image['minRam']) - - # Verify minDisk is the same as the original image or the flavor size - flavor_disk_size = self._get_default_flavor_disk_size(self.flavor_ref) - self.assertIn(str(image['minDisk']), - (str(original_image['minDisk']), str(flavor_disk_size))) - - # Verify the image was deleted correctly - self.client.delete_image(image['id']) - self.images.remove(image['id']) - self.client.wait_for_resource_deletion(image['id']) - - @decorators.idempotent_id('3b7c6fe4-dfe7-477c-9243-b06359db51e6') - def test_create_image_specify_multibyte_character_image_name(self): - # prefix character is: - # http://unicode.org/cldr/utility/character.jsp?a=20A1 - - # We use a string with 3 byte utf-8 character due to nova/glance which - # will return 400(Bad Request) if we attempt to send a name which has - # 4 byte utf-8 character. - utf8_name = data_utils.rand_name(b'\xe2\x82\xa1'.decode('utf-8')) - body = self.client.create_image(self.server_id, name=utf8_name) - image_id = data_utils.parse_image_id(body.response['location']) - self.addCleanup(self.client.delete_image, image_id) diff --git a/tempest/api/compute/images/test_images_oneserver_negative.py b/tempest/api/compute/images/test_images_oneserver_negative.py deleted file mode 100644 index cf32ba3ef..000000000 --- a/tempest/api/compute/images/test_images_oneserver_negative.py +++ /dev/null @@ -1,135 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# Copyright 2013 IBM 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 oslo_log import log as logging - -from tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - -LOG = logging.getLogger(__name__) - - -class ImagesOneServerNegativeTestJSON(base.BaseV2ComputeTest): - - def tearDown(self): - """Terminate test instances created after a test is executed.""" - self.server_check_teardown() - super(ImagesOneServerNegativeTestJSON, self).tearDown() - - def setUp(self): - # NOTE(afazekas): Normally we use the same server with all test cases, - # but if it has an issue, we build a new one - super(ImagesOneServerNegativeTestJSON, self).setUp() - # Check if the server is in a clean state after test - try: - waiters.wait_for_server_status(self.servers_client, self.server_id, - 'ACTIVE') - except Exception: - LOG.exception('server %s timed out to become ACTIVE. rebuilding', - self.server_id) - # Rebuild server if cannot reach the ACTIVE state - # Usually it means the server had a serious accident - self._reset_server() - - def _reset_server(self): - self.__class__.server_id = self.rebuild_server(self.server_id) - - @classmethod - def skip_checks(cls): - super(ImagesOneServerNegativeTestJSON, cls).skip_checks() - if not CONF.service_available.glance: - skip_msg = ("%s skipped as glance is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - if not CONF.compute_feature_enabled.snapshot: - skip_msg = ("%s skipped as instance snapshotting is not supported" - % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(ImagesOneServerNegativeTestJSON, cls).setup_clients() - cls.client = cls.compute_images_client - - @classmethod - def resource_setup(cls): - super(ImagesOneServerNegativeTestJSON, cls).resource_setup() - server = cls.create_test_server(wait_until='ACTIVE') - cls.server_id = server['id'] - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('55d1d38c-dd66-4933-9c8e-7d92aeb60ddc') - def test_create_image_specify_invalid_metadata(self): - # Return an error when creating image with invalid metadata - meta = {'': ''} - self.assertRaises(lib_exc.BadRequest, self.create_image_from_server, - self.server_id, metadata=meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('3d24d11f-5366-4536-bd28-cff32b748eca') - def test_create_image_specify_metadata_over_limits(self): - # Return an error when creating image with meta data over 255 chars - meta = {'a' * 256: 'b' * 256} - self.assertRaises(lib_exc.BadRequest, self.create_image_from_server, - self.server_id, metadata=meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0460efcf-ee88-4f94-acef-1bf658695456') - def test_create_second_image_when_first_image_is_being_saved(self): - # Disallow creating another image when first image is being saved - - # Create first snapshot - image = self.create_image_from_server(self.server_id) - self.addCleanup(self._reset_server) - - # Create second snapshot - self.assertRaises(lib_exc.Conflict, self.create_image_from_server, - self.server_id) - - image_id = data_utils.parse_image_id(image.response['location']) - self.client.delete_image(image_id) - self.images.remove(image_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('084f0cbc-500a-4963-8a4e-312905862581') - def test_create_image_specify_name_over_character_limit(self): - # Return an error if snapshot name over 255 characters is passed - - snapshot_name = ('a' * 256) - self.assertRaises(lib_exc.BadRequest, self.client.create_image, - self.server_id, name=snapshot_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0894954d-2db2-4195-a45b-ffec0bc0187e') - def test_delete_image_that_is_not_yet_active(self): - # Return an error while trying to delete an image what is creating - - image = self.create_image_from_server(self.server_id) - image_id = data_utils.parse_image_id(image.response['location']) - - self.addCleanup(self._reset_server) - - # Do not wait, attempt to delete the image, ensure it's successful - self.client.delete_image(image_id) - self.images.remove(image_id) - self.assertRaises(lib_exc.NotFound, - self.client.show_image, image_id) diff --git a/tempest/api/compute/images/test_list_image_filters.py b/tempest/api/compute/images/test_list_image_filters.py deleted file mode 100644 index acc8b3e29..000000000 --- a/tempest/api/compute/images/test_list_image_filters.py +++ /dev/null @@ -1,290 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 time - -import six -import testtools - -from tempest.api.compute import base -from tempest.common import image as common_image -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions - -CONF = config.CONF - - -class ListImageFiltersTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(ListImageFiltersTestJSON, cls).skip_checks() - if not CONF.service_available.glance: - skip_msg = ("%s skipped as glance is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(ListImageFiltersTestJSON, cls).setup_clients() - cls.client = cls.compute_images_client - # Check if glance v1 is available to determine which client to use. We - # prefer glance v1 for the compute API tests since the compute image - # API proxy was written for glance v1. - if CONF.image_feature_enabled.api_v1: - cls.glance_client = cls.os_primary.image_client - elif CONF.image_feature_enabled.api_v2: - cls.glance_client = cls.os_primary.image_client_v2 - else: - raise exceptions.InvalidConfiguration( - 'Either api_v1 or api_v2 must be True in ' - '[image-feature-enabled].') - - @classmethod - def resource_setup(cls): - super(ListImageFiltersTestJSON, cls).resource_setup() - - def _create_image(): - params = { - 'name': data_utils.rand_name(cls.__name__ + '-image'), - 'container_format': 'bare', - 'disk_format': 'raw' - } - if CONF.image_feature_enabled.api_v1: - params.update({'is_public': False}) - params = {'headers': - common_image.image_meta_to_headers(**params)} - else: - params.update({'visibility': 'private'}) - - body = cls.glance_client.create_image(**params) - body = body['image'] if 'image' in body else body - image_id = body['id'] - cls.images.append(image_id) - # Wait 1 second between creation and upload to ensure a delta - # between created_at and updated_at. - time.sleep(1) - image_file = six.BytesIO((b'*' * 1024)) - if CONF.image_feature_enabled.api_v1: - cls.glance_client.update_image(image_id, data=image_file) - else: - cls.glance_client.store_image_file(image_id, data=image_file) - waiters.wait_for_image_status(cls.client, image_id, 'ACTIVE') - body = cls.client.show_image(image_id)['image'] - return body - - # Create non-snapshot images via glance - cls.image1 = _create_image() - cls.image1_id = cls.image1['id'] - cls.image2 = _create_image() - cls.image2_id = cls.image2['id'] - cls.image3 = _create_image() - cls.image3_id = cls.image3['id'] - - if not CONF.compute_feature_enabled.snapshot: - return - - # Create instances and snapshots via nova - cls.server1 = cls.create_test_server() - cls.server2 = cls.create_test_server(wait_until='ACTIVE') - # NOTE(sdague) this is faster than doing the sync wait_util on both - waiters.wait_for_server_status(cls.servers_client, - cls.server1['id'], 'ACTIVE') - - # Create images to be used in the filter tests - cls.snapshot1 = cls.create_image_from_server( - cls.server1['id'], wait_until='ACTIVE') - cls.snapshot1_id = cls.snapshot1['id'] - - # Servers have a hidden property for when they are being imaged - # Performing back-to-back create image calls on a single - # server will sometimes cause failures - cls.snapshot3 = cls.create_image_from_server( - cls.server2['id'], wait_until='ACTIVE') - cls.snapshot3_id = cls.snapshot3['id'] - - # Wait for the server to be active after the image upload - cls.snapshot2 = cls.create_image_from_server( - cls.server1['id'], wait_until='ACTIVE') - cls.snapshot2_id = cls.snapshot2['id'] - - @decorators.idempotent_id('a3f5b513-aeb3-42a9-b18e-f091ef73254d') - def test_list_images_filter_by_status(self): - # The list of images should contain only images with the - # provided status - params = {'status': 'ACTIVE'} - images = self.client.list_images(**params)['images'] - - self.assertNotEmpty([i for i in images if i['id'] == self.image1_id]) - self.assertNotEmpty([i for i in images if i['id'] == self.image2_id]) - self.assertNotEmpty([i for i in images if i['id'] == self.image3_id]) - - @decorators.idempotent_id('33163b73-79f5-4d07-a7ea-9213bcc468ff') - def test_list_images_filter_by_name(self): - # List of all images should contain the expected images filtered - # by name - params = {'name': self.image1['name']} - images = self.client.list_images(**params)['images'] - - self.assertNotEmpty([i for i in images if i['id'] == self.image1_id]) - self.assertEmpty([i for i in images if i['id'] == self.image2_id]) - self.assertEmpty([i for i in images if i['id'] == self.image3_id]) - - @decorators.idempotent_id('9f238683-c763-45aa-b848-232ec3ce3105') - @testtools.skipUnless(CONF.compute_feature_enabled.snapshot, - 'Snapshotting is not available.') - def test_list_images_filter_by_server_id(self): - # The images should contain images filtered by server id - params = {'server': self.server1['id']} - images = self.client.list_images(**params)['images'] - - self.assertNotEmpty([i for i in images - if i['id'] == self.snapshot1_id], - "Failed to find image %s in images. " - "Got images %s" % (self.image1_id, images)) - self.assertNotEmpty([i for i in images - if i['id'] == self.snapshot2_id]) - self.assertEmpty([i for i in images if i['id'] == self.snapshot3_id]) - - @decorators.idempotent_id('05a377b8-28cf-4734-a1e6-2ab5c38bf606') - @testtools.skipUnless(CONF.compute_feature_enabled.snapshot, - 'Snapshotting is not available.') - def test_list_images_filter_by_server_ref(self): - # The list of servers should be filtered by server ref - server_links = self.server2['links'] - - # Try all server link types - for link in server_links: - params = {'server': link['href']} - images = self.client.list_images(**params)['images'] - - self.assertEmpty([i for i in images - if i['id'] == self.snapshot1_id]) - self.assertEmpty([i for i in images - if i['id'] == self.snapshot2_id]) - self.assertNotEmpty([i for i in images - if i['id'] == self.snapshot3_id]) - - @decorators.idempotent_id('e3356918-4d3e-4756-81d5-abc4524ba29f') - @testtools.skipUnless(CONF.compute_feature_enabled.snapshot, - 'Snapshotting is not available.') - def test_list_images_filter_by_type(self): - # The list of servers should be filtered by image type - params = {'type': 'snapshot'} - images = self.client.list_images(**params)['images'] - - self.assertNotEmpty([i for i in images - if i['id'] == self.snapshot1_id]) - self.assertNotEmpty([i for i in images - if i['id'] == self.snapshot2_id]) - self.assertNotEmpty([i for i in images - if i['id'] == self.snapshot3_id]) - self.assertEmpty([i for i in images if i['id'] == self.image_ref]) - - @decorators.idempotent_id('3a484ca9-67ba-451e-b494-7fcf28d32d62') - def test_list_images_limit_results(self): - # Verify only the expected number of results are returned - params = {'limit': '1'} - images = self.client.list_images(**params)['images'] - self.assertEqual(1, len([x for x in images if 'id' in x])) - - @decorators.idempotent_id('18bac3ae-da27-436c-92a9-b22474d13aab') - def test_list_images_filter_by_changes_since(self): - # Verify only updated images are returned in the detailed list - - # Becoming ACTIVE will modify the updated time - # Filter by the image's created time - params = {'changes-since': self.image3['created']} - images = self.client.list_images(**params)['images'] - found = [i for i in images if i['id'] == self.image3_id] - self.assertNotEmpty(found) - - @decorators.idempotent_id('9b0ea018-6185-4f71-948a-a123a107988e') - def test_list_images_with_detail_filter_by_status(self): - # Detailed list of all images should only contain images - # with the provided status - params = {'status': 'ACTIVE'} - images = self.client.list_images(detail=True, **params)['images'] - - self.assertNotEmpty([i for i in images if i['id'] == self.image1_id]) - self.assertNotEmpty([i for i in images if i['id'] == self.image2_id]) - self.assertNotEmpty([i for i in images if i['id'] == self.image3_id]) - - @decorators.idempotent_id('644ea267-9bd9-4f3b-af9f-dffa02396a17') - def test_list_images_with_detail_filter_by_name(self): - # Detailed list of all images should contain the expected - # images filtered by name - params = {'name': self.image1['name']} - images = self.client.list_images(detail=True, **params)['images'] - - self.assertNotEmpty([i for i in images if i['id'] == self.image1_id]) - self.assertEmpty([i for i in images if i['id'] == self.image2_id]) - self.assertEmpty([i for i in images if i['id'] == self.image3_id]) - - @decorators.idempotent_id('ba2fa9a9-b672-47cc-b354-3b4c0600e2cb') - def test_list_images_with_detail_limit_results(self): - # Verify only the expected number of results (with full details) - # are returned - params = {'limit': '1'} - images = self.client.list_images(detail=True, **params)['images'] - self.assertEqual(1, len(images)) - - @decorators.idempotent_id('8c78f822-203b-4bf6-8bba-56ebd551cf84') - @testtools.skipUnless(CONF.compute_feature_enabled.snapshot, - 'Snapshotting is not available.') - def test_list_images_with_detail_filter_by_server_ref(self): - # Detailed list of servers should be filtered by server ref - server_links = self.server2['links'] - - # Try all server link types - for link in server_links: - params = {'server': link['href']} - images = self.client.list_images(detail=True, **params)['images'] - - self.assertEmpty([i for i in images - if i['id'] == self.snapshot1_id]) - self.assertEmpty([i for i in images - if i['id'] == self.snapshot2_id]) - self.assertNotEmpty([i for i in images - if i['id'] == self.snapshot3_id]) - - @decorators.idempotent_id('888c0cc0-7223-43c5-9db0-b125fd0a393b') - @testtools.skipUnless(CONF.compute_feature_enabled.snapshot, - 'Snapshotting is not available.') - def test_list_images_with_detail_filter_by_type(self): - # The detailed list of servers should be filtered by image type - params = {'type': 'snapshot'} - images = self.client.list_images(detail=True, **params)['images'] - self.client.show_image(self.image_ref) - - self.assertNotEmpty([i for i in images - if i['id'] == self.snapshot1_id]) - self.assertNotEmpty([i for i in images - if i['id'] == self.snapshot2_id]) - self.assertNotEmpty([i for i in images - if i['id'] == self.snapshot3_id]) - self.assertEmpty([i for i in images if i['id'] == self.image_ref]) - - @decorators.idempotent_id('7d439e18-ac2e-4827-b049-7e18004712c4') - def test_list_images_with_detail_filter_by_changes_since(self): - # Verify an update image is returned - - # Becoming ACTIVE will modify the updated time - # Filter by the image's created time - params = {'changes-since': self.image1['created']} - images = self.client.list_images(detail=True, **params)['images'] - self.assertNotEmpty([i for i in images if i['id'] == self.image1_id]) diff --git a/tempest/api/compute/images/test_list_image_filters_negative.py b/tempest/api/compute/images/test_list_image_filters_negative.py deleted file mode 100644 index d37f8fc80..000000000 --- a/tempest/api/compute/images/test_list_image_filters_negative.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 tempest.api.compute import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class ListImageFiltersNegativeTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(ListImageFiltersNegativeTestJSON, cls).skip_checks() - if not CONF.service_available.glance: - skip_msg = ("%s skipped as glance is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(ListImageFiltersNegativeTestJSON, cls).setup_clients() - cls.client = cls.compute_images_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('391b0440-432c-4d4b-b5da-c5096aa247eb') - def test_get_nonexistent_image(self): - # Check raises a NotFound - nonexistent_image = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.show_image, - nonexistent_image) diff --git a/tempest/api/compute/images/test_list_images.py b/tempest/api/compute/images/test_list_images.py deleted file mode 100644 index e2dbd72f3..000000000 --- a/tempest/api/compute/images/test_list_images.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.compute import base -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class ListImagesTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(ListImagesTestJSON, cls).skip_checks() - if not CONF.service_available.glance: - skip_msg = ("%s skipped as glance is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(ListImagesTestJSON, cls).setup_clients() - cls.client = cls.compute_images_client - - @decorators.idempotent_id('490d0898-e12a-463f-aef0-c50156b9f789') - def test_get_image(self): - # Returns the correct details for a single image - image = self.client.show_image(self.image_ref)['image'] - self.assertEqual(self.image_ref, image['id']) - - @decorators.idempotent_id('fd51b7f4-d4a3-4331-9885-866658112a6f') - def test_list_images(self): - # The list of all images should contain the image - images = self.client.list_images()['images'] - found = [i for i in images if i['id'] == self.image_ref] - self.assertNotEmpty(found) - - @decorators.idempotent_id('9f94cb6b-7f10-48c5-b911-a0b84d7d4cd6') - def test_list_images_with_detail(self): - # Detailed list of all images should contain the expected images - images = self.client.list_images(detail=True)['images'] - found = [i for i in images if i['id'] == self.image_ref] - self.assertNotEmpty(found) diff --git a/tempest/api/compute/keypairs/__init__.py b/tempest/api/compute/keypairs/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/compute/keypairs/base.py b/tempest/api/compute/keypairs/base.py deleted file mode 100644 index 005181064..000000000 --- a/tempest/api/compute/keypairs/base.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2015 Deutsche Telekom AG -# 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 tempest.api.compute import base -from tempest.lib.common.utils import data_utils - - -class BaseKeypairTest(base.BaseV2ComputeTest): - """Base test case class for all keypair API tests.""" - - @classmethod - def setup_clients(cls): - super(BaseKeypairTest, cls).setup_clients() - cls.client = cls.keypairs_client - - def _delete_keypair(self, keypair_name, **params): - self.client.delete_keypair(keypair_name, **params) - - def create_keypair(self, keypair_name=None, - pub_key=None, keypair_type=None, - user_id=None): - if keypair_name is None: - keypair_name = data_utils.rand_name( - self.__class__.__name__ + '-keypair') - kwargs = {'name': keypair_name} - delete_params = {} - if pub_key: - kwargs.update({'public_key': pub_key}) - if keypair_type: - kwargs.update({'type': keypair_type}) - if user_id: - kwargs.update({'user_id': user_id}) - delete_params['user_id'] = user_id - body = self.client.create_keypair(**kwargs)['keypair'] - self.addCleanup(self._delete_keypair, keypair_name, **delete_params) - return body diff --git a/tempest/api/compute/keypairs/test_keypairs.py b/tempest/api/compute/keypairs/test_keypairs.py deleted file mode 100644 index 0b7a9675d..000000000 --- a/tempest/api/compute/keypairs/test_keypairs.py +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.compute.keypairs import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class KeyPairsV2TestJSON(base.BaseKeypairTest): - max_microversion = '2.1' - - @decorators.idempotent_id('1d1dbedb-d7a0-432a-9d09-83f543c3c19b') - def test_keypairs_create_list_delete(self): - # Keypairs created should be available in the response list - # Create 3 keypairs - key_list = list() - for _ in range(3): - keypair = self.create_keypair() - # Need to pop these keys so that our compare doesn't fail later, - # as the keypair dicts from list API doesn't have them. - keypair.pop('private_key') - keypair.pop('user_id') - key_list.append(keypair) - # Fetch all keypairs and verify the list - # has all created keypairs - fetched_list = self.client.list_keypairs()['keypairs'] - new_list = list() - for keypair in fetched_list: - new_list.append(keypair['keypair']) - fetched_list = new_list - # Now check if all the created keypairs are in the fetched list - missing_kps = [kp for kp in key_list if kp not in fetched_list] - self.assertFalse(missing_kps, - "Failed to find keypairs %s in fetched list" - % ', '.join(m_key['name'] for m_key in missing_kps)) - - @decorators.idempotent_id('6c1d3123-4519-4742-9194-622cb1714b7d') - def test_keypair_create_delete(self): - # Keypair should be created, verified and deleted - k_name = data_utils.rand_name('keypair') - keypair = self.create_keypair(k_name) - private_key = keypair['private_key'] - key_name = keypair['name'] - self.assertEqual(key_name, k_name, - "The created keypair name is not equal " - "to the requested name") - self.assertIsNotNone(private_key, - "Field private_key is empty or not found.") - - @decorators.idempotent_id('a4233d5d-52d8-47cc-9a25-e1864527e3df') - def test_get_keypair_detail(self): - # Keypair should be created, Got details by name and deleted - k_name = data_utils.rand_name('keypair') - self.create_keypair(k_name) - keypair_detail = self.client.show_keypair(k_name)['keypair'] - self.assertIn('name', keypair_detail) - self.assertIn('public_key', keypair_detail) - self.assertEqual(keypair_detail['name'], k_name, - "The created keypair name is not equal " - "to requested name") - public_key = keypair_detail['public_key'] - self.assertIsNotNone(public_key, - "Field public_key is empty or not found.") - - @decorators.idempotent_id('39c90c6a-304a-49dd-95ec-2366129def05') - def test_keypair_create_with_pub_key(self): - # Keypair should be created with a given public key - k_name = data_utils.rand_name('keypair') - pub_key = ("ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCs" - "Ne3/1ILNCqFyfYWDeTKLD6jEXC2OQHLmietMWW+/vd" - "aZq7KZEwO0jhglaFjU1mpqq4Gz5RX156sCTNM9vRbw" - "KAxfsdF9laBYVsex3m3Wmui3uYrKyumsoJn2g9GNnG1P" - "I1mrVjZ61i0GY3khna+wzlTpCCmy5HNlrmbj3XLqBUpip" - "TOXmsnr4sChzC53KCd8LXuwc1i/CZPvF+3XipvAgFSE53pCt" - "LOeB1kYMOBaiUPLQTWXR3JpckqFIQwhIH0zoHlJvZE8hh90" - "XcPojYN56tI0OlrGqojbediJYD0rUsJu4weZpbn8vilb3JuDY+jws" - "snSA8wzBx3A/8y9Pp1B nova@ubuntu") - keypair = self.create_keypair(k_name, pub_key) - self.assertNotIn('private_key', keypair, - "Field private_key is not empty!") - key_name = keypair['name'] - self.assertEqual(key_name, k_name, - "The created keypair name is not equal " - "to the requested name!") diff --git a/tempest/api/compute/keypairs/test_keypairs_negative.py b/tempest/api/compute/keypairs/test_keypairs_negative.py deleted file mode 100644 index 205076c56..000000000 --- a/tempest/api/compute/keypairs/test_keypairs_negative.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# Copyright 2013 IBM 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 tempest.api.compute.keypairs import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class KeyPairsNegativeTestJSON(base.BaseKeypairTest): - @decorators.attr(type=['negative']) - @decorators.idempotent_id('29cca892-46ae-4d48-bc32-8fe7e731eb81') - def test_keypair_create_with_invalid_pub_key(self): - # Keypair should not be created with a non RSA public key - pub_key = "ssh-rsa JUNK nova@ubuntu" - self.assertRaises(lib_exc.BadRequest, - self.create_keypair, pub_key=pub_key) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7cc32e47-4c42-489d-9623-c5e2cb5a2fa5') - def test_keypair_delete_nonexistent_key(self): - # Non-existent key deletion should throw a proper error - k_name = data_utils.rand_name("keypair-non-existent") - self.assertRaises(lib_exc.NotFound, self.client.delete_keypair, - k_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('dade320e-69ca-42a9-ba4a-345300f127e0') - def test_create_keypair_with_empty_public_key(self): - # Keypair should not be created with an empty public key - pub_key = ' ' - self.assertRaises(lib_exc.BadRequest, self.create_keypair, - pub_key=pub_key) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('fc100c19-2926-4b9c-8fdc-d0589ee2f9ff') - def test_create_keypair_when_public_key_bits_exceeds_maximum(self): - # Keypair should not be created when public key bits are too long - pub_key = 'ssh-rsa ' + 'A' * 2048 + ' openstack@ubuntu' - self.assertRaises(lib_exc.BadRequest, self.create_keypair, - pub_key=pub_key) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0359a7f1-f002-4682-8073-0c91e4011b7c') - def test_create_keypair_with_duplicate_name(self): - # Keypairs with duplicate names should not be created - k_name = data_utils.rand_name('keypair') - self.client.create_keypair(name=k_name) - # Now try the same keyname to create another key - self.assertRaises(lib_exc.Conflict, self.create_keypair, - k_name) - self.client.delete_keypair(k_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1398abe1-4a84-45fb-9294-89f514daff00') - def test_create_keypair_with_empty_name_string(self): - # Keypairs with name being an empty string should not be created - self.assertRaises(lib_exc.BadRequest, self.create_keypair, - '') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('3faa916f-779f-4103-aca7-dc3538eee1b7') - def test_create_keypair_with_long_keynames(self): - # Keypairs with name longer than 255 chars should not be created - k_name = 'keypair-'.ljust(260, '0') - self.assertRaises(lib_exc.BadRequest, self.create_keypair, - k_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('45fbe5e0-acb5-49aa-837a-ff8d0719db91') - def test_create_keypair_invalid_name(self): - # Keypairs with name being an invalid name should not be created - k_name = 'key_/.\@:' - self.assertRaises(lib_exc.BadRequest, self.create_keypair, - k_name) diff --git a/tempest/api/compute/keypairs/test_keypairs_v22.py b/tempest/api/compute/keypairs/test_keypairs_v22.py deleted file mode 100644 index f39bb1212..000000000 --- a/tempest/api/compute/keypairs/test_keypairs_v22.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.api.compute.keypairs import test_keypairs -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class KeyPairsV22TestJSON(test_keypairs.KeyPairsV2TestJSON): - min_microversion = '2.2' - max_microversion = 'latest' - - def _check_keypair_type(self, keypair, keypair_type): - if keypair_type is None: - keypair_type = 'ssh' - self.assertEqual(keypair_type, keypair['type']) - - def _test_keypairs_create_list_show(self, keypair_type=None): - k_name = data_utils.rand_name('keypair') - keypair = self.create_keypair(k_name, keypair_type=keypair_type) - # Verify whether 'type' is present in keypair create response of - # version 2.2 and it is with default value 'ssh'. - self._check_keypair_type(keypair, keypair_type) - keypair_detail = self.client.show_keypair(k_name)['keypair'] - self._check_keypair_type(keypair_detail, keypair_type) - fetched_list = self.client.list_keypairs()['keypairs'] - for keypair in fetched_list: - # Verify whether 'type' is present in keypair list response of - # version 2.2 and it is with default value 'ssh'. - if keypair['keypair']['name'] == k_name: - self._check_keypair_type(keypair['keypair'], keypair_type) - - @decorators.idempotent_id('8726fa85-7f98-4b20-af9e-f710a4f3391c') - def test_keypairsv22_create_list_show(self): - self._test_keypairs_create_list_show() - - @decorators.idempotent_id('89d59d43-f735-441a-abcf-0601727f47b6') - def test_keypairsv22_create_list_show_with_type(self): - keypair_type = 'x509' - self._test_keypairs_create_list_show(keypair_type=keypair_type) diff --git a/tempest/api/compute/limits/__init__.py b/tempest/api/compute/limits/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/compute/limits/test_absolute_limits.py b/tempest/api/compute/limits/test_absolute_limits.py deleted file mode 100644 index 0585fec3d..000000000 --- a/tempest/api/compute/limits/test_absolute_limits.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.compute import base -from tempest.lib import decorators - - -class AbsoluteLimitsTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_clients(cls): - super(AbsoluteLimitsTestJSON, cls).setup_clients() - cls.client = cls.limits_client - - @decorators.idempotent_id('b54c66af-6ab6-4cf0-a9e5-a0cb58d75e0b') - def test_absLimits_get(self): - # To check if all limits are present in the response - limits = self.client.show_limits()['limits'] - absolute_limits = limits['absolute'] - expected_elements = ['maxImageMeta', 'maxPersonality', - 'maxPersonalitySize', - 'maxServerMeta', 'maxTotalCores', - 'maxTotalFloatingIps', 'maxSecurityGroups', - 'maxSecurityGroupRules', 'maxTotalInstances', - 'maxTotalKeypairs', 'maxTotalRAMSize', - 'maxServerGroups', 'maxServerGroupMembers', - 'totalCoresUsed', 'totalFloatingIpsUsed', - 'totalSecurityGroupsUsed', 'totalInstancesUsed', - 'totalRAMUsed', 'totalServerGroupsUsed'] - # check whether all expected elements exist - missing_elements =\ - [ele for ele in expected_elements if ele not in absolute_limits] - self.assertEmpty(missing_elements, - "Failed to find element %s in absolute limits list" - % ', '.join(ele for ele in missing_elements)) diff --git a/tempest/api/compute/limits/test_absolute_limits_negative.py b/tempest/api/compute/limits/test_absolute_limits_negative.py deleted file mode 100644 index bef4eb526..000000000 --- a/tempest/api/compute/limits/test_absolute_limits_negative.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.compute import base -from tempest.common import tempest_fixtures as fixtures -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class AbsoluteLimitsNegativeTestJSON(base.BaseV2ComputeTest): - - def setUp(self): - # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests. - self.useFixture(fixtures.LockFixture('compute_quotas')) - super(AbsoluteLimitsNegativeTestJSON, self).setUp() - - @classmethod - def setup_clients(cls): - super(AbsoluteLimitsNegativeTestJSON, cls).setup_clients() - cls.client = cls.limits_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('215cd465-d8ae-49c9-bf33-9c911913a5c8') - def test_max_image_meta_exceed_limit(self): - # We should not create vm with image meta over maxImageMeta limit - # Get max limit value - limits = self.client.show_limits()['limits'] - max_meta = limits['absolute']['maxImageMeta'] - - # No point in running this test if there is no limit. - if max_meta == -1: - raise self.skipException('no limit for maxImageMeta') - - # Create server should fail, since we are passing > metadata Limit! - max_meta_data = max_meta + 1 - - meta_data = {} - for xx in range(max_meta_data): - meta_data[str(xx)] = str(xx) - - # A 403 Forbidden or 413 Overlimit (old behaviour) exception - # will be raised when out of quota - self.assertRaises((lib_exc.Forbidden, lib_exc.OverLimit), - self.create_test_server, metadata=meta_data) diff --git a/tempest/api/compute/security_groups/__init__.py b/tempest/api/compute/security_groups/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/compute/security_groups/base.py b/tempest/api/compute/security_groups/base.py deleted file mode 100644 index 6148e160c..000000000 --- a/tempest/api/compute/security_groups/base.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.compute import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest import test - -CONF = config.CONF - - -class BaseSecurityGroupsTest(base.BaseV2ComputeTest): - - @classmethod - def setup_credentials(cls): - # A network and a subnet will be created for these tests - cls.set_network_resources(network=True, subnet=True) - super(BaseSecurityGroupsTest, cls).setup_credentials() - - @staticmethod - def generate_random_security_group_id(): - if (CONF.service_available.neutron and - test.is_extension_enabled('security-group', 'network')): - return data_utils.rand_uuid() - else: - return data_utils.rand_int_id(start=999) diff --git a/tempest/api/compute/security_groups/test_security_group_rules.py b/tempest/api/compute/security_groups/test_security_group_rules.py deleted file mode 100644 index 124db0e45..000000000 --- a/tempest/api/compute/security_groups/test_security_group_rules.py +++ /dev/null @@ -1,189 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.compute.security_groups import base -from tempest.lib import decorators -from tempest import test - - -class SecurityGroupRulesTestJSON(base.BaseSecurityGroupsTest): - - @classmethod - def setup_clients(cls): - super(SecurityGroupRulesTestJSON, cls).setup_clients() - cls.client = cls.security_group_rules_client - - @classmethod - def resource_setup(cls): - super(SecurityGroupRulesTestJSON, cls).resource_setup() - cls.ip_protocol = 'tcp' - cls.from_port = 22 - cls.to_port = 22 - - def setUp(cls): - super(SecurityGroupRulesTestJSON, cls).setUp() - - from_port = cls.from_port - to_port = cls.to_port - group = {} - ip_range = {} - cls.expected = { - 'parent_group_id': None, - 'ip_protocol': cls.ip_protocol, - 'from_port': from_port, - 'to_port': to_port, - 'ip_range': ip_range, - 'group': group - } - - def _check_expected_response(self, actual_rule): - for key in self.expected: - self.assertEqual(self.expected[key], actual_rule[key], - "Miss-matched key is %s" % key) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('850795d7-d4d3-4e55-b527-a774c0123d3a') - @test.services('network') - def test_security_group_rules_create(self): - # Positive test: Creation of Security Group rule - # should be successful - # Creating a Security Group to add rules to it - security_group = self.create_security_group() - securitygroup_id = security_group['id'] - # Adding rules to the created Security Group - rule = self.client.create_security_group_rule( - parent_group_id=securitygroup_id, - ip_protocol=self.ip_protocol, - from_port=self.from_port, - to_port=self.to_port)['security_group_rule'] - self.expected['parent_group_id'] = securitygroup_id - self.expected['ip_range'] = {'cidr': '0.0.0.0/0'} - self._check_expected_response(rule) - - @decorators.idempotent_id('7a01873e-3c38-4f30-80be-31a043cfe2fd') - @test.services('network') - def test_security_group_rules_create_with_optional_cidr(self): - # Positive test: Creation of Security Group rule - # with optional argument cidr - # should be successful - - # Creating a Security Group to add rules to it - security_group = self.create_security_group() - parent_group_id = security_group['id'] - - # Adding rules to the created Security Group with optional cidr - cidr = '10.2.3.124/24' - rule = self.client.create_security_group_rule( - parent_group_id=parent_group_id, - ip_protocol=self.ip_protocol, - from_port=self.from_port, - to_port=self.to_port, - cidr=cidr)['security_group_rule'] - self.expected['parent_group_id'] = parent_group_id - self.expected['ip_range'] = {'cidr': cidr} - self._check_expected_response(rule) - - @decorators.idempotent_id('7f5d2899-7705-4d4b-8458-4505188ffab6') - @test.services('network') - def test_security_group_rules_create_with_optional_group_id(self): - # Positive test: Creation of Security Group rule - # with optional argument group_id - # should be successful - - # Creating a Security Group to add rules to it - security_group = self.create_security_group() - parent_group_id = security_group['id'] - - # Creating a Security Group so as to assign group_id to the rule - security_group = self.create_security_group() - group_id = security_group['id'] - group_name = security_group['name'] - - # Adding rules to the created Security Group with optional group_id - rule = self.client.create_security_group_rule( - parent_group_id=parent_group_id, - ip_protocol=self.ip_protocol, - from_port=self.from_port, - to_port=self.to_port, - group_id=group_id)['security_group_rule'] - self.expected['parent_group_id'] = parent_group_id - self.expected['group'] = {'tenant_id': self.client.tenant_id, - 'name': group_name} - self._check_expected_response(rule) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('a6154130-5a55-4850-8be4-5e9e796dbf17') - @test.services('network') - def test_security_group_rules_list(self): - # Positive test: Created Security Group rules should be - # in the list of all rules - # Creating a Security Group to add rules to it - security_group = self.create_security_group() - securitygroup_id = security_group['id'] - - # Add a first rule to the created Security Group - rule = self.client.create_security_group_rule( - parent_group_id=securitygroup_id, - ip_protocol=self.ip_protocol, - from_port=self.from_port, - to_port=self.to_port)['security_group_rule'] - rule1_id = rule['id'] - - # Add a second rule to the created Security Group - ip_protocol2 = 'icmp' - from_port2 = -1 - to_port2 = -1 - rule = self.client.create_security_group_rule( - parent_group_id=securitygroup_id, - ip_protocol=ip_protocol2, - from_port=from_port2, - to_port=to_port2)['security_group_rule'] - rule2_id = rule['id'] - # Delete the Security Group rule2 at the end of this method - self.addCleanup( - self.security_group_rules_client.delete_security_group_rule, - rule2_id) - - # Get rules of the created Security Group - rules = self.security_groups_client.show_security_group( - securitygroup_id)['security_group']['rules'] - self.assertNotEmpty([i for i in rules if i['id'] == rule1_id]) - self.assertNotEmpty([i for i in rules if i['id'] == rule2_id]) - - @decorators.idempotent_id('fc5c5acf-2091-43a6-a6ae-e42760e9ffaf') - @test.services('network') - def test_security_group_rules_delete_when_peer_group_deleted(self): - # Positive test:rule will delete when peer group deleting - # Creating a Security Group to add rules to it - security_group = self.create_security_group() - sg1_id = security_group['id'] - # Creating other Security Group to access to group1 - security_group = self.create_security_group() - sg2_id = security_group['id'] - # Adding rules to the Group1 - self.client.create_security_group_rule( - parent_group_id=sg1_id, - ip_protocol=self.ip_protocol, - from_port=self.from_port, - to_port=self.to_port, - group_id=sg2_id)['security_group_rule'] - - # Delete group2 - self.security_groups_client.delete_security_group(sg2_id) - # Get rules of the Group1 - rules = (self.security_groups_client.show_security_group(sg1_id) - ['security_group']['rules']) - # The group1 has no rules because group2 has deleted - self.assertEmpty(rules) diff --git a/tempest/api/compute/security_groups/test_security_group_rules_negative.py b/tempest/api/compute/security_groups/test_security_group_rules_negative.py deleted file mode 100644 index 4efb8b75c..000000000 --- a/tempest/api/compute/security_groups/test_security_group_rules_negative.py +++ /dev/null @@ -1,175 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD. -# 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 tempest.api.compute.security_groups import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - - -class SecurityGroupRulesNegativeTestJSON(base.BaseSecurityGroupsTest): - - @classmethod - def setup_clients(cls): - super(SecurityGroupRulesNegativeTestJSON, cls).setup_clients() - cls.rules_client = cls.security_group_rules_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1d507e98-7951-469b-82c3-23f1e6b8c254') - @test.services('network') - def test_create_security_group_rule_with_non_existent_id(self): - # Negative test: Creation of Security Group rule should FAIL - # with non existent Parent group id - # Adding rules to the non existent Security Group id - parent_group_id = self.generate_random_security_group_id() - ip_protocol = 'tcp' - from_port = 22 - to_port = 22 - self.assertRaises(lib_exc.NotFound, - self.rules_client.create_security_group_rule, - parent_group_id=parent_group_id, - ip_protocol=ip_protocol, from_port=from_port, - to_port=to_port) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('2244d7e4-adb7-4ecb-9930-2d77e123ce4f') - @test.services('network') - def test_create_security_group_rule_with_invalid_id(self): - # Negative test: Creation of Security Group rule should FAIL - # with Parent group id which is not integer - # Adding rules to the non int Security Group id - parent_group_id = data_utils.rand_name('non_int_id') - ip_protocol = 'tcp' - from_port = 22 - to_port = 22 - self.assertRaises(lib_exc.BadRequest, - self.rules_client.create_security_group_rule, - parent_group_id=parent_group_id, - ip_protocol=ip_protocol, from_port=from_port, - to_port=to_port) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('8bd56d02-3ffa-4d67-9933-b6b9a01d6089') - @test.services('network') - def test_create_security_group_rule_duplicate(self): - # Negative test: Create Security Group rule duplicate should fail - # Creating a Security Group to add rule to it - sg = self.create_security_group() - # Adding rules to the created Security Group - parent_group_id = sg['id'] - ip_protocol = 'tcp' - from_port = 22 - to_port = 22 - - rule = self.rules_client.create_security_group_rule( - parent_group_id=parent_group_id, ip_protocol=ip_protocol, - from_port=from_port, to_port=to_port)['security_group_rule'] - self.addCleanup(self.rules_client.delete_security_group_rule, - rule['id']) - # Add the same rule to the group should fail - self.assertRaises(lib_exc.BadRequest, - self.rules_client.create_security_group_rule, - parent_group_id=parent_group_id, - ip_protocol=ip_protocol, from_port=from_port, - to_port=to_port) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('84c81249-9f6e-439c-9bbf-cbb0d2cddbdf') - @test.services('network') - def test_create_security_group_rule_with_invalid_ip_protocol(self): - # Negative test: Creation of Security Group rule should FAIL - # with invalid ip_protocol - # Creating a Security Group to add rule to it - sg = self.create_security_group() - # Adding rules to the created Security Group - parent_group_id = sg['id'] - ip_protocol = data_utils.rand_name('999') - from_port = 22 - to_port = 22 - - self.assertRaises(lib_exc.BadRequest, - self.rules_client.create_security_group_rule, - parent_group_id=parent_group_id, - ip_protocol=ip_protocol, from_port=from_port, - to_port=to_port) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('12bbc875-1045-4f7a-be46-751277baedb9') - @test.services('network') - def test_create_security_group_rule_with_invalid_from_port(self): - # Negative test: Creation of Security Group rule should FAIL - # with invalid from_port - # Creating a Security Group to add rule to it - sg = self.create_security_group() - # Adding rules to the created Security Group - parent_group_id = sg['id'] - ip_protocol = 'tcp' - from_port = data_utils.rand_int_id(start=65536) - to_port = 22 - self.assertRaises(lib_exc.BadRequest, - self.rules_client.create_security_group_rule, - parent_group_id=parent_group_id, - ip_protocol=ip_protocol, from_port=from_port, - to_port=to_port) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ff88804d-144f-45d1-bf59-dd155838a43a') - @test.services('network') - def test_create_security_group_rule_with_invalid_to_port(self): - # Negative test: Creation of Security Group rule should FAIL - # with invalid to_port - # Creating a Security Group to add rule to it - sg = self.create_security_group() - # Adding rules to the created Security Group - parent_group_id = sg['id'] - ip_protocol = 'tcp' - from_port = 22 - to_port = data_utils.rand_int_id(start=65536) - self.assertRaises(lib_exc.BadRequest, - self.rules_client.create_security_group_rule, - parent_group_id=parent_group_id, - ip_protocol=ip_protocol, from_port=from_port, - to_port=to_port) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('00296fa9-0576-496a-ae15-fbab843189e0') - @test.services('network') - def test_create_security_group_rule_with_invalid_port_range(self): - # Negative test: Creation of Security Group rule should FAIL - # with invalid port range. - # Creating a Security Group to add rule to it. - sg = self.create_security_group() - # Adding a rule to the created Security Group - secgroup_id = sg['id'] - ip_protocol = 'tcp' - from_port = 22 - to_port = 21 - self.assertRaises(lib_exc.BadRequest, - self.rules_client.create_security_group_rule, - parent_group_id=secgroup_id, - ip_protocol=ip_protocol, from_port=from_port, - to_port=to_port) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('56fddcca-dbb8-4494-a0db-96e9f869527c') - @test.services('network') - def test_delete_security_group_rule_with_non_existent_id(self): - # Negative test: Deletion of Security Group rule should be FAIL - # with non existent id - non_existent_rule_id = self.generate_random_security_group_id() - self.assertRaises(lib_exc.NotFound, - self.rules_client.delete_security_group_rule, - non_existent_rule_id) diff --git a/tempest/api/compute/security_groups/test_security_groups.py b/tempest/api/compute/security_groups/test_security_groups.py deleted file mode 100644 index 930a58ef0..000000000 --- a/tempest/api/compute/security_groups/test_security_groups.py +++ /dev/null @@ -1,174 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.compute.security_groups import base -from tempest.common import waiters -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - - -class SecurityGroupsTestJSON(base.BaseSecurityGroupsTest): - - @classmethod - def setup_clients(cls): - super(SecurityGroupsTestJSON, cls).setup_clients() - cls.client = cls.security_groups_client - - @decorators.attr(type='smoke') - @decorators.idempotent_id('eb2b087d-633d-4d0d-a7bd-9e6ba35b32de') - @test.services('network') - def test_security_groups_create_list_delete(self): - # Positive test:Should return the list of Security Groups - # Create 3 Security Groups - security_group_list = [] - for _ in range(3): - body = self.create_security_group() - security_group_list.append(body) - # Fetch all Security Groups and verify the list - # has all created Security Groups - fetched_list = self.client.list_security_groups()['security_groups'] - # Now check if all the created Security Groups are in fetched list - missing_sgs = \ - [sg for sg in security_group_list if sg not in fetched_list] - self.assertFalse(missing_sgs, - "Failed to find Security Group %s in fetched " - "list" % ', '.join(m_group['name'] - for m_group in missing_sgs)) - # Delete all security groups - for sg in security_group_list: - self.client.delete_security_group(sg['id']) - self.client.wait_for_resource_deletion(sg['id']) - # Now check if all the created Security Groups are deleted - fetched_list = self.client.list_security_groups()['security_groups'] - deleted_sgs = \ - [sg for sg in security_group_list if sg in fetched_list] - self.assertFalse(deleted_sgs, - "Failed to delete Security Group %s " - "list" % ', '.join(m_group['name'] - for m_group in deleted_sgs)) - - @decorators.idempotent_id('ecc0da4a-2117-48af-91af-993cca39a615') - @test.services('network') - def test_security_group_create_get_delete(self): - # Security Group should be created, fetched and deleted - # with char space between name along with - # leading and trailing spaces - s_name = ' %s ' % data_utils.rand_name('securitygroup ') - securitygroup = self.create_security_group(name=s_name) - self.assertIn('name', securitygroup) - securitygroup_name = securitygroup['name'] - self.assertEqual(securitygroup_name, s_name, - "The created Security Group name is " - "not equal to the requested name") - # Now fetch the created Security Group by its 'id' - fetched_group = (self.client.show_security_group(securitygroup['id']) - ['security_group']) - self.assertEqual(securitygroup, fetched_group, - "The fetched Security Group is different " - "from the created Group") - self.client.delete_security_group(securitygroup['id']) - self.client.wait_for_resource_deletion(securitygroup['id']) - - @decorators.idempotent_id('fe4abc0d-83f5-4c50-ad11-57a1127297a2') - @test.services('network') - def test_server_security_groups(self): - # Checks that security groups may be added and linked to a server - # and not deleted if the server is active. - # Create a couple security groups that we will use - # for the server resource this test creates - sg = self.create_security_group() - sg2 = self.create_security_group() - - # Create server and add the security group created - # above to the server we just created - server = self.create_test_server(wait_until='ACTIVE') - server_id = server['id'] - self.servers_client.add_security_group(server_id, name=sg['name']) - - # Check that we are not able to delete the security - # group since it is in use by an active server - self.assertRaises(lib_exc.BadRequest, - self.client.delete_security_group, - sg['id']) - - # Reboot and add the other security group - self.servers_client.reboot_server(server_id, type='HARD') - waiters.wait_for_server_status(self.servers_client, server_id, - 'ACTIVE') - self.servers_client.add_security_group(server_id, name=sg2['name']) - - # Check that we are not able to delete the other security - # group since it is in use by an active server - self.assertRaises(lib_exc.BadRequest, - self.client.delete_security_group, - sg2['id']) - - # Shutdown the server and then verify we can destroy the - # security groups, since no active server instance is using them - self.servers_client.delete_server(server_id) - waiters.wait_for_server_termination(self.servers_client, server_id) - - self.client.delete_security_group(sg['id']) - self.client.delete_security_group(sg2['id']) - - @decorators.idempotent_id('7d4e1d3c-3209-4d6d-b020-986304ebad1f') - @test.services('network') - def test_update_security_groups(self): - # Update security group name and description - # Create a security group - securitygroup = self.create_security_group() - self.assertIn('id', securitygroup) - securitygroup_id = securitygroup['id'] - # Update the name and description - s_new_name = data_utils.rand_name('sg-hth') - s_new_des = data_utils.rand_name('description-hth') - self.client.update_security_group(securitygroup_id, - name=s_new_name, - description=s_new_des) - # get the security group - fetched_group = (self.client.show_security_group(securitygroup_id) - ['security_group']) - self.assertEqual(s_new_name, fetched_group['name']) - self.assertEqual(s_new_des, fetched_group['description']) - - @decorators.idempotent_id('79517d60-535a-438f-af3d-e6feab1cbea7') - @test.services('network') - def test_list_security_groups_by_server(self): - # Create a couple security groups that we will use - # for the server resource this test creates - sg = self.create_security_group() - sg2 = self.create_security_group() - assigned_security_groups_ids = [sg['id'], sg2['id']] - # Create server and add the security group created - # above to the server we just created - server_id = self.create_test_server(wait_until='ACTIVE')['id'] - # add security groups to server - self.servers_client.add_security_group(server_id, name=sg['name']) - self.servers_client.add_security_group(server_id, name=sg2['name']) - - # list security groups for a server - fetched_groups = ( - self.servers_client.list_security_groups_by_server( - server_id)['security_groups']) - fetched_security_groups_ids = [i['id'] for i in fetched_groups] - # verifying the security groups ids in list - missing_security_groups =\ - [p for p in assigned_security_groups_ids - if p not in fetched_security_groups_ids] - self.assertEmpty(missing_security_groups, - "Failed to find security_groups %s in fetched list" % - ', '.join(missing_security_groups)) diff --git a/tempest/api/compute/security_groups/test_security_groups_negative.py b/tempest/api/compute/security_groups/test_security_groups_negative.py deleted file mode 100644 index 207778a4c..000000000 --- a/tempest/api/compute/security_groups/test_security_groups_negative.py +++ /dev/null @@ -1,192 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD. -# 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 testtools - -from tempest.api.compute.security_groups import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class SecurityGroupsNegativeTestJSON(base.BaseSecurityGroupsTest): - - @classmethod - def setup_clients(cls): - super(SecurityGroupsNegativeTestJSON, cls).setup_clients() - cls.client = cls.security_groups_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('673eaec1-9b3e-48ed-bdf1-2786c1b9661c') - @test.services('network') - def test_security_group_get_nonexistent_group(self): - # Negative test:Should not be able to GET the details - # of non-existent Security Group - non_exist_id = self.generate_random_security_group_id() - self.assertRaises(lib_exc.NotFound, self.client.show_security_group, - non_exist_id) - - @decorators.skip_because(bug="1161411", - condition=CONF.service_available.neutron) - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1759c3cb-b0fc-44b7-86ce-c99236be911d') - @test.services('network') - def test_security_group_create_with_invalid_group_name(self): - # Negative test: Security Group should not be created with group name - # as an empty string/with white spaces/chars more than 255 - s_description = data_utils.rand_name('description') - # Create Security Group with empty string as group name - self.assertRaises(lib_exc.BadRequest, - self.client.create_security_group, - name="", description=s_description) - # Create Security Group with white space in group name - self.assertRaises(lib_exc.BadRequest, - self.client.create_security_group, - name=" ", description=s_description) - # Create Security Group with group name longer than 255 chars - s_name = 'securitygroup-'.ljust(260, '0') - self.assertRaises(lib_exc.BadRequest, - self.client.create_security_group, - name=s_name, description=s_description) - - @decorators.skip_because(bug="1161411", - condition=CONF.service_available.neutron) - @decorators.attr(type=['negative']) - @decorators.idempotent_id('777b6f14-aca9-4758-9e84-38783cfa58bc') - @test.services('network') - def test_security_group_create_with_invalid_group_description(self): - # Negative test: Security Group should not be created with description - # longer than 255 chars. Empty description is allowed by the API - # reference, however. - s_name = data_utils.rand_name('securitygroup') - # Create Security Group with group description longer than 255 chars - s_description = 'description-'.ljust(260, '0') - self.assertRaises(lib_exc.BadRequest, - self.client.create_security_group, - name=s_name, description=s_description) - - @decorators.idempotent_id('9fdb4abc-6b66-4b27-b89c-eb215a956168') - @testtools.skipIf(CONF.service_available.neutron, - "Neutron allows duplicate names for security groups") - @decorators.attr(type=['negative']) - @test.services('network') - def test_security_group_create_with_duplicate_name(self): - # Negative test:Security Group with duplicate name should not - # be created - s_name = data_utils.rand_name('securitygroup') - s_description = data_utils.rand_name('description') - self.create_security_group(name=s_name, description=s_description) - # Now try the Security Group with the same 'Name' - self.assertRaises(lib_exc.BadRequest, - self.client.create_security_group, - name=s_name, description=s_description) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('36a1629f-c6da-4a26-b8b8-55e7e5d5cd58') - @test.services('network') - def test_delete_the_default_security_group(self): - # Negative test:Deletion of the "default" Security Group should Fail - default_security_group_id = None - body = self.client.list_security_groups()['security_groups'] - for i in range(len(body)): - if body[i]['name'] == 'default': - default_security_group_id = body[i]['id'] - break - # Deleting the "default" Security Group - self.assertRaises(lib_exc.BadRequest, - self.client.delete_security_group, - default_security_group_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6727c00b-214c-4f9e-9a52-017ac3e98411') - @test.services('network') - def test_delete_nonexistent_security_group(self): - # Negative test:Deletion of a non-existent Security Group should fail - non_exist_id = self.generate_random_security_group_id() - self.assertRaises(lib_exc.NotFound, - self.client.delete_security_group, non_exist_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1438f330-8fa4-4aeb-8a94-37c250106d7f') - @test.services('network') - def test_delete_security_group_without_passing_id(self): - # Negative test:Deletion of a Security Group with out passing ID - # should Fail - self.assertRaises(lib_exc.NotFound, - self.client.delete_security_group, '') - - @decorators.idempotent_id('00579617-fe04-4e1c-9d08-ca7467d2e34b') - @testtools.skipIf(CONF.service_available.neutron, - "Neutron does not check the security group ID") - @decorators.attr(type=['negative']) - @test.services('network') - def test_update_security_group_with_invalid_sg_id(self): - # Update security_group with invalid sg_id should fail - s_name = data_utils.rand_name('sg') - s_description = data_utils.rand_name('description') - # Create a non int sg_id - sg_id_invalid = data_utils.rand_name('sg') - self.assertRaises(lib_exc.BadRequest, - self.client.update_security_group, sg_id_invalid, - name=s_name, description=s_description) - - @decorators.idempotent_id('cda8d8b4-59f8-4087-821d-20cf5a03b3b1') - @testtools.skipIf(CONF.service_available.neutron, - "Neutron does not check the security group name") - @decorators.attr(type=['negative']) - @test.services('network') - def test_update_security_group_with_invalid_sg_name(self): - # Update security_group with invalid sg_name should fail - securitygroup = self.create_security_group() - self.assertIn('id', securitygroup) - securitygroup_id = securitygroup['id'] - # Update Security Group with group name longer than 255 chars - s_new_name = 'securitygroup-'.ljust(260, '0') - self.assertRaises(lib_exc.BadRequest, - self.client.update_security_group, - securitygroup_id, name=s_new_name) - - @decorators.idempotent_id('97d12b1c-a610-4194-93f1-ba859e718b45') - @testtools.skipIf(CONF.service_available.neutron, - "Neutron does not check the security group description") - @decorators.attr(type=['negative']) - @test.services('network') - def test_update_security_group_with_invalid_sg_des(self): - # Update security_group with invalid sg_des should fail - securitygroup = self.create_security_group() - self.assertIn('id', securitygroup) - securitygroup_id = securitygroup['id'] - # Update Security Group with group description longer than 255 chars - s_new_des = 'des-'.ljust(260, '0') - self.assertRaises(lib_exc.BadRequest, - self.client.update_security_group, - securitygroup_id, description=s_new_des) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('27edee9c-873d-4da6-a68a-3c256efebe8f') - @test.services('network') - def test_update_non_existent_security_group(self): - # Update a non-existent Security Group should Fail - non_exist_id = self.generate_random_security_group_id() - s_name = data_utils.rand_name('sg') - s_description = data_utils.rand_name('description') - self.assertRaises(lib_exc.NotFound, - self.client.update_security_group, - non_exist_id, name=s_name, - description=s_description) diff --git a/tempest/api/compute/servers/__init__.py b/tempest/api/compute/servers/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py deleted file mode 100644 index 65d5042b5..000000000 --- a/tempest/api/compute/servers/test_attach_interfaces.py +++ /dev/null @@ -1,281 +0,0 @@ -# Copyright 2013 IBM 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 time - -from tempest.api.compute import base -from tempest.common import compute -from tempest.common.utils import net_utils -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class AttachInterfacesTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(AttachInterfacesTestJSON, cls).skip_checks() - if not CONF.service_available.neutron: - raise cls.skipException("Neutron is required") - if not CONF.compute_feature_enabled.interface_attach: - raise cls.skipException("Interface attachment is not available.") - - @classmethod - def setup_credentials(cls): - # This test class requires network and subnet - cls.set_network_resources(network=True, subnet=True) - super(AttachInterfacesTestJSON, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(AttachInterfacesTestJSON, cls).setup_clients() - cls.subnets_client = cls.os_primary.subnets_client - cls.ports_client = cls.os_primary.ports_client - - def wait_for_port_detach(self, port_id): - """Waits for the port's device_id to be unset. - - :param port_id: The id of the port being detached. - :returns: The final port dict from the show_port response. - """ - port = self.ports_client.show_port(port_id)['port'] - device_id = port['device_id'] - start = int(time.time()) - - # NOTE(mriedem): Nova updates the port's device_id to '' rather than - # None, but it's not contractual so handle Falsey either way. - while device_id: - time.sleep(self.build_interval) - port = self.ports_client.show_port(port_id)['port'] - device_id = port['device_id'] - - timed_out = int(time.time()) - start >= self.build_timeout - - if device_id and timed_out: - message = ('Port %s failed to detach (device_id %s) within ' - 'the required time (%s s).' % - (port_id, device_id, self.build_timeout)) - raise lib_exc.TimeoutException(message) - - return port - - def _check_interface(self, iface, port_id=None, network_id=None, - fixed_ip=None, mac_addr=None): - if port_id: - self.assertEqual(iface['port_id'], port_id) - if network_id: - self.assertEqual(iface['net_id'], network_id) - if fixed_ip: - self.assertEqual(iface['fixed_ips'][0]['ip_address'], fixed_ip) - if mac_addr: - self.assertEqual(iface['mac_addr'], mac_addr) - - def _create_server_get_interfaces(self): - server = self.create_test_server(wait_until='ACTIVE') - ifs = (self.interfaces_client.list_interfaces(server['id']) - ['interfaceAttachments']) - body = waiters.wait_for_interface_status( - self.interfaces_client, server['id'], ifs[0]['port_id'], 'ACTIVE') - ifs[0]['port_state'] = body['port_state'] - return server, ifs - - def _test_create_interface(self, server): - iface = (self.interfaces_client.create_interface(server['id']) - ['interfaceAttachment']) - iface = waiters.wait_for_interface_status( - self.interfaces_client, server['id'], iface['port_id'], 'ACTIVE') - self._check_interface(iface) - return iface - - def _test_create_interface_by_network_id(self, server, ifs): - network_id = ifs[0]['net_id'] - iface = self.interfaces_client.create_interface( - server['id'], net_id=network_id)['interfaceAttachment'] - iface = waiters.wait_for_interface_status( - self.interfaces_client, server['id'], iface['port_id'], 'ACTIVE') - self._check_interface(iface, network_id=network_id) - return iface - - def _test_create_interface_by_port_id(self, server, ifs): - network_id = ifs[0]['net_id'] - port = self.ports_client.create_port(network_id=network_id) - port_id = port['port']['id'] - self.addCleanup(self.ports_client.delete_port, port_id) - iface = self.interfaces_client.create_interface( - server['id'], port_id=port_id)['interfaceAttachment'] - iface = waiters.wait_for_interface_status( - self.interfaces_client, server['id'], iface['port_id'], 'ACTIVE') - self._check_interface(iface, port_id=port_id) - return iface - - def _test_create_interface_by_fixed_ips(self, server, ifs): - network_id = ifs[0]['net_id'] - subnet_id = ifs[0]['fixed_ips'][0]['subnet_id'] - ip_list = net_utils.get_unused_ip_addresses(self.ports_client, - self.subnets_client, - network_id, - subnet_id, - 1) - - fixed_ips = [{'ip_address': ip_list[0]}] - iface = self.interfaces_client.create_interface( - server['id'], net_id=network_id, - fixed_ips=fixed_ips)['interfaceAttachment'] - self.addCleanup(self.ports_client.delete_port, iface['port_id']) - iface = waiters.wait_for_interface_status( - self.interfaces_client, server['id'], iface['port_id'], 'ACTIVE') - self._check_interface(iface, fixed_ip=ip_list[0]) - return iface - - def _test_show_interface(self, server, ifs): - iface = ifs[0] - _iface = self.interfaces_client.show_interface( - server['id'], iface['port_id'])['interfaceAttachment'] - self._check_interface(iface, port_id=_iface['port_id'], - network_id=_iface['net_id'], - fixed_ip=_iface['fixed_ips'][0]['ip_address'], - mac_addr=_iface['mac_addr']) - - def _test_delete_interface(self, server, ifs): - # NOTE(danms): delete not the first or last, but one in the middle - iface = ifs[1] - self.interfaces_client.delete_interface(server['id'], iface['port_id']) - _ifs = (self.interfaces_client.list_interfaces(server['id']) - ['interfaceAttachments']) - start = int(time.time()) - - while len(ifs) == len(_ifs): - time.sleep(self.build_interval) - _ifs = (self.interfaces_client.list_interfaces(server['id']) - ['interfaceAttachments']) - timed_out = int(time.time()) - start >= self.build_timeout - if len(ifs) == len(_ifs) and timed_out: - message = ('Failed to delete interface within ' - 'the required time: %s sec.' % self.build_timeout) - raise lib_exc.TimeoutException(message) - - self.assertNotIn(iface['port_id'], [i['port_id'] for i in _ifs]) - return _ifs - - def _compare_iface_list(self, list1, list2): - # NOTE(danms): port_state will likely have changed, so just - # confirm the port_ids are the same at least - list1 = [x['port_id'] for x in list1] - list2 = [x['port_id'] for x in list2] - - self.assertEqual(sorted(list1), sorted(list2)) - - @decorators.idempotent_id('73fe8f02-590d-4bf1-b184-e9ca81065051') - @test.services('network') - def test_create_list_show_delete_interfaces(self): - server, ifs = self._create_server_get_interfaces() - interface_count = len(ifs) - self.assertGreater(interface_count, 0) - self._check_interface(ifs[0]) - - try: - iface = self._test_create_interface(server) - except lib_exc.BadRequest as e: - msg = ('Multiple possible networks found, use a Network ID to be ' - 'more specific.') - if not CONF.compute.fixed_network_name and e.message == msg: - raise - else: - ifs.append(iface) - - iface = self._test_create_interface_by_network_id(server, ifs) - ifs.append(iface) - - iface = self._test_create_interface_by_port_id(server, ifs) - ifs.append(iface) - - iface = self._test_create_interface_by_fixed_ips(server, ifs) - ifs.append(iface) - - _ifs = (self.interfaces_client.list_interfaces(server['id']) - ['interfaceAttachments']) - self._compare_iface_list(ifs, _ifs) - - self._test_show_interface(server, ifs) - - _ifs = self._test_delete_interface(server, ifs) - self.assertEqual(len(ifs) - 1, len(_ifs)) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('c7e0e60b-ee45-43d0-abeb-8596fd42a2f9') - @test.services('network') - def test_add_remove_fixed_ip(self): - # Add and Remove the fixed IP to server. - server, ifs = self._create_server_get_interfaces() - interface_count = len(ifs) - self.assertGreater(interface_count, 0) - self._check_interface(ifs[0]) - network_id = ifs[0]['net_id'] - self.servers_client.add_fixed_ip(server['id'], networkId=network_id) - # Remove the fixed IP from server. - server_detail = self.os_primary.servers_client.show_server( - server['id'])['server'] - # Get the Fixed IP from server. - fixed_ip = None - for ip_set in server_detail['addresses']: - for ip in server_detail['addresses'][ip_set]: - if ip['OS-EXT-IPS:type'] == 'fixed': - fixed_ip = ip['addr'] - break - if fixed_ip is not None: - break - self.servers_client.remove_fixed_ip(server['id'], address=fixed_ip) - - @decorators.skip_because(bug='1607714') - @decorators.idempotent_id('2f3a0127-95c7-4977-92d2-bc5aec602fb4') - def test_reassign_port_between_servers(self): - """Tests the following: - - 1. Create a port in Neutron. - 2. Create two servers in Nova. - 3. Attach the port to the first server. - 4. Detach the port from the first server. - 5. Attach the port to the second server. - 6. Detach the port from the second server. - """ - network = self.get_tenant_network() - network_id = network['id'] - port = self.ports_client.create_port(network_id=network_id) - port_id = port['port']['id'] - self.addCleanup(self.ports_client.delete_port, port_id) - - # create two servers - _, servers = compute.create_test_server( - self.os_primary, tenant_network=network, - wait_until='ACTIVE', min_count=2) - # add our cleanups for the servers since we bypassed the base class - for server in servers: - self.addCleanup(self.delete_server, server['id']) - - for server in servers: - # attach the port to the server - iface = self.interfaces_client.create_interface( - server['id'], port_id=port_id)['interfaceAttachment'] - self._check_interface(iface, port_id=port_id) - - # detach the port from the server; this is a cast in the compute - # API so we have to poll the port until the device_id is unset. - self.interfaces_client.delete_interface(server['id'], port_id) - self.wait_for_port_detach(port_id) diff --git a/tempest/api/compute/servers/test_availability_zone.py b/tempest/api/compute/servers/test_availability_zone.py deleted file mode 100644 index 36828d6b4..000000000 --- a/tempest/api/compute/servers/test_availability_zone.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2014 NEC Corporation -# 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 tempest.api.compute import base -from tempest.lib import decorators - - -class AZV2TestJSON(base.BaseV2ComputeTest): - """Tests Availability Zone API List""" - - @classmethod - def setup_clients(cls): - super(AZV2TestJSON, cls).setup_clients() - cls.client = cls.availability_zone_client - - @decorators.idempotent_id('a8333aa2-205c-449f-a828-d38c2489bf25') - def test_get_availability_zone_list_with_non_admin_user(self): - # List of availability zone with non-administrator user - availability_zone = self.client.list_availability_zones() - self.assertNotEmpty(availability_zone['availabilityZoneInfo']) diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py deleted file mode 100644 index aa5c43d8d..000000000 --- a/tempest/api/compute/servers/test_create_server.py +++ /dev/null @@ -1,172 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 netaddr -import testtools - -from tempest.api.compute import base -from tempest.common.utils.linux import remote_client -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class ServersTestJSON(base.BaseV2ComputeTest): - disk_config = 'AUTO' - volume_backed = False - - @classmethod - def setup_credentials(cls): - cls.prepare_instance_network() - super(ServersTestJSON, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(ServersTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - cls.set_validation_resources() - super(ServersTestJSON, cls).resource_setup() - cls.meta = {'hello': 'world'} - cls.accessIPv4 = '1.1.1.1' - cls.accessIPv6 = '0000:0000:0000:0000:0000:babe:220.12.22.2' - cls.name = data_utils.rand_name(cls.__name__ + '-server') - cls.password = data_utils.rand_password() - disk_config = cls.disk_config - server_initial = cls.create_test_server( - validatable=True, - wait_until='ACTIVE', - name=cls.name, - metadata=cls.meta, - accessIPv4=cls.accessIPv4, - accessIPv6=cls.accessIPv6, - disk_config=disk_config, - adminPass=cls.password, - volume_backed=cls.volume_backed) - cls.server = (cls.client.show_server(server_initial['id']) - ['server']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('5de47127-9977-400a-936f-abcfbec1218f') - def test_verify_server_details(self): - # Verify the specified server attributes are set correctly - self.assertEqual(self.accessIPv4, self.server['accessIPv4']) - # NOTE(maurosr): See http://tools.ietf.org/html/rfc5952 (section 4) - # Here we compare directly with the canonicalized format. - self.assertEqual(self.server['accessIPv6'], - str(netaddr.IPAddress(self.accessIPv6))) - self.assertEqual(self.name, self.server['name']) - if self.volume_backed: - # Image is an empty string as per documentation - self.assertEqual("", self.server['image']) - else: - self.assertEqual(self.image_ref, self.server['image']['id']) - self.assertEqual(self.flavor_ref, self.server['flavor']['id']) - self.assertEqual(self.meta, self.server['metadata']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('9a438d88-10c6-4bcd-8b5b-5b6e25e1346f') - def test_list_servers(self): - # The created server should be in the list of all servers - body = self.client.list_servers() - servers = body['servers'] - found = [i for i in servers if i['id'] == self.server['id']] - self.assertNotEmpty(found) - - @decorators.idempotent_id('585e934c-448e-43c4-acbf-d06a9b899997') - def test_list_servers_with_detail(self): - # The created server should be in the detailed list of all servers - body = self.client.list_servers(detail=True) - servers = body['servers'] - found = [i for i in servers if i['id'] == self.server['id']] - self.assertNotEmpty(found) - - @decorators.idempotent_id('cbc0f52f-05aa-492b-bdc1-84b575ca294b') - @testtools.skipUnless(CONF.validation.run_validation, - 'Instance validation tests are disabled.') - def test_verify_created_server_vcpus(self): - # Verify that the number of vcpus reported by the instance matches - # the amount stated by the flavor - flavor = self.flavors_client.show_flavor(self.flavor_ref)['flavor'] - linux_client = remote_client.RemoteClient( - self.get_server_ip(self.server), - self.ssh_user, - self.password, - self.validation_resources['keypair']['private_key'], - server=self.server, - servers_client=self.client) - output = linux_client.exec_command('grep -c ^processor /proc/cpuinfo') - self.assertEqual(flavor['vcpus'], int(output)) - - @decorators.idempotent_id('ac1ad47f-984b-4441-9274-c9079b7a0666') - @testtools.skipUnless(CONF.validation.run_validation, - 'Instance validation tests are disabled.') - def test_host_name_is_same_as_server_name(self): - # Verify the instance host name is the same as the server name - linux_client = remote_client.RemoteClient( - self.get_server_ip(self.server), - self.ssh_user, - self.password, - self.validation_resources['keypair']['private_key'], - server=self.server, - servers_client=self.client) - hostname = linux_client.exec_command("hostname").rstrip() - msg = ('Failed while verifying servername equals hostname. Expected ' - 'hostname "%s" but got "%s".' % (self.name, hostname)) - self.assertEqual(self.name.lower(), hostname, msg) - - @decorators.idempotent_id('ed20d3fb-9d1f-4329-b160-543fbd5d9811') - @testtools.skipUnless( - test.is_scheduler_filter_enabled("ServerGroupAffinityFilter"), - 'ServerGroupAffinityFilter is not available.') - def test_create_server_with_scheduler_hint_group(self): - # Create a server with the scheduler hint "group". - group_id = self.create_test_server_group()['id'] - hints = {'group': group_id} - server = self.create_test_server(scheduler_hints=hints, - wait_until='ACTIVE') - - # Check a server is in the group - server_group = (self.server_groups_client.show_server_group(group_id) - ['server_group']) - self.assertIn(server['id'], server_group['members']) - - -class ServersTestManualDisk(ServersTestJSON): - disk_config = 'MANUAL' - - @classmethod - def skip_checks(cls): - super(ServersTestManualDisk, cls).skip_checks() - if not CONF.compute_feature_enabled.disk_config: - msg = "DiskConfig extension not enabled." - raise cls.skipException(msg) - - -class ServersTestBootFromVolume(ServersTestJSON): - """Run the `ServersTestJSON` tests with a volume backed VM""" - volume_backed = True - - @classmethod - def skip_checks(cls): - super(ServersTestBootFromVolume, cls).skip_checks() - if not test.get_service_list()['volume']: - msg = "Volume service not enabled." - raise cls.skipException(msg) diff --git a/tempest/api/compute/servers/test_create_server_multi_nic.py b/tempest/api/compute/servers/test_create_server_multi_nic.py deleted file mode 100644 index 3447d858d..000000000 --- a/tempest/api/compute/servers/test_create_server_multi_nic.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 netaddr -import testtools - -from tempest.api.compute import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class ServersTestMultiNic(base.BaseV2ComputeTest): - - @classmethod - def setup_credentials(cls): - cls.prepare_instance_network() - super(ServersTestMultiNic, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(ServersTestMultiNic, cls).setup_clients() - cls.client = cls.servers_client - cls.networks_client = cls.os_primary.networks_client - cls.subnets_client = cls.os_primary.subnets_client - - def _create_net_subnet_ret_net_from_cidr(self, cidr): - name_net = data_utils.rand_name(self.__class__.__name__) - net = self.networks_client.create_network(name=name_net) - self.addCleanup(self.networks_client.delete_network, - net['network']['id']) - - subnet = self.subnets_client.create_subnet( - network_id=net['network']['id'], - cidr=cidr, - ip_version=4) - self.addCleanup(self.subnets_client.delete_subnet, - subnet['subnet']['id']) - return net - - @decorators.idempotent_id('0578d144-ed74-43f8-8e57-ab10dbf9b3c2') - @testtools.skipUnless(CONF.service_available.neutron, - 'Neutron service must be available.') - def test_verify_multiple_nics_order(self): - # Verify that the networks order given at the server creation is - # preserved within the server. - net1 = self._create_net_subnet_ret_net_from_cidr('19.80.0.0/24') - net2 = self._create_net_subnet_ret_net_from_cidr('19.86.0.0/24') - - networks = [{'uuid': net1['network']['id']}, - {'uuid': net2['network']['id']}] - - server_multi_nics = self.create_test_server( - networks=networks, wait_until='ACTIVE') - - # Cleanup server; this is needed in the test case because with the LIFO - # nature of the cleanups, if we don't delete the server first, the port - # will still be part of the subnet and we'll get a 409 from Neutron - # when trying to delete the subnet. The tear down in the base class - # will try to delete the server and get a 404 but it's ignored so - # we're OK. - self.addCleanup(self.delete_server, server_multi_nics['id']) - - addresses = (self.client.list_addresses(server_multi_nics['id']) - ['addresses']) - - # We can't predict the ip addresses assigned to the server on networks. - # Sometimes the assigned addresses are ['19.80.0.2', '19.86.0.2'], at - # other times ['19.80.0.3', '19.86.0.3']. So we check if the first - # address is in first network, similarly second address is in second - # network. - addr = [addresses[net1['network']['name']][0]['addr'], - addresses[net2['network']['name']][0]['addr']] - networks = [netaddr.IPNetwork('19.80.0.0/24'), - netaddr.IPNetwork('19.86.0.0/24')] - for address, network in zip(addr, networks): - self.assertIn(address, network) - - @decorators.idempotent_id('1678d144-ed74-43f8-8e57-ab10dbf9b3c2') - @testtools.skipUnless(CONF.service_available.neutron, - 'Neutron service must be available.') - def test_verify_duplicate_network_nics(self): - # Verify that server creation does not fail when more than one nic - # is created on the same network. - net1 = self._create_net_subnet_ret_net_from_cidr('19.80.0.0/24') - net2 = self._create_net_subnet_ret_net_from_cidr('19.86.0.0/24') - - networks = [{'uuid': net1['network']['id']}, - {'uuid': net2['network']['id']}, - {'uuid': net1['network']['id']}] - - server_multi_nics = self.create_test_server( - networks=networks, wait_until='ACTIVE') - self.addCleanup(self.delete_server, server_multi_nics['id']) - - addresses = (self.client.list_addresses(server_multi_nics['id']) - ['addresses']) - - addr = [addresses[net1['network']['name']][0]['addr'], - addresses[net2['network']['name']][0]['addr'], - addresses[net1['network']['name']][1]['addr']] - networks = [netaddr.IPNetwork('19.80.0.0/24'), - netaddr.IPNetwork('19.86.0.0/24'), - netaddr.IPNetwork('19.80.0.0/24')] - for address, network in zip(addr, networks): - self.assertIn(address, network) diff --git a/tempest/api/compute/servers/test_delete_server.py b/tempest/api/compute/servers/test_delete_server.py deleted file mode 100644 index 2b03b2be7..000000000 --- a/tempest/api/compute/servers/test_delete_server.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 testtools - -from tempest.api.compute import base -from tempest.common import compute -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class DeleteServersTestJSON(base.BaseV2ComputeTest): - - # NOTE: Server creations of each test class should be under 10 - # for preventing "Quota exceeded for instances" - - @classmethod - def setup_clients(cls): - super(DeleteServersTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @decorators.idempotent_id('9e6e0c87-3352-42f7-9faf-5d6210dbd159') - def test_delete_server_while_in_building_state(self): - # Delete a server while it's VM state is Building - server = self.create_test_server(wait_until='BUILD') - self.client.delete_server(server['id']) - waiters.wait_for_server_termination(self.client, server['id']) - - @decorators.idempotent_id('925fdfb4-5b13-47ea-ac8a-c36ae6fddb05') - def test_delete_active_server(self): - # Delete a server while it's VM state is Active - server = self.create_test_server(wait_until='ACTIVE') - self.client.delete_server(server['id']) - waiters.wait_for_server_termination(self.client, server['id']) - - @decorators.idempotent_id('546d368c-bb6c-4645-979a-83ed16f3a6be') - def test_delete_server_while_in_shutoff_state(self): - # Delete a server while it's VM state is Shutoff - server = self.create_test_server(wait_until='ACTIVE') - self.client.stop_server(server['id']) - waiters.wait_for_server_status(self.client, server['id'], 'SHUTOFF') - self.client.delete_server(server['id']) - waiters.wait_for_server_termination(self.client, server['id']) - - @decorators.idempotent_id('943bd6e8-4d7a-4904-be83-7a6cc2d4213b') - @testtools.skipUnless(CONF.compute_feature_enabled.pause, - 'Pause is not available.') - def test_delete_server_while_in_pause_state(self): - # Delete a server while it's VM state is Pause - server = self.create_test_server(wait_until='ACTIVE') - self.client.pause_server(server['id']) - waiters.wait_for_server_status(self.client, server['id'], 'PAUSED') - self.client.delete_server(server['id']) - waiters.wait_for_server_termination(self.client, server['id']) - - @decorators.idempotent_id('1f82ebd3-8253-4f4e-b93f-de9b7df56d8b') - @testtools.skipUnless(CONF.compute_feature_enabled.suspend, - 'Suspend is not available.') - def test_delete_server_while_in_suspended_state(self): - # Delete a server while it's VM state is Suspended - server = self.create_test_server(wait_until='ACTIVE') - self.client.suspend_server(server['id']) - waiters.wait_for_server_status(self.client, server['id'], 'SUSPENDED') - self.client.delete_server(server['id']) - waiters.wait_for_server_termination(self.client, server['id']) - - @decorators.idempotent_id('bb0cb402-09dd-4947-b6e5-5e7e1cfa61ad') - @testtools.skipUnless(CONF.compute_feature_enabled.shelve, - 'Shelve is not available.') - def test_delete_server_while_in_shelved_state(self): - # Delete a server while it's VM state is Shelved - server = self.create_test_server(wait_until='ACTIVE') - compute.shelve_server(self.client, server['id']) - - self.client.delete_server(server['id']) - waiters.wait_for_server_termination(self.client, server['id']) - - @decorators.idempotent_id('ab0c38b4-cdd8-49d3-9b92-0cb898723c01') - @testtools.skipIf(not CONF.compute_feature_enabled.resize, - 'Resize not available.') - def test_delete_server_while_in_verify_resize_state(self): - # Delete a server while it's VM state is VERIFY_RESIZE - server = self.create_test_server(wait_until='ACTIVE') - self.client.resize_server(server['id'], self.flavor_ref_alt) - waiters.wait_for_server_status(self.client, server['id'], - 'VERIFY_RESIZE') - self.client.delete_server(server['id']) - waiters.wait_for_server_termination(self.client, server['id']) - - @decorators.idempotent_id('d0f3f0d6-d9b6-4a32-8da4-23015dcab23c') - @test.services('volume') - def test_delete_server_while_in_attached_volume(self): - # Delete a server while a volume is attached to it - device = '/dev/%s' % CONF.compute.volume_device_name - server = self.create_test_server(wait_until='ACTIVE') - - volume = self.create_volume() - self.attach_volume(server, volume, device=device) - - self.client.delete_server(server['id']) - waiters.wait_for_server_termination(self.client, server['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') diff --git a/tempest/api/compute/servers/test_device_tagging.py b/tempest/api/compute/servers/test_device_tagging.py deleted file mode 100644 index 7ee1b0259..000000000 --- a/tempest/api/compute/servers/test_device_tagging.py +++ /dev/null @@ -1,288 +0,0 @@ -# Copyright (C) 2016, Red Hat, Inc. -# -# 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 json - -from oslo_log import log as logging - -from tempest.api.compute import base -from tempest.common.utils.linux import remote_client -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions -from tempest import test - - -CONF = config.CONF - -LOG = logging.getLogger(__name__) - - -class DeviceTaggingTest(base.BaseV2ComputeTest): - - min_microversion = '2.32' - # NOTE(mriedem): max_version looks odd but it's actually correct. Due to a - # bug in the 2.32 microversion, tags on block devices only worked with the - # 2.32 microversion specifically. And tags on networks only worked between - # 2.32 and 2.36 inclusive; the 2.37 microversion broke tags for networks. - max_microversion = '2.32' - - @classmethod - def skip_checks(cls): - super(DeviceTaggingTest, cls).skip_checks() - if not CONF.service_available.neutron: - raise cls.skipException('Neutron is required') - if not CONF.validation.run_validation: - raise cls.skipException('Validation must be enabled') - if (not CONF.compute_feature_enabled.config_drive - and not CONF.compute_feature_enabled.metadata_service): - raise cls.skipException('One of metadata or config drive must be ' - 'enabled') - - @classmethod - def setup_clients(cls): - super(DeviceTaggingTest, cls).setup_clients() - cls.networks_client = cls.os_primary.networks_client - cls.ports_client = cls.os_primary.ports_client - cls.subnets_client = cls.os_primary.subnets_client - cls.interfaces_client = cls.os_primary.interfaces_client - - @classmethod - def setup_credentials(cls): - cls.set_network_resources(network=True, subnet=True, router=True, - dhcp=True) - super(DeviceTaggingTest, cls).setup_credentials() - - @classmethod - def resource_setup(cls): - cls.set_validation_resources() - super(DeviceTaggingTest, cls).resource_setup() - - def verify_device_metadata(self, md_json): - md_dict = json.loads(md_json) - for d in md_dict['devices']: - if d['type'] == 'nic': - if d['mac'] == self.port1['mac_address']: - self.assertEqual(d['tags'], ['port-1']) - if d['mac'] == self.port2['mac_address']: - self.assertEqual(d['tags'], ['port-2']) - if d['mac'] == self.net_2_100_mac: - self.assertEqual(d['tags'], ['net-2-100']) - if d['mac'] == self.net_2_200_mac: - self.assertEqual(d['tags'], ['net-2-200']) - - # A hypervisor may present multiple paths to a tagged disk, so - # there may be duplicated tags in the metadata, use set() to - # remove duplicated tags. - found_devices = [d['tags'][0] for d in md_dict['devices']] - self.assertEqual(set(found_devices), set(['port-1', 'port-2', - 'net-1', 'net-2-100', - 'net-2-200', 'boot', - 'other'])) - - @decorators.idempotent_id('a2e65a6c-66f1-4442-aaa8-498c31778d96') - @test.services('network', 'volume', 'image') - def test_device_tagging(self): - # Create volumes - # The create_volume methods waits for the volumes to be available and - # the base class will clean them up on tearDown. - boot_volume = self.create_volume(CONF.compute.image_ref) - other_volume = self.create_volume() - untagged_volume = self.create_volume() - - # Create networks - net1 = self.networks_client.create_network( - name=data_utils.rand_name('device-tagging-net1'))['network'] - self.addCleanup(self.networks_client.delete_network, net1['id']) - - net2 = self.networks_client.create_network( - name=data_utils.rand_name('device-tagging-net2'))['network'] - self.addCleanup(self.networks_client.delete_network, net2['id']) - - # Create subnets - subnet1 = self.subnets_client.create_subnet( - network_id=net1['id'], - cidr='10.1.1.0/24', - ip_version=4)['subnet'] - self.addCleanup(self.subnets_client.delete_subnet, subnet1['id']) - - subnet2 = self.subnets_client.create_subnet( - network_id=net2['id'], - cidr='10.2.2.0/24', - ip_version=4)['subnet'] - self.addCleanup(self.subnets_client.delete_subnet, subnet2['id']) - - # Create ports - self.port1 = self.ports_client.create_port( - network_id=net1['id'], - fixed_ips=[{'subnet_id': subnet1['id']}])['port'] - self.addCleanup(self.ports_client.delete_port, self.port1['id']) - - self.port2 = self.ports_client.create_port( - network_id=net1['id'], - fixed_ips=[{'subnet_id': subnet1['id']}])['port'] - self.addCleanup(self.ports_client.delete_port, self.port2['id']) - - # Create server - admin_pass = data_utils.rand_password() - config_drive_enabled = CONF.compute_feature_enabled.config_drive - - server = self.create_test_server( - validatable=True, - config_drive=config_drive_enabled, - adminPass=admin_pass, - name=data_utils.rand_name('device-tagging-server'), - networks=[ - # Validation network for ssh - { - 'uuid': self.get_tenant_network()['id'] - }, - # Different tags for different ports - { - 'port': self.port1['id'], - 'tag': 'port-1' - }, - { - 'port': self.port2['id'], - 'tag': 'port-2' - }, - # Two nics on same net, one tagged one not - { - 'uuid': net1['id'], - 'tag': 'net-1' - }, - { - 'uuid': net1['id'] - }, - # Two nics on same net, different IP - { - 'uuid': net2['id'], - 'fixed_ip': '10.2.2.100', - 'tag': 'net-2-100' - }, - { - 'uuid': net2['id'], - 'fixed_ip': '10.2.2.200', - 'tag': 'net-2-200' - } - ], - block_device_mapping_v2=[ - # Boot volume - { - 'uuid': boot_volume['id'], - 'source_type': 'volume', - 'destination_type': 'volume', - 'boot_index': 0, - 'tag': 'boot' - }, - # Other volume - { - 'uuid': other_volume['id'], - 'source_type': 'volume', - 'destination_type': 'volume', - 'boot_index': 1, - 'tag': 'other' - }, - # Untagged volume - { - 'uuid': untagged_volume['id'], - 'source_type': 'volume', - 'destination_type': 'volume', - 'boot_index': 2 - } - ]) - - self.addCleanup(self.delete_server, server['id']) - - self.ssh_client = remote_client.RemoteClient( - self.get_server_ip(server), - CONF.validation.image_ssh_user, - admin_pass, - self.validation_resources['keypair']['private_key'], - server=server, - servers_client=self.servers_client) - - # Find the MAC addresses of our fixed IPs - self.net_2_100_mac = None - self.net_2_200_mac = None - ifaces = self.interfaces_client.list_interfaces(server['id']) - for iface in ifaces['interfaceAttachments']: - if 'fixed_ips' in iface: - for ip in iface['fixed_ips']: - if ip['ip_address'] == '10.2.2.100': - self.net_2_100_mac = iface['mac_addr'] - if ip['ip_address'] == '10.2.2.200': - self.net_2_200_mac = iface['mac_addr'] - # Make sure we have the MACs we need, there's no reason for some to be - # missing - self.assertTrue(self.net_2_100_mac) - self.assertTrue(self.net_2_200_mac) - - # Verify metadata from metadata service - if CONF.compute_feature_enabled.metadata_service: - md_url = 'http://169.254.169.254/openstack/latest/meta_data.json' - LOG.info('Attempting to verify tagged devices in server %s via ' - 'the metadata service: %s', server['id'], md_url) - - def get_and_verify_metadata(): - try: - self.ssh_client.exec_command('curl -V') - except exceptions.SSHExecCommandFailed: - if not CONF.compute_feature_enabled.config_drive: - raise self.skipException('curl not found in guest ' - 'and config drive is ' - 'disabled') - LOG.warning('curl was not found in the guest, device ' - 'tagging metadata was not checked in the ' - 'metadata API') - return True - cmd = 'curl %s' % md_url - md_json = self.ssh_client.exec_command(cmd) - self.verify_device_metadata(md_json) - return True - - if not test_utils.call_until_true(get_and_verify_metadata, - CONF.compute.build_timeout, - CONF.compute.build_interval): - raise exceptions.TimeoutException('Timeout while verifying ' - 'metadata on server.') - - # Verify metadata on config drive - if CONF.compute_feature_enabled.config_drive: - cmd_blkid = 'blkid -t LABEL=config-2 -o device' - LOG.info('Attempting to verify tagged devices in server %s via ' - 'the config drive.', server['id']) - dev_name = self.ssh_client.exec_command(cmd_blkid) - dev_name = dev_name.rstrip() - try: - self.ssh_client.exec_command('sudo mount %s /mnt' % dev_name) - except exceptions.SSHExecCommandFailed: - # So the command failed, let's try to know why and print some - # useful information. - lsblk = self.ssh_client.exec_command('sudo lsblk --fs --ascii') - LOG.error("Mounting %s on /mnt failed. Right after the " - "failure 'lsblk' in the guest reported:\n%s", - dev_name, lsblk) - raise - - cmd_md = 'sudo cat /mnt/openstack/latest/meta_data.json' - md_json = self.ssh_client.exec_command(cmd_md) - self.verify_device_metadata(md_json) - - -class DeviceTaggingTestV2_42(DeviceTaggingTest): - min_microversion = '2.42' - max_microversion = 'latest' diff --git a/tempest/api/compute/servers/test_disk_config.py b/tempest/api/compute/servers/test_disk_config.py deleted file mode 100644 index bc4806995..000000000 --- a/tempest/api/compute/servers/test_disk_config.py +++ /dev/null @@ -1,134 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 testtools - -from tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class ServerDiskConfigTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(ServerDiskConfigTestJSON, cls).skip_checks() - if not CONF.compute_feature_enabled.disk_config: - msg = "DiskConfig extension not enabled." - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(ServerDiskConfigTestJSON, cls).setup_clients() - cls.client = cls.os_primary.servers_client - - def _update_server_with_disk_config(self, server_id, disk_config): - server = self.client.show_server(server_id)['server'] - if disk_config != server['OS-DCF:diskConfig']: - server = self.client.update_server( - server_id, disk_config=disk_config)['server'] - waiters.wait_for_server_status(self.client, server['id'], 'ACTIVE') - server = self.client.show_server(server['id'])['server'] - self.assertEqual(disk_config, server['OS-DCF:diskConfig']) - - @decorators.idempotent_id('bef56b09-2e8c-4883-a370-4950812f430e') - def test_rebuild_server_with_manual_disk_config(self): - # A server should be rebuilt using the manual disk config option - server = self.create_test_server(wait_until='ACTIVE') - self.addCleanup(self.client.delete_server, server['id']) - self._update_server_with_disk_config(server['id'], - disk_config='AUTO') - - server = self.client.rebuild_server(server['id'], - self.image_ref_alt, - disk_config='MANUAL')['server'] - - # Wait for the server to become active - waiters.wait_for_server_status(self.client, server['id'], 'ACTIVE') - - # Verify the specified attributes are set correctly - server = self.client.show_server(server['id'])['server'] - self.assertEqual('MANUAL', server['OS-DCF:diskConfig']) - - @decorators.idempotent_id('9c9fae77-4feb-402f-8450-bf1c8b609713') - def test_rebuild_server_with_auto_disk_config(self): - # A server should be rebuilt using the auto disk config option - server = self.create_test_server(wait_until='ACTIVE') - self.addCleanup(self.client.delete_server, server['id']) - self._update_server_with_disk_config(server['id'], - disk_config='MANUAL') - - server = self.client.rebuild_server(server['id'], - self.image_ref_alt, - disk_config='AUTO')['server'] - - # Wait for the server to become active - waiters.wait_for_server_status(self.client, server['id'], 'ACTIVE') - - # Verify the specified attributes are set correctly - server = self.client.show_server(server['id'])['server'] - self.assertEqual('AUTO', server['OS-DCF:diskConfig']) - - @decorators.idempotent_id('414e7e93-45b5-44bc-8e03-55159c6bfc97') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize not available.') - def test_resize_server_from_manual_to_auto(self): - # A server should be resized from manual to auto disk config - server = self.create_test_server(wait_until='ACTIVE') - self.addCleanup(self.client.delete_server, server['id']) - self._update_server_with_disk_config(server['id'], - disk_config='MANUAL') - # Resize with auto option - self.resize_server(server['id'], self.flavor_ref_alt, - disk_config='AUTO') - - server = self.client.show_server(server['id'])['server'] - self.assertEqual('AUTO', server['OS-DCF:diskConfig']) - - @decorators.idempotent_id('693d16f3-556c-489a-8bac-3d0ca2490bad') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize not available.') - def test_resize_server_from_auto_to_manual(self): - # A server should be resized from auto to manual disk config - server = self.create_test_server(wait_until='ACTIVE') - self.addCleanup(self.client.delete_server, server['id']) - self._update_server_with_disk_config(server['id'], - disk_config='AUTO') - # Resize with manual option - self.resize_server(server['id'], self.flavor_ref_alt, - disk_config='MANUAL') - - server = self.client.show_server(server['id'])['server'] - self.assertEqual('MANUAL', server['OS-DCF:diskConfig']) - - @decorators.idempotent_id('5ef18867-358d-4de9-b3c9-94d4ba35742f') - def test_update_server_from_auto_to_manual(self): - # A server should be updated from auto to manual disk config - server = self.create_test_server(wait_until='ACTIVE') - self.addCleanup(self.client.delete_server, server['id']) - self._update_server_with_disk_config(server['id'], - disk_config='AUTO') - - # Update the disk_config attribute to manual - server = self.client.update_server(server['id'], - disk_config='MANUAL')['server'] - waiters.wait_for_server_status(self.client, server['id'], 'ACTIVE') - - # Verify the disk_config attribute is set correctly - server = self.client.show_server(server['id'])['server'] - self.assertEqual('MANUAL', server['OS-DCF:diskConfig']) diff --git a/tempest/api/compute/servers/test_instance_actions.py b/tempest/api/compute/servers/test_instance_actions.py deleted file mode 100644 index b916a42d6..000000000 --- a/tempest/api/compute/servers/test_instance_actions.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright 2013 NEC Corporation -# 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 tempest.api.compute import base -from tempest.common import waiters -from tempest.lib import decorators - - -class InstanceActionsTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_clients(cls): - super(InstanceActionsTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(InstanceActionsTestJSON, cls).resource_setup() - cls.server = cls.create_test_server(wait_until='ACTIVE') - cls.request_id = cls.server.response['x-compute-request-id'] - - @decorators.idempotent_id('77ca5cc5-9990-45e0-ab98-1de8fead201a') - def test_list_instance_actions(self): - # List actions of the provided server - self.client.reboot_server(self.server['id'], type='HARD') - waiters.wait_for_server_status(self.client, - self.server['id'], 'ACTIVE') - - body = (self.client.list_instance_actions(self.server['id']) - ['instanceActions']) - self.assertEqual(len(body), 2, str(body)) - self.assertEqual(sorted([i['action'] for i in body]), - ['create', 'reboot']) - - @decorators.idempotent_id('aacc71ca-1d70-4aa5-bbf6-0ff71470e43c') - def test_get_instance_action(self): - # Get the action details of the provided server - body = self.client.show_instance_action( - self.server['id'], self.request_id)['instanceAction'] - self.assertEqual(self.server['id'], body['instance_uuid']) - self.assertEqual('create', body['action']) - - -class InstanceActionsV221TestJSON(base.BaseV2ComputeTest): - - min_microversion = '2.21' - max_microversion = 'latest' - - @classmethod - def setup_clients(cls): - super(InstanceActionsV221TestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @decorators.idempotent_id('0a0f85d4-10fa-41f6-bf80-a54fb4aa2ae1') - def test_get_list_deleted_instance_actions(self): - - # List actions of the deleted server - server = self.create_test_server(wait_until='ACTIVE') - self.client.delete_server(server['id']) - waiters.wait_for_server_termination(self.client, server['id']) - body = (self.client.list_instance_actions(server['id']) - ['instanceActions']) - self.assertEqual(len(body), 2, str(body)) - self.assertEqual(sorted([i['action'] for i in body]), - ['create', 'delete']) diff --git a/tempest/api/compute/servers/test_instance_actions_negative.py b/tempest/api/compute/servers/test_instance_actions_negative.py deleted file mode 100644 index 1d3a79086..000000000 --- a/tempest/api/compute/servers/test_instance_actions_negative.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2013 NEC Corporation -# 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 tempest.api.compute import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class InstanceActionsNegativeTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_clients(cls): - super(InstanceActionsNegativeTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(InstanceActionsNegativeTestJSON, cls).resource_setup() - cls.server = cls.create_test_server(wait_until='ACTIVE') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('67e1fce6-7ec2-45c6-92d4-0a8f1a632910') - def test_list_instance_actions_non_existent_server(self): - # List actions of the non-existent server id - non_existent_server_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.client.list_instance_actions, - non_existent_server_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0269f40a-6f18-456c-b336-c03623c897f1') - def test_get_instance_action_invalid_request(self): - # Get the action details of the provided server with invalid request - self.assertRaises(lib_exc.NotFound, self.client.show_instance_action, - self.server['id'], '999') diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py deleted file mode 100644 index a4ed8e11f..000000000 --- a/tempest/api/compute/servers/test_list_server_filters.py +++ /dev/null @@ -1,323 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 testtools - -from tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common import fixed_network -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -CONF = config.CONF - - -class ListServerFiltersTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_credentials(cls): - cls.set_network_resources(network=True, subnet=True, dhcp=True) - super(ListServerFiltersTestJSON, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(ListServerFiltersTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(ListServerFiltersTestJSON, cls).resource_setup() - - network = cls.get_tenant_network() - if network: - cls.fixed_network_name = network.get('name') - else: - cls.fixed_network_name = None - network_kwargs = fixed_network.set_networks_kwarg(network) - cls.s1_name = data_utils.rand_name(cls.__name__ + '-instance') - cls.s1 = cls.create_test_server(name=cls.s1_name, **network_kwargs) - - cls.s2_name = data_utils.rand_name(cls.__name__ + '-instance') - # If image_ref_alt is "" or None then we still want to boot a server - # but we rely on `testtools.skipUnless` decorator to actually skip - # the irrelevant tests. - cls.s2 = cls.create_test_server( - name=cls.s2_name, image_id=cls.image_ref_alt or cls.image_ref) - - cls.s3_name = data_utils.rand_name(cls.__name__ + '-instance') - cls.s3 = cls.create_test_server(name=cls.s3_name, - flavor=cls.flavor_ref_alt, - wait_until='ACTIVE') - - waiters.wait_for_server_status(cls.client, cls.s1['id'], - 'ACTIVE') - waiters.wait_for_server_status(cls.client, cls.s2['id'], - 'ACTIVE') - - @decorators.idempotent_id('05e8a8e7-9659-459a-989d-92c2f501f4ba') - @testtools.skipUnless(CONF.compute.image_ref != CONF.compute.image_ref_alt, - "Need distinct images to run this test") - def test_list_servers_filter_by_image(self): - # Filter the list of servers by image - params = {'image': self.image_ref} - body = self.client.list_servers(**params) - servers = body['servers'] - - self.assertIn(self.s1['id'], map(lambda x: x['id'], servers)) - self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers)) - self.assertIn(self.s3['id'], map(lambda x: x['id'], servers)) - - @decorators.idempotent_id('573637f5-7325-47bb-9144-3476d0416908') - def test_list_servers_filter_by_flavor(self): - # Filter the list of servers by flavor - params = {'flavor': self.flavor_ref_alt} - body = self.client.list_servers(**params) - servers = body['servers'] - - self.assertNotIn(self.s1['id'], map(lambda x: x['id'], servers)) - self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers)) - self.assertIn(self.s3['id'], map(lambda x: x['id'], servers)) - - @decorators.idempotent_id('9b067a7b-7fee-4f6a-b29c-be43fe18fc5a') - def test_list_servers_filter_by_server_name(self): - # Filter the list of servers by server name - params = {'name': self.s1_name} - body = self.client.list_servers(**params) - servers = body['servers'] - - self.assertIn(self.s1_name, map(lambda x: x['name'], servers)) - self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers)) - self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers)) - - @decorators.idempotent_id('ca78e20e-fddb-4ce6-b7f7-bcbf8605e66e') - def test_list_servers_filter_by_active_status(self): - # Filter the list of servers by server active status - params = {'status': 'active'} - body = self.client.list_servers(**params) - servers = body['servers'] - - self.assertIn(self.s1['id'], map(lambda x: x['id'], servers)) - self.assertIn(self.s2['id'], map(lambda x: x['id'], servers)) - self.assertIn(self.s3['id'], map(lambda x: x['id'], servers)) - - @decorators.idempotent_id('451dbbb2-f330-4a9f-b0e1-5f5d2cb0f34c') - def test_list_servers_filter_by_shutoff_status(self): - # Filter the list of servers by server shutoff status - params = {'status': 'shutoff'} - self.client.stop_server(self.s1['id']) - waiters.wait_for_server_status(self.client, self.s1['id'], - 'SHUTOFF') - body = self.client.list_servers(**params) - self.client.start_server(self.s1['id']) - waiters.wait_for_server_status(self.client, self.s1['id'], - 'ACTIVE') - servers = body['servers'] - - self.assertIn(self.s1['id'], map(lambda x: x['id'], servers)) - self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers)) - self.assertNotIn(self.s3['id'], map(lambda x: x['id'], servers)) - - @decorators.idempotent_id('614cdfc1-d557-4bac-915b-3e67b48eee76') - def test_list_servers_filter_by_limit(self): - # Verify only the expected number of servers are returned - params = {'limit': 1} - servers = self.client.list_servers(**params) - self.assertEqual(1, len([x for x in servers['servers'] if 'id' in x])) - - @decorators.idempotent_id('b1495414-2d93-414c-8019-849afe8d319e') - def test_list_servers_filter_by_zero_limit(self): - # Verify only the expected number of servers are returned - params = {'limit': 0} - servers = self.client.list_servers(**params) - self.assertEmpty(servers['servers']) - - @decorators.idempotent_id('37791bbd-90c0-4de0-831e-5f38cba9c6b3') - def test_list_servers_filter_by_exceed_limit(self): - # Verify only the expected number of servers are returned - params = {'limit': 100000} - servers = self.client.list_servers(**params) - all_servers = self.client.list_servers() - self.assertEqual(len([x for x in all_servers['servers'] if 'id' in x]), - len([x for x in servers['servers'] if 'id' in x])) - - @decorators.idempotent_id('b3304c3b-97df-46d2-8cd3-e2b6659724e7') - @testtools.skipUnless(CONF.compute.image_ref != CONF.compute.image_ref_alt, - "Need distinct images to run this test") - def test_list_servers_detailed_filter_by_image(self): - # Filter the detailed list of servers by image - params = {'image': self.image_ref} - body = self.client.list_servers(detail=True, **params) - servers = body['servers'] - - self.assertIn(self.s1['id'], map(lambda x: x['id'], servers)) - self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers)) - self.assertIn(self.s3['id'], map(lambda x: x['id'], servers)) - - @decorators.idempotent_id('80c574cc-0925-44ba-8602-299028357dd9') - def test_list_servers_detailed_filter_by_flavor(self): - # Filter the detailed list of servers by flavor - params = {'flavor': self.flavor_ref_alt} - body = self.client.list_servers(detail=True, **params) - servers = body['servers'] - - self.assertNotIn(self.s1['id'], map(lambda x: x['id'], servers)) - self.assertNotIn(self.s2['id'], map(lambda x: x['id'], servers)) - self.assertIn(self.s3['id'], map(lambda x: x['id'], servers)) - - @decorators.idempotent_id('f9eb2b70-735f-416c-b260-9914ac6181e4') - def test_list_servers_detailed_filter_by_server_name(self): - # Filter the detailed list of servers by server name - params = {'name': self.s1_name} - body = self.client.list_servers(detail=True, **params) - servers = body['servers'] - - self.assertIn(self.s1_name, map(lambda x: x['name'], servers)) - self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers)) - self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers)) - - @decorators.idempotent_id('de2612ab-b7dd-4044-b0b1-d2539601911f') - def test_list_servers_detailed_filter_by_server_status(self): - # Filter the detailed list of servers by server status - params = {'status': 'active'} - body = self.client.list_servers(detail=True, **params) - servers = body['servers'] - test_ids = [s['id'] for s in (self.s1, self.s2, self.s3)] - - self.assertIn(self.s1['id'], map(lambda x: x['id'], servers)) - self.assertIn(self.s2['id'], map(lambda x: x['id'], servers)) - self.assertIn(self.s3['id'], map(lambda x: x['id'], servers)) - self.assertEqual(['ACTIVE'] * 3, [x['status'] for x in servers - if x['id'] in test_ids]) - - @decorators.idempotent_id('e9f624ee-92af-4562-8bec-437945a18dcb') - def test_list_servers_filtered_by_name_wildcard(self): - # List all servers that contains '-instance' in name - params = {'name': '-instance'} - body = self.client.list_servers(**params) - servers = body['servers'] - - self.assertIn(self.s1_name, map(lambda x: x['name'], servers)) - self.assertIn(self.s2_name, map(lambda x: x['name'], servers)) - self.assertIn(self.s3_name, map(lambda x: x['name'], servers)) - - # Let's take random part of name and try to search it - part_name = self.s1_name[6:-1] - - params = {'name': part_name} - body = self.client.list_servers(**params) - servers = body['servers'] - - self.assertIn(self.s1_name, map(lambda x: x['name'], servers)) - self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers)) - self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers)) - - @decorators.idempotent_id('24a89b0c-0d55-4a28-847f-45075f19b27b') - def test_list_servers_filtered_by_name_regex(self): - # list of regex that should match s1, s2 and s3 - regexes = ['^.*\-instance\-[0-9]+$', '^.*\-instance\-.*$'] - for regex in regexes: - params = {'name': regex} - body = self.client.list_servers(**params) - servers = body['servers'] - - self.assertIn(self.s1_name, map(lambda x: x['name'], servers)) - self.assertIn(self.s2_name, map(lambda x: x['name'], servers)) - self.assertIn(self.s3_name, map(lambda x: x['name'], servers)) - - # Let's take random part of name and try to search it - part_name = self.s1_name[-10:] - - params = {'name': part_name} - body = self.client.list_servers(**params) - servers = body['servers'] - - self.assertIn(self.s1_name, map(lambda x: x['name'], servers)) - self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers)) - self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers)) - - @decorators.idempotent_id('43a1242e-7b31-48d1-88f2-3f72aa9f2077') - def test_list_servers_filtered_by_ip(self): - # Filter servers by ip - # Here should be listed 1 server - if not self.fixed_network_name: - msg = 'fixed_network_name needs to be configured to run this test' - raise self.skipException(msg) - - # list servers filter by ip is something "regexp match", i.e, - # filter by "10.1.1.1" will return both "10.1.1.1" and "10.1.1.10". - # so here look for the longest server ip, and filter by that ip, - # so as to ensure only one server is returned. - ip_list = {} - self.s1 = self.client.show_server(self.s1['id'])['server'] - # Get first ip address inspite of v4 or v6 - ip_addr = self.s1['addresses'][self.fixed_network_name][0]['addr'] - ip_list[ip_addr] = self.s1['id'] - - self.s2 = self.client.show_server(self.s2['id'])['server'] - ip_addr = self.s2['addresses'][self.fixed_network_name][0]['addr'] - ip_list[ip_addr] = self.s2['id'] - - self.s3 = self.client.show_server(self.s3['id'])['server'] - ip_addr = self.s3['addresses'][self.fixed_network_name][0]['addr'] - ip_list[ip_addr] = self.s3['id'] - - longest_ip = max([[len(ip), ip] for ip in ip_list])[1] - params = {'ip': longest_ip} - body = self.client.list_servers(**params) - servers = body['servers'] - - self.assertIn(ip_list[longest_ip], map(lambda x: x['id'], servers)) - del ip_list[longest_ip] - for ip in ip_list: - self.assertNotIn(ip_list[ip], map(lambda x: x['id'], servers)) - - @decorators.skip_because(bug="1540645") - @decorators.idempotent_id('a905e287-c35e-42f2-b132-d02b09f3654a') - def test_list_servers_filtered_by_ip_regex(self): - # Filter servers by regex ip - # List all servers filtered by part of ip address. - # Here should be listed all servers - if not self.fixed_network_name: - msg = 'fixed_network_name needs to be configured to run this test' - raise self.skipException(msg) - self.s1 = self.client.show_server(self.s1['id'])['server'] - addr_spec = self.s1['addresses'][self.fixed_network_name][0] - ip = addr_spec['addr'][0:-3] - if addr_spec['version'] == 4: - params = {'ip': ip} - else: - params = {'ip6': ip} - # capture all servers in case something goes wrong - all_servers = self.client.list_servers(detail=True) - body = self.client.list_servers(**params) - servers = body['servers'] - - self.assertIn(self.s1_name, map(lambda x: x['name'], servers), - "%s not found in %s, all servers %s" % - (self.s1_name, servers, all_servers)) - self.assertIn(self.s2_name, map(lambda x: x['name'], servers), - "%s not found in %s, all servers %s" % - (self.s2_name, servers, all_servers)) - self.assertIn(self.s3_name, map(lambda x: x['name'], servers), - "%s not found in %s, all servers %s" % - (self.s3_name, servers, all_servers)) - - @decorators.idempotent_id('67aec2d0-35fe-4503-9f92-f13272b867ed') - def test_list_servers_detailed_limit_results(self): - # Verify only the expected number of detailed results are returned - params = {'limit': 1} - servers = self.client.list_servers(detail=True, **params) - self.assertEqual(1, len(servers['servers'])) diff --git a/tempest/api/compute/servers/test_list_servers_negative.py b/tempest/api/compute/servers/test_list_servers_negative.py deleted file mode 100644 index 6c9b28772..000000000 --- a/tempest/api/compute/servers/test_list_servers_negative.py +++ /dev/null @@ -1,135 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.compute import base -from tempest.common import waiters -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ListServersNegativeTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_clients(cls): - super(ListServersNegativeTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(ListServersNegativeTestJSON, cls).resource_setup() - - # The following servers are created for use - # by the test methods in this class. These - # servers are cleaned up automatically in the - # tearDownClass method of the super-class. - body = cls.create_test_server(wait_until='ACTIVE', min_count=3) - - # delete one of the created servers - cls.deleted_id = body['server']['id'] - cls.client.delete_server(cls.deleted_id) - waiters.wait_for_server_termination(cls.client, cls.deleted_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('24a26f1a-1ddc-4eea-b0d7-a90cc874ad8f') - def test_list_servers_with_a_deleted_server(self): - # Verify deleted servers do not show by default in list servers - # List servers and verify server not returned - body = self.client.list_servers() - servers = body['servers'] - actual = [srv for srv in servers - if srv['id'] == self.deleted_id] - self.assertEmpty(actual) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ff01387d-c7ad-47b4-ae9e-64fa214638fe') - def test_list_servers_by_non_existing_image(self): - # Listing servers for a non existing image returns empty list - body = self.client.list_servers(image='non_existing_image') - servers = body['servers'] - self.assertEmpty(servers) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5913660b-223b-44d4-a651-a0fbfd44ca75') - def test_list_servers_by_non_existing_flavor(self): - # Listing servers by non existing flavor returns empty list - body = self.client.list_servers(flavor='non_existing_flavor') - servers = body['servers'] - self.assertEmpty(servers) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e2c77c4a-000a-4af3-a0bd-629a328bde7c') - def test_list_servers_by_non_existing_server_name(self): - # Listing servers for a non existent server name returns empty list - body = self.client.list_servers(name='non_existing_server_name') - servers = body['servers'] - self.assertEmpty(servers) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('fcdf192d-0f74-4d89-911f-1ec002b822c4') - def test_list_servers_status_non_existing(self): - # Return an empty list when invalid status is specified - body = self.client.list_servers(status='non_existing_status') - servers = body['servers'] - self.assertEmpty(servers) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d47c17fb-eebd-4287-8e95-f20a7e627b18') - def test_list_servers_by_limits_greater_than_actual_count(self): - # Gather the complete list of servers in the project for reference - full_list = self.client.list_servers()['servers'] - # List servers by specifying a greater value for limit - limit = len(full_list) + 100 - body = self.client.list_servers(limit=limit) - self.assertEqual(len(full_list), len(body['servers'])) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('679bc053-5e70-4514-9800-3dfab1a380a6') - def test_list_servers_by_limits_pass_string(self): - # Return an error if a string value is passed for limit - self.assertRaises(lib_exc.BadRequest, self.client.list_servers, - limit='testing') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('62610dd9-4713-4ee0-8beb-fd2c1aa7f950') - def test_list_servers_by_limits_pass_negative_value(self): - # Return an error if a negative value for limit is passed - self.assertRaises(lib_exc.BadRequest, self.client.list_servers, - limit=-1) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('87d12517-e20a-4c9c-97b6-dd1628d6d6c9') - def test_list_servers_by_changes_since_invalid_date(self): - # Return an error when invalid date format is passed - params = {'changes-since': '2011/01/01'} - self.assertRaises(lib_exc.BadRequest, self.client.list_servers, - **params) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('74745ad8-b346-45b5-b9b8-509d7447fc1f') - def test_list_servers_by_changes_since_future_date(self): - # Return an empty list when a date in the future is passed - changes_since = {'changes-since': '2051-01-01T12:34:00Z'} - body = self.client.list_servers(**changes_since) - self.assertEmpty(body['servers']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('93055106-2d34-46fe-af68-d9ddbf7ee570') - def test_list_servers_detail_server_is_deleted(self): - # Server details are not listed for a deleted server - body = self.client.list_servers(detail=True) - servers = body['servers'] - actual = [srv for srv in servers - if srv['id'] == self.deleted_id] - self.assertEmpty(actual) diff --git a/tempest/api/compute/servers/test_multiple_create.py b/tempest/api/compute/servers/test_multiple_create.py deleted file mode 100644 index 059454dd0..000000000 --- a/tempest/api/compute/servers/test_multiple_create.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2013 IBM 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 tempest.api.compute import base -from tempest.common import compute -from tempest.lib import decorators - - -class MultipleCreateTestJSON(base.BaseV2ComputeTest): - - @decorators.idempotent_id('61e03386-89c3-449c-9bb1-a06f423fd9d1') - def test_multiple_create(self): - tenant_network = self.get_tenant_network() - body, servers = compute.create_test_server( - self.os_primary, - wait_until='ACTIVE', - min_count=2, - tenant_network=tenant_network) - for server in servers: - self.addCleanup(self.servers_client.delete_server, server['id']) - # NOTE(maurosr): do status response check and also make sure that - # reservation_id is not in the response body when the request send - # contains return_reservation_id=False - self.assertNotIn('reservation_id', body) - self.assertEqual(2, len(servers)) - - @decorators.idempotent_id('864777fb-2f1e-44e3-b5b9-3eb6fa84f2f7') - def test_multiple_create_with_reservation_return(self): - body = self.create_test_server(wait_until='ACTIVE', - min_count=1, - max_count=2, - return_reservation_id=True) - self.assertIn('reservation_id', body) diff --git a/tempest/api/compute/servers/test_multiple_create_negative.py b/tempest/api/compute/servers/test_multiple_create_negative.py deleted file mode 100644 index 422510f75..000000000 --- a/tempest/api/compute/servers/test_multiple_create_negative.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright 2013 IBM 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 tempest.api.compute import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class MultipleCreateNegativeTestJSON(base.BaseV2ComputeTest): - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('daf29d8d-e928-4a01-9a8c-b129603f3fc0') - def test_min_count_less_than_one(self): - invalid_min_count = 0 - self.assertRaises(lib_exc.BadRequest, self.create_test_server, - min_count=invalid_min_count) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('999aa722-d624-4423-b813-0d1ac9884d7a') - def test_min_count_non_integer(self): - invalid_min_count = 2.5 - self.assertRaises(lib_exc.BadRequest, self.create_test_server, - min_count=invalid_min_count) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a6f9c2ab-e060-4b82-b23c-4532cb9390ff') - def test_max_count_less_than_one(self): - invalid_max_count = 0 - self.assertRaises(lib_exc.BadRequest, self.create_test_server, - max_count=invalid_max_count) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9c5698d1-d7af-4c80-b971-9d403135eea2') - def test_max_count_non_integer(self): - invalid_max_count = 2.5 - self.assertRaises(lib_exc.BadRequest, self.create_test_server, - max_count=invalid_max_count) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('476da616-f1ef-4271-a9b1-b9fc87727cdf') - def test_max_count_less_than_min_count(self): - min_count = 3 - max_count = 2 - self.assertRaises(lib_exc.BadRequest, self.create_test_server, - min_count=min_count, - max_count=max_count) diff --git a/tempest/api/compute/servers/test_novnc.py b/tempest/api/compute/servers/test_novnc.py deleted file mode 100644 index 90b0665ca..000000000 --- a/tempest/api/compute/servers/test_novnc.py +++ /dev/null @@ -1,186 +0,0 @@ -# Copyright 2016-2017 OpenStack Foundation -# 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 struct - -import six -import urllib3 - -from tempest.api.compute import base -from tempest.common import compute -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - -if six.PY2: - ord_func = ord -else: - ord_func = int - - -class NoVNCConsoleTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(NoVNCConsoleTestJSON, cls).skip_checks() - if not CONF.compute_feature_enabled.vnc_console: - raise cls.skipException('VNC Console feature is disabled.') - - def setUp(self): - super(NoVNCConsoleTestJSON, self).setUp() - self._websocket = None - - def tearDown(self): - self.server_check_teardown() - super(NoVNCConsoleTestJSON, self).tearDown() - if self._websocket is not None: - self._websocket.close() - - @classmethod - def setup_clients(cls): - super(NoVNCConsoleTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(NoVNCConsoleTestJSON, cls).resource_setup() - cls.server = cls.create_test_server(wait_until="ACTIVE") - - def _validate_novnc_html(self, vnc_url): - """Verify we can connect to novnc and get back the javascript.""" - resp = urllib3.PoolManager().request('GET', vnc_url) - # Make sure that the GET request was accepted by the novncproxy - self.assertEqual(resp.status, 200, 'Got a Bad HTTP Response on the ' - 'initial call: ' + six.text_type(resp.status)) - # Do some basic validation to make sure it is an expected HTML document - resp_data = resp.data.decode() - self.assertIn('', resp_data, - 'Not a valid html document in the response.') - self.assertIn('', resp_data, - 'Not a valid html document in the response.') - # Just try to make sure we got JavaScript back for noVNC, since we - # won't actually use it since not inside of a browser - self.assertIn('noVNC', resp_data, - 'Not a valid noVNC javascript html document.') - self.assertIn('L", - data[20:24])[0] + 24), - 'Server initialization was not the right format.') - # Since the rest of the data on the screen is arbitrary, we will - # close the socket and end our validation of the data at this point - # Assert that the latest check was false, meaning that the server - # initialization was the right format - self.assertFalse(data_length <= 24 or - data_length != (struct.unpack(">L", - data[20:24])[0] + 24)) - - def _validate_websocket_upgrade(self): - self.assertTrue( - self._websocket.response.startswith(b'HTTP/1.1 101 Switching ' - b'Protocols\r\n'), - 'Did not get the expected 101 on the websockify call: ' - + six.text_type(self._websocket.response)) - self.assertTrue( - self._websocket.response.find(b'Server: WebSockify') > 0, - 'Did not get the expected WebSocket HTTP Response.') - - @decorators.idempotent_id('c640fdff-8ab4-45a4-a5d8-7e6146cbd0dc') - def test_novnc(self): - body = self.client.get_vnc_console(self.server['id'], - type='novnc')['console'] - self.assertEqual('novnc', body['type']) - # Do the initial HTTP Request to novncproxy to get the NoVNC JavaScript - self._validate_novnc_html(body['url']) - # Do the WebSockify HTTP Request to novncproxy to do the RFB connection - self._websocket = compute.create_websocket(body['url']) - # Validate that we succesfully connected and upgraded to Web Sockets - self._validate_websocket_upgrade() - # Validate the RFB Negotiation to determine if a valid VNC session - self._validate_rfb_negotiation() - - @decorators.idempotent_id('f9c79937-addc-4aaa-9e0e-841eef02aeb7') - def test_novnc_bad_token(self): - body = self.client.get_vnc_console(self.server['id'], - type='novnc')['console'] - self.assertEqual('novnc', body['type']) - # Do the WebSockify HTTP Request to novncproxy with a bad token - url = body['url'].replace('token=', 'token=bad') - self._websocket = compute.create_websocket(url) - # Make sure the novncproxy rejected the connection and closed it - data = self._websocket.receive_frame() - self.assertTrue(data is None or not data, - "The novnc proxy actually sent us some data, but we " - "expected it to close the connection.") diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py deleted file mode 100644 index cd09177b0..000000000 --- a/tempest/api/compute/servers/test_server_actions.py +++ /dev/null @@ -1,589 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_log import log as logging -from six.moves.urllib import parse as urlparse -import testtools - -from tempest.api.compute import base -from tempest.common import compute -from tempest.common.utils.linux import remote_client -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - -LOG = logging.getLogger(__name__) - - -class ServerActionsTestJSON(base.BaseV2ComputeTest): - run_ssh = CONF.validation.run_validation - - def setUp(self): - # NOTE(afazekas): Normally we use the same server with all test cases, - # but if it has an issue, we build a new one - super(ServerActionsTestJSON, self).setUp() - # Check if the server is in a clean state after test - try: - waiters.wait_for_server_status(self.client, - self.server_id, 'ACTIVE') - except lib_exc.NotFound: - # The server was deleted by previous test, create a new one - server = self.create_test_server( - validatable=True, - wait_until='ACTIVE') - self.__class__.server_id = server['id'] - except Exception: - # Rebuild server if something happened to it during a test - self.__class__.server_id = self.rebuild_server( - self.server_id, validatable=True) - - def tearDown(self): - self.server_check_teardown() - super(ServerActionsTestJSON, self).tearDown() - - @classmethod - def setup_credentials(cls): - cls.prepare_instance_network() - super(ServerActionsTestJSON, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(ServerActionsTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - cls.set_validation_resources() - - super(ServerActionsTestJSON, cls).resource_setup() - cls.server_id = cls.rebuild_server(None, validatable=True) - - @decorators.idempotent_id('6158df09-4b82-4ab3-af6d-29cf36af858d') - @testtools.skipUnless(CONF.compute_feature_enabled.change_password, - 'Change password not available.') - def test_change_server_password(self): - # Since this test messes with the password and makes the - # server unreachable, it should create its own server - newserver = self.create_test_server( - validatable=True, - wait_until='ACTIVE') - # The server's password should be set to the provided password - new_password = 'Newpass1234' - self.client.change_password(newserver['id'], adminPass=new_password) - waiters.wait_for_server_status(self.client, newserver['id'], 'ACTIVE') - - if CONF.validation.run_validation: - # Verify that the user can authenticate with the new password - server = self.client.show_server(newserver['id'])['server'] - linux_client = remote_client.RemoteClient( - self.get_server_ip(server), - self.ssh_user, - new_password, - server=server, - servers_client=self.client) - linux_client.validate_authentication() - - def _test_reboot_server(self, reboot_type): - if CONF.validation.run_validation: - # Get the time the server was last rebooted, - server = self.client.show_server(self.server_id)['server'] - linux_client = remote_client.RemoteClient( - self.get_server_ip(server), - self.ssh_user, - self.password, - self.validation_resources['keypair']['private_key'], - server=server, - servers_client=self.client) - boot_time = linux_client.get_boot_time() - - # NOTE: This sync is for avoiding the loss of pub key data - # in a server - linux_client.exec_command("sync") - - self.client.reboot_server(self.server_id, type=reboot_type) - waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE') - - if CONF.validation.run_validation: - # Log in and verify the boot time has changed - linux_client = remote_client.RemoteClient( - self.get_server_ip(server), - self.ssh_user, - self.password, - self.validation_resources['keypair']['private_key'], - server=server, - servers_client=self.client) - new_boot_time = linux_client.get_boot_time() - self.assertGreater(new_boot_time, boot_time, - '%s > %s' % (new_boot_time, boot_time)) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('2cb1baf6-ac8d-4429-bf0d-ba8a0ba53e32') - def test_reboot_server_hard(self): - # The server should be power cycled - self._test_reboot_server('HARD') - - @decorators.skip_because(bug="1014647") - @decorators.idempotent_id('4640e3ef-a5df-482e-95a1-ceeeb0faa84d') - def test_reboot_server_soft(self): - # The server should be signaled to reboot gracefully - self._test_reboot_server('SOFT') - - @decorators.idempotent_id('1d1c9104-1b0a-11e7-a3d4-fa163e65f5ce') - def test_remove_server_all_security_groups(self): - server = self.create_test_server(wait_until='ACTIVE') - - # Remove all Security group - self.client.remove_security_group( - server['id'], name=server['security_groups'][0]['name']) - - # Verify all Security group - server = self.client.show_server(server['id'])['server'] - self.assertNotIn('security_groups', server) - - def _rebuild_server_and_check(self, image_ref): - rebuilt_server = (self.client.rebuild_server(self.server_id, image_ref) - ['server']) - waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE') - msg = ('Server was not rebuilt to the original image. ' - 'The original image: {0}. The current image: {1}' - .format(image_ref, rebuilt_server['image']['id'])) - self.assertEqual(image_ref, rebuilt_server['image']['id'], msg) - - @decorators.idempotent_id('aaa6cdf3-55a7-461a-add9-1c8596b9a07c') - def test_rebuild_server(self): - # Get the IPs the server has before rebuilding it - original_addresses = (self.client.show_server(self.server_id)['server'] - ['addresses']) - # The server should be rebuilt using the provided image and data - meta = {'rebuild': 'server'} - new_name = data_utils.rand_name(self.__class__.__name__ + '-server') - password = 'rebuildPassw0rd' - rebuilt_server = self.client.rebuild_server( - self.server_id, - self.image_ref_alt, - name=new_name, - metadata=meta, - adminPass=password)['server'] - - # If the server was rebuilt on a different image, restore it to the - # original image once the test ends - if self.image_ref_alt != self.image_ref: - self.addCleanup(self._rebuild_server_and_check, self.image_ref) - - # Verify the properties in the initial response are correct - self.assertEqual(self.server_id, rebuilt_server['id']) - rebuilt_image_id = rebuilt_server['image']['id'] - self.assertTrue(self.image_ref_alt.endswith(rebuilt_image_id)) - self.assertEqual(self.flavor_ref, rebuilt_server['flavor']['id']) - - # Verify the server properties after the rebuild completes - waiters.wait_for_server_status(self.client, - rebuilt_server['id'], 'ACTIVE') - server = self.client.show_server(rebuilt_server['id'])['server'] - rebuilt_image_id = server['image']['id'] - self.assertTrue(self.image_ref_alt.endswith(rebuilt_image_id)) - self.assertEqual(new_name, server['name']) - self.assertEqual(original_addresses, server['addresses']) - - if CONF.validation.run_validation: - # Authentication is attempted in the following order of priority: - # 1.The key passed in, if one was passed in. - # 2.Any key we can find through an SSH agent (if allowed). - # 3.Any "id_rsa", "id_dsa" or "id_ecdsa" key discoverable in - # ~/.ssh/ (if allowed). - # 4.Plain username/password auth, if a password was given. - linux_client = remote_client.RemoteClient( - self.get_server_ip(rebuilt_server), - self.ssh_user, - password, - self.validation_resources['keypair']['private_key'], - server=rebuilt_server, - servers_client=self.client) - linux_client.validate_authentication() - - @decorators.idempotent_id('30449a88-5aff-4f9b-9866-6ee9b17f906d') - def test_rebuild_server_in_stop_state(self): - # The server in stop state should be rebuilt using the provided - # image and remain in SHUTOFF state - server = self.client.show_server(self.server_id)['server'] - old_image = server['image']['id'] - new_image = (self.image_ref_alt - if old_image == self.image_ref else self.image_ref) - self.client.stop_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, 'SHUTOFF') - rebuilt_server = (self.client.rebuild_server(self.server_id, new_image) - ['server']) - # If the server was rebuilt on a different image, restore it to the - # original image once the test ends - if self.image_ref_alt != self.image_ref: - self.addCleanup(self._rebuild_server_and_check, old_image) - - # Verify the properties in the initial response are correct - self.assertEqual(self.server_id, rebuilt_server['id']) - rebuilt_image_id = rebuilt_server['image']['id'] - self.assertEqual(new_image, rebuilt_image_id) - self.assertEqual(self.flavor_ref, rebuilt_server['flavor']['id']) - - # Verify the server properties after the rebuild completes - waiters.wait_for_server_status(self.client, - rebuilt_server['id'], 'SHUTOFF') - server = self.client.show_server(rebuilt_server['id'])['server'] - rebuilt_image_id = server['image']['id'] - self.assertEqual(new_image, rebuilt_image_id) - - self.client.start_server(self.server_id) - - @decorators.idempotent_id('b68bd8d6-855d-4212-b59b-2e704044dace') - @test.services('volume') - def test_rebuild_server_with_volume_attached(self): - # create a new volume and attach it to the server - volume = self.create_volume() - - server = self.client.show_server(self.server_id)['server'] - self.attach_volume(server, volume) - - # run general rebuild test - self.test_rebuild_server() - - # make sure the volume is attached to the instance after rebuild - vol_after_rebuild = self.volumes_client.show_volume(volume['id']) - vol_after_rebuild = vol_after_rebuild['volume'] - self.assertEqual('in-use', vol_after_rebuild['status']) - self.assertEqual(self.server_id, - vol_after_rebuild['attachments'][0]['server_id']) - - def _test_resize_server_confirm(self, stop=False): - # The server's RAM and disk space should be modified to that of - # the provided flavor - - if stop: - self.client.stop_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, - 'SHUTOFF') - - self.client.resize_server(self.server_id, self.flavor_ref_alt) - # NOTE(jlk): Explicitly delete the server to get a new one for later - # tests. Avoids resize down race issues. - self.addCleanup(self.delete_server, self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, - 'VERIFY_RESIZE') - - self.client.confirm_resize_server(self.server_id) - expected_status = 'SHUTOFF' if stop else 'ACTIVE' - waiters.wait_for_server_status(self.client, self.server_id, - expected_status) - - server = self.client.show_server(self.server_id)['server'] - self.assertEqual(self.flavor_ref_alt, server['flavor']['id']) - - if stop: - # NOTE(mriedem): tearDown requires the server to be started. - self.client.start_server(self.server_id) - - @decorators.idempotent_id('1499262a-9328-4eda-9068-db1ac57498d2') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize not available.') - def test_resize_server_confirm(self): - self._test_resize_server_confirm(stop=False) - - @decorators.idempotent_id('138b131d-66df-48c9-a171-64f45eb92962') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize not available.') - def test_resize_server_confirm_from_stopped(self): - self._test_resize_server_confirm(stop=True) - - @decorators.idempotent_id('c03aab19-adb1-44f5-917d-c419577e9e68') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize not available.') - def test_resize_server_revert(self): - # The server's RAM and disk space should return to its original - # values after a resize is reverted - - self.client.resize_server(self.server_id, self.flavor_ref_alt) - # NOTE(zhufl): Explicitly delete the server to get a new one for later - # tests. Avoids resize down race issues. - self.addCleanup(self.delete_server, self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, - 'VERIFY_RESIZE') - - self.client.revert_resize_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE') - - server = self.client.show_server(self.server_id)['server'] - self.assertEqual(self.flavor_ref, server['flavor']['id']) - - @decorators.idempotent_id('b963d4f1-94b3-4c40-9e97-7b583f46e470') - @testtools.skipUnless(CONF.compute_feature_enabled.snapshot, - 'Snapshotting not available, backup not possible.') - @test.services('image') - def test_create_backup(self): - # Positive test:create backup successfully and rotate backups correctly - # create the first and the second backup - - # Check if glance v1 is available to determine which client to use. We - # prefer glance v1 for the compute API tests since the compute image - # API proxy was written for glance v1. - if CONF.image_feature_enabled.api_v1: - glance_client = self.os_primary.image_client - elif CONF.image_feature_enabled.api_v2: - glance_client = self.os_primary.image_client_v2 - else: - raise lib_exc.InvalidConfiguration( - 'Either api_v1 or api_v2 must be True in ' - '[image-feature-enabled].') - - backup1 = data_utils.rand_name('backup-1') - resp = self.client.create_backup(self.server_id, - backup_type='daily', - rotation=2, - name=backup1).response - oldest_backup_exist = True - - # the oldest one should be deleted automatically in this test - def _clean_oldest_backup(oldest_backup): - if oldest_backup_exist: - try: - glance_client.delete_image(oldest_backup) - except lib_exc.NotFound: - pass - else: - LOG.warning("Deletion of oldest backup %s should not have " - "been successful as it should have been " - "deleted during rotation.", oldest_backup) - - image1_id = data_utils.parse_image_id(resp['location']) - self.addCleanup(_clean_oldest_backup, image1_id) - waiters.wait_for_image_status(glance_client, - image1_id, 'active') - - backup2 = data_utils.rand_name('backup-2') - waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE') - resp = self.client.create_backup(self.server_id, - backup_type='daily', - rotation=2, - name=backup2).response - image2_id = data_utils.parse_image_id(resp['location']) - self.addCleanup(glance_client.delete_image, image2_id) - waiters.wait_for_image_status(glance_client, - image2_id, 'active') - - # verify they have been created - properties = { - 'image_type': 'backup', - 'backup_type': "daily", - 'instance_uuid': self.server_id, - } - params = { - 'status': 'active', - 'sort_key': 'created_at', - 'sort_dir': 'asc' - } - if CONF.image_feature_enabled.api_v1: - for key, value in properties.items(): - params['property-%s' % key] = value - image_list = glance_client.list_images( - detail=True, - **params)['images'] - else: - # Additional properties are flattened in glance v2. - params.update(properties) - image_list = glance_client.list_images(params)['images'] - - self.assertEqual(2, len(image_list)) - self.assertEqual((backup1, backup2), - (image_list[0]['name'], image_list[1]['name'])) - - # create the third one, due to the rotation is 2, - # the first one will be deleted - backup3 = data_utils.rand_name('backup-3') - waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE') - resp = self.client.create_backup(self.server_id, - backup_type='daily', - rotation=2, - name=backup3).response - image3_id = data_utils.parse_image_id(resp['location']) - self.addCleanup(glance_client.delete_image, image3_id) - # the first back up should be deleted - waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE') - glance_client.wait_for_resource_deletion(image1_id) - oldest_backup_exist = False - if CONF.image_feature_enabled.api_v1: - image_list = glance_client.list_images( - detail=True, **params)['images'] - else: - image_list = glance_client.list_images(params)['images'] - self.assertEqual(2, len(image_list), - 'Unexpected number of images for ' - 'v2:test_create_backup; was the oldest backup not ' - 'yet deleted? Image list: %s' % - [image['name'] for image in image_list]) - self.assertEqual((backup2, backup3), - (image_list[0]['name'], image_list[1]['name'])) - - def _get_output(self): - output = self.client.get_console_output( - self.server_id, length=10)['output'] - self.assertTrue(output, "Console output was empty.") - lines = len(output.split('\n')) - self.assertEqual(lines, 10) - - @decorators.idempotent_id('4b8867e6-fffa-4d54-b1d1-6fdda57be2f3') - @testtools.skipUnless(CONF.compute_feature_enabled.console_output, - 'Console output not supported.') - def test_get_console_output(self): - # Positive test:Should be able to GET the console output - # for a given server_id and number of lines - - # This reboot is necessary for outputting some console log after - # creating an instance backup. If an instance backup, the console - # log file is truncated and we cannot get any console log through - # "console-log" API. - # The detail is https://bugs.launchpad.net/nova/+bug/1251920 - self.client.reboot_server(self.server_id, type='HARD') - waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE') - self.wait_for(self._get_output) - - @decorators.idempotent_id('89104062-69d8-4b19-a71b-f47b7af093d7') - @testtools.skipUnless(CONF.compute_feature_enabled.console_output, - 'Console output not supported.') - def test_get_console_output_with_unlimited_size(self): - server = self.create_test_server(wait_until='ACTIVE') - - def _check_full_length_console_log(): - output = self.client.get_console_output(server['id'])['output'] - self.assertTrue(output, "Console output was empty.") - lines = len(output.split('\n')) - - # NOTE: This test tries to get full length console log, and the - # length should be bigger than the one of test_get_console_output. - self.assertGreater(lines, 10, "Cannot get enough console log " - "length. (lines: %s)" % lines) - - self.wait_for(_check_full_length_console_log) - - @decorators.idempotent_id('5b65d4e7-4ecd-437c-83c0-d6b79d927568') - @testtools.skipUnless(CONF.compute_feature_enabled.console_output, - 'Console output not supported.') - def test_get_console_output_server_id_in_shutoff_status(self): - # Positive test:Should be able to GET the console output - # for a given server_id in SHUTOFF status - - # NOTE: SHUTOFF is irregular status. To avoid test instability, - # one server is created only for this test without using - # the server that was created in setUpClass. - server = self.create_test_server(wait_until='ACTIVE') - temp_server_id = server['id'] - - self.client.stop_server(temp_server_id) - waiters.wait_for_server_status(self.client, temp_server_id, 'SHUTOFF') - self.wait_for(self._get_output) - - @decorators.idempotent_id('bd61a9fd-062f-4670-972b-2d6c3e3b9e73') - @testtools.skipUnless(CONF.compute_feature_enabled.pause, - 'Pause is not available.') - def test_pause_unpause_server(self): - self.client.pause_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, 'PAUSED') - self.client.unpause_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE') - - @decorators.idempotent_id('0d8ee21e-b749-462d-83da-b85b41c86c7f') - @testtools.skipUnless(CONF.compute_feature_enabled.suspend, - 'Suspend is not available.') - def test_suspend_resume_server(self): - self.client.suspend_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, - 'SUSPENDED') - self.client.resume_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE') - - @decorators.idempotent_id('77eba8e0-036e-4635-944b-f7a8f3b78dc9') - @testtools.skipUnless(CONF.compute_feature_enabled.shelve, - 'Shelve is not available.') - @test.services('image') - def test_shelve_unshelve_server(self): - if CONF.image_feature_enabled.api_v2: - glance_client = self.os_primary.image_client_v2 - elif CONF.image_feature_enabled.api_v1: - glance_client = self.os_primary.image_client - else: - raise lib_exc.InvalidConfiguration( - 'Either api_v1 or api_v2 must be True in ' - '[image-feature-enabled].') - compute.shelve_server(self.client, self.server_id, - force_shelve_offload=True) - - server = self.client.show_server(self.server_id)['server'] - image_name = server['name'] + '-shelved' - params = {'name': image_name} - if CONF.image_feature_enabled.api_v2: - images = glance_client.list_images(params)['images'] - elif CONF.image_feature_enabled.api_v1: - images = glance_client.list_images( - detail=True, **params)['images'] - self.assertEqual(1, len(images)) - self.assertEqual(image_name, images[0]['name']) - - self.client.unshelve_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE') - glance_client.wait_for_resource_deletion(images[0]['id']) - - @decorators.idempotent_id('af8eafd4-38a7-4a4b-bdbc-75145a580560') - def test_stop_start_server(self): - self.client.stop_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, 'SHUTOFF') - self.client.start_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE') - - @decorators.idempotent_id('80a8094c-211e-440a-ab88-9e59d556c7ee') - def test_lock_unlock_server(self): - # Lock the server,try server stop(exceptions throw),unlock it and retry - self.client.lock_server(self.server_id) - self.addCleanup(self.client.unlock_server, self.server_id) - server = self.client.show_server(self.server_id)['server'] - self.assertEqual(server['status'], 'ACTIVE') - # Locked server is not allowed to be stopped by non-admin user - self.assertRaises(lib_exc.Conflict, - self.client.stop_server, self.server_id) - self.client.unlock_server(self.server_id) - self.client.stop_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, 'SHUTOFF') - self.client.start_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, 'ACTIVE') - - def _validate_url(self, url): - valid_scheme = ['http', 'https'] - parsed_url = urlparse.urlparse(url) - self.assertNotEqual('None', parsed_url.port) - self.assertNotEqual('None', parsed_url.hostname) - self.assertIn(parsed_url.scheme, valid_scheme) - - @decorators.idempotent_id('c6bc11bf-592e-4015-9319-1c98dc64daf5') - @testtools.skipUnless(CONF.compute_feature_enabled.vnc_console, - 'VNC Console feature is disabled.') - def test_get_vnc_console(self): - # Get the VNC console of type 'novnc' and 'xvpvnc' - console_types = ['novnc', 'xvpvnc'] - for console_type in console_types: - body = self.client.get_vnc_console(self.server_id, - type=console_type)['console'] - self.assertEqual(console_type, body['type']) - self.assertNotEqual('', body['url']) - self._validate_url(body['url']) diff --git a/tempest/api/compute/servers/test_server_addresses.py b/tempest/api/compute/servers/test_server_addresses.py deleted file mode 100644 index 022ceba77..000000000 --- a/tempest/api/compute/servers/test_server_addresses.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.compute import base -from tempest.lib import decorators -from tempest import test - - -class ServerAddressesTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_credentials(cls): - # This test module might use a network and a subnet - cls.set_network_resources(network=True, subnet=True) - super(ServerAddressesTestJSON, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(ServerAddressesTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(ServerAddressesTestJSON, cls).resource_setup() - - cls.server = cls.create_test_server(wait_until='ACTIVE') - - @decorators.attr(type='smoke') - @decorators.idempotent_id('6eb718c0-02d9-4d5e-acd1-4e0c269cef39') - @test.services('network') - def test_list_server_addresses(self): - # All public and private addresses for - # a server should be returned - - addresses = self.client.list_addresses(self.server['id'])['addresses'] - - # We do not know the exact network configuration, but an instance - # should at least have a single public or private address - self.assertNotEmpty(addresses) - for network_addresses in addresses.values(): - self.assertNotEmpty(network_addresses) - for address in network_addresses: - self.assertTrue(address['addr']) - self.assertTrue(address['version']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('87bbc374-5538-4f64-b673-2b0e4443cc30') - @test.services('network') - def test_list_server_addresses_by_network(self): - # Providing a network type should filter - # the addresses return by that type - - addresses = self.client.list_addresses(self.server['id'])['addresses'] - - # Once again we don't know the environment's exact network config, - # but the response for each individual network should be the same - # as the partial result of the full address list - id = self.server['id'] - for addr_type in addresses: - addr = self.client.list_addresses_by_network(id, addr_type) - - addr = addr[addr_type] - for address in addresses[addr_type]: - self.assertTrue(any([a for a in addr if a == address])) diff --git a/tempest/api/compute/servers/test_server_addresses_negative.py b/tempest/api/compute/servers/test_server_addresses_negative.py deleted file mode 100644 index 76a102bb6..000000000 --- a/tempest/api/compute/servers/test_server_addresses_negative.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.compute import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - - -class ServerAddressesNegativeTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_credentials(cls): - cls.set_network_resources(network=True, subnet=True) - super(ServerAddressesNegativeTestJSON, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(ServerAddressesNegativeTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(ServerAddressesNegativeTestJSON, cls).resource_setup() - cls.server = cls.create_test_server(wait_until='ACTIVE') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('02c3f645-2d2e-4417-8525-68c0407d001b') - @test.services('network') - def test_list_server_addresses_invalid_server_id(self): - # List addresses request should fail if server id not in system - self.assertRaises(lib_exc.NotFound, self.client.list_addresses, - '999') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a2ab5144-78c0-4942-a0ed-cc8edccfd9ba') - @test.services('network') - def test_list_server_addresses_by_network_neg(self): - # List addresses by network should fail if network name not valid - self.assertRaises(lib_exc.NotFound, - self.client.list_addresses_by_network, - self.server['id'], 'invalid') diff --git a/tempest/api/compute/servers/test_server_group.py b/tempest/api/compute/servers/test_server_group.py deleted file mode 100644 index 69d7897c2..000000000 --- a/tempest/api/compute/servers/test_server_group.py +++ /dev/null @@ -1,108 +0,0 @@ -# Copyright 2014 NEC Technologies India Ltd. -# 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 tempest.api.compute import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - - -class ServerGroupTestJSON(base.BaseV2ComputeTest): - """These tests check for the server-group APIs. - - They create/delete server-groups with different policies. - policies = affinity/anti-affinity - It also adds the tests for list and get details of server-groups - """ - - @classmethod - def skip_checks(cls): - super(ServerGroupTestJSON, cls).skip_checks() - if not test.is_extension_enabled('os-server-groups', 'compute'): - msg = "os-server-groups extension is not enabled." - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(ServerGroupTestJSON, cls).setup_clients() - cls.client = cls.server_groups_client - - @classmethod - def resource_setup(cls): - super(ServerGroupTestJSON, cls).resource_setup() - cls.policy = ['affinity'] - - cls.created_server_group = cls.create_test_server_group( - policy=cls.policy) - - def _create_server_group(self, name, policy): - # create the test server-group with given policy - server_group = {'name': name, 'policies': policy} - body = self.create_test_server_group(name, policy) - for key in ['name', 'policies']: - self.assertEqual(server_group[key], body[key]) - return body - - def _delete_server_group(self, server_group): - # delete the test server-group - self.client.delete_server_group(server_group['id']) - # validation of server-group deletion - server_group_list = self.client.list_server_groups()['server_groups'] - self.assertNotIn(server_group, server_group_list) - - def _create_delete_server_group(self, policy): - # Create and Delete the server-group with given policy - name = data_utils.rand_name('server-group') - server_group = self._create_server_group(name, policy) - self._delete_server_group(server_group) - - @decorators.idempotent_id('5dc57eda-35b7-4af7-9e5f-3c2be3d2d68b') - def test_create_delete_server_group_with_affinity_policy(self): - # Create and Delete the server-group with affinity policy - self._create_delete_server_group(self.policy) - - @decorators.idempotent_id('3645a102-372f-4140-afad-13698d850d23') - def test_create_delete_server_group_with_anti_affinity_policy(self): - # Create and Delete the server-group with anti-affinity policy - policy = ['anti-affinity'] - self._create_delete_server_group(policy) - - @decorators.idempotent_id('154dc5a4-a2fe-44b5-b99e-f15806a4a113') - def test_create_delete_multiple_server_groups_with_same_name_policy(self): - # Create and Delete the server-groups with same name and same policy - server_groups = [] - server_group_name = data_utils.rand_name('server-group') - for _ in range(0, 2): - server_groups.append(self._create_server_group(server_group_name, - self.policy)) - for key in ['name', 'policies']: - self.assertEqual(server_groups[0][key], server_groups[1][key]) - self.assertNotEqual(server_groups[0]['id'], server_groups[1]['id']) - - for i in range(0, 2): - self._delete_server_group(server_groups[i]) - - @decorators.idempotent_id('b3545034-dd78-48f0-bdc2-a4adfa6d0ead') - def test_show_server_group(self): - # Get the server-group - body = self.client.show_server_group( - self.created_server_group['id'])['server_group'] - self.assertEqual(self.created_server_group, body) - - @decorators.idempotent_id('d4874179-27b4-4d7d-80e4-6c560cdfe321') - def test_list_server_groups(self): - # List the server-group - body = self.client.list_server_groups()['server_groups'] - self.assertIn(self.created_server_group, body) diff --git a/tempest/api/compute/servers/test_server_metadata.py b/tempest/api/compute/servers/test_server_metadata.py deleted file mode 100644 index f77e7d309..000000000 --- a/tempest/api/compute/servers/test_server_metadata.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.compute import base -from tempest.lib import decorators - - -class ServerMetadataTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_clients(cls): - super(ServerMetadataTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(ServerMetadataTestJSON, cls).resource_setup() - cls.server = cls.create_test_server(metadata={}, wait_until='ACTIVE') - - def setUp(self): - super(ServerMetadataTestJSON, self).setUp() - meta = {'key1': 'value1', 'key2': 'value2'} - self.client.set_server_metadata(self.server['id'], meta)['metadata'] - - @decorators.idempotent_id('479da087-92b3-4dcf-aeb3-fd293b2d14ce') - def test_list_server_metadata(self): - # All metadata key/value pairs for a server should be returned - resp_metadata = (self.client.list_server_metadata(self.server['id']) - ['metadata']) - - # Verify the expected metadata items are in the list - expected = {'key1': 'value1', 'key2': 'value2'} - self.assertEqual(expected, resp_metadata) - - @decorators.idempotent_id('211021f6-21de-4657-a68f-908878cfe251') - def test_set_server_metadata(self): - # The server's metadata should be replaced with the provided values - # Create a new set of metadata for the server - req_metadata = {'meta2': 'data2', 'meta3': 'data3'} - self.client.set_server_metadata(self.server['id'], - req_metadata)['metadata'] - - # Verify the expected values are correct, and that the - # previous values have been removed - resp_metadata = (self.client.list_server_metadata(self.server['id']) - ['metadata']) - self.assertEqual(resp_metadata, req_metadata) - - @decorators.idempotent_id('344d981e-0c33-4997-8a5d-6c1d803e4134') - def test_update_server_metadata(self): - # The server's metadata values should be updated to the - # provided values - meta = {'key1': 'alt1', 'key3': 'value3'} - self.client.update_server_metadata(self.server['id'], meta) - - # Verify the values have been updated to the proper values - resp_metadata = (self.client.list_server_metadata(self.server['id']) - ['metadata']) - expected = {'key1': 'alt1', 'key2': 'value2', 'key3': 'value3'} - self.assertEqual(expected, resp_metadata) - - @decorators.idempotent_id('0f58d402-e34a-481d-8af8-b392b17426d9') - def test_update_metadata_empty_body(self): - # The original metadata should not be lost if empty metadata body is - # passed - meta = {} - self.client.update_server_metadata(self.server['id'], meta) - resp_metadata = (self.client.list_server_metadata(self.server['id']) - ['metadata']) - expected = {'key1': 'value1', 'key2': 'value2'} - self.assertEqual(expected, resp_metadata) - - @decorators.idempotent_id('3043c57d-7e0e-49a6-9a96-ad569c265e6a') - def test_get_server_metadata_item(self): - # The value for a specific metadata key should be returned - meta = self.client.show_server_metadata_item(self.server['id'], - 'key2')['meta'] - self.assertEqual('value2', meta['key2']) - - @decorators.idempotent_id('58c02d4f-5c67-40be-8744-d3fa5982eb1c') - def test_set_server_metadata_item(self): - # The item's value should be updated to the provided value - # Update the metadata value - meta = {'nova': 'alt'} - self.client.set_server_metadata_item(self.server['id'], 'nova', meta) - - # Verify the meta item's value has been updated - resp_metadata = (self.client.list_server_metadata(self.server['id']) - ['metadata']) - expected = {'key1': 'value1', 'key2': 'value2', 'nova': 'alt'} - self.assertEqual(expected, resp_metadata) - - @decorators.idempotent_id('127642d6-4c7b-4486-b7cd-07265a378658') - def test_delete_server_metadata_item(self): - # The metadata value/key pair should be deleted from the server - self.client.delete_server_metadata_item(self.server['id'], 'key1') - - # Verify the metadata item has been removed - resp_metadata = (self.client.list_server_metadata(self.server['id']) - ['metadata']) - expected = {'key2': 'value2'} - self.assertEqual(expected, resp_metadata) diff --git a/tempest/api/compute/servers/test_server_metadata_negative.py b/tempest/api/compute/servers/test_server_metadata_negative.py deleted file mode 100644 index 482ba0946..000000000 --- a/tempest/api/compute/servers/test_server_metadata_negative.py +++ /dev/null @@ -1,174 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.compute import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ServerMetadataNegativeTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_clients(cls): - super(ServerMetadataNegativeTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(ServerMetadataNegativeTestJSON, cls).resource_setup() - cls.tenant_id = cls.client.tenant_id - cls.server = cls.create_test_server(metadata={}, wait_until='ACTIVE') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('fe114a8f-3a57-4eff-9ee2-4e14628df049') - def test_server_create_metadata_key_too_long(self): - # Attempt to start a server with a meta-data key that is > 255 - # characters - - # Tryset_server_metadata_item a few values - for sz in [256, 257, 511, 1023]: - key = "k" * sz - meta = {key: 'data1'} - self.assertRaises((lib_exc.BadRequest, lib_exc.OverLimit), - self.create_test_server, - metadata=meta) - - # no teardown - all creates should fail - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('92431555-4d8b-467c-b95b-b17daa5e57ff') - def test_create_server_metadata_blank_key(self): - # Blank key should trigger an error. - meta = {'': 'data1'} - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, - metadata=meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('4d9cd7a3-2010-4b41-b8fe-3bbf0b169466') - def test_server_metadata_non_existent_server(self): - # GET on a non-existent server should not succeed - non_existent_server_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.client.show_server_metadata_item, - non_existent_server_id, - 'test2') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f408e78e-3066-4097-9299-3b0182da812e') - def test_list_server_metadata_non_existent_server(self): - # List metadata on a non-existent server should not succeed - non_existent_server_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.client.list_server_metadata, - non_existent_server_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0025fbd6-a4ba-4cde-b8c2-96805dcfdabc') - def test_wrong_key_passed_in_body(self): - # Raise BadRequest if key in uri does not match - # the key passed in body. - meta = {'testkey': 'testvalue'} - self.assertRaises(lib_exc.BadRequest, - self.client.set_server_metadata_item, - self.server['id'], 'key', meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0df38c2a-3d4e-4db5-98d8-d4d9fa843a12') - def test_set_metadata_non_existent_server(self): - # Set metadata on a non-existent server should not succeed - non_existent_server_id = data_utils.rand_uuid() - meta = {'meta1': 'data1'} - self.assertRaises(lib_exc.NotFound, - self.client.set_server_metadata, - non_existent_server_id, - meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('904b13dc-0ef2-4e4c-91cd-3b4a0f2f49d8') - def test_update_metadata_non_existent_server(self): - # An update should not happen for a non-existent server - non_existent_server_id = data_utils.rand_uuid() - meta = {'key1': 'value1', 'key2': 'value2'} - self.assertRaises(lib_exc.NotFound, - self.client.update_server_metadata, - non_existent_server_id, - meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a452f38c-05c2-4b47-bd44-a4f0bf5a5e48') - def test_update_metadata_with_blank_key(self): - # Blank key should trigger an error - meta = {'': 'data1'} - self.assertRaises(lib_exc.BadRequest, - self.client.update_server_metadata, - self.server['id'], meta=meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6bbd88e1-f8b3-424d-ba10-ae21c45ada8d') - def test_delete_metadata_non_existent_server(self): - # Should not be able to delete metadata item from a non-existent server - non_existent_server_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.client.delete_server_metadata_item, - non_existent_server_id, - 'd') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d8c0a210-a5c3-4664-be04-69d96746b547') - def test_metadata_items_limit(self): - # A 403 Forbidden or 413 Overlimit (old behaviour) exception - # will be raised while exceeding metadata items limit for - # tenant. - quota_set = self.quotas_client.show_quota_set( - self.tenant_id)['quota_set'] - quota_metadata = quota_set['metadata_items'] - if quota_metadata == -1: - raise self.skipException("No limit for metadata_items") - - req_metadata = {} - for num in range(1, quota_metadata + 2): - req_metadata['key' + str(num)] = 'val' + str(num) - self.assertRaises((lib_exc.OverLimit, lib_exc.Forbidden), - self.client.set_server_metadata, - self.server['id'], req_metadata) - - # A 403 Forbidden or 413 Overlimit (old behaviour) exception - # will be raised while exceeding metadata items limit for - # tenant. - self.assertRaises((lib_exc.Forbidden, lib_exc.OverLimit), - self.client.update_server_metadata, - self.server['id'], req_metadata) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('96100343-7fa9-40d8-80fa-d29ef588ce1c') - def test_set_server_metadata_blank_key(self): - # Raise a bad request error for blank key. - # set_server_metadata will replace all metadata with new value - meta = {'': 'data1'} - self.assertRaises(lib_exc.BadRequest, - self.client.set_server_metadata, - self.server['id'], meta=meta) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('64a91aee-9723-4863-be44-4c9d9f1e7d0e') - def test_set_server_metadata_missing_metadata(self): - # Raise a bad request error for a missing metadata field - # set_server_metadata will replace all metadata with new value - meta = {'meta1': 'data1'} - self.assertRaises(lib_exc.BadRequest, - self.client.set_server_metadata, - self.server['id'], meta=meta, no_metadata_field=True) diff --git a/tempest/api/compute/servers/test_server_password.py b/tempest/api/compute/servers/test_server_password.py deleted file mode 100644 index e7591a541..000000000 --- a/tempest/api/compute/servers/test_server_password.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2013 IBM Corporation -# 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 tempest.api.compute import base -from tempest.lib import decorators - - -class ServerPasswordTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_clients(cls): - super(ServerPasswordTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(ServerPasswordTestJSON, cls).resource_setup() - cls.server = cls.create_test_server(wait_until="ACTIVE") - - @decorators.idempotent_id('f83b582f-62a8-4f22-85b0-0dee50ff783a') - def test_get_server_password(self): - self.client.show_password(self.server['id']) - - @decorators.idempotent_id('f8229e8b-b625-4493-800a-bde86ac611ea') - def test_delete_server_password(self): - self.client.delete_password(self.server['id']) diff --git a/tempest/api/compute/servers/test_server_personality.py b/tempest/api/compute/servers/test_server_personality.py deleted file mode 100644 index 90b9da413..000000000 --- a/tempest/api/compute/servers/test_server_personality.py +++ /dev/null @@ -1,144 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_serialization import base64 - -from tempest.api.compute import base -from tempest.common.utils.linux import remote_client -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class ServerPersonalityTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_credentials(cls): - cls.prepare_instance_network() - super(ServerPersonalityTestJSON, cls).setup_credentials() - - @classmethod - def resource_setup(cls): - cls.set_validation_resources() - super(ServerPersonalityTestJSON, cls).resource_setup() - - @classmethod - def skip_checks(cls): - super(ServerPersonalityTestJSON, cls).skip_checks() - if not CONF.compute_feature_enabled.personality: - raise cls.skipException("Nova personality feature disabled") - - @classmethod - def setup_clients(cls): - super(ServerPersonalityTestJSON, cls).setup_clients() - cls.client = cls.servers_client - cls.user_client = cls.limits_client - - @decorators.idempotent_id('3cfe87fd-115b-4a02-b942-7dc36a337fdf') - def test_create_server_with_personality(self): - file_contents = 'This is a test file.' - file_path = '/test.txt' - personality = [{'path': file_path, - 'contents': base64.encode_as_text(file_contents)}] - password = data_utils.rand_password() - created_server = self.create_test_server(personality=personality, - adminPass=password, - wait_until='ACTIVE', - validatable=True) - server = self.client.show_server(created_server['id'])['server'] - if CONF.validation.run_validation: - linux_client = remote_client.RemoteClient( - self.get_server_ip(server), - self.ssh_user, password, - self.validation_resources['keypair']['private_key'], - server=server, - servers_client=self.client) - self.assertEqual(file_contents, - linux_client.exec_command( - 'sudo cat %s' % file_path)) - - @decorators.idempotent_id('128966d8-71fc-443c-8cab-08e24114ecc9') - def test_rebuild_server_with_personality(self): - server = self.create_test_server(wait_until='ACTIVE', validatable=True) - server_id = server['id'] - file_contents = 'Test server rebuild.' - personality = [{'path': 'rebuild.txt', - 'contents': base64.encode_as_text(file_contents)}] - rebuilt_server = self.client.rebuild_server(server_id, - self.image_ref_alt, - personality=personality) - waiters.wait_for_server_status(self.client, server_id, 'ACTIVE') - self.assertEqual(self.image_ref_alt, - rebuilt_server['server']['image']['id']) - - @decorators.idempotent_id('176cd8c9-b9e8-48ee-a480-180beab292bf') - def test_personality_files_exceed_limit(self): - # Server creation should fail if greater than the maximum allowed - # number of files are injected into the server. - file_contents = 'This is a test file.' - personality = [] - limits = self.user_client.show_limits()['limits'] - max_file_limit = limits['absolute']['maxPersonality'] - if max_file_limit == -1: - raise self.skipException("No limit for personality files") - for i in range(0, max_file_limit + 1): - path = 'etc/test' + str(i) + '.txt' - personality.append({'path': path, - 'contents': base64.encode_as_text( - file_contents)}) - # A 403 Forbidden or 413 Overlimit (old behaviour) exception - # will be raised when out of quota - self.assertRaises((lib_exc.Forbidden, lib_exc.OverLimit), - self.create_test_server, personality=personality) - - @decorators.idempotent_id('52f12ee8-5180-40cc-b417-31572ea3d555') - def test_can_create_server_with_max_number_personality_files(self): - # Server should be created successfully if maximum allowed number of - # files is injected into the server during creation. - file_contents = 'This is a test file.' - limits = self.user_client.show_limits()['limits'] - max_file_limit = limits['absolute']['maxPersonality'] - if max_file_limit == -1: - raise self.skipException("No limit for personality files") - person = [] - for i in range(0, max_file_limit): - # NOTE(andreaf) The cirros disk image is blank before boot - # so we can only inject safely to / - path = '/test' + str(i) + '.txt' - person.append({ - 'path': path, - 'contents': base64.encode_as_text(file_contents + str(i)), - }) - password = data_utils.rand_password() - created_server = self.create_test_server(personality=person, - adminPass=password, - wait_until='ACTIVE', - validatable=True) - server = self.client.show_server(created_server['id'])['server'] - if CONF.validation.run_validation: - linux_client = remote_client.RemoteClient( - self.get_server_ip(server), - self.ssh_user, password, - self.validation_resources['keypair']['private_key'], - server=server, - servers_client=self.client) - for i in person: - self.assertEqual(base64.decode_as_text(i['contents']), - linux_client.exec_command( - 'sudo cat %s' % i['path'])) diff --git a/tempest/api/compute/servers/test_server_rescue.py b/tempest/api/compute/servers/test_server_rescue.py deleted file mode 100644 index b0ef3bcb5..000000000 --- a/tempest/api/compute/servers/test_server_rescue.py +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright 2013 Hewlett-Packard Development Company, L.P. -# 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 testtools - -from tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class ServerRescueTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(ServerRescueTestJSON, cls).skip_checks() - if not CONF.compute_feature_enabled.rescue: - msg = "Server rescue not available." - raise cls.skipException(msg) - - @classmethod - def setup_credentials(cls): - cls.set_network_resources(network=True, subnet=True, router=True) - super(ServerRescueTestJSON, cls).setup_credentials() - - @classmethod - def resource_setup(cls): - super(ServerRescueTestJSON, cls).resource_setup() - - password = data_utils.rand_password() - server = cls.create_test_server(adminPass=password, - wait_until='ACTIVE') - cls.servers_client.rescue_server(server['id'], adminPass=password) - waiters.wait_for_server_status(cls.servers_client, server['id'], - 'RESCUE') - cls.rescued_server_id = server['id'] - - @decorators.idempotent_id('fd032140-714c-42e4-a8fd-adcd8df06be6') - def test_rescue_unrescue_instance(self): - password = data_utils.rand_password() - server = self.create_test_server(adminPass=password, - wait_until='ACTIVE') - self.servers_client.rescue_server(server['id'], adminPass=password) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'RESCUE') - self.servers_client.unrescue_server(server['id']) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'ACTIVE') - - @decorators.idempotent_id('4842e0cf-e87d-4d9d-b61f-f4791da3cacc') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - @testtools.skipUnless(CONF.network_feature_enabled.floating_ips, - "Floating ips are not available") - def test_rescued_vm_associate_dissociate_floating_ip(self): - # Association of floating IP to a rescued vm - floating_ip_body = self.floating_ips_client.create_floating_ip( - pool=CONF.network.floating_network_name)['floating_ip'] - self.addCleanup(self.floating_ips_client.delete_floating_ip, - floating_ip_body['id']) - - self.floating_ips_client.associate_floating_ip_to_server( - str(floating_ip_body['ip']).strip(), self.rescued_server_id) - - # Disassociation of floating IP that was associated in this method - self.floating_ips_client.disassociate_floating_ip_from_server( - str(floating_ip_body['ip']).strip(), self.rescued_server_id) - - @decorators.idempotent_id('affca41f-7195-492d-8065-e09eee245404') - def test_rescued_vm_add_remove_security_group(self): - # Add Security group - sg = self.create_security_group() - self.servers_client.add_security_group(self.rescued_server_id, - name=sg['name']) - - # Delete Security group - self.servers_client.remove_security_group(self.rescued_server_id, - name=sg['name']) diff --git a/tempest/api/compute/servers/test_server_rescue_negative.py b/tempest/api/compute/servers/test_server_rescue_negative.py deleted file mode 100644 index 5fac433dc..000000000 --- a/tempest/api/compute/servers/test_server_rescue_negative.py +++ /dev/null @@ -1,153 +0,0 @@ -# Copyright 2013 Hewlett-Packard Development Company, L.P. -# Copyright 2014 NEC Corporation. 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 testtools - -from tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class ServerRescueNegativeTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(ServerRescueNegativeTestJSON, cls).skip_checks() - if not CONF.compute_feature_enabled.rescue: - msg = "Server rescue not available." - raise cls.skipException(msg) - - @classmethod - def setup_credentials(cls): - cls.set_network_resources(network=True, subnet=True, router=True) - super(ServerRescueNegativeTestJSON, cls).setup_credentials() - - @classmethod - def resource_setup(cls): - super(ServerRescueNegativeTestJSON, cls).resource_setup() - cls.device = CONF.compute.volume_device_name - cls.password = data_utils.rand_password() - rescue_password = data_utils.rand_password() - # Server for negative tests - server = cls.create_test_server(adminPass=cls.password, - wait_until='BUILD') - resc_server = cls.create_test_server(adminPass=rescue_password, - wait_until='ACTIVE') - cls.server_id = server['id'] - cls.rescue_id = resc_server['id'] - - cls.servers_client.rescue_server( - cls.rescue_id, adminPass=rescue_password) - waiters.wait_for_server_status(cls.servers_client, - cls.rescue_id, 'RESCUE') - waiters.wait_for_server_status(cls.servers_client, - cls.server_id, 'ACTIVE') - - def _unrescue(self, server_id): - self.servers_client.unrescue_server(server_id) - waiters.wait_for_server_status(self.servers_client, - server_id, 'ACTIVE') - - def _unpause(self, server_id): - self.servers_client.unpause_server(server_id) - waiters.wait_for_server_status(self.servers_client, - server_id, 'ACTIVE') - - @decorators.idempotent_id('cc3a883f-43c0-4fb6-a9bb-5579d64984ed') - @testtools.skipUnless(CONF.compute_feature_enabled.pause, - 'Pause is not available.') - @decorators.attr(type=['negative']) - def test_rescue_paused_instance(self): - # Rescue a paused server - self.servers_client.pause_server(self.server_id) - self.addCleanup(self._unpause, self.server_id) - waiters.wait_for_server_status(self.servers_client, - self.server_id, 'PAUSED') - self.assertRaises(lib_exc.Conflict, - self.servers_client.rescue_server, - self.server_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('db22b618-f157-4566-a317-1b6d467a8094') - def test_rescued_vm_reboot(self): - self.assertRaises(lib_exc.Conflict, self.servers_client.reboot_server, - self.rescue_id, type='HARD') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6dfc0a55-3a77-4564-a144-1587b7971dde') - def test_rescue_non_existent_server(self): - # Rescue a non-existing server - non_existent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.servers_client.rescue_server, - non_existent_server) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('70cdb8a1-89f8-437d-9448-8844fd82bf46') - def test_rescued_vm_rebuild(self): - self.assertRaises(lib_exc.Conflict, - self.servers_client.rebuild_server, - self.rescue_id, - self.image_ref_alt) - - @decorators.idempotent_id('d0ccac79-0091-4cf4-a1ce-26162d0cc55f') - @test.services('volume') - @decorators.attr(type=['negative']) - def test_rescued_vm_attach_volume(self): - volume = self.create_volume() - - # Rescue the server - self.servers_client.rescue_server(self.server_id, - adminPass=self.password) - waiters.wait_for_server_status(self.servers_client, - self.server_id, 'RESCUE') - self.addCleanup(self._unrescue, self.server_id) - - # Attach the volume to the server - self.assertRaises(lib_exc.Conflict, - self.servers_client.attach_volume, - self.server_id, - volumeId=volume['id'], - device='/dev/%s' % self.device) - - @decorators.idempotent_id('f56e465b-fe10-48bf-b75d-646cda3a8bc9') - @test.services('volume') - @decorators.attr(type=['negative']) - def test_rescued_vm_detach_volume(self): - volume = self.create_volume() - - # Attach the volume to the server - server = self.servers_client.show_server(self.server_id)['server'] - self.attach_volume(server, volume, device='/dev/%s' % self.device) - - # Rescue the server - self.servers_client.rescue_server(self.server_id, - adminPass=self.password) - waiters.wait_for_server_status(self.servers_client, - self.server_id, 'RESCUE') - # addCleanup is a LIFO queue - self.addCleanup(self._unrescue, self.server_id) - - # Detach the volume from the server expecting failure - self.assertRaises(lib_exc.Conflict, - self.servers_client.detach_volume, - self.server_id, - volume['id']) diff --git a/tempest/api/compute/servers/test_server_tags.py b/tempest/api/compute/servers/test_server_tags.py deleted file mode 100644 index 037021537..000000000 --- a/tempest/api/compute/servers/test_server_tags.py +++ /dev/null @@ -1,108 +0,0 @@ -# Copyright 2017 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 six - -from tempest.api.compute import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - - -class ServerTagsTestJSON(base.BaseV2ComputeTest): - - min_microversion = '2.26' - max_microversion = 'latest' - - @classmethod - def skip_checks(cls): - super(ServerTagsTestJSON, cls).skip_checks() - if not test.is_extension_enabled('os-server-tags', 'compute'): - msg = "os-server-tags extension is not enabled." - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(ServerTagsTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(ServerTagsTestJSON, cls).resource_setup() - cls.server = cls.create_test_server(wait_until='ACTIVE') - - def _update_server_tags(self, server_id, tags): - if not isinstance(tags, (list, tuple)): - tags = [tags] - for tag in tags: - self.client.update_tag(server_id, tag) - self.addCleanup(self.client.delete_all_tags, server_id) - - @decorators.idempotent_id('8d95abe2-c658-4c42-9a44-c0258500306b') - def test_create_delete_tag(self): - # Check that no tags exist. - fetched_tags = self.client.list_tags(self.server['id'])['tags'] - self.assertEmpty(fetched_tags) - - # Add server tag to the server. - assigned_tag = data_utils.rand_name('tag') - self._update_server_tags(self.server['id'], assigned_tag) - - # Check that added tag exists. - fetched_tags = self.client.list_tags(self.server['id'])['tags'] - self.assertEqual([assigned_tag], fetched_tags) - - # Remove assigned tag from server and check that it was removed. - self.client.delete_tag(self.server['id'], assigned_tag) - fetched_tags = self.client.list_tags(self.server['id'])['tags'] - self.assertEmpty(fetched_tags) - - @decorators.idempotent_id('a2c1af8c-127d-417d-974b-8115f7e3d831') - def test_update_all_tags(self): - # Add server tags to the server. - tags = [data_utils.rand_name('tag'), data_utils.rand_name('tag')] - self._update_server_tags(self.server['id'], tags) - - # Replace tags with new tags and check that they are present. - new_tags = [data_utils.rand_name('tag'), data_utils.rand_name('tag')] - replaced_tags = self.client.update_all_tags( - self.server['id'], new_tags)['tags'] - six.assertCountEqual(self, new_tags, replaced_tags) - - # List the tags and check that the tags were replaced. - fetched_tags = self.client.list_tags(self.server['id'])['tags'] - six.assertCountEqual(self, new_tags, fetched_tags) - - @decorators.idempotent_id('a63b2a74-e918-4b7c-bcab-10c855f3a57e') - def test_delete_all_tags(self): - # Add server tags to the server. - assigned_tags = [data_utils.rand_name('tag'), - data_utils.rand_name('tag')] - self._update_server_tags(self.server['id'], assigned_tags) - - # Delete tags from the server and check that they were deleted. - self.client.delete_all_tags(self.server['id']) - fetched_tags = self.client.list_tags(self.server['id'])['tags'] - self.assertEmpty(fetched_tags) - - @decorators.idempotent_id('81279a66-61c3-4759-b830-a2dbe64cbe08') - def test_check_tag_existence(self): - # Add server tag to the server. - assigned_tag = data_utils.rand_name('tag') - self._update_server_tags(self.server['id'], assigned_tag) - - # Check that added tag exists. Throws a 404 if not found, else a 204, - # which was already checked by the schema validation. - self.client.check_tag_existence(self.server['id'], assigned_tag) diff --git a/tempest/api/compute/servers/test_servers.py b/tempest/api/compute/servers/test_servers.py deleted file mode 100644 index 7fd1dd1ce..000000000 --- a/tempest/api/compute/servers/test_servers.py +++ /dev/null @@ -1,147 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 testtools - -from tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class ServersTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_clients(cls): - super(ServersTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - def tearDown(self): - self.clear_servers() - super(ServersTestJSON, self).tearDown() - - @decorators.idempotent_id('b92d5ec7-b1dd-44a2-87e4-45e888c46ef0') - @testtools.skipUnless(CONF.compute_feature_enabled. - enable_instance_password, - 'Instance password not available.') - def test_create_server_with_admin_password(self): - # If an admin password is provided on server creation, the server's - # root password should be set to that password. - server = self.create_test_server(adminPass='testpassword') - - # Verify the password is set correctly in the response - self.assertEqual('testpassword', server['adminPass']) - - @decorators.idempotent_id('8fea6be7-065e-47cf-89b8-496e6f96c699') - def test_create_with_existing_server_name(self): - # Creating a server with a name that already exists is allowed - - # TODO(sdague): clear out try, we do cleanup one layer up - server_name = data_utils.rand_name( - self.__class__.__name__ + '-server') - server = self.create_test_server(name=server_name, - wait_until='ACTIVE') - id1 = server['id'] - server = self.create_test_server(name=server_name, - wait_until='ACTIVE') - id2 = server['id'] - self.assertNotEqual(id1, id2, "Did not create a new server") - server = self.client.show_server(id1)['server'] - name1 = server['name'] - server = self.client.show_server(id2)['server'] - name2 = server['name'] - self.assertEqual(name1, name2) - - @decorators.idempotent_id('f9e15296-d7f9-4e62-b53f-a04e89160833') - def test_create_specify_keypair(self): - # Specify a keypair while creating a server - - key_name = data_utils.rand_name('key') - self.keypairs_client.create_keypair(name=key_name) - self.addCleanup(self.keypairs_client.delete_keypair, key_name) - self.keypairs_client.list_keypairs() - server = self.create_test_server(key_name=key_name) - waiters.wait_for_server_status(self.client, server['id'], 'ACTIVE') - server = self.client.show_server(server['id'])['server'] - self.assertEqual(key_name, server['key_name']) - - def _update_server_name(self, server_id, status, prefix_name='server'): - # The server name should be changed to the provided value - new_name = data_utils.rand_name(prefix_name) - - # Update the server with a new name - self.client.update_server(server_id, - name=new_name) - waiters.wait_for_server_status(self.client, server_id, status) - - # Verify the name of the server has changed - server = self.client.show_server(server_id)['server'] - self.assertEqual(new_name, server['name']) - return server - - @decorators.idempotent_id('5e6ccff8-349d-4852-a8b3-055df7988dd2') - def test_update_server_name(self): - # The server name should be changed to the provided value - server = self.create_test_server(wait_until='ACTIVE') - # Update instance name with non-ASCII characters - prefix_name = u'\u00CD\u00F1st\u00E1\u00F1c\u00E9' - self._update_server_name(server['id'], 'ACTIVE', prefix_name) - - # stop server and check server name update again - self.client.stop_server(server['id']) - waiters.wait_for_server_status(self.client, server['id'], 'SHUTOFF') - # Update instance name with non-ASCII characters - updated_server = self._update_server_name(server['id'], - 'SHUTOFF', - prefix_name) - self.assertNotIn('progress', updated_server) - - @decorators.idempotent_id('89b90870-bc13-4b73-96af-f9d4f2b70077') - def test_update_access_server_address(self): - # The server's access addresses should reflect the provided values - server = self.create_test_server(wait_until='ACTIVE') - - # Update the IPv4 and IPv6 access addresses - self.client.update_server(server['id'], - accessIPv4='1.1.1.1', - accessIPv6='::babe:202:202') - waiters.wait_for_server_status(self.client, server['id'], 'ACTIVE') - - # Verify the access addresses have been updated - server = self.client.show_server(server['id'])['server'] - self.assertEqual('1.1.1.1', server['accessIPv4']) - self.assertEqual('::babe:202:202', server['accessIPv6']) - - @decorators.idempotent_id('38fb1d02-c3c5-41de-91d3-9bc2025a75eb') - def test_create_server_with_ipv6_addr_only(self): - # Create a server without an IPv4 address(only IPv6 address). - server = self.create_test_server(accessIPv6='2001:2001::3') - waiters.wait_for_server_status(self.client, server['id'], 'ACTIVE') - server = self.client.show_server(server['id'])['server'] - self.assertEqual('2001:2001::3', server['accessIPv6']) - - -class ServerShowV247Test(base.BaseV2ComputeTest): - min_microversion = '2.47' - max_microversion = 'latest' - - @decorators.idempotent_id('88b0bdb2-494c-11e7-a919-92ebcb67fe33') - def test_show_server(self): - server = self.create_test_server() - # All fields will be checked by API schema - self.servers_client.show_server(server['id']) diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py deleted file mode 100644 index 764767b8a..000000000 --- a/tempest/api/compute/servers/test_servers_negative.py +++ /dev/null @@ -1,583 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 sys - -import testtools - -from tempest.api.compute import base -from tempest.common import compute -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class ServersNegativeTestJSON(base.BaseV2ComputeTest): - - def setUp(self): - super(ServersNegativeTestJSON, self).setUp() - try: - waiters.wait_for_server_status(self.client, self.server_id, - 'ACTIVE') - except Exception: - self.__class__.server_id = self.rebuild_server(self.server_id) - - def tearDown(self): - self.server_check_teardown() - super(ServersNegativeTestJSON, self).tearDown() - - @classmethod - def setup_clients(cls): - super(ServersNegativeTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(ServersNegativeTestJSON, cls).resource_setup() - server = cls.create_test_server(wait_until='ACTIVE') - cls.server_id = server['id'] - - server = cls.create_test_server() - cls.client.delete_server(server['id']) - waiters.wait_for_server_termination(cls.client, server['id']) - cls.deleted_server_id = server['id'] - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('dbbfd247-c40c-449e-8f6c-d2aa7c7da7cf') - def test_server_name_blank(self): - # Create a server with name parameter empty - - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, - name='') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('b8a7235e-5246-4a8f-a08e-b34877c6586f') - @testtools.skipUnless(CONF.compute_feature_enabled.personality, - 'Nova personality feature disabled') - def test_personality_file_contents_not_encoded(self): - # Use an unencoded file when creating a server with personality - - file_contents = 'This is a test file.' - person = [{'path': '/etc/testfile.txt', - 'contents': file_contents}] - - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, - personality=person) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('fcba1052-0a50-4cf3-b1ac-fae241edf02f') - def test_create_with_invalid_image(self): - # Create a server with an unknown image - - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, - image_id=-1) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('18f5227f-d155-4429-807c-ccb103887537') - def test_create_with_invalid_flavor(self): - # Create a server with an unknown flavor - - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, - flavor=-1,) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7f70a4d1-608f-4794-9e56-cb182765972c') - def test_invalid_access_ip_v4_address(self): - # An access IPv4 address must match a valid address pattern - - IPv4 = '1.1.1.1.1.1' - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, accessIPv4=IPv4) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5226dd80-1e9c-4d8a-b5f9-b26ca4763fd0') - def test_invalid_ip_v6_address(self): - # An access IPv6 address must match a valid address pattern - - IPv6 = 'notvalid' - - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, accessIPv6=IPv6) - - @decorators.idempotent_id('7ea45b3e-e770-46fa-bfcc-9daaf6d987c0') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize not available.') - @decorators.attr(type=['negative']) - def test_resize_nonexistent_server(self): - # Resize a non-existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.client.resize_server, - nonexistent_server, self.flavor_ref) - - @decorators.idempotent_id('ced1a1d7-2ab6-45c9-b90f-b27d87b30efd') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize not available.') - @decorators.attr(type=['negative']) - def test_resize_server_with_non_existent_flavor(self): - # Resize a server with non-existent flavor - nonexistent_flavor = data_utils.rand_uuid() - self.assertRaises(lib_exc.BadRequest, self.client.resize_server, - self.server_id, flavor_ref=nonexistent_flavor) - - @decorators.idempotent_id('45436a7d-a388-4a35-a9d8-3adc5d0d940b') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize not available.') - @decorators.attr(type=['negative']) - def test_resize_server_with_null_flavor(self): - # Resize a server with null flavor - self.assertRaises(lib_exc.BadRequest, self.client.resize_server, - self.server_id, flavor_ref="") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d4c023a0-9c55-4747-9dd5-413b820143c7') - def test_reboot_non_existent_server(self): - # Reboot a non existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.reboot_server, - nonexistent_server, type='SOFT') - - @decorators.idempotent_id('d1417e7f-a509-41b5-a102-d5eed8613369') - @testtools.skipUnless(CONF.compute_feature_enabled.pause, - 'Pause is not available.') - @decorators.attr(type=['negative']) - def test_pause_paused_server(self): - # Pause a paused server. - self.client.pause_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, 'PAUSED') - self.assertRaises(lib_exc.Conflict, - self.client.pause_server, - self.server_id) - self.client.unpause_server(self.server_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('98fa0458-1485-440f-873b-fe7f0d714930') - def test_rebuild_deleted_server(self): - # Rebuild a deleted server - self.assertRaises(lib_exc.NotFound, - self.client.rebuild_server, - self.deleted_server_id, self.image_ref) - - @decorators.related_bug('1660878', status_code=409) - @decorators.attr(type=['negative']) - @decorators.idempotent_id('581a397d-5eab-486f-9cf9-1014bbd4c984') - def test_reboot_deleted_server(self): - # Reboot a deleted server - self.assertRaises(lib_exc.NotFound, self.client.reboot_server, - self.deleted_server_id, type='SOFT') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d86141a7-906e-4731-b187-d64a2ea61422') - def test_rebuild_non_existent_server(self): - # Rebuild a non existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.client.rebuild_server, - nonexistent_server, - self.image_ref) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('fd57f159-68d6-4c2a-902b-03070828a87e') - def test_create_numeric_server_name(self): - server_name = 12345 - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, - name=server_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('c3e0fb12-07fc-4d76-a22e-37409887afe8') - def test_create_server_name_length_exceeds_256(self): - # Create a server with name length exceeding 255 characters - - server_name = 'a' * 256 - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, - name=server_name) - - @decorators.attr(type=['negative']) - @decorators.related_bug('1651064', status_code=500) - @test.services('volume') - @decorators.idempotent_id('12146ac1-d7df-4928-ad25-b1f99e5286cd') - def test_create_server_invalid_bdm_in_2nd_dict(self): - volume = self.create_volume() - bdm_1st = {"source_type": "image", - "delete_on_termination": True, - "boot_index": 0, - "uuid": self.image_ref, - "destination_type": "local"} - bdm_2nd = {"source_type": "volume", - "uuid": volume["id"], - "destination_type": "invalid"} - bdm = [bdm_1st, bdm_2nd] - - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, - image_id=self.image_ref, - block_device_mapping_v2=bdm) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('4e72dc2d-44c5-4336-9667-f7972e95c402') - def test_create_with_invalid_network_uuid(self): - # Pass invalid network uuid while creating a server - - networks = [{'fixed_ip': '10.0.1.1', 'uuid': 'a-b-c-d-e-f-g-h-i-j'}] - - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, - networks=networks) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7a2efc39-530c-47de-b875-2dd01c8d39bd') - def test_create_with_non_existent_keypair(self): - # Pass a non-existent keypair while creating a server - - key_name = data_utils.rand_name('key') - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, - key_name=key_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7fc74810-0bd2-4cd7-8244-4f33a9db865a') - def test_create_server_metadata_exceeds_length_limit(self): - # Pass really long metadata while creating a server - - metadata = {'a': 'b' * 260} - self.assertRaises((lib_exc.BadRequest, lib_exc.OverLimit), - self.create_test_server, - metadata=metadata) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('aa8eed43-e2cb-4ebf-930b-da14f6a21d81') - def test_update_name_of_non_existent_server(self): - # Update name of a non-existent server - - nonexistent_server = data_utils.rand_uuid() - new_name = data_utils.rand_name( - self.__class__.__name__ + '-server') + '_updated' - - self.assertRaises(lib_exc.NotFound, self.client.update_server, - nonexistent_server, name=new_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('38204696-17c6-44da-9590-40f87fb5a899') - def test_update_server_set_empty_name(self): - # Update name of the server to an empty string - - new_name = '' - - self.assertRaises(lib_exc.BadRequest, self.client.update_server, - self.server_id, name=new_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5c8e244c-dada-4590-9944-749c455b431f') - def test_update_server_name_length_exceeds_256(self): - # Update name of server exceed the name length limit - - new_name = 'a' * 256 - self.assertRaises(lib_exc.BadRequest, - self.client.update_server, - self.server_id, - name=new_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1041b4e6-514b-4855-96a5-e974b60870a3') - def test_delete_non_existent_server(self): - # Delete a non existent server - - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.delete_server, - nonexistent_server) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('75f79124-277c-45e6-a373-a1d6803f4cc4') - def test_delete_server_pass_negative_id(self): - # Pass an invalid string parameter to delete server - - self.assertRaises(lib_exc.NotFound, self.client.delete_server, -1) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f4d7279b-5fd2-4bf2-9ba4-ae35df0d18c5') - def test_delete_server_pass_id_exceeding_length_limit(self): - # Pass a server ID that exceeds length limit to delete server - - self.assertRaises(lib_exc.NotFound, self.client.delete_server, - sys.maxsize + 1) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('c5fa6041-80cd-483b-aa6d-4e45f19d093c') - def test_create_with_nonexistent_security_group(self): - # Create a server with a nonexistent security group - - security_groups = [{'name': 'does_not_exist'}] - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, - security_groups=security_groups) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('3436b02f-1b1e-4f03-881e-c6a602327439') - def test_get_non_existent_server(self): - # Get a non existent server details - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.show_server, - nonexistent_server) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a31460a9-49e1-42aa-82ee-06e0bb7c2d03') - def test_stop_non_existent_server(self): - # Stop a non existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.servers_client.stop_server, - nonexistent_server) - - @decorators.idempotent_id('6a8dc0c6-6cd4-4c0a-9f32-413881828091') - @testtools.skipUnless(CONF.compute_feature_enabled.pause, - 'Pause is not available.') - @decorators.attr(type=['negative']) - def test_pause_non_existent_server(self): - # pause a non existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.pause_server, - nonexistent_server) - - @decorators.idempotent_id('705b8e3a-e8a7-477c-a19b-6868fc24ac75') - @testtools.skipUnless(CONF.compute_feature_enabled.pause, - 'Pause is not available.') - @decorators.attr(type=['negative']) - def test_unpause_non_existent_server(self): - # unpause a non existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.unpause_server, - nonexistent_server) - - @decorators.idempotent_id('c8e639a7-ece8-42dd-a2e0-49615917ba4f') - @testtools.skipUnless(CONF.compute_feature_enabled.pause, - 'Pause is not available.') - @decorators.attr(type=['negative']) - def test_unpause_server_invalid_state(self): - # unpause an active server. - self.assertRaises(lib_exc.Conflict, - self.client.unpause_server, - self.server_id) - - @decorators.idempotent_id('d1f032d5-7b6e-48aa-b252-d5f16dd994ca') - @testtools.skipUnless(CONF.compute_feature_enabled.suspend, - 'Suspend is not available.') - @decorators.attr(type=['negative']) - def test_suspend_non_existent_server(self): - # suspend a non existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.suspend_server, - nonexistent_server) - - @decorators.idempotent_id('7f323206-05a9-4bf8-996b-dd5b2036501b') - @testtools.skipUnless(CONF.compute_feature_enabled.suspend, - 'Suspend is not available.') - @decorators.attr(type=['negative']) - def test_suspend_server_invalid_state(self): - # suspend a suspended server. - self.client.suspend_server(self.server_id) - waiters.wait_for_server_status(self.client, self.server_id, - 'SUSPENDED') - self.assertRaises(lib_exc.Conflict, - self.client.suspend_server, - self.server_id) - self.client.resume_server(self.server_id) - - @decorators.idempotent_id('221cd282-bddb-4837-a683-89c2487389b6') - @testtools.skipUnless(CONF.compute_feature_enabled.suspend, - 'Suspend is not available.') - @decorators.attr(type=['negative']) - def test_resume_non_existent_server(self): - # resume a non existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.resume_server, - nonexistent_server) - - @decorators.idempotent_id('ccb6294d-c4c9-498f-8a43-554c098bfadb') - @testtools.skipUnless(CONF.compute_feature_enabled.suspend, - 'Suspend is not available.') - @decorators.attr(type=['negative']) - def test_resume_server_invalid_state(self): - # resume an active server. - self.assertRaises(lib_exc.Conflict, - self.client.resume_server, - self.server_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7dd919e7-413f-4198-bebb-35e2a01b13e9') - def test_get_console_output_of_non_existent_server(self): - # get the console output for a non existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.client.get_console_output, - nonexistent_server, length=10) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6f47992b-5144-4250-9f8b-f00aa33950f3') - def test_force_delete_nonexistent_server_id(self): - # force-delete a non existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.client.force_delete_server, - nonexistent_server) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9c6d38cc-fcfb-437a-85b9-7b788af8bf01') - def test_restore_nonexistent_server_id(self): - # restore-delete a non existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.client.restore_soft_deleted_server, - nonexistent_server) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7fcadfab-bd6a-4753-8db7-4a51e51aade9') - def test_restore_server_invalid_state(self): - # we can only restore-delete a server in 'soft-delete' state - self.assertRaises(lib_exc.Conflict, - self.client.restore_soft_deleted_server, - self.server_id) - - @decorators.idempotent_id('abca56e2-a892-48ea-b5e5-e07e69774816') - @testtools.skipUnless(CONF.compute_feature_enabled.shelve, - 'Shelve is not available.') - @decorators.attr(type=['negative']) - def test_shelve_non_existent_server(self): - # shelve a non existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.shelve_server, - nonexistent_server) - - @decorators.idempotent_id('443e4f9b-e6bf-4389-b601-3a710f15fddd') - @testtools.skipUnless(CONF.compute_feature_enabled.shelve, - 'Shelve is not available.') - @decorators.attr(type=['negative']) - def test_shelve_shelved_server(self): - # shelve a shelved server. - compute.shelve_server(self.client, self.server_id) - - server = self.client.show_server(self.server_id)['server'] - image_name = server['name'] + '-shelved' - params = {'name': image_name} - images = self.compute_images_client.list_images(**params)['images'] - self.assertEqual(1, len(images)) - self.assertEqual(image_name, images[0]['name']) - - self.assertRaises(lib_exc.Conflict, - self.client.shelve_server, - self.server_id) - - self.client.unshelve_server(self.server_id) - - @decorators.idempotent_id('23d23b37-afaf-40d7-aa5d-5726f82d8821') - @testtools.skipUnless(CONF.compute_feature_enabled.shelve, - 'Shelve is not available.') - @decorators.attr(type=['negative']) - def test_unshelve_non_existent_server(self): - # unshelve a non existent server - nonexistent_server = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.unshelve_server, - nonexistent_server) - - @decorators.idempotent_id('8f198ded-1cca-4228-9e65-c6b449c54880') - @testtools.skipUnless(CONF.compute_feature_enabled.shelve, - 'Shelve is not available.') - @decorators.attr(type=['negative']) - def test_unshelve_server_invalid_state(self): - # unshelve an active server. - self.assertRaises(lib_exc.Conflict, - self.client.unshelve_server, - self.server_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('74085be3-a370-4ca2-bc51-2d0e10e0f573') - @test.services('volume', 'image') - def test_create_server_from_non_bootable_volume(self): - # Create a volume - volume = self.create_volume() - - # Update volume bootable status to false - self.volumes_client.set_bootable_volume(volume['id'], - bootable=False) - - # Verify bootable flag was updated - nonbootable_vol = self.volumes_client.show_volume( - volume['id'])['volume'] - self.assertEqual('false', nonbootable_vol['bootable']) - - # Block device mapping - bd_map = [{'boot_index': '0', - 'uuid': volume['id'], - 'source_type': 'volume', - 'destination_type': 'volume', - 'delete_on_termination': False}] - - # Try creating a server from non-bootable volume - self.assertRaises(lib_exc.BadRequest, - self.create_test_server, - image_id='', - wait_until='ACTIVE', - block_device_mapping_v2=bd_map) - - -class ServersNegativeTestMultiTenantJSON(base.BaseV2ComputeTest): - - credentials = ['primary', 'alt'] - - def setUp(self): - super(ServersNegativeTestMultiTenantJSON, self).setUp() - try: - waiters.wait_for_server_status(self.servers_client, self.server_id, - 'ACTIVE') - except Exception: - self.__class__.server_id = self.rebuild_server(self.server_id) - - @classmethod - def setup_clients(cls): - super(ServersNegativeTestMultiTenantJSON, cls).setup_clients() - cls.alt_client = cls.os_alt.servers_client - - @classmethod - def resource_setup(cls): - super(ServersNegativeTestMultiTenantJSON, cls).resource_setup() - server = cls.create_test_server(wait_until='ACTIVE') - cls.server_id = server['id'] - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('543d84c1-dd2e-4c6d-8cb2-b9da0efaa384') - def test_update_server_of_another_tenant(self): - # Update name of a server that belongs to another tenant - - new_name = self.server_id + '_new' - self.assertRaises(lib_exc.NotFound, - self.alt_client.update_server, self.server_id, - name=new_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5c75009d-3eea-423e-bea3-61b09fd25f9c') - def test_delete_a_server_of_another_tenant(self): - # Delete a server that belongs to another tenant - self.assertRaises(lib_exc.NotFound, - self.alt_client.delete_server, - self.server_id) diff --git a/tempest/api/compute/servers/test_virtual_interfaces.py b/tempest/api/compute/servers/test_virtual_interfaces.py deleted file mode 100644 index 6b625d935..000000000 --- a/tempest/api/compute/servers/test_virtual_interfaces.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 netaddr -import testtools - -from tempest.api.compute import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions -from tempest import test - -CONF = config.CONF - - -class VirtualInterfacesTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_credentials(cls): - # This test needs a network and a subnet - cls.set_network_resources(network=True, subnet=True) - super(VirtualInterfacesTestJSON, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(VirtualInterfacesTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @classmethod - def resource_setup(cls): - super(VirtualInterfacesTestJSON, cls).resource_setup() - cls.server = cls.create_test_server(wait_until='ACTIVE') - - @decorators.idempotent_id('96c4e2ef-5e4d-4d7f-87f5-fed6dca18016') - @test.services('network') - def test_list_virtual_interfaces(self): - # Positive test:Should be able to GET the virtual interfaces list - # for a given server_id - - if CONF.service_available.neutron: - # TODO(mriedem): After a microversion implements the API for - # neutron, a 400 should be a failure for nova-network and neutron. - with testtools.ExpectedException(exceptions.BadRequest): - self.client.list_virtual_interfaces(self.server['id']) - else: - output = self.client.list_virtual_interfaces(self.server['id']) - self.assertIsNotNone(output) - virt_ifaces = output - self.assertNotEmpty(virt_ifaces['virtual_interfaces'], - 'Expected virtual interfaces, got 0 ' - 'interfaces.') - for virt_iface in virt_ifaces['virtual_interfaces']: - mac_address = virt_iface['mac_address'] - self.assertTrue(netaddr.valid_mac(mac_address), - "Invalid mac address detected. mac address: %s" - % mac_address) diff --git a/tempest/api/compute/servers/test_virtual_interfaces_negative.py b/tempest/api/compute/servers/test_virtual_interfaces_negative.py deleted file mode 100644 index 173784a40..000000000 --- a/tempest/api/compute/servers/test_virtual_interfaces_negative.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 tempest.api.compute import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - - -class VirtualInterfacesNegativeTestJSON(base.BaseV2ComputeTest): - - @classmethod - def setup_credentials(cls): - # For this test no network resources are needed - cls.set_network_resources() - super(VirtualInterfacesNegativeTestJSON, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(VirtualInterfacesNegativeTestJSON, cls).setup_clients() - cls.client = cls.servers_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('64ebd03c-1089-4306-93fa-60f5eb5c803c') - @test.services('network') - def test_list_virtual_interfaces_invalid_server_id(self): - # Negative test: Should not be able to GET virtual interfaces - # for an invalid server_id - invalid_server_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.client.list_virtual_interfaces, - invalid_server_id) diff --git a/tempest/api/compute/test_extensions.py b/tempest/api/compute/test_extensions.py deleted file mode 100644 index 42e13bdef..000000000 --- a/tempest/api/compute/test_extensions.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_log import log as logging - -from tempest.api.compute import base -from tempest import config -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -LOG = logging.getLogger(__name__) - - -class ExtensionsTestJSON(base.BaseV2ComputeTest): - - @decorators.idempotent_id('3bb27738-b759-4e0d-a5fa-37d7a6df07d1') - def test_list_extensions(self): - # List of all extensions - if not CONF.compute_feature_enabled.api_extensions: - raise self.skipException('There are not any extensions configured') - extensions = self.extensions_client.list_extensions()['extensions'] - ext = CONF.compute_feature_enabled.api_extensions[0] - - # Log extensions list - extension_list = map(lambda x: x['alias'], extensions) - LOG.debug("Nova extensions: %s", ','.join(extension_list)) - - if ext == 'all': - self.assertIn('Hosts', map(lambda x: x['name'], extensions)) - elif ext: - self.assertIn(ext, extension_list) - else: - raise self.skipException('There are not any extensions configured') - - @decorators.idempotent_id('05762f39-bdfa-4cdb-9b46-b78f8e78e2fd') - @test.requires_ext(extension='os-consoles', service='compute') - def test_get_extension(self): - # get the specified extensions - extension = self.extensions_client.show_extension('os-consoles') - self.assertEqual('os-consoles', extension['extension']['alias']) diff --git a/tempest/api/compute/test_networks.py b/tempest/api/compute/test_networks.py deleted file mode 100644 index b8c79d7ef..000000000 --- a/tempest/api/compute/test_networks.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# 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 tempest.api.compute import base -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class ComputeNetworksTest(base.BaseV2ComputeTest): - @classmethod - def skip_checks(cls): - super(ComputeNetworksTest, cls).skip_checks() - if CONF.service_available.neutron: - raise cls.skipException('nova-network is not available.') - - @classmethod - def setup_clients(cls): - super(ComputeNetworksTest, cls).setup_clients() - cls.client = cls.os_primary.compute_networks_client - - @decorators.idempotent_id('3fe07175-312e-49a5-a623-5f52eeada4c2') - def test_list_networks(self): - networks = self.client.list_networks()['networks'] - self.assertNotEmpty(networks, "No networks found.") diff --git a/tempest/api/compute/test_quotas.py b/tempest/api/compute/test_quotas.py deleted file mode 100644 index 9d83ee19b..000000000 --- a/tempest/api/compute/test_quotas.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.compute import base -from tempest.common import tempest_fixtures as fixtures -from tempest.lib import decorators -from tempest import test - - -class QuotasTestJSON(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(QuotasTestJSON, cls).skip_checks() - if not test.is_extension_enabled('os-quota-sets', 'compute'): - msg = "quotas extension not enabled." - raise cls.skipException(msg) - - def setUp(self): - # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests. - self.useFixture(fixtures.LockFixture('compute_quotas')) - super(QuotasTestJSON, self).setUp() - - @classmethod - def setup_clients(cls): - super(QuotasTestJSON, cls).setup_clients() - cls.client = cls.quotas_client - - @classmethod - def resource_setup(cls): - super(QuotasTestJSON, cls).resource_setup() - cls.tenant_id = cls.client.tenant_id - cls.user_id = cls.client.user_id - cls.default_quota_set = set(('injected_file_content_bytes', - 'metadata_items', 'injected_files', - 'ram', 'floating_ips', - 'fixed_ips', 'key_pairs', - 'injected_file_path_bytes', - 'instances', 'security_group_rules', - 'cores', 'security_groups', - 'server_group_members', 'server_groups')) - - @decorators.idempotent_id('f1ef0a97-dbbb-4cca-adc5-c9fbc4f76107') - def test_get_quotas(self): - # User can get the quota set for it's tenant - expected_quota_set = self.default_quota_set | set(['id']) - quota_set = self.client.show_quota_set(self.tenant_id)['quota_set'] - self.assertEqual(quota_set['id'], self.tenant_id) - for quota in expected_quota_set: - self.assertIn(quota, quota_set.keys()) - - # get the quota set using user id - quota_set = self.client.show_quota_set( - self.tenant_id, user_id=self.user_id)['quota_set'] - self.assertEqual(quota_set['id'], self.tenant_id) - for quota in expected_quota_set: - self.assertIn(quota, quota_set.keys()) - - @decorators.idempotent_id('9bfecac7-b966-4f47-913f-1a9e2c12134a') - def test_get_default_quotas(self): - # User can get the default quota set for it's tenant - expected_quota_set = self.default_quota_set | set(['id']) - quota_set = (self.client.show_default_quota_set(self.tenant_id) - ['quota_set']) - self.assertEqual(quota_set['id'], self.tenant_id) - for quota in expected_quota_set: - self.assertIn(quota, quota_set.keys()) - - @decorators.idempotent_id('cd65d997-f7e4-4966-a7e9-d5001b674fdc') - def test_compare_tenant_quotas_with_default_quotas(self): - # Tenants are created with the default quota values - default_quota_set = \ - self.client.show_default_quota_set(self.tenant_id)['quota_set'] - tenant_quota_set = (self.client.show_quota_set(self.tenant_id) - ['quota_set']) - self.assertEqual(default_quota_set, tenant_quota_set) diff --git a/tempest/api/compute/test_tenant_networks.py b/tempest/api/compute/test_tenant_networks.py deleted file mode 100644 index 18c5d385d..000000000 --- a/tempest/api/compute/test_tenant_networks.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 tempest.api.compute import base -from tempest.lib import decorators -from tempest import test - - -class ComputeTenantNetworksTest(base.BaseV2ComputeTest): - - @classmethod - def resource_setup(cls): - super(ComputeTenantNetworksTest, cls).resource_setup() - cls.client = cls.os_primary.tenant_networks_client - cls.network = cls.get_tenant_network() - - @classmethod - def setup_credentials(cls): - cls.set_network_resources(network=True) - super(ComputeTenantNetworksTest, cls).setup_credentials() - - @decorators.idempotent_id('edfea98e-bbe3-4c7a-9739-87b986baff26') - @test.services('network') - def test_list_show_tenant_networks(self): - # Fetch all networks that are visible to the tenant: this may include - # shared and external networks - tenant_networks = [ - n['id'] for n in self.client.list_tenant_networks()['networks'] - ] - self.assertIn(self.network['id'], tenant_networks, - "No tenant networks found.") - - net = self.client.show_tenant_network(self.network['id']) - self.assertEqual(self.network['id'], net['network']['id']) diff --git a/tempest/api/compute/test_versions.py b/tempest/api/compute/test_versions.py deleted file mode 100644 index 614155385..000000000 --- a/tempest/api/compute/test_versions.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# -# 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 tempest.api.compute import base -from tempest.lib import decorators - - -class TestVersions(base.BaseV2ComputeTest): - - @decorators.idempotent_id('6c0a0990-43b6-4529-9b61-5fd8daf7c55c') - @decorators.attr(type='smoke') - def test_list_api_versions(self): - """Test that a get of the unversioned url returns the choices doc. - - A key feature in OpenStack services is the idea that you can - GET / on the service and get a list of the versioned endpoints - that you can access. This comes back as a status 300 - request. It's important that this is available to API - consumers to discover the API they can use. - - """ - result = self.versions_client.list_versions() - versions = result['versions'] - # NOTE(sdague): at a later point we may want to loosen this - # up, but for now this should be true of all Novas deployed. - self.assertEqual(versions[0]['id'], 'v2.0', - "The first listed version should be v2.0") - - @decorators.idempotent_id('b953a29e-929c-4a8e-81be-ec3a7e03cb76') - @decorators.attr(type='smoke') - def test_get_version_details(self): - """Test individual version endpoints info works. - - In addition to the GET / version request, there is also a - version info document stored at the top of the versioned - endpoints. This provides access to details about that - endpoint, including min / max version if that implements - microversions. - - This test starts with the version list, iterates all the - returned endpoints, and fetches them. This will also ensure - that all the version links are followable constructs which - will help detect configuration issues when SSL termination - isn't done completely for a site. - - """ - result = self.versions_client.list_versions() - versions = result['versions'] - - # iterate through all the versions that are returned and - # attempt to get their version documents. - for version in versions: - links = [x for x in version['links'] if x['rel'] == 'self'] - self.assertEqual( - len(links), 1, - "There should only be 1 self link in %s" % version) - link = links[0] - # this is schema validated - result = self.versions_client.get_version_by_url(link['href']) - # ensure the new self link matches the old one - newlinks = [x for x in result['version']['links'] - if x['rel'] == 'self'] - self.assertEqual(links, newlinks) diff --git a/tempest/api/compute/volumes/__init__.py b/tempest/api/compute/volumes/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py deleted file mode 100644 index 502bc1b33..000000000 --- a/tempest/api/compute/volumes/test_attach_volume.py +++ /dev/null @@ -1,251 +0,0 @@ -# Copyright 2013 IBM 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 testtools - -from tempest.api.compute import base -from tempest.common import compute -from tempest.common.utils.linux import remote_client -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class AttachVolumeTestJSON(base.BaseV2ComputeTest): - max_microversion = '2.19' - - @classmethod - def skip_checks(cls): - super(AttachVolumeTestJSON, cls).skip_checks() - if not CONF.service_available.cinder: - skip_msg = ("%s skipped as Cinder is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_credentials(cls): - cls.prepare_instance_network() - super(AttachVolumeTestJSON, cls).setup_credentials() - - @classmethod - def resource_setup(cls): - cls.set_validation_resources() - super(AttachVolumeTestJSON, cls).resource_setup() - cls.device = CONF.compute.volume_device_name - - def _create_server(self): - # Start a server and wait for it to become ready - server = self.create_test_server( - validatable=True, - wait_until='ACTIVE', - adminPass=self.image_ssh_password) - self.addCleanup(self.delete_server, server['id']) - # Record addresses so that we can ssh later - server['addresses'] = self.servers_client.list_addresses( - server['id'])['addresses'] - return server - - @decorators.idempotent_id('52e9045a-e90d-4c0d-9087-79d657faffff') - def test_attach_detach_volume(self): - # Stop and Start a server with an attached volume, ensuring that - # the volume remains attached. - server = self._create_server() - - # NOTE(andreaf) Create one remote client used throughout the test. - if CONF.validation.run_validation: - linux_client = remote_client.RemoteClient( - self.get_server_ip(server), - self.image_ssh_user, - self.image_ssh_password, - self.validation_resources['keypair']['private_key'], - server=server, - servers_client=self.servers_client) - # NOTE(andreaf) We need to ensure the ssh key has been - # injected in the guest before we power cycle - linux_client.validate_authentication() - - volume = self.create_volume() - attachment = self.attach_volume(server, volume, - device=('/dev/%s' % self.device)) - - self.servers_client.stop_server(server['id']) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'SHUTOFF') - - self.servers_client.start_server(server['id']) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'ACTIVE') - - if CONF.validation.run_validation: - disks = linux_client.get_disks() - device_name_to_match = '\n' + self.device + ' ' - self.assertIn(device_name_to_match, disks) - - self.servers_client.detach_volume(server['id'], attachment['volumeId']) - waiters.wait_for_volume_resource_status( - self.volumes_client, attachment['volumeId'], 'available') - - self.servers_client.stop_server(server['id']) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'SHUTOFF') - - self.servers_client.start_server(server['id']) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'ACTIVE') - - if CONF.validation.run_validation: - disks = linux_client.get_disks() - self.assertNotIn(device_name_to_match, disks) - - @decorators.idempotent_id('7fa563fe-f0f7-43eb-9e22-a1ece036b513') - def test_list_get_volume_attachments(self): - # List volume attachment of the server - server = self._create_server() - volume_1st = self.create_volume() - attachment_1st = self.attach_volume(server, volume_1st, - device=('/dev/%s' % self.device)) - body = self.servers_client.list_volume_attachments( - server['id'])['volumeAttachments'] - self.assertEqual(1, len(body)) - self.assertIn(attachment_1st, body) - - # Get volume attachment of the server - body = self.servers_client.show_volume_attachment( - server['id'], - attachment_1st['id'])['volumeAttachment'] - self.assertEqual(server['id'], body['serverId']) - self.assertEqual(volume_1st['id'], body['volumeId']) - self.assertEqual(attachment_1st['id'], body['id']) - - # attach one more volume to server - volume_2nd = self.create_volume() - attachment_2nd = self.attach_volume(server, volume_2nd) - body = self.servers_client.list_volume_attachments( - server['id'])['volumeAttachments'] - self.assertEqual(2, len(body)) - - for attachment in [attachment_1st, attachment_2nd]: - body = self.servers_client.show_volume_attachment( - server['id'], attachment['id'])['volumeAttachment'] - self.assertEqual(server['id'], body['serverId']) - self.assertEqual(attachment['volumeId'], body['volumeId']) - self.assertEqual(attachment['id'], body['id']) - - -class AttachVolumeShelveTestJSON(AttachVolumeTestJSON): - """Testing volume with shelved instance. - - This test checks the attaching and detaching volumes from - a shelved or shelved offload instance. - """ - - min_microversion = '2.20' - max_microversion = 'latest' - - def _count_volumes(self, server): - # Count number of volumes on an instance - volumes = 0 - if CONF.validation.run_validation: - linux_client = remote_client.RemoteClient( - self.get_server_ip(server), - self.image_ssh_user, - self.image_ssh_password, - self.validation_resources['keypair']['private_key'], - server=server, - servers_client=self.servers_client) - - command = 'grep -c -E [vs]d.$ /proc/partitions' - volumes = int(linux_client.exec_command(command).strip()) - return volumes - - def _shelve_server(self, server): - # NOTE(andreaf) If we are going to shelve a server, we should - # check first whether the server is ssh-able. Otherwise we - # won't be able to distinguish failures introduced by shelve - # from pre-existing ones. Also it's good to wait for cloud-init - # to be done and sshd server to be running before shelving to - # avoid breaking the VM - if CONF.validation.run_validation: - linux_client = remote_client.RemoteClient( - self.get_server_ip(server), - self.image_ssh_user, - self.image_ssh_password, - self.validation_resources['keypair']['private_key'], - server=server, - servers_client=self.servers_client) - linux_client.validate_authentication() - - # If validation went ok, or it was skipped, shelve the server - compute.shelve_server(self.servers_client, server['id']) - - def _unshelve_server_and_check_volumes(self, server, number_of_volumes): - # Unshelve the instance and check that there are expected volumes - self.servers_client.unshelve_server(server['id']) - waiters.wait_for_server_status(self.servers_client, - server['id'], - 'ACTIVE') - if CONF.validation.run_validation: - counted_volumes = self._count_volumes(server) - self.assertEqual(number_of_volumes, counted_volumes) - - @decorators.idempotent_id('13a940b6-3474-4c3c-b03f-29b89112bfee') - @testtools.skipUnless(CONF.compute_feature_enabled.shelve, - 'Shelve is not available.') - def test_attach_volume_shelved_or_offload_server(self): - # Create server, count number of volumes on it, shelve - # server and attach pre-created volume to shelved server - server = self._create_server() - volume = self.create_volume() - num_vol = self._count_volumes(server) - self._shelve_server(server) - attachment = self.attach_volume(server, volume, - device=('/dev/%s' % self.device), - check_reserved=True) - - # Unshelve the instance and check that attached volume exists - self._unshelve_server_and_check_volumes(server, num_vol + 1) - - # Get volume attachment of the server - volume_attachment = self.servers_client.show_volume_attachment( - server['id'], - attachment['id'])['volumeAttachment'] - self.assertEqual(server['id'], volume_attachment['serverId']) - self.assertEqual(attachment['id'], volume_attachment['id']) - # Check the mountpoint is not None after unshelve server even in - # case of shelved_offloaded. - self.assertIsNotNone(volume_attachment['device']) - - @decorators.idempotent_id('b54e86dd-a070-49c4-9c07-59ae6dae15aa') - @testtools.skipUnless(CONF.compute_feature_enabled.shelve, - 'Shelve is not available.') - def test_detach_volume_shelved_or_offload_server(self): - # Count number of volumes on instance, shelve - # server and attach pre-created volume to shelved server - server = self._create_server() - volume = self.create_volume() - num_vol = self._count_volumes(server) - self._shelve_server(server) - - # Attach and then detach the volume - self.attach_volume(server, volume, device=('/dev/%s' % self.device), - check_reserved=True) - self.servers_client.detach_volume(server['id'], volume['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') - - # Unshelve the instance and check that we have the expected number of - # volume(s) - self._unshelve_server_and_check_volumes(server, num_vol) diff --git a/tempest/api/compute/volumes/test_attach_volume_negative.py b/tempest/api/compute/volumes/test_attach_volume_negative.py deleted file mode 100644 index eabb907ee..000000000 --- a/tempest/api/compute/volumes/test_attach_volume_negative.py +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.api.compute import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class AttachVolumeNegativeTest(base.BaseV2ComputeTest): - - @classmethod - def skip_checks(cls): - super(AttachVolumeNegativeTest, cls).skip_checks() - if not CONF.service_available.cinder: - skip_msg = ("%s skipped as Cinder is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @decorators.attr(type=['negative']) - @decorators.related_bug('1630783', status_code=500) - @decorators.idempotent_id('a313b5cd-fbd0-49cc-94de-870e99f763c7') - def test_delete_attached_volume(self): - server = self.create_test_server(wait_until='ACTIVE') - volume = self.create_volume() - - path = "/dev/%s" % CONF.compute.volume_device_name - self.attach_volume(server, volume, device=path) - - self.assertRaises(lib_exc.BadRequest, - self.delete_volume, volume['id']) diff --git a/tempest/api/compute/volumes/test_volume_snapshots.py b/tempest/api/compute/volumes/test_volume_snapshots.py deleted file mode 100644 index 0f436ebc7..000000000 --- a/tempest/api/compute/volumes/test_volume_snapshots.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright 2015 Fujitsu(fnst) Corporation -# 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 testtools - -from tempest.api.compute import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -CONF = config.CONF - - -class VolumesSnapshotsTestJSON(base.BaseV2ComputeTest): - - # These tests will fail with a 404 starting from microversion 2.36. For - # more information, see: - # https://developer.openstack.org/api-ref/compute/#volume-extension-os-volumes-os-snapshots-deprecated - max_microversion = '2.35' - - @classmethod - def skip_checks(cls): - super(VolumesSnapshotsTestJSON, cls).skip_checks() - if not CONF.service_available.cinder: - skip_msg = ("%s skipped as Cinder is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(VolumesSnapshotsTestJSON, cls).setup_clients() - cls.volumes_client = cls.volumes_extensions_client - cls.snapshots_client = cls.snapshots_extensions_client - - @decorators.idempotent_id('cd4ec87d-7825-450d-8040-6e2068f2da8f') - @testtools.skipUnless(CONF.volume_feature_enabled.snapshot, - 'Cinder volume snapshots are disabled') - def test_volume_snapshot_create_get_list_delete(self): - volume = self.create_volume() - self.addCleanup(self.delete_volume, volume['id']) - - s_name = data_utils.rand_name(self.__class__.__name__ + '-Snapshot') - # Create snapshot - snapshot = self.snapshots_client.create_snapshot( - volume_id=volume['id'], - display_name=s_name)['snapshot'] - - def delete_snapshot(snapshot_id): - waiters.wait_for_volume_resource_status(self.snapshots_client, - snapshot_id, - 'available') - # Delete snapshot - self.snapshots_client.delete_snapshot(snapshot_id) - self.snapshots_client.wait_for_resource_deletion(snapshot_id) - - self.addCleanup(delete_snapshot, snapshot['id']) - self.assertEqual(volume['id'], snapshot['volumeId']) - # Get snapshot - fetched_snapshot = self.snapshots_client.show_snapshot( - snapshot['id'])['snapshot'] - self.assertEqual(s_name, fetched_snapshot['displayName']) - self.assertEqual(volume['id'], fetched_snapshot['volumeId']) - # Fetch all snapshots - snapshots = self.snapshots_client.list_snapshots()['snapshots'] - self.assertIn(snapshot['id'], map(lambda x: x['id'], snapshots)) diff --git a/tempest/api/compute/volumes/test_volumes_get.py b/tempest/api/compute/volumes/test_volumes_get.py deleted file mode 100644 index 01cfb5f3d..000000000 --- a/tempest/api/compute/volumes/test_volumes_get.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 testtools import matchers - -from tempest.api.compute import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -CONF = config.CONF - - -class VolumesGetTestJSON(base.BaseV2ComputeTest): - - # These tests will fail with a 404 starting from microversion 2.36. For - # more information, see: - # https://developer.openstack.org/api-ref/compute/#volume-extension-os-volumes-os-snapshots-deprecated - max_microversion = '2.35' - - @classmethod - def skip_checks(cls): - super(VolumesGetTestJSON, cls).skip_checks() - if not CONF.service_available.cinder: - skip_msg = ("%s skipped as Cinder is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(VolumesGetTestJSON, cls).setup_clients() - cls.volumes_client = cls.volumes_extensions_client - - @decorators.idempotent_id('f10f25eb-9775-4d9d-9cbe-1cf54dae9d5f') - def test_volume_create_get_delete(self): - # CREATE, GET, DELETE Volume - v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume') - metadata = {'Type': 'work'} - # Create volume - volume = self.create_volume(size=CONF.volume.volume_size, - display_name=v_name, - metadata=metadata) - self.assertIn('id', volume) - self.assertIn('displayName', volume) - self.assertEqual(volume['displayName'], v_name, - "The created volume name is not equal " - "to the requested name") - self.assertIsNotNone(volume['id'], - "Field volume id is empty or not found.") - # GET Volume - fetched_volume = self.volumes_client.show_volume( - volume['id'])['volume'] - # Verification of details of fetched Volume - self.assertEqual(v_name, - fetched_volume['displayName'], - 'The fetched Volume is different ' - 'from the created Volume') - self.assertEqual(CONF.volume.volume_size, - fetched_volume['size'], - 'The fetched volume size is different ' - 'from the created Volume') - self.assertEqual(volume['id'], - fetched_volume['id'], - 'The fetched Volume is different ' - 'from the created Volume') - self.assertThat(fetched_volume['metadata'].items(), - matchers.ContainsAll(metadata.items()), - 'The fetched Volume metadata misses data ' - 'from the created Volume') diff --git a/tempest/api/compute/volumes/test_volumes_list.py b/tempest/api/compute/volumes/test_volumes_list.py deleted file mode 100644 index b2aebe79b..000000000 --- a/tempest/api/compute/volumes/test_volumes_list.py +++ /dev/null @@ -1,141 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.compute import base -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class VolumesTestJSON(base.BaseV2ComputeTest): - # NOTE: This test creates a number of 1G volumes. To run successfully, - # ensure that the backing file for the volume group that Nova uses - # has space for at least 3 1G volumes! - # If you are running a Devstack environment, ensure that the - # VOLUME_BACKING_FILE_SIZE is at least 4G in your localrc - - # These tests will fail with a 404 starting from microversion 2.36. For - # more information, see: - # https://developer.openstack.org/api-ref/compute/#volume-extension-os-volumes-os-snapshots-deprecated - max_microversion = '2.35' - - @classmethod - def skip_checks(cls): - super(VolumesTestJSON, cls).skip_checks() - if not CONF.service_available.cinder: - skip_msg = ("%s skipped as Cinder is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(VolumesTestJSON, cls).setup_clients() - cls.client = cls.volumes_extensions_client - - @classmethod - def resource_setup(cls): - super(VolumesTestJSON, cls).resource_setup() - # Create 3 Volumes - cls.volume_list = [] - for _ in range(3): - metadata = {'Type': 'work'} - volume = cls.create_volume(metadata=metadata) - volume = cls.client.show_volume(volume['id'])['volume'] - cls.volume_list.append(volume) - - @decorators.idempotent_id('bc2dd1a0-15af-48e5-9990-f2e75a48325d') - def test_volume_list(self): - # Should return the list of Volumes - # Fetch all Volumes - fetched_list = self.client.list_volumes()['volumes'] - # Now check if all the Volumes created in setup are in fetched list - missing_volumes = [ - v for v in self.volume_list if v not in fetched_list - ] - - self.assertFalse(missing_volumes, - "Failed to find volume %s in fetched list" % - ', '.join(m_vol['displayName'] - for m_vol in missing_volumes)) - - @decorators.idempotent_id('bad0567a-5a4f-420b-851e-780b55bb867c') - def test_volume_list_with_details(self): - # Should return the list of Volumes with details - # Fetch all Volumes - fetched_list = self.client.list_volumes(detail=True)['volumes'] - # Now check if all the Volumes created in setup are in fetched list - missing_volumes = [ - v for v in self.volume_list if v not in fetched_list - ] - - self.assertFalse(missing_volumes, - "Failed to find volume %s in fetched list" % - ', '.join(m_vol['displayName'] - for m_vol in missing_volumes)) - - @decorators.idempotent_id('1048ed81-2baf-487a-b284-c0622b86e7b8') - def test_volume_list_param_limit(self): - # Return the list of volumes based on limit set - params = {'limit': 2} - fetched_vol_list = self.client.list_volumes(**params)['volumes'] - - self.assertEqual(len(fetched_vol_list), params['limit'], - "Failed to list volumes by limit set") - - @decorators.idempotent_id('33985568-4965-49d5-9bcc-0aa007ca5b7a') - def test_volume_list_with_detail_param_limit(self): - # Return the list of volumes with details based on limit set. - params = {'limit': 2} - fetched_vol_list = self.client.list_volumes(detail=True, - **params)['volumes'] - - self.assertEqual(len(fetched_vol_list), params['limit'], - "Failed to list volume details by limit set") - - @decorators.idempotent_id('51c22651-a074-4ea7-af0b-094f9331303e') - def test_volume_list_param_offset_and_limit(self): - # Return the list of volumes based on offset and limit set. - # get all volumes list - all_vol_list = self.client.list_volumes()['volumes'] - params = {'offset': 1, 'limit': 1} - fetched_vol_list = self.client.list_volumes(**params)['volumes'] - - # Validating length of the fetched volumes - self.assertEqual(len(fetched_vol_list), params['limit'], - "Failed to list volumes by offset and limit") - # Validating offset of fetched volume - for index, volume in enumerate(fetched_vol_list): - self.assertEqual(volume['id'], - all_vol_list[index + params['offset']]['id'], - "Failed to list volumes by offset and limit") - - @decorators.idempotent_id('06b6abc4-3f10-48e9-a7a1-3facc98f03e5') - def test_volume_list_with_detail_param_offset_and_limit(self): - # Return the list of volumes details based on offset and limit set. - # get all volumes list - all_vol_list = self.client.list_volumes(detail=True)['volumes'] - params = {'offset': 1, 'limit': 1} - fetched_vol_list = self.client.list_volumes(detail=True, - **params)['volumes'] - - # Validating length of the fetched volumes - self.assertEqual(len(fetched_vol_list), params['limit'], - "Failed to list volume details by offset and limit") - # Validating offset of fetched volume - for index, volume in enumerate(fetched_vol_list): - self.assertEqual(volume['id'], - all_vol_list[index + params['offset']]['id'], - "Failed to list volume details by " - "offset and limit") diff --git a/tempest/api/compute/volumes/test_volumes_negative.py b/tempest/api/compute/volumes/test_volumes_negative.py deleted file mode 100644 index 87f7d8a49..000000000 --- a/tempest/api/compute/volumes/test_volumes_negative.py +++ /dev/null @@ -1,110 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.compute import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class VolumesNegativeTest(base.BaseV2ComputeTest): - - # These tests will fail with a 404 starting from microversion 2.36. For - # more information, see: - # https://developer.openstack.org/api-ref/compute/#volume-extension-os-volumes-os-snapshots-deprecated - max_microversion = '2.35' - - @classmethod - def skip_checks(cls): - super(VolumesNegativeTest, cls).skip_checks() - if not CONF.service_available.cinder: - skip_msg = ("%s skipped as Cinder is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(VolumesNegativeTest, cls).setup_clients() - cls.client = cls.volumes_extensions_client - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('c03ea686-905b-41a2-8748-9635154b7c57') - def test_volume_get_nonexistent_volume_id(self): - # Negative: Should not be able to get details of nonexistent volume - # Creating a nonexistent volume id - # Trying to GET a non existent volume - self.assertRaises(lib_exc.NotFound, self.client.show_volume, - data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('54a34226-d910-4b00-9ef8-8683e6c55846') - def test_volume_delete_nonexistent_volume_id(self): - # Negative: Should not be able to delete nonexistent Volume - # Creating nonexistent volume id - # Trying to DELETE a non existent volume - self.assertRaises(lib_exc.NotFound, self.client.delete_volume, - data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5125ae14-152b-40a7-b3c5-eae15e9022ef') - def test_create_volume_with_invalid_size(self): - # Negative: Should not be able to create volume with invalid size - # in request - v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume') - metadata = {'Type': 'work'} - self.assertRaises(lib_exc.BadRequest, self.client.create_volume, - size='#$%', display_name=v_name, metadata=metadata) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('131cb3a1-75cc-4d40-b4c3-1317f64719b0') - def test_create_volume_without_passing_size(self): - # Negative: Should not be able to create volume without passing size - # in request - v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume') - metadata = {'Type': 'work'} - self.assertRaises(lib_exc.BadRequest, self.client.create_volume, - size='', display_name=v_name, metadata=metadata) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('8cce995e-0a83-479a-b94d-e1e40b8a09d1') - def test_create_volume_with_size_zero(self): - # Negative: Should not be able to create volume with size zero - v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume') - metadata = {'Type': 'work'} - self.assertRaises(lib_exc.BadRequest, self.client.create_volume, - size='0', display_name=v_name, metadata=metadata) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('62bab09a-4c03-4617-8cca-8572bc94af9b') - def test_get_volume_without_passing_volume_id(self): - # Negative: Should not be able to get volume when empty ID is passed - self.assertRaises(lib_exc.NotFound, self.client.show_volume, '') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('62972737-124b-4513-b6cf-2f019f178494') - def test_delete_invalid_volume_id(self): - # Negative: Should not be able to delete volume when invalid ID is - # passed - self.assertRaises(lib_exc.NotFound, - self.client.delete_volume, - data_utils.rand_name('invalid')) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0d1417c5-4ae8-4c2c-adc5-5f0b864253e5') - def test_delete_volume_without_passing_volume_id(self): - # Negative: Should not be able to delete volume when empty ID is passed - self.assertRaises(lib_exc.NotFound, self.client.delete_volume, '') diff --git a/tempest/api/identity/__init__.py b/tempest/api/identity/__init__.py deleted file mode 100644 index 17efdcc37..000000000 --- a/tempest/api/identity/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_log import log as logging - -LOG = logging.getLogger(__name__) - - -# All identity tests -- single setup function -def setup_package(): - LOG.debug("Entering tempest.api.identity.setup_package") diff --git a/tempest/api/identity/admin/__init__.py b/tempest/api/identity/admin/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/identity/admin/v2/__init__.py b/tempest/api/identity/admin/v2/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/identity/admin/v2/test_endpoints.py b/tempest/api/identity/admin/v2/test_endpoints.py deleted file mode 100644 index 59fc4d8c7..000000000 --- a/tempest/api/identity/admin/v2/test_endpoints.py +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class EndPointsTestJSON(base.BaseIdentityV2AdminTest): - - @classmethod - def resource_setup(cls): - super(EndPointsTestJSON, cls).resource_setup() - cls.service_ids = list() - s_name = data_utils.rand_name('service') - s_type = data_utils.rand_name('type') - s_description = data_utils.rand_name('description') - service_data = cls.services_client.create_service( - name=s_name, type=s_type, - description=s_description)['OS-KSADM:service'] - cls.service_id = service_data['id'] - cls.service_ids.append(cls.service_id) - # Create endpoints so as to use for LIST and GET test cases - cls.setup_endpoints = list() - for _ in range(2): - region = data_utils.rand_name('region') - url = data_utils.rand_url() - endpoint = cls.endpoints_client.create_endpoint( - service_id=cls.service_id, - region=region, - publicurl=url, - adminurl=url, - internalurl=url)['endpoint'] - # list_endpoints() will return 'enabled' field - endpoint['enabled'] = True - cls.setup_endpoints.append(endpoint) - - @classmethod - def resource_cleanup(cls): - for e in cls.setup_endpoints: - cls.endpoints_client.delete_endpoint(e['id']) - for s in cls.service_ids: - cls.services_client.delete_service(s) - super(EndPointsTestJSON, cls).resource_cleanup() - - @decorators.idempotent_id('11f590eb-59d8-4067-8b2b-980c7f387f51') - def test_list_endpoints(self): - # Get a list of endpoints - fetched_endpoints = self.endpoints_client.list_endpoints()['endpoints'] - # Asserting LIST endpoints - missing_endpoints =\ - [e for e in self.setup_endpoints if e not in fetched_endpoints] - self.assertEmpty(missing_endpoints, - "Failed to find endpoint %s in fetched list" % - ', '.join(str(e) for e in missing_endpoints)) - - @decorators.idempotent_id('9974530a-aa28-4362-8403-f06db02b26c1') - def test_create_list_delete_endpoint(self): - region = data_utils.rand_name('region') - url = data_utils.rand_url() - endpoint = self.endpoints_client.create_endpoint( - service_id=self.service_id, - region=region, - publicurl=url, - adminurl=url, - internalurl=url)['endpoint'] - # Asserting Create Endpoint response body - self.assertIn('id', endpoint) - self.assertEqual(region, endpoint['region']) - self.assertEqual(url, endpoint['publicurl']) - # Checking if created endpoint is present in the list of endpoints - fetched_endpoints = self.endpoints_client.list_endpoints()['endpoints'] - fetched_endpoints_id = [e['id'] for e in fetched_endpoints] - self.assertIn(endpoint['id'], fetched_endpoints_id) - # Deleting the endpoint created in this method - self.endpoints_client.delete_endpoint(endpoint['id']) - # Checking whether endpoint is deleted successfully - fetched_endpoints = self.endpoints_client.list_endpoints()['endpoints'] - fetched_endpoints_id = [e['id'] for e in fetched_endpoints] - self.assertNotIn(endpoint['id'], fetched_endpoints_id) diff --git a/tempest/api/identity/admin/v2/test_roles.py b/tempest/api/identity/admin/v2/test_roles.py deleted file mode 100644 index 124bb5f66..000000000 --- a/tempest/api/identity/admin/v2/test_roles.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - - -class RolesTestJSON(base.BaseIdentityV2AdminTest): - - @classmethod - def resource_setup(cls): - super(RolesTestJSON, cls).resource_setup() - cls.roles = list() - for _ in range(5): - role_name = data_utils.rand_name(name='role') - role = cls.roles_client.create_role(name=role_name)['role'] - cls.roles.append(role) - - @classmethod - def resource_cleanup(cls): - super(RolesTestJSON, cls).resource_cleanup() - for role in cls.roles: - cls.roles_client.delete_role(role['id']) - - def _get_role_params(self): - user = self.setup_test_user() - tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant'] - role = self.setup_test_role() - return (user, tenant, role) - - def assert_role_in_role_list(self, role, roles): - found = False - for user_role in roles: - if user_role['id'] == role['id']: - found = True - self.assertTrue(found, "assigned role was not in list") - - @decorators.idempotent_id('75d9593f-50b7-4fcf-bd64-e3fb4a278e23') - def test_list_roles(self): - """Return a list of all roles.""" - body = self.roles_client.list_roles()['roles'] - found = [role for role in body if role in self.roles] - self.assertNotEmpty(found) - self.assertEqual(len(found), len(self.roles)) - - @decorators.idempotent_id('c62d909d-6c21-48c0-ae40-0a0760e6db5e') - def test_role_create_delete(self): - """Role should be created, verified, and deleted.""" - role_name = data_utils.rand_name(name='role-test') - body = self.roles_client.create_role(name=role_name)['role'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.roles_client.delete_role, body['id']) - self.assertEqual(role_name, body['name']) - - body = self.roles_client.list_roles()['roles'] - found = [role for role in body if role['name'] == role_name] - self.assertNotEmpty(found) - - body = self.roles_client.delete_role(found[0]['id']) - - body = self.roles_client.list_roles()['roles'] - found = [role for role in body if role['name'] == role_name] - self.assertEmpty(found) - - @decorators.idempotent_id('db6870bd-a6ed-43be-a9b1-2f10a5c9994f') - def test_get_role_by_id(self): - """Get a role by its id.""" - role = self.setup_test_role() - role_id = role['id'] - role_name = role['name'] - body = self.roles_client.show_role(role_id)['role'] - self.assertEqual(role_id, body['id']) - self.assertEqual(role_name, body['name']) - - @decorators.idempotent_id('0146f675-ffbd-4208-b3a4-60eb628dbc5e') - def test_assign_user_role(self): - """Assign a role to a user on a tenant.""" - (user, tenant, role) = self._get_role_params() - self.roles_client.create_user_role_on_project(tenant['id'], - user['id'], - role['id']) - roles = self.roles_client.list_user_roles_on_project( - tenant['id'], user['id'])['roles'] - self.assert_role_in_role_list(role, roles) - - @decorators.idempotent_id('f0b9292c-d3ba-4082-aa6c-440489beef69') - def test_remove_user_role(self): - """Remove a role assigned to a user on a tenant.""" - (user, tenant, role) = self._get_role_params() - user_role = self.roles_client.create_user_role_on_project( - tenant['id'], user['id'], role['id'])['role'] - self.roles_client.delete_role_from_user_on_project(tenant['id'], - user['id'], - user_role['id']) - - @decorators.idempotent_id('262e1e3e-ed71-4edd-a0e5-d64e83d66d05') - def test_list_user_roles(self): - """List roles assigned to a user on tenant.""" - (user, tenant, role) = self._get_role_params() - self.roles_client.create_user_role_on_project(tenant['id'], - user['id'], - role['id']) - roles = self.roles_client.list_user_roles_on_project( - tenant['id'], user['id'])['roles'] - self.assert_role_in_role_list(role, roles) diff --git a/tempest/api/identity/admin/v2/test_roles_negative.py b/tempest/api/identity/admin/v2/test_roles_negative.py deleted file mode 100644 index f3b7494c1..000000000 --- a/tempest/api/identity/admin/v2/test_roles_negative.py +++ /dev/null @@ -1,256 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD. -# 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 tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class RolesNegativeTestJSON(base.BaseIdentityV2AdminTest): - - def _get_role_params(self): - user = self.setup_test_user() - tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant'] - role = self.setup_test_role() - return (user, tenant, role) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d5d5f1df-f8ca-4de0-b2ef-259c1cc67025') - def test_list_roles_by_unauthorized_user(self): - # Non-administrator user should not be able to list roles - self.assertRaises(lib_exc.Forbidden, - self.non_admin_roles_client.list_roles) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('11a3c7da-df6c-40c2-abc2-badd682edf9f') - def test_list_roles_request_without_token(self): - # Request to list roles without a valid token should fail - token = self.client.auth_provider.get_token() - self.client.delete_token(token) - self.assertRaises(lib_exc.Unauthorized, self.roles_client.list_roles) - self.client.auth_provider.clear_auth() - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('c0b89e56-accc-4c73-85f8-9c0f866104c1') - def test_role_create_blank_name(self): - # Should not be able to create a role with a blank name - self.assertRaises(lib_exc.BadRequest, self.roles_client.create_role, - name='') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('585c8998-a8a4-4641-a5dd-abef7a8ced00') - def test_create_role_by_unauthorized_user(self): - # Non-administrator user should not be able to create role - role_name = data_utils.rand_name(name='role') - self.assertRaises(lib_exc.Forbidden, - self.non_admin_roles_client.create_role, - name=role_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a7edd17a-e34a-4aab-8bb7-fa6f498645b8') - def test_create_role_request_without_token(self): - # Request to create role without a valid token should fail - token = self.client.auth_provider.get_token() - self.client.delete_token(token) - role_name = data_utils.rand_name(name='role') - self.assertRaises(lib_exc.Unauthorized, - self.roles_client.create_role, name=role_name) - self.client.auth_provider.clear_auth() - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('c0cde2c8-81c1-4bb0-8fe2-cf615a3547a8') - def test_role_create_duplicate(self): - # Role names should be unique - role_name = data_utils.rand_name(name='role-dup') - body = self.roles_client.create_role(name=role_name)['role'] - role1_id = body.get('id') - self.addCleanup(self.roles_client.delete_role, role1_id) - self.assertRaises(lib_exc.Conflict, self.roles_client.create_role, - name=role_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('15347635-b5b1-4a87-a280-deb2bd6d865e') - def test_delete_role_by_unauthorized_user(self): - # Non-administrator user should not be able to delete role - role_name = data_utils.rand_name(name='role') - body = self.roles_client.create_role(name=role_name)['role'] - self.addCleanup(self.roles_client.delete_role, body['id']) - role_id = body.get('id') - self.assertRaises(lib_exc.Forbidden, - self.non_admin_roles_client.delete_role, role_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('44b60b20-70de-4dac-beaf-a3fc2650a16b') - def test_delete_role_request_without_token(self): - # Request to delete role without a valid token should fail - role_name = data_utils.rand_name(name='role') - body = self.roles_client.create_role(name=role_name)['role'] - self.addCleanup(self.roles_client.delete_role, body['id']) - role_id = body.get('id') - token = self.client.auth_provider.get_token() - self.client.delete_token(token) - self.assertRaises(lib_exc.Unauthorized, - self.roles_client.delete_role, - role_id) - self.client.auth_provider.clear_auth() - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('38373691-8551-453a-b074-4260ad8298ef') - def test_delete_role_non_existent(self): - # Attempt to delete a non existent role should fail - non_existent_role = data_utils.rand_uuid_hex() - self.assertRaises(lib_exc.NotFound, self.roles_client.delete_role, - non_existent_role) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('391df5cf-3ec3-46c9-bbe5-5cb58dd4dc41') - def test_assign_user_role_by_unauthorized_user(self): - # Non-administrator user should not be authorized to - # assign a role to user - (user, tenant, role) = self._get_role_params() - self.assertRaises( - lib_exc.Forbidden, - self.non_admin_roles_client.create_user_role_on_project, - tenant['id'], user['id'], role['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f0d2683c-5603-4aee-95d7-21420e87cfd8') - def test_assign_user_role_request_without_token(self): - # Request to assign a role to a user without a valid token - (user, tenant, role) = self._get_role_params() - token = self.client.auth_provider.get_token() - self.client.delete_token(token) - self.assertRaises( - lib_exc.Unauthorized, - self.roles_client.create_user_role_on_project, tenant['id'], - user['id'], role['id']) - self.client.auth_provider.clear_auth() - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('99b297f6-2b5d-47c7-97a9-8b6bb4f91042') - def test_assign_user_role_for_non_existent_role(self): - # Attempt to assign a non existent role to user should fail - (user, tenant, _) = self._get_role_params() - non_existent_role = data_utils.rand_uuid_hex() - self.assertRaises(lib_exc.NotFound, - self.roles_client.create_user_role_on_project, - tenant['id'], user['id'], non_existent_role) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('b2285aaa-9e76-4704-93a9-7a8acd0a6c8f') - def test_assign_user_role_for_non_existent_tenant(self): - # Attempt to assign a role on a non existent tenant should fail - (user, _, role) = self._get_role_params() - non_existent_tenant = data_utils.rand_uuid_hex() - self.assertRaises(lib_exc.NotFound, - self.roles_client.create_user_role_on_project, - non_existent_tenant, user['id'], role['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5c3132cd-c4c8-4402-b5ea-71eb44e97793') - def test_assign_duplicate_user_role(self): - # Duplicate user role should not get assigned - (user, tenant, role) = self._get_role_params() - self.roles_client.create_user_role_on_project(tenant['id'], - user['id'], - role['id']) - self.assertRaises(lib_exc.Conflict, - self.roles_client.create_user_role_on_project, - tenant['id'], user['id'], role['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d0537987-0977-448f-a435-904c15de7298') - def test_remove_user_role_by_unauthorized_user(self): - # Non-administrator user should not be authorized to - # remove a user's role - (user, tenant, role) = self._get_role_params() - self.roles_client.create_user_role_on_project(tenant['id'], - user['id'], - role['id']) - self.assertRaises( - lib_exc.Forbidden, - self.non_admin_roles_client.delete_role_from_user_on_project, - tenant['id'], user['id'], role['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('cac81cf4-c1d2-47dc-90d3-f2b7eb572286') - def test_remove_user_role_request_without_token(self): - # Request to remove a user's role without a valid token - (user, tenant, role) = self._get_role_params() - self.roles_client.create_user_role_on_project(tenant['id'], - user['id'], - role['id']) - token = self.client.auth_provider.get_token() - self.client.delete_token(token) - self.assertRaises(lib_exc.Unauthorized, - self.roles_client.delete_role_from_user_on_project, - tenant['id'], user['id'], role['id']) - self.client.auth_provider.clear_auth() - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ab32d759-cd16-41f1-a86e-44405fa9f6d2') - def test_remove_user_role_non_existent_role(self): - # Attempt to delete a non existent role from a user should fail - (user, tenant, role) = self._get_role_params() - self.roles_client.create_user_role_on_project(tenant['id'], - user['id'], - role['id']) - non_existent_role = data_utils.rand_uuid_hex() - self.assertRaises(lib_exc.NotFound, - self.roles_client.delete_role_from_user_on_project, - tenant['id'], user['id'], non_existent_role) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('67a679ec-03dd-4551-bbfc-d1c93284f023') - def test_remove_user_role_non_existent_tenant(self): - # Attempt to remove a role from a non existent tenant should fail - (user, tenant, role) = self._get_role_params() - self.roles_client.create_user_role_on_project(tenant['id'], - user['id'], - role['id']) - non_existent_tenant = data_utils.rand_uuid_hex() - self.assertRaises(lib_exc.NotFound, - self.roles_client.delete_role_from_user_on_project, - non_existent_tenant, user['id'], role['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7391ab4c-06f3-477a-a64a-c8e55ce89837') - def test_list_user_roles_by_unauthorized_user(self): - # Non-administrator user should not be authorized to list - # a user's roles - (user, tenant, role) = self._get_role_params() - self.roles_client.create_user_role_on_project(tenant['id'], - user['id'], - role['id']) - self.assertRaises( - lib_exc.Forbidden, - self.non_admin_roles_client.list_user_roles_on_project, - tenant['id'], user['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('682adfb2-fd5f-4b0a-a9ca-322e9bebb907') - def test_list_user_roles_request_without_token(self): - # Request to list user's roles without a valid token should fail - (user, tenant, _) = self._get_role_params() - token = self.client.auth_provider.get_token() - self.client.delete_token(token) - try: - self.assertRaises(lib_exc.Unauthorized, - self.roles_client.list_user_roles_on_project, - tenant['id'], - user['id']) - finally: - self.client.auth_provider.clear_auth() diff --git a/tempest/api/identity/admin/v2/test_services.py b/tempest/api/identity/admin/v2/test_services.py deleted file mode 100644 index 634cf21f2..000000000 --- a/tempest/api/identity/admin/v2/test_services.py +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ServicesTestJSON(base.BaseIdentityV2AdminTest): - - def _del_service(self, service_id): - # Deleting the service created in this method - self.services_client.delete_service(service_id) - # Checking whether service is deleted successfully - self.assertRaises(lib_exc.NotFound, self.services_client.show_service, - service_id) - - @decorators.idempotent_id('84521085-c6e6-491c-9a08-ec9f70f90110') - def test_create_get_delete_service(self): - # GET Service - # Creating a Service - name = data_utils.rand_name('service') - s_type = data_utils.rand_name('type') - description = data_utils.rand_name('description') - service_data = self.services_client.create_service( - name=name, type=s_type, - description=description)['OS-KSADM:service'] - self.assertIsNotNone(service_data['id']) - self.addCleanup(self._del_service, service_data['id']) - # Verifying response body of create service - self.assertIn('id', service_data) - self.assertIn('name', service_data) - self.assertEqual(name, service_data['name']) - self.assertIn('type', service_data) - self.assertEqual(s_type, service_data['type']) - self.assertIn('description', service_data) - self.assertEqual(description, service_data['description']) - # Get service - fetched_service = ( - self.services_client.show_service(service_data['id']) - ['OS-KSADM:service']) - # verifying the existence of service created - self.assertIn('id', fetched_service) - self.assertEqual(fetched_service['id'], service_data['id']) - self.assertIn('name', fetched_service) - self.assertEqual(fetched_service['name'], service_data['name']) - self.assertIn('type', fetched_service) - self.assertEqual(fetched_service['type'], service_data['type']) - self.assertIn('description', fetched_service) - self.assertEqual(fetched_service['description'], - service_data['description']) - - @decorators.idempotent_id('5d3252c8-e555-494b-a6c8-e11d7335da42') - def test_create_service_without_description(self): - # Create a service only with name and type - name = data_utils.rand_name('service') - s_type = data_utils.rand_name('type') - service = self.services_client.create_service( - name=name, type=s_type)['OS-KSADM:service'] - self.assertIn('id', service) - self.addCleanup(self._del_service, service['id']) - self.assertIn('name', service) - self.assertEqual(name, service['name']) - self.assertIn('type', service) - self.assertEqual(s_type, service['type']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('34ea6489-012d-4a86-9038-1287cadd5eca') - def test_list_services(self): - # Create, List, Verify and Delete Services - services = [] - for _ in range(3): - name = data_utils.rand_name('service') - s_type = data_utils.rand_name('type') - description = data_utils.rand_name('description') - - service = self.services_client.create_service( - name=name, type=s_type, - description=description)['OS-KSADM:service'] - services.append(service) - service_ids = [svc['id'] for svc in services] - - def delete_services(): - for service_id in service_ids: - self.services_client.delete_service(service_id) - - self.addCleanup(delete_services) - # List and Verify Services - body = self.services_client.list_services()['OS-KSADM:services'] - found = [serv for serv in body if serv['id'] in service_ids] - self.assertEqual(len(found), len(services), 'Services not found') diff --git a/tempest/api/identity/admin/v2/test_tenant_negative.py b/tempest/api/identity/admin/v2/test_tenant_negative.py deleted file mode 100644 index 49bb949cf..000000000 --- a/tempest/api/identity/admin/v2/test_tenant_negative.py +++ /dev/null @@ -1,142 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD. -# 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 tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class TenantsNegativeTestJSON(base.BaseIdentityV2AdminTest): - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ca9bb202-63dd-4240-8a07-8ef9c19c04bb') - def test_list_tenants_by_unauthorized_user(self): - # Non-administrator user should not be able to list tenants - self.assertRaises(lib_exc.Forbidden, - self.non_admin_tenants_client.list_tenants) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('df33926c-1c96-4d8d-a762-79cc6b0c3cf4') - def test_list_tenant_request_without_token(self): - # Request to list tenants without a valid token should fail - token = self.client.auth_provider.get_token() - self.client.delete_token(token) - self.assertRaises(lib_exc.Unauthorized, - self.tenants_client.list_tenants) - self.client.auth_provider.clear_auth() - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('162ba316-f18b-4987-8c0c-fd9140cd63ed') - def test_tenant_delete_by_unauthorized_user(self): - # Non-administrator user should not be able to delete a tenant - tenant = self.setup_test_tenant() - self.assertRaises(lib_exc.Forbidden, - self.non_admin_tenants_client.delete_tenant, - tenant['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e450db62-2e9d-418f-893a-54772d6386b1') - def test_tenant_delete_request_without_token(self): - # Request to delete a tenant without a valid token should fail - tenant = self.setup_test_tenant() - token = self.client.auth_provider.get_token() - self.client.delete_token(token) - self.assertRaises(lib_exc.Unauthorized, - self.tenants_client.delete_tenant, - tenant['id']) - self.client.auth_provider.clear_auth() - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9c9a2aed-6e3c-467a-8f5c-89da9d1b516b') - def test_delete_non_existent_tenant(self): - # Attempt to delete a non existent tenant should fail - self.assertRaises(lib_exc.NotFound, self.tenants_client.delete_tenant, - data_utils.rand_uuid_hex()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('af16f44b-a849-46cb-9f13-a751c388f739') - def test_tenant_create_duplicate(self): - # Tenant names should be unique - tenant_name = data_utils.rand_name(name='tenant') - self.setup_test_tenant(name=tenant_name) - self.assertRaises(lib_exc.Conflict, self.tenants_client.create_tenant, - name=tenant_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d26b278a-6389-4702-8d6e-5980d80137e0') - def test_create_tenant_by_unauthorized_user(self): - # Non-administrator user should not be authorized to create a tenant - tenant_name = data_utils.rand_name(name='tenant') - self.assertRaises(lib_exc.Forbidden, - self.non_admin_tenants_client.create_tenant, - name=tenant_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a3ee9d7e-6920-4dd5-9321-d4b2b7f0a638') - def test_create_tenant_request_without_token(self): - # Create tenant request without a token should not be authorized - tenant_name = data_utils.rand_name(name='tenant') - token = self.client.auth_provider.get_token() - self.client.delete_token(token) - self.assertRaises(lib_exc.Unauthorized, - self.tenants_client.create_tenant, - name=tenant_name) - self.client.auth_provider.clear_auth() - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5a2e4ca9-b0c0-486c-9c48-64a94fba2395') - def test_create_tenant_with_empty_name(self): - # Tenant name should not be empty - self.assertRaises(lib_exc.BadRequest, - self.tenants_client.create_tenant, - name='') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('2ff18d1e-dfe3-4359-9dc3-abf582c196b9') - def test_create_tenants_name_length_over_64(self): - # Tenant name length should not be greater than 64 characters - tenant_name = 'a' * 65 - self.assertRaises(lib_exc.BadRequest, - self.tenants_client.create_tenant, - name=tenant_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('bd20dc2a-9557-4db7-b755-f48d952ad706') - def test_update_non_existent_tenant(self): - # Attempt to update a non existent tenant should fail - self.assertRaises(lib_exc.NotFound, self.tenants_client.update_tenant, - data_utils.rand_uuid_hex()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('41704dc5-c5f7-4f79-abfa-76e6fedc570b') - def test_tenant_update_by_unauthorized_user(self): - # Non-administrator user should not be able to update a tenant - tenant = self.setup_test_tenant() - self.assertRaises(lib_exc.Forbidden, - self.non_admin_tenants_client.update_tenant, - tenant['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7a421573-72c7-4c22-a98e-ce539219c657') - def test_tenant_update_request_without_token(self): - # Request to update a tenant without a valid token should fail - tenant = self.setup_test_tenant() - token = self.client.auth_provider.get_token() - self.client.delete_token(token) - self.assertRaises(lib_exc.Unauthorized, - self.tenants_client.update_tenant, - tenant['id']) - self.client.auth_provider.clear_auth() diff --git a/tempest/api/identity/admin/v2/test_tenants.py b/tempest/api/identity/admin/v2/test_tenants.py deleted file mode 100644 index 0f955bf8f..000000000 --- a/tempest/api/identity/admin/v2/test_tenants.py +++ /dev/null @@ -1,149 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class TenantsTestJSON(base.BaseIdentityV2AdminTest): - - @decorators.idempotent_id('16c6e05c-6112-4b0e-b83f-5e43f221b6b0') - def test_tenant_list_delete(self): - # Create several tenants and delete them - tenants = [] - for _ in range(3): - tenant = self.setup_test_tenant() - tenants.append(tenant) - tenant_ids = [tn['id'] for tn in tenants] - body = self.tenants_client.list_tenants()['tenants'] - found = [t for t in body if t['id'] in tenant_ids] - self.assertEqual(len(found), len(tenants), 'Tenants not created') - - for tenant in tenants: - self.tenants_client.delete_tenant(tenant['id']) - - body = self.tenants_client.list_tenants()['tenants'] - found = [tenant for tenant in body if tenant['id'] in tenant_ids] - self.assertEmpty(found, 'Tenants failed to delete') - - @decorators.idempotent_id('d25e9f24-1310-4d29-b61b-d91299c21d6d') - def test_tenant_create_with_description(self): - # Create tenant with a description - tenant_desc = data_utils.rand_name(name='desc') - tenant = self.setup_test_tenant(description=tenant_desc) - tenant_id = tenant['id'] - desc1 = tenant['description'] - self.assertEqual(desc1, tenant_desc, 'Description should have ' - 'been sent in response for create') - body = self.tenants_client.show_tenant(tenant_id)['tenant'] - desc2 = body['description'] - self.assertEqual(desc2, tenant_desc, 'Description does not appear' - 'to be set') - self.tenants_client.delete_tenant(tenant_id) - - @decorators.idempotent_id('670bdddc-1cd7-41c7-b8e2-751cfb67df50') - def test_tenant_create_enabled(self): - # Create a tenant that is enabled - tenant = self.setup_test_tenant(enabled=True) - tenant_id = tenant['id'] - en1 = tenant['enabled'] - self.assertTrue(en1, 'Enable should be True in response') - body = self.tenants_client.show_tenant(tenant_id)['tenant'] - en2 = body['enabled'] - self.assertTrue(en2, 'Enable should be True in lookup') - self.tenants_client.delete_tenant(tenant_id) - - @decorators.idempotent_id('3be22093-b30f-499d-b772-38340e5e16fb') - def test_tenant_create_not_enabled(self): - # Create a tenant that is not enabled - tenant = self.setup_test_tenant(enabled=False) - tenant_id = tenant['id'] - en1 = tenant['enabled'] - self.assertEqual('false', str(en1).lower(), - 'Enable should be False in response') - body = self.tenants_client.show_tenant(tenant_id)['tenant'] - en2 = body['enabled'] - self.assertEqual('false', str(en2).lower(), - 'Enable should be False in lookup') - self.tenants_client.delete_tenant(tenant_id) - - @decorators.idempotent_id('781f2266-d128-47f3-8bdb-f70970add238') - def test_tenant_update_name(self): - # Update name attribute of a tenant - t_name1 = data_utils.rand_name(name='tenant') - tenant = self.setup_test_tenant(name=t_name1) - t_id = tenant['id'] - resp1_name = tenant['name'] - - t_name2 = data_utils.rand_name(name='tenant2') - body = self.tenants_client.update_tenant(t_id, name=t_name2)['tenant'] - resp2_name = body['name'] - self.assertNotEqual(resp1_name, resp2_name) - - body = self.tenants_client.show_tenant(t_id)['tenant'] - resp3_name = body['name'] - - self.assertNotEqual(resp1_name, resp3_name) - self.assertEqual(t_name1, resp1_name) - self.assertEqual(resp2_name, resp3_name) - - self.tenants_client.delete_tenant(t_id) - - @decorators.idempotent_id('859fcfe1-3a03-41ef-86f9-b19a47d1cd87') - def test_tenant_update_desc(self): - # Update description attribute of a tenant - t_desc = data_utils.rand_name(name='desc') - tenant = self.setup_test_tenant(description=t_desc) - t_id = tenant['id'] - resp1_desc = tenant['description'] - - t_desc2 = data_utils.rand_name(name='desc2') - body = self.tenants_client.update_tenant(t_id, description=t_desc2) - updated_tenant = body['tenant'] - resp2_desc = updated_tenant['description'] - self.assertNotEqual(resp1_desc, resp2_desc) - - body = self.tenants_client.show_tenant(t_id)['tenant'] - resp3_desc = body['description'] - - self.assertNotEqual(resp1_desc, resp3_desc) - self.assertEqual(t_desc, resp1_desc) - self.assertEqual(resp2_desc, resp3_desc) - - self.tenants_client.delete_tenant(t_id) - - @decorators.idempotent_id('8fc8981f-f12d-4c66-9972-2bdcf2bc2e1a') - def test_tenant_update_enable(self): - # Update the enabled attribute of a tenant - t_en = False - tenant = self.setup_test_tenant(enabled=t_en) - t_id = tenant['id'] - resp1_en = tenant['enabled'] - - t_en2 = True - body = self.tenants_client.update_tenant(t_id, enabled=t_en2) - updated_tenant = body['tenant'] - resp2_en = updated_tenant['enabled'] - self.assertNotEqual(resp1_en, resp2_en) - - body = self.tenants_client.show_tenant(t_id)['tenant'] - resp3_en = body['enabled'] - - self.assertNotEqual(resp1_en, resp3_en) - self.assertEqual('false', str(resp1_en).lower()) - self.assertEqual(resp2_en, resp3_en) - - self.tenants_client.delete_tenant(t_id) diff --git a/tempest/api/identity/admin/v2/test_tokens.py b/tempest/api/identity/admin/v2/test_tokens.py deleted file mode 100644 index 6b30d23cc..000000000 --- a/tempest/api/identity/admin/v2/test_tokens.py +++ /dev/null @@ -1,133 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD. -# 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 tempest.api.identity import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class TokensTestJSON(base.BaseIdentityV2AdminTest): - - @decorators.idempotent_id('453ad4d5-e486-4b2f-be72-cffc8149e586') - def test_create_check_get_delete_token(self): - # get a token by username and password - user_name = data_utils.rand_name(name='user') - user_password = data_utils.rand_password() - # first:create a tenant - tenant = self.setup_test_tenant() - # second:create a user - user = self.create_test_user(name=user_name, - password=user_password, - tenantId=tenant['id'], - email='') - # then get a token for the user - body = self.token_client.auth(user_name, - user_password, - tenant['name']) - self.assertEqual(body['token']['tenant']['name'], - tenant['name']) - # Perform GET Token - token_id = body['token']['id'] - self.client.check_token_existence(token_id) - token_details = self.client.show_token(token_id)['access'] - self.assertEqual(token_id, token_details['token']['id']) - self.assertEqual(user['id'], token_details['user']['id']) - self.assertEqual(user_name, token_details['user']['name']) - self.assertEqual(tenant['name'], - token_details['token']['tenant']['name']) - # then delete the token - self.client.delete_token(token_id) - self.assertRaises(lib_exc.NotFound, - self.client.check_token_existence, - token_id) - - @decorators.idempotent_id('25ba82ee-8a32-4ceb-8f50-8b8c71e8765e') - def test_rescope_token(self): - """An unscoped token can be requested - - That token can be used to request a scoped token. - """ - - # Create a user. - user_name = data_utils.rand_name(name='user') - user_password = data_utils.rand_password() - tenant_id = None # No default tenant so will get unscoped token. - user = self.create_test_user(name=user_name, - password=user_password, - tenantId=tenant_id, - email='') - - # Create a couple tenants. - tenant1_name = data_utils.rand_name(name='tenant') - tenant1 = self.setup_test_tenant(name=tenant1_name) - - tenant2_name = data_utils.rand_name(name='tenant') - tenant2 = self.setup_test_tenant(name=tenant2_name) - - # Create a role - role = self.setup_test_role() - - # Grant the user the role on the tenants. - self.roles_client.create_user_role_on_project(tenant1['id'], - user['id'], - role['id']) - - self.roles_client.create_user_role_on_project(tenant2['id'], - user['id'], - role['id']) - - # Get an unscoped token. - body = self.token_client.auth(user_name, user_password) - - token_id = body['token']['id'] - - # Use the unscoped token to get a token scoped to tenant1 - body = self.token_client.auth_token(token_id, - tenant=tenant1_name) - - scoped_token_id = body['token']['id'] - - # Revoke the scoped token - self.client.delete_token(scoped_token_id) - - # Use the unscoped token to get a token scoped to tenant2 - body = self.token_client.auth_token(token_id, - tenant=tenant2_name) - - @decorators.idempotent_id('ca3ea6f7-ed08-4a61-adbd-96906456ad31') - def test_list_endpoints_for_token(self): - # get a token for the user - creds = self.os_primary.credentials - username = creds.username - password = creds.password - tenant_name = creds.tenant_name - token = self.token_client.auth(username, - password, - tenant_name)['token'] - endpoints = self.client.list_endpoints_for_token( - token['id'])['endpoints'] - self.assertIsInstance(endpoints, list) - # Store list of service names - service_names = [e['name'] for e in endpoints] - # Get the list of available services. - available_services = [s[0] for s in list( - CONF.service_available.items()) if s[1] is True] - # Verify that all available services are present. - for service in available_services: - self.assertIn(service, service_names) diff --git a/tempest/api/identity/admin/v2/test_tokens_negative.py b/tempest/api/identity/admin/v2/test_tokens_negative.py deleted file mode 100644 index eb3e365ec..000000000 --- a/tempest/api/identity/admin/v2/test_tokens_negative.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2017 AT&T Corporation -# 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 tempest.api.identity import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class TokensAdminTestNegative(base.BaseIdentityV2AdminTest): - - credentials = ['primary', 'admin', 'alt'] - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a0a0a600-4292-4364-99c5-922c834fdf05') - def test_check_token_existence_negative(self): - creds = self.os_primary.credentials - creds_alt = self.os_alt.credentials - username = creds.username - password = creds.password - tenant_name = creds.tenant_name - alt_tenant_name = creds_alt.tenant_name - body = self.token_client.auth(username, password, tenant_name) - self.assertRaises(lib_exc.Unauthorized, - self.client.check_token_existence, - body['token']['id'], - belongsTo=alt_tenant_name) diff --git a/tempest/api/identity/admin/v2/test_users.py b/tempest/api/identity/admin/v2/test_users.py deleted file mode 100644 index 0d98af5fa..000000000 --- a/tempest/api/identity/admin/v2/test_users.py +++ /dev/null @@ -1,193 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 time - -from testtools import matchers - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class UsersTestJSON(base.BaseIdentityV2AdminTest): - - @classmethod - def resource_setup(cls): - super(UsersTestJSON, cls).resource_setup() - cls.alt_user = data_utils.rand_name('test_user') - cls.alt_email = cls.alt_user + '@testmail.tm' - - @decorators.attr(type='smoke') - @decorators.idempotent_id('2d55a71e-da1d-4b43-9c03-d269fd93d905') - def test_create_user(self): - # Create a user - tenant = self.setup_test_tenant() - user = self.create_test_user(name=self.alt_user, tenantId=tenant['id']) - self.assertEqual(self.alt_user, user['name']) - - @decorators.idempotent_id('89d9fdb8-15c2-4304-a429-48715d0af33d') - def test_create_user_with_enabled(self): - # Create a user with enabled : False - tenant = self.setup_test_tenant() - name = data_utils.rand_name('test_user') - user = self.create_test_user(name=name, - tenantId=tenant['id'], - email=self.alt_email, - enabled=False) - self.assertEqual(name, user['name']) - self.assertEqual(False, user['enabled']) - self.assertEqual(self.alt_email, user['email']) - - @decorators.idempotent_id('39d05857-e8a5-4ed4-ba83-0b52d3ab97ee') - def test_update_user(self): - # Test case to check if updating of user attributes is successful. - tenant = self.setup_test_tenant() - user = self.create_test_user(tenantId=tenant['id']) - - # Updating user details with new values - u_name2 = data_utils.rand_name('user2') - u_email2 = u_name2 + '@testmail.tm' - update_user = self.users_client.update_user(user['id'], name=u_name2, - email=u_email2, - enabled=False)['user'] - self.assertEqual(u_name2, update_user['name']) - self.assertEqual(u_email2, update_user['email']) - self.assertEqual(False, update_user['enabled']) - # GET by id after updating - updated_user = self.users_client.show_user(user['id'])['user'] - # Assert response body of GET after updating - self.assertEqual(u_name2, updated_user['name']) - self.assertEqual(u_email2, updated_user['email']) - self.assertEqual(False, update_user['enabled']) - - @decorators.idempotent_id('29ed26f4-a74e-4425-9a85-fdb49fa269d2') - def test_delete_user(self): - # Delete a user - tenant = self.setup_test_tenant() - user = self.create_test_user(tenantId=tenant['id']) - self.users_client.delete_user(user['id']) - - @decorators.idempotent_id('aca696c3-d645-4f45-b728-63646045beb1') - def test_user_authentication(self): - # Valid user's token is authenticated - password = data_utils.rand_password() - user = self.setup_test_user(password) - tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant'] - # Get a token - self.token_client.auth(user['name'], - password, - tenant['name']) - # Re-auth - self.token_client.auth(user['name'], - password, - tenant['name']) - - @decorators.idempotent_id('5d1fa498-4c2d-4732-a8fe-2b054598cfdd') - def test_authentication_request_without_token(self): - # Request for token authentication with a valid token in header - password = data_utils.rand_password() - user = self.setup_test_user(password) - tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant'] - self.token_client.auth(user['name'], - password, - tenant['name']) - # Get the token of the current client - token = self.client.auth_provider.get_token() - # Delete the token from database - self.client.delete_token(token) - # Re-auth - self.token_client.auth(user['name'], - password, - tenant['name']) - self.client.auth_provider.clear_auth() - - @decorators.idempotent_id('a149c02e-e5e0-4b89-809e-7e8faf33ccda') - def test_get_users(self): - # Get a list of users and find the test user - user = self.setup_test_user() - users = self.users_client.list_users()['users'] - self.assertThat([u['name'] for u in users], - matchers.Contains(user['name']), - "Could not find %s" % user['name']) - - @decorators.idempotent_id('6e317209-383a-4bed-9f10-075b7c82c79a') - def test_list_users_for_tenant(self): - # Return a list of all users for a tenant - tenant = self.setup_test_tenant() - user_ids = list() - fetched_user_ids = list() - user1 = self.create_test_user(tenantId=tenant['id']) - user_ids.append(user1['id']) - user2 = self.create_test_user(tenantId=tenant['id']) - user_ids.append(user2['id']) - # List of users for the respective tenant ID - body = (self.tenants_client.list_tenant_users(tenant['id']) - ['users']) - for i in body: - fetched_user_ids.append(i['id']) - # verifying the user Id in the list - missing_users =\ - [user for user in user_ids if user not in fetched_user_ids] - self.assertEmpty(missing_users, - "Failed to find user %s in fetched list" % - ', '.join(m_user for m_user in missing_users)) - - @decorators.idempotent_id('a8b54974-40e1-41c0-b812-50fc90827971') - def test_list_users_with_roles_for_tenant(self): - # Return list of users on tenant when roles are assigned to users - user = self.setup_test_user() - tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant'] - role = self.setup_test_role() - # Assigning roles to two users - user_ids = list() - fetched_user_ids = list() - user_ids.append(user['id']) - role = self.roles_client.create_user_role_on_project( - tenant['id'], user['id'], role['id'])['role'] - - second_user = self.create_test_user(tenantId=tenant['id']) - user_ids.append(second_user['id']) - role = self.roles_client.create_user_role_on_project( - tenant['id'], second_user['id'], role['id'])['role'] - # List of users with roles for the respective tenant ID - body = (self.tenants_client.list_tenant_users(tenant['id'])['users']) - for i in body: - fetched_user_ids.append(i['id']) - # verifying the user Id in the list - missing_users = [missing_user for missing_user in user_ids - if missing_user not in fetched_user_ids] - self.assertEmpty(missing_users, - "Failed to find user %s in fetched list" % - ', '.join(m_user for m_user in missing_users)) - - @decorators.idempotent_id('1aeb25ac-6ec5-4d8b-97cb-7ac3567a989f') - def test_update_user_password(self): - # Test case to check if updating of user password is successful. - user = self.setup_test_user() - tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant'] - # Updating the user with new password - new_pass = data_utils.rand_password() - update_user = self.users_client.update_user_password( - user['id'], password=new_pass)['user'] - self.assertEqual(update_user['id'], user['id']) - # NOTE(morganfainberg): Fernet tokens are not subsecond aware and - # Keystone should only be precise to the second. Sleep to ensure - # we are passing the second boundary. - time.sleep(1) - # Validate the updated password through getting a token. - body = self.token_client.auth(user['name'], new_pass, - tenant['name']) - self.assertIn('id', body['token']) diff --git a/tempest/api/identity/admin/v2/test_users_negative.py b/tempest/api/identity/admin/v2/test_users_negative.py deleted file mode 100644 index 4f47e41d8..000000000 --- a/tempest/api/identity/admin/v2/test_users_negative.py +++ /dev/null @@ -1,268 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class UsersNegativeTestJSON(base.BaseIdentityV2AdminTest): - - @classmethod - def resource_setup(cls): - super(UsersNegativeTestJSON, cls).resource_setup() - cls.alt_user = data_utils.rand_name('test_user') - cls.alt_password = data_utils.rand_password() - cls.alt_email = cls.alt_user + '@testmail.tm' - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('60a1f5fa-5744-4cdf-82bf-60b7de2d29a4') - def test_create_user_by_unauthorized_user(self): - # Non-administrator should not be authorized to create a user - tenant = self.setup_test_tenant() - self.assertRaises(lib_exc.Forbidden, - self.non_admin_users_client.create_user, - name=self.alt_user, password=self.alt_password, - tenantId=tenant['id'], - email=self.alt_email) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d80d0c2f-4514-4d1e-806d-0930dfc5a187') - def test_create_user_with_empty_name(self): - # User with an empty name should not be created - tenant = self.setup_test_tenant() - self.assertRaises(lib_exc.BadRequest, self.users_client.create_user, - name='', password=self.alt_password, - tenantId=tenant['id'], - email=self.alt_email) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7704b4f3-3b75-4b82-87cc-931d41c8f780') - def test_create_user_with_name_length_over_255(self): - # Length of user name filed should be restricted to 255 characters - tenant = self.setup_test_tenant() - self.assertRaises(lib_exc.BadRequest, self.users_client.create_user, - name='a' * 256, password=self.alt_password, - tenantId=tenant['id'], - email=self.alt_email) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('57ae8558-120c-4723-9308-3751474e7ecf') - def test_create_user_with_duplicate_name(self): - # Duplicate user should not be created - password = data_utils.rand_password() - user = self.setup_test_user(password) - tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant'] - self.assertRaises(lib_exc.Conflict, self.users_client.create_user, - name=user['name'], - password=password, - tenantId=tenant['id'], - email=user['email']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0132cc22-7c4f-42e1-9e50-ac6aad31d59a') - def test_create_user_for_non_existent_tenant(self): - # Attempt to create a user in a non-existent tenant should fail - self.assertRaises(lib_exc.NotFound, self.users_client.create_user, - name=self.alt_user, - password=self.alt_password, - tenantId='49ffgg99999', - email=self.alt_email) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('55bbb103-d1ae-437b-989b-bcdf8175c1f4') - def test_create_user_request_without_a_token(self): - # Request to create a user without a valid token should fail - tenant = self.setup_test_tenant() - # Get the token of the current client - token = self.client.auth_provider.get_token() - # Delete the token from database - self.client.delete_token(token) - - # Unset the token to allow further tests to generate a new token - self.addCleanup(self.client.auth_provider.clear_auth) - - self.assertRaises(lib_exc.Unauthorized, self.users_client.create_user, - name=self.alt_user, password=self.alt_password, - tenantId=tenant['id'], - email=self.alt_email) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('23a2f3da-4a1a-41da-abdd-632328a861ad') - def test_create_user_with_enabled_non_bool(self): - # Attempt to create a user with valid enabled para should fail - tenant = self.setup_test_tenant() - name = data_utils.rand_name('test_user') - self.assertRaises(lib_exc.BadRequest, self.users_client.create_user, - name=name, password=self.alt_password, - tenantId=tenant['id'], - email=self.alt_email, enabled=3) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('3d07e294-27a0-4144-b780-a2a1bf6fee19') - def test_update_user_for_non_existent_user(self): - # Attempt to update a user non-existent user should fail - user_name = data_utils.rand_name('user') - non_existent_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.users_client.update_user, - non_existent_id, name=user_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('3cc2a64b-83aa-4b02-88f0-d6ab737c4466') - def test_update_user_request_without_a_token(self): - # Request to update a user without a valid token should fail - - # Get the token of the current client - token = self.client.auth_provider.get_token() - # Delete the token from database - self.client.delete_token(token) - - # Unset the token to allow further tests to generate a new token - self.addCleanup(self.client.auth_provider.clear_auth) - - self.assertRaises(lib_exc.Unauthorized, self.users_client.update_user, - self.alt_user) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('424868d5-18a7-43e1-8903-a64f95ee3aac') - def test_update_user_by_unauthorized_user(self): - # Non-administrator should not be authorized to update user - self.assertRaises(lib_exc.Forbidden, - self.non_admin_users_client.update_user, - self.alt_user) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d45195d5-33ed-41b9-a452-7d0d6a00f6e9') - def test_delete_users_by_unauthorized_user(self): - # Non-administrator user should not be authorized to delete a user - user = self.setup_test_user() - self.assertRaises(lib_exc.Forbidden, - self.non_admin_users_client.delete_user, - user['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7cc82f7e-9998-4f89-abae-23df36495867') - def test_delete_non_existent_user(self): - # Attempt to delete a non-existent user should fail - self.assertRaises(lib_exc.NotFound, self.users_client.delete_user, - 'junk12345123') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('57fe1df8-0aa7-46c0-ae9f-c2e785c7504a') - def test_delete_user_request_without_a_token(self): - # Request to delete a user without a valid token should fail - - # Get the token of the current client - token = self.client.auth_provider.get_token() - # Delete the token from database - self.client.delete_token(token) - - # Unset the token to allow further tests to generate a new token - self.addCleanup(self.client.auth_provider.clear_auth) - - self.assertRaises(lib_exc.Unauthorized, self.users_client.delete_user, - self.alt_user) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('593a4981-f6d4-460a-99a1-57a78bf20829') - def test_authentication_for_disabled_user(self): - # Disabled user's token should not get authenticated - password = data_utils.rand_password() - user = self.setup_test_user(password) - tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant'] - self.disable_user(user['name']) - self.assertRaises(lib_exc.Unauthorized, self.token_client.auth, - user['name'], - password, - tenant['name']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('440a7a8d-9328-4b7b-83e0-d717010495e4') - def test_authentication_when_tenant_is_disabled(self): - # User's token for a disabled tenant should not be authenticated - password = data_utils.rand_password() - user = self.setup_test_user(password) - tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant'] - self.disable_tenant(tenant['name']) - self.assertRaises(lib_exc.Unauthorized, self.token_client.auth, - user['name'], - password, - tenant['name']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('921f1ad6-7907-40b8-853f-637e7ee52178') - def test_authentication_with_invalid_tenant(self): - # User's token for an invalid tenant should not be authenticated - password = data_utils.rand_password() - user = self.setup_test_user(password) - self.assertRaises(lib_exc.Unauthorized, self.token_client.auth, - user['name'], - password, - 'junktenant1234') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('bde9aecd-3b1c-4079-858f-beb5deaa5b5e') - def test_authentication_with_invalid_username(self): - # Non-existent user's token should not get authenticated - password = data_utils.rand_password() - user = self.setup_test_user(password) - tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant'] - self.assertRaises(lib_exc.Unauthorized, self.token_client.auth, - 'junkuser123', password, tenant['name']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d5308b33-3574-43c3-8d87-1c090c5e1eca') - def test_authentication_with_invalid_password(self): - # User's token with invalid password should not be authenticated - user = self.setup_test_user() - tenant = self.tenants_client.show_tenant(user['tenantId'])['tenant'] - self.assertRaises(lib_exc.Unauthorized, self.token_client.auth, - user['name'], 'junkpass1234', tenant['name']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('284192ce-fb7c-4909-a63b-9a502e0ddd11') - def test_get_users_by_unauthorized_user(self): - # Non-administrator user should not be authorized to get user list - self.assertRaises(lib_exc.Forbidden, - self.non_admin_users_client.list_users) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a73591ec-1903-4ffe-be42-282b39fefc9d') - def test_get_users_request_without_token(self): - # Request to get list of users without a valid token should fail - token = self.client.auth_provider.get_token() - self.client.delete_token(token) - - # Unset the token to allow further tests to generate a new token - self.addCleanup(self.client.auth_provider.clear_auth) - - self.assertRaises(lib_exc.Unauthorized, self.users_client.list_users) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f5d39046-fc5f-425c-b29e-bac2632da28e') - def test_list_users_with_invalid_tenant(self): - # Should not be able to return a list of all - # users for a non-existent tenant - # Assign invalid tenant ids - invalid_id = list() - invalid_id.append(data_utils.rand_name('999')) - invalid_id.append('alpha') - invalid_id.append(data_utils.rand_name("dddd@#%%^$")) - invalid_id.append('!@#()$%^&*?<>{}[]') - # List the users with invalid tenant id - for invalid in invalid_id: - self.assertRaises(lib_exc.NotFound, - self.tenants_client.list_tenant_users, invalid) diff --git a/tempest/api/identity/admin/v3/__init__.py b/tempest/api/identity/admin/v3/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/identity/admin/v3/test_credentials.py b/tempest/api/identity/admin/v3/test_credentials.py deleted file mode 100644 index 15b20081e..000000000 --- a/tempest/api/identity/admin/v3/test_credentials.py +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class CredentialsTestJSON(base.BaseIdentityV3AdminTest): - - @classmethod - def resource_setup(cls): - super(CredentialsTestJSON, cls).resource_setup() - cls.projects = list() - cls.creds_list = [['project_id', 'user_id', 'id'], - ['access', 'secret']] - u_name = data_utils.rand_name('user') - u_desc = '%s description' % u_name - u_email = '%s@testmail.tm' % u_name - u_password = data_utils.rand_password() - for _ in range(2): - cls.project = cls.projects_client.create_project( - data_utils.rand_name('project'), - description=data_utils.rand_name('project-desc'))['project'] - cls.projects.append(cls.project['id']) - - cls.user_body = cls.users_client.create_user( - name=u_name, description=u_desc, password=u_password, - email=u_email, project_id=cls.projects[0])['user'] - - @classmethod - def resource_cleanup(cls): - cls.users_client.delete_user(cls.user_body['id']) - for p in cls.projects: - cls.projects_client.delete_project(p) - super(CredentialsTestJSON, cls).resource_cleanup() - - def _delete_credential(self, cred_id): - self.creds_client.delete_credential(cred_id) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('7cd59bf9-bda4-4c72-9467-d21cab278355') - def test_credentials_create_get_update_delete(self): - blob = '{"access": "%s", "secret": "%s"}' % ( - data_utils.rand_name('Access'), data_utils.rand_name('Secret')) - cred = self.creds_client.create_credential( - user_id=self.user_body['id'], project_id=self.projects[0], - blob=blob, type='ec2')['credential'] - self.addCleanup(self._delete_credential, cred['id']) - for value1 in self.creds_list[0]: - self.assertIn(value1, cred) - for value2 in self.creds_list[1]: - self.assertIn(value2, cred['blob']) - - new_keys = [data_utils.rand_name('NewAccess'), - data_utils.rand_name('NewSecret')] - blob = '{"access": "%s", "secret": "%s"}' % (new_keys[0], new_keys[1]) - update_body = self.creds_client.update_credential( - cred['id'], blob=blob, project_id=self.projects[1], - type='ec2')['credential'] - update_body['blob'] = json.loads(update_body['blob']) - self.assertEqual(cred['id'], update_body['id']) - self.assertEqual(self.projects[1], update_body['project_id']) - self.assertEqual(self.user_body['id'], update_body['user_id']) - self.assertEqual(update_body['blob']['access'], new_keys[0]) - self.assertEqual(update_body['blob']['secret'], new_keys[1]) - - get_body = self.creds_client.show_credential(cred['id'])['credential'] - get_body['blob'] = json.loads(get_body['blob']) - for value1 in self.creds_list[0]: - self.assertEqual(update_body[value1], - get_body[value1]) - for value2 in self.creds_list[1]: - self.assertEqual(update_body['blob'][value2], - get_body['blob'][value2]) - - @decorators.idempotent_id('13202c00-0021-42a1-88d4-81b44d448aab') - def test_credentials_list_delete(self): - created_cred_ids = list() - fetched_cred_ids = list() - - for _ in range(2): - blob = '{"access": "%s", "secret": "%s"}' % ( - data_utils.rand_name('Access'), data_utils.rand_name('Secret')) - cred = self.creds_client.create_credential( - user_id=self.user_body['id'], project_id=self.projects[0], - blob=blob, type='ec2')['credential'] - created_cred_ids.append(cred['id']) - self.addCleanup(self._delete_credential, cred['id']) - - creds = self.creds_client.list_credentials()['credentials'] - - for i in creds: - fetched_cred_ids.append(i['id']) - missing_creds = [c for c in created_cred_ids - if c not in fetched_cred_ids] - self.assertEmpty(missing_creds, - "Failed to find cred %s in fetched list" % - ', '.join(m_cred for m_cred in missing_creds)) diff --git a/tempest/api/identity/admin/v3/test_default_project_id.py b/tempest/api/identity/admin/v3/test_default_project_id.py deleted file mode 100644 index 302a0e541..000000000 --- a/tempest/api/identity/admin/v3/test_default_project_id.py +++ /dev/null @@ -1,85 +0,0 @@ -# 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 tempest.api.identity import base -from tempest import clients -from tempest import config -from tempest.lib import auth -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class TestDefaultProjectId (base.BaseIdentityV3AdminTest): - - @classmethod - def setup_credentials(cls): - cls.set_network_resources() - super(TestDefaultProjectId, cls).setup_credentials() - - def _delete_domain(self, domain_id): - # It is necessary to disable the domain before deleting, - # or else it would result in unauthorized error - self.domains_client.update_domain(domain_id, enabled=False) - self.domains_client.delete_domain(domain_id) - - @decorators.idempotent_id('d6110661-6a71-49a7-a453-b5e26640ff6d') - def test_default_project_id(self): - # create a domain - dom_name = data_utils.rand_name('dom') - domain_body = self.domains_client.create_domain( - name=dom_name)['domain'] - dom_id = domain_body['id'] - self.addCleanup(self._delete_domain, dom_id) - - # create a project in the domain - proj_body = self.setup_test_project(domain_id=dom_id) - proj_id = proj_body['id'] - self.assertEqual(proj_body['domain_id'], dom_id, - "project " + proj_body['name'] + - "doesn't have domain id " + dom_id) - - # create a user in the domain, with the previous project as his - # default project - user_name = data_utils.rand_name('user') - user_body = self.users_client.create_user( - name=user_name, - password=user_name, - domain_id=dom_id, - default_project_id=proj_id)['user'] - user_id = user_body['id'] - self.addCleanup(self.users_client.delete_user, user_id) - self.assertEqual(user_body['domain_id'], dom_id, - "user " + user_name + - "doesn't have domain id " + dom_id) - - # get roles and find the admin role - admin_role = self.get_role_by_name(CONF.identity.admin_role) - admin_role_id = admin_role['id'] - - # grant the admin role to the user on his project - self.roles_client.create_user_role_on_project(proj_id, user_id, - admin_role_id) - - # create a new client with user's credentials (NOTE: unscoped token!) - creds = auth.KeystoneV3Credentials(username=user_name, - password=user_name, - user_domain_name=dom_name) - auth_provider = clients.get_auth_provider(creds) - creds = auth_provider.fill_credentials() - admin_client = clients.Manager(credentials=creds) - - # verify the user's token and see that it is scoped to the project - token, _ = admin_client.auth_provider.get_auth() - result = admin_client.identity_v3_client.show_token(token)['token'] - self.assertEqual(result['project']['domain']['id'], dom_id) - self.assertEqual(result['project']['id'], proj_id) diff --git a/tempest/api/identity/admin/v3/test_domain_configuration.py b/tempest/api/identity/admin/v3/test_domain_configuration.py deleted file mode 100644 index f7316970b..000000000 --- a/tempest/api/identity/admin/v3/test_domain_configuration.py +++ /dev/null @@ -1,184 +0,0 @@ -# Copyright 2017 AT&T Corporation -# 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 tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class DomainConfigurationTestJSON(base.BaseIdentityV3AdminTest): - - custom_config = { - "identity": { - "driver": "ldap" - }, - "ldap": { - "url": "ldap://myldap.com:389/", - "user_tree_dn": "ou=Users,dc=my_new_root,dc=org" - } - } - - @classmethod - def setup_clients(cls): - super(DomainConfigurationTestJSON, cls).setup_clients() - cls.client = cls.domain_config_client - - @classmethod - def resource_setup(cls): - super(DomainConfigurationTestJSON, cls).resource_setup() - cls.group = cls.groups_client.create_group( - name=data_utils.rand_name('group'), - description=data_utils.rand_name('group-desc'))['group'] - - @classmethod - def resource_cleanup(cls): - cls.groups_client.delete_group(cls.group['id']) - super(DomainConfigurationTestJSON, cls).resource_cleanup() - - def _create_domain_and_config(self, config): - domain = self.setup_test_domain() - config = self.client.create_domain_config(domain['id'], **config)[ - 'config'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.client.delete_domain_config, domain['id']) - return domain, config - - @decorators.idempotent_id('11a02bf0-6f94-4380-b3b0-c8dc18fc0d22') - def test_show_default_group_config_and_options(self): - # The API supports only the identity and ldap groups. For the ldap - # group, a valid value is url or user_tree_dn. For the identity group, - # a valid value is driver. - - # Check that the default config has the identity and ldap groups. - config = self.client.show_default_config_settings()['config'] - self.assertIsInstance(config, dict) - self.assertIn('identity', config) - self.assertIn('ldap', config) - - # Check that the identity group is correct. - identity_config = self.client.show_default_group_config('identity')[ - 'config'] - - self.assertIsInstance(identity_config, dict) - self.assertIn('identity', identity_config) - self.assertIn('driver', identity_config['identity']) - self.assertIn('list_limit', identity_config['identity']) - - # Show each option for the default domain and identity group. - for config_opt_name in ['driver', 'list_limit']: - retrieved_config_opt = self.client.show_default_group_option( - 'identity', config_opt_name)['config'] - self.assertIn(config_opt_name, retrieved_config_opt) - - # Check that the ldap group is correct. - ldap_config = self.client.show_default_group_config('ldap')['config'] - - self.assertIsInstance(ldap_config, dict) - self.assertIn('ldap', ldap_config) - - # Several valid options exist for ldap group. - valid_options = ldap_config['ldap'].keys() - - # Show each option for the default domain and ldap group. - for config_opt_name in valid_options: - retrieved_config_opt = self.client.show_default_group_option( - 'ldap', config_opt_name)['config'] - self.assertIn(config_opt_name, retrieved_config_opt) - - @decorators.idempotent_id('9e3ff13c-f597-4f01-9377-d6c06c2a1477') - def test_create_domain_config_and_show_config_groups_and_options(self): - domain, created_config = self._create_domain_and_config( - self.custom_config) - - # Check that the entire configuration is correct. - self.assertEqual(self.custom_config, created_config) - - # Check that each configuration group is correct. - for group_name in self.custom_config.keys(): - group_cfg = self.client.show_domain_group_config( - domain['id'], group_name)['config'] - self.assertIn(group_name, group_cfg) - self.assertEqual(self.custom_config[group_name], - group_cfg[group_name]) - - # Check that each configuration option is correct. - for opt_name in self.custom_config[group_name].keys(): - group_opt = self.client.show_domain_group_option_config( - domain['id'], group_name, opt_name)['config'] - self.assertIn(opt_name, group_opt) - self.assertEqual(self.custom_config[group_name][opt_name], - group_opt[opt_name]) - - @decorators.idempotent_id('7161023e-5dd0-4612-9da0-1bac6ac30b63') - def test_create_update_and_delete_domain_config(self): - domain, created_config = self._create_domain_and_config( - self.custom_config) - - new_config = created_config - new_config['ldap']['url'] = data_utils.rand_url() - - # Check that the altered configuration is reflected in updated_config. - updated_config = self.client.update_domain_config( - domain['id'], **new_config)['config'] - self.assertEqual(new_config, updated_config) - - # Check that showing the domain config shows the altered configuration. - retrieved_config = self.client.show_domain_config(domain['id'])[ - 'config'] - self.assertEqual(new_config, retrieved_config) - - # Check that deleting a configuration works. - self.client.delete_domain_config(domain['id']) - self.assertRaises(lib_exc.NotFound, self.client.show_domain_config, - domain['id']) - - @decorators.idempotent_id('c7510fa2-6661-4170-9c6b-4783a80651e9') - def test_create_update_and_delete_domain_config_groups_and_opts(self): - domain, _ = self._create_domain_and_config(self.custom_config) - - # Check that updating configuration groups work. - new_driver = data_utils.rand_name('driver') - new_limit = data_utils.rand_int_id(0, 100) - new_group_config = {'identity': {'driver': new_driver, - 'list_limit': new_limit}} - - updated_config = self.client.update_domain_group_config( - domain['id'], 'identity', **new_group_config)['config'] - - self.assertEqual(new_driver, updated_config['identity']['driver']) - self.assertEqual(new_limit, updated_config['identity']['list_limit']) - - # Check that updating individual configuration group options work. - new_driver = data_utils.rand_name('driver') - - updated_config = self.client.update_domain_group_option_config( - domain['id'], 'identity', 'driver', driver=new_driver)['config'] - - self.assertEqual(new_driver, updated_config['identity']['driver']) - - # Check that deleting individual configuration group options work. - self.client.delete_domain_group_option_config( - domain['id'], 'identity', 'driver') - self.assertRaises(lib_exc.NotFound, - self.client.show_domain_group_option_config, - domain['id'], 'identity', 'driver') - - # Check that deleting configuration groups work. - self.client.delete_domain_group_config(domain['id'], 'identity') - self.assertRaises(lib_exc.NotFound, - self.client.show_domain_group_config, - domain['id'], 'identity') diff --git a/tempest/api/identity/admin/v3/test_domains.py b/tempest/api/identity/admin/v3/test_domains.py deleted file mode 100644 index 9fe978c9d..000000000 --- a/tempest/api/identity/admin/v3/test_domains.py +++ /dev/null @@ -1,168 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 tempest.api.identity import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class DomainsTestJSON(base.BaseIdentityV3AdminTest): - - @classmethod - def resource_setup(cls): - super(DomainsTestJSON, cls).resource_setup() - # Create some test domains to be used during tests - # One of those domains will be disabled - cls.setup_domains = list() - for i in range(3): - domain = cls.create_domain(enabled=i < 2) - cls.setup_domains.append(domain) - - @classmethod - def resource_cleanup(cls): - for domain in cls.setup_domains: - cls._delete_domain(domain['id']) - super(DomainsTestJSON, cls).resource_cleanup() - - @classmethod - def _delete_domain(cls, domain_id): - # It is necessary to disable the domain before deleting, - # or else it would result in unauthorized error - cls.domains_client.update_domain(domain_id, enabled=False) - cls.domains_client.delete_domain(domain_id) - - @decorators.idempotent_id('8cf516ef-2114-48f1-907b-d32726c734d4') - def test_list_domains(self): - # Test to list domains - fetched_ids = list() - # List and Verify Domains - body = self.domains_client.list_domains()['domains'] - for d in body: - fetched_ids.append(d['id']) - missing_doms = [d for d in self.setup_domains - if d['id'] not in fetched_ids] - self.assertEmpty(missing_doms) - - @decorators.idempotent_id('c6aee07b-4981-440c-bb0b-eb598f58ffe9') - def test_list_domains_filter_by_name(self): - # List domains filtering by name - params = {'name': self.setup_domains[0]['name']} - fetched_domains = self.domains_client.list_domains( - **params)['domains'] - # Verify the filtered list is correct, domain names are unique - # so exactly one domain should be found with the provided name - self.assertEqual(1, len(fetched_domains)) - self.assertEqual(self.setup_domains[0]['name'], - fetched_domains[0]['name']) - - @decorators.idempotent_id('3fd19840-65c1-43f8-b48c-51bdd066dff9') - def test_list_domains_filter_by_enabled(self): - # List domains filtering by enabled domains - params = {'enabled': True} - fetched_domains = self.domains_client.list_domains( - **params)['domains'] - # Verify the filtered list is correct - self.assertIn(self.setup_domains[0], fetched_domains) - self.assertIn(self.setup_domains[1], fetched_domains) - for domain in fetched_domains: - self.assertEqual(True, domain['enabled']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('f2f5b44a-82e8-4dad-8084-0661ea3b18cf') - def test_create_update_delete_domain(self): - # Create domain - d_name = data_utils.rand_name('domain') - d_desc = data_utils.rand_name('domain-desc') - domain = self.domains_client.create_domain( - name=d_name, description=d_desc)['domain'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self._delete_domain, domain['id']) - self.assertIn('id', domain) - self.assertIn('description', domain) - self.assertIn('name', domain) - self.assertIn('enabled', domain) - self.assertIn('links', domain) - self.assertIsNotNone(domain['id']) - self.assertEqual(d_name, domain['name']) - self.assertEqual(d_desc, domain['description']) - self.assertEqual(True, domain['enabled']) - # Update domain - new_desc = data_utils.rand_name('new-desc') - new_name = data_utils.rand_name('new-name') - updated_domain = self.domains_client.update_domain( - domain['id'], name=new_name, description=new_desc, - enabled=False)['domain'] - self.assertIn('id', updated_domain) - self.assertIn('description', updated_domain) - self.assertIn('name', updated_domain) - self.assertIn('enabled', updated_domain) - self.assertIn('links', updated_domain) - self.assertIsNotNone(updated_domain['id']) - self.assertEqual(new_name, updated_domain['name']) - self.assertEqual(new_desc, updated_domain['description']) - self.assertEqual(False, updated_domain['enabled']) - # Show domain - fetched_domain = self.domains_client.show_domain( - domain['id'])['domain'] - self.assertEqual(new_name, fetched_domain['name']) - self.assertEqual(new_desc, fetched_domain['description']) - self.assertEqual(False, fetched_domain['enabled']) - # Delete domain - self.domains_client.delete_domain(domain['id']) - body = self.domains_client.list_domains()['domains'] - domains_list = [d['id'] for d in body] - self.assertNotIn(domain['id'], domains_list) - - @decorators.idempotent_id('036df86e-bb5d-42c0-a7c2-66b9db3a6046') - def test_create_domain_with_disabled_status(self): - # Create domain with enabled status as false - d_name = data_utils.rand_name('domain') - d_desc = data_utils.rand_name('domain-desc') - domain = self.domains_client.create_domain( - name=d_name, description=d_desc, enabled=False)['domain'] - self.addCleanup(self.domains_client.delete_domain, domain['id']) - self.assertEqual(d_name, domain['name']) - self.assertFalse(domain['enabled']) - self.assertEqual(d_desc, domain['description']) - - @decorators.idempotent_id('2abf8764-309a-4fa9-bc58-201b799817ad') - def test_create_domain_without_description(self): - # Create domain only with name - d_name = data_utils.rand_name('domain') - domain = self.domains_client.create_domain(name=d_name)['domain'] - self.addCleanup(self._delete_domain, domain['id']) - self.assertIn('id', domain) - expected_data = {'name': d_name, 'enabled': True} - self.assertEqual('', domain['description']) - self.assertDictContainsSubset(expected_data, domain) - - -class DefaultDomainTestJSON(base.BaseIdentityV3AdminTest): - - @classmethod - def resource_setup(cls): - cls.domain_id = CONF.identity.default_domain_id - super(DefaultDomainTestJSON, cls).resource_setup() - - @decorators.attr(type='smoke') - @decorators.idempotent_id('17a5de24-e6a0-4e4a-a9ee-d85b6e5612b5') - def test_default_domain_exists(self): - domain = self.domains_client.show_domain(self.domain_id)['domain'] - - self.assertTrue(domain['enabled']) diff --git a/tempest/api/identity/admin/v3/test_domains_negative.py b/tempest/api/identity/admin/v3/test_domains_negative.py deleted file mode 100644 index 1a0b85181..000000000 --- a/tempest/api/identity/admin/v3/test_domains_negative.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright 2015 Red Hat Inc. -# 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 tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class DomainsNegativeTestJSON(base.BaseIdentityV3AdminTest): - _interface = 'json' - - @decorators.attr(type=['negative', 'gate']) - @decorators.idempotent_id('1f3fbff5-4e44-400d-9ca1-d953f05f609b') - def test_delete_active_domain(self): - domain = self.create_domain() - domain_id = domain['id'] - - self.addCleanup(self.delete_domain, domain_id) - - # domain need to be disabled before deleting - self.assertRaises(lib_exc.Forbidden, self.domains_client.delete_domain, - domain_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9018461d-7d24-408d-b3fe-ae37e8cd5c9e') - def test_create_domain_with_empty_name(self): - # Domain name should not be empty - self.assertRaises(lib_exc.BadRequest, - self.domains_client.create_domain, name='') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('37b1bbf2-d664-4785-9a11-333438586eae') - def test_create_domain_with_name_length_over_64(self): - # Domain name length should not ne greater than 64 characters - d_name = 'a' * 65 - self.assertRaises(lib_exc.BadRequest, - self.domains_client.create_domain, - name=d_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('43781c07-764f-4cf2-a405-953c1916f605') - def test_delete_non_existent_domain(self): - # Attempt to delete a non existent domain should fail - self.assertRaises(lib_exc.NotFound, self.domains_client.delete_domain, - data_utils.rand_uuid_hex()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e6f9e4a2-4f36-4be8-bdbc-4e199ae29427') - def test_domain_create_duplicate(self): - domain_name = data_utils.rand_name('domain-dup') - domain = self.domains_client.create_domain(name=domain_name)['domain'] - domain_id = domain['id'] - self.addCleanup(self.delete_domain, domain_id) - # Domain name should be unique - self.assertRaises( - lib_exc.Conflict, self.domains_client.create_domain, - name=domain_name) diff --git a/tempest/api/identity/admin/v3/test_endpoint_groups.py b/tempest/api/identity/admin/v3/test_endpoint_groups.py deleted file mode 100644 index 49dbba198..000000000 --- a/tempest/api/identity/admin/v3/test_endpoint_groups.py +++ /dev/null @@ -1,157 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class EndPointGroupsTest(base.BaseIdentityV3AdminTest): - - @classmethod - def setup_clients(cls): - super(EndPointGroupsTest, cls).setup_clients() - cls.client = cls.endpoint_groups_client - - @classmethod - def resource_setup(cls): - super(EndPointGroupsTest, cls).resource_setup() - cls.service_ids = list() - cls.endpoint_groups = list() - - # Create endpoint group so as to use it for LIST test - service_id = cls._create_service() - - name = data_utils.rand_name('service_group') - description = data_utils.rand_name('description') - filters = {'service_id': service_id} - - endpoint_group = cls.client.create_endpoint_group( - name=name, - description=description, - filters=filters)['endpoint_group'] - - cls.endpoint_groups.append(endpoint_group) - - @classmethod - def resource_cleanup(cls): - for e in cls.endpoint_groups: - cls.client.delete_endpoint_group(e['id']) - for s in cls.service_ids: - cls.services_client.delete_service(s) - super(EndPointGroupsTest, cls).resource_cleanup() - - @classmethod - def _create_service(cls): - s_name = data_utils.rand_name('service') - s_type = data_utils.rand_name('type') - s_description = data_utils.rand_name('description') - service_data = ( - cls.services_client.create_service(name=s_name, - type=s_type, - description=s_description)) - - service_id = service_data['service']['id'] - cls.service_ids.append(service_id) - return service_id - - @decorators.idempotent_id('7c69e7a1-f865-402d-a2ea-44493017315a') - def test_create_list_show_check_delete_endpoint_group(self): - service_id = self._create_service() - name = data_utils.rand_name('service_group') - description = data_utils.rand_name('description') - filters = {'service_id': service_id} - - endpoint_group = self.client.create_endpoint_group( - name=name, - description=description, - filters=filters)['endpoint_group'] - - self.endpoint_groups.append(endpoint_group) - - # Asserting created endpoint group response body - self.assertIn('id', endpoint_group) - self.assertEqual(name, endpoint_group['name']) - self.assertEqual(description, endpoint_group['description']) - - # Checking if endpoint groups are present in the list of endpoints - # Note that there are two endpoint groups in the list, one created - # in the resource setup, one created in this test case. - fetched_endpoints = \ - self.client.list_endpoint_groups()['endpoint_groups'] - - missing_endpoints = \ - [e for e in self.endpoint_groups if e not in fetched_endpoints] - - # Asserting LIST endpoints - self.assertEmpty(missing_endpoints, - "Failed to find endpoint %s in fetched list" % - ', '.join(str(e) for e in missing_endpoints)) - - # Show endpoint group - fetched_endpoint = self.client.show_endpoint_group( - endpoint_group['id'])['endpoint_group'] - - # Asserting if the attributes of endpoint group are the same - self.assertEqual(service_id, - fetched_endpoint['filters']['service_id']) - for attr in ('id', 'name', 'description'): - self.assertEqual(endpoint_group[attr], fetched_endpoint[attr]) - - # Check endpoint group - self.client.check_endpoint_group(endpoint_group['id']) - - # Deleting the endpoint group created in this method - self.client.delete_endpoint_group(endpoint_group['id']) - self.endpoint_groups.remove(endpoint_group) - - # Checking whether endpoint group is deleted successfully - fetched_endpoints = \ - self.client.list_endpoint_groups()['endpoint_groups'] - fetched_endpoint_ids = [e['id'] for e in fetched_endpoints] - self.assertNotIn(endpoint_group['id'], fetched_endpoint_ids) - - @decorators.idempotent_id('51c8fc38-fa84-4e76-b5b6-6fc37770fb26') - def test_update_endpoint_group(self): - # Creating an endpoint group so as to check update endpoint group - # with new values - service1_id = self._create_service() - name = data_utils.rand_name('service_group') - description = data_utils.rand_name('description') - filters = {'service_id': service1_id} - - endpoint_group = self.client.create_endpoint_group( - name=name, - description=description, - filters=filters)['endpoint_group'] - self.endpoint_groups.append(endpoint_group) - - # Creating new attr values to update endpoint group - service2_id = self._create_service() - name2 = data_utils.rand_name('service_group2') - description2 = data_utils.rand_name('description2') - filters = {'service_id': service2_id} - - # Updating endpoint group with new attr values - updated_endpoint_group = self.client.update_endpoint_group( - endpoint_group['id'], - name=name2, - description=description2, - filters=filters)['endpoint_group'] - - self.assertEqual(name2, updated_endpoint_group['name']) - self.assertEqual(description2, updated_endpoint_group['description']) - self.assertEqual(service2_id, - updated_endpoint_group['filters']['service_id']) diff --git a/tempest/api/identity/admin/v3/test_endpoints.py b/tempest/api/identity/admin/v3/test_endpoints.py deleted file mode 100644 index c9faa9aa5..000000000 --- a/tempest/api/identity/admin/v3/test_endpoints.py +++ /dev/null @@ -1,182 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class EndPointsTestJSON(base.BaseIdentityV3AdminTest): - - @classmethod - def setup_clients(cls): - super(EndPointsTestJSON, cls).setup_clients() - cls.client = cls.endpoints_client - - @classmethod - def resource_setup(cls): - super(EndPointsTestJSON, cls).resource_setup() - cls.service_ids = list() - - # Create endpoints so as to use for LIST and GET test cases - interfaces = ['public', 'internal'] - cls.setup_endpoint_ids = list() - for i in range(2): - cls._create_service() - region = data_utils.rand_name('region') - url = data_utils.rand_url() - endpoint = cls.client.create_endpoint( - service_id=cls.service_ids[i], interface=interfaces[i], - url=url, region=region, enabled=True)['endpoint'] - cls.setup_endpoint_ids.append(endpoint['id']) - - @classmethod - def _create_service(cls, s_name=None, s_type=None, s_description=None): - if s_name is None: - s_name = data_utils.rand_name('service') - if s_type is None: - s_type = data_utils.rand_name('type') - if s_description is None: - s_description = data_utils.rand_name('description') - service_data = ( - cls.services_client.create_service(name=s_name, type=s_type, - description=s_description)) - service = service_data['service'] - cls.service_ids.append(service['id']) - return service - - @classmethod - def resource_cleanup(cls): - for e in cls.setup_endpoint_ids: - cls.client.delete_endpoint(e) - for s in cls.service_ids: - cls.services_client.delete_service(s) - super(EndPointsTestJSON, cls).resource_cleanup() - - @decorators.idempotent_id('c19ecf90-240e-4e23-9966-21cee3f6a618') - def test_list_endpoints(self): - # Get the list of all the endpoints. - fetched_endpoints = self.client.list_endpoints()['endpoints'] - fetched_endpoint_ids = [e['id'] for e in fetched_endpoints] - # Check that all the created endpoints are present in - # "fetched_endpoints". - missing_endpoints =\ - [e for e in self.setup_endpoint_ids - if e not in fetched_endpoint_ids] - self.assertEqual(0, len(missing_endpoints), - "Failed to find endpoint %s in fetched list" % - ', '.join(str(e) for e in missing_endpoints)) - - # Check that filtering endpoints by service_id works. - fetched_endpoints_for_service = self.client.list_endpoints( - service_id=self.service_ids[0])['endpoints'] - fetched_endpoints_for_alt_service = self.client.list_endpoints( - service_id=self.service_ids[1])['endpoints'] - - # Assert that both filters returned the correct result. - self.assertEqual(1, len(fetched_endpoints_for_service)) - self.assertEqual(1, len(fetched_endpoints_for_alt_service)) - self.assertEqual(set(self.setup_endpoint_ids), - set([fetched_endpoints_for_service[0]['id'], - fetched_endpoints_for_alt_service[0]['id']])) - - # Check that filtering endpoints by interface works. - fetched_public_endpoints = self.client.list_endpoints( - interface='public')['endpoints'] - fetched_internal_endpoints = self.client.list_endpoints( - interface='internal')['endpoints'] - - # Check that the expected endpoint_id is present per filter. [0] is - # public and [1] is internal. - self.assertIn(self.setup_endpoint_ids[0], - [e['id'] for e in fetched_public_endpoints]) - self.assertIn(self.setup_endpoint_ids[1], - [e['id'] for e in fetched_internal_endpoints]) - - @decorators.idempotent_id('0e2446d2-c1fd-461b-a729-b9e73e3e3b37') - def test_create_list_show_delete_endpoint(self): - region = data_utils.rand_name('region') - url = data_utils.rand_url() - interface = 'public' - endpoint = self.client.create_endpoint(service_id=self.service_ids[0], - interface=interface, - url=url, region=region, - enabled=True)['endpoint'] - - self.setup_endpoint_ids.append(endpoint['id']) - # Asserting Create Endpoint response body - self.assertIn('id', endpoint) - self.assertEqual(region, endpoint['region']) - self.assertEqual(url, endpoint['url']) - - # Checking if created endpoint is present in the list of endpoints - fetched_endpoints = self.client.list_endpoints()['endpoints'] - fetched_endpoints_id = [e['id'] for e in fetched_endpoints] - self.assertIn(endpoint['id'], fetched_endpoints_id) - - # Show endpoint - fetched_endpoint = ( - self.client.show_endpoint(endpoint['id'])['endpoint']) - # Asserting if the attributes of endpoint are the same - self.assertEqual(self.service_ids[0], fetched_endpoint['service_id']) - self.assertEqual(interface, fetched_endpoint['interface']) - self.assertEqual(url, fetched_endpoint['url']) - self.assertEqual(region, fetched_endpoint['region']) - self.assertEqual(True, fetched_endpoint['enabled']) - - # Deleting the endpoint created in this method - self.client.delete_endpoint(endpoint['id']) - self.setup_endpoint_ids.remove(endpoint['id']) - - # Checking whether endpoint is deleted successfully - fetched_endpoints = self.client.list_endpoints()['endpoints'] - fetched_endpoints_id = [e['id'] for e in fetched_endpoints] - self.assertNotIn(endpoint['id'], fetched_endpoints_id) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('37e8f15e-ee7c-4657-a1e7-f6b61e375eff') - def test_update_endpoint(self): - # Creating an endpoint so as to check update endpoint - # with new values - region1 = data_utils.rand_name('region') - url1 = data_utils.rand_url() - interface1 = 'public' - endpoint_for_update = ( - self.client.create_endpoint(service_id=self.service_ids[0], - interface=interface1, - url=url1, region=region1, - enabled=True)['endpoint']) - self.addCleanup(self.client.delete_endpoint, endpoint_for_update['id']) - # Creating service so as update endpoint with new service ID - s_name = data_utils.rand_name('service') - s_type = data_utils.rand_name('type') - s_description = data_utils.rand_name('description') - service2 = self._create_service(s_name=s_name, s_type=s_type, - s_description=s_description) - # Updating endpoint with new values - region2 = data_utils.rand_name('region') - url2 = data_utils.rand_url() - interface2 = 'internal' - endpoint = self.client.update_endpoint(endpoint_for_update['id'], - service_id=service2['id'], - interface=interface2, - url=url2, region=region2, - enabled=False)['endpoint'] - # Asserting if the attributes of endpoint are updated - self.assertEqual(service2['id'], endpoint['service_id']) - self.assertEqual(interface2, endpoint['interface']) - self.assertEqual(url2, endpoint['url']) - self.assertEqual(region2, endpoint['region']) - self.assertEqual(False, endpoint['enabled']) diff --git a/tempest/api/identity/admin/v3/test_endpoints_negative.py b/tempest/api/identity/admin/v3/test_endpoints_negative.py deleted file mode 100644 index 70dd7b523..000000000 --- a/tempest/api/identity/admin/v3/test_endpoints_negative.py +++ /dev/null @@ -1,98 +0,0 @@ - -# Copyright 2013 IBM 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 tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class EndpointsNegativeTestJSON(base.BaseIdentityV3AdminTest): - - @classmethod - def setup_clients(cls): - super(EndpointsNegativeTestJSON, cls).setup_clients() - cls.client = cls.endpoints_client - - @classmethod - def resource_setup(cls): - super(EndpointsNegativeTestJSON, cls).resource_setup() - cls.service_ids = list() - s_name = data_utils.rand_name('service') - s_type = data_utils.rand_name('type') - s_description = data_utils.rand_name('description') - service_data = ( - cls.services_client.create_service(name=s_name, type=s_type, - description=s_description) - ['service']) - cls.service_id = service_data['id'] - cls.service_ids.append(cls.service_id) - - @classmethod - def resource_cleanup(cls): - for s in cls.service_ids: - cls.services_client.delete_service(s) - super(EndpointsNegativeTestJSON, cls).resource_cleanup() - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ac6c137e-4d3d-448f-8c83-4f13d0942651') - def test_create_with_enabled_False(self): - # Enabled should be a boolean, not a string like 'False' - interface = 'public' - url = data_utils.rand_url() - region = data_utils.rand_name('region') - self.assertRaises(lib_exc.BadRequest, self.client.create_endpoint, - service_id=self.service_id, interface=interface, - url=url, region=region, enabled='False') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9c43181e-0627-484a-8c79-923e8a59598b') - def test_create_with_enabled_True(self): - # Enabled should be a boolean, not a string like 'True' - interface = 'public' - url = data_utils.rand_url() - region = data_utils.rand_name('region') - self.assertRaises(lib_exc.BadRequest, self.client.create_endpoint, - service_id=self.service_id, interface=interface, - url=url, region=region, enabled='True') - - def _assert_update_raises_bad_request(self, enabled): - - # Create an endpoint - region1 = data_utils.rand_name('region') - url1 = data_utils.rand_url() - interface1 = 'public' - endpoint_for_update = ( - self.client.create_endpoint(service_id=self.service_id, - interface=interface1, - url=url1, region=region1, - enabled=True)['endpoint']) - self.addCleanup(self.client.delete_endpoint, endpoint_for_update['id']) - - self.assertRaises(lib_exc.BadRequest, self.client.update_endpoint, - endpoint_for_update['id'], enabled=enabled) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('65e41f32-5eb7-498f-a92a-a6ccacf7439a') - def test_update_with_enabled_False(self): - # Enabled should be a boolean, not a string like 'False' - self._assert_update_raises_bad_request('False') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('faba3587-f066-4757-a48e-b4a3f01803bb') - def test_update_with_enabled_True(self): - # Enabled should be a boolean, not a string like 'True' - self._assert_update_raises_bad_request('True') diff --git a/tempest/api/identity/admin/v3/test_groups.py b/tempest/api/identity/admin/v3/test_groups.py deleted file mode 100644 index 4bc987fbe..000000000 --- a/tempest/api/identity/admin/v3/test_groups.py +++ /dev/null @@ -1,137 +0,0 @@ -# Copyright 2013 IBM 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 tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class GroupsV3TestJSON(base.BaseIdentityV3AdminTest): - - @classmethod - def resource_setup(cls): - super(GroupsV3TestJSON, cls).resource_setup() - cls.domain = cls.create_domain() - - @classmethod - def resource_cleanup(cls): - # Cleanup the domains created in the setup - cls.domains_client.update_domain(cls.domain['id'], enabled=False) - cls.domains_client.delete_domain(cls.domain['id']) - super(GroupsV3TestJSON, cls).resource_cleanup() - - @decorators.idempotent_id('2e80343b-6c81-4ac3-88c7-452f3e9d5129') - def test_group_create_update_get(self): - name = data_utils.rand_name('Group') - description = data_utils.rand_name('Description') - group = self.groups_client.create_group( - name=name, domain_id=self.domain['id'], - description=description)['group'] - self.addCleanup(self.groups_client.delete_group, group['id']) - self.assertEqual(group['name'], name) - self.assertEqual(group['description'], description) - - new_name = data_utils.rand_name('UpdateGroup') - new_desc = data_utils.rand_name('UpdateDescription') - updated_group = self.groups_client.update_group( - group['id'], name=new_name, description=new_desc)['group'] - self.assertEqual(updated_group['name'], new_name) - self.assertEqual(updated_group['description'], new_desc) - - new_group = self.groups_client.show_group(group['id'])['group'] - self.assertEqual(group['id'], new_group['id']) - self.assertEqual(new_name, new_group['name']) - self.assertEqual(new_desc, new_group['description']) - - @decorators.idempotent_id('b66eb441-b08a-4a6d-81ab-fef71baeb26c') - def test_group_update_with_few_fields(self): - name = data_utils.rand_name('Group') - old_description = data_utils.rand_name('Description') - group = self.groups_client.create_group( - name=name, domain_id=self.domain['id'], - description=old_description)['group'] - self.addCleanup(self.groups_client.delete_group, group['id']) - - new_name = data_utils.rand_name('UpdateGroup') - updated_group = self.groups_client.update_group( - group['id'], name=new_name)['group'] - self.assertEqual(new_name, updated_group['name']) - # Verify that 'description' is not being updated or deleted. - self.assertEqual(old_description, updated_group['description']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('1598521a-2f36-4606-8df9-30772bd51339') - def test_group_users_add_list_delete(self): - name = data_utils.rand_name('Group') - group = self.groups_client.create_group( - name=name, domain_id=self.domain['id'])['group'] - self.addCleanup(self.groups_client.delete_group, group['id']) - # add user into group - users = [] - for _ in range(3): - user = self.create_test_user() - users.append(user) - self.groups_client.add_group_user(group['id'], user['id']) - - # list users in group - group_users = self.groups_client.list_group_users(group['id'])['users'] - self.assertEqual(sorted(users, key=lambda k: k['name']), - sorted(group_users, key=lambda k: k['name'])) - # check and delete user in group - for user in users: - self.groups_client.check_group_user_existence( - group['id'], user['id']) - self.groups_client.delete_group_user(group['id'], user['id']) - group_users = self.groups_client.list_group_users(group['id'])['users'] - self.assertEqual(len(group_users), 0) - - @decorators.idempotent_id('64573281-d26a-4a52-b899-503cb0f4e4ec') - def test_list_user_groups(self): - # create a user - user = self.create_test_user() - # create two groups, and add user into them - groups = [] - for _ in range(2): - name = data_utils.rand_name('Group') - group = self.groups_client.create_group( - name=name, domain_id=self.domain['id'])['group'] - groups.append(group) - self.addCleanup(self.groups_client.delete_group, group['id']) - self.groups_client.add_group_user(group['id'], user['id']) - # list groups which user belongs to - user_groups = self.users_client.list_user_groups(user['id'])['groups'] - self.assertEqual(sorted(groups, key=lambda k: k['name']), - sorted(user_groups, key=lambda k: k['name'])) - self.assertEqual(2, len(user_groups)) - - @decorators.idempotent_id('cc9a57a5-a9ed-4f2d-a29f-4f979a06ec71') - def test_list_groups(self): - # Test to list groups - group_ids = list() - fetched_ids = list() - for _ in range(3): - name = data_utils.rand_name('Group') - description = data_utils.rand_name('Description') - group = self.groups_client.create_group( - name=name, domain_id=self.domain['id'], - description=description)['group'] - self.addCleanup(self.groups_client.delete_group, group['id']) - group_ids.append(group['id']) - # List and Verify Groups - body = self.groups_client.list_groups()['groups'] - for g in body: - fetched_ids.append(g['id']) - missing_groups = [g for g in group_ids if g not in fetched_ids] - self.assertEmpty(missing_groups) diff --git a/tempest/api/identity/admin/v3/test_inherits.py b/tempest/api/identity/admin/v3/test_inherits.py deleted file mode 100644 index 49b658507..000000000 --- a/tempest/api/identity/admin/v3/test_inherits.py +++ /dev/null @@ -1,214 +0,0 @@ -# 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 tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - - -class BaseInheritsV3Test(base.BaseIdentityV3AdminTest): - - @classmethod - def skip_checks(cls): - super(BaseInheritsV3Test, cls).skip_checks() - if not test.is_extension_enabled('OS-INHERIT', 'identity'): - raise cls.skipException("Inherits aren't enabled") - - @classmethod - def resource_setup(cls): - super(BaseInheritsV3Test, cls).resource_setup() - u_name = data_utils.rand_name('user-') - u_desc = '%s description' % u_name - u_email = '%s@testmail.tm' % u_name - u_password = data_utils.rand_name('pass-') - cls.domain = cls.create_domain() - cls.project = cls.projects_client.create_project( - data_utils.rand_name('project-'), - description=data_utils.rand_name('project-desc-'), - domain_id=cls.domain['id'])['project'] - cls.group = cls.groups_client.create_group( - name=data_utils.rand_name('group-'), project_id=cls.project['id'], - domain_id=cls.domain['id'])['group'] - cls.user = cls.users_client.create_user( - name=u_name, description=u_desc, password=u_password, - email=u_email, project_id=cls.project['id'], - domain_id=cls.domain['id'])['user'] - - @classmethod - def resource_cleanup(cls): - cls.groups_client.delete_group(cls.group['id']) - cls.users_client.delete_user(cls.user['id']) - cls.projects_client.delete_project(cls.project['id']) - cls.domains_client.update_domain(cls.domain['id'], enabled=False) - cls.domains_client.delete_domain(cls.domain['id']) - super(BaseInheritsV3Test, cls).resource_cleanup() - - def _list_assertions(self, body, fetched_role_ids, role_id): - self.assertEqual(len(body), 1) - self.assertIn(role_id, fetched_role_ids) - - -class InheritsV3TestJSON(BaseInheritsV3Test): - - @decorators.idempotent_id('4e6f0366-97c8-423c-b2be-41eae6ac91c8') - def test_inherit_assign_list_check_revoke_roles_on_domains_user(self): - # Create role - src_role = self.setup_test_role() - # Assign role on domains user - self.inherited_roles_client.create_inherited_role_on_domains_user( - self.domain['id'], self.user['id'], src_role['id']) - # list role on domains user - roles = self.inherited_roles_client.\ - list_inherited_project_role_for_user_on_domain( - self.domain['id'], self.user['id'])['roles'] - - fetched_role_ids = [i['id'] for i in roles] - self._list_assertions(roles, fetched_role_ids, - src_role['id']) - - # Check role on domains user - (self.inherited_roles_client. - check_user_inherited_project_role_on_domain( - self.domain['id'], self.user['id'], src_role['id'])) - # Revoke role from domains user. - self.inherited_roles_client.delete_inherited_role_from_user_on_domain( - self.domain['id'], self.user['id'], src_role['id']) - - @decorators.idempotent_id('c7a8dda2-be50-4fb4-9a9c-e830771078b1') - def test_inherit_assign_list_check_revoke_roles_on_domains_group(self): - # Create role - src_role = self.setup_test_role() - # Assign role on domains group - self.inherited_roles_client.create_inherited_role_on_domains_group( - self.domain['id'], self.group['id'], src_role['id']) - # List role on domains group - roles = self.inherited_roles_client.\ - list_inherited_project_role_for_group_on_domain( - self.domain['id'], self.group['id'])['roles'] - - fetched_role_ids = [i['id'] for i in roles] - self._list_assertions(roles, fetched_role_ids, - src_role['id']) - - # Check role on domains group - (self.inherited_roles_client. - check_group_inherited_project_role_on_domain( - self.domain['id'], self.group['id'], src_role['id'])) - # Revoke role from domains group - self.inherited_roles_client.delete_inherited_role_from_group_on_domain( - self.domain['id'], self.group['id'], src_role['id']) - - @decorators.idempotent_id('18b70e45-7687-4b72-8277-b8f1a47d7591') - def test_inherit_assign_check_revoke_roles_on_projects_user(self): - # Create role - src_role = self.setup_test_role() - # Assign role on projects user - self.inherited_roles_client.create_inherited_role_on_projects_user( - self.project['id'], self.user['id'], src_role['id']) - # Check role on projects user - (self.inherited_roles_client. - check_user_has_flag_on_inherited_to_project( - self.project['id'], self.user['id'], src_role['id'])) - # Revoke role from projects user - self.inherited_roles_client.delete_inherited_role_from_user_on_project( - self.project['id'], self.user['id'], src_role['id']) - - @decorators.idempotent_id('26021436-d5a4-4256-943c-ded01e0d4b45') - def test_inherit_assign_check_revoke_roles_on_projects_group(self): - # Create role - src_role = self.setup_test_role() - # Assign role on projects group - self.inherited_roles_client.create_inherited_role_on_projects_group( - self.project['id'], self.group['id'], src_role['id']) - # Check role on projects group - (self.inherited_roles_client. - check_group_has_flag_on_inherited_to_project( - self.project['id'], self.group['id'], src_role['id'])) - # Revoke role from projects group - (self.inherited_roles_client. - delete_inherited_role_from_group_on_project( - self.project['id'], self.group['id'], src_role['id'])) - - @decorators.idempotent_id('3acf666e-5354-42ac-8e17-8b68893bcd36') - def test_inherit_assign_list_revoke_user_roles_on_domain(self): - # Create role - src_role = self.setup_test_role() - - # Create a project hierarchy - leaf_project = self.setup_test_project(domain_id=self.domain['id'], - parent_id=self.project['id']) - - # Assign role on domain - self.inherited_roles_client.create_inherited_role_on_domains_user( - self.domain['id'], self.user['id'], src_role['id']) - - # List "effective" role assignments from user on the parent project - params = {'scope.project.id': self.project['id'], - 'user.id': self.user['id']} - assignments = self.role_assignments.list_role_assignments( - effective=True, **params)['role_assignments'] - self.assertNotEmpty(assignments) - - # List "effective" role assignments from user on the leaf project - params['scope.project.id'] = leaf_project['id'] - assignments = self.role_assignments.list_role_assignments( - effective=True, **params)['role_assignments'] - self.assertNotEmpty(assignments) - - # Revoke role from domain - self.inherited_roles_client.delete_inherited_role_from_user_on_domain( - self.domain['id'], self.user['id'], src_role['id']) - - # List "effective" role assignments from user on the parent project - # should return an empty list - params['scope.project.id'] = self.project['id'] - assignments = self.role_assignments.list_role_assignments( - effective=True, **params)['role_assignments'] - self.assertEmpty(assignments) - - # List "effective" role assignments from user on the leaf project - # should return an empty list - params['scope.project.id'] = leaf_project['id'] - assignments = self.role_assignments.list_role_assignments( - effective=True, **params)['role_assignments'] - self.assertEmpty(assignments) - - @decorators.idempotent_id('9f02ccd9-9b57-46b4-8f77-dd5a736f3a06') - def test_inherit_assign_list_revoke_user_roles_on_project_tree(self): - # Create role - src_role = self.setup_test_role() - - # Create a project hierarchy - leaf_project = self.setup_test_project(domain_id=self.domain['id'], - parent_id=self.project['id']) - - # Assign role on parent project - self.inherited_roles_client.create_inherited_role_on_projects_user( - self.project['id'], self.user['id'], src_role['id']) - - # List "effective" role assignments from user on the leaf project - params = {'scope.project.id': leaf_project['id'], - 'user.id': self.user['id']} - assignments = self.role_assignments.list_role_assignments( - effective=True, **params)['role_assignments'] - self.assertNotEmpty(assignments) - - # Revoke role from parent project - self.inherited_roles_client.delete_inherited_role_from_user_on_project( - self.project['id'], self.user['id'], src_role['id']) - - # List "effective" role assignments from user on the leaf project - # should return an empty list - assignments = self.role_assignments.list_role_assignments( - effective=True, **params)['role_assignments'] - self.assertEmpty(assignments) diff --git a/tempest/api/identity/admin/v3/test_list_projects.py b/tempest/api/identity/admin/v3/test_list_projects.py deleted file mode 100644 index 7e70c14f8..000000000 --- a/tempest/api/identity/admin/v3/test_list_projects.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P -# 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 tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class ListProjectsTestJSON(base.BaseIdentityV3AdminTest): - - @classmethod - def resource_setup(cls): - super(ListProjectsTestJSON, cls).resource_setup() - cls.project_ids = list() - # Create a domain - cls.domain = cls.create_domain() - # Create project with domain - cls.projects = list() - cls.p1_name = data_utils.rand_name('project') - cls.p1 = cls.projects_client.create_project( - cls.p1_name, enabled=False, - domain_id=cls.domain['id'])['project'] - cls.projects.append(cls.p1) - cls.project_ids.append(cls.p1['id']) - # Create default project - p2_name = data_utils.rand_name('project') - cls.p2 = cls.projects_client.create_project(p2_name)['project'] - cls.projects.append(cls.p2) - cls.project_ids.append(cls.p2['id']) - # Create a new project (p3) using p2 as parent project - p3_name = data_utils.rand_name('project') - cls.p3 = cls.projects_client.create_project( - p3_name, parent_id=cls.p2['id'])['project'] - cls.projects.append(cls.p3) - cls.project_ids.append(cls.p3['id']) - - @classmethod - def resource_cleanup(cls): - # Cleanup the projects created during setup in inverse order - for project in reversed(cls.projects): - cls.projects_client.delete_project(project['id']) - # Cleanup the domain created during setup - cls.domains_client.update_domain(cls.domain['id'], enabled=False) - cls.domains_client.delete_domain(cls.domain['id']) - super(ListProjectsTestJSON, cls).resource_cleanup() - - @decorators.idempotent_id('1d830662-22ad-427c-8c3e-4ec854b0af44') - def test_list_projects(self): - # List projects - list_projects = self.projects_client.list_projects()['projects'] - - for p in self.project_ids: - show_project = self.projects_client.show_project(p)['project'] - self.assertIn(show_project, list_projects) - - @decorators.idempotent_id('fab13f3c-f6a6-4b9f-829b-d32fd44fdf10') - def test_list_projects_with_domains(self): - # List projects with domain - self._list_projects_with_params( - {'domain_id': self.domain['id']}, 'domain_id') - - @decorators.idempotent_id('0fe7a334-675a-4509-b00e-1c4b95d5dae8') - def test_list_projects_with_enabled(self): - # List the projects with enabled - self._list_projects_with_params({'enabled': False}, 'enabled') - - @decorators.idempotent_id('fa178524-4e6d-4925-907c-7ab9f42c7e26') - def test_list_projects_with_name(self): - # List projects with name - self._list_projects_with_params({'name': self.p1_name}, 'name') - - @decorators.idempotent_id('6edc66f5-2941-4a17-9526-4073311c1fac') - def test_list_projects_with_parent(self): - # List projects with parent - params = {'parent_id': self.p3['parent_id']} - fetched_projects = self.projects_client.list_projects( - params)['projects'] - self.assertNotEmpty(fetched_projects) - for project in fetched_projects: - self.assertEqual(self.p3['parent_id'], project['parent_id']) - - def _list_projects_with_params(self, params, key): - body = self.projects_client.list_projects(params)['projects'] - self.assertIn(self.p1[key], map(lambda x: x[key], body)) - self.assertNotIn(self.p2[key], map(lambda x: x[key], body)) diff --git a/tempest/api/identity/admin/v3/test_list_users.py b/tempest/api/identity/admin/v3/test_list_users.py deleted file mode 100644 index 47a358068..000000000 --- a/tempest/api/identity/admin/v3/test_list_users.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P -# 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 tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class UsersV3TestJSON(base.BaseIdentityV3AdminTest): - - def _list_users_with_params(self, params, key, expected, not_expected): - # Helper method to list users filtered with params and - # assert the response based on expected and not_expected - # expected: user expected in the list response - # not_expected: user, which should not be present in list response - body = self.users_client.list_users(**params)['users'] - self.assertIn(expected[key], map(lambda x: x[key], body)) - self.assertNotIn(not_expected[key], - map(lambda x: x[key], body)) - - @classmethod - def resource_setup(cls): - super(UsersV3TestJSON, cls).resource_setup() - alt_user = data_utils.rand_name('test_user') - alt_password = data_utils.rand_password() - cls.alt_email = alt_user + '@testmail.tm' - # Create a domain - cls.domain = cls.create_domain() - # Create user with Domain - cls.users = list() - u1_name = data_utils.rand_name('test_user') - cls.domain_enabled_user = cls.users_client.create_user( - name=u1_name, password=alt_password, - email=cls.alt_email, domain_id=cls.domain['id'])['user'] - cls.users.append(cls.domain_enabled_user) - # Create default not enabled user - u2_name = data_utils.rand_name('test_user') - cls.non_domain_enabled_user = cls.users_client.create_user( - name=u2_name, password=alt_password, - email=cls.alt_email, enabled=False)['user'] - cls.users.append(cls.non_domain_enabled_user) - - @classmethod - def resource_cleanup(cls): - # Cleanup the users created during setup - for user in cls.users: - cls.users_client.delete_user(user['id']) - # Cleanup the domain created during setup - cls.domains_client.update_domain(cls.domain['id'], enabled=False) - cls.domains_client.delete_domain(cls.domain['id']) - super(UsersV3TestJSON, cls).resource_cleanup() - - @decorators.idempotent_id('08f9aabb-dcfe-41d0-8172-82b5fa0bd73d') - def test_list_user_domains(self): - # List users with domain - params = {'domain_id': self.domain['id']} - self._list_users_with_params(params, 'domain_id', - self.domain_enabled_user, - self.non_domain_enabled_user) - - @decorators.idempotent_id('bff8bf2f-9408-4ef5-b63a-753c8c2124eb') - def test_list_users_with_not_enabled(self): - # List the users with not enabled - params = {'enabled': False} - self._list_users_with_params(params, 'enabled', - self.non_domain_enabled_user, - self.domain_enabled_user) - - @decorators.idempotent_id('c285bb37-7325-4c02-bff3-3da5d946d683') - def test_list_users_with_name(self): - # List users with name - params = {'name': self.domain_enabled_user['name']} - self._list_users_with_params(params, 'name', - self.domain_enabled_user, - self.non_domain_enabled_user) - - @decorators.idempotent_id('b30d4651-a2ea-4666-8551-0c0e49692635') - def test_list_users(self): - # List users - body = self.users_client.list_users()['users'] - fetched_ids = [u['id'] for u in body] - missing_users = [u['id'] for u in self.users - if u['id'] not in fetched_ids] - self.assertEmpty(missing_users, - "Failed to find user %s in fetched list" % - ', '.join(m_user for m_user in missing_users)) - - @decorators.idempotent_id('b4baa3ae-ac00-4b4e-9e27-80deaad7771f') - def test_get_user(self): - # Get a user detail - user = self.users_client.show_user(self.users[0]['id'])['user'] - self.assertEqual(self.users[0]['id'], user['id']) - self.assertEqual(self.users[0]['name'], user['name']) - self.assertEqual(self.alt_email, user['email']) - self.assertEqual(self.domain['id'], user['domain_id']) diff --git a/tempest/api/identity/admin/v3/test_oauth_consumers.py b/tempest/api/identity/admin/v3/test_oauth_consumers.py deleted file mode 100644 index f06fb8f5f..000000000 --- a/tempest/api/identity/admin/v3/test_oauth_consumers.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 tempest.api.identity import base -from tempest.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as exceptions - - -class OAUTHConsumersV3Test(base.BaseIdentityV3AdminTest): - - def _create_consumer(self): - """Creates a consumer with a random description.""" - description = data_utils.rand_name('test_create_consumer') - consumer = self.oauth_consumers_client.create_consumer( - description)['consumer'] - # cleans up created consumers after tests - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.oauth_consumers_client.delete_consumer, - consumer['id']) - return consumer - - @decorators.idempotent_id('c8307ea6-a86c-47fd-ae7b-5b3b2caca76d') - def test_create_and_show_consumer(self): - """Tests to make sure that a consumer with parameters is made""" - consumer = self._create_consumer() - # fetch created consumer from client - fetched_consumer = self.oauth_consumers_client.show_consumer( - consumer['id'])['consumer'] - # assert that the fetched consumer matches the created one and - # has all parameters - for key in ['description', 'id', 'links']: - self.assertEqual(consumer[key], fetched_consumer[key]) - - @decorators.idempotent_id('fdfa1b7f-2a31-4354-b2c7-f6ae20554f93') - def test_delete_consumer(self): - """Tests the delete function.""" - consumer = self._create_consumer() - # fetch consumer from client to confirm it exists - fetched_consumer = self.oauth_consumers_client.show_consumer( - consumer['id'])['consumer'] - self.assertEqual(consumer['id'], fetched_consumer['id']) - # delete existing consumer - self.oauth_consumers_client.delete_consumer(consumer['id']) - # check that consumer no longer exists - self.assertRaises(exceptions.NotFound, - self.oauth_consumers_client.show_consumer, - consumer['id']) - - @decorators.idempotent_id('080a9b1a-c009-47c0-9979-5305bf72e3dc') - def test_update_consumer(self): - """Tests the update functionality""" - # create a new consumer to update - consumer = self._create_consumer() - # create new description - new_description = data_utils.rand_name('test_update_consumer') - # update consumer - self.oauth_consumers_client.update_consumer(consumer['id'], - new_description) - # check that the same consumer now has the new description - updated_consumer = self.oauth_consumers_client.show_consumer( - consumer['id'])['consumer'] - self.assertEqual(new_description, updated_consumer['description']) - - @decorators.idempotent_id('09ca50de-78f2-4ffb-ac71-f2254036b2b8') - def test_list_consumers(self): - """Test for listing consumers""" - # create two consumers to populate list - new_consumer_one = self._create_consumer() - new_consumer_two = self._create_consumer() - # fetch the list of consumers - consumer_list = self.oauth_consumers_client \ - .list_consumers()['consumers'] - # add fetched consumer ids to a list - id_list = [consumer['id'] for consumer in consumer_list] - # check if created consumers are in the list - self.assertIn(new_consumer_one['id'], id_list) - self.assertIn(new_consumer_two['id'], id_list) diff --git a/tempest/api/identity/admin/v3/test_policies.py b/tempest/api/identity/admin/v3/test_policies.py deleted file mode 100644 index 960e2cb12..000000000 --- a/tempest/api/identity/admin/v3/test_policies.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class PoliciesTestJSON(base.BaseIdentityV3AdminTest): - - def _delete_policy(self, policy_id): - self.policies_client.delete_policy(policy_id) - - @decorators.idempotent_id('1a0ad286-2d06-4123-ab0d-728893a76201') - def test_list_policies(self): - # Test to list policies - policy_ids = list() - fetched_ids = list() - for _ in range(3): - blob = data_utils.rand_name('BlobName') - policy_type = data_utils.rand_name('PolicyType') - policy = self.policies_client.create_policy( - blob=blob, type=policy_type)['policy'] - # Delete the Policy at the end of this method - self.addCleanup(self._delete_policy, policy['id']) - policy_ids.append(policy['id']) - # List and Verify Policies - body = self.policies_client.list_policies()['policies'] - for p in body: - fetched_ids.append(p['id']) - missing_pols = [p for p in policy_ids if p not in fetched_ids] - self.assertEmpty(missing_pols) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('e544703a-2f03-4cf2-9b0f-350782fdb0d3') - def test_create_update_delete_policy(self): - # Test to update policy - blob = data_utils.rand_name('BlobName') - policy_type = data_utils.rand_name('PolicyType') - policy = self.policies_client.create_policy(blob=blob, - type=policy_type)['policy'] - self.addCleanup(self._delete_policy, policy['id']) - self.assertIn('id', policy) - self.assertIn('type', policy) - self.assertIn('blob', policy) - self.assertIsNotNone(policy['id']) - self.assertEqual(blob, policy['blob']) - self.assertEqual(policy_type, policy['type']) - # Update policy - update_type = data_utils.rand_name('UpdatedPolicyType') - data = self.policies_client.update_policy( - policy['id'], type=update_type)['policy'] - self.assertIn('type', data) - # Assertion for updated value with fetched value - fetched_policy = self.policies_client.show_policy( - policy['id'])['policy'] - self.assertIn('id', fetched_policy) - self.assertIn('blob', fetched_policy) - self.assertIn('type', fetched_policy) - self.assertEqual(fetched_policy['id'], policy['id']) - self.assertEqual(fetched_policy['blob'], policy['blob']) - self.assertEqual(update_type, fetched_policy['type']) diff --git a/tempest/api/identity/admin/v3/test_projects.py b/tempest/api/identity/admin/v3/test_projects.py deleted file mode 100644 index 1b1d3f702..000000000 --- a/tempest/api/identity/admin/v3/test_projects.py +++ /dev/null @@ -1,207 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 tempest.api.identity import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class ProjectsTestJSON(base.BaseIdentityV3AdminTest): - - @decorators.idempotent_id('0ecf465c-0dc4-4532-ab53-91ffeb74d12d') - def test_project_create_with_description(self): - # Create project with a description - project_desc = data_utils.rand_name('desc') - project = self.setup_test_project(description=project_desc) - project_id = project['id'] - desc1 = project['description'] - self.assertEqual(desc1, project_desc, 'Description should have ' - 'been sent in response for create') - body = self.projects_client.show_project(project_id)['project'] - desc2 = body['description'] - self.assertEqual(desc2, project_desc, 'Description does not appear' - 'to be set') - - @decorators.idempotent_id('5f50fe07-8166-430b-a882-3b2ee0abe26f') - def test_project_create_with_domain(self): - # Create project with a domain - domain = self.setup_test_domain() - project_name = data_utils.rand_name('project') - project = self.setup_test_project( - name=project_name, domain_id=domain['id']) - project_id = project['id'] - self.assertEqual(project_name, project['name']) - self.assertEqual(domain['id'], project['domain_id']) - body = self.projects_client.show_project(project_id)['project'] - self.assertEqual(project_name, body['name']) - self.assertEqual(domain['id'], body['domain_id']) - - @decorators.idempotent_id('1854f9c0-70bc-4d11-a08a-1c789d339e3d') - def test_project_create_with_parent(self): - # Create root project without providing a parent_id - domain = self.setup_test_domain() - domain_id = domain['id'] - - root_project_name = data_utils.rand_name('root_project') - root_project = self.setup_test_project( - name=root_project_name, domain_id=domain_id) - - root_project_id = root_project['id'] - parent_id = root_project['parent_id'] - self.assertEqual(root_project_name, root_project['name']) - # If not provided, the parent_id must point to the top level - # project in the hierarchy, i.e. its domain - self.assertEqual(domain_id, parent_id) - - # Create a project using root_project_id as parent_id - project_name = data_utils.rand_name('project') - project = self.setup_test_project( - name=project_name, domain_id=domain_id, parent_id=root_project_id) - parent_id = project['parent_id'] - self.assertEqual(project_name, project['name']) - self.assertEqual(root_project_id, parent_id) - - @decorators.idempotent_id('a7eb9416-6f9b-4dbb-b71b-7f73aaef59d5') - def test_create_is_domain_project(self): - project = self.setup_test_project(domain_id=None, is_domain=True) - # To delete a domain, we need to disable it first - self.addCleanup(self.projects_client.update_project, project['id'], - enabled=False) - - # Check if the is_domain project is correctly returned by both - # project and domain APIs - projects_list = self.projects_client.list_projects( - params={'is_domain': True})['projects'] - self.assertIn(project, projects_list) - - # The domains API return different attributes for the entity, so we - # compare the entities IDs - domains_ids = [d['id'] for d in self.domains_client.list_domains()[ - 'domains']] - self.assertIn(project['id'], domains_ids) - - @decorators.idempotent_id('1f66dc76-50cc-4741-a200-af984509e480') - def test_project_create_enabled(self): - # Create a project that is enabled - project = self.setup_test_project(enabled=True) - project_id = project['id'] - en1 = project['enabled'] - self.assertTrue(en1, 'Enable should be True in response') - body = self.projects_client.show_project(project_id)['project'] - en2 = body['enabled'] - self.assertTrue(en2, 'Enable should be True in lookup') - - @decorators.idempotent_id('78f96a9c-e0e0-4ee6-a3ba-fbf6dfd03207') - def test_project_create_not_enabled(self): - # Create a project that is not enabled - project = self.setup_test_project(enabled=False) - en1 = project['enabled'] - self.assertEqual('false', str(en1).lower(), - 'Enable should be False in response') - body = self.projects_client.show_project(project['id'])['project'] - en2 = body['enabled'] - self.assertEqual('false', str(en2).lower(), - 'Enable should be False in lookup') - - @decorators.idempotent_id('f608f368-048c-496b-ad63-d286c26dab6b') - def test_project_update_name(self): - # Update name attribute of a project - p_name1 = data_utils.rand_name('project') - project = self.setup_test_project(name=p_name1) - - resp1_name = project['name'] - - p_name2 = data_utils.rand_name('project2') - body = self.projects_client.update_project(project['id'], - name=p_name2)['project'] - resp2_name = body['name'] - self.assertNotEqual(resp1_name, resp2_name) - - body = self.projects_client.show_project(project['id'])['project'] - resp3_name = body['name'] - - self.assertNotEqual(resp1_name, resp3_name) - self.assertEqual(p_name1, resp1_name) - self.assertEqual(resp2_name, resp3_name) - - @decorators.idempotent_id('f138b715-255e-4a7d-871d-351e1ef2e153') - def test_project_update_desc(self): - # Update description attribute of a project - p_desc = data_utils.rand_name('desc') - project = self.setup_test_project(description=p_desc) - resp1_desc = project['description'] - - p_desc2 = data_utils.rand_name('desc2') - body = self.projects_client.update_project( - project['id'], description=p_desc2)['project'] - resp2_desc = body['description'] - self.assertNotEqual(resp1_desc, resp2_desc) - - body = self.projects_client.show_project(project['id'])['project'] - resp3_desc = body['description'] - - self.assertNotEqual(resp1_desc, resp3_desc) - self.assertEqual(p_desc, resp1_desc) - self.assertEqual(resp2_desc, resp3_desc) - - @decorators.idempotent_id('b6b25683-c97f-474d-a595-55d410b68100') - def test_project_update_enable(self): - # Update the enabled attribute of a project - p_en = False - project = self.setup_test_project(enabled=p_en) - - resp1_en = project['enabled'] - - p_en2 = True - body = self.projects_client.update_project(project['id'], - enabled=p_en2)['project'] - resp2_en = body['enabled'] - self.assertNotEqual(resp1_en, resp2_en) - - body = self.projects_client.show_project(project['id'])['project'] - resp3_en = body['enabled'] - - self.assertNotEqual(resp1_en, resp3_en) - self.assertEqual('false', str(resp1_en).lower()) - self.assertEqual(resp2_en, resp3_en) - - @decorators.idempotent_id('59398d4a-5dc5-4f86-9a4c-c26cc804d6c6') - def test_associate_user_to_project(self): - # Associate a user to a project - # Create a Project - project = self.setup_test_project() - - # Create a User - u_name = data_utils.rand_name('user') - u_desc = u_name + 'description' - u_email = u_name + '@testmail.tm' - u_password = data_utils.rand_password() - user = self.users_client.create_user( - name=u_name, description=u_desc, password=u_password, - email=u_email, project_id=project['id'])['user'] - # Delete the User at the end of this method - self.addCleanup(self.users_client.delete_user, user['id']) - - # Get User To validate the user details - new_user_get = self.users_client.show_user(user['id'])['user'] - # Assert response body of GET - self.assertEqual(u_name, new_user_get['name']) - self.assertEqual(u_desc, new_user_get['description']) - self.assertEqual(project['id'], - new_user_get['project_id']) - self.assertEqual(u_email, new_user_get['email']) diff --git a/tempest/api/identity/admin/v3/test_projects_negative.py b/tempest/api/identity/admin/v3/test_projects_negative.py deleted file mode 100644 index 33a9c8cda..000000000 --- a/tempest/api/identity/admin/v3/test_projects_negative.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ProjectsNegativeTestJSON(base.BaseIdentityV3AdminTest): - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('24c49279-45dd-4155-887a-cb738c2385aa') - def test_list_projects_by_unauthorized_user(self): - # Non-admin user should not be able to list projects - self.assertRaises(lib_exc.Forbidden, - self.non_admin_projects_client.list_projects) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('874c3e84-d174-4348-a16b-8c01f599561b') - def test_project_create_duplicate(self): - # Project names should be unique - project_name = data_utils.rand_name('project-dup') - self.setup_test_project(name=project_name) - - self.assertRaises(lib_exc.Conflict, - self.projects_client.create_project, project_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('8fba9de2-3e1f-4e77-812a-60cb68f8df13') - def test_create_project_by_unauthorized_user(self): - # Non-admin user should not be authorized to create a project - project_name = data_utils.rand_name('project') - self.assertRaises( - lib_exc.Forbidden, self.non_admin_projects_client.create_project, - project_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7828db17-95e5-475b-9432-9a51b4aa79a9') - def test_create_project_with_empty_name(self): - # Project name should not be empty - self.assertRaises(lib_exc.BadRequest, - self.projects_client.create_project, name='') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('502b6ceb-b0c8-4422-bf53-f08fdb21e2f0') - def test_create_projects_name_length_over_64(self): - # Project name length should not be greater than 64 characters - project_name = 'a' * 65 - self.assertRaises(lib_exc.BadRequest, - self.projects_client.create_project, project_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('8d68c012-89e0-4394-8d6b-ccd7196def97') - def test_project_delete_by_unauthorized_user(self): - # Non-admin user should not be able to delete a project - project = self.setup_test_project() - self.assertRaises( - lib_exc.Forbidden, self.non_admin_projects_client.delete_project, - project['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7965b581-60c1-43b7-8169-95d4ab7fc6fb') - def test_delete_non_existent_project(self): - # Attempt to delete a non existent project should fail - self.assertRaises(lib_exc.NotFound, - self.projects_client.delete_project, - data_utils.rand_uuid_hex()) diff --git a/tempest/api/identity/admin/v3/test_regions.py b/tempest/api/identity/admin/v3/test_regions.py deleted file mode 100644 index d00e40811..000000000 --- a/tempest/api/identity/admin/v3/test_regions.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P -# 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 tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - - -class RegionsTestJSON(base.BaseIdentityV3AdminTest): - - @classmethod - def setup_clients(cls): - super(RegionsTestJSON, cls).setup_clients() - cls.client = cls.regions_client - - @classmethod - def resource_setup(cls): - super(RegionsTestJSON, cls).resource_setup() - cls.setup_regions = list() - for _ in range(2): - r_description = data_utils.rand_name('description') - region = cls.client.create_region( - description=r_description)['region'] - cls.setup_regions.append(region) - - @classmethod - def resource_cleanup(cls): - for r in cls.setup_regions: - cls.client.delete_region(r['id']) - super(RegionsTestJSON, cls).resource_cleanup() - - @decorators.idempotent_id('56186092-82e4-43f2-b954-91013218ba42') - def test_create_update_get_delete_region(self): - # Create region - r_description = data_utils.rand_name('description') - region = self.client.create_region( - description=r_description, - parent_region_id=self.setup_regions[0]['id'])['region'] - # This test will delete the region as part of the validation - # procedure, so it needs a different cleanup method that - # would be useful in case the tests fails at any point before - # reaching the deletion part. - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.client.delete_region, region['id']) - self.assertEqual(r_description, region['description']) - self.assertEqual(self.setup_regions[0]['id'], - region['parent_region_id']) - # Update region with new description and parent ID - r_alt_description = data_utils.rand_name('description') - region = self.client.update_region( - region['id'], - description=r_alt_description, - parent_region_id=self.setup_regions[1]['id'])['region'] - self.assertEqual(r_alt_description, region['description']) - self.assertEqual(self.setup_regions[1]['id'], - region['parent_region_id']) - # Get the details of region - region = self.client.show_region(region['id'])['region'] - self.assertEqual(r_alt_description, region['description']) - self.assertEqual(self.setup_regions[1]['id'], - region['parent_region_id']) - # Delete the region - self.client.delete_region(region['id']) - body = self.client.list_regions()['regions'] - regions_list = [r['id'] for r in body] - self.assertNotIn(region['id'], regions_list) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('2c12c5b5-efcf-4aa5-90c5-bff1ab0cdbe2') - def test_create_region_with_specific_id(self): - # Create a region with a specific id - r_region_id = data_utils.rand_uuid() - r_description = data_utils.rand_name('description') - region = self.client.create_region( - region_id=r_region_id, description=r_description)['region'] - self.addCleanup(self.client.delete_region, region['id']) - # Asserting Create Region with specific id response body - self.assertEqual(r_region_id, region['id']) - self.assertEqual(r_description, region['description']) - - @decorators.idempotent_id('d180bf99-544a-445c-ad0d-0c0d27663796') - def test_list_regions(self): - # Get a list of regions - fetched_regions = self.client.list_regions()['regions'] - missing_regions =\ - [e for e in self.setup_regions if e not in fetched_regions] - # Asserting List Regions response - self.assertEmpty(missing_regions, - "Failed to find region %s in fetched list" % - ', '.join(str(e) for e in missing_regions)) - - @decorators.idempotent_id('2d1057cb-bbde-413a-acdf-e2d265284542') - def test_list_regions_filter_by_parent_region_id(self): - # Add a sub-region to one of the existing test regions - r_description = data_utils.rand_name('description') - region = self.client.create_region( - description=r_description, - parent_region_id=self.setup_regions[0]['id'])['region'] - self.addCleanup(self.client.delete_region, region['id']) - # Get the list of regions filtering with the parent_region_id - params = {'parent_region_id': self.setup_regions[0]['id']} - fetched_regions = self.client.list_regions(params=params)['regions'] - # Asserting list regions response - self.assertIn(region, fetched_regions) - for r in fetched_regions: - self.assertEqual(self.setup_regions[0]['id'], - r['parent_region_id']) diff --git a/tempest/api/identity/admin/v3/test_roles.py b/tempest/api/identity/admin/v3/test_roles.py deleted file mode 100644 index 6d42b2afa..000000000 --- a/tempest/api/identity/admin/v3/test_roles.py +++ /dev/null @@ -1,435 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 tempest.api.identity import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class RolesV3TestJSON(base.BaseIdentityV3AdminTest): - - @classmethod - def resource_setup(cls): - super(RolesV3TestJSON, cls).resource_setup() - cls.roles = list() - for _ in range(3): - role_name = data_utils.rand_name(name='role') - role = cls.roles_client.create_role(name=role_name)['role'] - cls.roles.append(role) - cls.fetched_role_ids = list() - u_name = data_utils.rand_name('user') - u_desc = '%s description' % u_name - u_email = '%s@testmail.tm' % u_name - cls.u_password = data_utils.rand_password() - cls.domain = cls.create_domain() - cls.project = cls.projects_client.create_project( - data_utils.rand_name('project'), - description=data_utils.rand_name('project-desc'), - domain_id=cls.domain['id'])['project'] - cls.group_body = cls.groups_client.create_group( - name=data_utils.rand_name('Group'), project_id=cls.project['id'], - domain_id=cls.domain['id'])['group'] - cls.user_body = cls.users_client.create_user( - name=u_name, description=u_desc, password=cls.u_password, - email=u_email, project_id=cls.project['id'], - domain_id=cls.domain['id'])['user'] - cls.role = cls.roles_client.create_role( - name=data_utils.rand_name('Role'))['role'] - - @classmethod - def resource_cleanup(cls): - cls.roles_client.delete_role(cls.role['id']) - cls.groups_client.delete_group(cls.group_body['id']) - cls.users_client.delete_user(cls.user_body['id']) - cls.projects_client.delete_project(cls.project['id']) - # NOTE(harika-vakadi): It is necessary to disable the domain - # before deleting,or else it would result in unauthorized error - cls.domains_client.update_domain(cls.domain['id'], enabled=False) - cls.domains_client.delete_domain(cls.domain['id']) - for role in cls.roles: - cls.roles_client.delete_role(role['id']) - super(RolesV3TestJSON, cls).resource_cleanup() - - def _list_assertions(self, body, fetched_role_ids, role_id): - self.assertEqual(len(body), 1) - self.assertIn(role_id, fetched_role_ids) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('18afc6c0-46cf-4911-824e-9989cc056c3a') - def test_role_create_update_show_list(self): - r_name = data_utils.rand_name('Role') - role = self.roles_client.create_role(name=r_name)['role'] - self.addCleanup(self.roles_client.delete_role, role['id']) - self.assertIn('name', role) - self.assertEqual(role['name'], r_name) - - new_name = data_utils.rand_name('NewRole') - updated_role = self.roles_client.update_role(role['id'], - name=new_name)['role'] - self.assertIn('name', updated_role) - self.assertIn('id', updated_role) - self.assertIn('links', updated_role) - self.assertNotEqual(r_name, updated_role['name']) - - new_role = self.roles_client.show_role(role['id'])['role'] - self.assertEqual(new_name, new_role['name']) - self.assertEqual(updated_role['id'], new_role['id']) - - roles = self.roles_client.list_roles()['roles'] - self.assertIn(role['id'], [r['id'] for r in roles]) - - @decorators.idempotent_id('c6b80012-fe4a-498b-9ce8-eb391c05169f') - def test_grant_list_revoke_role_to_user_on_project(self): - self.roles_client.create_user_role_on_project(self.project['id'], - self.user_body['id'], - self.role['id']) - - roles = self.roles_client.list_user_roles_on_project( - self.project['id'], self.user_body['id'])['roles'] - - for i in roles: - self.fetched_role_ids.append(i['id']) - - self._list_assertions(roles, self.fetched_role_ids, - self.role['id']) - - self.roles_client.check_user_role_existence_on_project( - self.project['id'], self.user_body['id'], self.role['id']) - - self.roles_client.delete_role_from_user_on_project( - self.project['id'], self.user_body['id'], self.role['id']) - - @decorators.idempotent_id('6c9a2940-3625-43a3-ac02-5dcec62ef3bd') - def test_grant_list_revoke_role_to_user_on_domain(self): - self.roles_client.create_user_role_on_domain( - self.domain['id'], self.user_body['id'], self.role['id']) - - roles = self.roles_client.list_user_roles_on_domain( - self.domain['id'], self.user_body['id'])['roles'] - - for i in roles: - self.fetched_role_ids.append(i['id']) - - self._list_assertions(roles, self.fetched_role_ids, - self.role['id']) - - self.roles_client.check_user_role_existence_on_domain( - self.domain['id'], self.user_body['id'], self.role['id']) - - self.roles_client.delete_role_from_user_on_domain( - self.domain['id'], self.user_body['id'], self.role['id']) - - @decorators.idempotent_id('cbf11737-1904-4690-9613-97bcbb3df1c4') - def test_grant_list_revoke_role_to_group_on_project(self): - # Grant role to group on project - self.roles_client.create_group_role_on_project( - self.project['id'], self.group_body['id'], self.role['id']) - # List group roles on project - roles = self.roles_client.list_group_roles_on_project( - self.project['id'], self.group_body['id'])['roles'] - - for i in roles: - self.fetched_role_ids.append(i['id']) - - self._list_assertions(roles, self.fetched_role_ids, - self.role['id']) - # Add user to group, and insure user has role on project - self.groups_client.add_group_user(self.group_body['id'], - self.user_body['id']) - self.addCleanup(self.groups_client.delete_group_user, - self.group_body['id'], self.user_body['id']) - body = self.token.auth(user_id=self.user_body['id'], - password=self.u_password, - user_domain_name=self.domain['name'], - project_name=self.project['name'], - project_domain_name=self.domain['name']) - roles = body['token']['roles'] - self.assertEqual(len(roles), 1) - self.assertEqual(roles[0]['id'], self.role['id']) - - self.roles_client.check_role_from_group_on_project_existence( - self.project['id'], self.group_body['id'], self.role['id']) - - # Revoke role to group on project - self.roles_client.delete_role_from_group_on_project( - self.project['id'], self.group_body['id'], self.role['id']) - - @decorators.idempotent_id('4bf8a70b-e785-413a-ad53-9f91ce02faa7') - def test_grant_list_revoke_role_to_group_on_domain(self): - self.roles_client.create_group_role_on_domain( - self.domain['id'], self.group_body['id'], self.role['id']) - - roles = self.roles_client.list_group_roles_on_domain( - self.domain['id'], self.group_body['id'])['roles'] - - for i in roles: - self.fetched_role_ids.append(i['id']) - - self._list_assertions(roles, self.fetched_role_ids, - self.role['id']) - - self.roles_client.check_role_from_group_on_domain_existence( - self.domain['id'], self.group_body['id'], self.role['id']) - - self.roles_client.delete_role_from_group_on_domain( - self.domain['id'], self.group_body['id'], self.role['id']) - - @decorators.idempotent_id('f5654bcc-08c4-4f71-88fe-05d64e06de94') - def test_list_roles(self): - # Return a list of all roles - body = self.roles_client.list_roles()['roles'] - found = [role for role in body if role in self.roles] - self.assertEqual(len(found), len(self.roles)) - - def _create_implied_role(self, prior_role_id, implies_role_id, - ignore_not_found=False): - self.roles_client.create_role_inference_rule( - prior_role_id, implies_role_id) - if ignore_not_found: - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.roles_client.delete_role_inference_rule, - prior_role_id, - implies_role_id) - else: - self.addCleanup( - self.roles_client.delete_role_inference_rule, - prior_role_id, - implies_role_id) - - @decorators.idempotent_id('c90c316c-d706-4728-bcba-eb1912081b69') - def test_implied_roles_create_check_show_delete(self): - prior_role_id = self.roles[0]['id'] - implies_role_id = self.roles[1]['id'] - - # Create an inference rule from prior_role to implies_role - self._create_implied_role(prior_role_id, implies_role_id, - ignore_not_found=True) - - # Check if the inference rule exists - self.roles_client.check_role_inference_rule( - prior_role_id, implies_role_id) - - # Show the inference rule and check its elements - resp_body = self.roles_client.show_role_inference_rule( - prior_role_id, implies_role_id) - self.assertIn('role_inference', resp_body) - role_inference = resp_body['role_inference'] - for key1 in ['prior_role', 'implies']: - self.assertIn(key1, role_inference) - for key2 in ['id', 'links', 'name']: - self.assertIn(key2, role_inference[key1]) - - # Delete the inference rule - self.roles_client.delete_role_inference_rule( - prior_role_id, implies_role_id) - # Check if the inference rule no longer exists - self.assertRaises( - lib_exc.NotFound, - self.roles_client.show_role_inference_rule, - prior_role_id, - implies_role_id) - - @decorators.idempotent_id('dc6f5959-b74d-4e30-a9e5-a8255494ff00') - def test_roles_hierarchy(self): - # Create inference rule from "roles[0]" to "role[1]" - self._create_implied_role( - self.roles[0]['id'], self.roles[1]['id']) - - # Create inference rule from "roles[0]" to "role[2]" - self._create_implied_role( - self.roles[0]['id'], self.roles[2]['id']) - - # Create inference rule from "roles[2]" to "role" - self._create_implied_role( - self.roles[2]['id'], self.role['id']) - - # Listing inferences rules from "roles[2]" should only return "role" - rules = self.roles_client.list_role_inferences_rules( - self.roles[2]['id'])['role_inference'] - self.assertEqual(1, len(rules['implies'])) - self.assertEqual(self.role['id'], rules['implies'][0]['id']) - - # Listing inferences rules from "roles[0]" should return "roles[1]" and - # "roles[2]" (only direct rules are listed) - rules = self.roles_client.list_role_inferences_rules( - self.roles[0]['id'])['role_inference'] - implies_ids = [role['id'] for role in rules['implies']] - self.assertEqual(2, len(implies_ids)) - self.assertIn(self.roles[1]['id'], implies_ids) - self.assertIn(self.roles[2]['id'], implies_ids) - - @decorators.idempotent_id('c8828027-df48-4021-95df-b65b92c7429e') - def test_assignments_for_implied_roles_create_delete(self): - # Create a grant using "roles[0]" - self.roles_client.create_user_role_on_project( - self.project['id'], self.user_body['id'], self.roles[0]['id']) - self.addCleanup( - self.roles_client.delete_role_from_user_on_project, - self.project['id'], self.user_body['id'], self.roles[0]['id']) - - # Create an inference rule from "roles[0]" to "roles[1]" - self._create_implied_role(self.roles[0]['id'], self.roles[1]['id'], - ignore_not_found=True) - - # In the effective list of role assignments, both prior role and - # implied role should be present. This means that a user can - # authenticate using both roles (both roles will be present - # in the token). - params = {'scope.project.id': self.project['id'], - 'user.id': self.user_body['id']} - role_assignments = self.role_assignments.list_role_assignments( - effective=True, **params)['role_assignments'] - self.assertEqual(2, len(role_assignments)) - - roles_ids = [assignment['role']['id'] - for assignment in role_assignments] - self.assertIn(self.roles[0]['id'], roles_ids) - self.assertIn(self.roles[1]['id'], roles_ids) - - # After deleting the implied role, only the assignment with "roles[0]" - # should be present. - self.roles_client.delete_role_inference_rule( - self.roles[0]['id'], self.roles[1]['id']) - - role_assignments = self.role_assignments.list_role_assignments( - effective=True, **params)['role_assignments'] - self.assertEqual(1, len(role_assignments)) - - roles_ids = [assignment['role']['id'] - for assignment in role_assignments] - self.assertIn(self.roles[0]['id'], roles_ids) - - @decorators.idempotent_id('d92a41d2-5501-497a-84bb-6e294330e8f8') - def test_domain_roles_create_delete(self): - domain_role = self.roles_client.create_role( - name=data_utils.rand_name('domain_role'), - domain_id=self.domain['id'])['role'] - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.roles_client.delete_role, - domain_role['id']) - - domain_roles = self.roles_client.list_roles( - domain_id=self.domain['id'])['roles'] - self.assertEqual(1, len(domain_roles)) - self.assertIn(domain_role, domain_roles) - - self.roles_client.delete_role(domain_role['id']) - domain_roles = self.roles_client.list_roles( - domain_id=self.domain['id'])['roles'] - self.assertEmpty(domain_roles) - - @decorators.idempotent_id('eb1e1c24-1bc4-4d47-9748-e127a1852c82') - def test_implied_domain_roles(self): - # Create two roles in the same domain - domain_role1 = self.setup_test_role(domain_id=self.domain['id']) - domain_role2 = self.setup_test_role(domain_id=self.domain['id']) - - # Check if we can create an inference rule from roles in the same - # domain - self._create_implied_role(domain_role1['id'], domain_role2['id']) - - # Create another role in a different domain - domain2 = self.setup_test_domain() - domain_role3 = self.setup_test_role(domain_id=domain2['id']) - - # Check if we can create cross domain implied roles - self._create_implied_role(domain_role1['id'], domain_role3['id']) - - # Finally, we also should be able to create an implied from a - # domain role to a global one - self._create_implied_role(domain_role1['id'], self.role['id']) - - if CONF.identity_feature_enabled.forbid_global_implied_dsr: - # The contrary is not true: we can't create an inference rule - # from a global role to a domain role - self.assertRaises( - lib_exc.Forbidden, - self.roles_client.create_role_inference_rule, - self.role['id'], - domain_role1['id']) - - @decorators.idempotent_id('3859df7e-5b78-4e4d-b10e-214c8953842a') - def test_assignments_for_domain_roles(self): - domain_role = self.setup_test_role(domain_id=self.domain['id']) - - # Create a grant using "domain_role" - self.roles_client.create_user_role_on_project( - self.project['id'], self.user_body['id'], domain_role['id']) - self.addCleanup( - self.roles_client.delete_role_from_user_on_project, - self.project['id'], self.user_body['id'], domain_role['id']) - - # NOTE(rodrigods): Regular roles would appear in the effective - # list of role assignments (meaning the role would be returned in - # a token) as a result from the grant above. This is not the case - # for domain roles, they should not appear in the effective role - # assignments list. - params = {'scope.project.id': self.project['id'], - 'user.id': self.user_body['id']} - role_assignments = self.role_assignments.list_role_assignments( - effective=True, **params)['role_assignments'] - self.assertEmpty(role_assignments) - - @decorators.idempotent_id('3748c316-c18f-4b08-997b-c60567bc6235') - def test_list_all_implied_roles(self): - # Create inference rule from "roles[0]" to "roles[1]" - self._create_implied_role( - self.roles[0]['id'], self.roles[1]['id']) - - # Create inference rule from "roles[0]" to "roles[2]" - self._create_implied_role( - self.roles[0]['id'], self.roles[2]['id']) - - # Create inference rule from "roles[2]" to "role" - self._create_implied_role( - self.roles[2]['id'], self.role['id']) - - rules = self.roles_client.list_all_role_inference_rules()[ - 'role_inferences'] - # Sort the rules by the number of inferences, since there should be 1 - # inference between "roles[2]" and "role" and 2 inferences for - # "roles[0]": between "roles[1]" and "roles[2]". - sorted_rules = sorted(rules, key=lambda r: len(r['implies'])) - - # Check that 2 sets of rules are returned. - self.assertEqual(2, len(sorted_rules)) - # Check that only 1 inference rule exists between "roles[2]" and "role" - self.assertEqual(1, len(sorted_rules[0]['implies'])) - # Check that 2 inference rules exist for "roles[0]": one between - # "roles[1]" and one between "roles[2]". - self.assertEqual(2, len(sorted_rules[1]['implies'])) - - # Check that "roles[2]" is the "prior_role" and that "role" is the - # "implies" role. - self.assertEqual(self.roles[2]['id'], - sorted_rules[0]['prior_role']['id']) - self.assertEqual(self.role['id'], - sorted_rules[0]['implies'][0]['id']) - - # Check that "roles[0]" is the "prior_role" and that "roles[1]" and - # "roles[2]" are the "implies" roles. - self.assertEqual(self.roles[0]['id'], - sorted_rules[1]['prior_role']['id']) - - implies_ids = [r['id'] for r in sorted_rules[1]['implies']] - self.assertIn(self.roles[1]['id'], implies_ids) - self.assertIn(self.roles[2]['id'], implies_ids) diff --git a/tempest/api/identity/admin/v3/test_services.py b/tempest/api/identity/admin/v3/test_services.py deleted file mode 100644 index 20c8a4456..000000000 --- a/tempest/api/identity/admin/v3/test_services.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ServicesTestJSON(base.BaseIdentityV3AdminTest): - - def _del_service(self, service_id): - # Used for deleting the services created in this class - self.services_client.delete_service(service_id) - # Checking whether service is deleted successfully - self.assertRaises(lib_exc.NotFound, self.services_client.show_service, - service_id) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('5193aad5-bcb7-411d-85b0-b3b61b96ef06') - def test_create_update_get_service(self): - # Creating a Service - name = data_utils.rand_name('service') - serv_type = data_utils.rand_name('type') - desc = data_utils.rand_name('description') - create_service = self.services_client.create_service( - type=serv_type, name=name, description=desc)['service'] - self.addCleanup(self._del_service, create_service['id']) - self.assertIsNotNone(create_service['id']) - - # Verifying response body of create service - expected_data = {'name': name, 'type': serv_type, 'description': desc} - self.assertDictContainsSubset(expected_data, create_service) - - # Update description - s_id = create_service['id'] - resp1_desc = create_service['description'] - s_desc2 = data_utils.rand_name('desc2') - update_service = self.services_client.update_service( - s_id, description=s_desc2)['service'] - resp2_desc = update_service['description'] - - self.assertNotEqual(resp1_desc, resp2_desc) - - # Get service - fetched_service = self.services_client.show_service(s_id)['service'] - resp3_desc = fetched_service['description'] - - self.assertEqual(resp2_desc, resp3_desc) - self.assertDictContainsSubset(update_service, fetched_service) - - @decorators.idempotent_id('d1dcb1a1-2b6b-4da8-bbb8-5532ef6e8269') - def test_create_service_without_description(self): - # Create a service only with name and type - name = data_utils.rand_name('service') - serv_type = data_utils.rand_name('type') - service = self.services_client.create_service( - type=serv_type, name=name)['service'] - self.addCleanup(self.services_client.delete_service, service['id']) - self.assertIn('id', service) - expected_data = {'name': name, 'type': serv_type} - self.assertDictContainsSubset(expected_data, service) - - @decorators.idempotent_id('e55908e8-360e-439e-8719-c3230a3e179e') - def test_list_services(self): - # Create, List, Verify and Delete Services - service_ids = list() - service_types = list() - for _ in range(3): - name = data_utils.rand_name(self.__class__.__name__ + '-Service') - serv_type = data_utils.rand_name(self.__class__.__name__ + '-Type') - create_service = self.services_client.create_service( - type=serv_type, name=name)['service'] - self.addCleanup(self.services_client.delete_service, - create_service['id']) - service_ids.append(create_service['id']) - service_types.append(serv_type) - - # List and Verify Services - services = self.services_client.list_services()['services'] - fetched_ids = [service['id'] for service in services] - found = [s for s in fetched_ids if s in service_ids] - self.assertEqual(len(found), len(service_ids)) - - # Check that filtering by service type works. - for serv_type in service_types: - fetched_services = self.services_client.list_services( - type=serv_type)['services'] - self.assertEqual(1, len(fetched_services)) - self.assertEqual(serv_type, fetched_services[0]['type']) diff --git a/tempest/api/identity/admin/v3/test_tokens.py b/tempest/api/identity/admin/v3/test_tokens.py deleted file mode 100644 index 5c3cd2667..000000000 --- a/tempest/api/identity/admin/v3/test_tokens.py +++ /dev/null @@ -1,176 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 six - -from tempest.api.identity import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class TokensV3TestJSON(base.BaseIdentityV3AdminTest): - - @decorators.idempotent_id('0f9f5a5f-d5cd-4a86-8a5b-c5ded151f212') - def test_tokens(self): - # Valid user's token is authenticated - # Create a User - u_name = data_utils.rand_name('user') - u_desc = '%s-description' % u_name - u_password = data_utils.rand_password() - user = self.create_test_user( - name=u_name, description=u_desc, password=u_password) - # Perform Authentication - resp = self.token.auth(user_id=user['id'], - password=u_password).response - subject_token = resp['x-subject-token'] - self.client.check_token_existence(subject_token) - # Perform GET Token - token_details = self.client.show_token(subject_token)['token'] - self.assertEqual(resp['x-subject-token'], subject_token) - self.assertEqual(token_details['user']['id'], user['id']) - self.assertEqual(token_details['user']['name'], u_name) - # Perform Delete Token - self.client.delete_token(subject_token) - self.assertRaises(lib_exc.NotFound, self.client.check_token_existence, - subject_token) - - @decorators.idempotent_id('565fa210-1da1-4563-999b-f7b5b67cf112') - def test_rescope_token(self): - """Rescope a token. - - An unscoped token can be requested, that token can be used to request a - scoped token. The scoped token can be revoked, and the original token - used to get a token in a different project. - - """ - - # Create a user. - user_password = data_utils.rand_password() - user = self.create_test_user(password=user_password) - - # Create a couple projects - project1_name = data_utils.rand_name(name='project') - project1 = self.setup_test_project(name=project1_name) - - project2_name = data_utils.rand_name(name='project') - project2 = self.setup_test_project(name=project2_name) - self.addCleanup(self.projects_client.delete_project, project2['id']) - - # Create a role - role = self.setup_test_role() - - # Grant the user the role on both projects. - self.roles_client.create_user_role_on_project(project1['id'], - user['id'], - role['id']) - - self.roles_client.create_user_role_on_project(project2['id'], - user['id'], - role['id']) - - # Get an unscoped token. - token_auth = self.token.auth(user_id=user['id'], - password=user_password) - - token_id = token_auth.response['x-subject-token'] - orig_expires_at = token_auth['token']['expires_at'] - orig_user = token_auth['token']['user'] - - self.assertIsInstance(token_auth['token']['expires_at'], six.text_type) - self.assertIsInstance(token_auth['token']['issued_at'], six.text_type) - self.assertEqual(['password'], token_auth['token']['methods']) - self.assertEqual(user['id'], token_auth['token']['user']['id']) - self.assertEqual(user['name'], token_auth['token']['user']['name']) - self.assertEqual(CONF.identity.default_domain_id, - token_auth['token']['user']['domain']['id']) - self.assertIsNotNone(token_auth['token']['user']['domain']['name']) - self.assertNotIn('catalog', token_auth['token']) - self.assertNotIn('project', token_auth['token']) - self.assertNotIn('roles', token_auth['token']) - - # Use the unscoped token to get a scoped token. - token_auth = self.token.auth( - token=token_id, - project_name=project1_name, - project_domain_id=CONF.identity.default_domain_id) - token1_id = token_auth.response['x-subject-token'] - - self.assertEqual(orig_expires_at, token_auth['token']['expires_at'], - 'Expiration time should match original token') - self.assertIsInstance(token_auth['token']['issued_at'], six.text_type) - self.assertEqual(set(['password', 'token']), - set(token_auth['token']['methods'])) - self.assertEqual(orig_user, token_auth['token']['user'], - 'User should match original token') - self.assertIsInstance(token_auth['token']['catalog'], list) - self.assertEqual(project1['id'], - token_auth['token']['project']['id']) - self.assertEqual(project1['name'], - token_auth['token']['project']['name']) - self.assertEqual(CONF.identity.default_domain_id, - token_auth['token']['project']['domain']['id']) - self.assertIsNotNone(token_auth['token']['project']['domain']['name']) - self.assertEqual(1, len(token_auth['token']['roles'])) - self.assertEqual(role['id'], token_auth['token']['roles'][0]['id']) - self.assertEqual(role['name'], token_auth['token']['roles'][0]['name']) - - # Revoke the unscoped token. - self.client.delete_token(token1_id) - - # Now get another scoped token using the unscoped token. - token_auth = self.token.auth( - token=token_id, - project_name=project2_name, - project_domain_id=CONF.identity.default_domain_id) - - self.assertEqual(project2['id'], - token_auth['token']['project']['id']) - self.assertEqual(project2['name'], - token_auth['token']['project']['name']) - - @decorators.idempotent_id('08ed85ce-2ba8-4864-b442-bcc61f16ae89') - def test_get_available_project_scopes(self): - manager_project_id = self.os_primary.credentials.project_id - admin_user_id = self.os_admin.credentials.user_id - admin_role_id = self.get_role_by_name(CONF.identity.admin_role)['id'] - - # Grant the user the role on both projects. - self.roles_client.create_user_role_on_project( - manager_project_id, admin_user_id, admin_role_id) - self.addCleanup( - self.roles_client.delete_role_from_user_on_project, - manager_project_id, admin_user_id, admin_role_id) - - assigned_project_ids = [self.os_admin.credentials.project_id, - manager_project_id] - - # Get available project scopes - available_projects =\ - self.client.list_auth_projects()['projects'] - - # create list to save fetched project's id - fetched_project_ids = [i['id'] for i in available_projects] - - # verifying the project ids in list - missing_project_ids = \ - [p for p in assigned_project_ids - if p not in fetched_project_ids] - self.assertEmpty(missing_project_ids, - "Failed to find project_id %s in fetched list" % - ', '.join(missing_project_ids)) diff --git a/tempest/api/identity/admin/v3/test_trusts.py b/tempest/api/identity/admin/v3/test_trusts.py deleted file mode 100644 index 3e6a2de7a..000000000 --- a/tempest/api/identity/admin/v3/test_trusts.py +++ /dev/null @@ -1,289 +0,0 @@ -# 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 datetime -import re - -from oslo_utils import timeutils - -from tempest.api.identity import base -from tempest import clients -from tempest.common import credentials_factory as common_creds -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class BaseTrustsV3Test(base.BaseIdentityV3AdminTest): - - def setUp(self): - super(BaseTrustsV3Test, self).setUp() - # Use alt_username as the trustee - if not CONF.identity_feature_enabled.trust: - raise self.skipException("Trusts aren't enabled") - - self.trust_id = None - - def tearDown(self): - if self.trust_id: - # Do the delete in tearDown not addCleanup - we want the test to - # fail in the event there is a bug which causes undeletable trusts - self.delete_trust() - super(BaseTrustsV3Test, self).tearDown() - - def create_trustor_and_roles(self): - # create a project that trusts will be granted on - trustor_project_name = data_utils.rand_name(name='project') - project = self.projects_client.create_project( - trustor_project_name, - domain_id=CONF.identity.default_domain_id)['project'] - self.trustor_project_id = project['id'] - self.assertIsNotNone(self.trustor_project_id) - - # Create a trustor User - trustor_username = data_utils.rand_name('user') - u_desc = trustor_username + 'description' - u_email = trustor_username + '@testmail.xx' - trustor_password = data_utils.rand_password() - user = self.users_client.create_user( - name=trustor_username, - description=u_desc, - password=trustor_password, - email=u_email, - project_id=self.trustor_project_id, - domain_id=CONF.identity.default_domain_id)['user'] - self.trustor_user_id = user['id'] - - # And two roles, one we'll delegate and one we won't - self.delegated_role = data_utils.rand_name('DelegatedRole') - self.not_delegated_role = data_utils.rand_name('NotDelegatedRole') - - role = self.roles_client.create_role(name=self.delegated_role)['role'] - self.delegated_role_id = role['id'] - - role = self.roles_client.create_role( - name=self.not_delegated_role)['role'] - self.not_delegated_role_id = role['id'] - - # Assign roles to trustor - self.roles_client.create_user_role_on_project( - self.trustor_project_id, - self.trustor_user_id, - self.delegated_role_id) - self.roles_client.create_user_role_on_project( - self.trustor_project_id, - self.trustor_user_id, - self.not_delegated_role_id) - - # Get trustee user ID, use the demo user - trustee_username = self.non_admin_client.user - self.trustee_user_id = self.get_user_by_name(trustee_username)['id'] - self.assertIsNotNone(self.trustee_user_id) - - # Initialize a new client with the trustor credentials - creds = common_creds.get_credentials( - identity_version='v3', - username=trustor_username, - password=trustor_password, - user_domain_id=CONF.identity.default_domain_id, - tenant_name=trustor_project_name, - project_domain_id=CONF.identity.default_domain_id, - domain_id=CONF.identity.default_domain_id) - os = clients.Manager(credentials=creds) - self.trustor_client = os.trusts_client - - def cleanup_user_and_roles(self): - if self.trustor_user_id: - self.users_client.delete_user(self.trustor_user_id) - if self.trustor_project_id: - self.projects_client.delete_project(self.trustor_project_id) - if self.delegated_role_id: - self.roles_client.delete_role(self.delegated_role_id) - if self.not_delegated_role_id: - self.roles_client.delete_role(self.not_delegated_role_id) - - def create_trust(self, impersonate=True, expires=None): - - trust_create = self.trustor_client.create_trust( - trustor_user_id=self.trustor_user_id, - trustee_user_id=self.trustee_user_id, - project_id=self.trustor_project_id, - roles=[{'name': self.delegated_role}], - impersonation=impersonate, - expires_at=expires)['trust'] - self.trust_id = trust_create['id'] - return trust_create - - def validate_trust(self, trust, impersonate=True, expires=None, - summary=False): - self.assertIsNotNone(trust['id']) - self.assertEqual(impersonate, trust['impersonation']) - if expires is not None: - # Omit microseconds component of the expiry time - trust_expires_at = re.sub(r'\.([0-9]){6}', '', trust['expires_at']) - self.assertEqual(expires, trust_expires_at) - else: - self.assertIsNone(trust['expires_at']) - self.assertEqual(self.trustor_user_id, trust['trustor_user_id']) - self.assertEqual(self.trustee_user_id, trust['trustee_user_id']) - self.assertIn('v3/OS-TRUST/trusts', trust['links']['self']) - self.assertEqual(self.trustor_project_id, trust['project_id']) - if not summary: - self.assertEqual(self.delegated_role, trust['roles'][0]['name']) - self.assertEqual(1, len(trust['roles'])) - - def show_trust(self): - trust_get = self.trustor_client.show_trust(self.trust_id)['trust'] - return trust_get - - def validate_role(self, role): - self.assertEqual(self.delegated_role_id, role['id']) - self.assertEqual(self.delegated_role, role['name']) - self.assertIn('v3/roles/%s' % self.delegated_role_id, - role['links']['self']) - self.assertNotEqual(self.not_delegated_role_id, role['id']) - self.assertNotEqual(self.not_delegated_role, role['name']) - self.assertNotIn('v3/roles/%s' % self.not_delegated_role_id, - role['links']['self']) - - def check_trust_roles(self): - # Check we find the delegated role - roles_get = self.trustor_client.list_trust_roles( - self.trust_id)['roles'] - self.assertEqual(1, len(roles_get)) - self.validate_role(roles_get[0]) - - role_get = self.trustor_client.show_trust_role( - self.trust_id, self.delegated_role_id)['role'] - self.validate_role(role_get) - - role_get = self.trustor_client.check_trust_role( - self.trust_id, self.delegated_role_id) - - # And that we don't find not_delegated_role - self.assertRaises(lib_exc.NotFound, - self.trustor_client.show_trust_role, - self.trust_id, - self.not_delegated_role_id) - - self.assertRaises(lib_exc.NotFound, - self.trustor_client.check_trust_role, - self.trust_id, - self.not_delegated_role_id) - - def delete_trust(self): - self.trustor_client.delete_trust(self.trust_id) - self.assertRaises(lib_exc.NotFound, - self.trustor_client.show_trust, - self.trust_id) - self.trust_id = None - - -class TrustsV3TestJSON(BaseTrustsV3Test): - - def setUp(self): - super(TrustsV3TestJSON, self).setUp() - self.create_trustor_and_roles() - self.addCleanup(self.cleanup_user_and_roles) - - @decorators.idempotent_id('5a0a91a4-baef-4a14-baba-59bf4d7fcace') - def test_trust_impersonate(self): - # Test case to check we can create, get and delete a trust - # updates are not supported for trusts - trust = self.create_trust() - self.validate_trust(trust) - - trust_get = self.show_trust() - self.validate_trust(trust_get) - - self.check_trust_roles() - - @decorators.idempotent_id('ed2a8779-a7ac-49dc-afd7-30f32f936ed2') - def test_trust_noimpersonate(self): - # Test case to check we can create, get and delete a trust - # with impersonation=False - trust = self.create_trust(impersonate=False) - self.validate_trust(trust, impersonate=False) - - trust_get = self.show_trust() - self.validate_trust(trust_get, impersonate=False) - - self.check_trust_roles() - - @decorators.idempotent_id('0ed14b66-cefd-4b5c-a964-65759453e292') - def test_trust_expire(self): - # Test case to check we can create, get and delete a trust - # with an expiry specified - expires_at = timeutils.utcnow() + datetime.timedelta(hours=1) - # NOTE(ylobankov) In some cases the expiry time may be rounded up - # because of microseconds. In fact, it depends on database and its - # version. At least MySQL 5.6.16 does this. - # For example, when creating a trust, we will set the expiry time of - # the trust to 2015-02-17T17:34:01.907051Z. However, if we make a GET - # request on the trust, the response will contain the time rounded up - # to 2015-02-17T17:34:02.000000Z. That is why we set microsecond to - # 0 when we invoke isoformat to avoid problems with rounding. - expires_at = expires_at.replace(microsecond=0) - # NOTE(ekhugen) Python datetime does not support military timezones - # since we used UTC we'll add the Z so our compare works. - expires_str = expires_at.isoformat() + 'Z' - - trust = self.create_trust(expires=expires_str) - self.validate_trust(trust, expires=expires_str) - - trust_get = self.show_trust() - - self.validate_trust(trust_get, expires=expires_str) - - self.check_trust_roles() - - @decorators.idempotent_id('3e48f95d-e660-4fa9-85e0-5a3d85594384') - def test_trust_expire_invalid(self): - # Test case to check we can check an invalid expiry time - # is rejected with the correct error - # with an expiry specified - expires_str = 'bad.123Z' - self.assertRaises(lib_exc.BadRequest, - self.create_trust, - expires=expires_str) - - @decorators.idempotent_id('6268b345-87ca-47c0-9ce3-37792b43403a') - def test_get_trusts_query(self): - self.create_trust() - trusts_get = self.trustor_client.list_trusts( - trustor_user_id=self.trustor_user_id)['trusts'] - self.assertEqual(1, len(trusts_get)) - self.validate_trust(trusts_get[0], summary=True) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('4773ebd5-ecbf-4255-b8d8-b63e6f72b65d') - def test_get_trusts_all(self): - - # Simple function that can be used for cleanup - def set_scope(auth_provider, scope): - auth_provider.scope = scope - - self.create_trust() - # Listing trusts can be done by trustor, by trustee, or without - # any filter if scoped to a project, so we must ensure token scope is - # project for this test. - original_scope = self.os_admin.auth_provider.scope - set_scope(self.os_admin.auth_provider, 'project') - self.addCleanup(set_scope, self.os_admin.auth_provider, original_scope) - trusts_get = self.trusts_client.list_trusts()['trusts'] - trusts = [t for t in trusts_get - if t['id'] == self.trust_id] - self.assertEqual(1, len(trusts)) - self.validate_trust(trusts[0], summary=True) diff --git a/tempest/api/identity/admin/v3/test_users.py b/tempest/api/identity/admin/v3/test_users.py deleted file mode 100644 index 409d4f837..000000000 --- a/tempest/api/identity/admin/v3/test_users.py +++ /dev/null @@ -1,171 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 time - -import testtools - -from tempest.api.identity import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -CONF = config.CONF - - -class UsersV3TestJSON(base.BaseIdentityV3AdminTest): - - @decorators.idempotent_id('b537d090-afb9-4519-b95d-270b0708e87e') - def test_user_update(self): - # Test case to check if updating of user attributes is successful. - # Creating first user - u_name = data_utils.rand_name('user') - u_desc = u_name + 'description' - u_email = u_name + '@testmail.tm' - u_password = data_utils.rand_password() - user = self.users_client.create_user( - name=u_name, description=u_desc, password=u_password, - email=u_email, enabled=False)['user'] - # Delete the User at the end of this method - self.addCleanup(self.users_client.delete_user, user['id']) - # Creating second project for updation - project = self.setup_test_project() - # Updating user details with new values - u_name2 = data_utils.rand_name('user2') - u_email2 = u_name2 + '@testmail.tm' - u_description2 = u_name2 + ' description' - update_user = self.users_client.update_user( - user['id'], name=u_name2, description=u_description2, - project_id=project['id'], - email=u_email2, enabled=False)['user'] - self.assertEqual(u_name2, update_user['name']) - self.assertEqual(u_description2, update_user['description']) - self.assertEqual(project['id'], - update_user['project_id']) - self.assertEqual(u_email2, update_user['email']) - self.assertEqual(False, update_user['enabled']) - # GET by id after updation - new_user_get = self.users_client.show_user(user['id'])['user'] - # Assert response body of GET after updation - self.assertEqual(u_name2, new_user_get['name']) - self.assertEqual(u_description2, new_user_get['description']) - self.assertEqual(project['id'], - new_user_get['project_id']) - self.assertEqual(u_email2, new_user_get['email']) - self.assertEqual(False, new_user_get['enabled']) - - @decorators.idempotent_id('2d223a0e-e457-4a70-9fb1-febe027a0ff9') - def test_update_user_password(self): - # Creating User to check password updation - u_name = data_utils.rand_name('user') - original_password = data_utils.rand_password() - user = self.users_client.create_user( - name=u_name, password=original_password)['user'] - # Delete the User at the end all test methods - self.addCleanup(self.users_client.delete_user, user['id']) - # Update user with new password - new_password = data_utils.rand_password() - self.users_client.update_user_password( - user['id'], password=new_password, - original_password=original_password) - # NOTE(morganfainberg): Fernet tokens are not subsecond aware and - # Keystone should only be precise to the second. Sleep to ensure - # we are passing the second boundary. - time.sleep(1) - resp = self.token.auth(user_id=user['id'], - password=new_password).response - subject_token = resp['x-subject-token'] - # Perform GET Token to verify and confirm password is updated - token_details = self.client.show_token(subject_token)['token'] - self.assertEqual(token_details['user']['id'], user['id']) - self.assertEqual(token_details['user']['name'], u_name) - - @decorators.idempotent_id('a831e70c-e35b-430b-92ed-81ebbc5437b8') - def test_list_user_projects(self): - # List the projects that a user has access upon - assigned_project_ids = list() - fetched_project_ids = list() - u_project = self.setup_test_project() - # Create a user. - u_name = data_utils.rand_name('user') - u_desc = u_name + 'description' - u_email = u_name + '@testmail.tm' - u_password = data_utils.rand_password() - user_body = self.users_client.create_user( - name=u_name, description=u_desc, password=u_password, - email=u_email, enabled=False, project_id=u_project['id'])['user'] - # Delete the User at the end of this method - self.addCleanup(self.users_client.delete_user, user_body['id']) - # Creating Role - role_body = self.setup_test_role() - - user = self.users_client.show_user(user_body['id'])['user'] - role = self.roles_client.show_role(role_body['id'])['role'] - for _ in range(2): - # Creating project so as to assign role - project_body = self.setup_test_project() - project = self.projects_client.show_project( - project_body['id'])['project'] - # Assigning roles to user on project - self.roles_client.create_user_role_on_project(project['id'], - user['id'], - role['id']) - assigned_project_ids.append(project['id']) - body = self.users_client.list_user_projects(user['id'])['projects'] - for i in body: - fetched_project_ids.append(i['id']) - # verifying the project ids in list - missing_projects =\ - [p for p in assigned_project_ids - if p not in fetched_project_ids] - self.assertEmpty(missing_projects, - "Failed to find project %s in fetched list" % - ', '.join(m_project for m_project - in missing_projects)) - - @decorators.idempotent_id('c10dcd90-461d-4b16-8e23-4eb836c00644') - def test_get_user(self): - # Get a user detail - user = self.setup_test_user() - fetched_user = self.users_client.show_user(user['id'])['user'] - self.assertEqual(user['id'], fetched_user['id']) - - @testtools.skipUnless(CONF.identity_feature_enabled.security_compliance, - 'Security compliance not available.') - @decorators.idempotent_id('568cd46c-ee6c-4ab4-a33a-d3791931979e') - def test_password_history_not_enforced_in_admin_reset(self): - old_password = self.os_primary.credentials.password - user_id = self.os_primary.credentials.user_id - - new_password = data_utils.rand_password() - self.users_client.update_user(user_id, password=new_password) - # To be safe, we add this cleanup to restore the original password in - # case something goes wrong before it is restored later. - self.addCleanup( - self.users_client.update_user, user_id, password=old_password) - - # Check authorization with new password - self.token.auth(user_id=user_id, password=new_password) - - if CONF.identity.user_unique_last_password_count > 1: - # The password history is not enforced via the admin reset route. - # We can set the same password. - self.users_client.update_user(user_id, password=new_password) - - # Restore original password - self.users_client.update_user(user_id, password=old_password) - # Check authorization with old password - self.token.auth(user_id=user_id, password=old_password) diff --git a/tempest/api/identity/admin/v3/test_users_negative.py b/tempest/api/identity/admin/v3/test_users_negative.py deleted file mode 100644 index 11dcdb03f..000000000 --- a/tempest/api/identity/admin/v3/test_users_negative.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2015 OpenStack Foundation -# 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 tempest.api.identity import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class UsersNegativeTest(base.BaseIdentityV3AdminTest): - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e75f006c-89cc-477b-874d-588e4eab4b17') - def test_create_user_for_non_existent_domain(self): - # Attempt to create a user in a non-existent domain should fail - u_name = data_utils.rand_name('user') - u_email = u_name + '@testmail.tm' - u_password = data_utils.rand_password() - self.assertRaises(lib_exc.NotFound, self.users_client.create_user, - name=u_name, password=u_password, - email=u_email, - domain_id=data_utils.rand_uuid_hex()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('b3c9fccc-4134-46f5-b600-1da6fb0a3b1f') - def test_authentication_for_disabled_user(self): - # Attempt to authenticate for disabled user should fail - password = data_utils.rand_password() - user = self.setup_test_user(password) - self.disable_user(user['name'], user['domain_id']) - self.assertRaises(lib_exc.Unauthorized, self.token.auth, - username=user['name'], - password=password, - user_domain_id=CONF.identity.default_domain_id) diff --git a/tempest/api/identity/base.py b/tempest/api/identity/base.py deleted file mode 100644 index 30d2a366a..000000000 --- a/tempest/api/identity/base.py +++ /dev/null @@ -1,287 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -import tempest.test - -CONF = config.CONF - - -class BaseIdentityTest(tempest.test.BaseTestCase): - - @classmethod - def setup_credentials(cls): - # Create no network resources for these test. - cls.set_network_resources() - super(BaseIdentityTest, cls).setup_credentials() - - @classmethod - def disable_user(cls, user_name): - user = cls.get_user_by_name(user_name) - cls.users_client.update_user_enabled(user['id'], enabled=False) - - @classmethod - def disable_tenant(cls, tenant_name): - tenant = cls.get_tenant_by_name(tenant_name) - cls.tenants_client.update_tenant(tenant['id'], enabled=False) - - @classmethod - def get_user_by_name(cls, name, domain_id=None): - if domain_id: - params = {'domain_id': domain_id} - users = cls.users_client.list_users(**params)['users'] - else: - users = cls.users_client.list_users()['users'] - user = [u for u in users if u['name'] == name] - if user: - return user[0] - - @classmethod - def get_tenant_by_name(cls, name): - try: - tenants = cls.tenants_client.list_tenants()['tenants'] - except AttributeError: - tenants = cls.projects_client.list_projects()['projects'] - tenant = [t for t in tenants if t['name'] == name] - if tenant: - return tenant[0] - - @classmethod - def get_role_by_name(cls, name): - roles = cls.roles_client.list_roles()['roles'] - role = [r for r in roles if r['name'] == name] - if role: - return role[0] - - def create_test_user(self, **kwargs): - if kwargs.get('password', None) is None: - kwargs['password'] = data_utils.rand_password() - if 'name' not in kwargs: - kwargs['name'] = data_utils.rand_name('test_user') - if 'email' not in kwargs: - kwargs['email'] = kwargs['name'] + '@testmail.tm' - - user = self.users_client.create_user(**kwargs)['user'] - # Delete the user at the end of the test - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.users_client.delete_user, user['id']) - return user - - def setup_test_role(self, name=None, domain_id=None): - """Set up a test role.""" - params = {'name': name or data_utils.rand_name('test_role')} - if domain_id: - params['domain_id'] = domain_id - - role = self.roles_client.create_role(**params)['role'] - # Delete the role at the end of the test - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.roles_client.delete_role, role['id']) - return role - - -class BaseIdentityV2Test(BaseIdentityTest): - - credentials = ['primary'] - - # identity v2 tests should obtain tokens and create accounts via v2 - # regardless of the configured CONF.identity.auth_version - identity_version = 'v2' - - @classmethod - def setup_clients(cls): - super(BaseIdentityV2Test, cls).setup_clients() - cls.non_admin_client = cls.os_primary.identity_public_client - cls.non_admin_token_client = cls.os_primary.token_client - cls.non_admin_tenants_client = cls.os_primary.tenants_public_client - cls.non_admin_users_client = cls.os_primary.users_public_client - - -class BaseIdentityV2AdminTest(BaseIdentityV2Test): - - credentials = ['primary', 'admin'] - - # NOTE(andreaf) Identity tests work with credentials, so it is safer - # for them to always use disposable credentials. Forcing dynamic creds - # on regular identity tests would be however to restrictive, since it - # would prevent any identity test from being executed against clouds where - # admin credentials are not available. - # Since All admin tests require admin credentials to be - # executed, so this will not impact the ability to execute tests. - force_tenant_isolation = True - - @classmethod - def skip_checks(cls): - super(BaseIdentityV2AdminTest, cls).skip_checks() - if not CONF.identity_feature_enabled.api_v2_admin: - raise cls.skipException('Identity v2 admin not available') - - @classmethod - def setup_clients(cls): - super(BaseIdentityV2AdminTest, cls).setup_clients() - cls.client = cls.os_admin.identity_client - cls.non_admin_client = cls.os_primary.identity_client - cls.token_client = cls.os_admin.token_client - cls.tenants_client = cls.os_admin.tenants_client - cls.non_admin_tenants_client = cls.os_primary.tenants_client - cls.roles_client = cls.os_admin.roles_client - cls.non_admin_roles_client = cls.os_primary.roles_client - cls.users_client = cls.os_admin.users_client - cls.non_admin_users_client = cls.os_primary.users_client - cls.services_client = cls.os_admin.identity_services_client - cls.endpoints_client = cls.os_admin.endpoints_client - - @classmethod - def resource_setup(cls): - super(BaseIdentityV2AdminTest, cls).resource_setup() - cls.projects_client = cls.tenants_client - - def setup_test_user(self, password=None): - """Set up a test user.""" - tenant = self.setup_test_tenant() - user = self.create_test_user(tenantId=tenant['id'], password=password) - return user - - def setup_test_tenant(self, **kwargs): - """Set up a test tenant.""" - if 'name' not in kwargs: - kwargs['name'] = data_utils.rand_name('test_tenant') - if 'description' not in kwargs: - kwargs['description'] = data_utils.rand_name('desc') - tenant = self.projects_client.create_tenant(**kwargs)['tenant'] - # Delete the tenant at the end of the test - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.tenants_client.delete_tenant, tenant['id']) - return tenant - - -class BaseIdentityV3Test(BaseIdentityTest): - - credentials = ['primary'] - - # identity v3 tests should obtain tokens and create accounts via v3 - # regardless of the configured CONF.identity.auth_version - identity_version = 'v3' - - @classmethod - def setup_clients(cls): - super(BaseIdentityV3Test, cls).setup_clients() - cls.non_admin_client = cls.os_primary.identity_v3_client - cls.non_admin_users_client = cls.os_primary.users_v3_client - cls.non_admin_token = cls.os_primary.token_v3_client - cls.non_admin_projects_client = cls.os_primary.projects_client - cls.non_admin_catalog_client = cls.os_primary.catalog_client - cls.non_admin_versions_client =\ - cls.os_primary.identity_versions_v3_client - - -class BaseIdentityV3AdminTest(BaseIdentityV3Test): - - credentials = ['primary', 'admin'] - - # NOTE(andreaf) Identity tests work with credentials, so it is safer - # for them to always use disposable credentials. Forcing dynamic creds - # on regular identity tests would be however to restrictive, since it - # would prevent any identity test from being executed against clouds where - # admin credentials are not available. - # Since All admin tests require admin credentials to be - # executed, so this will not impact the ability to execute tests. - force_tenant_isolation = True - - @classmethod - def setup_clients(cls): - super(BaseIdentityV3AdminTest, cls).setup_clients() - cls.client = cls.os_admin.identity_v3_client - cls.domains_client = cls.os_admin.domains_client - cls.users_client = cls.os_admin.users_v3_client - cls.trusts_client = cls.os_admin.trusts_client - cls.roles_client = cls.os_admin.roles_v3_client - cls.inherited_roles_client = cls.os_admin.inherited_roles_client - cls.token = cls.os_admin.token_v3_client - cls.endpoints_client = cls.os_admin.endpoints_v3_client - cls.regions_client = cls.os_admin.regions_client - cls.services_client = cls.os_admin.identity_services_v3_client - cls.policies_client = cls.os_admin.policies_client - cls.creds_client = cls.os_admin.credentials_client - cls.groups_client = cls.os_admin.groups_client - cls.projects_client = cls.os_admin.projects_client - cls.role_assignments = cls.os_admin.role_assignments_client - cls.oauth_consumers_client = cls.os_admin.oauth_consumers_client - cls.oauth_token_client = cls.os_admin.oauth_token_client - cls.domain_config_client = cls.os_admin.domain_config_client - cls.endpoint_filter_client = cls.os_admin.endpoint_filter_client - cls.endpoint_groups_client = cls.os_admin.endpoint_groups_client - - if CONF.identity.admin_domain_scope: - # NOTE(andreaf) When keystone policy requires it, the identity - # admin clients for these tests shall use 'domain' scoped tokens. - # As the client manager is already created by the base class, - # we set the scope for the inner auth provider. - cls.os_admin.auth_provider.scope = 'domain' - - @classmethod - def disable_user(cls, user_name, domain_id=None): - user = cls.get_user_by_name(user_name, domain_id) - cls.users_client.update_user(user['id'], name=user_name, enabled=False) - - @classmethod - def create_domain(cls, **kwargs): - """Create a domain.""" - if 'name' not in kwargs: - kwargs['name'] = data_utils.rand_name('test_domain') - if 'description' not in kwargs: - kwargs['description'] = data_utils.rand_name('desc') - domain = cls.domains_client.create_domain(**kwargs)['domain'] - return domain - - def delete_domain(self, domain_id): - # NOTE(mpavlase) It is necessary to disable the domain before deleting - # otherwise it raises Forbidden exception - self.domains_client.update_domain(domain_id, enabled=False) - self.domains_client.delete_domain(domain_id) - - def setup_test_user(self, password=None): - """Set up a test user.""" - project = self.setup_test_project() - user = self.create_test_user(project_id=project['id'], - password=password) - return user - - def setup_test_project(self, **kwargs): - """Set up a test project.""" - if 'name' not in kwargs: - kwargs['name'] = data_utils.rand_name('test_project') - if 'description' not in kwargs: - kwargs['description'] = data_utils.rand_name('test_description') - project = self.projects_client.create_project(**kwargs)['project'] - # Delete the project at the end of the test - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.projects_client.delete_project, project['id']) - return project - - def setup_test_domain(self): - """Set up a test domain.""" - domain = self.create_domain() - # Delete the domain at the end of the test - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.delete_domain, domain['id']) - return domain diff --git a/tempest/api/identity/v2/__init__.py b/tempest/api/identity/v2/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/identity/v2/test_api_discovery.py b/tempest/api/identity/v2/test_api_discovery.py deleted file mode 100644 index 5b9d38c48..000000000 --- a/tempest/api/identity/v2/test_api_discovery.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2015 OpenStack Foundation. -# Copyright 2015, Red Hat, Inc. -# -# 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 tempest.api.identity import base -from tempest.lib import decorators - - -class TestApiDiscovery(base.BaseIdentityV2Test): - """Tests for API discovery features.""" - - @decorators.attr(type='smoke') - @decorators.idempotent_id('ea889a68-a15f-4166-bfb1-c12456eae853') - def test_api_version_resources(self): - descr = self.non_admin_client.show_api_description()['version'] - expected_resources = ('id', 'links', 'media-types', 'status', - 'updated') - - keys = descr.keys() - for res in expected_resources: - self.assertIn(res, keys) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('007a0be0-78fe-4fdb-bbee-e9216cc17bb2') - def test_api_media_types(self): - descr = self.non_admin_client.show_api_description()['version'] - # Get MIME type bases and descriptions - media_types = [(media_type['base'], media_type['type']) for - media_type in descr['media-types']] - # These are supported for API version 2 - supported_types = [('application/json', - 'application/vnd.openstack.identity-v2.0+json')] - - # Check if supported types exist in response body - for s_type in supported_types: - self.assertIn(s_type, media_types) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('77fd6be0-8801-48e6-b9bf-38cdd2f253ec') - def test_api_version_statuses(self): - descr = self.non_admin_client.show_api_description()['version'] - status = descr['status'].lower() - supported_statuses = ['current', 'stable', 'experimental', - 'supported', 'deprecated'] - - self.assertIn(status, supported_statuses) diff --git a/tempest/api/identity/v2/test_ec2_credentials.py b/tempest/api/identity/v2/test_ec2_credentials.py deleted file mode 100644 index 599b784d6..000000000 --- a/tempest/api/identity/v2/test_ec2_credentials.py +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright 2015 OpenStack Foundation -# 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 tempest.api.identity import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - - -class EC2CredentialsTest(base.BaseIdentityV2Test): - - @classmethod - def skip_checks(cls): - super(EC2CredentialsTest, cls).skip_checks() - if not test.is_extension_enabled('OS-EC2', 'identity'): - msg = "OS-EC2 identity extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(EC2CredentialsTest, cls).resource_setup() - cls.creds = cls.os_primary.credentials - - @decorators.idempotent_id('b580fab9-7ae9-46e8-8138-417260cb6f9f') - def test_create_ec2_credential(self): - """Create user ec2 credential.""" - resp = self.non_admin_users_client.create_user_ec2_credential( - self.creds.user_id, - tenant_id=self.creds.tenant_id)["credential"] - access = resp['access'] - self.addCleanup( - self.non_admin_users_client.delete_user_ec2_credential, - self.creds.user_id, access) - self.assertNotEmpty(resp['access']) - self.assertNotEmpty(resp['secret']) - self.assertEqual(self.creds.user_id, resp['user_id']) - self.assertEqual(self.creds.tenant_id, resp['tenant_id']) - - @decorators.idempotent_id('9e2ea42f-0a4f-468c-a768-51859ce492e0') - def test_list_ec2_credentials(self): - """Get the list of user ec2 credentials.""" - created_creds = [] - # create first ec2 credentials - creds1 = self.non_admin_users_client.create_user_ec2_credential( - self.creds.user_id, - tenant_id=self.creds.tenant_id)["credential"] - created_creds.append(creds1['access']) - # create second ec2 credentials - creds2 = self.non_admin_users_client.create_user_ec2_credential( - self.creds.user_id, - tenant_id=self.creds.tenant_id)["credential"] - created_creds.append(creds2['access']) - # add credentials to be cleaned up - self.addCleanup( - self.non_admin_users_client.delete_user_ec2_credential, - self.creds.user_id, creds1['access']) - self.addCleanup( - self.non_admin_users_client.delete_user_ec2_credential, - self.creds.user_id, creds2['access']) - # get the list of user ec2 credentials - resp = self.non_admin_users_client.list_user_ec2_credentials( - self.creds.user_id)["credentials"] - fetched_creds = [cred['access'] for cred in resp] - # created credentials should be in a fetched list - missing = [cred for cred in created_creds - if cred not in fetched_creds] - self.assertEmpty(missing, - "Failed to find ec2_credentials %s in fetched list" % - ', '.join(cred for cred in missing)) - - @decorators.idempotent_id('cb284075-b613-440d-83ca-fe0b33b3c2b8') - def test_show_ec2_credential(self): - """Get the definite user ec2 credential.""" - resp = self.non_admin_users_client.create_user_ec2_credential( - self.creds.user_id, - tenant_id=self.creds.tenant_id)["credential"] - self.addCleanup( - self.non_admin_users_client.delete_user_ec2_credential, - self.creds.user_id, resp['access']) - - ec2_creds = self.non_admin_users_client.show_user_ec2_credential( - self.creds.user_id, resp['access'] - )["credential"] - for key in ['access', 'secret', 'user_id', 'tenant_id']: - self.assertEqual(ec2_creds[key], resp[key]) - - @decorators.idempotent_id('6aba0d4c-b76b-4e46-aa42-add79bc1551d') - def test_delete_ec2_credential(self): - """Delete user ec2 credential.""" - resp = self.non_admin_users_client.create_user_ec2_credential( - self.creds.user_id, - tenant_id=self.creds.tenant_id)["credential"] - access = resp['access'] - self.non_admin_users_client.delete_user_ec2_credential( - self.creds.user_id, access) - self.assertRaises( - lib_exc.NotFound, - self.non_admin_users_client.show_user_ec2_credential, - self.creds.user_id, - access) diff --git a/tempest/api/identity/v2/test_extension.py b/tempest/api/identity/v2/test_extension.py deleted file mode 100644 index c538c142c..000000000 --- a/tempest/api/identity/v2/test_extension.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2014 NEC Corporation -# 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 tempest.api.identity import base -from tempest.lib import decorators - - -class ExtensionTestJSON(base.BaseIdentityV2Test): - - @decorators.idempotent_id('85f3f661-f54c-4d48-b563-72ae952b9383') - def test_list_extensions(self): - # List all the extensions - body = self.non_admin_client.list_extensions()['extensions']['values'] - self.assertNotEmpty(body) - keys = ['name', 'updated', 'alias', 'links', - 'namespace', 'description'] - for value in body: - for key in keys: - self.assertIn(key, value) diff --git a/tempest/api/identity/v2/test_tenants.py b/tempest/api/identity/v2/test_tenants.py deleted file mode 100644 index b2a6d13c3..000000000 --- a/tempest/api/identity/v2/test_tenants.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2015 OpenStack Foundation -# 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 tempest.api.identity import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class IdentityTenantsTest(base.BaseIdentityV2Test): - - credentials = ['primary', 'alt'] - - @decorators.idempotent_id('ecae2459-243d-4ba1-ad02-65f15dc82b78') - def test_list_tenants_returns_only_authorized_tenants(self): - alt_tenant_name = self.os_alt.credentials.tenant_name - resp = self.non_admin_tenants_client.list_tenants() - - # check that user can see only that tenants that he presents in so user - # can successfully authenticate using his credentials and tenant name - # from received tenants list - for tenant in resp['tenants']: - body = self.non_admin_token_client.auth( - self.os_primary.credentials.username, - self.os_primary.credentials.password, - tenant['name']) - self.assertNotEmpty(body['token']['id']) - self.assertEqual(body['token']['tenant']['id'], tenant['id']) - self.assertEqual(body['token']['tenant']['name'], tenant['name']) - self.assertEqual( - body['user']['id'], self.os_primary.credentials.user_id) - - # check that user cannot log in to alt user's tenant - self.assertRaises( - lib_exc.Unauthorized, - self.non_admin_token_client.auth, - self.os_primary.credentials.username, - self.os_primary.credentials.password, - alt_tenant_name) diff --git a/tempest/api/identity/v2/test_tokens.py b/tempest/api/identity/v2/test_tokens.py deleted file mode 100644 index 64b81c229..000000000 --- a/tempest/api/identity/v2/test_tokens.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2015 OpenStack Foundation -# 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 oslo_utils import timeutils -import six -from tempest.api.identity import base -from tempest.lib import decorators - - -class TokensTest(base.BaseIdentityV2Test): - - @decorators.idempotent_id('65ae3b78-91ff-467b-a705-f6678863b8ec') - def test_create_token(self): - - token_client = self.non_admin_token_client - - # get a token for the user - creds = self.os_primary.credentials - username = creds.username - password = creds.password - tenant_name = creds.tenant_name - - body = token_client.auth(username, password, tenant_name) - - self.assertNotEmpty(body['token']['id']) - self.assertIsInstance(body['token']['id'], six.string_types) - - now = timeutils.utcnow() - expires_at = timeutils.normalize_time( - timeutils.parse_isotime(body['token']['expires'])) - self.assertGreater(expires_at, now) - - self.assertEqual(body['token']['tenant']['id'], - creds.tenant_id) - self.assertEqual(body['token']['tenant']['name'], - tenant_name) - - self.assertEqual(body['user']['id'], creds.user_id) diff --git a/tempest/api/identity/v2/test_users.py b/tempest/api/identity/v2/test_users.py deleted file mode 100644 index 9c77fff51..000000000 --- a/tempest/api/identity/v2/test_users.py +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright 2015 OpenStack Foundation -# 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 time - -from tempest.api.identity import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions - - -CONF = config.CONF - - -class IdentityUsersTest(base.BaseIdentityV2Test): - - @classmethod - def resource_setup(cls): - super(IdentityUsersTest, cls).resource_setup() - cls.creds = cls.os_primary.credentials - cls.username = cls.creds.username - cls.password = cls.creds.password - cls.tenant_name = cls.creds.tenant_name - - def _update_password(self, user_id, original_password, password): - self.non_admin_users_client.update_user_own_password( - user_id, password=password, original_password=original_password) - - # NOTE(morganfainberg): Fernet tokens are not subsecond aware and - # Keystone should only be precise to the second. Sleep to ensure - # we are passing the second boundary. - time.sleep(1) - - # check authorization with new password - self.non_admin_token_client.auth(self.username, - password, - self.tenant_name) - - # Reset auth to get a new token with the new password - self.non_admin_users_client.auth_provider.clear_auth() - self.non_admin_users_client.auth_provider.credentials.password = ( - password) - - def _restore_password(self, user_id, old_pass, new_pass): - if CONF.identity_feature_enabled.security_compliance: - # First we need to clear the password history - unique_count = CONF.identity.user_unique_last_password_count - for _ in range(unique_count): - random_pass = data_utils.rand_password() - self._update_password( - user_id, original_password=new_pass, password=random_pass) - new_pass = random_pass - - self._update_password( - user_id, original_password=new_pass, password=old_pass) - # Reset auth again to verify the password restore does work. - # Clear auth restores the original credentials and deletes - # cached auth data - self.non_admin_users_client.auth_provider.clear_auth() - # NOTE(lbragstad): Fernet tokens are not subsecond aware and - # Keystone should only be precise to the second. Sleep to ensure we - # are passing the second boundary before attempting to - # authenticate. - time.sleep(1) - self.non_admin_users_client.auth_provider.set_auth() - - @decorators.idempotent_id('165859c9-277f-4124-9479-a7d1627b0ca7') - def test_user_update_own_password(self): - old_pass = self.creds.password - old_token = self.non_admin_users_client.token - new_pass = data_utils.rand_password() - user_id = self.creds.user_id - - # to change password back. important for allow_tenant_isolation = false - self.addCleanup(self._restore_password, user_id, old_pass, new_pass) - - # user updates own password - self._update_password( - user_id, original_password=old_pass, password=new_pass) - - # authorize with old token should lead to Unauthorized - self.assertRaises(exceptions.Unauthorized, - self.non_admin_token_client.auth_token, - old_token) - - # authorize with old password should lead to Unauthorized - self.assertRaises(exceptions.Unauthorized, - self.non_admin_token_client.auth, - self.username, - old_pass, - self.tenant_name) diff --git a/tempest/api/identity/v3/__init__.py b/tempest/api/identity/v3/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/identity/v3/test_api_discovery.py b/tempest/api/identity/v3/test_api_discovery.py deleted file mode 100644 index c04c21bc9..000000000 --- a/tempest/api/identity/v3/test_api_discovery.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2015 OpenStack Foundation. -# Copyright 2015, Red Hat, Inc. -# -# 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 tempest.api.identity import base -from tempest.lib import decorators - - -class TestApiDiscovery(base.BaseIdentityV3Test): - """Tests for API discovery features.""" - - @decorators.idempotent_id('721f480f-35b6-46c7-846e-047e6acea0dc') - @decorators.attr(type='smoke') - def test_list_api_versions(self): - # NOTE: Actually this API doesn't depend on v3 API at all, because - # the API operation is "GET /" without v3's endpoint. The reason of - # this test path is just v3 API is CURRENT on Keystone side. - versions = self.non_admin_versions_client.list_versions() - expected_resources = ('id', 'links', 'media-types', 'status', - 'updated') - - for version in versions['versions']["values"]: - for res in expected_resources: - self.assertIn(res, version) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('b9232f5e-d9e5-4d97-b96c-28d3db4de1bd') - def test_api_version_resources(self): - descr = self.non_admin_client.show_api_description()['version'] - expected_resources = ('id', 'links', 'media-types', 'status', - 'updated') - - keys = descr.keys() - for res in expected_resources: - self.assertIn(res, keys) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('657c1970-4722-4189-8831-7325f3bc4265') - def test_api_media_types(self): - descr = self.non_admin_client.show_api_description()['version'] - # Get MIME type bases and descriptions - media_types = [(media_type['base'], media_type['type']) for - media_type in descr['media-types']] - # These are supported for API version 2 - supported_types = [('application/json', - 'application/vnd.openstack.identity-v3+json')] - - # Check if supported types exist in response body - for s_type in supported_types: - self.assertIn(s_type, media_types) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('8879a470-abfb-47bb-bb8d-5a7fd279ad1e') - def test_api_version_statuses(self): - descr = self.non_admin_client.show_api_description()['version'] - status = descr['status'].lower() - supported_statuses = ['current', 'stable', 'experimental', - 'supported', 'deprecated'] - - self.assertIn(status, supported_statuses) diff --git a/tempest/api/identity/v3/test_catalog.py b/tempest/api/identity/v3/test_catalog.py deleted file mode 100755 index deec2dcf1..000000000 --- a/tempest/api/identity/v3/test_catalog.py +++ /dev/null @@ -1,41 +0,0 @@ -# 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 tempest.api.identity import base -from tempest import config -from tempest.lib import decorators - - -CONF = config.CONF - - -class IdentityCatalogTest(base.BaseIdentityV3Test): - - @decorators.idempotent_id('56b57ced-22b8-4127-9b8a-565dfb0207e2') - def test_catalog_standardization(self): - # http://git.openstack.org/cgit/openstack/service-types-authority - # /tree/service-types.yaml - standard_service_values = [{'name': 'keystone', 'type': 'identity'}, - {'name': 'nova', 'type': 'compute'}, - {'name': 'glance', 'type': 'image'}, - {'name': 'swift', 'type': 'object-store'}] - # next, we need to GET the catalog using the catalog client - catalog = self.non_admin_catalog_client.show_catalog()['catalog'] - # get list of the service types present in the catalog - catalog_services = [] - for service in catalog: - catalog_services.append(service['type']) - for service in standard_service_values: - # if service enabled, check if it has a standard typevalue - if service['name'] == 'keystone' or\ - getattr(CONF.service_available, service['name']): - self.assertIn(service['type'], catalog_services) diff --git a/tempest/api/identity/v3/test_projects.py b/tempest/api/identity/v3/test_projects.py deleted file mode 100644 index 0ae35eada..000000000 --- a/tempest/api/identity/v3/test_projects.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2015 OpenStack Foundation -# 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 tempest.api.identity import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class IdentityV3ProjectsTest(base.BaseIdentityV3Test): - - credentials = ['primary', 'alt'] - - @decorators.idempotent_id('86128d46-e170-4644-866a-cc487f699e1d') - def test_list_projects_returns_only_authorized_projects(self): - alt_project_name =\ - self.os_alt.credentials.project_name - resp = self.non_admin_users_client.list_user_projects( - self.os_primary.credentials.user_id) - - # check that user can see only that projects that he presents in so - # user can successfully authenticate using his credentials and - # project name from received projects list - for project in resp['projects']: - # 'user_domain_id' needs to be specified otherwise tempest.lib - # assumes it to be 'default' - token_id, body = self.non_admin_token.get_token( - username=self.os_primary.credentials.username, - user_domain_id=self.os_primary.credentials.user_domain_id, - password=self.os_primary.credentials.password, - project_name=project['name'], - project_domain_id=project['domain_id'], - auth_data=True) - self.assertNotEmpty(token_id) - self.assertEqual(body['project']['id'], project['id']) - self.assertEqual(body['project']['name'], project['name']) - self.assertEqual( - body['user']['id'], self.os_primary.credentials.user_id) - - # check that user cannot log in to alt user's project - self.assertRaises( - lib_exc.Unauthorized, - self.non_admin_token.get_token, - username=self.os_primary.credentials.username, - user_domain_id=self.os_primary.credentials.user_domain_id, - password=self.os_primary.credentials.password, - project_name=alt_project_name, - project_domain_id=project['domain_id']) diff --git a/tempest/api/identity/v3/test_tokens.py b/tempest/api/identity/v3/test_tokens.py deleted file mode 100644 index 4c72d828f..000000000 --- a/tempest/api/identity/v3/test_tokens.py +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright 2015 OpenStack Foundation -# 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 oslo_utils import timeutils -import six - -from tempest.api.identity import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class TokensV3Test(base.BaseIdentityV3Test): - - @decorators.idempotent_id('a9512ac3-3909-48a4-b395-11f438e16260') - def test_validate_token(self): - creds = self.os_primary.credentials - user_id = creds.user_id - username = creds.username - password = creds.password - user_domain_id = creds.user_domain_id - # GET and validate token - subject_token, token_body = self.non_admin_token.get_token( - user_id=user_id, - username=username, - user_domain_id=user_domain_id, - password=password, - auth_data=True) - authenticated_token = self.non_admin_client.show_token( - subject_token)['token'] - # sanity checking to make sure they are indeed the same token - self.assertEqual(authenticated_token, token_body) - # test to see if token has been properly authenticated - self.assertEqual(authenticated_token['user']['id'], user_id) - self.assertEqual(authenticated_token['user']['name'], username) - self.non_admin_client.delete_token(subject_token) - self.assertRaises( - lib_exc.NotFound, self.non_admin_client.show_token, subject_token) - - @decorators.idempotent_id('6f8e4436-fc96-4282-8122-e41df57197a9') - def test_create_token(self): - - creds = self.os_primary.credentials - user_id = creds.user_id - username = creds.username - password = creds.password - user_domain_id = creds.user_domain_id - - # 'user_domain_id' needs to be specified otherwise tempest.lib assumes - # it to be 'default' - token_id, resp = self.non_admin_token.get_token( - user_id=user_id, - username=username, - user_domain_id=user_domain_id, - password=password, - auth_data=True) - - self.assertNotEmpty(token_id) - self.assertIsInstance(token_id, six.string_types) - - now = timeutils.utcnow() - expires_at = timeutils.normalize_time( - timeutils.parse_isotime(resp['expires_at'])) - self.assertGreater(resp['expires_at'], - resp['issued_at']) - self.assertGreater(expires_at, now) - - subject_id = resp['user']['id'] - if user_id: - self.assertEqual(subject_id, user_id) - else: - # Expect a user ID, but don't know what it will be. - self.assertIsNotNone(subject_id, 'Expected user ID in token.') - - subject_name = resp['user']['name'] - if username: - self.assertEqual(subject_name, username) - else: - # Expect a user name, but don't know what it will be. - self.assertIsNotNone(subject_name, 'Expected user name in token.') - - self.assertEqual(resp['methods'][0], 'password') diff --git a/tempest/api/identity/v3/test_users.py b/tempest/api/identity/v3/test_users.py deleted file mode 100644 index 1f099df49..000000000 --- a/tempest/api/identity/v3/test_users.py +++ /dev/null @@ -1,158 +0,0 @@ -# Copyright 2015 OpenStack Foundation -# 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 time - -import testtools - -from tempest.api.identity import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions - - -CONF = config.CONF - - -class IdentityV3UsersTest(base.BaseIdentityV3Test): - - @classmethod - def resource_setup(cls): - super(IdentityV3UsersTest, cls).resource_setup() - cls.creds = cls.os_primary.credentials - cls.user_id = cls.creds.user_id - - def _update_password(self, original_password, password): - self.non_admin_users_client.update_user_password( - self.user_id, - password=password, - original_password=original_password) - - # NOTE(morganfainberg): Fernet tokens are not subsecond aware and - # Keystone should only be precise to the second. Sleep to ensure - # we are passing the second boundary. - time.sleep(1) - - # check authorization with new password - self.non_admin_token.auth(user_id=self.user_id, password=password) - - # Reset auth to get a new token with the new password - self.non_admin_users_client.auth_provider.clear_auth() - self.non_admin_users_client.auth_provider.credentials.password = ( - password) - - def _restore_password(self, old_pass, new_pass): - if CONF.identity_feature_enabled.security_compliance: - # First we need to clear the password history - unique_count = CONF.identity.user_unique_last_password_count - for _ in range(unique_count): - random_pass = data_utils.rand_password() - self._update_password( - original_password=new_pass, password=random_pass) - new_pass = random_pass - - self._update_password(original_password=new_pass, password=old_pass) - # Reset auth again to verify the password restore does work. - # Clear auth restores the original credentials and deletes - # cached auth data - self.non_admin_users_client.auth_provider.clear_auth() - # NOTE(lbragstad): Fernet tokens are not subsecond aware and - # Keystone should only be precise to the second. Sleep to ensure we - # are passing the second boundary before attempting to - # authenticate. - time.sleep(1) - self.non_admin_users_client.auth_provider.set_auth() - - @decorators.idempotent_id('ad71bd23-12ad-426b-bb8b-195d2b635f27') - def test_user_update_own_password(self): - old_pass = self.creds.password - old_token = self.non_admin_client.token - new_pass = data_utils.rand_password() - - # to change password back. important for allow_tenant_isolation = false - self.addCleanup(self._restore_password, old_pass, new_pass) - - # user updates own password - self._update_password(original_password=old_pass, password=new_pass) - - # authorize with old token should lead to IdentityError (404 code) - self.assertRaises(exceptions.IdentityError, - self.non_admin_token.auth, - token=old_token) - - # authorize with old password should lead to Unauthorized - self.assertRaises(exceptions.Unauthorized, - self.non_admin_token.auth, - user_id=self.user_id, - password=old_pass) - - @testtools.skipUnless(CONF.identity_feature_enabled.security_compliance, - 'Security compliance not available.') - @decorators.idempotent_id('941784ee-5342-4571-959b-b80dd2cea516') - def test_password_history_check_self_service_api(self): - old_pass = self.creds.password - new_pass1 = data_utils.rand_password() - new_pass2 = data_utils.rand_password() - - self.addCleanup(self._restore_password, old_pass, new_pass2) - - # Update password - self._update_password(original_password=old_pass, password=new_pass1) - - if CONF.identity.user_unique_last_password_count > 1: - # Can not reuse a previously set password - self.assertRaises(exceptions.BadRequest, - self.non_admin_users_client.update_user_password, - self.user_id, - password=new_pass1, - original_password=new_pass1) - - self.assertRaises(exceptions.BadRequest, - self.non_admin_users_client.update_user_password, - self.user_id, - password=old_pass, - original_password=new_pass1) - - # A different password can be set - self._update_password(original_password=new_pass1, password=new_pass2) - - @testtools.skipUnless(CONF.identity_feature_enabled.security_compliance, - 'Security compliance not available.') - @decorators.idempotent_id('a7ad8bbf-2cff-4520-8c1d-96332e151658') - def test_user_account_lockout(self): - password = self.creds.password - - # First, we login using the correct credentials - self.non_admin_token.auth(user_id=self.user_id, password=password) - - # Lock user account by using the wrong password to login - bad_password = data_utils.rand_password() - for _ in range(CONF.identity.user_lockout_failure_attempts): - self.assertRaises(exceptions.Unauthorized, - self.non_admin_token.auth, - user_id=self.user_id, - password=bad_password) - - # The user account must be locked, so now it is not possible to login - # even using the correct password - self.assertRaises(exceptions.Unauthorized, - self.non_admin_token.auth, - user_id=self.user_id, - password=password) - - # If we wait the required time, the user account will be unlocked - time.sleep(CONF.identity.user_lockout_duration + 1) - self.non_admin_token.auth(user_id=self.user_id, password=password) diff --git a/tempest/api/image/__init__.py b/tempest/api/image/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py deleted file mode 100644 index 70ba2feca..000000000 --- a/tempest/api/image/base.py +++ /dev/null @@ -1,211 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# 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 six - -from tempest.common import image as common_image -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -import tempest.test - -CONF = config.CONF - - -class BaseImageTest(tempest.test.BaseTestCase): - """Base test class for Image API tests.""" - - credentials = ['primary'] - - @classmethod - def skip_checks(cls): - super(BaseImageTest, cls).skip_checks() - if not CONF.service_available.glance: - skip_msg = ("%s skipped as glance is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_credentials(cls): - cls.set_network_resources() - super(BaseImageTest, cls).setup_credentials() - - @classmethod - def resource_setup(cls): - super(BaseImageTest, cls).resource_setup() - cls.created_images = [] - - @classmethod - def resource_cleanup(cls): - for image_id in cls.created_images: - test_utils.call_and_ignore_notfound_exc( - cls.client.delete_image, image_id) - - for image_id in cls.created_images: - cls.client.wait_for_resource_deletion(image_id) - super(BaseImageTest, cls).resource_cleanup() - - @classmethod - def create_image(cls, data=None, **kwargs): - """Wrapper that returns a test image.""" - - if 'name' not in kwargs: - name = data_utils.rand_name(cls.__name__ + "-image") - kwargs['name'] = name - - params = cls._get_create_params(**kwargs) - if data: - # NOTE: On glance v1 API, the data should be passed on - # a header. Then here handles the data separately. - params['data'] = data - - image = cls.client.create_image(**params) - # Image objects returned by the v1 client have the image - # data inside a dict that is keyed against 'image'. - if 'image' in image: - image = image['image'] - cls.created_images.append(image['id']) - return image - - @classmethod - def _get_create_params(cls, **kwargs): - return kwargs - - -class BaseV1ImageTest(BaseImageTest): - - @classmethod - def skip_checks(cls): - super(BaseV1ImageTest, cls).skip_checks() - if not CONF.image_feature_enabled.api_v1: - msg = "Glance API v1 not supported" - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(BaseV1ImageTest, cls).setup_clients() - cls.client = cls.os_primary.image_client - - @classmethod - def _get_create_params(cls, **kwargs): - return {'headers': common_image.image_meta_to_headers(**kwargs)} - - -class BaseV1ImageMembersTest(BaseV1ImageTest): - - credentials = ['primary', 'alt'] - - @classmethod - def setup_clients(cls): - super(BaseV1ImageMembersTest, cls).setup_clients() - cls.image_member_client = cls.os_primary.image_member_client - cls.alt_image_member_client = cls.os_alt.image_member_client - cls.alt_img_cli = cls.os_alt.image_client - - @classmethod - def resource_setup(cls): - super(BaseV1ImageMembersTest, cls).resource_setup() - cls.alt_tenant_id = cls.alt_image_member_client.tenant_id - - def _create_image(self): - image_file = six.BytesIO(data_utils.random_bytes()) - image = self.create_image(container_format='bare', - disk_format='raw', - is_public=False, - data=image_file) - return image['id'] - - -class BaseV2ImageTest(BaseImageTest): - - @classmethod - def skip_checks(cls): - super(BaseV2ImageTest, cls).skip_checks() - if not CONF.image_feature_enabled.api_v2: - msg = "Glance API v2 not supported" - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(BaseV2ImageTest, cls).setup_clients() - cls.client = cls.os_primary.image_client_v2 - cls.namespaces_client = cls.os_primary.namespaces_client - cls.resource_types_client = cls.os_primary.resource_types_client - cls.namespace_properties_client =\ - cls.os_primary.namespace_properties_client - cls.namespace_objects_client = cls.os_primary.namespace_objects_client - cls.namespace_tags_client = cls.os_primary.namespace_tags_client - cls.schemas_client = cls.os_primary.schemas_client - cls.versions_client = cls.os_primary.image_versions_client - - def create_namespace(cls, namespace_name=None, visibility='public', - description='Tempest', protected=False, - **kwargs): - if not namespace_name: - namespace_name = data_utils.rand_name('test-ns') - kwargs.setdefault('display_name', namespace_name) - namespace = cls.namespaces_client.create_namespace( - namespace=namespace_name, visibility=visibility, - description=description, protected=protected, **kwargs) - cls.addCleanup(cls.namespaces_client.delete_namespace, namespace_name) - return namespace - - -class BaseV2MemberImageTest(BaseV2ImageTest): - - credentials = ['primary', 'alt'] - - @classmethod - def setup_clients(cls): - super(BaseV2MemberImageTest, cls).setup_clients() - cls.image_member_client = cls.os_primary.image_member_client_v2 - cls.alt_image_member_client = cls.os_alt.image_member_client_v2 - cls.alt_img_client = cls.os_alt.image_client_v2 - - @classmethod - def resource_setup(cls): - super(BaseV2MemberImageTest, cls).resource_setup() - cls.alt_tenant_id = cls.alt_image_member_client.tenant_id - - def _list_image_ids_as_alt(self): - image_list = self.alt_img_client.list_images()['images'] - image_ids = map(lambda x: x['id'], image_list) - return image_ids - - def _create_image(self): - name = data_utils.rand_name(self.__class__.__name__ + '-image') - image = self.client.create_image(name=name, - container_format='bare', - disk_format='raw') - self.addCleanup(self.client.delete_image, image['id']) - return image['id'] - - -class BaseV1ImageAdminTest(BaseImageTest): - credentials = ['admin', 'primary'] - - @classmethod - def setup_clients(cls): - super(BaseV1ImageAdminTest, cls).setup_clients() - cls.client = cls.os_primary.image_client - cls.admin_client = cls.os_admin.image_client - - -class BaseV2ImageAdminTest(BaseImageTest): - credentials = ['admin', 'primary'] - - @classmethod - def setup_clients(cls): - super(BaseV2ImageAdminTest, cls).setup_clients() - cls.client = cls.os_primary.image_client_v2 - cls.admin_client = cls.os_admin.image_client_v2 diff --git a/tempest/api/image/v1/__init__.py b/tempest/api/image/v1/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/image/v1/test_image_members.py b/tempest/api/image/v1/test_image_members.py deleted file mode 100644 index bf2e510ed..000000000 --- a/tempest/api/image/v1/test_image_members.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# 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 tempest.api.image import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ImageMembersTest(base.BaseV1ImageMembersTest): - - @decorators.idempotent_id('1d6ef640-3a20-4c84-8710-d95828fdb6ad') - def test_add_image_member(self): - image = self._create_image() - self.image_member_client.create_image_member(image, self.alt_tenant_id) - body = self.image_member_client.list_image_members(image) - members = body['members'] - members = [member['member_id'] for member in members] - self.assertIn(self.alt_tenant_id, members) - # get image as alt user - self.alt_img_cli.show_image(image) - - @decorators.idempotent_id('6a5328a5-80e8-4b82-bd32-6c061f128da9') - def test_get_shared_images(self): - image = self._create_image() - self.image_member_client.create_image_member(image, self.alt_tenant_id) - share_image = self._create_image() - self.image_member_client.create_image_member(share_image, - self.alt_tenant_id) - body = self.image_member_client.list_shared_images( - self.alt_tenant_id) - images = body['shared_images'] - images = [img['image_id'] for img in images] - self.assertIn(share_image, images) - self.assertIn(image, images) - - @decorators.idempotent_id('a76a3191-8948-4b44-a9d6-4053e5f2b138') - def test_remove_member(self): - image_id = self._create_image() - self.image_member_client.create_image_member(image_id, - self.alt_tenant_id) - self.image_member_client.delete_image_member(image_id, - self.alt_tenant_id) - body = self.image_member_client.list_image_members(image_id) - members = body['members'] - self.assertEmpty(members) - self.assertRaises( - lib_exc.NotFound, self.alt_img_cli.show_image, image_id) diff --git a/tempest/api/image/v1/test_image_members_negative.py b/tempest/api/image/v1/test_image_members_negative.py deleted file mode 100644 index 2748bd54e..000000000 --- a/tempest/api/image/v1/test_image_members_negative.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# 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 tempest.api.image import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ImageMembersNegativeTest(base.BaseV1ImageMembersTest): - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('147a9536-18e3-45da-91ea-b037a028f364') - def test_add_member_with_non_existing_image(self): - # Add member with non existing image. - non_exist_image = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.image_member_client.create_image_member, - non_exist_image, self.alt_tenant_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e1559f05-b667-4f1b-a7af-518b52dc0c0f') - def test_delete_member_with_non_existing_image(self): - # Delete member with non existing image. - non_exist_image = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.image_member_client.delete_image_member, - non_exist_image, self.alt_tenant_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f5720333-dd69-4194-bb76-d2f048addd56') - def test_delete_member_with_non_existing_tenant(self): - # Delete member with non existing tenant. - image_id = self._create_image() - non_exist_tenant = data_utils.rand_uuid_hex() - self.assertRaises(lib_exc.NotFound, - self.image_member_client.delete_image_member, - image_id, non_exist_tenant) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f25f89e4-0b6c-453b-a853-1f80b9d7ef26') - def test_get_image_without_membership(self): - # Image is hidden from another tenants. - image_id = self._create_image() - self.assertRaises(lib_exc.NotFound, - self.alt_img_cli.show_image, - image_id) diff --git a/tempest/api/image/v1/test_images.py b/tempest/api/image/v1/test_images.py deleted file mode 100644 index 76723f496..000000000 --- a/tempest/api/image/v1/test_images.py +++ /dev/null @@ -1,330 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 six - -from tempest.api.image import base -from tempest.common import image as common_image -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions - -CONF = config.CONF - - -def get_container_and_disk_format(): - a_formats = ['ami', 'ari', 'aki'] - - container_format = CONF.image.container_formats[0] - - # In v1, If container_format is one of ['ami', 'ari', 'aki'], then - # disk_format must be same with container_format. - # If they are of different item sequence in tempest.conf, such as: - # container_formats = ami,ari,aki,bare - # disk_formats = ari,ami,aki,vhd - # we can select one in disk_format list that is same with container_format. - if container_format in a_formats: - if container_format in CONF.image.disk_formats: - disk_format = container_format - else: - msg = ("The container format and the disk format don't match. " - "Container format: %(container)s, Disk format: %(disk)s." % - {'container': container_format, 'disk': - CONF.image.disk_formats}) - raise exceptions.InvalidConfiguration(msg) - else: - disk_format = CONF.image.disk_formats[0] - - return container_format, disk_format - - -class CreateRegisterImagesTest(base.BaseV1ImageTest): - """Here we test the registration and creation of images.""" - - @decorators.idempotent_id('3027f8e6-3492-4a11-8575-c3293017af4d') - def test_register_then_upload(self): - # Register, then upload an image - properties = {'prop1': 'val1'} - container_format, disk_format = get_container_and_disk_format() - image = self.create_image(name='New Name', - container_format=container_format, - disk_format=disk_format, - is_public=False, - properties=properties) - self.assertEqual('New Name', image.get('name')) - self.assertFalse(image.get('is_public')) - self.assertEqual('queued', image.get('status')) - for key, val in properties.items(): - self.assertEqual(val, image.get('properties')[key]) - - # Now try uploading an image file - image_file = six.BytesIO(data_utils.random_bytes()) - body = self.client.update_image(image['id'], data=image_file)['image'] - self.assertIn('size', body) - self.assertEqual(1024, body.get('size')) - - @decorators.idempotent_id('69da74d9-68a9-404b-9664-ff7164ccb0f5') - def test_register_remote_image(self): - # Register a new remote image - container_format, disk_format = get_container_and_disk_format() - body = self.create_image(name='New Remote Image', - container_format=container_format, - disk_format=disk_format, is_public=False, - location=CONF.image.http_image, - properties={'key1': 'value1', - 'key2': 'value2'}) - self.assertEqual('New Remote Image', body.get('name')) - self.assertFalse(body.get('is_public')) - self.assertEqual('active', body.get('status')) - properties = body.get('properties') - self.assertEqual(properties['key1'], 'value1') - self.assertEqual(properties['key2'], 'value2') - - @decorators.idempotent_id('6d0e13a7-515b-460c-b91f-9f4793f09816') - def test_register_http_image(self): - container_format, disk_format = get_container_and_disk_format() - image = self.create_image(name='New Http Image', - container_format=container_format, - disk_format=disk_format, is_public=False, - copy_from=CONF.image.http_image) - self.assertEqual('New Http Image', image.get('name')) - self.assertFalse(image.get('is_public')) - waiters.wait_for_image_status(self.client, image['id'], 'active') - self.client.show_image(image['id']) - - @decorators.idempotent_id('05b19d55-140c-40d0-b36b-fafd774d421b') - def test_register_image_with_min_ram(self): - # Register an image with min ram - container_format, disk_format = get_container_and_disk_format() - properties = {'prop1': 'val1'} - body = self.create_image(name='New_image_with_min_ram', - container_format=container_format, - disk_format=disk_format, - is_public=False, - min_ram=40, - properties=properties) - self.assertEqual('New_image_with_min_ram', body.get('name')) - self.assertFalse(body.get('is_public')) - self.assertEqual('queued', body.get('status')) - self.assertEqual(40, body.get('min_ram')) - for key, val in properties.items(): - self.assertEqual(val, body.get('properties')[key]) - self.client.delete_image(body['id']) - - -class ListImagesTest(base.BaseV1ImageTest): - """Here we test the listing of image information""" - - @classmethod - def skip_checks(cls): - super(ListImagesTest, cls).skip_checks() - if (len(CONF.image.container_formats) < 2 - or len(CONF.image.disk_formats) < 2): - skip_msg = ("%s skipped as multiple container formats " - "or disk formats are not available." % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def resource_setup(cls): - super(ListImagesTest, cls).resource_setup() - # We add a few images here to test the listing functionality of - # the images API - a_formats = ['ami', 'ari', 'aki'] - - (cls.container_format, - container_format_alt) = CONF.image.container_formats[:2] - cls.disk_format, cls.disk_format_alt = CONF.image.disk_formats[:2] - if cls.container_format in a_formats: - cls.disk_format = cls.container_format - if container_format_alt in a_formats: - cls.disk_format_alt = container_format_alt - - img1 = cls._create_remote_image('one', cls.container_format, - cls.disk_format) - img2 = cls._create_remote_image('two', container_format_alt, - cls.disk_format_alt) - img3 = cls._create_remote_image('dup', cls.container_format, - cls.disk_format) - img4 = cls._create_remote_image('dup', cls.container_format, - cls.disk_format) - img5 = cls._create_standard_image('1', container_format_alt, - cls.disk_format_alt, 42) - img6 = cls._create_standard_image('2', container_format_alt, - cls.disk_format_alt, 142) - img7 = cls._create_standard_image('33', cls.container_format, - cls.disk_format, 142) - img8 = cls._create_standard_image('33', cls.container_format, - cls.disk_format, 142) - cls.created_set = set(cls.created_images) - # same container format - cls.same_container_format_set = set((img1, img3, img4, img7, img8)) - # same disk format - cls.same_disk_format_set = set((img2, img5, img6)) - - # 1x with size 42 - cls.size42_set = set((img5,)) - # 3x with size 142 - cls.size142_set = set((img6, img7, img8,)) - # dup named - cls.dup_set = set((img3, img4)) - - @classmethod - def _create_remote_image(cls, name, container_format, disk_format): - """Create a new remote image and return newly-registered image-id""" - - name = 'New Remote Image %s' % name - location = CONF.image.http_image - image = cls.create_image(name=name, - container_format=container_format, - disk_format=disk_format, - is_public=False, - location=location) - return image['id'] - - @classmethod - def _create_standard_image(cls, name, container_format, - disk_format, size): - """Create a new standard image and return newly-registered image-id - - Note that the size of the new image is a random number between - 1024 and 4096 - """ - image_file = six.BytesIO(data_utils.random_bytes(size)) - name = 'New Standard Image %s' % name - image = cls.create_image(name=name, - container_format=container_format, - disk_format=disk_format, - is_public=False, data=image_file) - return image['id'] - - @decorators.idempotent_id('246178ab-3b33-4212-9a4b-a7fe8261794d') - def test_index_no_params(self): - # Simple test to see all fixture images returned - images_list = self.client.list_images()['images'] - image_list = [image['id'] for image in images_list] - for image_id in self.created_images: - self.assertIn(image_id, image_list) - - @decorators.idempotent_id('f1755589-63d6-4468-b098-589820eb4031') - def test_index_disk_format(self): - images_list = self.client.list_images( - disk_format=self.disk_format_alt)['images'] - for image in images_list: - self.assertEqual(image['disk_format'], self.disk_format_alt) - result_set = set(map(lambda x: x['id'], images_list)) - self.assertTrue(self.same_disk_format_set <= result_set) - self.assertFalse(self.created_set - self.same_disk_format_set - <= result_set) - - @decorators.idempotent_id('2143655d-96d9-4bec-9188-8674206b4b3b') - def test_index_container_format(self): - images_list = self.client.list_images( - container_format=self.container_format)['images'] - for image in images_list: - self.assertEqual(image['container_format'], self.container_format) - result_set = set(map(lambda x: x['id'], images_list)) - self.assertTrue(self.same_container_format_set <= result_set) - self.assertFalse(self.created_set - self.same_container_format_set - <= result_set) - - @decorators.idempotent_id('feb32ac6-22bb-4a16-afd8-9454bb714b14') - def test_index_max_size(self): - images_list = self.client.list_images(size_max=42)['images'] - for image in images_list: - self.assertLessEqual(image['size'], 42) - result_set = set(map(lambda x: x['id'], images_list)) - self.assertTrue(self.size42_set <= result_set) - self.assertFalse(self.created_set - self.size42_set <= result_set) - - @decorators.idempotent_id('6ffc16d0-4cbf-4401-95c8-4ac63eac34d8') - def test_index_min_size(self): - images_list = self.client.list_images(size_min=142)['images'] - for image in images_list: - self.assertGreaterEqual(image['size'], 142) - result_set = set(map(lambda x: x['id'], images_list)) - self.assertTrue(self.size142_set <= result_set) - self.assertFalse(self.size42_set <= result_set) - - @decorators.idempotent_id('e5dc26d9-9aa2-48dd-bda5-748e1445da98') - def test_index_status_active_detail(self): - images_list = self.client.list_images(detail=True, - status='active', - sort_key='size', - sort_dir='desc')['images'] - top_size = images_list[0]['size'] # We have non-zero sized images - for image in images_list: - size = image['size'] - self.assertLessEqual(size, top_size) - top_size = size - self.assertEqual(image['status'], 'active') - - @decorators.idempotent_id('097af10a-bae8-4342-bff4-edf89969ed2a') - def test_index_name(self): - images_list = self.client.list_images( - detail=True, - name='New Remote Image dup')['images'] - result_set = set(map(lambda x: x['id'], images_list)) - for image in images_list: - self.assertEqual(image['name'], 'New Remote Image dup') - self.assertTrue(self.dup_set <= result_set) - self.assertFalse(self.created_set - self.dup_set <= result_set) - - -class UpdateImageMetaTest(base.BaseV1ImageTest): - @classmethod - def resource_setup(cls): - super(UpdateImageMetaTest, cls).resource_setup() - container_format, disk_format = get_container_and_disk_format() - cls.image_id = cls._create_standard_image('1', container_format, - disk_format, 42) - - @classmethod - def _create_standard_image(cls, name, container_format, - disk_format, size): - """Create a new standard image and return newly-registered image-id""" - - image_file = six.BytesIO(data_utils.random_bytes(size)) - name = 'New Standard Image %s' % name - image = cls.create_image(name=name, - container_format=container_format, - disk_format=disk_format, - is_public=False, data=image_file, - properties={'key1': 'value1'}) - return image['id'] - - @decorators.idempotent_id('01752c1c-0275-4de3-9e5b-876e44541928') - def test_list_image_metadata(self): - # All metadata key/value pairs for an image should be returned - resp = self.client.check_image(self.image_id) - resp_metadata = common_image.get_image_meta_from_headers(resp) - expected = {'key1': 'value1'} - self.assertEqual(expected, resp_metadata['properties']) - - @decorators.idempotent_id('d6d7649c-08ce-440d-9ea7-e3dda552f33c') - def test_update_image_metadata(self): - # The metadata for the image should match the updated values - req_metadata = {'key1': 'alt1', 'key2': 'value2'} - resp = self.client.check_image(self.image_id) - metadata = common_image.get_image_meta_from_headers(resp) - self.assertEqual(metadata['properties'], {'key1': 'value1'}) - metadata['properties'].update(req_metadata) - headers = common_image.image_meta_to_headers( - properties=metadata['properties']) - self.client.update_image(self.image_id, headers=headers) - resp = self.client.check_image(self.image_id) - resp_metadata = common_image.get_image_meta_from_headers(resp) - self.assertEqual(req_metadata, resp_metadata['properties']) diff --git a/tempest/api/image/v1/test_images_negative.py b/tempest/api/image/v1/test_images_negative.py deleted file mode 100644 index 690b8da71..000000000 --- a/tempest/api/image/v1/test_images_negative.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright 2013 IBM 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 tempest.api.image import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class CreateDeleteImagesNegativeTest(base.BaseV1ImageTest): - """Here are negative tests for the deletion and creation of images.""" - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('036ede36-6160-4463-8c01-c781eee6369d') - def test_register_with_invalid_container_format(self): - # Negative tests for invalid data supplied to POST /images - self.assertRaises(lib_exc.BadRequest, self.client.create_image, - headers={'x-image-meta-name': 'test', - 'x-image-meta-container_format': 'wrong', - 'x-image-meta-disk_format': 'vhd'}) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('993face5-921d-4e84-aabf-c1bba4234a67') - def test_register_with_invalid_disk_format(self): - self.assertRaises(lib_exc.BadRequest, self.client.create_image, - headers={'x-image-meta-name': 'test', - 'x-image-meta-container_format': 'bare', - 'x-image-meta-disk_format': 'wrong'}) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ec652588-7e3c-4b67-a2f2-0fa96f57c8fc') - def test_delete_non_existent_image(self): - # Return an error while trying to delete a non-existent image - - non_existent_image_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.delete_image, - non_existent_image_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('04f72aa3-fcec-45a3-81a3-308ef7cc82bc') - def test_delete_image_blank_id(self): - # Return an error while trying to delete an image with blank Id - self.assertRaises(lib_exc.NotFound, self.client.delete_image, '') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('950e5054-a3c7-4dee-ada5-e576f1087abd') - def test_delete_image_non_hex_string_id(self): - # Return an error while trying to delete an image with non hex id - invalid_image_id = data_utils.rand_uuid()[:-1] + "j" - self.assertRaises(lib_exc.NotFound, self.client.delete_image, - invalid_image_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('4ed757cd-450c-44b1-9fd1-c819748c650d') - def test_delete_image_negative_image_id(self): - # Return an error while trying to delete an image with negative id - self.assertRaises(lib_exc.NotFound, self.client.delete_image, -1) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a4a448ab-3db2-4d2d-b9b2-6a1271241dfe') - def test_delete_image_id_over_character_limit(self): - # Return an error while trying to delete image with id over limit - overlimit_image_id = data_utils.rand_uuid() + "1" - self.assertRaises(lib_exc.NotFound, self.client.delete_image, - overlimit_image_id) diff --git a/tempest/api/image/v2/__init__.py b/tempest/api/image/v2/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py deleted file mode 100644 index 2e68efd67..000000000 --- a/tempest/api/image/v2/test_images.py +++ /dev/null @@ -1,390 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# Copyright 2013 IBM 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 random - -import six - -import testtools - -from oslo_log import log as logging -from tempest.api.image import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF -LOG = logging.getLogger(__name__) - - -class BasicOperationsImagesTest(base.BaseV2ImageTest): - """Here we test the basic operations of images""" - - @decorators.attr(type='smoke') - @decorators.idempotent_id('139b765e-7f3d-4b3d-8b37-3ca3876ee318') - def test_register_upload_get_image_file(self): - """Here we test these functionalities - - Register image, upload the image file, get image and get image - file api's - """ - - uuid = '00000000-1111-2222-3333-444455556666' - image_name = data_utils.rand_name('image') - container_format = CONF.image.container_formats[0] - disk_format = CONF.image.disk_formats[0] - image = self.create_image(name=image_name, - container_format=container_format, - disk_format=disk_format, - visibility='private', - ramdisk_id=uuid) - self.assertIn('name', image) - self.assertEqual(image_name, image['name']) - self.assertIn('visibility', image) - self.assertEqual('private', image['visibility']) - self.assertIn('status', image) - self.assertEqual('queued', image['status']) - - # Now try uploading an image file - file_content = data_utils.random_bytes() - image_file = six.BytesIO(file_content) - self.client.store_image_file(image['id'], image_file) - - # Now try to get image details - body = self.client.show_image(image['id']) - self.assertEqual(image['id'], body['id']) - self.assertEqual(image_name, body['name']) - self.assertEqual(uuid, body['ramdisk_id']) - self.assertIn('size', body) - self.assertEqual(1024, body.get('size')) - - # Now try get image file - body = self.client.show_image_file(image['id']) - self.assertEqual(file_content, body.data) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('f848bb94-1c6e-45a4-8726-39e3a5b23535') - def test_delete_image(self): - # Deletes an image by image_id - - # Create image - image_name = data_utils.rand_name('image') - container_format = CONF.image.container_formats[0] - disk_format = CONF.image.disk_formats[0] - image = self.create_image(name=image_name, - container_format=container_format, - disk_format=disk_format, - visibility='private') - # Delete Image - self.client.delete_image(image['id']) - self.client.wait_for_resource_deletion(image['id']) - - # Verifying deletion - images = self.client.list_images()['images'] - images_id = [item['id'] for item in images] - self.assertNotIn(image['id'], images_id) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('f66891a7-a35c-41a8-b590-a065c2a1caa6') - def test_update_image(self): - # Updates an image by image_id - - # Create image - image_name = data_utils.rand_name('image') - container_format = CONF.image.container_formats[0] - disk_format = CONF.image.disk_formats[0] - image = self.create_image(name=image_name, - container_format=container_format, - disk_format=disk_format, - visibility='private') - self.assertEqual('queued', image['status']) - - # Now try uploading an image file - image_file = six.BytesIO(data_utils.random_bytes()) - self.client.store_image_file(image['id'], image_file) - - # Update Image - new_image_name = data_utils.rand_name('new-image') - body = self.client.update_image(image['id'], [ - dict(replace='/name', value=new_image_name)]) - - # Verifying updating - - body = self.client.show_image(image['id']) - self.assertEqual(image['id'], body['id']) - self.assertEqual(new_image_name, body['name']) - - @testtools.skipUnless(CONF.image_feature_enabled.deactivate_image, - 'deactivate-image is not available.') - @decorators.idempotent_id('951ebe01-969f-4ea9-9898-8a3f1f442ab0') - def test_deactivate_reactivate_image(self): - # Create image - image_name = data_utils.rand_name('image') - image = self.create_image(name=image_name, - container_format='bare', - disk_format='raw', - visibility='private') - - # Upload an image file - content = data_utils.random_bytes() - image_file = six.BytesIO(content) - self.client.store_image_file(image['id'], image_file) - - # Deactivate image - self.client.deactivate_image(image['id']) - body = self.client.show_image(image['id']) - self.assertEqual("deactivated", body['status']) - - # User unable to download deactivated image - self.assertRaises(lib_exc.Forbidden, self.client.show_image_file, - image['id']) - - # Reactivate image - self.client.reactivate_image(image['id']) - body = self.client.show_image(image['id']) - self.assertEqual("active", body['status']) - - # User able to download image after reactivation - body = self.client.show_image_file(image['id']) - self.assertEqual(content, body.data) - - -class ListUserImagesTest(base.BaseV2ImageTest): - """Here we test the listing of image information""" - - @classmethod - def resource_setup(cls): - super(ListUserImagesTest, cls).resource_setup() - # We add a few images here to test the listing functionality of - # the images API - container_fmts = CONF.image.container_formats - disk_fmts = CONF.image.disk_formats - all_pairs = [(container_fmt, disk_fmt) - for container_fmt in container_fmts - for disk_fmt in disk_fmts] - - for (container_fmt, disk_fmt) in all_pairs[:6]: - LOG.debug("Creating an image" - "(Container format: %s, Disk format: %s).", - container_fmt, disk_fmt) - cls._create_standard_image(container_fmt, disk_fmt) - - @classmethod - def _create_standard_image(cls, container_format, disk_format): - """Create a new standard image and return the newly-registered image-id - - Note that the size of the new image is a random number between - 1024 and 4096 - """ - size = random.randint(1024, 4096) - image_file = six.BytesIO(data_utils.random_bytes(size)) - tags = [data_utils.rand_name('tag'), data_utils.rand_name('tag')] - image = cls.create_image(container_format=container_format, - disk_format=disk_format, - visibility='private', - tags=tags) - cls.client.store_image_file(image['id'], data=image_file) - # Keep the data of one test image so it can be used to filter lists - cls.test_data = image - - return image['id'] - - def _list_by_param_value_and_assert(self, params): - """Perform list action with given params and validates result.""" - # Retrieve the list of images that meet the filter - images_list = self.client.list_images(params=params)['images'] - # Validating params of fetched images - msg = 'No images were found that met the filter criteria.' - self.assertNotEmpty(images_list, msg) - for image in images_list: - for key in params: - msg = "Failed to list images by %s" % key - self.assertEqual(params[key], image[key], msg) - - def _list_sorted_by_image_size_and_assert(self, params, desc=False): - """Validate an image list that has been sorted by size - - Perform list action with given params and validates the results are - sorted by image size in either ascending or descending order. - """ - # Retrieve the list of images that meet the filter - images_list = self.client.list_images(params=params)['images'] - # Validate that the list was fetched sorted accordingly - msg = 'No images were found that met the filter criteria.' - self.assertNotEmpty(images_list, msg) - sorted_list = [image['size'] for image in images_list] - msg = 'The list of images was not sorted correctly.' - self.assertEqual(sorted(sorted_list, reverse=desc), sorted_list, msg) - - @decorators.idempotent_id('1e341d7a-90a9-494c-b143-2cdf2aeb6aee') - def test_list_no_params(self): - # Simple test to see all fixture images returned - images_list = self.client.list_images()['images'] - image_list = [image['id'] for image in images_list] - - for image in self.created_images: - self.assertIn(image, image_list) - - @decorators.idempotent_id('9959ca1d-1aa7-4b7a-a1ea-0fff0499b37e') - def test_list_images_param_container_format(self): - # Test to get all images with a specific container_format - params = {"container_format": self.test_data['container_format']} - self._list_by_param_value_and_assert(params) - - @decorators.idempotent_id('4a4735a7-f22f-49b6-b0d9-66e1ef7453eb') - def test_list_images_param_disk_format(self): - # Test to get all images with disk_format = raw - params = {"disk_format": "raw"} - self._list_by_param_value_and_assert(params) - - @decorators.idempotent_id('7a95bb92-d99e-4b12-9718-7bc6ab73e6d2') - def test_list_images_param_visibility(self): - # Test to get all images with visibility = private - params = {"visibility": "private"} - self._list_by_param_value_and_assert(params) - - @decorators.idempotent_id('cf1b9a48-8340-480e-af7b-fe7e17690876') - def test_list_images_param_size(self): - # Test to get all images by size - image_id = self.created_images[0] - # Get image metadata - image = self.client.show_image(image_id) - - params = {"size": image['size']} - self._list_by_param_value_and_assert(params) - - @decorators.idempotent_id('4ad8c157-971a-4ba8-aa84-ed61154b1e7f') - def test_list_images_param_min_max_size(self): - # Test to get all images with size between 2000 to 3000 - image_id = self.created_images[0] - # Get image metadata - image = self.client.show_image(image_id) - - size = image['size'] - params = {"size_min": size - 500, "size_max": size + 500} - images_list = self.client.list_images(params=params)['images'] - image_size_list = map(lambda x: x['size'], images_list) - - for image_size in image_size_list: - self.assertGreaterEqual(image_size, params['size_min'], - "Failed to get images by size_min") - self.assertLessEqual(image_size, params['size_max'], - "Failed to get images by size_max") - - @decorators.idempotent_id('7fc9e369-0f58-4d05-9aa5-0969e2d59d15') - def test_list_images_param_status(self): - # Test to get all active images - params = {"status": "active"} - self._list_by_param_value_and_assert(params) - - @decorators.idempotent_id('e914a891-3cc8-4b40-ad32-e0a39ffbddbb') - def test_list_images_param_limit(self): - # Test to get images by limit - params = {"limit": 1} - images_list = self.client.list_images(params=params)['images'] - - self.assertEqual(len(images_list), params['limit'], - "Failed to get images by limit") - - @decorators.idempotent_id('e9a44b91-31c8-4b40-a332-e0a39ffb4dbb') - def test_list_image_param_owner(self): - # Test to get images by owner - image_id = self.created_images[0] - # Get image metadata - image = self.client.show_image(image_id) - - params = {"owner": image['owner']} - self._list_by_param_value_and_assert(params) - - @decorators.idempotent_id('55c8f5f5-bfed-409d-a6d5-4caeda985d7b') - def test_list_images_param_name(self): - # Test to get images by name - params = {'name': self.test_data['name']} - self._list_by_param_value_and_assert(params) - - @decorators.idempotent_id('aa8ac4df-cff9-418b-8d0f-dd9c67b072c9') - def test_list_images_param_tag(self): - # Test to get images matching a tag - params = {'tag': self.test_data['tags'][0]} - images_list = self.client.list_images(params=params)['images'] - # Validating properties of fetched images - self.assertNotEmpty(images_list) - for image in images_list: - msg = ("The image {image_name} does not have the expected tag " - "{expected_tag} among its tags: {observerd_tags}." - .format(image_name=image['name'], - expected_tag=self.test_data['tags'][0], - observerd_tags=image['tags'])) - self.assertIn(self.test_data['tags'][0], image['tags'], msg) - - @decorators.idempotent_id('eeadce49-04e0-43b7-aec7-52535d903e7a') - def test_list_images_param_sort(self): - params = {'sort': 'size:desc'} - self._list_sorted_by_image_size_and_assert(params, desc=True) - - @decorators.idempotent_id('9faaa0c2-c3a5-43e1-8f61-61c54b409a49') - def test_list_images_param_sort_key_dir(self): - params = {'sort_key': 'size', 'sort_dir': 'desc'} - self._list_sorted_by_image_size_and_assert(params, desc=True) - - @decorators.idempotent_id('622b925c-479f-4736-860d-adeaf13bc371') - def test_get_image_schema(self): - # Test to get image schema - schema = "image" - body = self.schemas_client.show_schema(schema) - self.assertEqual("image", body['name']) - - @decorators.idempotent_id('25c8d7b2-df21-460f-87ac-93130bcdc684') - def test_get_images_schema(self): - # Test to get images schema - schema = "images" - body = self.schemas_client.show_schema(schema) - self.assertEqual("images", body['name']) - - -class ListSharedImagesTest(base.BaseV2ImageTest): - """Here we test the listing of a shared image information""" - - credentials = ['primary', 'alt'] - - @classmethod - def setup_clients(cls): - super(ListSharedImagesTest, cls).setup_clients() - cls.image_member_client = cls.os_primary.image_member_client_v2 - cls.alt_img_client = cls.os_alt.image_client_v2 - - @decorators.idempotent_id('3fa50be4-8e38-4c02-a8db-7811bb780122') - def test_list_images_param_member_status(self): - # Create an image to be shared using default visibility - image_file = six.BytesIO(data_utils.random_bytes(2048)) - container_format = CONF.image.container_formats[0] - disk_format = CONF.image.disk_formats[0] - image = self.create_image(container_format=container_format, - disk_format=disk_format) - self.client.store_image_file(image['id'], data=image_file) - - # Share the image created with the alt user - self.image_member_client.create_image_member( - image_id=image['id'], member=self.alt_img_client.tenant_id) - - # As an image consumer you need to provide the member_status parameter - # along with the visibility=shared parameter in order for it to show - # results - params = {'member_status': 'pending', 'visibility': 'shared'} - fetched_images = self.alt_img_client.list_images(params)['images'] - self.assertEqual(1, len(fetched_images)) - self.assertEqual(image['id'], fetched_images[0]['id']) diff --git a/tempest/api/image/v2/test_images_member.py b/tempest/api/image/v2/test_images_member.py deleted file mode 100644 index 02087802c..000000000 --- a/tempest/api/image/v2/test_images_member.py +++ /dev/null @@ -1,98 +0,0 @@ -# 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 tempest.api.image import base -from tempest.lib import decorators - - -class ImagesMemberTest(base.BaseV2MemberImageTest): - - @decorators.idempotent_id('5934c6ea-27dc-4d6e-9421-eeb5e045494a') - def test_image_share_accept(self): - image_id = self._create_image() - member = self.image_member_client.create_image_member( - image_id, member=self.alt_tenant_id) - self.addCleanup(self.image_member_client.delete_image_member, - image_id, self.alt_tenant_id) - self.assertEqual(member['member_id'], self.alt_tenant_id) - self.assertEqual(member['image_id'], image_id) - self.assertEqual(member['status'], 'pending') - self.assertNotIn(image_id, self._list_image_ids_as_alt()) - self.alt_image_member_client.update_image_member(image_id, - self.alt_tenant_id, - status='accepted') - self.assertIn(image_id, self._list_image_ids_as_alt()) - body = self.image_member_client.list_image_members(image_id) - members = body['members'] - member = members[0] - self.assertEqual(len(members), 1, str(members)) - self.assertEqual(member['member_id'], self.alt_tenant_id) - self.assertEqual(member['image_id'], image_id) - self.assertEqual(member['status'], 'accepted') - - @decorators.idempotent_id('d9e83e5f-3524-4b38-a900-22abcb26e90e') - def test_image_share_reject(self): - image_id = self._create_image() - member = self.image_member_client.create_image_member( - image_id, member=self.alt_tenant_id) - self.addCleanup(self.image_member_client.delete_image_member, - image_id, self.alt_tenant_id) - self.assertEqual(member['member_id'], self.alt_tenant_id) - self.assertEqual(member['image_id'], image_id) - self.assertEqual(member['status'], 'pending') - self.assertNotIn(image_id, self._list_image_ids_as_alt()) - self.alt_image_member_client.update_image_member(image_id, - self.alt_tenant_id, - status='rejected') - self.assertNotIn(image_id, self._list_image_ids_as_alt()) - - @decorators.idempotent_id('a6ee18b9-4378-465e-9ad9-9a6de58a3287') - def test_get_image_member(self): - image_id = self._create_image() - self.image_member_client.create_image_member( - image_id, member=self.alt_tenant_id) - self.addCleanup(self.image_member_client.delete_image_member, - image_id, self.alt_tenant_id) - self.alt_image_member_client.update_image_member(image_id, - self.alt_tenant_id, - status='accepted') - - self.assertIn(image_id, self._list_image_ids_as_alt()) - member = self.image_member_client.show_image_member( - image_id, self.alt_tenant_id) - self.assertEqual(self.alt_tenant_id, member['member_id']) - self.assertEqual(image_id, member['image_id']) - self.assertEqual('accepted', member['status']) - - @decorators.idempotent_id('72989bc7-2268-48ed-af22-8821e835c914') - def test_remove_image_member(self): - image_id = self._create_image() - self.image_member_client.create_image_member( - image_id, member=self.alt_tenant_id) - self.alt_image_member_client.update_image_member(image_id, - self.alt_tenant_id, - status='accepted') - - self.assertIn(image_id, self._list_image_ids_as_alt()) - self.image_member_client.delete_image_member(image_id, - self.alt_tenant_id) - self.assertNotIn(image_id, self._list_image_ids_as_alt()) - - @decorators.idempotent_id('634dcc3f-f6e2-4409-b8fd-354a0bb25d83') - def test_get_image_member_schema(self): - body = self.schemas_client.show_schema("member") - self.assertEqual("member", body['name']) - - @decorators.idempotent_id('6ae916ef-1052-4e11-8d36-b3ae14853cbb') - def test_get_image_members_schema(self): - body = self.schemas_client.show_schema("members") - self.assertEqual("members", body['name']) diff --git a/tempest/api/image/v2/test_images_member_negative.py b/tempest/api/image/v2/test_images_member_negative.py deleted file mode 100644 index caa90f9f3..000000000 --- a/tempest/api/image/v2/test_images_member_negative.py +++ /dev/null @@ -1,43 +0,0 @@ -# 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 tempest.api.image import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ImagesMemberNegativeTest(base.BaseV2MemberImageTest): - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('b79efb37-820d-4cf0-b54c-308b00cf842c') - def test_image_share_invalid_status(self): - image_id = self._create_image() - member = self.image_member_client.create_image_member( - image_id, member=self.alt_tenant_id) - self.assertEqual(member['status'], 'pending') - self.assertRaises(lib_exc.BadRequest, - self.alt_image_member_client.update_image_member, - image_id, self.alt_tenant_id, - status='notavalidstatus') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('27002f74-109e-4a37-acd0-f91cd4597967') - def test_image_share_owner_cannot_accept(self): - image_id = self._create_image() - member = self.image_member_client.create_image_member( - image_id, member=self.alt_tenant_id) - self.assertEqual(member['status'], 'pending') - self.assertNotIn(image_id, self._list_image_ids_as_alt()) - self.assertRaises(lib_exc.Forbidden, - self.image_member_client.update_image_member, - image_id, self.alt_tenant_id, status='accepted') - self.assertNotIn(image_id, self._list_image_ids_as_alt()) diff --git a/tempest/api/image/v2/test_images_metadefs_namespace_objects.py b/tempest/api/image/v2/test_images_metadefs_namespace_objects.py deleted file mode 100644 index 80f811211..000000000 --- a/tempest/api/image/v2/test_images_metadefs_namespace_objects.py +++ /dev/null @@ -1,73 +0,0 @@ -# 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 tempest.api.image import base -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - - -class MetadataNamespaceObjectsTest(base.BaseV2ImageTest): - """Test the Metadata definition namespace objects basic functionality""" - - def _create_namespace_object(self, namespace): - object_name = data_utils.rand_name(self.__class__.__name__ + '-object') - namespace_object = self.namespace_objects_client.\ - create_namespace_object(namespace['namespace'], name=object_name) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.namespace_objects_client.delete_namespace_object, - namespace['namespace'], object_name) - return namespace_object - - @decorators.idempotent_id('b1a3775e-3b5c-4f6a-a3b4-1ba3574ae718') - def test_create_update_delete_meta_namespace_objects(self): - # Create a namespace - namespace = self.create_namespace() - # Create a namespace object - body = self._create_namespace_object(namespace) - # Update a namespace object - up_object_name = data_utils.rand_name('update-object') - body = self.namespace_objects_client.update_namespace_object( - namespace['namespace'], body['name'], - name=up_object_name) - self.assertEqual(up_object_name, body['name']) - # Delete a namespace object - self.namespace_objects_client.delete_namespace_object( - namespace['namespace'], up_object_name) - # List namespace objects and validate deletion - namespace_objects = [ - namespace_object['name'] for namespace_object in - self.namespace_objects_client.list_namespace_objects( - namespace['namespace'])['objects']] - self.assertNotIn(up_object_name, namespace_objects) - - @decorators.idempotent_id('a2a3615e-3b5c-3f6a-a2b1-1ba3574ae738') - def test_list_meta_namespace_objects(self): - # Create a namespace object - namespace = self.create_namespace() - meta_namespace_object = self._create_namespace_object(namespace) - # List namespace objects - namespace_objects = [ - namespace_object['name'] for namespace_object in - self.namespace_objects_client.list_namespace_objects( - namespace['namespace'])['objects']] - self.assertIn(meta_namespace_object['name'], namespace_objects) - - @decorators.idempotent_id('b1a3674e-3b4c-3f6a-a3b4-1ba3573ca768') - def test_show_meta_namespace_objects(self): - # Create a namespace object - namespace = self.create_namespace() - namespace_object = self._create_namespace_object(namespace) - # Show a namespace object - body = self.namespace_objects_client.show_namespace_object( - namespace['namespace'], namespace_object['name']) - self.assertEqual(namespace_object['name'], body['name']) diff --git a/tempest/api/image/v2/test_images_metadefs_namespace_properties.py b/tempest/api/image/v2/test_images_metadefs_namespace_properties.py deleted file mode 100644 index ed91726e0..000000000 --- a/tempest/api/image/v2/test_images_metadefs_namespace_properties.py +++ /dev/null @@ -1,57 +0,0 @@ -# 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 tempest.api.image import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class MetadataNamespacePropertiesTest(base.BaseV2ImageTest): - """Test the Metadata definition namespace property basic functionality""" - - @decorators.idempotent_id('b1a3765e-3a5d-4f6d-a3a7-3ca3476ae768') - def test_basic_meta_def_namespace_property(self): - # Get the available resource types and use one resource_type - body = self.resource_types_client.list_resource_types() - resource_name = body['resource_types'][0]['name'] - enum = ["xen", "qemu", "kvm", "lxc", "uml", "vmware", "hyperv"] - # Create a namespace - namespace = self.create_namespace() - # Create resource type association - body = self.resource_types_client.create_resource_type_association( - namespace['namespace'], name=resource_name) - # Create a property - property_title = data_utils.rand_name('property') - body = self.namespace_properties_client.create_namespace_property( - namespace=namespace['namespace'], title=property_title, - name=resource_name, type="string", enum=enum) - self.assertEqual(property_title, body['title']) - # Show namespace property - body = self.namespace_properties_client.show_namespace_properties( - namespace['namespace'], resource_name) - self.assertEqual(resource_name, body['name']) - # Update namespace property - update_property_title = data_utils.rand_name('update-property') - body = self.namespace_properties_client.update_namespace_properties( - namespace['namespace'], resource_name, - title=update_property_title, type="string", - enum=enum, name=resource_name) - self.assertEqual(update_property_title, body['title']) - # Delete namespace property - self.namespace_properties_client.delete_namespace_property( - namespace['namespace'], resource_name) - # List namespace properties and validate deletion - namespace_property = [ - namespace_property['title'] for namespace_property in - self.namespace_properties_client.list_namespace_properties( - namespace['namespace'])['properties']] - self.assertNotIn(update_property_title, namespace_property) diff --git a/tempest/api/image/v2/test_images_metadefs_namespace_tags.py b/tempest/api/image/v2/test_images_metadefs_namespace_tags.py deleted file mode 100644 index 69bebfe30..000000000 --- a/tempest/api/image/v2/test_images_metadefs_namespace_tags.py +++ /dev/null @@ -1,90 +0,0 @@ -# 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 tempest.api.image import base -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - - -class MetadataNamespaceTagsTest(base.BaseV2ImageTest): - """Test the Metadata definition namespace tags basic functionality""" - - tags = [ - { - "name": "sample-tag1" - }, - { - "name": "sample-tag2" - }, - { - "name": "sample-tag3" - } - ] - tag_list = ["sample-tag1", "sample-tag2", "sample-tag3"] - - def _create_namespace_tags(self, namespace): - # Create a namespace - namespace_tags = self.namespace_tags_client.create_namespace_tags( - namespace['namespace'], tags=self.tags) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.namespace_tags_client.delete_namespace_tags, - namespace['namespace']) - return namespace_tags - - @decorators.idempotent_id('a2a3765e-3a6d-4f6d-a3a7-3cc3476aa876') - def test_create_list_delete_namespace_tags(self): - # Create a namespace - namespace = self.create_namespace() - self._create_namespace_tags(namespace) - # List namespace tags - body = self.namespace_tags_client.list_namespace_tags( - namespace['namespace']) - self.assertTrue(3, len(body['tags'])) - self.assertIn(body['tags'][0]['name'], self.tag_list) - self.assertIn(body['tags'][1]['name'], self.tag_list) - self.assertIn(body['tags'][2]['name'], self.tag_list) - # Delete all tag definitions - self.namespace_tags_client.delete_namespace_tags( - namespace['namespace']) - body = self.namespace_tags_client.list_namespace_tags( - namespace['namespace']) - self.assertEmpty(body['tags']) - - @decorators.idempotent_id('a2a3765e-1a2c-3f6d-a3a7-3cc3466ab875') - def test_create_update_delete_tag(self): - # Create a namespace - namespace = self.create_namespace() - self._create_namespace_tags(namespace) - # Create a tag - tag_name = data_utils.rand_name('tag_name') - self.namespace_tags_client.create_namespace_tag( - namespace=namespace['namespace'], tag_name=tag_name) - - body = self.namespace_tags_client.show_namespace_tag( - namespace['namespace'], tag_name) - self.assertEqual(tag_name, body['name']) - # Update tag definition - update_tag_definition = data_utils.rand_name('update-tag') - body = self.namespace_tags_client.update_namespace_tag( - namespace['namespace'], tag_name=tag_name, - name=update_tag_definition) - self.assertEqual(update_tag_definition, body['name']) - # Delete tag definition - self.namespace_tags_client.delete_namespace_tag( - namespace['namespace'], update_tag_definition) - # List namespace tags and validate deletion - namespace_tags = [ - namespace_tag['name'] for namespace_tag in - self.namespace_tags_client.list_namespace_tags( - namespace['namespace'])['tags']] - self.assertNotIn(update_tag_definition, namespace_tags) diff --git a/tempest/api/image/v2/test_images_metadefs_namespaces.py b/tempest/api/image/v2/test_images_metadefs_namespaces.py deleted file mode 100644 index f71b16c4e..000000000 --- a/tempest/api/image/v2/test_images_metadefs_namespaces.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright 2015 Red Hat, Inc. -# 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 tempest.api.image import base -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class MetadataNamespacesTest(base.BaseV2ImageTest): - """Test the Metadata definition Namespaces basic functionality""" - - @decorators.idempotent_id('319b765e-7f3d-4b3d-8b37-3ca3876ee768') - def test_basic_metadata_definition_namespaces(self): - # get the available resource types and use one resource_type - body = self.resource_types_client.list_resource_types() - resource_name = body['resource_types'][0]['name'] - name = [{'name': resource_name}] - namespace_name = data_utils.rand_name('namespace') - # create the metadef namespace - body = self.namespaces_client.create_namespace( - namespace=namespace_name, - visibility='public', - description='Tempest', - display_name=namespace_name, - resource_type_associations=name, - protected=True) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self._cleanup_namespace, namespace_name) - # list namespaces - bodys = self.namespaces_client.list_namespaces()['namespaces'] - body = [namespace['namespace'] for namespace in bodys] - self.assertIn(namespace_name, body) - # get namespace details - body = self.namespaces_client.show_namespace(namespace_name) - self.assertEqual(namespace_name, body['namespace']) - self.assertEqual('public', body['visibility']) - # unable to delete protected namespace - self.assertRaises(lib_exc.Forbidden, - self.namespaces_client.delete_namespace, - namespace_name) - # update the visibility to private and protected to False - body = self.namespaces_client.update_namespace( - namespace=namespace_name, - description='Tempest', - visibility='private', - display_name=namespace_name, - protected=False) - self.assertEqual('private', body['visibility']) - self.assertEqual(False, body['protected']) - # now able to delete the non-protected namespace - self.namespaces_client.delete_namespace(namespace_name) - - def _cleanup_namespace(self, namespace_name): - body = self.namespaces_client.show_namespace(namespace_name) - self.assertEqual(namespace_name, body['namespace']) - body = self.namespaces_client.update_namespace( - namespace=namespace_name, - description='Tempest', - visibility='private', - display_name=namespace_name, - protected=False) - self.namespaces_client.delete_namespace(namespace_name) diff --git a/tempest/api/image/v2/test_images_metadefs_resource_types.py b/tempest/api/image/v2/test_images_metadefs_resource_types.py deleted file mode 100644 index c60b3f716..000000000 --- a/tempest/api/image/v2/test_images_metadefs_resource_types.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2016 Ericsson India Global Services Private Limited -# 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 tempest.api.image import base -from tempest.lib import decorators - - -class MetadataResourceTypesTest(base.BaseV2ImageTest): - """Test the Metadata definition resource types basic functionality""" - - @decorators.idempotent_id('6f358a4e-5ef0-11e6-a795-080027d0d606') - def test_basic_meta_def_resource_type_association(self): - # Get the available resource types and use one resource_type - body = self.resource_types_client.list_resource_types() - resource_name = body['resource_types'][0]['name'] - # Create a namespace - namespace = self.create_namespace() - # Create resource type association - body = self.resource_types_client.create_resource_type_association( - namespace['namespace'], name=resource_name) - self.assertEqual(body['name'], resource_name) - # NOTE(raiesmh08): Here intentionally I have not added addcleanup - # method for resource type dissociation because its a metadata add and - # being cleaned as soon as namespace is cleaned at test case level. - # When namespace cleans, resource type association will automatically - # clean without any error or dependency. - - # List resource type associations and validate creation - rs_type_associations = [ - rs_type_association['name'] for rs_type_association in - self.resource_types_client.list_resource_type_association( - namespace['namespace'])['resource_type_associations']] - self.assertIn(resource_name, rs_type_associations) - # Delete resource type association - self.resource_types_client.delete_resource_type_association( - namespace['namespace'], resource_name) - # List resource type associations and validate deletion - rs_type_associations = [ - rs_type_association['name'] for rs_type_association in - self.resource_types_client.list_resource_type_association( - namespace['namespace'])['resource_type_associations']] - self.assertNotIn(resource_name, rs_type_associations) diff --git a/tempest/api/image/v2/test_images_metadefs_schema.py b/tempest/api/image/v2/test_images_metadefs_schema.py deleted file mode 100644 index 95cc31079..000000000 --- a/tempest/api/image/v2/test_images_metadefs_schema.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright 2016 EasyStack. -# 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 tempest.api.image import base -from tempest.lib import decorators - - -class MetadataSchemaTest(base.BaseV2ImageTest): - """Test to get metadata schema""" - - @decorators.idempotent_id('e9e44891-3cb8-3b40-a532-e0a39fea3dab') - def test_get_metadata_namespace_schema(self): - # Test to get namespace schema - body = self.schemas_client.show_schema("metadefs/namespace") - self.assertEqual("namespace", body['name']) - - @decorators.idempotent_id('ffe44891-678b-3ba0-a3e2-e0a3967b3aeb') - def test_get_metadata_namespaces_schema(self): - # Test to get namespaces schema - body = self.schemas_client.show_schema("metadefs/namespaces") - self.assertEqual("namespaces", body['name']) - - @decorators.idempotent_id('fde34891-678b-3b40-ae32-e0a3e67b6beb') - def test_get_metadata_resource_type_schema(self): - # Test to get resource_type schema - body = self.schemas_client.show_schema("metadefs/resource_type") - self.assertEqual("resource_type_association", body['name']) - - @decorators.idempotent_id('dfe4a891-b38b-3bf0-a3b2-e03ee67b3a3a') - def test_get_metadata_resources_types_schema(self): - # Test to get resource_types schema - body = self.schemas_client.show_schema("metadefs/resource_types") - self.assertEqual("resource_type_associations", body['name']) - - @decorators.idempotent_id('dff4a891-b38b-3bf0-a3b2-e03ee67b3a3b') - def test_get_metadata_object_schema(self): - # Test to get object schema - body = self.schemas_client.show_schema("metadefs/object") - self.assertEqual("object", body['name']) - - @decorators.idempotent_id('dee4a891-b38b-3bf0-a3b2-e03ee67b3a3c') - def test_get_metadata_objects_schema(self): - # Test to get objects schema - body = self.schemas_client.show_schema("metadefs/objects") - self.assertEqual("objects", body['name']) - - @decorators.idempotent_id('dae4a891-b38b-3bf0-a3b2-e03ee67b3a3d') - def test_get_metadata_property_schema(self): - # Test to get property schema - body = self.schemas_client.show_schema("metadefs/property") - self.assertEqual("property", body['name']) - - @decorators.idempotent_id('dce4a891-b38b-3bf0-a3b2-e03ee67b3a3e') - def test_get_metadata_properties_schema(self): - # Test to get properties schema - body = self.schemas_client.show_schema("metadefs/properties") - self.assertEqual("properties", body['name']) - - @decorators.idempotent_id('dde4a891-b38b-3bf0-a3b2-e03ee67b3a3e') - def test_get_metadata_tag_schema(self): - # Test to get tag schema - body = self.schemas_client.show_schema("metadefs/tag") - self.assertEqual("tag", body['name']) - - @decorators.idempotent_id('cde4a891-b38b-3bf0-a3b2-e03ee67b3a3a') - def test_get_metadata_tags_schema(self): - # Test to get tags schema - body = self.schemas_client.show_schema("metadefs/tags") - self.assertEqual("tags", body['name']) diff --git a/tempest/api/image/v2/test_images_negative.py b/tempest/api/image/v2/test_images_negative.py deleted file mode 100644 index b4baf05d3..000000000 --- a/tempest/api/image/v2/test_images_negative.py +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# All Rights Reserved. -# Copyright 2013 IBM Corp. -# -# 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 tempest.api.image import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ImagesNegativeTest(base.BaseV2ImageTest): - - """here we have -ve tests for show_image and delete_image api - - Tests - ** get non-existent image - ** get image with image_id=NULL - ** get the deleted image - ** delete non-existent image - ** delete image with image_id=NULL - ** delete the deleted image - """ - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('668743d5-08ad-4480-b2b8-15da34f81d9f') - def test_get_non_existent_image(self): - # get the non-existent image - non_existent_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.show_image, - non_existent_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ef45000d-0a72-4781-866d-4cb7bf2562ad') - def test_get_image_null_id(self): - # get image with image_id = NULL - image_id = "" - self.assertRaises(lib_exc.NotFound, self.client.show_image, image_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e57fc127-7ba0-4693-92d7-1d8a05ebcba9') - def test_get_delete_deleted_image(self): - # get and delete the deleted image - # create and delete image - image = self.client.create_image(name='test', - container_format='bare', - disk_format='raw') - self.client.delete_image(image['id']) - self.client.wait_for_resource_deletion(image['id']) - - # get the deleted image - self.assertRaises(lib_exc.NotFound, - self.client.show_image, image['id']) - - # delete the deleted image - self.assertRaises(lib_exc.NotFound, self.client.delete_image, - image['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6fe40f1c-57bd-4918-89cc-8500f850f3de') - def test_delete_non_existing_image(self): - # delete non-existent image - non_existent_image_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.delete_image, - non_existent_image_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('32248db1-ab88-4821-9604-c7c369f1f88c') - def test_delete_image_null_id(self): - # delete image with image_id=NULL - image_id = "" - self.assertRaises(lib_exc.NotFound, self.client.delete_image, - image_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('292bd310-369b-41c7-a7a3-10276ef76753') - def test_register_with_invalid_container_format(self): - # Negative tests for invalid data supplied to POST /images - self.assertRaises(lib_exc.BadRequest, self.client.create_image, - name='test', container_format='wrong', - disk_format='vhd') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('70c6040c-5a97-4111-9e13-e73665264ce1') - def test_register_with_invalid_disk_format(self): - self.assertRaises(lib_exc.BadRequest, self.client.create_image, - name='test', container_format='bare', - disk_format='wrong') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ab980a34-8410-40eb-872b-f264752f46e5') - def test_delete_protected_image(self): - # Create a protected image - image = self.create_image(protected=True) - self.addCleanup(self.client.update_image, image['id'], - [dict(replace="/protected", value=False)]) - - # Try deleting the protected image - self.assertRaises(lib_exc.Forbidden, - self.client.delete_image, - image['id']) diff --git a/tempest/api/image/v2/test_images_tags.py b/tempest/api/image/v2/test_images_tags.py deleted file mode 100644 index 601826ee4..000000000 --- a/tempest/api/image/v2/test_images_tags.py +++ /dev/null @@ -1,38 +0,0 @@ -# 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 tempest.api.image import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class ImagesTagsTest(base.BaseV2ImageTest): - - @decorators.idempotent_id('10407036-6059-4f95-a2cd-cbbbee7ed329') - def test_update_delete_tags_for_image(self): - image = self.create_image(container_format='bare', - disk_format='raw', - visibility='private') - tag = data_utils.rand_name('tag') - self.addCleanup(self.client.delete_image, image['id']) - - # Creating image tag and verify it. - self.client.add_image_tag(image['id'], tag) - body = self.client.show_image(image['id']) - self.assertIn(tag, body['tags']) - - # Deleting image tag and verify it. - self.client.delete_image_tag(image['id'], tag) - body = self.client.show_image(image['id']) - self.assertNotIn(tag, body['tags']) diff --git a/tempest/api/image/v2/test_images_tags_negative.py b/tempest/api/image/v2/test_images_tags_negative.py deleted file mode 100644 index 440fa3688..000000000 --- a/tempest/api/image/v2/test_images_tags_negative.py +++ /dev/null @@ -1,43 +0,0 @@ -# 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 tempest.api.image import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ImagesTagsNegativeTest(base.BaseV2ImageTest): - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('8cd30f82-6f9a-4c6e-8034-c1b51fba43d9') - def test_update_tags_for_non_existing_image(self): - # Update tag with non existing image. - tag = data_utils.rand_name('tag') - non_exist_image = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.client.add_image_tag, - non_exist_image, tag) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('39c023a2-325a-433a-9eea-649bf1414b19') - def test_delete_non_existing_tag(self): - # Delete non existing tag. - image = self.create_image(container_format='bare', - disk_format='raw', - visibility='private' - ) - tag = data_utils.rand_name('non-exist-tag') - self.addCleanup(self.client.delete_image, image['id']) - self.assertRaises(lib_exc.NotFound, self.client.delete_image_tag, - image['id'], tag) diff --git a/tempest/api/image/v2/test_versions.py b/tempest/api/image/v2/test_versions.py deleted file mode 100644 index 84f10685c..000000000 --- a/tempest/api/image/v2/test_versions.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2017 NEC Corporation. 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 tempest.api.image import base -from tempest.lib import decorators - - -class VersionsTest(base.BaseV2ImageTest): - - @decorators.idempotent_id('659ea30a-a17c-4317-832c-0f68ed23c31d') - @decorators.attr(type='smoke') - def test_list_versions(self): - versions = self.versions_client.list_versions()['versions'] - expected_resources = ('id', 'links', 'status') - - for version in versions: - for res in expected_resources: - self.assertIn(res, version) diff --git a/tempest/api/network/__init__.py b/tempest/api/network/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/network/admin/__init__.py b/tempest/api/network/admin/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/network/admin/test_agent_management.py b/tempest/api/network/admin/test_agent_management.py deleted file mode 100644 index 7304db92b..000000000 --- a/tempest/api/network/admin/test_agent_management.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# 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 tempest.api.network import base -from tempest.common import tempest_fixtures as fixtures -from tempest.lib import decorators -from tempest import test - - -class AgentManagementTestJSON(base.BaseAdminNetworkTest): - - @classmethod - def skip_checks(cls): - super(AgentManagementTestJSON, cls).skip_checks() - if not test.is_extension_enabled('agent', 'network'): - msg = "agent extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(AgentManagementTestJSON, cls).resource_setup() - body = cls.admin_agents_client.list_agents() - agents = body['agents'] - cls.agent = agents[0] - - @decorators.idempotent_id('9c80f04d-11f3-44a4-8738-ed2f879b0ff4') - def test_list_agent(self): - body = self.admin_agents_client.list_agents() - agents = body['agents'] - # Hearthbeats must be excluded from comparison - self.agent.pop('heartbeat_timestamp', None) - self.agent.pop('configurations', None) - for agent in agents: - agent.pop('heartbeat_timestamp', None) - agent.pop('configurations', None) - self.assertIn(self.agent, agents) - - @decorators.idempotent_id('e335be47-b9a1-46fd-be30-0874c0b751e6') - def test_list_agents_non_admin(self): - body = self.agents_client.list_agents() - self.assertEmpty(body["agents"]) - - @decorators.idempotent_id('869bc8e8-0fda-4a30-9b71-f8a7cf58ca9f') - def test_show_agent(self): - body = self.admin_agents_client.show_agent(self.agent['id']) - agent = body['agent'] - self.assertEqual(agent['id'], self.agent['id']) - - @decorators.idempotent_id('371dfc5b-55b9-4cb5-ac82-c40eadaac941') - def test_update_agent_status(self): - origin_status = self.agent['admin_state_up'] - # Try to update the 'admin_state_up' to the original - # one to avoid the negative effect. - agent_status = {'admin_state_up': origin_status} - body = self.admin_agents_client.update_agent(agent_id=self.agent['id'], - agent=agent_status) - updated_status = body['agent']['admin_state_up'] - self.assertEqual(origin_status, updated_status) - - @decorators.idempotent_id('68a94a14-1243-46e6-83bf-157627e31556') - def test_update_agent_description(self): - self.useFixture(fixtures.LockFixture('agent_description')) - description = 'description for update agent.' - agent_description = {'description': description} - body = self.admin_agents_client.update_agent(agent_id=self.agent['id'], - agent=agent_description) - self.addCleanup(self._restore_agent) - updated_description = body['agent']['description'] - self.assertEqual(updated_description, description) - - def _restore_agent(self): - """Restore the agent description after update test""" - - description = self.agent['description'] or '' - origin_agent = {'description': description} - self.admin_agents_client.update_agent(agent_id=self.agent['id'], - agent=origin_agent) diff --git a/tempest/api/network/admin/test_dhcp_agent_scheduler.py b/tempest/api/network/admin/test_dhcp_agent_scheduler.py deleted file mode 100644 index 485c8f5ed..000000000 --- a/tempest/api/network/admin/test_dhcp_agent_scheduler.py +++ /dev/null @@ -1,98 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# 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 tempest.api.network import base -from tempest.lib import decorators -from tempest import test - - -class DHCPAgentSchedulersTestJSON(base.BaseAdminNetworkTest): - - @classmethod - def skip_checks(cls): - super(DHCPAgentSchedulersTestJSON, cls).skip_checks() - if not test.is_extension_enabled('dhcp_agent_scheduler', 'network'): - msg = "dhcp_agent_scheduler extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(DHCPAgentSchedulersTestJSON, cls).resource_setup() - # Create a network and make sure it will be hosted by a - # dhcp agent: this is done by creating a regular port - cls.network = cls.create_network() - cls.create_subnet(cls.network) - cls.port = cls.create_port(cls.network) - - @decorators.idempotent_id('5032b1fe-eb42-4a64-8f3b-6e189d8b5c7d') - def test_list_dhcp_agent_hosting_network(self): - self.admin_networks_client.list_dhcp_agents_on_hosting_network( - self.network['id']) - - @decorators.idempotent_id('30c48f98-e45d-4ffb-841c-b8aad57c7587') - def test_list_networks_hosted_by_one_dhcp(self): - body = self.admin_networks_client.list_dhcp_agents_on_hosting_network( - self.network['id']) - agents = body['agents'] - self.assertNotEmpty(agents, "no dhcp agent") - agent = agents[0] - self.assertTrue(self._check_network_in_dhcp_agent( - self.network['id'], agent)) - - def _check_network_in_dhcp_agent(self, network_id, agent): - network_ids = [] - body = self.admin_agents_client.list_networks_hosted_by_one_dhcp_agent( - agent['id']) - networks = body['networks'] - for network in networks: - network_ids.append(network['id']) - return network_id in network_ids - - @decorators.idempotent_id('a0856713-6549-470c-a656-e97c8df9a14d') - def test_add_remove_network_from_dhcp_agent(self): - # The agent is now bound to the network, we can free the port - self.ports_client.delete_port(self.port['id']) - self.ports.remove(self.port) - agent = dict() - agent['agent_type'] = None - body = self.admin_agents_client.list_agents() - agents = body['agents'] - for a in agents: - if a['agent_type'] == 'DHCP agent': - agent = a - break - self.assertEqual(agent['agent_type'], 'DHCP agent', 'Could not find ' - 'DHCP agent in agent list though dhcp_agent_scheduler' - ' is enabled.') - network = self.create_network() - network_id = network['id'] - if self._check_network_in_dhcp_agent(network_id, agent): - self._remove_network_from_dhcp_agent(network_id, agent) - self._add_dhcp_agent_to_network(network_id, agent) - else: - self._add_dhcp_agent_to_network(network_id, agent) - self._remove_network_from_dhcp_agent(network_id, agent) - - def _remove_network_from_dhcp_agent(self, network_id, agent): - self.admin_agents_client.delete_network_from_dhcp_agent( - agent_id=agent['id'], - network_id=network_id) - self.assertFalse(self._check_network_in_dhcp_agent( - network_id, agent)) - - def _add_dhcp_agent_to_network(self, network_id, agent): - self.admin_agents_client.add_dhcp_agent_to_network( - agent['id'], network_id=network_id) - self.assertTrue(self._check_network_in_dhcp_agent( - network_id, agent)) diff --git a/tempest/api/network/admin/test_external_network_extension.py b/tempest/api/network/admin/test_external_network_extension.py deleted file mode 100644 index 4d41e3354..000000000 --- a/tempest/api/network/admin/test_external_network_extension.py +++ /dev/null @@ -1,134 +0,0 @@ -# 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 testtools - -from tempest.api.network import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class ExternalNetworksTestJSON(base.BaseAdminNetworkTest): - - @classmethod - def resource_setup(cls): - super(ExternalNetworksTestJSON, cls).resource_setup() - cls.network = cls.create_network() - - def _create_network(self, external=True): - post_body = {'name': data_utils.rand_name('network-')} - if external: - post_body['router:external'] = external - body = self.admin_networks_client.create_network(**post_body) - network = body['network'] - self.addCleanup( - self.admin_networks_client.delete_network, network['id']) - return network - - @decorators.idempotent_id('462be770-b310-4df9-9c42-773217e4c8b1') - def test_create_external_network(self): - # Create a network as an admin user specifying the - # external network extension attribute - ext_network = self._create_network() - # Verifies router:external parameter - self.assertIsNotNone(ext_network['id']) - self.assertTrue(ext_network['router:external']) - - @decorators.idempotent_id('4db5417a-e11c-474d-a361-af00ebef57c5') - def test_update_external_network(self): - # Update a network as an admin user specifying the - # external network extension attribute - network = self._create_network(external=False) - self.assertFalse(network.get('router:external', False)) - update_body = {'router:external': True} - body = self.admin_networks_client.update_network(network['id'], - **update_body) - updated_network = body['network'] - # Verify that router:external parameter was updated - self.assertTrue(updated_network['router:external']) - - @decorators.idempotent_id('39be4c9b-a57e-4ff9-b7c7-b218e209dfcc') - def test_list_external_networks(self): - # Create external_net - external_network = self._create_network() - # List networks as a normal user and confirm the external - # network extension attribute is returned for those networks - # that were created as external - body = self.networks_client.list_networks() - networks_list = [net['id'] for net in body['networks']] - self.assertIn(external_network['id'], networks_list) - self.assertIn(self.network['id'], networks_list) - for net in body['networks']: - if net['id'] == self.network['id']: - self.assertFalse(net['router:external']) - elif net['id'] == external_network['id']: - self.assertTrue(net['router:external']) - - @decorators.idempotent_id('2ac50ab2-7ebd-4e27-b3ce-a9e399faaea2') - def test_show_external_networks_attribute(self): - # Create external_net - external_network = self._create_network() - # Show an external network as a normal user and confirm the - # external network extension attribute is returned. - body = self.networks_client.show_network(external_network['id']) - show_ext_net = body['network'] - self.assertEqual(external_network['name'], show_ext_net['name']) - self.assertEqual(external_network['id'], show_ext_net['id']) - self.assertTrue(show_ext_net['router:external']) - body = self.networks_client.show_network(self.network['id']) - show_net = body['network'] - # Verify with show that router:external is False for network - self.assertEqual(self.network['name'], show_net['name']) - self.assertEqual(self.network['id'], show_net['id']) - self.assertFalse(show_net['router:external']) - - @decorators.idempotent_id('82068503-2cf2-4ed4-b3be-ecb89432e4bb') - @testtools.skipUnless(CONF.network_feature_enabled.floating_ips, - 'Floating ips are not availabled') - def test_delete_external_networks_with_floating_ip(self): - # Verifies external network can be deleted while still holding - # (unassociated) floating IPs - - body = self.admin_networks_client.create_network( - **{'router:external': True}) - external_network = body['network'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.admin_networks_client.delete_network, - external_network['id']) - subnet = self.create_subnet( - external_network, client=self.admin_subnets_client, - enable_dhcp=False) - body = self.admin_floating_ips_client.create_floatingip( - floating_network_id=external_network['id']) - created_floating_ip = body['floatingip'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.admin_floating_ips_client.delete_floatingip, - created_floating_ip['id']) - floatingip_list = self.admin_floating_ips_client.list_floatingips( - network=external_network['id']) - self.assertIn(created_floating_ip['id'], - (f['id'] for f in floatingip_list['floatingips'])) - self.admin_networks_client.delete_network(external_network['id']) - # Verifies floating ip is deleted - floatingip_list = self.admin_floating_ips_client.list_floatingips() - self.assertNotIn(created_floating_ip['id'], - (f['id'] for f in floatingip_list['floatingips'])) - # Verifies subnet is deleted - subnet_list = self.admin_subnets_client.list_subnets() - self.assertNotIn(subnet['id'], - (s['id'] for s in subnet_list)) - # Removes subnet from the cleanup list - self.subnets.remove(subnet) diff --git a/tempest/api/network/admin/test_external_networks_negative.py b/tempest/api/network/admin/test_external_networks_negative.py deleted file mode 100644 index 0709d2ade..000000000 --- a/tempest/api/network/admin/test_external_networks_negative.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# 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 testtools - -from tempest.api.network import base -from tempest import config -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class ExternalNetworksAdminNegativeTestJSON(base.BaseAdminNetworkTest): - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d402ae6c-0be0-4d8e-833b-a738895d98d0') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_create_port_with_precreated_floatingip_as_fixed_ip(self): - # NOTE: External networks can be used to create both floating-ip as - # well as instance-ip. So, creating an instance-ip with a value of a - # pre-created floating-ip should be denied. - - # create a floating ip - body = self.admin_floating_ips_client.create_floatingip( - floating_network_id=CONF.network.public_network_id) - created_floating_ip = body['floatingip'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.admin_floating_ips_client.delete_floatingip, - created_floating_ip['id']) - floating_ip_address = created_floating_ip['floating_ip_address'] - self.assertIsNotNone(floating_ip_address) - - # use the same value of floatingip as fixed-ip to create_port() - fixed_ips = [{'ip_address': floating_ip_address}] - - # create a port which will internally create an instance-ip - self.assertRaises(lib_exc.Conflict, - self.admin_ports_client.create_port, - network_id=CONF.network.public_network_id, - fixed_ips=fixed_ips) diff --git a/tempest/api/network/admin/test_floating_ips_admin_actions.py b/tempest/api/network/admin/test_floating_ips_admin_actions.py deleted file mode 100644 index 7ee819ea7..000000000 --- a/tempest/api/network/admin/test_floating_ips_admin_actions.py +++ /dev/null @@ -1,121 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# 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 tempest.api.network import base -from tempest import config -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class FloatingIPAdminTestJSON(base.BaseAdminNetworkTest): - force_tenant_isolation = True - credentials = ['primary', 'alt', 'admin'] - - @classmethod - def skip_checks(cls): - super(FloatingIPAdminTestJSON, cls).skip_checks() - if not test.is_extension_enabled('router', 'network'): - msg = "router extension not enabled." - raise cls.skipException(msg) - if not CONF.network.public_network_id: - msg = "The public_network_id option must be specified." - raise cls.skipException(msg) - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - @classmethod - def setup_clients(cls): - super(FloatingIPAdminTestJSON, cls).setup_clients() - cls.alt_floating_ips_client = cls.os_alt.floating_ips_client - - @classmethod - def resource_setup(cls): - super(FloatingIPAdminTestJSON, cls).resource_setup() - cls.ext_net_id = CONF.network.public_network_id - cls.floating_ip = cls.create_floatingip(cls.ext_net_id) - cls.network = cls.create_network() - subnet = cls.create_subnet(cls.network) - router = cls.create_router(external_network_id=cls.ext_net_id) - cls.create_router_interface(router['id'], subnet['id']) - cls.port = cls.create_port(cls.network) - - @decorators.idempotent_id('64f2100b-5471-4ded-b46c-ddeeeb4f231b') - def test_list_floating_ips_from_admin_and_nonadmin(self): - # Create floating ip from admin user - floating_ip_admin = self.admin_floating_ips_client.create_floatingip( - floating_network_id=self.ext_net_id) - self.addCleanup(self.admin_floating_ips_client.delete_floatingip, - floating_ip_admin['floatingip']['id']) - # Create floating ip from alt user - body = self.alt_floating_ips_client.create_floatingip( - floating_network_id=self.ext_net_id) - floating_ip_alt = body['floatingip'] - self.addCleanup(self.alt_floating_ips_client.delete_floatingip, - floating_ip_alt['id']) - # List floating ips from admin - body = self.admin_floating_ips_client.list_floatingips() - floating_ip_ids_admin = [f['id'] for f in body['floatingips']] - # Check that admin sees all floating ips - self.assertIn(self.floating_ip['id'], floating_ip_ids_admin) - self.assertIn(floating_ip_admin['floatingip']['id'], - floating_ip_ids_admin) - self.assertIn(floating_ip_alt['id'], floating_ip_ids_admin) - # List floating ips from nonadmin - body = self.floating_ips_client.list_floatingips() - floating_ip_ids = [f['id'] for f in body['floatingips']] - # Check that nonadmin user doesn't see floating ip created from admin - # and floating ip that is created in another project (alt user) - self.assertIn(self.floating_ip['id'], floating_ip_ids) - self.assertNotIn(floating_ip_admin['floatingip']['id'], - floating_ip_ids) - self.assertNotIn(floating_ip_alt['id'], floating_ip_ids) - - @decorators.idempotent_id('32727cc3-abe2-4485-a16e-48f2d54c14f2') - def test_create_list_show_floating_ip_with_tenant_id_by_admin(self): - # Creates a floating IP - body = self.admin_floating_ips_client.create_floatingip( - floating_network_id=self.ext_net_id, - tenant_id=self.network['tenant_id'], - port_id=self.port['id']) - created_floating_ip = body['floatingip'] - self.addCleanup(self.floating_ips_client.delete_floatingip, - created_floating_ip['id']) - self.assertIsNotNone(created_floating_ip['id']) - self.assertIsNotNone(created_floating_ip['tenant_id']) - self.assertIsNotNone(created_floating_ip['floating_ip_address']) - self.assertEqual(created_floating_ip['port_id'], self.port['id']) - self.assertEqual(created_floating_ip['floating_network_id'], - self.ext_net_id) - port = self.port['fixed_ips'] - self.assertEqual(created_floating_ip['fixed_ip_address'], - port[0]['ip_address']) - # Verifies the details of a floating_ip - floating_ip = self.admin_floating_ips_client.show_floatingip( - created_floating_ip['id']) - shown_floating_ip = floating_ip['floatingip'] - self.assertEqual(shown_floating_ip['id'], created_floating_ip['id']) - self.assertEqual(shown_floating_ip['floating_network_id'], - self.ext_net_id) - self.assertEqual(shown_floating_ip['tenant_id'], - self.network['tenant_id']) - self.assertEqual(shown_floating_ip['floating_ip_address'], - created_floating_ip['floating_ip_address']) - self.assertEqual(shown_floating_ip['port_id'], self.port['id']) - # Verify the floating ip exists in the list of all floating_ips - floating_ips = self.admin_floating_ips_client.list_floatingips() - floatingip_id_list = [f['id'] for f in floating_ips['floatingips']] - self.assertIn(created_floating_ip['id'], floatingip_id_list) diff --git a/tempest/api/network/admin/test_l3_agent_scheduler.py b/tempest/api/network/admin/test_l3_agent_scheduler.py deleted file mode 100644 index 85b2472e8..000000000 --- a/tempest/api/network/admin/test_l3_agent_scheduler.py +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# 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 tempest.api.network import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions -from tempest import test - -CONF = config.CONF -AGENT_TYPE = 'L3 agent' -AGENT_MODES = ( - 'legacy', - 'dvr_snat' -) - - -class L3AgentSchedulerTestJSON(base.BaseAdminNetworkTest): - """Tests the following operations in the Neutron API: - - List routers that the given L3 agent is hosting. - List L3 agents hosting the given router. - Add and Remove Router to L3 agent - - v2.0 of the Neutron API is assumed. - - The l3_agent_scheduler extension is required for these tests. - """ - - @classmethod - def skip_checks(cls): - super(L3AgentSchedulerTestJSON, cls).skip_checks() - if not test.is_extension_enabled('l3_agent_scheduler', 'network'): - msg = "L3 Agent Scheduler Extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(L3AgentSchedulerTestJSON, cls).resource_setup() - agents = cls.admin_agents_client.list_agents( - agent_type=AGENT_TYPE)['agents'] - for agent in agents: - if agent['configurations']['agent_mode'] in AGENT_MODES: - cls.agent = agent - break - else: - msg = "L3 Agent Scheduler enabled in conf, but L3 Agent not found" - raise exceptions.InvalidConfiguration(msg) - cls.router = cls.create_router() - - @decorators.idempotent_id('b7ce6e89-e837-4ded-9b78-9ed3c9c6a45a') - def test_list_routers_on_l3_agent(self): - self.admin_agents_client.list_routers_on_l3_agent(self.agent['id']) - - @decorators.idempotent_id('9464e5e7-8625-49c3-8fd1-89c52be59d66') - def test_add_list_remove_router_on_l3_agent(self): - l3_agent_ids = list() - self.admin_agents_client.create_router_on_l3_agent( - self.agent['id'], - router_id=self.router['id']) - body = ( - self.admin_routers_client.list_l3_agents_hosting_router( - self.router['id'])) - for agent in body['agents']: - l3_agent_ids.append(agent['id']) - self.assertIn('agent_type', agent) - self.assertEqual('L3 agent', agent['agent_type']) - self.assertIn(self.agent['id'], l3_agent_ids) - body = self.admin_agents_client.delete_router_from_l3_agent( - self.agent['id'], - self.router['id']) - # NOTE(afazekas): The deletion not asserted, because neutron - # is not forbidden to reschedule the router to the same agent diff --git a/tempest/api/network/admin/test_metering_extensions.py b/tempest/api/network/admin/test_metering_extensions.py deleted file mode 100644 index 21a7ab4ea..000000000 --- a/tempest/api/network/admin/test_metering_extensions.py +++ /dev/null @@ -1,168 +0,0 @@ -# Copyright (C) 2014 eNovance SAS -# -# 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 tempest.api.network import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - - -class MeteringTestJSON(base.BaseAdminNetworkTest): - """Tests the following operations in the Neutron API: - - List, Show, Create, Delete Metering labels - List, Show, Create, Delete Metering labels rules - """ - - @classmethod - def skip_checks(cls): - super(MeteringTestJSON, cls).skip_checks() - if not test.is_extension_enabled('metering', 'network'): - msg = "metering extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(MeteringTestJSON, cls).resource_setup() - description = "metering label created by tempest" - name = data_utils.rand_name("metering-label") - cls.metering_label = cls.create_metering_label(name, description) - remote_ip_prefix = ("10.0.0.0/24" if cls._ip_version == 4 - else "fd02::/64") - direction = "ingress" - cls.metering_label_rule = cls.create_metering_label_rule( - remote_ip_prefix, direction, - metering_label_id=cls.metering_label['id']) - - @classmethod - def create_metering_label(cls, name, description): - """Wrapper utility that returns a test metering label.""" - body = cls.admin_metering_labels_client.create_metering_label( - description=description, - name=name) - metering_label = body['metering_label'] - cls.metering_labels.append(metering_label) - return metering_label - - @classmethod - def create_metering_label_rule(cls, remote_ip_prefix, direction, - metering_label_id): - """Wrapper utility that returns a test metering label rule.""" - client = cls.admin_metering_label_rules_client - body = client.create_metering_label_rule( - remote_ip_prefix=remote_ip_prefix, direction=direction, - metering_label_id=metering_label_id) - metering_label_rule = body['metering_label_rule'] - cls.metering_label_rules.append(metering_label_rule) - return metering_label_rule - - def _delete_metering_label(self, metering_label_id): - # Deletes a label and verifies if it is deleted or not - self.admin_metering_labels_client.delete_metering_label( - metering_label_id) - # Asserting that the label is not found in list after deletion - labels = self.admin_metering_labels_client.list_metering_labels( - id=metering_label_id) - self.assertEmpty(labels['metering_labels']) - - def _delete_metering_label_rule(self, metering_label_rule_id): - client = self.admin_metering_label_rules_client - # Deletes a rule and verifies if it is deleted or not - client.delete_metering_label_rule(metering_label_rule_id) - # Asserting that the rule is not found in list after deletion - rules = client.list_metering_label_rules(id=metering_label_rule_id) - self.assertEqual(len(rules['metering_label_rules']), 0) - - @decorators.idempotent_id('e2fb2f8c-45bf-429a-9f17-171c70444612') - def test_list_metering_labels(self): - # Verify label filtering - body = self.admin_metering_labels_client.list_metering_labels(id=33) - metering_labels = body['metering_labels'] - self.assertEmpty(metering_labels) - - @decorators.idempotent_id('ec8e15ff-95d0-433b-b8a6-b466bddb1e50') - def test_create_delete_metering_label_with_filters(self): - # Creates a label - name = data_utils.rand_name('metering-label-') - description = "label created by tempest" - body = self.admin_metering_labels_client.create_metering_label( - name=name, description=description) - metering_label = body['metering_label'] - self.addCleanup(self._delete_metering_label, - metering_label['id']) - # Assert whether created labels are found in labels list or fail - # if created labels are not found in labels list - labels = (self.admin_metering_labels_client.list_metering_labels( - id=metering_label['id'])) - self.assertEqual(len(labels['metering_labels']), 1) - - @decorators.idempotent_id('30abb445-0eea-472e-bd02-8649f54a5968') - def test_show_metering_label(self): - # Verifies the details of a label - body = self.admin_metering_labels_client.show_metering_label( - self.metering_label['id']) - metering_label = body['metering_label'] - self.assertEqual(self.metering_label['id'], metering_label['id']) - self.assertEqual(self.metering_label['tenant_id'], - metering_label['tenant_id']) - self.assertEqual(self.metering_label['name'], metering_label['name']) - self.assertEqual(self.metering_label['description'], - metering_label['description']) - - @decorators.idempotent_id('cc832399-6681-493b-9d79-0202831a1281') - def test_list_metering_label_rules(self): - client = self.admin_metering_label_rules_client - # Verify rule filtering - body = client.list_metering_label_rules(id=33) - metering_label_rules = body['metering_label_rules'] - self.assertEmpty(metering_label_rules) - - @decorators.idempotent_id('f4d547cd-3aee-408f-bf36-454f8825e045') - def test_create_delete_metering_label_rule_with_filters(self): - # Creates a rule - remote_ip_prefix = ("10.0.1.0/24" if self._ip_version == 4 - else "fd03::/64") - client = self.admin_metering_label_rules_client - body = (client.create_metering_label_rule( - remote_ip_prefix=remote_ip_prefix, - direction="ingress", - metering_label_id=self.metering_label['id'])) - metering_label_rule = body['metering_label_rule'] - self.addCleanup(self._delete_metering_label_rule, - metering_label_rule['id']) - # Assert whether created rules are found in rules list or fail - # if created rules are not found in rules list - rules = client.list_metering_label_rules(id=metering_label_rule['id']) - self.assertEqual(len(rules['metering_label_rules']), 1) - - @decorators.idempotent_id('b7354489-96ea-41f3-9452-bace120fb4a7') - def test_show_metering_label_rule(self): - # Verifies the details of a rule - client = self.admin_metering_label_rules_client - body = (client.show_metering_label_rule( - self.metering_label_rule['id'])) - metering_label_rule = body['metering_label_rule'] - self.assertEqual(self.metering_label_rule['id'], - metering_label_rule['id']) - self.assertEqual(self.metering_label_rule['remote_ip_prefix'], - metering_label_rule['remote_ip_prefix']) - self.assertEqual(self.metering_label_rule['direction'], - metering_label_rule['direction']) - self.assertEqual(self.metering_label_rule['metering_label_id'], - metering_label_rule['metering_label_id']) - self.assertFalse(metering_label_rule['excluded']) - - -class MeteringIpV6TestJSON(MeteringTestJSON): - _ip_version = 6 diff --git a/tempest/api/network/admin/test_negative_quotas.py b/tempest/api/network/admin/test_negative_quotas.py deleted file mode 100644 index 21688d242..000000000 --- a/tempest/api/network/admin/test_negative_quotas.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2015 Cloudwatt -# 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 tempest.api.network import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - - -class QuotasNegativeTest(base.BaseAdminNetworkTest): - """Tests the following operations in the Neutron API: - - set network quota and exceed this quota - - v2.0 of the API is assumed. - It is also assumed that the per-project quota extension API is configured - in /etc/neutron/neutron.conf as follows: - - quota_driver = neutron.db.quota_db.DbQuotaDriver - """ - force_tenant_isolation = True - - @classmethod - def skip_checks(cls): - super(QuotasNegativeTest, cls).skip_checks() - if not test.is_extension_enabled('quotas', 'network'): - msg = "quotas extension not enabled." - raise cls.skipException(msg) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('644f4e1b-1bf9-4af0-9fd8-eb56ac0f51cf') - def test_network_quota_exceeding(self): - # Set the network quota to two - self.admin_quotas_client.update_quotas(self.networks_client.tenant_id, - network=2) - self.addCleanup(self.admin_quotas_client.reset_quotas, - self.networks_client.tenant_id) - - # Create two networks - n1 = self.networks_client.create_network() - self.addCleanup(self.networks_client.delete_network, - n1['network']['id']) - n2 = self.networks_client.create_network() - self.addCleanup(self.networks_client.delete_network, - n2['network']['id']) - - # Try to create a third network while the quota is two - with self.assertRaisesRegex( - lib_exc.Conflict, - "Quota exceeded for resources: \['network'\].*"): - n3 = self.networks_client.create_network() - self.addCleanup(self.networks_client.delete_network, - n3['network']['id']) diff --git a/tempest/api/network/admin/test_ports.py b/tempest/api/network/admin/test_ports.py deleted file mode 100644 index 807994b9f..000000000 --- a/tempest/api/network/admin/test_ports.py +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# 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 socket - -from tempest.api.network import base -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class PortsAdminExtendedAttrsTestJSON(base.BaseAdminNetworkTest): - - @classmethod - def resource_setup(cls): - super(PortsAdminExtendedAttrsTestJSON, cls).resource_setup() - cls.network = cls.create_network() - cls.host_id = socket.gethostname() - - @decorators.idempotent_id('8e8569c1-9ac7-44db-8bc1-f5fb2814f29b') - def test_create_port_binding_ext_attr(self): - post_body = {"network_id": self.network['id'], - "binding:host_id": self.host_id} - body = self.admin_ports_client.create_port(**post_body) - port = body['port'] - self.addCleanup(self.admin_ports_client.delete_port, port['id']) - host_id = port['binding:host_id'] - self.assertIsNotNone(host_id) - self.assertEqual(self.host_id, host_id) - - @decorators.idempotent_id('6f6c412c-711f-444d-8502-0ac30fbf5dd5') - def test_update_port_binding_ext_attr(self): - post_body = {"network_id": self.network['id']} - body = self.admin_ports_client.create_port(**post_body) - port = body['port'] - self.addCleanup(self.admin_ports_client.delete_port, port['id']) - update_body = {"binding:host_id": self.host_id} - body = self.admin_ports_client.update_port(port['id'], **update_body) - updated_port = body['port'] - host_id = updated_port['binding:host_id'] - self.assertIsNotNone(host_id) - self.assertEqual(self.host_id, host_id) - - @decorators.idempotent_id('1c82a44a-6c6e-48ff-89e1-abe7eaf8f9f8') - def test_list_ports_binding_ext_attr(self): - # Create a new port - post_body = {"network_id": self.network['id']} - body = self.admin_ports_client.create_port(**post_body) - port = body['port'] - self.addCleanup(self.admin_ports_client.delete_port, port['id']) - - # Update the port's binding attributes so that is now 'bound' - # to a host - update_body = {"binding:host_id": self.host_id} - self.admin_ports_client.update_port(port['id'], **update_body) - - # List all ports, ensure new port is part of list and its binding - # attributes are set and accurate - body = self.admin_ports_client.list_ports() - ports_list = body['ports'] - pids_list = [p['id'] for p in ports_list] - self.assertIn(port['id'], pids_list) - listed_port = [p for p in ports_list if p['id'] == port['id']] - self.assertEqual(1, len(listed_port), - 'Multiple ports listed with id %s in ports listing: ' - '%s' % (port['id'], ports_list)) - self.assertEqual(self.host_id, listed_port[0]['binding:host_id']) - - @decorators.idempotent_id('b54ac0ff-35fc-4c79-9ca3-c7dbd4ea4f13') - def test_show_port_binding_ext_attr(self): - body = self.admin_ports_client.create_port( - network_id=self.network['id']) - port = body['port'] - self.addCleanup(self.admin_ports_client.delete_port, port['id']) - body = self.admin_ports_client.show_port(port['id']) - show_port = body['port'] - self.assertEqual(port['binding:host_id'], - show_port['binding:host_id']) - self.assertEqual(port['binding:vif_type'], - show_port['binding:vif_type']) - self.assertEqual(port['binding:vif_details'], - show_port['binding:vif_details']) - - -class PortsAdminExtendedAttrsIpV6TestJSON(PortsAdminExtendedAttrsTestJSON): - _ip_version = 6 diff --git a/tempest/api/network/admin/test_quotas.py b/tempest/api/network/admin/test_quotas.py deleted file mode 100644 index aa8b2dca9..000000000 --- a/tempest/api/network/admin/test_quotas.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 tempest.api.network import base -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest import test - - -class QuotasTest(base.BaseAdminNetworkTest): - """Tests the following operations in the Neutron API: - - list quotas for projects who have non-default quota values - show quotas for a specified project - update quotas for a specified project - reset quotas to default values for a specified project - - v2.0 of the API is assumed. - It is also assumed that the per-project quota extension API is configured - in /etc/neutron/neutron.conf as follows: - - quota_driver = neutron.db.quota_db.DbQuotaDriver - """ - - @classmethod - def skip_checks(cls): - super(QuotasTest, cls).skip_checks() - if not test.is_extension_enabled('quotas', 'network'): - msg = "quotas extension not enabled." - raise cls.skipException(msg) - - def _check_quotas(self, new_quotas): - # Add a project to conduct the test - project = data_utils.rand_name('test_project_') - description = data_utils.rand_name('desc_') - project = self.identity_utils.create_project(name=project, - description=description) - project_id = project['id'] - self.addCleanup(self.identity_utils.delete_project, project_id) - - # Change quotas for project - quota_set = self.admin_quotas_client.update_quotas( - project_id, **new_quotas)['quota'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.admin_quotas_client.reset_quotas, project_id) - for key, value in new_quotas.items(): - self.assertEqual(value, quota_set[key]) - - # Confirm our project is listed among projects with non default quotas - non_default_quotas = self.admin_quotas_client.list_quotas() - found = False - for qs in non_default_quotas['quotas']: - if qs['tenant_id'] == project_id: - found = True - self.assertTrue(found) - - # Confirm from API quotas were changed as requested for project - quota_set = self.admin_quotas_client.show_quotas(project_id) - quota_set = quota_set['quota'] - for key, value in new_quotas.items(): - self.assertEqual(value, quota_set[key]) - - # Reset quotas to default and confirm - self.admin_quotas_client.reset_quotas(project_id) - non_default_quotas = self.admin_quotas_client.list_quotas() - for q in non_default_quotas['quotas']: - self.assertNotEqual(project_id, q['tenant_id']) - - @decorators.idempotent_id('2390f766-836d-40ef-9aeb-e810d78207fb') - def test_quotas(self): - new_quotas = {'network': 0, 'port': 0} - self._check_quotas(new_quotas) diff --git a/tempest/api/network/admin/test_routers.py b/tempest/api/network/admin/test_routers.py deleted file mode 100644 index f180cdaea..000000000 --- a/tempest/api/network/admin/test_routers.py +++ /dev/null @@ -1,224 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 testtools - -from tempest.api.network import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class RoutersAdminTest(base.BaseAdminNetworkTest): - # NOTE(salv-orlando): This class inherits from BaseAdminNetworkTest - # as some router operations, such as enabling or disabling SNAT - # require admin credentials by default - - def _cleanup_router(self, router): - self.delete_router(router) - self.routers.remove(router) - - def _create_router(self, name=None, admin_state_up=False, - external_network_id=None, enable_snat=None): - # associate a cleanup with created routers to avoid quota limits - router = self.create_router(name, admin_state_up, - external_network_id, enable_snat) - self.addCleanup(self._cleanup_router, router) - return router - - def _add_router_interface_with_subnet_id(self, router_id, subnet_id): - interface = self.routers_client.add_router_interface( - router_id, subnet_id=subnet_id) - self.addCleanup(self._remove_router_interface_with_subnet_id, - router_id, subnet_id) - self.assertEqual(subnet_id, interface['subnet_id']) - return interface - - def _remove_router_interface_with_subnet_id(self, router_id, subnet_id): - body = self.routers_client.remove_router_interface(router_id, - subnet_id=subnet_id) - self.assertEqual(subnet_id, body['subnet_id']) - - @classmethod - def skip_checks(cls): - super(RoutersAdminTest, cls).skip_checks() - if not test.is_extension_enabled('router', 'network'): - msg = "router extension not enabled." - raise cls.skipException(msg) - - @decorators.idempotent_id('e54dd3a3-4352-4921-b09d-44369ae17397') - def test_create_router_setting_project_id(self): - # Test creating router from admin user setting project_id. - project = data_utils.rand_name('test_tenant_') - description = data_utils.rand_name('desc_') - project = self.identity_utils.create_project(name=project, - description=description) - project_id = project['id'] - self.addCleanup(self.identity_utils.delete_project, project_id) - - name = data_utils.rand_name('router-') - create_body = self.admin_routers_client.create_router( - name=name, tenant_id=project_id) - self.addCleanup(self.admin_routers_client.delete_router, - create_body['router']['id']) - self.assertEqual(project_id, create_body['router']['tenant_id']) - - @decorators.idempotent_id('847257cc-6afd-4154-b8fb-af49f5670ce8') - @test.requires_ext(extension='ext-gw-mode', service='network') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_create_router_with_default_snat_value(self): - # Create a router with default snat rule - router = self._create_router( - external_network_id=CONF.network.public_network_id) - self._verify_router_gateway( - router['id'], {'network_id': CONF.network.public_network_id, - 'enable_snat': True}) - - @decorators.idempotent_id('ea74068d-09e9-4fd7-8995-9b6a1ace920f') - @test.requires_ext(extension='ext-gw-mode', service='network') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_create_router_with_snat_explicit(self): - name = data_utils.rand_name('snat-router') - # Create a router enabling snat attributes - enable_snat_states = [False, True] - for enable_snat in enable_snat_states: - external_gateway_info = { - 'network_id': CONF.network.public_network_id, - 'enable_snat': enable_snat} - create_body = self.admin_routers_client.create_router( - name=name, external_gateway_info=external_gateway_info) - self.addCleanup(self.admin_routers_client.delete_router, - create_body['router']['id']) - # Verify snat attributes after router creation - self._verify_router_gateway(create_body['router']['id'], - exp_ext_gw_info=external_gateway_info) - - def _verify_router_gateway(self, router_id, exp_ext_gw_info=None): - show_body = self.admin_routers_client.show_router(router_id) - actual_ext_gw_info = show_body['router']['external_gateway_info'] - if exp_ext_gw_info is None: - self.assertIsNone(actual_ext_gw_info) - return - # Verify only keys passed in exp_ext_gw_info - for k, v in exp_ext_gw_info.items(): - self.assertEqual(v, actual_ext_gw_info[k]) - - def _verify_gateway_port(self, router_id): - list_body = self.admin_ports_client.list_ports( - network_id=CONF.network.public_network_id, - device_id=router_id) - self.assertEqual(len(list_body['ports']), 1) - gw_port = list_body['ports'][0] - fixed_ips = gw_port['fixed_ips'] - self.assertNotEmpty(fixed_ips) - # Assert that all of the IPs from the router gateway port - # are allocated from a valid public subnet. - public_net_body = self.admin_networks_client.show_network( - CONF.network.public_network_id) - public_subnet_ids = public_net_body['network']['subnets'] - for fixed_ip in fixed_ips: - subnet_id = fixed_ip['subnet_id'] - self.assertIn(subnet_id, public_subnet_ids) - - @decorators.idempotent_id('6cc285d8-46bf-4f36-9b1a-783e3008ba79') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_update_router_set_gateway(self): - router = self._create_router() - self.routers_client.update_router( - router['id'], - external_gateway_info={ - 'network_id': CONF.network.public_network_id}) - # Verify operation - router - self._verify_router_gateway( - router['id'], - {'network_id': CONF.network.public_network_id}) - self._verify_gateway_port(router['id']) - - @decorators.idempotent_id('b386c111-3b21-466d-880c-5e72b01e1a33') - @test.requires_ext(extension='ext-gw-mode', service='network') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_update_router_set_gateway_with_snat_explicit(self): - router = self._create_router() - self.admin_routers_client.update_router( - router['id'], - external_gateway_info={ - 'network_id': CONF.network.public_network_id, - 'enable_snat': True}) - self._verify_router_gateway( - router['id'], - {'network_id': CONF.network.public_network_id, - 'enable_snat': True}) - self._verify_gateway_port(router['id']) - - @decorators.idempotent_id('96536bc7-8262-4fb2-9967-5c46940fa279') - @test.requires_ext(extension='ext-gw-mode', service='network') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_update_router_set_gateway_without_snat(self): - router = self._create_router() - self.admin_routers_client.update_router( - router['id'], - external_gateway_info={ - 'network_id': CONF.network.public_network_id, - 'enable_snat': False}) - self._verify_router_gateway( - router['id'], - {'network_id': CONF.network.public_network_id, - 'enable_snat': False}) - self._verify_gateway_port(router['id']) - - @decorators.idempotent_id('ad81b7ee-4f81-407b-a19c-17e623f763e8') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_update_router_unset_gateway(self): - router = self._create_router( - external_network_id=CONF.network.public_network_id) - self.routers_client.update_router(router['id'], - external_gateway_info={}) - self._verify_router_gateway(router['id']) - # No gateway port expected - list_body = self.admin_ports_client.list_ports( - network_id=CONF.network.public_network_id, - device_id=router['id']) - self.assertFalse(list_body['ports']) - - @decorators.idempotent_id('f2faf994-97f4-410b-a831-9bc977b64374') - @test.requires_ext(extension='ext-gw-mode', service='network') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_update_router_reset_gateway_without_snat(self): - router = self._create_router( - external_network_id=CONF.network.public_network_id) - self.admin_routers_client.update_router( - router['id'], - external_gateway_info={ - 'network_id': CONF.network.public_network_id, - 'enable_snat': False}) - self._verify_router_gateway( - router['id'], - {'network_id': CONF.network.public_network_id, - 'enable_snat': False}) - self._verify_gateway_port(router['id']) - - -class RoutersIpV6AdminTest(RoutersAdminTest): - _ip_version = 6 diff --git a/tempest/api/network/admin/test_routers_dvr.py b/tempest/api/network/admin/test_routers_dvr.py deleted file mode 100644 index f9a0cfb51..000000000 --- a/tempest/api/network/admin/test_routers_dvr.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright 2015 OpenStack Foundation -# 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 testtools - -from tempest.api.network import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - - -class RoutersTestDVR(base.BaseAdminNetworkTest): - - @classmethod - def resource_setup(cls): - for ext in ['router', 'dvr']: - if not test.is_extension_enabled(ext, 'network'): - msg = "%s extension not enabled." % ext - raise cls.skipException(msg) - # The check above will pass if api_extensions=all, which does - # not mean DVR extension itself is present. - # Instead, we have to check whether DVR is actually present by using - # admin credentials to create router with distributed=True attribute - # and checking for BadRequest exception and that the resulting router - # has a distributed attribute. - super(RoutersTestDVR, cls).resource_setup() - name = data_utils.rand_name('pretest-check') - router = cls.admin_routers_client.create_router(name=name) - cls.admin_routers_client.delete_router(router['router']['id']) - if 'distributed' not in router['router']: - msg = "'distributed' flag not found. DVR Possibly not enabled" - raise cls.skipException(msg) - - @decorators.idempotent_id('08a2a0a8-f1e4-4b34-8e30-e522e836c44e') - def test_distributed_router_creation(self): - """Test distributed router creation - - Test uses administrative credentials to creates a - DVR (Distributed Virtual Routing) router using the - distributed=True. - - Acceptance - The router is created and the "distributed" attribute is - set to True - """ - name = data_utils.rand_name('router') - router = self.admin_routers_client.create_router(name=name, - distributed=True) - self.addCleanup(self.admin_routers_client.delete_router, - router['router']['id']) - self.assertTrue(router['router']['distributed']) - - @decorators.idempotent_id('8a0a72b4-7290-4677-afeb-b4ffe37bc352') - def test_centralized_router_creation(self): - """Test centralized router creation - - Test uses administrative credentials to creates a - CVR (Centralized Virtual Routing) router using the - distributed=False. - - Acceptance - The router is created and the "distributed" attribute is - set to False, thus making it a "Centralized Virtual Router" - as opposed to a "Distributed Virtual Router" - """ - name = data_utils.rand_name('router') - router = self.admin_routers_client.create_router(name=name, - distributed=False) - self.addCleanup(self.admin_routers_client.delete_router, - router['router']['id']) - self.assertFalse(router['router']['distributed']) - - @decorators.idempotent_id('acd43596-c1fb-439d-ada8-31ad48ae3c2e') - @testtools.skipUnless(test.is_extension_enabled('l3-ha', 'network'), - 'HA routers are not available.') - def test_centralized_router_update_to_dvr(self): - """Test centralized router update - - Test uses administrative credentials to creates a - CVR (Centralized Virtual Routing) router using the - distributed=False. Then it will "update" the router - distributed attribute to True - - Acceptance - The router is created and the "distributed" attribute is - set to False. Once the router is updated, the distributed - attribute will be set to True - """ - name = data_utils.rand_name('router') - tenant_id = self.routers_client.tenant_id - # router needs to be in admin state down in order to be upgraded to DVR - # l3ha routers are not upgradable to dvr, make it explicitly non ha - router = self.admin_routers_client.create_router(name=name, - distributed=False, - admin_state_up=False, - ha=False, - tenant_id=tenant_id) - router_id = router['router']['id'] - self.addCleanup(self.admin_routers_client.delete_router, - router_id) - self.assertFalse(router['router']['distributed']) - router = self.admin_routers_client.update_router( - router_id, distributed=True) - self.assertTrue(router['router']['distributed']) - show_body = self.admin_routers_client.show_router(router_id) - self.assertTrue(show_body['router']['distributed']) - show_body = self.routers_client.show_router(router_id) - self.assertNotIn('distributed', show_body['router']) diff --git a/tempest/api/network/admin/test_routers_negative.py b/tempest/api/network/admin/test_routers_negative.py deleted file mode 100644 index f350a1571..000000000 --- a/tempest/api/network/admin/test_routers_negative.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 testtools - -from tempest.api.network import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class RoutersAdminNegativeTest(base.BaseAdminNetworkTest): - - @classmethod - def skip_checks(cls): - super(RoutersAdminNegativeTest, cls).skip_checks() - if not test.is_extension_enabled('router', 'network'): - msg = "router extension not enabled." - raise cls.skipException(msg) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7101cc02-058a-11e7-93e1-fa163e4fa634') - @test.requires_ext(extension='ext-gw-mode', service='network') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_router_set_gateway_used_ip_returns_409(self): - # At first create a address from public_network_id - port = self.admin_ports_client.create_port( - network_id=CONF.network.public_network_id)['port'] - self.addCleanup(self.admin_ports_client.delete_port, - port_id=port['id']) - # Add used ip and subnet_id in external_fixed_ips - fixed_ip = { - 'subnet_id': port['fixed_ips'][0]['subnet_id'], - 'ip_address': port['fixed_ips'][0]['ip_address'] - } - external_gateway_info = { - 'network_id': CONF.network.public_network_id, - 'external_fixed_ips': [fixed_ip] - } - # Create a router and set gateway to used ip - self.assertRaises(lib_exc.Conflict, - self.admin_routers_client.create_router, - external_gateway_info=external_gateway_info) - - -class RoutersAdminNegativeIpV6Test(RoutersAdminNegativeTest): - _ip_version = 6 diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py deleted file mode 100644 index 6bec0d7e4..000000000 --- a/tempest/api/network/base.py +++ /dev/null @@ -1,272 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 netaddr - -from tempest import config -from tempest import exceptions -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import exceptions as lib_exc -import tempest.test - -CONF = config.CONF - - -class BaseNetworkTest(tempest.test.BaseTestCase): - """Base class for the Neutron tests. - - Per the Neutron API Guide, API v1.x was removed from the source code tree - (docs.openstack.org/api/openstack-network/2.0/content/Overview-d1e71.html) - Therefore, v2.x of the Neutron API is assumed. It is also assumed that the - following options are defined in the [network] section of etc/tempest.conf: - - project_network_cidr with a block of cidr's from which smaller blocks - can be allocated for project networks - - project_network_mask_bits with the mask bits to be used to partition - the block defined by project-network_cidr - - Finally, it is assumed that the following option is defined in the - [service_available] section of etc/tempest.conf - - neutron as True - """ - - force_tenant_isolation = False - credentials = ['primary'] - - # Default to ipv4. - _ip_version = 4 - - @classmethod - def skip_checks(cls): - super(BaseNetworkTest, cls).skip_checks() - if not CONF.service_available.neutron: - raise cls.skipException("Neutron support is required") - if cls._ip_version == 6 and not CONF.network_feature_enabled.ipv6: - raise cls.skipException("IPv6 Tests are disabled.") - - @classmethod - def setup_credentials(cls): - # Create no network resources for these test. - cls.set_network_resources() - super(BaseNetworkTest, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(BaseNetworkTest, cls).setup_clients() - cls.agents_client = cls.os_primary.network_agents_client - cls.network_extensions_client =\ - cls.os_primary.network_extensions_client - cls.networks_client = cls.os_primary.networks_client - cls.routers_client = cls.os_primary.routers_client - cls.subnetpools_client = cls.os_primary.subnetpools_client - cls.subnets_client = cls.os_primary.subnets_client - cls.ports_client = cls.os_primary.ports_client - cls.quotas_client = cls.os_primary.network_quotas_client - cls.floating_ips_client = cls.os_primary.floating_ips_client - cls.security_groups_client = cls.os_primary.security_groups_client - cls.security_group_rules_client = ( - cls.os_primary.security_group_rules_client) - cls.network_versions_client = cls.os_primary.network_versions_client - cls.service_providers_client = cls.os_primary.service_providers_client - cls.tags_client = cls.os_primary.tags_client - - @classmethod - def resource_setup(cls): - super(BaseNetworkTest, cls).resource_setup() - cls.networks = [] - cls.subnets = [] - cls.ports = [] - cls.routers = [] - cls.floating_ips = [] - cls.metering_labels = [] - cls.metering_label_rules = [] - cls.ethertype = "IPv" + str(cls._ip_version) - - @classmethod - def resource_cleanup(cls): - if CONF.service_available.neutron: - # Clean up floating IPs - for floating_ip in cls.floating_ips: - test_utils.call_and_ignore_notfound_exc( - cls.floating_ips_client.delete_floatingip, - floating_ip['id']) - - # Clean up metering label rules - # Not all classes in the hierarchy have the client class variable - if cls.metering_label_rules: - label_rules_client = cls.admin_metering_label_rules_client - for metering_label_rule in cls.metering_label_rules: - test_utils.call_and_ignore_notfound_exc( - label_rules_client.delete_metering_label_rule, - metering_label_rule['id']) - # Clean up metering labels - for metering_label in cls.metering_labels: - test_utils.call_and_ignore_notfound_exc( - cls.admin_metering_labels_client.delete_metering_label, - metering_label['id']) - # Clean up ports - for port in cls.ports: - test_utils.call_and_ignore_notfound_exc( - cls.ports_client.delete_port, port['id']) - # Clean up routers - for router in cls.routers: - test_utils.call_and_ignore_notfound_exc( - cls.delete_router, router) - # Clean up subnets - for subnet in cls.subnets: - test_utils.call_and_ignore_notfound_exc( - cls.subnets_client.delete_subnet, subnet['id']) - # Clean up networks - for network in cls.networks: - test_utils.call_and_ignore_notfound_exc( - cls.networks_client.delete_network, network['id']) - super(BaseNetworkTest, cls).resource_cleanup() - - @classmethod - def create_network(cls, network_name=None, **kwargs): - """Wrapper utility that returns a test network.""" - network_name = network_name or data_utils.rand_name( - cls.__name__ + '-test-network') - - body = cls.networks_client.create_network(name=network_name, **kwargs) - network = body['network'] - cls.networks.append(network) - return network - - @classmethod - def create_subnet(cls, network, gateway='', cidr=None, mask_bits=None, - ip_version=None, client=None, **kwargs): - """Wrapper utility that returns a test subnet.""" - # allow tests to use admin client - if not client: - client = cls.subnets_client - - # The cidr and mask_bits depend on the ip version. - ip_version = ip_version if ip_version is not None else cls._ip_version - gateway_not_set = gateway == '' - if ip_version == 4: - cidr = cidr or netaddr.IPNetwork(CONF.network.project_network_cidr) - mask_bits = mask_bits or CONF.network.project_network_mask_bits - elif ip_version == 6: - cidr = (cidr or - netaddr.IPNetwork(CONF.network.project_network_v6_cidr)) - mask_bits = mask_bits or CONF.network.project_network_v6_mask_bits - # Find a cidr that is not in use yet and create a subnet with it - for subnet_cidr in cidr.subnet(mask_bits): - if gateway_not_set: - gateway_ip = str(netaddr.IPAddress(subnet_cidr) + 1) - else: - gateway_ip = gateway - try: - body = client.create_subnet( - network_id=network['id'], - cidr=str(subnet_cidr), - ip_version=ip_version, - gateway_ip=gateway_ip, - **kwargs) - break - except lib_exc.BadRequest as e: - is_overlapping_cidr = 'overlaps with another subnet' in str(e) - if not is_overlapping_cidr: - raise - else: - message = 'Available CIDR for subnet creation could not be found' - raise exceptions.BuildErrorException(message) - subnet = body['subnet'] - cls.subnets.append(subnet) - return subnet - - @classmethod - def create_port(cls, network, **kwargs): - """Wrapper utility that returns a test port.""" - body = cls.ports_client.create_port(network_id=network['id'], - **kwargs) - port = body['port'] - cls.ports.append(port) - return port - - @classmethod - def update_port(cls, port, **kwargs): - """Wrapper utility that updates a test port.""" - body = cls.ports_client.update_port(port['id'], - **kwargs) - return body['port'] - - @classmethod - def create_router(cls, router_name=None, admin_state_up=False, - external_network_id=None, enable_snat=None, - **kwargs): - router_name = router_name or data_utils.rand_name( - cls.__name__ + "-router") - - ext_gw_info = {} - if external_network_id: - ext_gw_info['network_id'] = external_network_id - if enable_snat is not None: - ext_gw_info['enable_snat'] = enable_snat - body = cls.routers_client.create_router( - name=router_name, external_gateway_info=ext_gw_info, - admin_state_up=admin_state_up, **kwargs) - router = body['router'] - cls.routers.append(router) - return router - - @classmethod - def create_floatingip(cls, external_network_id): - """Wrapper utility that returns a test floating IP.""" - body = cls.floating_ips_client.create_floatingip( - floating_network_id=external_network_id) - fip = body['floatingip'] - cls.floating_ips.append(fip) - return fip - - @classmethod - def create_router_interface(cls, router_id, subnet_id): - """Wrapper utility that returns a router interface.""" - interface = cls.routers_client.add_router_interface( - router_id, subnet_id=subnet_id) - return interface - - @classmethod - def delete_router(cls, router): - body = cls.ports_client.list_ports(device_id=router['id']) - interfaces = body['ports'] - for i in interfaces: - test_utils.call_and_ignore_notfound_exc( - cls.routers_client.remove_router_interface, router['id'], - subnet_id=i['fixed_ips'][0]['subnet_id']) - cls.routers_client.delete_router(router['id']) - - -class BaseAdminNetworkTest(BaseNetworkTest): - - credentials = ['primary', 'admin'] - - @classmethod - def setup_clients(cls): - super(BaseAdminNetworkTest, cls).setup_clients() - cls.admin_agents_client = cls.os_admin.network_agents_client - cls.admin_networks_client = cls.os_admin.networks_client - cls.admin_routers_client = cls.os_admin.routers_client - cls.admin_subnets_client = cls.os_admin.subnets_client - cls.admin_ports_client = cls.os_admin.ports_client - cls.admin_quotas_client = cls.os_admin.network_quotas_client - cls.admin_floating_ips_client = cls.os_admin.floating_ips_client - cls.admin_metering_labels_client = cls.os_admin.metering_labels_client - cls.admin_metering_label_rules_client = ( - cls.os_admin.metering_label_rules_client) diff --git a/tempest/api/network/base_security_groups.py b/tempest/api/network/base_security_groups.py deleted file mode 100644 index b8d677a69..000000000 --- a/tempest/api/network/base_security_groups.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 tempest.api.network import base -from tempest.lib.common.utils import data_utils - - -class BaseSecGroupTest(base.BaseNetworkTest): - - def _create_security_group(self): - # Create a security group - name = data_utils.rand_name('secgroup-') - group_create_body = ( - self.security_groups_client.create_security_group(name=name)) - self.addCleanup(self._delete_security_group, - group_create_body['security_group']['id']) - self.assertEqual(group_create_body['security_group']['name'], name) - return group_create_body, name - - def _delete_security_group(self, secgroup_id): - self.security_groups_client.delete_security_group(secgroup_id) - # Asserting that the security group is not found in the list - # after deletion - list_body = self.security_groups_client.list_security_groups() - secgroup_list = list() - for secgroup in list_body['security_groups']: - secgroup_list.append(secgroup['id']) - self.assertNotIn(secgroup_id, secgroup_list) - - def _delete_security_group_rule(self, rule_id): - self.security_group_rules_client.delete_security_group_rule(rule_id) - # Asserting that the security group is not found in the list - # after deletion - list_body = ( - self.security_group_rules_client.list_security_group_rules()) - rules_list = list() - for rule in list_body['security_group_rules']: - rules_list.append(rule['id']) - self.assertNotIn(rule_id, rules_list) diff --git a/tempest/api/network/test_allowed_address_pair.py b/tempest/api/network/test_allowed_address_pair.py deleted file mode 100644 index a90e4bfe4..000000000 --- a/tempest/api/network/test_allowed_address_pair.py +++ /dev/null @@ -1,135 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# 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 netaddr -import six - -from tempest.api.network import base -from tempest import config -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class AllowedAddressPairTestJSON(base.BaseNetworkTest): - """Tests the Neutron Allowed Address Pair API extension - - The following API operations are tested with this extension: - - create port - list ports - update port - show port - - v2.0 of the Neutron API is assumed. It is also assumed that the following - options are defined in the [network-feature-enabled] section of - etc/tempest.conf - - api_extensions - """ - - @classmethod - def skip_checks(cls): - super(AllowedAddressPairTestJSON, cls).skip_checks() - if not test.is_extension_enabled('allowed-address-pairs', 'network'): - msg = "Allowed Address Pairs extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(AllowedAddressPairTestJSON, cls).resource_setup() - cls.network = cls.create_network() - cls.create_subnet(cls.network) - port = cls.create_port(cls.network) - cls.ip_address = port['fixed_ips'][0]['ip_address'] - cls.mac_address = port['mac_address'] - - @decorators.idempotent_id('86c3529b-1231-40de-803c-00e40882f043') - def test_create_list_port_with_address_pair(self): - # Create port with allowed address pair attribute - allowed_address_pairs = [{'ip_address': self.ip_address, - 'mac_address': self.mac_address}] - body = self.ports_client.create_port( - network_id=self.network['id'], - allowed_address_pairs=allowed_address_pairs) - port_id = body['port']['id'] - self.addCleanup(self.ports_client.delete_port, port_id) - - # Confirm port was created with allowed address pair attribute - body = self.ports_client.list_ports() - ports = body['ports'] - port = [p for p in ports if p['id'] == port_id] - msg = 'Created port not found in list of ports returned by Neutron' - self.assertTrue(port, msg) - self._confirm_allowed_address_pair(port[0], self.ip_address) - - def _update_port_with_address(self, address, mac_address=None, **kwargs): - # Create a port without allowed address pair - body = self.ports_client.create_port(network_id=self.network['id']) - port_id = body['port']['id'] - self.addCleanup(self.ports_client.delete_port, port_id) - if mac_address is None: - mac_address = self.mac_address - - # Update allowed address pair attribute of port - allowed_address_pairs = [{'ip_address': address, - 'mac_address': mac_address}] - if kwargs: - allowed_address_pairs.append(kwargs['allowed_address_pairs']) - body = self.ports_client.update_port( - port_id, allowed_address_pairs=allowed_address_pairs) - allowed_address_pair = body['port']['allowed_address_pairs'] - six.assertCountEqual(self, allowed_address_pair, - allowed_address_pairs) - - @decorators.idempotent_id('9599b337-272c-47fd-b3cf-509414414ac4') - def test_update_port_with_address_pair(self): - # Update port with allowed address pair - self._update_port_with_address(self.ip_address) - - @decorators.idempotent_id('4d6d178f-34f6-4bff-a01c-0a2f8fe909e4') - def test_update_port_with_cidr_address_pair(self): - # Update allowed address pair with cidr - cidr = str(netaddr.IPNetwork(CONF.network.project_network_cidr)) - self._update_port_with_address(cidr) - - @decorators.idempotent_id('b3f20091-6cd5-472b-8487-3516137df933') - def test_update_port_with_multiple_ip_mac_address_pair(self): - # Create an ip _address and mac_address through port create - resp = self.ports_client.create_port(network_id=self.network['id']) - newportid = resp['port']['id'] - self.addCleanup(self.ports_client.delete_port, newportid) - ipaddress = resp['port']['fixed_ips'][0]['ip_address'] - macaddress = resp['port']['mac_address'] - - # Update allowed address pair port with multiple ip and mac - allowed_address_pairs = {'ip_address': ipaddress, - 'mac_address': macaddress} - self._update_port_with_address( - self.ip_address, self.mac_address, - allowed_address_pairs=allowed_address_pairs) - - def _confirm_allowed_address_pair(self, port, ip): - msg = 'Port allowed address pairs should not be empty' - self.assertTrue(port['allowed_address_pairs'], msg) - ip_address = port['allowed_address_pairs'][0]['ip_address'] - mac_address = port['allowed_address_pairs'][0]['mac_address'] - self.assertEqual(ip_address, ip) - self.assertEqual(mac_address, self.mac_address) - - -class AllowedAddressPairIpV6TestJSON(AllowedAddressPairTestJSON): - _ip_version = 6 diff --git a/tempest/api/network/test_dhcp_ipv6.py b/tempest/api/network/test_dhcp_ipv6.py deleted file mode 100644 index 9d6d7008d..000000000 --- a/tempest/api/network/test_dhcp_ipv6.py +++ /dev/null @@ -1,374 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# 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 random - -import netaddr -from oslo_utils import netutils - -from tempest.api.network import base -from tempest.common.utils import net_info -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class NetworksTestDHCPv6(base.BaseNetworkTest): - _ip_version = 6 - - """Test DHCPv6 specific features using SLAAC, stateless and - stateful settings for subnets. Also it shall check dual-stack - functionality (IPv4 + IPv6 together). - The tests include: - generating of SLAAC EUI-64 address in subnets with various settings - receiving SLAAC addresses in combinations of various subnets - receiving stateful IPv6 addresses - addressing in subnets with router - """ - - @classmethod - def skip_checks(cls): - super(NetworksTestDHCPv6, cls).skip_checks() - msg = None - if not CONF.network_feature_enabled.ipv6: - msg = "IPv6 is not enabled" - elif not CONF.network_feature_enabled.ipv6_subnet_attributes: - msg = "DHCPv6 attributes are not enabled." - if msg: - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(NetworksTestDHCPv6, cls).resource_setup() - cls.network = cls.create_network() - - def _remove_from_list_by_index(self, things_list, elem): - for index, i in enumerate(things_list): - if i['id'] == elem['id']: - break - del things_list[index] - - def _clean_network(self): - body = self.ports_client.list_ports() - ports = body['ports'] - for port in ports: - if (net_info.is_router_interface_port(port) and - port['device_id'] in [r['id'] for r in self.routers]): - self.routers_client.remove_router_interface(port['device_id'], - port_id=port['id']) - else: - if port['id'] in [p['id'] for p in self.ports]: - self.ports_client.delete_port(port['id']) - self._remove_from_list_by_index(self.ports, port) - body = self.subnets_client.list_subnets() - subnets = body['subnets'] - for subnet in subnets: - if subnet['id'] in [s['id'] for s in self.subnets]: - self.subnets_client.delete_subnet(subnet['id']) - self._remove_from_list_by_index(self.subnets, subnet) - body = self.routers_client.list_routers() - routers = body['routers'] - for router in routers: - if router['id'] in [r['id'] for r in self.routers]: - self.routers_client.delete_router(router['id']) - self._remove_from_list_by_index(self.routers, router) - - def _get_ips_from_subnet(self, **kwargs): - subnet = self.create_subnet(self.network, **kwargs) - port_mac = data_utils.rand_mac_address() - port = self.create_port(self.network, mac_address=port_mac) - real_ip = next(iter(port['fixed_ips']), None)['ip_address'] - eui_ip = str(netutils.get_ipv6_addr_by_EUI64( - subnet['cidr'], port_mac)) - return real_ip, eui_ip - - @decorators.idempotent_id('e5517e62-6f16-430d-a672-f80875493d4c') - def test_dhcpv6_stateless_eui64(self): - # NOTE: When subnets configured with RAs SLAAC (AOM=100) and DHCP - # stateless (AOM=110) both for radvd and dnsmasq, port shall receive - # IP address calculated from its MAC. - for ra_mode, add_mode in ( - ('slaac', 'slaac'), - ('dhcpv6-stateless', 'dhcpv6-stateless'), - ): - kwargs = {'ipv6_ra_mode': ra_mode, - 'ipv6_address_mode': add_mode} - real_ip, eui_ip = self._get_ips_from_subnet(**kwargs) - self._clean_network() - self.assertEqual(eui_ip, real_ip, - ('Real port IP is %s, but shall be %s when ' - 'ipv6_ra_mode=%s and ipv6_address_mode=%s') % ( - real_ip, eui_ip, ra_mode, add_mode)) - - @decorators.idempotent_id('ae2f4a5d-03ff-4c42-a3b0-ce2fcb7ea832') - def test_dhcpv6_stateless_no_ra(self): - # NOTE: When subnets configured with dnsmasq SLAAC and DHCP stateless - # and there is no radvd, port shall receive IP address calculated - # from its MAC and mask of subnet. - for ra_mode, add_mode in ( - (None, 'slaac'), - (None, 'dhcpv6-stateless'), - ): - kwargs = {'ipv6_ra_mode': ra_mode, - 'ipv6_address_mode': add_mode} - kwargs = dict((k, v) for k, v in kwargs.items() if v) - real_ip, eui_ip = self._get_ips_from_subnet(**kwargs) - self._clean_network() - self.assertEqual(eui_ip, real_ip, - ('Real port IP %s shall be equal to EUI-64 %s' - 'when ipv6_ra_mode=%s,ipv6_address_mode=%s') % ( - real_ip, eui_ip, - ra_mode if ra_mode else "Off", - add_mode if add_mode else "Off")) - - @decorators.idempotent_id('81f18ef6-95b5-4584-9966-10d480b7496a') - def test_dhcpv6_invalid_options(self): - """Different configurations for radvd and dnsmasq are not allowed""" - for ra_mode, add_mode in ( - ('dhcpv6-stateless', 'dhcpv6-stateful'), - ('dhcpv6-stateless', 'slaac'), - ('slaac', 'dhcpv6-stateful'), - ('dhcpv6-stateful', 'dhcpv6-stateless'), - ('dhcpv6-stateful', 'slaac'), - ('slaac', 'dhcpv6-stateless'), - ): - kwargs = {'ipv6_ra_mode': ra_mode, - 'ipv6_address_mode': add_mode} - self.assertRaises(lib_exc.BadRequest, - self.create_subnet, - self.network, - **kwargs) - - @decorators.idempotent_id('21635b6f-165a-4d42-bf49-7d195e47342f') - def test_dhcpv6_stateless_no_ra_no_dhcp(self): - # NOTE: If no radvd option and no dnsmasq option is configured - # port shall receive IP from fixed IPs list of subnet. - real_ip, eui_ip = self._get_ips_from_subnet() - self._clean_network() - self.assertNotEqual(eui_ip, real_ip, - ('Real port IP %s equal to EUI-64 %s when ' - 'ipv6_ra_mode=Off and ipv6_address_mode=Off,' - 'but shall be taken from fixed IPs') % ( - real_ip, eui_ip)) - - @decorators.idempotent_id('4544adf7-bb5f-4bdc-b769-b3e77026cef2') - def test_dhcpv6_two_subnets(self): - # NOTE: When one IPv6 subnet configured with dnsmasq SLAAC or DHCP - # stateless and other IPv6 is with DHCP stateful, port shall receive - # EUI-64 IP addresses from first subnet and DHCP address from second - # one. Order of subnet creating should be unimportant. - for order in ("slaac_first", "dhcp_first"): - for ra_mode, add_mode in ( - ('slaac', 'slaac'), - ('dhcpv6-stateless', 'dhcpv6-stateless'), - ): - kwargs = {'ipv6_ra_mode': ra_mode, - 'ipv6_address_mode': add_mode} - kwargs_dhcp = {'ipv6_address_mode': 'dhcpv6-stateful'} - if order == "slaac_first": - subnet_slaac = self.create_subnet(self.network, **kwargs) - subnet_dhcp = self.create_subnet( - self.network, **kwargs_dhcp) - else: - subnet_dhcp = self.create_subnet( - self.network, **kwargs_dhcp) - subnet_slaac = self.create_subnet(self.network, **kwargs) - port_mac = data_utils.rand_mac_address() - eui_ip = str(netutils.get_ipv6_addr_by_EUI64( - subnet_slaac['cidr'], port_mac)) - port = self.create_port(self.network, mac_address=port_mac) - real_ips = dict([(k['subnet_id'], k['ip_address']) - for k in port['fixed_ips']]) - real_dhcp_ip, real_eui_ip = [real_ips[sub['id']] - for sub in [subnet_dhcp, - subnet_slaac]] - self.ports_client.delete_port(port['id']) - self.ports.pop() - body = self.ports_client.list_ports() - ports_id_list = [i['id'] for i in body['ports']] - self.assertNotIn(port['id'], ports_id_list) - self._clean_network() - self.assertEqual(real_eui_ip, - eui_ip, - 'Real IP is {0}, but shall be {1}'.format( - real_eui_ip, - eui_ip)) - msg = ('Real IP address is {0} and it is NOT on ' - 'subnet {1}'.format(real_dhcp_ip, subnet_dhcp['cidr'])) - self.assertIn(netaddr.IPAddress(real_dhcp_ip), - netaddr.IPNetwork(subnet_dhcp['cidr']), msg) - - @decorators.idempotent_id('4256c61d-c538-41ea-9147-3c450c36669e') - def test_dhcpv6_64_subnets(self): - # NOTE: When one IPv6 subnet configured with dnsmasq SLAAC or DHCP - # stateless and other IPv4 is with DHCP of IPv4, port shall receive - # EUI-64 IP addresses from first subnet and IPv4 DHCP address from - # second one. Order of subnet creating should be unimportant. - for order in ("slaac_first", "dhcp_first"): - for ra_mode, add_mode in ( - ('slaac', 'slaac'), - ('dhcpv6-stateless', 'dhcpv6-stateless'), - ): - kwargs = {'ipv6_ra_mode': ra_mode, - 'ipv6_address_mode': add_mode} - if order == "slaac_first": - subnet_slaac = self.create_subnet(self.network, **kwargs) - subnet_dhcp = self.create_subnet( - self.network, ip_version=4) - else: - subnet_dhcp = self.create_subnet( - self.network, ip_version=4) - subnet_slaac = self.create_subnet(self.network, **kwargs) - port_mac = data_utils.rand_mac_address() - eui_ip = str(netutils.get_ipv6_addr_by_EUI64( - subnet_slaac['cidr'], port_mac)) - port = self.create_port(self.network, mac_address=port_mac) - real_ips = dict([(k['subnet_id'], k['ip_address']) - for k in port['fixed_ips']]) - real_dhcp_ip, real_eui_ip = [real_ips[sub['id']] - for sub in [subnet_dhcp, - subnet_slaac]] - self._clean_network() - self.assertEqual(real_eui_ip, - eui_ip, - 'Real IP is {0}, but shall be {1}'.format( - real_eui_ip, - eui_ip)) - msg = ('Real IP address is {0} and it is NOT on ' - 'subnet {1}'.format(real_dhcp_ip, subnet_dhcp['cidr'])) - self.assertIn(netaddr.IPAddress(real_dhcp_ip), - netaddr.IPNetwork(subnet_dhcp['cidr']), msg) - - @decorators.idempotent_id('4ab211a0-276f-4552-9070-51e27f58fecf') - def test_dhcp_stateful(self): - # NOTE: With all options below, DHCPv6 shall allocate address from - # subnet pool to port. - for ra_mode, add_mode in ( - ('dhcpv6-stateful', 'dhcpv6-stateful'), - ('dhcpv6-stateful', None), - (None, 'dhcpv6-stateful'), - ): - kwargs = {'ipv6_ra_mode': ra_mode, - 'ipv6_address_mode': add_mode} - kwargs = dict((k, v) for k, v in kwargs.items() if v) - subnet = self.create_subnet(self.network, **kwargs) - port = self.create_port(self.network) - port_ip = next(iter(port['fixed_ips']), None)['ip_address'] - self._clean_network() - msg = ('Real IP address is {0} and it is NOT on ' - 'subnet {1}'.format(port_ip, subnet['cidr'])) - self.assertIn(netaddr.IPAddress(port_ip), - netaddr.IPNetwork(subnet['cidr']), msg) - - @decorators.idempotent_id('51a5e97f-f02e-4e4e-9a17-a69811d300e3') - def test_dhcp_stateful_fixedips(self): - # NOTE: With all options below, port shall be able to get - # requested IP from fixed IP range not depending on - # DHCP stateful (not SLAAC!) settings configured. - for ra_mode, add_mode in ( - ('dhcpv6-stateful', 'dhcpv6-stateful'), - ('dhcpv6-stateful', None), - (None, 'dhcpv6-stateful'), - ): - kwargs = {'ipv6_ra_mode': ra_mode, - 'ipv6_address_mode': add_mode} - kwargs = dict((k, v) for k, v in kwargs.items() if v) - subnet = self.create_subnet(self.network, **kwargs) - ip_range = netaddr.IPRange(subnet["allocation_pools"][0]["start"], - subnet["allocation_pools"][0]["end"]) - ip = netaddr.IPAddress(random.randrange(ip_range.first, - ip_range.last)).format() - port = self.create_port(self.network, - fixed_ips=[{'subnet_id': subnet['id'], - 'ip_address': ip}]) - port_ip = next(iter(port['fixed_ips']), None)['ip_address'] - self._clean_network() - self.assertEqual(port_ip, ip, - ("Port IP %s is not as fixed IP from " - "port create request: %s") % ( - port_ip, ip)) - - @decorators.idempotent_id('98244d88-d990-4570-91d4-6b25d70d08af') - def test_dhcp_stateful_fixedips_outrange(self): - # NOTE: When port gets IP address from fixed IP range it - # shall be checked if it's from subnets range. - kwargs = {'ipv6_ra_mode': 'dhcpv6-stateful', - 'ipv6_address_mode': 'dhcpv6-stateful'} - subnet = self.create_subnet(self.network, **kwargs) - ip_range = netaddr.IPRange(subnet["allocation_pools"][0]["start"], - subnet["allocation_pools"][0]["end"]) - ip = netaddr.IPAddress(random.randrange( - ip_range.last + 1, ip_range.last + 10)).format() - self.assertRaises(lib_exc.BadRequest, - self.create_port, - self.network, - fixed_ips=[{'subnet_id': subnet['id'], - 'ip_address': ip}]) - - @decorators.idempotent_id('57b8302b-cba9-4fbb-8835-9168df029051') - def test_dhcp_stateful_fixedips_duplicate(self): - # NOTE: When port gets IP address from fixed IP range it - # shall be checked if it's not duplicate. - kwargs = {'ipv6_ra_mode': 'dhcpv6-stateful', - 'ipv6_address_mode': 'dhcpv6-stateful'} - subnet = self.create_subnet(self.network, **kwargs) - ip_range = netaddr.IPRange(subnet["allocation_pools"][0]["start"], - subnet["allocation_pools"][0]["end"]) - ip = netaddr.IPAddress(random.randrange( - ip_range.first, ip_range.last)).format() - self.create_port(self.network, - fixed_ips=[ - {'subnet_id': subnet['id'], - 'ip_address': ip}]) - self.assertRaisesRegex(lib_exc.Conflict, - "IpAddressAlreadyAllocated|IpAddressInUse", - self.create_port, - self.network, - fixed_ips=[{'subnet_id': subnet['id'], - 'ip_address': ip}]) - - def _create_subnet_router(self, kwargs): - subnet = self.create_subnet(self.network, **kwargs) - router = self.create_router(admin_state_up=True) - port = self.create_router_interface(router['id'], - subnet['id']) - body = self.ports_client.show_port(port['port_id']) - return subnet, body['port'] - - @decorators.idempotent_id('e98f65db-68f4-4330-9fea-abd8c5192d4d') - def test_dhcp_stateful_router(self): - # NOTE: With all options below the router interface shall - # receive DHCPv6 IP address from allocation pool. - for ra_mode, add_mode in ( - ('dhcpv6-stateful', 'dhcpv6-stateful'), - ('dhcpv6-stateful', None), - ): - kwargs = {'ipv6_ra_mode': ra_mode, - 'ipv6_address_mode': add_mode} - kwargs = dict((k, v) for k, v in kwargs.items() if v) - subnet, port = self._create_subnet_router(kwargs) - port_ip = next(iter(port['fixed_ips']), None)['ip_address'] - self._clean_network() - self.assertEqual(port_ip, subnet['gateway_ip'], - ("Port IP %s is not as first IP from " - "subnets allocation pool: %s") % ( - port_ip, subnet['gateway_ip'])) - - def tearDown(self): - self._clean_network() - super(NetworksTestDHCPv6, self).tearDown() diff --git a/tempest/api/network/test_extensions.py b/tempest/api/network/test_extensions.py deleted file mode 100644 index 014d06445..000000000 --- a/tempest/api/network/test_extensions.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright 2013 OpenStack, Foundation -# 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 tempest.api.network import base -from tempest.lib import decorators -from tempest import test - - -class ExtensionsTestJSON(base.BaseNetworkTest): - """Tests the following operations in the Neutron API: - - List all available extensions - - v2.0 of the Neutron API is assumed. It is also assumed that api-extensions - option is defined in the [network-feature-enabled] section of - etc/tempest.conf. - """ - - @decorators.attr(type='smoke') - @decorators.idempotent_id('ef28c7e6-e646-4979-9d67-deb207bc5564') - def test_list_show_extensions(self): - # List available extensions for the project - expected_alias = ['security-group', 'l3_agent_scheduler', - 'ext-gw-mode', 'binding', 'quotas', - 'agent', 'dhcp_agent_scheduler', 'provider', - 'router', 'extraroute', 'external-net', - 'allowed-address-pairs', 'extra_dhcp_opt', - 'metering', 'dvr'] - expected_alias = [ext for ext in expected_alias if - test.is_extension_enabled(ext, 'network')] - actual_alias = list() - extensions = self.network_extensions_client.list_extensions() - list_extensions = extensions['extensions'] - # Show and verify the details of the available extensions - for ext in list_extensions: - ext_name = ext['name'] - ext_alias = ext['alias'] - actual_alias.append(ext['alias']) - ext_details = self.network_extensions_client.show_extension( - ext_alias) - ext_details = ext_details['extension'] - - self.assertIsNotNone(ext_details) - self.assertIn('updated', ext_details.keys()) - self.assertIn('name', ext_details.keys()) - self.assertIn('description', ext_details.keys()) - self.assertIn('links', ext_details.keys()) - self.assertIn('alias', ext_details.keys()) - self.assertEqual(ext_details['name'], ext_name) - self.assertEqual(ext_details['alias'], ext_alias) - self.assertEqual(ext_details, ext) - # Verify if expected extensions are present in the actual list - # of extensions returned, but only for those that have been - # enabled via configuration - for e in expected_alias: - if test.is_extension_enabled(e, 'network'): - self.assertIn(e, actual_alias) diff --git a/tempest/api/network/test_extra_dhcp_options.py b/tempest/api/network/test_extra_dhcp_options.py deleted file mode 100644 index dc9042ef1..000000000 --- a/tempest/api/network/test_extra_dhcp_options.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 tempest.api.network import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - - -class ExtraDHCPOptionsTestJSON(base.BaseNetworkTest): - """Tests the following operations with the Extra DHCP Options: - - port create - port list - port show - port update - - v2.0 of the Neutron API is assumed. It is also assumed that the Extra - DHCP Options extension is enabled in the [network-feature-enabled] - section of etc/tempest.conf - """ - - @classmethod - def skip_checks(cls): - super(ExtraDHCPOptionsTestJSON, cls).skip_checks() - if not test.is_extension_enabled('extra_dhcp_opt', 'network'): - msg = "Extra DHCP Options extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(ExtraDHCPOptionsTestJSON, cls).resource_setup() - cls.network = cls.create_network() - cls.create_subnet(cls.network) - cls.port = cls.create_port(cls.network) - ip_tftp = ('123.123.123.123' if cls._ip_version == 4 - else '2015::dead') - ip_server = ('123.123.123.45' if cls._ip_version == 4 - else '2015::badd') - cls.extra_dhcp_opts = [ - {'opt_value': 'pxelinux.0', 'opt_name': 'bootfile-name'}, - {'opt_value': ip_tftp, 'opt_name': 'tftp-server'}, - {'opt_value': ip_server, 'opt_name': 'server-ip-address'} - ] - - @decorators.idempotent_id('d2c17063-3767-4a24-be4f-a23dbfa133c9') - def test_create_list_port_with_extra_dhcp_options(self): - # Create a port with Extra DHCP Options - body = self.ports_client.create_port( - network_id=self.network['id'], - extra_dhcp_opts=self.extra_dhcp_opts) - port_id = body['port']['id'] - self.addCleanup(self.ports_client.delete_port, port_id) - - # Confirm port created has Extra DHCP Options - body = self.ports_client.list_ports() - ports = body['ports'] - port = [p for p in ports if p['id'] == port_id] - self.assertTrue(port) - self._confirm_extra_dhcp_options(port[0], self.extra_dhcp_opts) - - @decorators.idempotent_id('9a6aebf4-86ee-4f47-b07a-7f7232c55607') - def test_update_show_port_with_extra_dhcp_options(self): - # Update port with extra dhcp options - name = data_utils.rand_name('new-port-name') - body = self.ports_client.update_port( - self.port['id'], - name=name, - extra_dhcp_opts=self.extra_dhcp_opts) - # Confirm extra dhcp options were added to the port - body = self.ports_client.show_port(self.port['id']) - self._confirm_extra_dhcp_options(body['port'], self.extra_dhcp_opts) - - def _confirm_extra_dhcp_options(self, port, extra_dhcp_opts): - retrieved = port['extra_dhcp_opts'] - self.assertEqual(len(retrieved), len(extra_dhcp_opts)) - for retrieved_option in retrieved: - for option in extra_dhcp_opts: - if (retrieved_option['opt_value'] == option['opt_value'] and - retrieved_option['opt_name'] == option['opt_name']): - break - else: - self.fail('Extra DHCP option not found in port %s' % - str(retrieved_option)) - - -class ExtraDHCPOptionsIpV6TestJSON(ExtraDHCPOptionsTestJSON): - _ip_version = 6 diff --git a/tempest/api/network/test_floating_ips.py b/tempest/api/network/test_floating_ips.py deleted file mode 100644 index c799b15a3..000000000 --- a/tempest/api/network/test_floating_ips.py +++ /dev/null @@ -1,225 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 tempest.api.network import base -from tempest.common.utils import net_utils -from tempest import config -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class FloatingIPTestJSON(base.BaseNetworkTest): - """Tests the following operations in the Neutron API: - - Create a Floating IP - Update a Floating IP - Delete a Floating IP - List all Floating IPs - Show Floating IP details - Associate a Floating IP with a port and then delete that port - Associate a Floating IP with a port and then with a port on another - router - - v2.0 of the Neutron API is assumed. It is also assumed that the following - options are defined in the [network] section of etc/tempest.conf: - - public_network_id which is the id for the external network present - """ - - @classmethod - def skip_checks(cls): - super(FloatingIPTestJSON, cls).skip_checks() - if not test.is_extension_enabled('router', 'network'): - msg = "router extension not enabled." - raise cls.skipException(msg) - if not CONF.network.public_network_id: - msg = "The public_network_id option must be specified." - raise cls.skipException(msg) - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - @classmethod - def resource_setup(cls): - super(FloatingIPTestJSON, cls).resource_setup() - cls.ext_net_id = CONF.network.public_network_id - - # Create network, subnet, router and add interface - cls.network = cls.create_network() - cls.subnet = cls.create_subnet(cls.network, enable_dhcp=False) - cls.router = cls.create_router(external_network_id=cls.ext_net_id) - cls.create_router_interface(cls.router['id'], cls.subnet['id']) - # Create two ports one each for Creation and Updating of floatingIP - for i in range(2): - cls.create_port(cls.network) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('62595970-ab1c-4b7f-8fcc-fddfe55e8718') - def test_create_list_show_update_delete_floating_ip(self): - # Creates a floating IP - body = self.floating_ips_client.create_floatingip( - floating_network_id=self.ext_net_id, - port_id=self.ports[0]['id']) - created_floating_ip = body['floatingip'] - self.addCleanup(self.floating_ips_client.delete_floatingip, - created_floating_ip['id']) - self.assertIsNotNone(created_floating_ip['id']) - self.assertIsNotNone(created_floating_ip['tenant_id']) - self.assertIsNotNone(created_floating_ip['floating_ip_address']) - self.assertEqual(created_floating_ip['port_id'], self.ports[0]['id']) - self.assertEqual(created_floating_ip['floating_network_id'], - self.ext_net_id) - self.assertIn(created_floating_ip['fixed_ip_address'], - [ip['ip_address'] for ip in self.ports[0]['fixed_ips']]) - # Verifies the details of a floating_ip - floating_ip = self.floating_ips_client.show_floatingip( - created_floating_ip['id']) - shown_floating_ip = floating_ip['floatingip'] - self.assertEqual(shown_floating_ip['id'], created_floating_ip['id']) - self.assertEqual(shown_floating_ip['floating_network_id'], - self.ext_net_id) - self.assertEqual(shown_floating_ip['tenant_id'], - created_floating_ip['tenant_id']) - self.assertEqual(shown_floating_ip['floating_ip_address'], - created_floating_ip['floating_ip_address']) - self.assertEqual(shown_floating_ip['port_id'], self.ports[0]['id']) - - # Verify the floating ip exists in the list of all floating_ips - floating_ips = self.floating_ips_client.list_floatingips() - floatingip_id_list = list() - for f in floating_ips['floatingips']: - floatingip_id_list.append(f['id']) - self.assertIn(created_floating_ip['id'], floatingip_id_list) - # Associate floating IP to the other port - floating_ip = self.floating_ips_client.update_floatingip( - created_floating_ip['id'], - port_id=self.ports[1]['id']) - updated_floating_ip = floating_ip['floatingip'] - self.assertEqual(updated_floating_ip['port_id'], self.ports[1]['id']) - self.assertEqual(updated_floating_ip['fixed_ip_address'], - self.ports[1]['fixed_ips'][0]['ip_address']) - self.assertEqual(updated_floating_ip['router_id'], self.router['id']) - - # Disassociate floating IP from the port - floating_ip = self.floating_ips_client.update_floatingip( - created_floating_ip['id'], - port_id=None) - updated_floating_ip = floating_ip['floatingip'] - self.assertIsNone(updated_floating_ip['port_id']) - self.assertIsNone(updated_floating_ip['fixed_ip_address']) - self.assertIsNone(updated_floating_ip['router_id']) - - @decorators.idempotent_id('e1f6bffd-442f-4668-b30e-df13f2705e77') - def test_floating_ip_delete_port(self): - # Create a floating IP - body = self.floating_ips_client.create_floatingip( - floating_network_id=self.ext_net_id) - created_floating_ip = body['floatingip'] - self.addCleanup(self.floating_ips_client.delete_floatingip, - created_floating_ip['id']) - # Create a port - port = self.ports_client.create_port(network_id=self.network['id']) - created_port = port['port'] - floating_ip = self.floating_ips_client.update_floatingip( - created_floating_ip['id'], - port_id=created_port['id']) - # Delete port - self.ports_client.delete_port(created_port['id']) - # Verifies the details of the floating_ip - floating_ip = self.floating_ips_client.show_floatingip( - created_floating_ip['id']) - shown_floating_ip = floating_ip['floatingip'] - # Confirm the fields are back to None - self.assertEqual(shown_floating_ip['id'], created_floating_ip['id']) - self.assertIsNone(shown_floating_ip['port_id']) - self.assertIsNone(shown_floating_ip['fixed_ip_address']) - self.assertIsNone(shown_floating_ip['router_id']) - - @decorators.idempotent_id('1bb2f731-fe5a-4b8c-8409-799ade1bed4d') - def test_floating_ip_update_different_router(self): - # Associate a floating IP to a port on a router - body = self.floating_ips_client.create_floatingip( - floating_network_id=self.ext_net_id, - port_id=self.ports[1]['id']) - created_floating_ip = body['floatingip'] - self.addCleanup(self.floating_ips_client.delete_floatingip, - created_floating_ip['id']) - self.assertEqual(created_floating_ip['router_id'], self.router['id']) - network2 = self.create_network() - subnet2 = self.create_subnet(network2) - router2 = self.create_router(external_network_id=self.ext_net_id) - self.create_router_interface(router2['id'], subnet2['id']) - port_other_router = self.create_port(network2) - # Associate floating IP to the other port on another router - floating_ip = self.floating_ips_client.update_floatingip( - created_floating_ip['id'], - port_id=port_other_router['id']) - updated_floating_ip = floating_ip['floatingip'] - self.assertEqual(updated_floating_ip['router_id'], router2['id']) - self.assertEqual(updated_floating_ip['port_id'], - port_other_router['id']) - self.assertIsNotNone(updated_floating_ip['fixed_ip_address']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('36de4bd0-f09c-43e3-a8e1-1decc1ffd3a5') - def test_create_floating_ip_specifying_a_fixed_ip_address(self): - body = self.floating_ips_client.create_floatingip( - floating_network_id=self.ext_net_id, - port_id=self.ports[1]['id'], - fixed_ip_address=self.ports[1]['fixed_ips'][0]['ip_address']) - created_floating_ip = body['floatingip'] - self.addCleanup(self.floating_ips_client.delete_floatingip, - created_floating_ip['id']) - self.assertIsNotNone(created_floating_ip['id']) - self.assertEqual(created_floating_ip['fixed_ip_address'], - self.ports[1]['fixed_ips'][0]['ip_address']) - floating_ip = self.floating_ips_client.update_floatingip( - created_floating_ip['id'], - port_id=None) - self.assertIsNone(floating_ip['floatingip']['port_id']) - - @decorators.idempotent_id('45c4c683-ea97-41ef-9c51-5e9802f2f3d7') - def test_create_update_floatingip_with_port_multiple_ip_address(self): - # Find out ips that can be used for tests - list_ips = net_utils.get_unused_ip_addresses( - self.ports_client, - self.subnets_client, - self.subnet['network_id'], - self.subnet['id'], - 2) - fixed_ips = [{'ip_address': list_ips[0]}, {'ip_address': list_ips[1]}] - # Create port - body = self.ports_client.create_port(network_id=self.network['id'], - fixed_ips=fixed_ips) - port = body['port'] - self.addCleanup(self.ports_client.delete_port, port['id']) - # Create floating ip - body = self.floating_ips_client.create_floatingip( - floating_network_id=self.ext_net_id, - port_id=port['id'], - fixed_ip_address=list_ips[0]) - floating_ip = body['floatingip'] - self.addCleanup(self.floating_ips_client.delete_floatingip, - floating_ip['id']) - self.assertIsNotNone(floating_ip['id']) - self.assertEqual(floating_ip['fixed_ip_address'], list_ips[0]) - # Update floating ip - body = self.floating_ips_client.update_floatingip( - floating_ip['id'], port_id=port['id'], - fixed_ip_address=list_ips[1]) - update_floating_ip = body['floatingip'] - self.assertEqual(update_floating_ip['fixed_ip_address'], - list_ips[1]) diff --git a/tempest/api/network/test_floating_ips_negative.py b/tempest/api/network/test_floating_ips_negative.py deleted file mode 100644 index 5ca17fec0..000000000 --- a/tempest/api/network/test_floating_ips_negative.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P. -# Copyright 2014 OpenStack Foundation -# 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 tempest.api.network import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class FloatingIPNegativeTestJSON(base.BaseNetworkTest): - """Test the following negative operations for floating ips: - - Create floatingip with a port that is unreachable to external network - Create floatingip in private network - Associate floatingip with port that is unreachable to external network - """ - - @classmethod - def skip_checks(cls): - super(FloatingIPNegativeTestJSON, cls).skip_checks() - if not test.is_extension_enabled('router', 'network'): - msg = "router extension not enabled." - raise cls.skipException(msg) - if not CONF.network.public_network_id: - msg = "The public_network_id option must be specified." - raise cls.skipException(msg) - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - @classmethod - def resource_setup(cls): - super(FloatingIPNegativeTestJSON, cls).resource_setup() - cls.ext_net_id = CONF.network.public_network_id - # Create a network with a subnet connected to a router. - cls.network = cls.create_network() - subnet = cls.create_subnet(cls.network) - router = cls.create_router() - cls.create_router_interface(router['id'], subnet['id']) - cls.port = cls.create_port(cls.network) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('22996ea8-4a81-4b27-b6e1-fa5df92fa5e8') - def test_create_floatingip_with_port_ext_net_unreachable(self): - self.assertRaises( - lib_exc.NotFound, self.floating_ips_client.create_floatingip, - floating_network_id=self.ext_net_id, port_id=self.port['id'], - fixed_ip_address=self.port['fixed_ips'][0] - ['ip_address']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('50b9aeb4-9f0b-48ee-aa31-fa955a48ff54') - def test_create_floatingip_in_private_network(self): - self.assertRaises(lib_exc.BadRequest, - self.floating_ips_client.create_floatingip, - floating_network_id=self.network['id'], - port_id=self.port['id'], - fixed_ip_address=self.port['fixed_ips'][0] - ['ip_address']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6b3b8797-6d43-4191-985c-c48b773eb429') - def test_associate_floatingip_port_ext_net_unreachable(self): - # Create floating ip - body = self.floating_ips_client.create_floatingip( - floating_network_id=self.ext_net_id) - floating_ip = body['floatingip'] - self.addCleanup( - self.floating_ips_client.delete_floatingip, floating_ip['id']) - # Associate floating IP to the other port - self.assertRaises( - lib_exc.NotFound, self.floating_ips_client.update_floatingip, - floating_ip['id'], port_id=self.port['id'], - fixed_ip_address=self.port['fixed_ips'][0]['ip_address']) diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py deleted file mode 100644 index 269f2c2d6..000000000 --- a/tempest/api/network/test_networks.py +++ /dev/null @@ -1,654 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 netaddr -import six -import testtools - -from tempest.api.network import base -from tempest.common import custom_matchers -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class BaseNetworkTestResources(base.BaseNetworkTest): - - @classmethod - def resource_setup(cls): - super(BaseNetworkTestResources, cls).resource_setup() - cls.network = cls.create_network() - cls.subnet = cls._create_subnet_with_last_subnet_block(cls.network, - cls._ip_version) - cls._subnet_data = {6: {'gateway': - str(cls._get_gateway_from_tempest_conf(6)), - 'allocation_pools': - cls._get_allocation_pools_from_gateway(6), - 'dns_nameservers': ['2001:4860:4860::8844', - '2001:4860:4860::8888'], - 'host_routes': [{'destination': '2001::/64', - 'nexthop': '2003::1'}], - 'new_host_routes': [{'destination': - '2001::/64', - 'nexthop': '2005::1'}], - 'new_dns_nameservers': - ['2001:4860:4860::7744', - '2001:4860:4860::7888']}, - 4: {'gateway': - str(cls._get_gateway_from_tempest_conf(4)), - 'allocation_pools': - cls._get_allocation_pools_from_gateway(4), - 'dns_nameservers': ['8.8.4.4', '8.8.8.8'], - 'host_routes': [{'destination': '10.20.0.0/32', - 'nexthop': '10.100.1.1'}], - 'new_host_routes': [{'destination': - '10.20.0.0/32', - 'nexthop': - '10.100.1.2'}], - 'new_dns_nameservers': ['7.8.8.8', '7.8.4.4']}} - - @classmethod - def _create_subnet_with_last_subnet_block(cls, network, ip_version): - # Derive last subnet CIDR block from project CIDR and - # create the subnet with that derived CIDR - if ip_version == 4: - cidr = netaddr.IPNetwork(CONF.network.project_network_cidr) - mask_bits = CONF.network.project_network_mask_bits - elif ip_version == 6: - cidr = netaddr.IPNetwork(CONF.network.project_network_v6_cidr) - mask_bits = CONF.network.project_network_v6_mask_bits - - subnet_cidr = list(cidr.subnet(mask_bits))[-1] - gateway_ip = str(netaddr.IPAddress(subnet_cidr) + 1) - return cls.create_subnet(network, gateway=gateway_ip, - cidr=subnet_cidr, mask_bits=mask_bits) - - @classmethod - def _get_gateway_from_tempest_conf(cls, ip_version): - """Return first subnet gateway for configured CIDR """ - if ip_version == 4: - cidr = netaddr.IPNetwork(CONF.network.project_network_cidr) - mask_bits = CONF.network.project_network_mask_bits - elif ip_version == 6: - cidr = netaddr.IPNetwork(CONF.network.project_network_v6_cidr) - mask_bits = CONF.network.project_network_v6_mask_bits - - if mask_bits >= cidr.prefixlen: - return netaddr.IPAddress(cidr) + 1 - else: - for subnet in cidr.subnet(mask_bits): - return netaddr.IPAddress(subnet) + 1 - - @classmethod - def _get_allocation_pools_from_gateway(cls, ip_version): - """Return allocation range for subnet of given gateway""" - gateway = cls._get_gateway_from_tempest_conf(ip_version) - return [{'start': str(gateway + 2), 'end': str(gateway + 6)}] - - def subnet_dict(self, include_keys): - # Return a subnet dict which has include_keys and their corresponding - # value from self._subnet_data - return dict((key, self._subnet_data[self._ip_version][key]) - for key in include_keys) - - def _compare_resource_attrs(self, actual, expected): - exclude_keys = set(actual).symmetric_difference(expected) - self.assertThat(actual, custom_matchers.MatchesDictExceptForKeys( - expected, exclude_keys)) - - def _delete_network(self, network): - # Deleting network also deletes its subnets if exists - self.networks_client.delete_network(network['id']) - if network in self.networks: - self.networks.remove(network) - for subnet in self.subnets: - if subnet['network_id'] == network['id']: - self.subnets.remove(subnet) - - def _create_verify_delete_subnet(self, cidr=None, mask_bits=None, - **kwargs): - network = self.create_network() - net_id = network['id'] - gateway = kwargs.pop('gateway', None) - subnet = self.create_subnet(network, gateway, cidr, mask_bits, - **kwargs) - compare_args_full = dict(gateway_ip=gateway, cidr=cidr, - mask_bits=mask_bits, **kwargs) - compare_args = dict((k, v) for k, v in compare_args_full.items() - if v is not None) - - if 'dns_nameservers' in set(subnet).intersection(compare_args): - self.assertEqual(sorted(compare_args['dns_nameservers']), - sorted(subnet['dns_nameservers'])) - del subnet['dns_nameservers'], compare_args['dns_nameservers'] - - self._compare_resource_attrs(subnet, compare_args) - self.networks_client.delete_network(net_id) - self.networks.pop() - self.subnets.pop() - - -class NetworksTest(BaseNetworkTestResources): - """Tests the following operations in the Neutron API: - - create a network for a project - list project's networks - show a project network details - create a subnet for a project - list project's subnets - show a project subnet details - network update - subnet update - delete a network also deletes its subnets - list external networks - - All subnet tests are run once with ipv4 and once with ipv6. - - v2.0 of the Neutron API is assumed. It is also assumed that the following - options are defined in the [network] section of etc/tempest.conf: - - project_network_cidr with a block of cidr's from which smaller blocks - can be allocated for project ipv4 subnets - - project_network_v6_cidr is the equivalent for ipv6 subnets - - project_network_mask_bits with the mask bits to be used to partition - the block defined by project_network_cidr - - project_network_v6_mask_bits is the equivalent for ipv6 subnets - """ - - @decorators.attr(type='smoke') - @decorators.idempotent_id('0e269138-0da6-4efc-a46d-578161e7b221') - def test_create_update_delete_network_subnet(self): - # Create a network - network = self.create_network() - self.addCleanup(self._delete_network, network) - net_id = network['id'] - self.assertEqual('ACTIVE', network['status']) - # Verify network update - new_name = "New_network" - body = self.networks_client.update_network(net_id, name=new_name) - updated_net = body['network'] - self.assertEqual(updated_net['name'], new_name) - # Find a cidr that is not in use yet and create a subnet with it - subnet = self.create_subnet(network) - subnet_id = subnet['id'] - # Verify subnet update - new_name = "New_subnet" - body = self.subnets_client.update_subnet(subnet_id, name=new_name) - updated_subnet = body['subnet'] - self.assertEqual(updated_subnet['name'], new_name) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('2bf13842-c93f-4a69-83ed-717d2ec3b44e') - def test_show_network(self): - # Verify the details of a network - body = self.networks_client.show_network(self.network['id']) - network = body['network'] - for key in ['id', 'name']: - self.assertEqual(network[key], self.network[key]) - - @decorators.idempotent_id('867819bb-c4b6-45f7-acf9-90edcf70aa5e') - def test_show_network_fields(self): - # Verify specific fields of a network - fields = ['id', 'name'] - if test.is_extension_enabled('net-mtu', 'network'): - fields.append('mtu') - body = self.networks_client.show_network(self.network['id'], - fields=fields) - network = body['network'] - self.assertEqual(sorted(network.keys()), sorted(fields)) - for field_name in fields: - self.assertEqual(network[field_name], self.network[field_name]) - self.assertNotIn('tenant_id', network) - self.assertNotIn('project_id', network) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('f7ffdeda-e200-4a7a-bcbe-05716e86bf43') - def test_list_networks(self): - # Verify the network exists in the list of all networks - body = self.networks_client.list_networks() - networks = [network['id'] for network in body['networks'] - if network['id'] == self.network['id']] - self.assertNotEmpty(networks, "Created network not found in the list") - - @decorators.idempotent_id('6ae6d24f-9194-4869-9c85-c313cb20e080') - def test_list_networks_fields(self): - # Verify specific fields of the networks - fields = ['id', 'name'] - if test.is_extension_enabled('net-mtu', 'network'): - fields.append('mtu') - body = self.networks_client.list_networks(fields=fields) - networks = body['networks'] - self.assertNotEmpty(networks, "Network list returned is empty") - for network in networks: - self.assertEqual(sorted(network.keys()), sorted(fields)) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('bd635d81-6030-4dd1-b3b9-31ba0cfdf6cc') - def test_show_subnet(self): - # Verify the details of a subnet - body = self.subnets_client.show_subnet(self.subnet['id']) - subnet = body['subnet'] - self.assertNotEmpty(subnet, "Subnet returned has no fields") - for key in ['id', 'cidr']: - self.assertIn(key, subnet) - self.assertEqual(subnet[key], self.subnet[key]) - - @decorators.idempotent_id('270fff0b-8bfc-411f-a184-1e8fd35286f0') - def test_show_subnet_fields(self): - # Verify specific fields of a subnet - fields = ['id', 'network_id'] - body = self.subnets_client.show_subnet(self.subnet['id'], - fields=fields) - subnet = body['subnet'] - self.assertEqual(sorted(subnet.keys()), sorted(fields)) - for field_name in fields: - self.assertEqual(subnet[field_name], self.subnet[field_name]) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('db68ba48-f4ea-49e9-81d1-e367f6d0b20a') - def test_list_subnets(self): - # Verify the subnet exists in the list of all subnets - body = self.subnets_client.list_subnets() - subnets = [subnet['id'] for subnet in body['subnets'] - if subnet['id'] == self.subnet['id']] - self.assertNotEmpty(subnets, "Created subnet not found in the list") - - @decorators.idempotent_id('842589e3-9663-46b0-85e4-7f01273b0412') - def test_list_subnets_fields(self): - # Verify specific fields of subnets - fields = ['id', 'network_id'] - body = self.subnets_client.list_subnets(fields=fields) - subnets = body['subnets'] - self.assertNotEmpty(subnets, "Subnet list returned is empty") - for subnet in subnets: - self.assertEqual(sorted(subnet.keys()), sorted(fields)) - - @decorators.idempotent_id('f04f61a9-b7f3-4194-90b2-9bcf660d1bfe') - def test_delete_network_with_subnet(self): - # Creates a network - network = self.create_network() - net_id = network['id'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self._delete_network, network) - - # Find a cidr that is not in use yet and create a subnet with it - subnet = self.create_subnet(network) - subnet_id = subnet['id'] - - # Delete network while the subnet still exists - self.networks_client.delete_network(net_id) - - # Verify that the subnet got automatically deleted. - self.assertRaises(lib_exc.NotFound, self.subnets_client.show_subnet, - subnet_id) - - @decorators.idempotent_id('d2d596e2-8e76-47a9-ac51-d4648009f4d3') - def test_create_delete_subnet_without_gateway(self): - self._create_verify_delete_subnet() - - @decorators.idempotent_id('9393b468-186d-496d-aa36-732348cd76e7') - def test_create_delete_subnet_with_gw(self): - self._create_verify_delete_subnet( - **self.subnet_dict(['gateway'])) - - @decorators.idempotent_id('bec949c4-3147-4ba6-af5f-cd2306118404') - def test_create_delete_subnet_with_allocation_pools(self): - self._create_verify_delete_subnet( - **self.subnet_dict(['allocation_pools'])) - - @decorators.idempotent_id('8217a149-0c6c-4cfb-93db-0486f707d13f') - def test_create_delete_subnet_with_gw_and_allocation_pools(self): - self._create_verify_delete_subnet(**self.subnet_dict( - ['gateway', 'allocation_pools'])) - - @decorators.idempotent_id('d830de0a-be47-468f-8f02-1fd996118289') - def test_create_delete_subnet_with_host_routes_and_dns_nameservers(self): - self._create_verify_delete_subnet( - **self.subnet_dict(['host_routes', 'dns_nameservers'])) - - @decorators.idempotent_id('94ce038d-ff0a-4a4c-a56b-09da3ca0b55d') - def test_create_delete_subnet_with_dhcp_enabled(self): - self._create_verify_delete_subnet(enable_dhcp=True) - - @decorators.idempotent_id('3d3852eb-3009-49ec-97ac-5ce83b73010a') - def test_update_subnet_gw_dns_host_routes_dhcp(self): - network = self.create_network() - self.addCleanup(self._delete_network, network) - - subnet = self.create_subnet( - network, **self.subnet_dict(['gateway', 'host_routes', - 'dns_nameservers', - 'allocation_pools'])) - subnet_id = subnet['id'] - new_gateway = str(netaddr.IPAddress( - self._subnet_data[self._ip_version]['gateway']) + 1) - # Verify subnet update - new_host_routes = self._subnet_data[self._ip_version][ - 'new_host_routes'] - - new_dns_nameservers = self._subnet_data[self._ip_version][ - 'new_dns_nameservers'] - kwargs = {'host_routes': new_host_routes, - 'dns_nameservers': new_dns_nameservers, - 'gateway_ip': new_gateway, 'enable_dhcp': True} - - new_name = "New_subnet" - body = self.subnets_client.update_subnet(subnet_id, name=new_name, - **kwargs) - updated_subnet = body['subnet'] - kwargs['name'] = new_name - self.assertEqual(sorted(updated_subnet['dns_nameservers']), - sorted(kwargs['dns_nameservers'])) - del subnet['dns_nameservers'], kwargs['dns_nameservers'] - - self._compare_resource_attrs(updated_subnet, kwargs) - - @decorators.idempotent_id('a4d9ec4c-0306-4111-a75c-db01a709030b') - def test_create_delete_subnet_all_attributes(self): - self._create_verify_delete_subnet( - enable_dhcp=True, - **self.subnet_dict(['gateway', 'host_routes', 'dns_nameservers'])) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('af774677-42a9-4e4b-bb58-16fe6a5bc1ec') - @test.requires_ext(extension='external-net', service='network') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_external_network_visibility(self): - """Verifies user can see external networks but not subnets.""" - body = self.networks_client.list_networks(**{'router:external': True}) - networks = [network['id'] for network in body['networks']] - self.assertNotEmpty(networks, "No external networks found") - - nonexternal = [net for net in body['networks'] if - not net['router:external']] - self.assertEmpty(nonexternal, "Found non-external networks" - " in filtered list (%s)." % nonexternal) - self.assertIn(CONF.network.public_network_id, networks) - # only check the public network ID because the other networks may - # belong to other tests and their state may have changed during this - # test - body = self.subnets_client.list_subnets( - network_id=CONF.network.public_network_id) - self.assertEmpty(body['subnets'], "Public subnets visible") - - @decorators.idempotent_id('c72c1c0c-2193-4aca-ccc4-b1442640bbbb') - @test.requires_ext(extension="standard-attr-description", - service="network") - def test_create_update_network_description(self): - body = self.create_network(description='d1') - self.assertEqual('d1', body['description']) - net_id = body['id'] - body = self.networks_client.list_networks(id=net_id)['networks'][0] - self.assertEqual('d1', body['description']) - body = self.networks_client.update_network(body['id'], - description='d2') - self.assertEqual('d2', body['network']['description']) - body = self.networks_client.list_networks(id=net_id)['networks'][0] - self.assertEqual('d2', body['description']) - - -class BulkNetworkOpsTest(base.BaseNetworkTest): - """Tests the following operations in the Neutron API: - - bulk network creation - bulk subnet creation - bulk port creation - list project's networks - - v2.0 of the Neutron API is assumed. It is also assumed that the following - options are defined in the [network] section of etc/tempest.conf: - - project_network_cidr with a block of cidr's from which smaller blocks - can be allocated for project networks - - project_network_mask_bits with the mask bits to be used to partition - the block defined by project-network_cidr - """ - - def _delete_networks(self, created_networks): - for n in created_networks: - self.networks_client.delete_network(n['id']) - # Asserting that the networks are not found in the list after deletion - body = self.networks_client.list_networks() - networks_list = [network['id'] for network in body['networks']] - for n in created_networks: - self.assertNotIn(n['id'], networks_list) - - def _delete_subnets(self, created_subnets): - for n in created_subnets: - self.subnets_client.delete_subnet(n['id']) - # Asserting that the subnets are not found in the list after deletion - body = self.subnets_client.list_subnets() - subnets_list = [subnet['id'] for subnet in body['subnets']] - for n in created_subnets: - self.assertNotIn(n['id'], subnets_list) - - def _delete_ports(self, created_ports): - for n in created_ports: - self.ports_client.delete_port(n['id']) - # Asserting that the ports are not found in the list after deletion - body = self.ports_client.list_ports() - ports_list = [port['id'] for port in body['ports']] - for n in created_ports: - self.assertNotIn(n['id'], ports_list) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('d4f9024d-1e28-4fc1-a6b1-25dbc6fa11e2') - def test_bulk_create_delete_network(self): - # Creates 2 networks in one request - network_list = [{'name': data_utils.rand_name('network-')}, - {'name': data_utils.rand_name('network-')}] - body = self.networks_client.create_bulk_networks(networks=network_list) - created_networks = body['networks'] - self.addCleanup(self._delete_networks, created_networks) - # Asserting that the networks are found in the list after creation - body = self.networks_client.list_networks() - networks_list = [network['id'] for network in body['networks']] - for n in created_networks: - self.assertIsNotNone(n['id']) - self.assertIn(n['id'], networks_list) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('8936533b-c0aa-4f29-8e53-6cc873aec489') - def test_bulk_create_delete_subnet(self): - networks = [self.create_network(), self.create_network()] - # Creates 2 subnets in one request - if self._ip_version == 4: - cidr = netaddr.IPNetwork(CONF.network.project_network_cidr) - mask_bits = CONF.network.project_network_mask_bits - else: - cidr = netaddr.IPNetwork(CONF.network.project_network_v6_cidr) - mask_bits = CONF.network.project_network_v6_mask_bits - - cidrs = [subnet_cidr for subnet_cidr in cidr.subnet(mask_bits)] - - names = [data_utils.rand_name('subnet-') for i in range(len(networks))] - subnets_list = [] - for i in range(len(names)): - p1 = { - 'network_id': networks[i]['id'], - 'cidr': str(cidrs[(i)]), - 'name': names[i], - 'ip_version': self._ip_version - } - subnets_list.append(p1) - del subnets_list[1]['name'] - body = self.subnets_client.create_bulk_subnets(subnets=subnets_list) - created_subnets = body['subnets'] - self.addCleanup(self._delete_subnets, created_subnets) - # Asserting that the subnets are found in the list after creation - body = self.subnets_client.list_subnets() - subnets_list = [subnet['id'] for subnet in body['subnets']] - for n in created_subnets: - self.assertIsNotNone(n['id']) - self.assertIn(n['id'], subnets_list) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('48037ff2-e889-4c3b-b86a-8e3f34d2d060') - def test_bulk_create_delete_port(self): - networks = [self.create_network(), self.create_network()] - # Creates 2 ports in one request - names = [data_utils.rand_name('port-') for i in range(len(networks))] - port_list = [] - state = [True, False] - for i in range(len(names)): - p1 = { - 'network_id': networks[i]['id'], - 'name': names[i], - 'admin_state_up': state[i], - } - port_list.append(p1) - del port_list[1]['name'] - body = self.ports_client.create_bulk_ports(ports=port_list) - created_ports = body['ports'] - self.addCleanup(self._delete_ports, created_ports) - # Asserting that the ports are found in the list after creation - body = self.ports_client.list_ports() - ports_list = [port['id'] for port in body['ports']] - for n in created_ports: - self.assertIsNotNone(n['id']) - self.assertIn(n['id'], ports_list) - - -class BulkNetworkOpsIpV6Test(BulkNetworkOpsTest): - _ip_version = 6 - - -class NetworksIpV6Test(NetworksTest): - _ip_version = 6 - - @decorators.idempotent_id('e41a4888-65a6-418c-a095-f7c2ef4ad59a') - def test_create_delete_subnet_with_gw(self): - net = netaddr.IPNetwork(CONF.network.project_network_v6_cidr) - gateway = str(netaddr.IPAddress(net.first + 2)) - network = self.create_network() - subnet = self.create_subnet(network, gateway) - # Verifies Subnet GW in IPv6 - self.assertEqual(subnet['gateway_ip'], gateway) - - @decorators.idempotent_id('ebb4fd95-524f-46af-83c1-0305b239338f') - def test_create_delete_subnet_with_default_gw(self): - net = netaddr.IPNetwork(CONF.network.project_network_v6_cidr) - gateway_ip = str(netaddr.IPAddress(net.first + 1)) - network = self.create_network() - subnet = self.create_subnet(network) - # Verifies Subnet GW in IPv6 - self.assertEqual(subnet['gateway_ip'], gateway_ip) - - @decorators.idempotent_id('a9653883-b2a4-469b-8c3c-4518430a7e55') - def test_create_list_subnet_with_no_gw64_one_network(self): - network = self.create_network() - ipv6_gateway = self.subnet_dict(['gateway'])['gateway'] - subnet1 = self.create_subnet(network, - ip_version=6, - gateway=ipv6_gateway) - self.assertEqual(netaddr.IPNetwork(subnet1['cidr']).version, 6, - 'The created subnet is not IPv6') - subnet2 = self.create_subnet(network, - gateway=None, - ip_version=4) - self.assertEqual(netaddr.IPNetwork(subnet2['cidr']).version, 4, - 'The created subnet is not IPv4') - # Verifies Subnet GW is set in IPv6 - self.assertEqual(subnet1['gateway_ip'], ipv6_gateway) - # Verifies Subnet GW is None in IPv4 - self.assertIsNone(subnet2['gateway_ip']) - # Verifies all 2 subnets in the same network - body = self.subnets_client.list_subnets() - subnets = [sub['id'] for sub in body['subnets'] - if sub['network_id'] == network['id']] - test_subnet_ids = [sub['id'] for sub in (subnet1, subnet2)] - six.assertCountEqual(self, subnets, - test_subnet_ids, - 'Subnet are not in the same network') - - -class NetworksIpV6TestAttrs(BaseNetworkTestResources): - - _ip_version = 6 - - @classmethod - def skip_checks(cls): - super(NetworksIpV6TestAttrs, cls).skip_checks() - if not CONF.network_feature_enabled.ipv6_subnet_attributes: - raise cls.skipException("IPv6 extended attributes for " - "subnets not available") - - @decorators.idempotent_id('da40cd1b-a833-4354-9a85-cd9b8a3b74ca') - def test_create_delete_subnet_with_v6_attributes_stateful(self): - self._create_verify_delete_subnet( - gateway=self._subnet_data[self._ip_version]['gateway'], - ipv6_ra_mode='dhcpv6-stateful', - ipv6_address_mode='dhcpv6-stateful') - - @decorators.idempotent_id('176b030f-a923-4040-a755-9dc94329e60c') - def test_create_delete_subnet_with_v6_attributes_slaac(self): - self._create_verify_delete_subnet( - ipv6_ra_mode='slaac', - ipv6_address_mode='slaac') - - @decorators.idempotent_id('7d410310-8c86-4902-adf9-865d08e31adb') - def test_create_delete_subnet_with_v6_attributes_stateless(self): - self._create_verify_delete_subnet( - ipv6_ra_mode='dhcpv6-stateless', - ipv6_address_mode='dhcpv6-stateless') - - def _test_delete_subnet_with_ports(self, mode): - """Create subnet and delete it with existing ports""" - slaac_network = self.create_network() - subnet_slaac = self.create_subnet(slaac_network, - **{'ipv6_ra_mode': mode, - 'ipv6_address_mode': mode}) - port = self.create_port(slaac_network) - self.assertIsNotNone(port['fixed_ips'][0]['ip_address']) - self.subnets_client.delete_subnet(subnet_slaac['id']) - self.subnets.pop() - subnets = self.subnets_client.list_subnets() - subnet_ids = [subnet['id'] for subnet in subnets['subnets']] - self.assertNotIn(subnet_slaac['id'], subnet_ids, - "Subnet wasn't deleted") - self.assertRaisesRegex( - lib_exc.Conflict, - "There are one or more ports still in use on the network", - self.networks_client.delete_network, - slaac_network['id']) - - @decorators.idempotent_id('88554555-ebf8-41ef-9300-4926d45e06e9') - def test_create_delete_slaac_subnet_with_ports(self): - """Test deleting subnet with SLAAC ports - - Create subnet with SLAAC, create ports in network - and then you shall be able to delete subnet without port - deletion. But you still can not delete the network. - """ - self._test_delete_subnet_with_ports("slaac") - - @decorators.idempotent_id('2de6ab5a-fcf0-4144-9813-f91a940291f1') - def test_create_delete_stateless_subnet_with_ports(self): - """Test deleting subnet with DHCPv6 stateless ports - - Create subnet with DHCPv6 stateless, create ports in network - and then you shall be able to delete subnet without port - deletion. But you still can not delete the network. - """ - self._test_delete_subnet_with_ports("dhcpv6-stateless") diff --git a/tempest/api/network/test_networks_negative.py b/tempest/api/network/test_networks_negative.py deleted file mode 100644 index bc4f41f99..000000000 --- a/tempest/api/network/test_networks_negative.py +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD. -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.network import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class NetworksNegativeTestJSON(base.BaseNetworkTest): - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9293e937-824d-42d2-8d5b-e985ea67002a') - def test_show_non_existent_network(self): - non_exist_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.networks_client.show_network, - non_exist_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d746b40c-5e09-4043-99f7-cba1be8b70df') - def test_show_non_existent_subnet(self): - non_exist_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.subnets_client.show_subnet, - non_exist_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a954861d-cbfd-44e8-b0a9-7fab111f235d') - def test_show_non_existent_port(self): - non_exist_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.ports_client.show_port, - non_exist_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('98bfe4e3-574e-4012-8b17-b2647063de87') - def test_update_non_existent_network(self): - non_exist_id = data_utils.rand_uuid() - self.assertRaises( - lib_exc.NotFound, self.networks_client.update_network, - non_exist_id, name="new_name") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('03795047-4a94-4120-a0a1-bd376e36fd4e') - def test_delete_non_existent_network(self): - non_exist_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.networks_client.delete_network, - non_exist_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1cc47884-ac52-4415-a31c-e7ce5474a868') - def test_update_non_existent_subnet(self): - non_exist_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.subnets_client.update_subnet, - non_exist_id, name='new_name') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a176c859-99fb-42ec-a208-8a85b552a239') - def test_delete_non_existent_subnet(self): - non_exist_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.subnets_client.delete_subnet, non_exist_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('13d3b106-47e6-4b9b-8d53-dae947f092fe') - def test_create_port_on_non_existent_network(self): - non_exist_net_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.ports_client.create_port, - network_id=non_exist_net_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('cf8eef21-4351-4f53-adcd-cc5cb1e76b92') - def test_update_non_existent_port(self): - non_exist_port_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, self.ports_client.update_port, - non_exist_port_id, name='new_name') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('49ec2bbd-ac2e-46fd-8054-798e679ff894') - def test_delete_non_existent_port(self): - non_exist_port_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.ports_client.delete_port, non_exist_port_id) diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py deleted file mode 100644 index f81927d7a..000000000 --- a/tempest/api/network/test_ports.py +++ /dev/null @@ -1,359 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# 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 netaddr -import testtools - -from tempest.api.network import base_security_groups as sec_base -from tempest.common import custom_matchers -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions -from tempest import test - -CONF = config.CONF - - -class PortsTestJSON(sec_base.BaseSecGroupTest): - """Test the following operations for ports: - - port create - port delete - port list - port show - port update - """ - - @classmethod - def resource_setup(cls): - super(PortsTestJSON, cls).resource_setup() - cls.network = cls.create_network() - cls.port = cls.create_port(cls.network) - - def _delete_port(self, port_id): - self.ports_client.delete_port(port_id) - body = self.ports_client.list_ports() - ports_list = body['ports'] - self.assertFalse(port_id in [n['id'] for n in ports_list]) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('c72c1c0c-2193-4aca-aaa4-b1442640f51c') - def test_create_update_delete_port(self): - # Verify port creation - body = self.ports_client.create_port(network_id=self.network['id']) - port = body['port'] - # Schedule port deletion with verification upon test completion - self.addCleanup(self._delete_port, port['id']) - self.assertTrue(port['admin_state_up']) - # Verify port update - new_name = "New_Port" - body = self.ports_client.update_port(port['id'], - name=new_name, - admin_state_up=False) - updated_port = body['port'] - self.assertEqual(updated_port['name'], new_name) - self.assertFalse(updated_port['admin_state_up']) - - @decorators.idempotent_id('67f1b811-f8db-43e2-86bd-72c074d4a42c') - def test_create_bulk_port(self): - network1 = self.network - network2 = self.create_network() - network_list = [network1['id'], network2['id']] - port_list = [{'network_id': net_id} for net_id in network_list] - body = self.ports_client.create_bulk_ports(ports=port_list) - created_ports = body['ports'] - port1 = created_ports[0] - port2 = created_ports[1] - self.addCleanup(self._delete_port, port1['id']) - self.addCleanup(self._delete_port, port2['id']) - self.assertEqual(port1['network_id'], network1['id']) - self.assertEqual(port2['network_id'], network2['id']) - self.assertTrue(port1['admin_state_up']) - self.assertTrue(port2['admin_state_up']) - - @classmethod - def _get_ipaddress_from_tempest_conf(cls): - """Return subnet with mask bits for configured CIDR """ - if cls._ip_version == 4: - cidr = netaddr.IPNetwork(CONF.network.project_network_cidr) - cidr.prefixlen = CONF.network.project_network_mask_bits - - elif cls._ip_version == 6: - cidr = netaddr.IPNetwork(CONF.network.project_network_v6_cidr) - cidr.prefixlen = CONF.network.project_network_v6_mask_bits - - return cidr - - @decorators.attr(type='smoke') - @decorators.idempotent_id('0435f278-40ae-48cb-a404-b8a087bc09b1') - def test_create_port_in_allowed_allocation_pools(self): - network = self.create_network() - net_id = network['id'] - address = self._get_ipaddress_from_tempest_conf() - if ((address.version == 4 and address.prefixlen >= 30) or - (address.version == 6 and address.prefixlen >= 126)): - msg = ("Subnet %s isn't large enough for the test" % address.cidr) - raise exceptions.InvalidConfiguration(msg) - allocation_pools = {'allocation_pools': [{'start': str(address[2]), - 'end': str(address[-2])}]} - subnet = self.create_subnet(network, cidr=address, - mask_bits=address.prefixlen, - **allocation_pools) - self.addCleanup(self.subnets_client.delete_subnet, subnet['id']) - body = self.ports_client.create_port(network_id=net_id) - self.addCleanup(self.ports_client.delete_port, body['port']['id']) - port = body['port'] - ip_address = port['fixed_ips'][0]['ip_address'] - start_ip_address = allocation_pools['allocation_pools'][0]['start'] - end_ip_address = allocation_pools['allocation_pools'][0]['end'] - ip_range = netaddr.IPRange(start_ip_address, end_ip_address) - self.assertIn(ip_address, ip_range) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('c9a685bd-e83f-499c-939f-9f7863ca259f') - def test_show_port(self): - # Verify the details of port - body = self.ports_client.show_port(self.port['id']) - port = body['port'] - self.assertIn('id', port) - # NOTE(rfolco): created_at and updated_at may get inconsistent values - # due to possible delay between POST request and resource creation. - # TODO(rfolco): Neutron Bug #1365341 is fixed, can remove the key - # extra_dhcp_opts in the O release (K/L gate jobs still need it). - self.assertThat(self.port, - custom_matchers.MatchesDictExceptForKeys - (port, excluded_keys=['extra_dhcp_opts', - 'created_at', - 'updated_at'])) - - @decorators.idempotent_id('45fcdaf2-dab0-4c13-ac6c-fcddfb579dbd') - def test_show_port_fields(self): - # Verify specific fields of a port - fields = ['id', 'mac_address'] - body = self.ports_client.show_port(self.port['id'], - fields=fields) - port = body['port'] - self.assertEqual(sorted(port.keys()), sorted(fields)) - for field_name in fields: - self.assertEqual(port[field_name], self.port[field_name]) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('cf95b358-3e92-4a29-a148-52445e1ac50e') - def test_list_ports(self): - # Verify the port exists in the list of all ports - body = self.ports_client.list_ports() - ports = [port['id'] for port in body['ports'] - if port['id'] == self.port['id']] - self.assertNotEmpty(ports, "Created port not found in the list") - - @decorators.idempotent_id('e7fe260b-1e79-4dd3-86d9-bec6a7959fc5') - def test_port_list_filter_by_ip(self): - # Create network and subnet - network = self.create_network() - subnet = self.create_subnet(network) - self.addCleanup(self.subnets_client.delete_subnet, subnet['id']) - # Create two ports - port_1 = self.ports_client.create_port(network_id=network['id']) - self.addCleanup(self.ports_client.delete_port, port_1['port']['id']) - port_2 = self.ports_client.create_port(network_id=network['id']) - self.addCleanup(self.ports_client.delete_port, port_2['port']['id']) - # List ports filtered by fixed_ips - port_1_fixed_ip = port_1['port']['fixed_ips'][0]['ip_address'] - fixed_ips = 'ip_address=' + port_1_fixed_ip - port_list = self.ports_client.list_ports(fixed_ips=fixed_ips) - # Check that we got the desired port - ports = port_list['ports'] - tenant_ids = set([port['tenant_id'] for port in ports]) - self.assertEqual(len(tenant_ids), 1, - 'Ports from multiple tenants are in the list resp') - port_ids = [port['id'] for port in ports] - fixed_ips = [port['fixed_ips'] for port in ports] - port_ips = [] - for addr in fixed_ips: - port_ips.extend([port['ip_address'] for port in addr]) - - port_net_ids = [port['network_id'] for port in ports] - self.assertIn(port_1['port']['id'], port_ids) - self.assertIn(port_1_fixed_ip, port_ips) - self.assertIn(network['id'], port_net_ids) - - @decorators.idempotent_id('5ad01ed0-0e6e-4c5d-8194-232801b15c72') - def test_port_list_filter_by_router_id(self): - # Create a router - network = self.create_network() - self.addCleanup(self.networks_client.delete_network, network['id']) - subnet = self.create_subnet(network) - self.addCleanup(self.subnets_client.delete_subnet, subnet['id']) - router = self.create_router() - self.addCleanup(self.routers_client.delete_router, router['id']) - port = self.ports_client.create_port(network_id=network['id']) - # Add router interface to port created above - self.routers_client.add_router_interface(router['id'], - port_id=port['port']['id']) - self.addCleanup(self.routers_client.remove_router_interface, - router['id'], port_id=port['port']['id']) - # List ports filtered by router_id - port_list = self.ports_client.list_ports(device_id=router['id']) - ports = port_list['ports'] - self.assertEqual(len(ports), 1) - self.assertEqual(ports[0]['id'], port['port']['id']) - self.assertEqual(ports[0]['device_id'], router['id']) - - @decorators.idempotent_id('ff7f117f-f034-4e0e-abff-ccef05c454b4') - def test_list_ports_fields(self): - # Verify specific fields of ports - fields = ['id', 'mac_address'] - body = self.ports_client.list_ports(fields=fields) - ports = body['ports'] - self.assertNotEmpty(ports, "Port list returned is empty") - # Asserting the fields returned are correct - for port in ports: - self.assertEqual(sorted(fields), sorted(port.keys())) - - @decorators.idempotent_id('63aeadd4-3b49-427f-a3b1-19ca81f06270') - def test_create_update_port_with_second_ip(self): - # Create a network with two subnets - network = self.create_network() - self.addCleanup(self.networks_client.delete_network, network['id']) - subnet_1 = self.create_subnet(network) - self.addCleanup(self.subnets_client.delete_subnet, subnet_1['id']) - subnet_2 = self.create_subnet(network) - self.addCleanup(self.subnets_client.delete_subnet, subnet_2['id']) - fixed_ip_1 = [{'subnet_id': subnet_1['id']}] - fixed_ip_2 = [{'subnet_id': subnet_2['id']}] - - fixed_ips = fixed_ip_1 + fixed_ip_2 - - # Create a port with multiple IP addresses - port = self.create_port(network, - fixed_ips=fixed_ips) - self.addCleanup(self.ports_client.delete_port, port['id']) - self.assertEqual(2, len(port['fixed_ips'])) - check_fixed_ips = [subnet_1['id'], subnet_2['id']] - for item in port['fixed_ips']: - self.assertIn(item['subnet_id'], check_fixed_ips) - - # Update the port to return to a single IP address - port = self.update_port(port, fixed_ips=fixed_ip_1) - self.assertEqual(1, len(port['fixed_ips'])) - - # Update the port with a second IP address from second subnet - port = self.update_port(port, fixed_ips=fixed_ips) - self.assertEqual(2, len(port['fixed_ips'])) - - def _update_port_with_security_groups(self, security_groups_names): - subnet_1 = self.create_subnet(self.network) - self.addCleanup(self.subnets_client.delete_subnet, subnet_1['id']) - fixed_ip_1 = [{'subnet_id': subnet_1['id']}] - - security_groups_list = list() - sec_grps_client = self.security_groups_client - for name in security_groups_names: - group_create_body = sec_grps_client.create_security_group( - name=name) - self.addCleanup(self.security_groups_client.delete_security_group, - group_create_body['security_group']['id']) - security_groups_list.append(group_create_body['security_group'] - ['id']) - # Create a port - sec_grp_name = data_utils.rand_name('secgroup') - security_group = sec_grps_client.create_security_group( - name=sec_grp_name) - self.addCleanup(self.security_groups_client.delete_security_group, - security_group['security_group']['id']) - post_body = { - "name": data_utils.rand_name('port-'), - "security_groups": [security_group['security_group']['id']], - "network_id": self.network['id'], - "admin_state_up": True, - "fixed_ips": fixed_ip_1} - body = self.ports_client.create_port(**post_body) - self.addCleanup(self.ports_client.delete_port, body['port']['id']) - port = body['port'] - - # Update the port with security groups - subnet_2 = self.create_subnet(self.network) - fixed_ip_2 = [{'subnet_id': subnet_2['id']}] - update_body = {"name": data_utils.rand_name('port-'), - "admin_state_up": False, - "fixed_ips": fixed_ip_2, - "security_groups": security_groups_list} - body = self.ports_client.update_port(port['id'], **update_body) - port_show = body['port'] - # Verify the security groups and other attributes updated to port - exclude_keys = set(port_show).symmetric_difference(update_body) - exclude_keys.add('fixed_ips') - exclude_keys.add('security_groups') - self.assertThat(port_show, custom_matchers.MatchesDictExceptForKeys( - update_body, exclude_keys)) - self.assertEqual(fixed_ip_2[0]['subnet_id'], - port_show['fixed_ips'][0]['subnet_id']) - - for security_group in security_groups_list: - self.assertIn(security_group, port_show['security_groups']) - - @decorators.idempotent_id('58091b66-4ff4-4cc1-a549-05d60c7acd1a') - @testtools.skipUnless( - test.is_extension_enabled('security-group', 'network'), - 'security-group extension not enabled.') - def test_update_port_with_security_group_and_extra_attributes(self): - self._update_port_with_security_groups( - [data_utils.rand_name('secgroup')]) - - @decorators.idempotent_id('edf6766d-3d40-4621-bc6e-2521a44c257d') - @testtools.skipUnless( - test.is_extension_enabled('security-group', 'network'), - 'security-group extension not enabled.') - def test_update_port_with_two_security_groups_and_extra_attributes(self): - self._update_port_with_security_groups( - [data_utils.rand_name('secgroup'), - data_utils.rand_name('secgroup')]) - - @decorators.idempotent_id('13e95171-6cbd-489c-9d7c-3f9c58215c18') - def test_create_show_delete_port_user_defined_mac(self): - # Create a port for a legal mac - body = self.ports_client.create_port(network_id=self.network['id']) - old_port = body['port'] - free_mac_address = old_port['mac_address'] - self.ports_client.delete_port(old_port['id']) - # Create a new port with user defined mac - body = self.ports_client.create_port(network_id=self.network['id'], - mac_address=free_mac_address) - self.addCleanup(self.ports_client.delete_port, body['port']['id']) - port = body['port'] - body = self.ports_client.show_port(port['id']) - show_port = body['port'] - self.assertEqual(free_mac_address, - show_port['mac_address']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('4179dcb9-1382-4ced-84fe-1b91c54f5735') - @testtools.skipUnless( - test.is_extension_enabled('security-group', 'network'), - 'security-group extension not enabled.') - def test_create_port_with_no_securitygroups(self): - network = self.create_network() - self.addCleanup(self.networks_client.delete_network, network['id']) - subnet = self.create_subnet(network) - self.addCleanup(self.subnets_client.delete_subnet, subnet['id']) - port = self.create_port(network, security_groups=[]) - self.addCleanup(self.ports_client.delete_port, port['id']) - self.assertIsNotNone(port['security_groups']) - self.assertEmpty(port['security_groups']) - - -class PortsIpV6TestJSON(PortsTestJSON): - _ip_version = 6 diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py deleted file mode 100644 index 128544b1b..000000000 --- a/tempest/api/network/test_routers.py +++ /dev/null @@ -1,319 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 netaddr -import testtools - -from tempest.api.network import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class RoutersTest(base.BaseNetworkTest): - - def _cleanup_router(self, router): - self.delete_router(router) - self.routers.remove(router) - - def _create_router(self, name=None, admin_state_up=False, - external_network_id=None, enable_snat=None): - # associate a cleanup with created routers to avoid quota limits - router = self.create_router(name, admin_state_up, - external_network_id, enable_snat) - self.addCleanup(self._cleanup_router, router) - return router - - def _add_router_interface_with_subnet_id(self, router_id, subnet_id): - interface = self.routers_client.add_router_interface( - router_id, subnet_id=subnet_id) - self.addCleanup(self._remove_router_interface_with_subnet_id, - router_id, subnet_id) - self.assertEqual(subnet_id, interface['subnet_id']) - return interface - - def _remove_router_interface_with_subnet_id(self, router_id, subnet_id): - body = self.routers_client.remove_router_interface(router_id, - subnet_id=subnet_id) - self.assertEqual(subnet_id, body['subnet_id']) - - @classmethod - def skip_checks(cls): - super(RoutersTest, cls).skip_checks() - if not test.is_extension_enabled('router', 'network'): - msg = "router extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(RoutersTest, cls).resource_setup() - cls.tenant_cidr = (CONF.network.project_network_cidr - if cls._ip_version == 4 else - CONF.network.project_network_v6_cidr) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('f64403e2-8483-4b34-8ccd-b09a87bcc68c') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - def test_create_show_list_update_delete_router(self): - # Create a router - router = self._create_router( - admin_state_up=False, - external_network_id=CONF.network.public_network_id) - self.assertEqual(router['admin_state_up'], False) - self.assertEqual( - router['external_gateway_info']['network_id'], - CONF.network.public_network_id) - # Show details of the created router - router_show = self.routers_client.show_router( - router['id'])['router'] - self.assertEqual(router_show['name'], router['name']) - self.assertEqual( - router_show['external_gateway_info']['network_id'], - CONF.network.public_network_id) - # List routers and verify if created router is there in response - routers = self.routers_client.list_routers()['routers'] - self.assertIn(router['id'], map(lambda x: x['id'], routers)) - # Update the name of router and verify if it is updated - updated_name = 'updated' + router['name'] - router_update = self.routers_client.update_router( - router['id'], name=updated_name)['router'] - self.assertEqual(router_update['name'], updated_name) - router_show = self.routers_client.show_router( - router['id'])['router'] - self.assertEqual(router_show['name'], updated_name) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('b42e6e39-2e37-49cc-a6f4-8467e940900a') - def test_add_remove_router_interface_with_subnet_id(self): - network = self.create_network() - subnet = self.create_subnet(network) - router = self._create_router() - # Add router interface with subnet id - interface = self.routers_client.add_router_interface( - router['id'], subnet_id=subnet['id']) - self.addCleanup(self._remove_router_interface_with_subnet_id, - router['id'], subnet['id']) - self.assertIn('subnet_id', interface.keys()) - self.assertIn('port_id', interface.keys()) - # Verify router id is equal to device id in port details - show_port_body = self.ports_client.show_port( - interface['port_id']) - self.assertEqual(show_port_body['port']['device_id'], - router['id']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('2b7d2f37-6748-4d78-92e5-1d590234f0d5') - def test_add_remove_router_interface_with_port_id(self): - network = self.create_network() - self.create_subnet(network) - router = self._create_router() - port_body = self.ports_client.create_port( - network_id=network['id']) - # add router interface to port created above - interface = self.routers_client.add_router_interface( - router['id'], - port_id=port_body['port']['id']) - self.addCleanup(self.routers_client.remove_router_interface, - router['id'], port_id=port_body['port']['id']) - self.assertIn('subnet_id', interface.keys()) - self.assertIn('port_id', interface.keys()) - # Verify router id is equal to device id in port details - show_port_body = self.ports_client.show_port( - interface['port_id']) - self.assertEqual(show_port_body['port']['device_id'], - router['id']) - - def _verify_router_gateway(self, router_id, exp_ext_gw_info=None): - show_body = self.admin_routers_client.show_router(router_id) - actual_ext_gw_info = show_body['router']['external_gateway_info'] - if exp_ext_gw_info is None: - self.assertIsNone(actual_ext_gw_info) - return - # Verify only keys passed in exp_ext_gw_info - for k, v in exp_ext_gw_info.items(): - self.assertEqual(v, actual_ext_gw_info[k]) - - def _verify_gateway_port(self, router_id): - list_body = self.admin_ports_client.list_ports( - network_id=CONF.network.public_network_id, - device_id=router_id) - self.assertEqual(len(list_body['ports']), 1) - gw_port = list_body['ports'][0] - fixed_ips = gw_port['fixed_ips'] - self.assertNotEmpty(fixed_ips) - # Assert that all of the IPs from the router gateway port - # are allocated from a valid public subnet. - public_net_body = self.admin_networks_client.show_network( - CONF.network.public_network_id) - public_subnet_ids = public_net_body['network']['subnets'] - for fixed_ip in fixed_ips: - subnet_id = fixed_ip['subnet_id'] - self.assertIn(subnet_id, public_subnet_ids) - - @decorators.idempotent_id('cbe42f84-04c2-11e7-8adb-fa163e4fa634') - @test.requires_ext(extension='ext-gw-mode', service='network') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - @decorators.skip_because(bug='1676207') - def test_create_router_set_gateway_with_fixed_ip(self): - # Don't know public_network_address, so at first create address - # from public_network and delete - port = self.admin_ports_client.create_port( - network_id=CONF.network.public_network_id)['port'] - self.admin_ports_client.delete_port(port_id=port['id']) - - fixed_ip = { - 'subnet_id': port['fixed_ips'][0]['subnet_id'], - 'ip_address': port['fixed_ips'][0]['ip_address'] - } - external_gateway_info = { - 'network_id': CONF.network.public_network_id, - 'external_fixed_ips': [fixed_ip] - } - - # Create a router and set gateway to fixed_ip - router = self.admin_routers_client.create_router( - external_gateway_info=external_gateway_info)['router'] - self.addCleanup(self.admin_routers_client.delete_router, - router_id=router['id']) - # Examine router's gateway is equal to fixed_ip - self.assertEqual(router['external_gateway_info'][ - 'external_fixed_ips'][0]['ip_address'], - fixed_ip['ip_address']) - - @decorators.idempotent_id('c86ac3a8-50bd-4b00-a6b8-62af84a0765c') - @test.requires_ext(extension='extraroute', service='network') - def test_update_delete_extra_route(self): - # Create different cidr for each subnet to avoid cidr duplicate - # The cidr starts from project_cidr - next_cidr = netaddr.IPNetwork(self.tenant_cidr) - # Prepare to build several routes - test_routes = [] - routes_num = 4 - # Create a router - router = self._create_router(admin_state_up=True) - self.addCleanup( - self._delete_extra_routes, - router['id']) - # Update router extra route, second ip of the range is - # used as next hop - for i in range(routes_num): - network = self.create_network() - subnet = self.create_subnet(network, cidr=next_cidr) - next_cidr = next_cidr.next() - - # Add router interface with subnet id - self.create_router_interface(router['id'], subnet['id']) - - cidr = netaddr.IPNetwork(subnet['cidr']) - next_hop = str(cidr[2]) - destination = str(subnet['cidr']) - test_routes.append( - {'nexthop': next_hop, 'destination': destination} - ) - - test_routes.sort(key=lambda x: x['destination']) - extra_route = self.routers_client.update_router( - router['id'], routes=test_routes) - show_body = self.routers_client.show_router(router['id']) - # Assert the number of routes - self.assertEqual(routes_num, len(extra_route['router']['routes'])) - self.assertEqual(routes_num, len(show_body['router']['routes'])) - - routes = extra_route['router']['routes'] - routes.sort(key=lambda x: x['destination']) - # Assert the nexthops & destination - for i in range(routes_num): - self.assertEqual(test_routes[i]['destination'], - routes[i]['destination']) - self.assertEqual(test_routes[i]['nexthop'], routes[i]['nexthop']) - - routes = show_body['router']['routes'] - routes.sort(key=lambda x: x['destination']) - for i in range(routes_num): - self.assertEqual(test_routes[i]['destination'], - routes[i]['destination']) - self.assertEqual(test_routes[i]['nexthop'], routes[i]['nexthop']) - - self._delete_extra_routes(router['id']) - show_body_after_deletion = self.routers_client.show_router( - router['id']) - self.assertEmpty(show_body_after_deletion['router']['routes']) - - def _delete_extra_routes(self, router_id): - self.routers_client.update_router(router_id, routes=None) - - @decorators.idempotent_id('a8902683-c788-4246-95c7-ad9c6d63a4d9') - def test_update_router_admin_state(self): - router = self._create_router() - self.assertFalse(router['admin_state_up']) - # Update router admin state - update_body = self.routers_client.update_router(router['id'], - admin_state_up=True) - self.assertTrue(update_body['router']['admin_state_up']) - show_body = self.routers_client.show_router(router['id']) - self.assertTrue(show_body['router']['admin_state_up']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('802c73c9-c937-4cef-824b-2191e24a6aab') - def test_add_multiple_router_interfaces(self): - network01 = self.create_network( - network_name=data_utils.rand_name('router-network01-')) - network02 = self.create_network( - network_name=data_utils.rand_name('router-network02-')) - subnet01 = self.create_subnet(network01) - sub02_cidr = netaddr.IPNetwork(self.tenant_cidr).next() - subnet02 = self.create_subnet(network02, cidr=sub02_cidr) - router = self._create_router() - interface01 = self._add_router_interface_with_subnet_id(router['id'], - subnet01['id']) - self._verify_router_interface(router['id'], subnet01['id'], - interface01['port_id']) - interface02 = self._add_router_interface_with_subnet_id(router['id'], - subnet02['id']) - self._verify_router_interface(router['id'], subnet02['id'], - interface02['port_id']) - - @decorators.idempotent_id('96522edf-b4b5-45d9-8443-fa11c26e6eff') - def test_router_interface_port_update_with_fixed_ip(self): - network = self.create_network() - subnet = self.create_subnet(network) - router = self._create_router() - fixed_ip = [{'subnet_id': subnet['id']}] - interface = self._add_router_interface_with_subnet_id(router['id'], - subnet['id']) - self.assertIn('port_id', interface) - self.assertIn('subnet_id', interface) - port = self.ports_client.show_port(interface['port_id']) - self.assertEqual(port['port']['id'], interface['port_id']) - router_port = self.ports_client.update_port(port['port']['id'], - fixed_ips=fixed_ip) - self.assertEqual(subnet['id'], - router_port['port']['fixed_ips'][0]['subnet_id']) - - def _verify_router_interface(self, router_id, subnet_id, port_id): - show_port_body = self.ports_client.show_port(port_id) - interface_port = show_port_body['port'] - self.assertEqual(router_id, interface_port['device_id']) - self.assertEqual(subnet_id, - interface_port['fixed_ips'][0]['subnet_id']) - - -class RoutersIpV6Test(RoutersTest): - _ip_version = 6 diff --git a/tempest/api/network/test_routers_negative.py b/tempest/api/network/test_routers_negative.py deleted file mode 100644 index 72face872..000000000 --- a/tempest/api/network/test_routers_negative.py +++ /dev/null @@ -1,142 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 netaddr - -from tempest.api.network import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class RoutersNegativeTest(base.BaseNetworkTest): - - @classmethod - def skip_checks(cls): - super(RoutersNegativeTest, cls).skip_checks() - if not test.is_extension_enabled('router', 'network'): - msg = "router extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(RoutersNegativeTest, cls).resource_setup() - cls.router = cls.create_router() - cls.network = cls.create_network() - cls.subnet = cls.create_subnet(cls.network) - cls.tenant_cidr = (CONF.network.project_network_cidr - if cls._ip_version == 4 else - CONF.network.project_network_v6_cidr) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('37a94fc0-a834-45b9-bd23-9a81d2fd1e22') - def test_router_add_gateway_invalid_network_returns_404(self): - self.assertRaises(lib_exc.NotFound, - self.routers_client.update_router, - self.router['id'], - external_gateway_info={ - 'network_id': self.router['id']}) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('11836a18-0b15-4327-a50b-f0d9dc66bddd') - def test_router_add_gateway_net_not_external_returns_400(self): - alt_network = self.create_network() - sub_cidr = netaddr.IPNetwork(self.tenant_cidr).next() - self.create_subnet(alt_network, cidr=sub_cidr) - self.assertRaises(lib_exc.BadRequest, - self.routers_client.update_router, - self.router['id'], - external_gateway_info={ - 'network_id': alt_network['id']}) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('957751a3-3c68-4fa2-93b6-eb52ea10db6e') - def test_add_router_interfaces_on_overlapping_subnets_returns_400(self): - network01 = self.create_network( - network_name=data_utils.rand_name('router-network01-')) - network02 = self.create_network( - network_name=data_utils.rand_name('router-network02-')) - subnet01 = self.create_subnet(network01) - subnet02 = self.create_subnet(network02) - interface = self.routers_client.add_router_interface( - self.router['id'], subnet_id=subnet01['id']) - self.addCleanup(self.routers_client.remove_router_interface, - self.router['id'], subnet_id=subnet01['id']) - self.assertEqual(subnet01['id'], interface['subnet_id']) - self.assertRaises(lib_exc.BadRequest, - self.routers_client.add_router_interface, - self.router['id'], - subnet_id=subnet02['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('04df80f9-224d-47f5-837a-bf23e33d1c20') - def test_router_remove_interface_in_use_returns_409(self): - self.routers_client.add_router_interface(self.router['id'], - subnet_id=self.subnet['id']) - self.assertRaises(lib_exc.Conflict, - self.routers_client.delete_router, - self.router['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('c2a70d72-8826-43a7-8208-0209e6360c47') - def test_show_non_existent_router_returns_404(self): - router = data_utils.rand_name('non_exist_router') - self.assertRaises(lib_exc.NotFound, self.routers_client.show_router, - router) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('b23d1569-8b0c-4169-8d4b-6abd34fad5c7') - def test_update_non_existent_router_returns_404(self): - router = data_utils.rand_name('non_exist_router') - self.assertRaises(lib_exc.NotFound, self.routers_client.update_router, - router, name="new_name") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('c7edc5ad-d09d-41e6-a344-5c0c31e2e3e4') - def test_delete_non_existent_router_returns_404(self): - router = data_utils.rand_name('non_exist_router') - self.assertRaises(lib_exc.NotFound, self.routers_client.delete_router, - router) - - -class RoutersNegativeIpV6Test(RoutersNegativeTest): - _ip_version = 6 - - -class DvrRoutersNegativeTest(base.BaseNetworkTest): - - @classmethod - def skip_checks(cls): - super(DvrRoutersNegativeTest, cls).skip_checks() - if not test.is_extension_enabled('dvr', 'network'): - msg = "DVR extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(DvrRoutersNegativeTest, cls).resource_setup() - cls.router = cls.create_router() - cls.network = cls.create_network() - cls.subnet = cls.create_subnet(cls.network) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('4990b055-8fc7-48ab-bba7-aa28beaad0b9') - def test_router_create_tenant_distributed_returns_forbidden(self): - self.assertRaises(lib_exc.Forbidden, self.create_router, - distributed=True) diff --git a/tempest/api/network/test_security_groups.py b/tempest/api/network/test_security_groups.py deleted file mode 100644 index a1218644d..000000000 --- a/tempest/api/network/test_security_groups.py +++ /dev/null @@ -1,241 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 tempest.api.network import base_security_groups as base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class SecGroupTest(base.BaseSecGroupTest): - _project_network_cidr = CONF.network.project_network_cidr - - @classmethod - def skip_checks(cls): - super(SecGroupTest, cls).skip_checks() - if not test.is_extension_enabled('security-group', 'network'): - msg = "security-group extension not enabled." - raise cls.skipException(msg) - - def _create_verify_security_group_rule(self, sg_id, direction, - ethertype, protocol, - port_range_min, - port_range_max, - remote_group_id=None, - remote_ip_prefix=None): - # Create Security Group rule with the input params and validate - # that SG rule is created with the same parameters. - sec_group_rules_client = self.security_group_rules_client - rule_create_body = sec_group_rules_client.create_security_group_rule( - security_group_id=sg_id, - direction=direction, - ethertype=ethertype, - protocol=protocol, - port_range_min=port_range_min, - port_range_max=port_range_max, - remote_group_id=remote_group_id, - remote_ip_prefix=remote_ip_prefix - ) - - sec_group_rule = rule_create_body['security_group_rule'] - self.addCleanup(self._delete_security_group_rule, - sec_group_rule['id']) - - expected = {'direction': direction, 'protocol': protocol, - 'ethertype': ethertype, 'port_range_min': port_range_min, - 'port_range_max': port_range_max, - 'remote_group_id': remote_group_id, - 'remote_ip_prefix': remote_ip_prefix} - for key, value in expected.items(): - self.assertEqual(value, sec_group_rule[key], - "Field %s of the created security group " - "rule does not match with %s." % - (key, value)) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('e30abd17-fef9-4739-8617-dc26da88e686') - def test_list_security_groups(self): - # Verify the security group belonging to project exist in list - body = self.security_groups_client.list_security_groups() - security_groups = body['security_groups'] - found = None - for n in security_groups: - if (n['name'] == 'default'): - found = n['id'] - msg = "Security-group list doesn't contain default security-group" - self.assertIsNotNone(found, msg) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('bfd128e5-3c92-44b6-9d66-7fe29d22c802') - def test_create_list_update_show_delete_security_group(self): - group_create_body, _ = self._create_security_group() - - # List security groups and verify if created group is there in response - list_body = self.security_groups_client.list_security_groups() - secgroup_list = list() - for secgroup in list_body['security_groups']: - secgroup_list.append(secgroup['id']) - self.assertIn(group_create_body['security_group']['id'], secgroup_list) - # Update the security group - new_name = data_utils.rand_name('security-') - new_description = data_utils.rand_name('security-description') - update_body = self.security_groups_client.update_security_group( - group_create_body['security_group']['id'], - name=new_name, - description=new_description) - # Verify if security group is updated - self.assertEqual(update_body['security_group']['name'], new_name) - self.assertEqual(update_body['security_group']['description'], - new_description) - # Show details of the updated security group - show_body = self.security_groups_client.show_security_group( - group_create_body['security_group']['id']) - self.assertEqual(show_body['security_group']['name'], new_name) - self.assertEqual(show_body['security_group']['description'], - new_description) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('cfb99e0e-7410-4a3d-8a0c-959a63ee77e9') - def test_create_show_delete_security_group_rule(self): - group_create_body, _ = self._create_security_group() - - # Create rules for each protocol - protocols = ['tcp', 'udp', 'icmp'] - client = self.security_group_rules_client - for protocol in protocols: - rule_create_body = client.create_security_group_rule( - security_group_id=group_create_body['security_group']['id'], - protocol=protocol, - direction='ingress', - ethertype=self.ethertype - ) - - # Show details of the created security rule - show_rule_body = client.show_security_group_rule( - rule_create_body['security_group_rule']['id'] - ) - create_dict = rule_create_body['security_group_rule'] - for key, value in create_dict.items(): - self.assertEqual(value, - show_rule_body['security_group_rule'][key], - "%s does not match." % key) - - # List rules and verify created rule is in response - rule_list_body = ( - self.security_group_rules_client.list_security_group_rules()) - rule_list = [rule['id'] - for rule in rule_list_body['security_group_rules']] - self.assertIn(rule_create_body['security_group_rule']['id'], - rule_list) - - @decorators.idempotent_id('87dfbcf9-1849-43ea-b1e4-efa3eeae9f71') - def test_create_security_group_rule_with_additional_args(self): - """Verify security group rule with additional arguments works. - - direction:ingress, ethertype:[IPv4/IPv6], - protocol:tcp, port_range_min:77, port_range_max:77 - """ - group_create_body, _ = self._create_security_group() - sg_id = group_create_body['security_group']['id'] - direction = 'ingress' - protocol = 'tcp' - port_range_min = 77 - port_range_max = 77 - self._create_verify_security_group_rule(sg_id, direction, - self.ethertype, protocol, - port_range_min, - port_range_max) - - @decorators.idempotent_id('c9463db8-b44d-4f52-b6c0-8dbda99f26ce') - def test_create_security_group_rule_with_icmp_type_code(self): - """Verify security group rule for icmp protocol works. - - Specify icmp type (port_range_min) and icmp code - (port_range_max) with different values. A separate testcase - is added for icmp protocol as icmp validation would be - different from tcp/udp. - """ - group_create_body, _ = self._create_security_group() - - sg_id = group_create_body['security_group']['id'] - direction = 'ingress' - protocol = 'icmp' - icmp_type_codes = [(3, 2), (3, 0), (8, 0), (0, 0), (11, None)] - for icmp_type, icmp_code in icmp_type_codes: - self._create_verify_security_group_rule(sg_id, direction, - self.ethertype, protocol, - icmp_type, icmp_code) - - @decorators.idempotent_id('c2ed2deb-7a0c-44d8-8b4c-a5825b5c310b') - def test_create_security_group_rule_with_remote_group_id(self): - # Verify creating security group rule with remote_group_id works - sg1_body, _ = self._create_security_group() - sg2_body, _ = self._create_security_group() - - sg_id = sg1_body['security_group']['id'] - direction = 'ingress' - protocol = 'udp' - port_range_min = 50 - port_range_max = 55 - remote_id = sg2_body['security_group']['id'] - self._create_verify_security_group_rule(sg_id, direction, - self.ethertype, protocol, - port_range_min, - port_range_max, - remote_group_id=remote_id) - - @decorators.idempotent_id('16459776-5da2-4634-bce4-4b55ee3ec188') - def test_create_security_group_rule_with_remote_ip_prefix(self): - # Verify creating security group rule with remote_ip_prefix works - sg1_body, _ = self._create_security_group() - - sg_id = sg1_body['security_group']['id'] - direction = 'ingress' - protocol = 'tcp' - port_range_min = 76 - port_range_max = 77 - ip_prefix = self._project_network_cidr - self._create_verify_security_group_rule(sg_id, direction, - self.ethertype, protocol, - port_range_min, - port_range_max, - remote_ip_prefix=ip_prefix) - - @decorators.idempotent_id('0a307599-6655-4220-bebc-fd70c64f2290') - def test_create_security_group_rule_with_protocol_integer_value(self): - # Verify creating security group rule with the - # protocol as integer value - # arguments : "protocol": 17 - group_create_body, _ = self._create_security_group() - direction = 'ingress' - protocol = 17 - security_group_id = group_create_body['security_group']['id'] - client = self.security_group_rules_client - rule_create_body = client.create_security_group_rule( - security_group_id=security_group_id, - direction=direction, - protocol=protocol - ) - sec_group_rule = rule_create_body['security_group_rule'] - self.assertEqual(sec_group_rule['direction'], direction) - self.assertEqual(int(sec_group_rule['protocol']), protocol) - - -class SecGroupIPv6Test(SecGroupTest): - _ip_version = 6 - _project_network_cidr = CONF.network.project_network_v6_cidr diff --git a/tempest/api/network/test_security_groups_negative.py b/tempest/api/network/test_security_groups_negative.py deleted file mode 100644 index f51fb3302..000000000 --- a/tempest/api/network/test_security_groups_negative.py +++ /dev/null @@ -1,248 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 tempest.api.network import base_security_groups as base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class NegativeSecGroupTest(base.BaseSecGroupTest): - _project_network_cidr = CONF.network.project_network_cidr - - @classmethod - def skip_checks(cls): - super(NegativeSecGroupTest, cls).skip_checks() - if not test.is_extension_enabled('security-group', 'network'): - msg = "security-group extension not enabled." - raise cls.skipException(msg) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('424fd5c3-9ddc-486a-b45f-39bf0c820fc6') - def test_show_non_existent_security_group(self): - non_exist_id = data_utils.rand_uuid() - self.assertRaises( - lib_exc.NotFound, self.security_groups_client.show_security_group, - non_exist_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('4c094c09-000b-4e41-8100-9617600c02a6') - def test_show_non_existent_security_group_rule(self): - non_exist_id = data_utils.rand_uuid() - self.assertRaises( - lib_exc.NotFound, - self.security_group_rules_client.show_security_group_rule, - non_exist_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1f1bb89d-5664-4956-9fcd-83ee0fa603df') - def test_delete_non_existent_security_group(self): - non_exist_id = data_utils.rand_uuid() - self.assertRaises(lib_exc.NotFound, - self.security_groups_client.delete_security_group, - non_exist_id - ) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('981bdc22-ce48-41ed-900a-73148b583958') - def test_create_security_group_rule_with_bad_protocol(self): - group_create_body, _ = self._create_security_group() - - # Create rule with bad protocol name - pname = 'bad_protocol_name' - self.assertRaises( - lib_exc.BadRequest, - self.security_group_rules_client.create_security_group_rule, - security_group_id=group_create_body['security_group']['id'], - protocol=pname, direction='ingress', ethertype=self.ethertype) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5f8daf69-3c5f-4aaa-88c9-db1d66f68679') - def test_create_security_group_rule_with_bad_remote_ip_prefix(self): - group_create_body, _ = self._create_security_group() - - # Create rule with bad remote_ip_prefix - prefix = ['192.168.1./24', '192.168.1.1/33', 'bad_prefix', '256'] - for remote_ip_prefix in prefix: - self.assertRaises( - lib_exc.BadRequest, - self.security_group_rules_client.create_security_group_rule, - security_group_id=group_create_body['security_group']['id'], - protocol='tcp', direction='ingress', ethertype=self.ethertype, - remote_ip_prefix=remote_ip_prefix) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('4bf786fd-2f02-443c-9716-5b98e159a49a') - def test_create_security_group_rule_with_non_existent_remote_groupid(self): - group_create_body, _ = self._create_security_group() - non_exist_id = data_utils.rand_uuid() - - # Create rule with non existent remote_group_id - group_ids = ['bad_group_id', non_exist_id] - for remote_group_id in group_ids: - self.assertRaises( - lib_exc.NotFound, - self.security_group_rules_client.create_security_group_rule, - security_group_id=group_create_body['security_group']['id'], - protocol='tcp', direction='ingress', ethertype=self.ethertype, - remote_group_id=remote_group_id) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('b5c4b247-6b02-435b-b088-d10d45650881') - def test_create_security_group_rule_with_remote_ip_and_group(self): - sg1_body, _ = self._create_security_group() - sg2_body, _ = self._create_security_group() - - # Create rule specifying both remote_ip_prefix and remote_group_id - prefix = self._project_network_cidr - self.assertRaises( - lib_exc.BadRequest, - self.security_group_rules_client.create_security_group_rule, - security_group_id=sg1_body['security_group']['id'], - protocol='tcp', direction='ingress', - ethertype=self.ethertype, remote_ip_prefix=prefix, - remote_group_id=sg2_body['security_group']['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5666968c-fff3-40d6-9efc-df1c8bd01abb') - def test_create_security_group_rule_with_bad_ethertype(self): - group_create_body, _ = self._create_security_group() - - # Create rule with bad ethertype - ethertype = 'bad_ethertype' - self.assertRaises( - lib_exc.BadRequest, - self.security_group_rules_client.create_security_group_rule, - security_group_id=group_create_body['security_group']['id'], - protocol='udp', direction='ingress', ethertype=ethertype) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0d9c7791-f2ad-4e2f-ac73-abf2373b0d2d') - def test_create_security_group_rule_with_invalid_ports(self): - group_create_body, _ = self._create_security_group() - - # Create rule for tcp protocol with invalid ports - states = [(-16, 80, 'Invalid value for port -16'), - (80, 79, 'port_range_min must be <= port_range_max'), - (80, 65536, 'Invalid value for port 65536'), - (None, 6, 'port_range_min must be <= port_range_max'), - (-16, 65536, 'Invalid value for port')] - for pmin, pmax, msg in states: - ex = self.assertRaises( - lib_exc.BadRequest, - self.security_group_rules_client.create_security_group_rule, - security_group_id=group_create_body['security_group']['id'], - protocol='tcp', port_range_min=pmin, port_range_max=pmax, - direction='ingress', ethertype=self.ethertype) - self.assertIn(msg, str(ex)) - - # Create rule for icmp protocol with invalid ports - states = [(1, 256, 'Invalid value for ICMP code'), - (-1, 25, 'Invalid value'), - (None, 6, 'ICMP type (port-range-min) is missing'), - (300, 1, 'Invalid value for ICMP type')] - for pmin, pmax, msg in states: - ex = self.assertRaises( - lib_exc.BadRequest, - self.security_group_rules_client.create_security_group_rule, - security_group_id=group_create_body['security_group']['id'], - protocol='icmp', port_range_min=pmin, port_range_max=pmax, - direction='ingress', ethertype=self.ethertype) - self.assertIn(msg, str(ex)) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('2323061e-9fbf-4eb0-b547-7e8fafc90849') - def test_create_additional_default_security_group_fails(self): - # Create security group named 'default', it should be failed. - name = 'default' - self.assertRaises(lib_exc.Conflict, - self.security_groups_client.create_security_group, - name=name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('966e2b96-023a-11e7-a9e4-fa163e4fa634') - def test_create_security_group_update_name_default(self): - # Update security group name to 'default', it should be failed. - group_create_body, _ = self._create_security_group() - self.assertRaises(lib_exc.Conflict, - self.security_groups_client.update_security_group, - group_create_body['security_group']['id'], - name="default") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('8fde898f-ce88-493b-adc9-4e4692879fc5') - def test_create_duplicate_security_group_rule_fails(self): - # Create duplicate security group rule, it should fail. - body, _ = self._create_security_group() - - min_port = 66 - max_port = 67 - # Create a rule with valid params - self.security_group_rules_client.create_security_group_rule( - security_group_id=body['security_group']['id'], - direction='ingress', - ethertype=self.ethertype, - protocol='tcp', - port_range_min=min_port, - port_range_max=max_port - ) - - # Try creating the same security group rule, it should fail - self.assertRaises( - lib_exc.Conflict, - self.security_group_rules_client.create_security_group_rule, - security_group_id=body['security_group']['id'], - protocol='tcp', direction='ingress', ethertype=self.ethertype, - port_range_min=min_port, port_range_max=max_port) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('be308db6-a7cf-4d5c-9baf-71bafd73f35e') - def test_create_security_group_rule_with_non_existent_security_group(self): - # Create security group rules with not existing security group. - non_existent_sg = data_utils.rand_uuid() - self.assertRaises( - lib_exc.NotFound, - self.security_group_rules_client.create_security_group_rule, - security_group_id=non_existent_sg, - direction='ingress', ethertype=self.ethertype) - - -class NegativeSecGroupIPv6Test(NegativeSecGroupTest): - _ip_version = 6 - _project_network_cidr = CONF.network.project_network_v6_cidr - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7607439c-af73-499e-bf64-f687fd12a842') - def test_create_security_group_rule_wrong_ip_prefix_version(self): - group_create_body, _ = self._create_security_group() - - # Create rule with bad remote_ip_prefix - pairs = ({'ethertype': 'IPv6', - 'ip_prefix': CONF.network.project_network_cidr}, - {'ethertype': 'IPv4', - 'ip_prefix': CONF.network.project_network_v6_cidr}) - for pair in pairs: - self.assertRaisesRegex( - lib_exc.BadRequest, - "Conflicting value ethertype", - self.security_group_rules_client.create_security_group_rule, - security_group_id=group_create_body['security_group']['id'], - protocol='tcp', direction='ingress', - ethertype=pair['ethertype'], - remote_ip_prefix=pair['ip_prefix']) diff --git a/tempest/api/network/test_service_providers.py b/tempest/api/network/test_service_providers.py deleted file mode 100644 index b90c81b7f..000000000 --- a/tempest/api/network/test_service_providers.py +++ /dev/null @@ -1,29 +0,0 @@ -# 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 testtools - -from tempest.api.network import base -from tempest.lib import decorators -from tempest import test - - -class ServiceProvidersTest(base.BaseNetworkTest): - - @decorators.idempotent_id('2cbbeea9-f010-40f6-8df5-4eaa0c918ea6') - @testtools.skipUnless( - test.is_extension_enabled('service-type', 'network'), - 'service-type extension not enabled.') - def test_service_providers_list(self): - body = self.service_providers_client.list_service_providers() - self.assertIn('service_providers', body) - self.assertIsInstance(body['service_providers'], list) diff --git a/tempest/api/network/test_subnetpools_extensions.py b/tempest/api/network/test_subnetpools_extensions.py deleted file mode 100644 index 01d7db254..000000000 --- a/tempest/api/network/test_subnetpools_extensions.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2015 GlobalLogic. 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 tempest.api.network import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class SubnetPoolsTestJSON(base.BaseNetworkTest): - """Tests the following operations in the subnetpools API: - - Create a subnet pool. - Update a subnet pool. - Delete a subnet pool. - Lists subnet pool. - Show subnet pool details. - - v2.0 of the Neutron API is assumed. It is assumed that subnet_allocation - options mentioned in the [network-feature-enabled] section and - default_network option mentioned in the [network] section of - etc/tempest.conf: - - """ - - @classmethod - def skip_checks(cls): - super(SubnetPoolsTestJSON, cls).skip_checks() - if not test.is_extension_enabled('subnet_allocation', 'network'): - msg = "subnet_allocation extension not enabled." - raise cls.skipException(msg) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('62595970-ab1c-4b7f-8fcc-fddfe55e9811') - def test_create_list_show_update_delete_subnetpools(self): - subnetpool_name = data_utils.rand_name('subnetpools') - # create subnet pool - prefix = CONF.network.default_network - body = self.subnetpools_client.create_subnetpool(name=subnetpool_name, - prefixes=prefix) - subnetpool_id = body["subnetpool"]["id"] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.subnetpools_client.delete_subnetpool, - subnetpool_id) - self.assertEqual(subnetpool_name, body["subnetpool"]["name"]) - # get detail about subnet pool - body = self.subnetpools_client.show_subnetpool(subnetpool_id) - self.assertEqual(subnetpool_name, body["subnetpool"]["name"]) - # update the subnet pool - subnetpool_name = data_utils.rand_name('subnetpools_update') - body = self.subnetpools_client.update_subnetpool(subnetpool_id, - name=subnetpool_name) - self.assertEqual(subnetpool_name, body["subnetpool"]["name"]) - # delete subnet pool - body = self.subnetpools_client.delete_subnetpool(subnetpool_id) - self.assertRaises(lib_exc.NotFound, - self.subnetpools_client.show_subnetpool, - subnetpool_id) diff --git a/tempest/api/network/test_tags.py b/tempest/api/network/test_tags.py deleted file mode 100644 index 567a4621f..000000000 --- a/tempest/api/network/test_tags.py +++ /dev/null @@ -1,202 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 tempest.api.network import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class TagsTest(base.BaseNetworkTest): - """Tests the following operations in the tags API: - - Update all tags. - Delete all tags. - Check tag existence. - Create a tag. - List tags. - Remove a tag. - - v2.0 of the Neutron API is assumed. The tag extension allows users to set - tags on their networks. The extension supports networks only. - """ - - @classmethod - def skip_checks(cls): - super(TagsTest, cls).skip_checks() - if not test.is_extension_enabled('tag', 'network'): - msg = "tag extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(TagsTest, cls).resource_setup() - cls.network = cls.create_network() - - @decorators.idempotent_id('ee76bfaf-ac94-4d74-9ecc-4bbd4c583cb1') - def test_create_list_show_update_delete_tags(self): - # Validate that creating a tag on a network resource works. - tag_name = data_utils.rand_name(self.__class__.__name__ + '-Tag') - self.tags_client.create_tag('networks', self.network['id'], tag_name) - self.addCleanup(self.tags_client.delete_all_tags, 'networks', - self.network['id']) - self.tags_client.check_tag_existence('networks', self.network['id'], - tag_name) - - # Validate that listing tags on a network resource works. - retrieved_tags = self.tags_client.list_tags( - 'networks', self.network['id'])['tags'] - self.assertEqual([tag_name], retrieved_tags) - - # Generate 3 new tag names. - replace_tags = [data_utils.rand_name( - self.__class__.__name__ + '-Tag') for _ in range(3)] - - # Replace the current tag with the 3 new tags and validate that the - # network resource has the 3 new tags. - updated_tags = self.tags_client.update_all_tags( - 'networks', self.network['id'], replace_tags)['tags'] - self.assertEqual(3, len(updated_tags)) - self.assertEqual(set(replace_tags), set(updated_tags)) - - # Delete the first tag and check that it has been removed. - self.tags_client.delete_tag( - 'networks', self.network['id'], replace_tags[0]) - self.assertRaises(lib_exc.NotFound, - self.tags_client.check_tag_existence, 'networks', - self.network['id'], replace_tags[0]) - for i in range(1, 3): - self.tags_client.check_tag_existence( - 'networks', self.network['id'], replace_tags[i]) - - # Delete all the remaining tags and check that they have been removed. - self.tags_client.delete_all_tags('networks', self.network['id']) - for i in range(1, 3): - self.assertRaises(lib_exc.NotFound, - self.tags_client.check_tag_existence, 'networks', - self.network['id'], replace_tags[i]) - - -class TagsExtTest(base.BaseNetworkTest): - """Tests the following operations in the tags API: - - Update all tags. - Delete all tags. - Check tag existence. - Create a tag. - List tags. - Remove a tag. - - v2.0 of the Neutron API is assumed. The tag-ext extension allows users to - set tags on the following resources: subnets, ports, routers and - subnetpools. - """ - - # NOTE(felipemonteiro): The supported resource names are plural. Use - # the singular case for the corresponding class resource object. - SUPPORTED_RESOURCES = ['subnets', 'ports', 'routers', 'subnetpools'] - - @classmethod - def skip_checks(cls): - super(TagsExtTest, cls).skip_checks() - if not test.is_extension_enabled('tag-ext', 'network'): - msg = "tag-ext extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(TagsExtTest, cls).resource_setup() - cls.network = cls.create_network() - cls.subnet = cls.create_subnet(cls.network) - cls.port = cls.create_port(cls.network) - cls.router = cls.create_router() - - subnetpool_name = data_utils.rand_name(cls.__name__ + '-Subnetpool') - prefix = CONF.network.default_network - cls.subnetpool = cls.subnetpools_client.create_subnetpool( - name=subnetpool_name, prefixes=prefix)['subnetpool'] - - @classmethod - def resource_cleanup(cls): - cls.subnetpools_client.delete_subnetpool(cls.subnetpool['id']) - super(TagsExtTest, cls).resource_cleanup() - - def _create_tags_for_each_resource(self): - # Create a tag for each resource in `SUPPORTED_RESOURCES` and return - # the list of tag names. - tag_names = [] - - for resource in self.SUPPORTED_RESOURCES: - tag_name = data_utils.rand_name(self.__class__.__name__ + '-Tag') - tag_names.append(tag_name) - resource_object = getattr(self, resource[:-1]) - - self.tags_client.create_tag(resource, resource_object['id'], - tag_name) - self.addCleanup(self.tags_client.delete_all_tags, resource, - resource_object['id']) - - return tag_names - - @decorators.idempotent_id('c6231efa-9a89-4adf-b050-2a3156b8a1d9') - def test_create_check_list_and_delete_tags(self): - tag_names = self._create_tags_for_each_resource() - - for i, resource in enumerate(self.SUPPORTED_RESOURCES): - # Ensure that a tag was created for each resource. - resource_object = getattr(self, resource[:-1]) - retrieved_tags = self.tags_client.list_tags( - resource, resource_object['id'])['tags'] - self.assertEqual(1, len(retrieved_tags)) - self.assertEqual(tag_names[i], retrieved_tags[0]) - - # Check that the expected tag exists for each resource. - self.tags_client.check_tag_existence( - resource, resource_object['id'], tag_names[i]) - - # Delete the tag and ensure it was deleted. - self.tags_client.delete_tag( - resource, resource_object['id'], tag_names[i]) - retrieved_tags = self.tags_client.list_tags( - resource, resource_object['id'])['tags'] - self.assertEmpty(retrieved_tags) - - @decorators.idempotent_id('663a90f5-f334-4b44-afe0-c5fc1d408791') - def test_update_and_delete_all_tags(self): - self._create_tags_for_each_resource() - - for resource in self.SUPPORTED_RESOURCES: - # Generate 3 new tag names. - replace_tags = [data_utils.rand_name( - self.__class__.__name__ + '-Tag') for _ in range(3)] - - # Replace the current tag with the 3 new tags and validate that the - # current resource has the 3 new tags. - resource_object = getattr(self, resource[:-1]) - updated_tags = self.tags_client.update_all_tags( - resource, resource_object['id'], replace_tags)['tags'] - self.assertEqual(3, len(updated_tags)) - self.assertEqual(set(replace_tags), set(updated_tags)) - - # Delete all the tags and check that they have been removed. - self.tags_client.delete_all_tags(resource, resource_object['id']) - for i in range(3): - self.assertRaises( - lib_exc.NotFound, self.tags_client.check_tag_existence, - resource, resource_object['id'], replace_tags[i]) diff --git a/tempest/api/network/test_versions.py b/tempest/api/network/test_versions.py deleted file mode 100644 index 2f01e5040..000000000 --- a/tempest/api/network/test_versions.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2016 VMware, Inc. -# -# 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 tempest.api.network import base -from tempest.lib import decorators - - -class NetworksApiDiscovery(base.BaseNetworkTest): - @decorators.attr(type='smoke') - @decorators.idempotent_id('cac8a836-c2e0-4304-b556-cd299c7281d1') - def test_api_version_resources(self): - """Test that GET / returns expected resources. - - The versions document returned by Neutron returns a few other - resources other than just available API versions: it also - states the status of each API version and provides links to - schema. - """ - - result = self.network_versions_client.list_versions() - expected_versions = ('v2.0') - expected_resources = ('id', 'links', 'status') - received_list = result.values() - - for item in received_list: - for version in item: - for resource in expected_resources: - self.assertIn(resource, version) - self.assertIn(version['id'], expected_versions) diff --git a/tempest/api/object_storage/__init__.py b/tempest/api/object_storage/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py deleted file mode 100644 index 11273e459..000000000 --- a/tempest/api/object_storage/base.py +++ /dev/null @@ -1,145 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 time - -from tempest.common import custom_matchers -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import exceptions as lib_exc -import tempest.test - -CONF = config.CONF - - -def delete_containers(containers, container_client, object_client): - """Remove containers and all objects in them. - - The containers should be visible from the container_client given. - Will not throw any error if the containers don't exist. - Will not check that object and container deletions succeed. - After delete all the objects from a container, it will wait 2 - seconds before delete the container itself, in order to deployments - using HA proxy sync the deletion properly, otherwise, the container - might fail to be deleted because it's not empty. - - :param containers: List of containers to be deleted - :param container_client: Client to be used to delete containers - :param object_client: Client to be used to delete objects - """ - for cont in containers: - try: - params = {'limit': 9999, 'format': 'json'} - _, objlist = container_client.list_container_contents(cont, params) - # delete every object in the container - for obj in objlist: - test_utils.call_and_ignore_notfound_exc( - object_client.delete_object, cont, obj['name']) - # sleep 2 seconds to sync the deletion of the objects - # in HA deployment - time.sleep(2) - container_client.delete_container(cont) - except lib_exc.NotFound: - pass - - -class BaseObjectTest(tempest.test.BaseTestCase): - - credentials = [['operator', CONF.object_storage.operator_role]] - - @classmethod - def skip_checks(cls): - super(BaseObjectTest, cls).skip_checks() - if not CONF.service_available.swift: - skip_msg = ("%s skipped as swift is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_credentials(cls): - cls.set_network_resources() - super(BaseObjectTest, cls).setup_credentials() - # credentials may be overwritten by children classes - if hasattr(cls, 'os_roles_operator'): - cls.os = cls.os_roles_operator - - @classmethod - def setup_clients(cls): - super(BaseObjectTest, cls).setup_clients() - cls.object_client = cls.os_roles_operator.object_client - cls.bulk_client = cls.os_roles_operator.bulk_client - cls.container_client = cls.os_roles_operator.container_client - cls.account_client = cls.os_roles_operator.account_client - cls.capabilities_client = cls.os_roles_operator.capabilities_client - - @classmethod - def resource_setup(cls): - super(BaseObjectTest, cls).resource_setup() - - # Make sure we get fresh auth data after assigning swift role - cls.object_client.auth_provider.clear_auth() - cls.container_client.auth_provider.clear_auth() - cls.account_client.auth_provider.clear_auth() - - # make sure that discoverability is enabled and that the sections - # have not been disallowed by Swift - cls.policies = None - - if CONF.object_storage_feature_enabled.discoverability: - body = cls.capabilities_client.list_capabilities() - - if 'swift' in body and 'policies' in body['swift']: - cls.policies = body['swift']['policies'] - - cls.containers = [] - - @classmethod - def create_container(cls): - # wrapper that returns a test container - container_name = data_utils.rand_name(name='TestContainer') - cls.container_client.create_container(container_name) - cls.containers.append(container_name) - - return container_name - - @classmethod - def create_object(cls, container_name, object_name=None, - data=None, metadata=None): - # wrapper that returns a test object - if object_name is None: - object_name = data_utils.rand_name(name='TestObject') - if data is None: - data = data_utils.random_bytes() - cls.object_client.create_object(container_name, - object_name, - data, - metadata=metadata) - - return object_name, data - - @classmethod - def delete_containers(cls, container_client=None, object_client=None): - if container_client is None: - container_client = cls.container_client - if object_client is None: - object_client = cls.object_client - delete_containers(cls.containers, container_client, object_client) - - def assertHeaders(self, resp, target, method): - """Check the existence and the format of response headers""" - - self.assertThat(resp, custom_matchers.ExistsAllResponseHeaders( - target, method, self.policies)) - self.assertThat(resp, custom_matchers.AreAllWellFormatted()) diff --git a/tempest/api/object_storage/test_account_bulk.py b/tempest/api/object_storage/test_account_bulk.py deleted file mode 100644 index 7c538e8f3..000000000 --- a/tempest/api/object_storage/test_account_bulk.py +++ /dev/null @@ -1,155 +0,0 @@ -# Copyright 2013 NTT Corporation -# -# 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 tarfile -import tempfile - -from tempest.api.object_storage import base -from tempest.common import custom_matchers -from tempest.lib import decorators -from tempest import test - - -class BulkTest(base.BaseObjectTest): - - def setUp(self): - super(BulkTest, self).setUp() - self.containers = [] - - def tearDown(self): - # NOTE(andreaf) BulkTests needs to cleanup containers after each - # test is executed. - base.delete_containers(self.containers, self.container_client, - self.object_client) - super(BulkTest, self).tearDown() - - def _create_archive(self): - # Create an archived file for bulk upload testing. - # Directory and files contained in the directory correspond to - # container and subsidiary objects. - tmp_dir = tempfile.mkdtemp() - tmp_file = tempfile.mkstemp(dir=tmp_dir) - - # Extract a container name and an object name - container_name = tmp_dir.split("/")[-1] - object_name = tmp_file[1].split("/")[-1] - - # Create tar file - tarpath = tempfile.NamedTemporaryFile(suffix=".tar") - tar = tarfile.open(None, 'w', tarpath) - tar.add(tmp_dir, arcname=container_name) - tar.close() - tarpath.flush() - - return tarpath.name, container_name, object_name - - def _upload_archive(self, filepath): - # upload an archived file - with open(filepath) as fh: - mydata = fh.read() - resp = self.bulk_client.upload_archive( - upload_path='', data=mydata, archive_file_format='tar') - return resp - - def _check_contents_deleted(self, container_name): - param = {'format': 'txt'} - resp, body = self.account_client.list_account_containers(param) - self.assertHeaders(resp, 'Account', 'GET') - self.assertNotIn(container_name, body) - - @decorators.idempotent_id('a407de51-1983-47cc-9f14-47c2b059413c') - @test.requires_ext(extension='bulk_upload', service='object') - def test_extract_archive(self): - # Test bulk operation of file upload with an archived file - filepath, container_name, object_name = self._create_archive() - resp = self._upload_archive(filepath) - self.containers.append(container_name) - - # When uploading an archived file with the bulk operation, the response - # does not contain 'content-length' header. This is the special case, - # therefore the existence of response headers is checked without - # custom matcher. - self.assertIn('transfer-encoding', resp.response) - self.assertIn('content-type', resp.response) - self.assertIn('x-trans-id', resp.response) - self.assertIn('date', resp.response) - - # Check only the format of common headers with custom matcher - self.assertThat(resp.response, custom_matchers.AreAllWellFormatted()) - - param = {'format': 'json'} - resp, body = self.account_client.list_account_containers(param) - - self.assertHeaders(resp, 'Account', 'GET') - - self.assertIn(container_name, [b['name'] for b in body]) - - param = {'format': 'json'} - resp, contents_list = self.container_client.list_container_contents( - container_name, param) - - self.assertHeaders(resp, 'Container', 'GET') - - self.assertIn(object_name, [c['name'] for c in contents_list]) - - @decorators.idempotent_id('c075e682-0d2a-43b2-808d-4116200d736d') - @test.requires_ext(extension='bulk_delete', service='object') - def test_bulk_delete(self): - # Test bulk operation of deleting multiple files - filepath, container_name, object_name = self._create_archive() - self._upload_archive(filepath) - - data = '%s/%s\n%s' % (container_name, object_name, container_name) - resp = self.bulk_client.delete_bulk_data(data=data) - - # When deleting multiple files using the bulk operation, the response - # does not contain 'content-length' header. This is the special case, - # therefore the existence of response headers is checked without - # custom matcher. - self.assertIn('transfer-encoding', resp.response) - self.assertIn('content-type', resp.response) - self.assertIn('x-trans-id', resp.response) - self.assertIn('date', resp.response) - - # Check only the format of common headers with custom matcher - self.assertThat(resp.response, custom_matchers.AreAllWellFormatted()) - - # Check if uploaded contents are completely deleted - self._check_contents_deleted(container_name) - - @decorators.idempotent_id('dbea2bcb-efbb-4674-ac8a-a5a0e33d1d79') - @test.requires_ext(extension='bulk_delete', service='object') - def test_bulk_delete_by_POST(self): - # Test bulk operation of deleting multiple files - filepath, container_name, object_name = self._create_archive() - self._upload_archive(filepath) - - data = '%s/%s\n%s' % (container_name, object_name, container_name) - - resp = self.bulk_client.delete_bulk_data_with_post(data=data) - - # When deleting multiple files using the bulk operation, the response - # does not contain 'content-length' header. This is the special case, - # therefore the existence of response headers is checked without - # custom matcher. - self.assertIn('transfer-encoding', resp.response) - self.assertIn('content-type', resp.response) - self.assertIn('x-trans-id', resp.response) - self.assertIn('date', resp.response) - - # Check only the format of common headers with custom matcher - self.assertThat(resp.response, custom_matchers.AreAllWellFormatted()) - - # Check if uploaded contents are completely deleted - self._check_contents_deleted(container_name) diff --git a/tempest/api/object_storage/test_account_quotas.py b/tempest/api/object_storage/test_account_quotas.py deleted file mode 100644 index 092d36969..000000000 --- a/tempest/api/object_storage/test_account_quotas.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright (C) 2013 eNovance SAS -# -# 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 tempest.api.object_storage import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class AccountQuotasTest(base.BaseObjectTest): - - credentials = [['operator', CONF.object_storage.operator_role], - ['reseller', CONF.object_storage.reseller_admin_role]] - - @classmethod - def setup_credentials(cls): - super(AccountQuotasTest, cls).setup_credentials() - cls.os = cls.os_roles_operator - cls.os_reselleradmin = cls.os_roles_reseller - - @classmethod - def resource_setup(cls): - super(AccountQuotasTest, cls).resource_setup() - cls.container_name = cls.create_container() - - # Retrieve a ResellerAdmin auth data and use it to set a quota - # on the client's account - cls.reselleradmin_auth_data = \ - cls.os_reselleradmin.auth_provider.auth_data - - def setUp(self): - super(AccountQuotasTest, self).setUp() - - # Set the reselleradmin auth in headers for next account_client - # request - self.account_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.reselleradmin_auth_data - ) - # Set a quota of 20 bytes on the user's account before each test - headers = {"X-Account-Meta-Quota-Bytes": "20"} - - self.os_roles_operator.account_client.request( - "POST", url="", headers=headers, body="") - - def tearDown(self): - # Set the reselleradmin auth in headers for next account_client - # request - self.account_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.reselleradmin_auth_data - ) - # remove the quota from the container - headers = {"X-Remove-Account-Meta-Quota-Bytes": "x"} - - self.os_roles_operator.account_client.request( - "POST", url="", headers=headers, body="") - super(AccountQuotasTest, self).tearDown() - - @classmethod - def resource_cleanup(cls): - cls.delete_containers() - super(AccountQuotasTest, cls).resource_cleanup() - - @decorators.attr(type="smoke") - @decorators.idempotent_id('a22ef352-a342-4587-8f47-3bbdb5b039c4') - @test.requires_ext(extension='account_quotas', service='object') - def test_upload_valid_object(self): - object_name = data_utils.rand_name(name="TestObject") - data = data_utils.arbitrary_string() - resp, _ = self.object_client.create_object(self.container_name, - object_name, data) - - self.assertHeaders(resp, 'Object', 'PUT') - - @decorators.attr(type=["smoke"]) - @decorators.idempotent_id('63f51f9f-5f1d-4fc6-b5be-d454d70949d6') - @test.requires_ext(extension='account_quotas', service='object') - def test_admin_modify_quota(self): - """Test ResellerAdmin can modify/remove the quota on a user's account - - Using the account client, the test modifies the quota - successively to: - - * "25": a random value different from the initial quota value. - * "" : an empty value, equivalent to the removal of the quota. - * "20": set the quota to its initial value. - """ - for quota in ("25", "", "20"): - - self.account_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.reselleradmin_auth_data - ) - headers = {"X-Account-Meta-Quota-Bytes": quota} - - resp, _ = self.os_roles_operator.account_client.request( - "POST", url="", headers=headers, body="") - - self.assertEqual(resp["status"], "204") - self.assertHeaders(resp, 'Account', 'POST') diff --git a/tempest/api/object_storage/test_account_quotas_negative.py b/tempest/api/object_storage/test_account_quotas_negative.py deleted file mode 100644 index 55a6c7ad4..000000000 --- a/tempest/api/object_storage/test_account_quotas_negative.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright (C) 2013 eNovance SAS -# -# 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 tempest.api.object_storage import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class AccountQuotasNegativeTest(base.BaseObjectTest): - - credentials = [['operator', CONF.object_storage.operator_role], - ['reseller', CONF.object_storage.reseller_admin_role]] - - @classmethod - def setup_credentials(cls): - super(AccountQuotasNegativeTest, cls).setup_credentials() - cls.os = cls.os_roles_operator - cls.os_reselleradmin = cls.os_roles_reseller - - @classmethod - def resource_setup(cls): - super(AccountQuotasNegativeTest, cls).resource_setup() - cls.container_name = cls.create_container() - - # Retrieve a ResellerAdmin auth data and use it to set a quota - # on the client's account - cls.reselleradmin_auth_data = \ - cls.os_reselleradmin.auth_provider.auth_data - - def setUp(self): - super(AccountQuotasNegativeTest, self).setUp() - # Set the reselleradmin auth in headers for next account_client - # request - self.account_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.reselleradmin_auth_data - ) - # Set a quota of 20 bytes on the user's account before each test - headers = {"X-Account-Meta-Quota-Bytes": "20"} - - self.os_roles_operator.account_client.request( - "POST", url="", headers=headers, body="") - - def tearDown(self): - # Set the reselleradmin auth in headers for next account_client - # request - self.account_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.reselleradmin_auth_data - ) - # remove the quota from the container - headers = {"X-Remove-Account-Meta-Quota-Bytes": "x"} - - self.os_roles_operator.account_client.request( - "POST", url="", headers=headers, body="") - super(AccountQuotasNegativeTest, self).tearDown() - - @classmethod - def resource_cleanup(cls): - cls.delete_containers() - super(AccountQuotasNegativeTest, cls).resource_cleanup() - - @decorators.attr(type=["negative"]) - @decorators.idempotent_id('d1dc5076-555e-4e6d-9697-28f1fe976324') - @test.requires_ext(extension='account_quotas', service='object') - def test_user_modify_quota(self): - """Test that a user cannot modify or remove a quota on its account.""" - - # Not able to remove quota - self.assertRaises( - lib_exc.Forbidden, - self.account_client.create_update_or_delete_account_metadata, - create_update_metadata={"Quota-Bytes": ""}) - - # Not able to modify quota - self.assertRaises( - lib_exc.Forbidden, - self.account_client.create_update_or_delete_account_metadata, - create_update_metadata={"Quota-Bytes": "100"}) diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py deleted file mode 100644 index 2fb676fe3..000000000 --- a/tempest/api/object_storage/test_account_services.py +++ /dev/null @@ -1,368 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 random - -import six -import testtools - -from tempest.api.object_storage import base -from tempest.common import custom_matchers -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class AccountTest(base.BaseObjectTest): - - credentials = [['operator', CONF.object_storage.operator_role], - ['operator_alt', CONF.object_storage.operator_role]] - containers = [] - - @classmethod - def setup_credentials(cls): - super(AccountTest, cls).setup_credentials() - cls.os = cls.os_roles_operator - cls.os_operator = cls.os_roles_operator_alt - - @classmethod - def resource_setup(cls): - super(AccountTest, cls).resource_setup() - for i in range(ord('a'), ord('f') + 1): - name = data_utils.rand_name(name='%s-' % chr(i)) - cls.container_client.create_container(name) - cls.containers.append(name) - cls.containers_count = len(cls.containers) - - @classmethod - def resource_cleanup(cls): - cls.delete_containers() - super(AccountTest, cls).resource_cleanup() - - @decorators.attr(type='smoke') - @decorators.idempotent_id('3499406a-ae53-4f8c-b43a-133d4dc6fe3f') - def test_list_containers(self): - # list of all containers should not be empty - resp, container_list = self.account_client.list_account_containers() - self.assertHeaders(resp, 'Account', 'GET') - - self.assertIsNotNone(container_list) - - for container_name in self.containers: - self.assertIn(six.text_type(container_name).encode('utf-8'), - container_list) - - @decorators.idempotent_id('884ec421-fbad-4fcc-916b-0580f2699565') - def test_list_no_containers(self): - # List request to empty account - - # To test listing no containers, create new user other than - # the base user of this instance. - - resp, container_list = \ - self.os_operator.account_client.list_account_containers() - - # When sending a request to an account which has not received a PUT - # container request, the response does not contain 'accept-ranges' - # header. This is a special case, therefore the existence of response - # headers is checked without custom matcher. - # - # As the expected response is 204 No Content, Content-Length presence - # is not checked here intentionally. According to RFC 7230 a server - # MUST NOT send the header in such responses. Thus, clients should not - # depend on this header. However, the standard does not require them - # to validate the server's behavior. We leverage that to not refuse - # any implementation violating it like Swift [1] or some versions of - # Ceph RadosGW [2]. - # [1] https://bugs.launchpad.net/swift/+bug/1537811 - # [2] http://tracker.ceph.com/issues/13582 - self.assertIn('x-timestamp', resp) - self.assertIn('x-account-bytes-used', resp) - self.assertIn('x-account-container-count', resp) - self.assertIn('x-account-object-count', resp) - self.assertIn('content-type', resp) - self.assertIn('x-trans-id', resp) - self.assertIn('date', resp) - - # Check only the format of common headers with custom matcher - self.assertThat(resp, custom_matchers.AreAllWellFormatted()) - - self.assertEmpty(container_list) - - @decorators.idempotent_id('1c7efa35-e8a2-4b0b-b5ff-862c7fd83704') - def test_list_containers_with_format_json(self): - # list containers setting format parameter to 'json' - params = {'format': 'json'} - resp, container_list = self.account_client.list_account_containers( - params=params) - self.assertHeaders(resp, 'Account', 'GET') - self.assertIsNotNone(container_list) - self.assertTrue([c['name'] for c in container_list]) - self.assertTrue([c['count'] for c in container_list]) - self.assertTrue([c['bytes'] for c in container_list]) - - @decorators.idempotent_id('4477b609-1ca6-4d4b-b25d-ad3f01086089') - def test_list_containers_with_format_xml(self): - # list containers setting format parameter to 'xml' - params = {'format': 'xml'} - resp, container_list = self.account_client.list_account_containers( - params=params) - self.assertHeaders(resp, 'Account', 'GET') - self.assertIsNotNone(container_list) - self.assertEqual(container_list.tag, 'account') - self.assertIn('name', container_list.keys()) - self.assertEqual(container_list.find(".//container").tag, 'container') - self.assertEqual(container_list.find(".//name").tag, 'name') - self.assertEqual(container_list.find(".//count").tag, 'count') - self.assertEqual(container_list.find(".//bytes").tag, 'bytes') - - @decorators.idempotent_id('6eb04a6a-4860-4e31-ba91-ea3347d76b58') - @testtools.skipIf( - not CONF.object_storage_feature_enabled.discoverability, - 'Discoverability function is disabled') - def test_list_extensions(self): - resp = self.capabilities_client.list_capabilities() - - self.assertThat(resp, custom_matchers.AreAllWellFormatted()) - - @decorators.idempotent_id('5cfa4ab2-4373-48dd-a41f-a532b12b08b2') - def test_list_containers_with_limit(self): - # list containers one of them, half of them then all of them - for limit in (1, self.containers_count // 2, - self.containers_count): - params = {'limit': limit} - resp, container_list = \ - self.account_client.list_account_containers(params=params) - self.assertHeaders(resp, 'Account', 'GET') - - self.assertEqual(len(container_list), limit) - - @decorators.idempotent_id('638f876d-6a43-482a-bbb3-0840bca101c6') - def test_list_containers_with_marker(self): - # list containers using marker param - # first expect to get 0 container as we specified last - # the container as marker - # second expect to get the bottom half of the containers - params = {'marker': self.containers[-1]} - resp, container_list = \ - self.account_client.list_account_containers(params=params) - self.assertHeaders(resp, 'Account', 'GET') - - self.assertEmpty(container_list) - - params = {'marker': self.containers[self.containers_count // 2]} - resp, container_list = \ - self.account_client.list_account_containers(params=params) - self.assertHeaders(resp, 'Account', 'GET') - - self.assertEqual(len(container_list), - self.containers_count // 2 - 1) - - @decorators.idempotent_id('5ca164e4-7bde-43fa-bafb-913b53b9e786') - def test_list_containers_with_end_marker(self): - # list containers using end_marker param - # first expect to get 0 container as we specified first container as - # end_marker - # second expect to get the top half of the containers - params = {'end_marker': self.containers[0]} - resp, container_list = \ - self.account_client.list_account_containers(params=params) - self.assertHeaders(resp, 'Account', 'GET') - self.assertEmpty(container_list) - - params = {'end_marker': self.containers[self.containers_count // 2]} - resp, container_list = \ - self.account_client.list_account_containers(params=params) - self.assertHeaders(resp, 'Account', 'GET') - self.assertEqual(len(container_list), self.containers_count // 2) - - @decorators.idempotent_id('ac8502c2-d4e4-4f68-85a6-40befea2ef5e') - def test_list_containers_with_marker_and_end_marker(self): - # list containers combining marker and end_marker param - params = {'marker': self.containers[0], - 'end_marker': self.containers[self.containers_count - 1]} - resp, container_list = self.account_client.list_account_containers( - params=params) - self.assertHeaders(resp, 'Account', 'GET') - self.assertEqual(len(container_list), self.containers_count - 2) - - @decorators.idempotent_id('f7064ae8-dbcc-48da-b594-82feef6ea5af') - def test_list_containers_with_limit_and_marker(self): - # list containers combining marker and limit param - # result are always limitated by the limit whatever the marker - for marker in random.choice(self.containers): - limit = random.randint(0, self.containers_count - 1) - params = {'marker': marker, - 'limit': limit} - resp, container_list = \ - self.account_client.list_account_containers(params=params) - self.assertHeaders(resp, 'Account', 'GET') - - self.assertLessEqual(len(container_list), limit, - str(container_list)) - - @decorators.idempotent_id('888a3f0e-7214-4806-8e50-5e0c9a69bb5e') - def test_list_containers_with_limit_and_end_marker(self): - # list containers combining limit and end_marker param - limit = random.randint(1, self.containers_count) - params = {'limit': limit, - 'end_marker': self.containers[self.containers_count // 2]} - resp, container_list = self.account_client.list_account_containers( - params=params) - self.assertHeaders(resp, 'Account', 'GET') - self.assertEqual(len(container_list), - min(limit, self.containers_count // 2)) - - @decorators.idempotent_id('8cf98d9c-e3a0-4e44-971b-c87656fdddbd') - def test_list_containers_with_limit_and_marker_and_end_marker(self): - # list containers combining limit, marker and end_marker param - limit = random.randint(1, self.containers_count) - params = {'limit': limit, - 'marker': self.containers[0], - 'end_marker': self.containers[self.containers_count - 1]} - resp, container_list = self.account_client.list_account_containers( - params=params) - self.assertHeaders(resp, 'Account', 'GET') - self.assertEqual(len(container_list), - min(limit, self.containers_count - 2)) - - @decorators.idempotent_id('365e6fc7-1cfe-463b-a37c-8bd08d47b6aa') - def test_list_containers_with_prefix(self): - # list containers that have a name that starts with a prefix - prefix = '{0}-a'.format(CONF.resources_prefix) - params = {'prefix': prefix} - resp, container_list = self.account_client.list_account_containers( - params=params) - self.assertHeaders(resp, 'Account', 'GET') - for container in container_list: - self.assertEqual(True, container.decode( - 'utf-8').startswith(prefix)) - - @decorators.idempotent_id('b1811cff-d1ed-4c15-a52e-efd8de41cf34') - def test_list_containers_reverse_order(self): - # list containers in reverse order - _, orig_container_list = self.account_client.list_account_containers() - - params = {'reverse': True} - resp, container_list = self.account_client.list_account_containers( - params=params) - self.assertHeaders(resp, 'Account', 'GET') - self.assertEqual(sorted(orig_container_list, reverse=True), - container_list) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('4894c312-6056-4587-8d6f-86ffbf861f80') - def test_list_account_metadata(self): - # list all account metadata - - # set metadata to account - metadata = {'test-account-meta1': 'Meta1', - 'test-account-meta2': 'Meta2'} - resp, _ = self.account_client.create_update_or_delete_account_metadata( - create_update_metadata=metadata) - - resp, _ = self.account_client.list_account_metadata() - self.assertHeaders(resp, 'Account', 'HEAD') - self.assertIn('x-account-meta-test-account-meta1', resp) - self.assertIn('x-account-meta-test-account-meta2', resp) - self.account_client.create_update_or_delete_account_metadata( - delete_metadata=metadata) - - @decorators.idempotent_id('b904c2e3-24c2-4dba-ad7d-04e90a761be5') - def test_list_no_account_metadata(self): - # list no account metadata - resp, _ = self.account_client.list_account_metadata() - self.assertHeaders(resp, 'Account', 'HEAD') - self.assertNotIn('x-account-meta-', str(resp)) - - @decorators.idempotent_id('e2a08b5f-3115-4768-a3ee-d4287acd6c08') - def test_update_account_metadata_with_create_metadata(self): - # add metadata to account - metadata = {'test-account-meta1': 'Meta1'} - resp, _ = self.account_client.create_update_or_delete_account_metadata( - create_update_metadata=metadata) - self.assertHeaders(resp, 'Account', 'POST') - - resp, _ = self.account_client.list_account_metadata() - self.assertIn('x-account-meta-test-account-meta1', resp) - self.assertEqual(resp['x-account-meta-test-account-meta1'], - metadata['test-account-meta1']) - - self.account_client.create_update_or_delete_account_metadata( - delete_metadata=metadata) - - @decorators.idempotent_id('9f60348d-c46f-4465-ae06-d51dbd470953') - def test_update_account_metadata_with_delete_metadata(self): - # delete metadata from account - metadata = {'test-account-meta1': 'Meta1'} - self.account_client.create_update_or_delete_account_metadata( - create_update_metadata=metadata) - resp, _ = self.account_client.create_update_or_delete_account_metadata( - delete_metadata=metadata) - self.assertHeaders(resp, 'Account', 'POST') - - resp, _ = self.account_client.list_account_metadata() - self.assertNotIn('x-account-meta-test-account-meta1', resp) - - @decorators.idempotent_id('64fd53f3-adbd-4639-af54-436e4982dbfb') - def test_update_account_metadata_with_create_metadata_key(self): - # if the value of metadata is not set, the metadata is not - # registered at a server - metadata = {'test-account-meta1': ''} - resp, _ = self.account_client.create_update_or_delete_account_metadata( - create_update_metadata=metadata) - self.assertHeaders(resp, 'Account', 'POST') - - resp, _ = self.account_client.list_account_metadata() - self.assertNotIn('x-account-meta-test-account-meta1', resp) - - @decorators.idempotent_id('d4d884d3-4696-4b85-bc98-4f57c4dd2bf1') - def test_update_account_metadata_with_delete_metadata_key(self): - # Although the value of metadata is not set, the feature of - # deleting metadata is valid - metadata_1 = {'test-account-meta1': 'Meta1'} - self.account_client.create_update_or_delete_account_metadata( - create_update_metadata=metadata_1) - metadata_2 = {'test-account-meta1': ''} - resp, _ = self.account_client.create_update_or_delete_account_metadata( - delete_metadata=metadata_2) - self.assertHeaders(resp, 'Account', 'POST') - - resp, _ = self.account_client.list_account_metadata() - self.assertNotIn('x-account-meta-test-account-meta1', resp) - - @decorators.idempotent_id('8e5fc073-59b9-42ee-984a-29ed11b2c749') - def test_update_account_metadata_with_create_and_delete_metadata(self): - # Send a request adding and deleting metadata requests simultaneously - metadata_1 = {'test-account-meta1': 'Meta1'} - self.account_client.create_update_or_delete_account_metadata( - create_update_metadata=metadata_1) - metadata_2 = {'test-account-meta2': 'Meta2'} - resp, _ = ( - self.account_client.create_update_or_delete_account_metadata( - create_update_metadata=metadata_2, - delete_metadata=metadata_1)) - self.assertHeaders(resp, 'Account', 'POST') - - resp, _ = self.account_client.list_account_metadata() - self.assertNotIn('x-account-meta-test-account-meta1', resp) - self.assertIn('x-account-meta-test-account-meta2', resp) - self.assertEqual(resp['x-account-meta-test-account-meta2'], - metadata_2['test-account-meta2']) - - self.account_client.create_update_or_delete_account_metadata( - delete_metadata=metadata_2) diff --git a/tempest/api/object_storage/test_account_services_negative.py b/tempest/api/object_storage/test_account_services_negative.py deleted file mode 100644 index e98a4f540..000000000 --- a/tempest/api/object_storage/test_account_services_negative.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright (C) 2013 eNovance SAS -# -# 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 tempest.api.object_storage import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class AccountNegativeTest(base.BaseObjectTest): - - credentials = [['operator', CONF.object_storage.operator_role], - ['operator_alt', CONF.object_storage.operator_role]] - - @classmethod - def setup_credentials(cls): - super(AccountNegativeTest, cls).setup_credentials() - cls.os = cls.os_roles_operator - cls.os_operator = cls.os_roles_operator_alt - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('070e6aca-6152-4867-868d-1118d68fb38c') - def test_list_containers_with_non_authorized_user(self): - # list containers using non-authorized user - - test_auth_provider = self.os_operator.auth_provider - # Get auth for the test user - test_auth_provider.auth_data - - # Get fresh auth for test user and set it to next auth request for - # account_client - delattr(test_auth_provider, 'auth_data') - test_auth_new_data = test_auth_provider.auth_data - self.account_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=test_auth_new_data - ) - - params = {'format': 'json'} - # list containers with non-authorized user token - self.assertRaises(lib_exc.Forbidden, - self.account_client.list_account_containers, - params=params) diff --git a/tempest/api/object_storage/test_container_acl.py b/tempest/api/object_storage/test_container_acl.py deleted file mode 100644 index 4b66ebf16..000000000 --- a/tempest/api/object_storage/test_container_acl.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.object_storage import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class ObjectTestACLs(base.BaseObjectTest): - - credentials = [['operator', CONF.object_storage.operator_role], - ['operator_alt', CONF.object_storage.operator_role]] - - def setUp(self): - super(ObjectTestACLs, self).setUp() - self.container_name = self.create_container() - - def tearDown(self): - self.delete_containers() - super(ObjectTestACLs, self).tearDown() - - @decorators.idempotent_id('a3270f3f-7640-4944-8448-c7ea783ea5b6') - def test_read_object_with_rights(self): - # attempt to read object using authorized user - # update X-Container-Read metadata ACL - tenant_name = self.os_roles_operator_alt.credentials.tenant_name - username = self.os_roles_operator_alt.credentials.username - cont_headers = {'X-Container-Read': tenant_name + ':' + username} - resp_meta, _ = ( - self.os_roles_operator.container_client.update_container_metadata( - self.container_name, metadata=cont_headers, - metadata_prefix='')) - self.assertHeaders(resp_meta, 'Container', 'POST') - # create object - object_name = data_utils.rand_name(name='Object') - resp, _ = self.os_roles_operator.object_client.create_object( - self.container_name, object_name, 'data') - self.assertHeaders(resp, 'Object', 'PUT') - # set alternative authentication data; cannot simply use the - # other object client. - self.os_roles_operator.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.os_roles_operator_alt.object_client.auth_provider. - auth_data) - resp, _ = self.os_roles_operator.object_client.get_object( - self.container_name, object_name) - self.assertHeaders(resp, 'Object', 'GET') - - @decorators.idempotent_id('aa58bfa5-40d9-4bc3-82b4-d07f4a9e392a') - def test_write_object_with_rights(self): - # attempt to write object using authorized user - # update X-Container-Write metadata ACL - tenant_name = self.os_roles_operator_alt.credentials.tenant_name - username = self.os_roles_operator_alt.credentials.username - cont_headers = {'X-Container-Write': tenant_name + ':' + username} - resp_meta, _ = ( - self.os_roles_operator.container_client.update_container_metadata( - self.container_name, metadata=cont_headers, - metadata_prefix='')) - self.assertHeaders(resp_meta, 'Container', 'POST') - # set alternative authentication data; cannot simply use the - # other object client. - self.os_roles_operator.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.os_roles_operator_alt.object_client.auth_provider. - auth_data) - # Trying to write the object with rights - object_name = data_utils.rand_name(name='Object') - resp, _ = self.os_roles_operator.object_client.create_object( - self.container_name, - object_name, 'data', headers={}) - self.assertHeaders(resp, 'Object', 'PUT') diff --git a/tempest/api/object_storage/test_container_acl_negative.py b/tempest/api/object_storage/test_container_acl_negative.py deleted file mode 100644 index 655626c29..000000000 --- a/tempest/api/object_storage/test_container_acl_negative.py +++ /dev/null @@ -1,228 +0,0 @@ -# Copyright (C) 2013 eNovance SAS -# -# 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 tempest.api.object_storage import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class ObjectACLsNegativeTest(base.BaseObjectTest): - - credentials = [['operator', CONF.object_storage.operator_role], - ['operator_alt', CONF.object_storage.operator_role]] - - @classmethod - def setup_credentials(cls): - super(ObjectACLsNegativeTest, cls).setup_credentials() - cls.os = cls.os_roles_operator - cls.os_operator = cls.os_roles_operator_alt - - @classmethod - def resource_setup(cls): - super(ObjectACLsNegativeTest, cls).resource_setup() - cls.test_auth_data = cls.os_operator.auth_provider.auth_data - - def setUp(self): - super(ObjectACLsNegativeTest, self).setUp() - self.container_name = data_utils.rand_name(name='TestContainer') - self.container_client.create_container(self.container_name) - - def tearDown(self): - self.delete_containers([self.container_name]) - super(ObjectACLsNegativeTest, self).tearDown() - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('af587587-0c24-4e15-9822-8352ce711013') - def test_write_object_without_using_creds(self): - # trying to create object with empty headers - # X-Auth-Token is not provided - object_name = data_utils.rand_name(name='Object') - self.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=None - ) - self.assertRaises(lib_exc.Unauthorized, - self.object_client.create_object, - self.container_name, object_name, 'data', headers={}) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('af85af0b-a025-4e72-a90e-121babf55720') - def test_delete_object_without_using_creds(self): - # create object - object_name = data_utils.rand_name(name='Object') - self.object_client.create_object(self.container_name, object_name, - 'data') - # trying to delete object with empty headers - # X-Auth-Token is not provided - self.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=None - ) - self.assertRaises(lib_exc.Unauthorized, - self.object_client.delete_object, - self.container_name, object_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('63d84e37-55a6-42e2-9e5f-276e60e26a00') - def test_write_object_with_non_authorized_user(self): - # attempt to upload another file using non-authorized user - # User provided token is forbidden. ACL are not set - object_name = data_utils.rand_name(name='Object') - # trying to create object with non-authorized user - self.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.test_auth_data - ) - self.assertRaises(lib_exc.Forbidden, - self.object_client.create_object, - self.container_name, object_name, 'data', headers={}) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('abf63359-be52-4feb-87dd-447689fc77fd') - def test_read_object_with_non_authorized_user(self): - # attempt to read object using non-authorized user - # User provided token is forbidden. ACL are not set - object_name = data_utils.rand_name(name='Object') - resp, _ = self.object_client.create_object( - self.container_name, object_name, 'data') - self.assertHeaders(resp, 'Object', 'PUT') - # trying to get object with non authorized user token - self.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.test_auth_data - ) - self.assertRaises(lib_exc.Forbidden, - self.object_client.get_object, - self.container_name, object_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('7343ac3d-cfed-4198-9bb0-00149741a492') - def test_delete_object_with_non_authorized_user(self): - # attempt to delete object using non-authorized user - # User provided token is forbidden. ACL are not set - object_name = data_utils.rand_name(name='Object') - resp, _ = self.object_client.create_object( - self.container_name, object_name, 'data') - self.assertHeaders(resp, 'Object', 'PUT') - # trying to delete object with non-authorized user token - self.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.test_auth_data - ) - self.assertRaises(lib_exc.Forbidden, - self.object_client.delete_object, - self.container_name, object_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9ed01334-01e9-41ea-87ea-e6f465582823') - def test_read_object_without_rights(self): - # attempt to read object using non-authorized user - # update X-Container-Read metadata ACL - cont_headers = {'X-Container-Read': 'badtenant:baduser'} - resp_meta, _ = self.container_client.update_container_metadata( - self.container_name, metadata=cont_headers, - metadata_prefix='') - self.assertHeaders(resp_meta, 'Container', 'POST') - # create object - object_name = data_utils.rand_name(name='Object') - resp, _ = self.object_client.create_object(self.container_name, - object_name, 'data') - self.assertHeaders(resp, 'Object', 'PUT') - # Trying to read the object without rights - self.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.test_auth_data - ) - self.assertRaises(lib_exc.Forbidden, - self.object_client.get_object, - self.container_name, object_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a3a585a7-d8cf-4b65-a1a0-edc2b1204f85') - def test_write_object_without_rights(self): - # attempt to write object using non-authorized user - # update X-Container-Write metadata ACL - cont_headers = {'X-Container-Write': 'badtenant:baduser'} - resp_meta, _ = self.container_client.update_container_metadata( - self.container_name, metadata=cont_headers, - metadata_prefix='') - self.assertHeaders(resp_meta, 'Container', 'POST') - # Trying to write the object without rights - self.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.test_auth_data - ) - object_name = data_utils.rand_name(name='Object') - self.assertRaises(lib_exc.Forbidden, - self.object_client.create_object, - self.container_name, - object_name, 'data', headers={}) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('8ba512ad-aa6e-444e-b882-2906a0ea2052') - def test_write_object_without_write_rights(self): - # attempt to write object using non-authorized user - # update X-Container-Read and X-Container-Write metadata ACL - tenant_name = self.os_operator.credentials.tenant_name - username = self.os_operator.credentials.username - cont_headers = {'X-Container-Read': - tenant_name + ':' + username, - 'X-Container-Write': ''} - resp_meta, _ = self.container_client.update_container_metadata( - self.container_name, metadata=cont_headers, - metadata_prefix='') - self.assertHeaders(resp_meta, 'Container', 'POST') - # Trying to write the object without write rights - self.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.test_auth_data - ) - object_name = data_utils.rand_name(name='Object') - self.assertRaises(lib_exc.Forbidden, - self.object_client.create_object, - self.container_name, - object_name, 'data', headers={}) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('b4e366f8-f185-47ab-b789-df4416f9ecdb') - def test_delete_object_without_write_rights(self): - # attempt to delete object using non-authorized user - # update X-Container-Read and X-Container-Write metadata ACL - tenant_name = self.os_operator.credentials.tenant_name - username = self.os_operator.credentials.username - cont_headers = {'X-Container-Read': - tenant_name + ':' + username, - 'X-Container-Write': ''} - resp_meta, _ = self.container_client.update_container_metadata( - self.container_name, metadata=cont_headers, - metadata_prefix='') - self.assertHeaders(resp_meta, 'Container', 'POST') - # create object - object_name = data_utils.rand_name(name='Object') - resp, _ = self.object_client.create_object(self.container_name, - object_name, 'data') - self.assertHeaders(resp, 'Object', 'PUT') - # Trying to delete the object without write rights - self.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=self.test_auth_data - ) - self.assertRaises(lib_exc.Forbidden, - self.object_client.delete_object, - self.container_name, - object_name) diff --git a/tempest/api/object_storage/test_container_quotas.py b/tempest/api/object_storage/test_container_quotas.py deleted file mode 100644 index 8266341af..000000000 --- a/tempest/api/object_storage/test_container_quotas.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright 2013 Cloudwatt -# 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 tempest.api.object_storage import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -QUOTA_BYTES = 10 -QUOTA_COUNT = 3 - - -class ContainerQuotasTest(base.BaseObjectTest): - """Attempts to test the perfect behavior of quotas in a container.""" - - def setUp(self): - """Creates and sets a container with quotas. - - Quotas are set by adding meta values to the container, - and are validated when set: - - X-Container-Meta-Quota-Bytes: - Maximum size of the container, in bytes. - - X-Container-Meta-Quota-Count: - Maximum object count of the container. - """ - super(ContainerQuotasTest, self).setUp() - self.container_name = self.create_container() - metadata = {"quota-bytes": str(QUOTA_BYTES), - "quota-count": str(QUOTA_COUNT), } - self.container_client.update_container_metadata( - self.container_name, metadata) - - def tearDown(self): - """Cleans the container of any object after each test.""" - self.delete_containers() - super(ContainerQuotasTest, self).tearDown() - - @decorators.idempotent_id('9a0fb034-86af-4df0-86fa-f8bd7db21ae0') - @test.requires_ext(extension='container_quotas', service='object') - @decorators.attr(type="smoke") - def test_upload_valid_object(self): - """Attempts to uploads an object smaller than the bytes quota.""" - object_name = data_utils.rand_name(name="TestObject") - data = data_utils.arbitrary_string(QUOTA_BYTES) - - nbefore = self._get_bytes_used() - - resp, _ = self.object_client.create_object( - self.container_name, object_name, data) - self.assertHeaders(resp, 'Object', 'PUT') - - nafter = self._get_bytes_used() - self.assertEqual(nbefore + len(data), nafter) - - @decorators.idempotent_id('22eeeb2b-3668-4160-baef-44790f65a5a0') - @test.requires_ext(extension='container_quotas', service='object') - @decorators.attr(type="smoke") - def test_upload_large_object(self): - """Attempts to upload an object larger than the bytes quota.""" - object_name = data_utils.rand_name(name="TestObject") - data = data_utils.arbitrary_string(QUOTA_BYTES + 1) - - nbefore = self._get_bytes_used() - - self.assertRaises(lib_exc.OverLimit, - self.object_client.create_object, - self.container_name, object_name, data) - - nafter = self._get_bytes_used() - self.assertEqual(nbefore, nafter) - - @decorators.idempotent_id('3a387039-697a-44fc-a9c0-935de31f426b') - @test.requires_ext(extension='container_quotas', service='object') - @decorators.attr(type="smoke") - def test_upload_too_many_objects(self): - """Attempts to upload many objects that exceeds the count limit.""" - for _ in range(QUOTA_COUNT): - name = data_utils.rand_name(name="TestObject") - self.object_client.create_object(self.container_name, name, "") - - nbefore = self._get_object_count() - self.assertEqual(nbefore, QUOTA_COUNT) - - self.assertRaises(lib_exc.OverLimit, - self.object_client.create_object, - self.container_name, "OverQuotaObject", "") - - nafter = self._get_object_count() - self.assertEqual(nbefore, nafter) - - def _get_container_metadata(self): - resp, _ = self.container_client.list_container_metadata( - self.container_name) - return resp - - def _get_object_count(self): - resp = self._get_container_metadata() - return int(resp["x-container-object-count"]) - - def _get_bytes_used(self): - resp = self._get_container_metadata() - return int(resp["x-container-bytes-used"]) diff --git a/tempest/api/object_storage/test_container_services.py b/tempest/api/object_storage/test_container_services.py deleted file mode 100644 index 76fe8d4f5..000000000 --- a/tempest/api/object_storage/test_container_services.py +++ /dev/null @@ -1,389 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.object_storage import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class ContainerTest(base.BaseObjectTest): - def tearDown(self): - self.delete_containers() - super(ContainerTest, self).tearDown() - - @decorators.attr(type='smoke') - @decorators.idempotent_id('92139d73-7819-4db1-85f8-3f2f22a8d91f') - def test_create_container(self): - container_name = data_utils.rand_name(name='TestContainer') - resp, _ = self.container_client.create_container(container_name) - self.containers.append(container_name) - self.assertHeaders(resp, 'Container', 'PUT') - - @decorators.idempotent_id('49f866ed-d6af-4395-93e7-4187eb56d322') - def test_create_container_overwrite(self): - # overwrite container with the same name - container_name = data_utils.rand_name(name='TestContainer') - self.container_client.create_container(container_name) - self.containers.append(container_name) - - resp, _ = self.container_client.create_container(container_name) - self.assertHeaders(resp, 'Container', 'PUT') - - @decorators.idempotent_id('c2ac4d59-d0f5-40d5-ba19-0635056d48cd') - def test_create_container_with_metadata_key(self): - # create container with the blank value of metadata - container_name = data_utils.rand_name(name='TestContainer') - metadata = {'test-container-meta': ''} - resp, _ = self.container_client.create_container( - container_name, - metadata=metadata) - self.containers.append(container_name) - self.assertHeaders(resp, 'Container', 'PUT') - - resp, _ = self.container_client.list_container_metadata( - container_name) - # if the value of metadata is blank, metadata is not registered - # in the server - self.assertNotIn('x-container-meta-test-container-meta', resp) - - @decorators.idempotent_id('e1e8df32-7b22-44e1-aa08-ccfd8d446b58') - def test_create_container_with_metadata_value(self): - # create container with metadata value - container_name = data_utils.rand_name(name='TestContainer') - - # metadata name using underscores should be converted to hyphens - metadata = {'test_container_meta': 'Meta1'} - resp, _ = self.container_client.create_container( - container_name, - metadata=metadata) - self.containers.append(container_name) - self.assertHeaders(resp, 'Container', 'PUT') - - resp, _ = self.container_client.list_container_metadata( - container_name) - self.assertIn('x-container-meta-test-container-meta', resp) - self.assertEqual(resp['x-container-meta-test-container-meta'], - metadata['test_container_meta']) - - @decorators.idempotent_id('24d16451-1c0c-4e4f-b59c-9840a3aba40e') - def test_create_container_with_remove_metadata_key(self): - # create container with the blank value of remove metadata - container_name = data_utils.rand_name(name='TestContainer') - metadata_1 = {'test-container-meta': 'Meta1'} - self.container_client.create_container( - container_name, - metadata=metadata_1) - self.containers.append(container_name) - - metadata_2 = {'test-container-meta': ''} - resp, _ = self.container_client.create_container( - container_name, - remove_metadata=metadata_2) - self.assertHeaders(resp, 'Container', 'PUT') - - resp, _ = self.container_client.list_container_metadata( - container_name) - self.assertNotIn('x-container-meta-test-container-meta', resp) - - @decorators.idempotent_id('8a21ebad-a5c7-4e29-b428-384edc8cd156') - def test_create_container_with_remove_metadata_value(self): - # create container with remove metadata - container_name = data_utils.rand_name(name='TestContainer') - metadata = {'test-container-meta': 'Meta1'} - self.container_client.create_container(container_name, - metadata=metadata) - self.containers.append(container_name) - - resp, _ = self.container_client.create_container( - container_name, - remove_metadata=metadata) - self.assertHeaders(resp, 'Container', 'PUT') - - resp, _ = self.container_client.list_container_metadata( - container_name) - self.assertNotIn('x-container-meta-test-container-meta', resp) - - @decorators.idempotent_id('95d3a249-b702-4082-a2c4-14bb860cf06a') - def test_delete_container(self): - # create a container - container_name = self.create_container() - # delete container, success asserted within - resp, _ = self.container_client.delete_container(container_name) - self.assertHeaders(resp, 'Container', 'DELETE') - - @decorators.attr(type='smoke') - @decorators.idempotent_id('312ff6bd-5290-497f-bda1-7c5fec6697ab') - def test_list_container_contents(self): - # get container contents list - container_name = self.create_container() - object_name, _ = self.create_object(container_name) - - resp, object_list = self.container_client.list_container_contents( - container_name) - self.assertHeaders(resp, 'Container', 'GET') - self.assertEqual([object_name], object_list) - - @decorators.idempotent_id('4646ac2d-9bfb-4c7d-a3c5-0f527402b3df') - def test_list_container_contents_with_no_object(self): - # get empty container contents list - container_name = self.create_container() - - resp, object_list = self.container_client.list_container_contents( - container_name) - self.assertHeaders(resp, 'Container', 'GET') - self.assertEmpty(object_list) - - @decorators.idempotent_id('fe323a32-57b9-4704-a996-2e68f83b09bc') - def test_list_container_contents_with_delimiter(self): - # get container contents list using delimiter param - container_name = self.create_container() - object_name = data_utils.rand_name(name='TestObject/') - self.create_object(container_name, object_name) - - params = {'delimiter': '/'} - resp, object_list = self.container_client.list_container_contents( - container_name, - params=params) - self.assertHeaders(resp, 'Container', 'GET') - self.assertEqual([object_name.split('/')[0] + '/'], object_list) - - @decorators.idempotent_id('55b4fa5c-e12e-4ca9-8fcf-a79afe118522') - def test_list_container_contents_with_end_marker(self): - # get container contents list using end_marker param - container_name = self.create_container() - object_name, _ = self.create_object(container_name) - - params = {'end_marker': object_name + 'zzzz'} - resp, object_list = self.container_client.list_container_contents( - container_name, - params=params) - self.assertHeaders(resp, 'Container', 'GET') - self.assertEqual([object_name], object_list) - - @decorators.idempotent_id('196f5034-6ab0-4032-9da9-a937bbb9fba9') - def test_list_container_contents_with_format_json(self): - # get container contents list using format_json param - container_name = self.create_container() - self.create_object(container_name) - - params = {'format': 'json'} - resp, object_list = self.container_client.list_container_contents( - container_name, - params=params) - self.assertHeaders(resp, 'Container', 'GET') - - self.assertIsNotNone(object_list) - self.assertTrue([c['name'] for c in object_list]) - self.assertTrue([c['hash'] for c in object_list]) - self.assertTrue([c['bytes'] for c in object_list]) - self.assertTrue([c['content_type'] for c in object_list]) - self.assertTrue([c['last_modified'] for c in object_list]) - - @decorators.idempotent_id('655a53ca-4d15-408c-a377-f4c6dbd0a1fa') - def test_list_container_contents_with_format_xml(self): - # get container contents list using format_xml param - container_name = self.create_container() - self.create_object(container_name) - - params = {'format': 'xml'} - resp, object_list = self.container_client.list_container_contents( - container_name, - params=params) - self.assertHeaders(resp, 'Container', 'GET') - - self.assertIsNotNone(object_list) - self.assertEqual(object_list.tag, 'container') - self.assertIn('name', object_list.keys()) - self.assertEqual(object_list.find(".//object").tag, 'object') - self.assertEqual(object_list.find(".//name").tag, 'name') - self.assertEqual(object_list.find(".//hash").tag, 'hash') - self.assertEqual(object_list.find(".//bytes").tag, 'bytes') - self.assertEqual(object_list.find(".//content_type").tag, - 'content_type') - self.assertEqual(object_list.find(".//last_modified").tag, - 'last_modified') - - @decorators.idempotent_id('297ec38b-2b61-4ff4-bcd1-7fa055e97b61') - def test_list_container_contents_with_limit(self): - # get container contents list using limit param - container_name = self.create_container() - object_name, _ = self.create_object(container_name) - - params = {'limit': data_utils.rand_int_id(1, 10000)} - resp, object_list = self.container_client.list_container_contents( - container_name, - params=params) - self.assertHeaders(resp, 'Container', 'GET') - self.assertEqual([object_name], object_list) - - @decorators.idempotent_id('c31ddc63-2a58-4f6b-b25c-94d2937e6867') - def test_list_container_contents_with_marker(self): - # get container contents list using marker param - container_name = self.create_container() - object_name, _ = self.create_object(container_name) - - params = {'marker': 'AaaaObject1234567890'} - resp, object_list = self.container_client.list_container_contents( - container_name, - params=params) - self.assertHeaders(resp, 'Container', 'GET') - self.assertEqual([object_name], object_list) - - @decorators.idempotent_id('58ca6cc9-6af0-408d-aaec-2a6a7b2f0df9') - def test_list_container_contents_with_path(self): - # get container contents list using path param - container_name = self.create_container() - object_name = data_utils.rand_name(name='TestObject') - object_name = 'Swift/' + object_name - self.create_object(container_name, object_name) - - params = {'path': 'Swift'} - resp, object_list = self.container_client.list_container_contents( - container_name, - params=params) - self.assertHeaders(resp, 'Container', 'GET') - self.assertEqual([object_name], object_list) - - @decorators.idempotent_id('77e742c7-caf2-4ec9-8aa4-f7d509a3344c') - def test_list_container_contents_with_prefix(self): - # get container contents list using prefix param - container_name = self.create_container() - object_name, _ = self.create_object(container_name) - - prefix_key = object_name[0:8] - params = {'prefix': prefix_key} - resp, object_list = self.container_client.list_container_contents( - container_name, - params=params) - self.assertHeaders(resp, 'Container', 'GET') - self.assertEqual([object_name], object_list) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('96e68f0e-19ec-4aa2-86f3-adc6a45e14dd') - def test_list_container_metadata(self): - # List container metadata - container_name = self.create_container() - - metadata = {'name': 'Pictures'} - self.container_client.update_container_metadata( - container_name, - metadata=metadata) - - resp, _ = self.container_client.list_container_metadata( - container_name) - self.assertHeaders(resp, 'Container', 'HEAD') - self.assertIn('x-container-meta-name', resp) - self.assertEqual(resp['x-container-meta-name'], metadata['name']) - - @decorators.idempotent_id('a2faf936-6b13-4f8d-92a2-c2278355821e') - def test_list_no_container_metadata(self): - # HEAD container without metadata - container_name = self.create_container() - - resp, _ = self.container_client.list_container_metadata( - container_name) - self.assertHeaders(resp, 'Container', 'HEAD') - self.assertNotIn('x-container-meta-', str(resp)) - - @decorators.idempotent_id('cf19bc0b-7e16-4a5a-aaed-cb0c2fe8deef') - def test_update_container_metadata_with_create_and_delete_metadata(self): - # Send one request of adding and deleting metadata - container_name = data_utils.rand_name(name='TestContainer') - metadata_1 = {'test-container-meta1': 'Meta1'} - self.container_client.create_container(container_name, - metadata=metadata_1) - self.containers.append(container_name) - - metadata_2 = {'test-container-meta2': 'Meta2'} - resp, _ = self.container_client.update_container_metadata( - container_name, - metadata=metadata_2, - remove_metadata=metadata_1) - self.assertHeaders(resp, 'Container', 'POST') - - resp, _ = self.container_client.list_container_metadata( - container_name) - self.assertNotIn('x-container-meta-test-container-meta1', resp) - self.assertIn('x-container-meta-test-container-meta2', resp) - self.assertEqual(resp['x-container-meta-test-container-meta2'], - metadata_2['test-container-meta2']) - - @decorators.idempotent_id('2ae5f295-4bf1-4e04-bfad-21e54b62cec5') - def test_update_container_metadata_with_create_metadata(self): - # update container metadata using add metadata - container_name = self.create_container() - - metadata = {'test-container-meta1': 'Meta1'} - resp, _ = self.container_client.update_container_metadata( - container_name, - metadata=metadata) - self.assertHeaders(resp, 'Container', 'POST') - - resp, _ = self.container_client.list_container_metadata( - container_name) - self.assertIn('x-container-meta-test-container-meta1', resp) - self.assertEqual(resp['x-container-meta-test-container-meta1'], - metadata['test-container-meta1']) - - @decorators.idempotent_id('3a5ce7d4-6e4b-47d0-9d87-7cd42c325094') - def test_update_container_metadata_with_delete_metadata(self): - # update container metadata using delete metadata - container_name = data_utils.rand_name(name='TestContainer') - metadata = {'test-container-meta1': 'Meta1'} - self.container_client.create_container(container_name, - metadata=metadata) - self.containers.append(container_name) - - resp, _ = self.container_client.delete_container_metadata( - container_name, - metadata=metadata) - self.assertHeaders(resp, 'Container', 'POST') - - resp, _ = self.container_client.list_container_metadata( - container_name) - self.assertNotIn('x-container-meta-test-container-meta1', resp) - - @decorators.idempotent_id('31f40a5f-6a52-4314-8794-cd89baed3040') - def test_update_container_metadata_with_create_metadata_key(self): - # update container metadata with a blank value of metadata - container_name = self.create_container() - - metadata = {'test-container-meta1': ''} - resp, _ = self.container_client.update_container_metadata( - container_name, - metadata=metadata) - self.assertHeaders(resp, 'Container', 'POST') - - resp, _ = self.container_client.list_container_metadata( - container_name) - self.assertNotIn('x-container-meta-test-container-meta1', resp) - - @decorators.idempotent_id('a2e36378-6f1f-43f4-840a-ffd9cfd61914') - def test_update_container_metadata_with_delete_metadata_key(self): - # update container metadata with a blank value of metadata - container_name = data_utils.rand_name(name='TestContainer') - metadata = {'test-container-meta1': 'Meta1'} - self.container_client.create_container(container_name, - metadata=metadata) - self.containers.append(container_name) - - metadata = {'test-container-meta1': ''} - resp, _ = self.container_client.delete_container_metadata( - container_name, - metadata=metadata) - self.assertHeaders(resp, 'Container', 'POST') - - resp, _ = self.container_client.list_container_metadata(container_name) - self.assertNotIn('x-container-meta-test-container-meta1', resp) diff --git a/tempest/api/object_storage/test_container_services_negative.py b/tempest/api/object_storage/test_container_services_negative.py deleted file mode 100644 index 387b7b61b..000000000 --- a/tempest/api/object_storage/test_container_services_negative.py +++ /dev/null @@ -1,177 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# 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 testtools - -from tempest.api.object_storage import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions - -CONF = config.CONF - - -class ContainerNegativeTest(base.BaseObjectTest): - - @classmethod - def resource_setup(cls): - super(ContainerNegativeTest, cls).resource_setup() - - if CONF.object_storage_feature_enabled.discoverability: - # use /info to get default constraints - body = cls.capabilities_client.list_capabilities() - cls.constraints = body['swift'] - - @decorators.attr(type=["negative"]) - @decorators.idempotent_id('30686921-4bed-4764-a038-40d741ed4e78') - @testtools.skipUnless( - CONF.object_storage_feature_enabled.discoverability, - 'Discoverability function is disabled') - def test_create_container_name_exceeds_max_length(self): - # Attempts to create a container name that is longer than max - max_length = self.constraints['max_container_name_length'] - # create a container with long name - container_name = data_utils.arbitrary_string(size=max_length + 1) - ex = self.assertRaises(exceptions.BadRequest, - self.container_client.create_container, - container_name) - self.assertIn('Container name length of ' + str(max_length + 1) + - ' longer than ' + str(max_length), str(ex)) - - @decorators.attr(type=["negative"]) - @decorators.idempotent_id('41e645bf-2e68-4f84-bf7b-c71aa5cd76ce') - @testtools.skipUnless( - CONF.object_storage_feature_enabled.discoverability, - 'Discoverability function is disabled') - def test_create_container_metadata_name_exceeds_max_length(self): - # Attempts to create container with metadata name - # that is longer than max. - max_length = self.constraints['max_meta_name_length'] - container_name = data_utils.rand_name(name='TestContainer') - metadata_name = data_utils.arbitrary_string(size=max_length + 1) - metadata = {metadata_name: 'penguin'} - ex = self.assertRaises(exceptions.BadRequest, - self.container_client.create_container, - container_name, metadata=metadata) - self.assertIn('Metadata name too long', str(ex)) - - @decorators.attr(type=["negative"]) - @decorators.idempotent_id('81e36922-326b-4b7c-8155-3bbceecd7a82') - @testtools.skipUnless( - CONF.object_storage_feature_enabled.discoverability, - 'Discoverability function is disabled') - def test_create_container_metadata_value_exceeds_max_length(self): - # Attempts to create container with metadata value - # that is longer than max. - max_length = self.constraints['max_meta_value_length'] - container_name = data_utils.rand_name(name='TestContainer') - metadata_value = data_utils.arbitrary_string(size=max_length + 1) - metadata = {'animal': metadata_value} - ex = self.assertRaises(exceptions.BadRequest, - self.container_client.create_container, - container_name, metadata=metadata) - self.assertIn('Metadata value longer than ' + str(max_length), str(ex)) - - @decorators.attr(type=["negative"]) - @decorators.idempotent_id('ac666539-d566-4f02-8ceb-58e968dfb732') - @testtools.skipUnless( - CONF.object_storage_feature_enabled.discoverability, - 'Discoverability function is disabled') - def test_create_container_metadata_exceeds_overall_metadata_count(self): - # Attempts to create container with metadata that exceeds the - # default count - max_count = self.constraints['max_meta_count'] - container_name = data_utils.rand_name(name='TestContainer') - metadata = {} - for i in range(max_count + 1): - metadata['animal-' + str(i)] = 'penguin' - - ex = self.assertRaises(exceptions.BadRequest, - self.container_client.create_container, - container_name, metadata=metadata) - self.assertIn('Too many metadata items; max ' + str(max_count), - str(ex)) - - @decorators.attr(type=["negative"]) - @decorators.idempotent_id('1a95ab2e-b712-4a98-8a4d-8ce21b7557d6') - def test_get_metadata_headers_with_invalid_container_name(self): - # Attempts to retrieve metadata headers with an invalid - # container name. - self.assertRaises(exceptions.NotFound, - self.container_client.list_container_metadata, - 'invalid_container_name') - - @decorators.attr(type=["negative"]) - @decorators.idempotent_id('125a24fa-90a7-4cfc-b604-44e49d788390') - def test_update_metadata_with_nonexistent_container_name(self): - # Attempts to update metadata using a nonexistent container name. - metadata = {'animal': 'penguin'} - - self.assertRaises(exceptions.NotFound, - self.container_client.update_container_metadata, - 'nonexistent_container_name', metadata) - - @decorators.attr(type=["negative"]) - @decorators.idempotent_id('65387dbf-a0e2-4aac-9ddc-16eb3f1f69ba') - def test_delete_with_nonexistent_container_name(self): - # Attempts to delete metadata using a nonexistent container name. - metadata = {'animal': 'penguin'} - - self.assertRaises(exceptions.NotFound, - self.container_client.delete_container_metadata, - 'nonexistent_container_name', metadata) - - @decorators.attr(type=["negative"]) - @decorators.idempotent_id('14331d21-1e81-420a-beea-19cb5e5207f5') - def test_list_all_container_objects_with_nonexistent_container(self): - # Attempts to get a listing of all objects on a container - # that doesn't exist. - params = {'limit': 9999, 'format': 'json'} - self.assertRaises(exceptions.NotFound, - self.container_client.list_container_contents, - 'nonexistent_container_name', params) - - @decorators.attr(type=["negative"]) - @decorators.idempotent_id('86b2ab08-92d5-493d-acd2-85f0c848819e') - def test_list_all_container_objects_on_deleted_container(self): - # Attempts to get a listing of all objects on a container - # that was deleted. - container_name = self.create_container() - # delete container - resp, _ = self.container_client.delete_container(container_name) - self.assertHeaders(resp, 'Container', 'DELETE') - params = {'limit': 9999, 'format': 'json'} - self.assertRaises(exceptions.NotFound, - self.container_client.list_container_contents, - container_name, params) - - @decorators.attr(type=["negative"]) - @decorators.idempotent_id('42da116e-1e8c-4c96-9e06-2f13884ed2b1') - def test_delete_non_empty_container(self): - # create a container and an object within it - # attempt to delete a container that isn't empty. - container_name = self.create_container() - self.addCleanup(self.container_client.delete_container, - container_name) - object_name, _ = self.create_object(container_name) - self.addCleanup(self.object_client.delete_object, - container_name, object_name) - - ex = self.assertRaises(exceptions.Conflict, - self.container_client.delete_container, - container_name) - self.assertIn('There was a conflict when trying to complete your ' - 'request.', str(ex)) diff --git a/tempest/api/object_storage/test_container_staticweb.py b/tempest/api/object_storage/test_container_staticweb.py deleted file mode 100644 index 378061a59..000000000 --- a/tempest/api/object_storage/test_container_staticweb.py +++ /dev/null @@ -1,158 +0,0 @@ -# Copyright (C) 2013 eNovance SAS -# -# 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 tempest.api.object_storage import base -from tempest.common import custom_matchers -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - - -class StaticWebTest(base.BaseObjectTest): - - @classmethod - def resource_setup(cls): - super(StaticWebTest, cls).resource_setup() - - # This header should be posted on the container before every test - cls.headers_public_read_acl = {'Read': '.r:*,.rlistings'} - - # Create test container and create one object in it - cls.container_name = cls.create_container() - cls.object_name, cls.object_data = cls.create_object( - cls.container_name) - - cls.container_client.update_container_metadata( - cls.container_name, - metadata=cls.headers_public_read_acl, - metadata_prefix="X-Container-") - - @classmethod - def resource_cleanup(cls): - cls.delete_containers() - super(StaticWebTest, cls).resource_cleanup() - - @decorators.idempotent_id('c1f055ab-621d-4a6a-831f-846fcb578b8b') - @test.requires_ext(extension='staticweb', service='object') - def test_web_index(self): - headers = {'web-index': self.object_name} - - self.container_client.update_container_metadata( - self.container_name, metadata=headers) - - # Maintain original headers, no auth added - self.account_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=None - ) - - # test GET on http://account_url/container_name - # we should retrieve the self.object_name file - resp, body = self.account_client.request("GET", - self.container_name, - headers={}) - # This request is equivalent to GET object - self.assertHeaders(resp, 'Object', 'GET') - self.assertEqual(body, self.object_data) - - # clean up before exiting - self.container_client.update_container_metadata(self.container_name, - {'web-index': ""}) - - _, body = self.container_client.list_container_metadata( - self.container_name) - self.assertNotIn('x-container-meta-web-index', body) - - @decorators.idempotent_id('941814cf-db9e-4b21-8112-2b6d0af10ee5') - @test.requires_ext(extension='staticweb', service='object') - def test_web_listing(self): - headers = {'web-listings': 'true'} - - self.container_client.update_container_metadata( - self.container_name, metadata=headers) - - # test GET on http://account_url/container_name - # we should retrieve a listing of objects - resp, body = self.account_client.request("GET", - self.container_name, - headers={}) - # The target of the request is not any Swift resource. Therefore, the - # existence of response header is checked without a custom matcher. - self.assertIn('content-length', resp) - self.assertIn('content-type', resp) - self.assertIn('x-trans-id', resp) - self.assertIn('date', resp) - # Check only the format of common headers with custom matcher - self.assertThat(resp, custom_matchers.AreAllWellFormatted()) - - self.assertIn(self.object_name, body.decode()) - - # clean up before exiting - self.container_client.update_container_metadata(self.container_name, - {'web-listings': ""}) - - _, body = self.container_client.list_container_metadata( - self.container_name) - self.assertNotIn('x-container-meta-web-listings', body) - - @decorators.idempotent_id('bc37ec94-43c8-4990-842e-0e5e02fc8926') - @test.requires_ext(extension='staticweb', service='object') - def test_web_listing_css(self): - headers = {'web-listings': 'true', - 'web-listings-css': 'listings.css'} - - self.container_client.update_container_metadata( - self.container_name, metadata=headers) - - # Maintain original headers, no auth added - self.account_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=None - ) - - # test GET on http://account_url/container_name - # we should retrieve a listing of objects - _, body = self.account_client.request("GET", self.container_name, - headers={}) - self.assertIn(self.object_name, body.decode()) - css = '' - self.assertIn(css, body.decode()) - - @decorators.idempotent_id('f18b4bef-212e-45e7-b3ca-59af3a465f82') - @test.requires_ext(extension='staticweb', service='object') - def test_web_error(self): - headers = {'web-listings': 'true', - 'web-error': self.object_name} - - self.container_client.update_container_metadata( - self.container_name, metadata=headers) - - # Create object to return when requested object not found - object_name_404 = "404" + self.object_name - object_data_404 = data_utils.arbitrary_string() - self.object_client.create_object(self.container_name, - object_name_404, - object_data_404) - - # Do not set auth in HTTP headers for next request - self.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=None - ) - - # Request non-existing object - self.assertRaises( - lib_exc.NotFound, self.object_client.get_object, - self.container_name, "notexisting") diff --git a/tempest/api/object_storage/test_container_sync.py b/tempest/api/object_storage/test_container_sync.py deleted file mode 100644 index 4cb191404..000000000 --- a/tempest/api/object_storage/test_container_sync.py +++ /dev/null @@ -1,147 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 time - -from six.moves.urllib import parse as urlparse -import testtools - -from tempest.api.object_storage import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -# This test can be quite long to run due to its -# dependency on container-sync process running interval. -# You can obviously reduce the container-sync interval in the -# container-server configuration. - - -class ContainerSyncTest(base.BaseObjectTest): - clients = {} - - credentials = [['operator', CONF.object_storage.operator_role], - ['operator_alt', CONF.object_storage.operator_role]] - - @classmethod - def setup_credentials(cls): - super(ContainerSyncTest, cls).setup_credentials() - cls.os = cls.os_roles_operator - cls.os_alt = cls.os_roles_operator_alt - - @classmethod - def setup_clients(cls): - super(ContainerSyncTest, cls).setup_clients() - cls.object_client_alt = cls.os_alt.object_client - cls.container_client_alt = cls.os_alt.container_client - - @classmethod - def resource_setup(cls): - super(ContainerSyncTest, cls).resource_setup() - cls.containers = [] - cls.objects = [] - - # Default container-server config only allows localhost - cls.local_ip = '127.0.0.1' - - # Must be configure according to container-sync interval - container_sync_timeout = CONF.object_storage.container_sync_timeout - cls.container_sync_interval = \ - CONF.object_storage.container_sync_interval - cls.attempts = \ - int(container_sync_timeout / cls.container_sync_interval) - - # define container and object clients - cls.clients[data_utils.rand_name(name='TestContainerSync')] = \ - (cls.container_client, cls.object_client) - cls.clients[data_utils.rand_name(name='TestContainerSync')] = \ - (cls.container_client_alt, cls.object_client_alt) - for cont_name, client in cls.clients.items(): - client[0].create_container(cont_name) - cls.containers.append(cont_name) - - @classmethod - def resource_cleanup(cls): - for client in cls.clients.values(): - cls.delete_containers(client[0], client[1]) - super(ContainerSyncTest, cls).resource_cleanup() - - def _test_container_synchronization(self, make_headers): - # container to container synchronization - # to allow/accept sync requests to/from other accounts - - # turn container synchronization on and create object in container - for cont in (self.containers, self.containers[::-1]): - cont_client = [self.clients[c][0] for c in cont] - obj_client = [self.clients[c][1] for c in cont] - headers = make_headers(cont[1], cont_client[1]) - cont_client[0].put(str(cont[0]), body=None, headers=headers) - # create object in container - object_name = data_utils.rand_name(name='TestSyncObject') - data = object_name[::-1].encode() # Raw data, we need bytes - resp, _ = obj_client[0].create_object(cont[0], object_name, data) - self.objects.append(object_name) - - # wait until container contents list is not empty - cont_client = [self.clients[c][0] for c in self.containers] - params = {'format': 'json'} - while self.attempts > 0: - object_lists = [] - for c_client, cont in zip(cont_client, self.containers): - resp, object_list = c_client.list_container_contents( - cont, params=params) - object_lists.append(dict( - (obj['name'], obj) for obj in object_list)) - # check that containers are not empty and have equal keys() - # or wait for next attempt - if object_lists[0] and object_lists[1] and \ - set(object_lists[0].keys()) == set(object_lists[1].keys()): - break - else: - time.sleep(self.container_sync_interval) - self.attempts -= 1 - - self.assertEqual(object_lists[0], object_lists[1], - 'Different object lists in containers.') - - # Verify object content - obj_clients = [(self.clients[c][1], c) for c in self.containers] - for obj_client, cont in obj_clients: - for obj_name in object_lists[0]: - resp, object_content = obj_client.get_object(cont, obj_name) - self.assertEqual(object_content, obj_name[::-1].encode()) - - @decorators.attr(type='slow') - @decorators.skip_because(bug='1317133') - @decorators.idempotent_id('be008325-1bba-4925-b7dd-93b58f22ce9b') - @testtools.skipIf( - not CONF.object_storage_feature_enabled.container_sync, - 'Old-style container sync function is disabled') - def test_container_synchronization(self): - def make_headers(cont, cont_client): - # tell first container to synchronize to a second - client_proxy_ip = \ - urlparse.urlparse(cont_client.base_url).netloc.split(':')[0] - client_base_url = \ - cont_client.base_url.replace(client_proxy_ip, - self.local_ip) - headers = {'X-Container-Sync-Key': 'sync_key', - 'X-Container-Sync-To': "%s/%s" % - (client_base_url, str(cont))} - return headers - self._test_container_synchronization(make_headers) diff --git a/tempest/api/object_storage/test_container_sync_middleware.py b/tempest/api/object_storage/test_container_sync_middleware.py deleted file mode 100644 index 9eae13874..000000000 --- a/tempest/api/object_storage/test_container_sync_middleware.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright(c)2015 NTT 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 tempest.api.object_storage import test_container_sync -from tempest import config -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -# This test can be quite long to run due to its -# dependency on container-sync process running interval. -# You can obviously reduce the container-sync interval in the -# container-server configuration. - - -class ContainerSyncMiddlewareTest(test_container_sync.ContainerSyncTest): - - @classmethod - def resource_setup(cls): - super(ContainerSyncMiddlewareTest, cls).resource_setup() - - # Set container-sync-realms.conf info - cls.realm_name = CONF.object_storage.realm_name - cls.key = 'sync_key' - cls.cluster_name = CONF.object_storage.cluster_name - - @decorators.attr(type='slow') - @decorators.idempotent_id('ea4645a1-d147-4976-82f7-e5a7a3065f80') - @test.requires_ext(extension='container_sync', service='object') - def test_container_synchronization(self): - def make_headers(cont, cont_client): - # tell first container to synchronize to a second - account_name = cont_client.base_url.split('/')[-1] - - headers = {'X-Container-Sync-Key': "%s" % (self.key), - 'X-Container-Sync-To': "//%s/%s/%s/%s" % - (self.realm_name, self.cluster_name, - str(account_name), str(cont))} - return headers - self._test_container_synchronization(make_headers) diff --git a/tempest/api/object_storage/test_crossdomain.py b/tempest/api/object_storage/test_crossdomain.py deleted file mode 100644 index c47aa93eb..000000000 --- a/tempest/api/object_storage/test_crossdomain.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright (C) 2013 eNovance SAS -# -# 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 tempest.api.object_storage import base -from tempest.common import custom_matchers -from tempest.lib import decorators -from tempest import test - - -class CrossdomainTest(base.BaseObjectTest): - - @classmethod - def resource_setup(cls): - super(CrossdomainTest, cls).resource_setup() - - cls.xml_start = '\n' \ - '\n\n' - - cls.xml_end = "" - - def setUp(self): - super(CrossdomainTest, self).setUp() - - # Turning http://.../v1/foobar into http://.../ - self.account_client.skip_path() - - @decorators.idempotent_id('d1b8b031-b622-4010-82f9-ff78a9e915c7') - @test.requires_ext(extension='crossdomain', service='object') - def test_get_crossdomain_policy(self): - resp, body = self.account_client.get("crossdomain.xml", {}) - body = body.decode() - - self.assertTrue(body.startswith(self.xml_start) and - body.endswith(self.xml_end)) - - # The target of the request is not any Swift resource. Therefore, the - # existence of response header is checked without a custom matcher. - self.assertIn('content-length', resp) - self.assertIn('content-type', resp) - self.assertIn('x-trans-id', resp) - self.assertIn('date', resp) - # Check only the format of common headers with custom matcher - self.assertThat(resp, custom_matchers.AreAllWellFormatted()) diff --git a/tempest/api/object_storage/test_healthcheck.py b/tempest/api/object_storage/test_healthcheck.py deleted file mode 100644 index a186f9ee6..000000000 --- a/tempest/api/object_storage/test_healthcheck.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright (C) 2013 eNovance SAS -# -# 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 tempest.api.object_storage import base -from tempest.common import custom_matchers -from tempest.lib import decorators - - -class HealthcheckTest(base.BaseObjectTest): - - def setUp(self): - super(HealthcheckTest, self).setUp() - # Turning http://.../v1/foobar into http://.../ - self.account_client.skip_path() - - @decorators.idempotent_id('db5723b1-f25c-49a9-bfeb-7b5640caf337') - def test_get_healthcheck(self): - - resp, _ = self.account_client.get("healthcheck", {}) - - # The target of the request is not any Swift resource. Therefore, the - # existence of response header is checked without a custom matcher. - self.assertIn('content-length', resp) - self.assertIn('content-type', resp) - self.assertIn('x-trans-id', resp) - self.assertIn('date', resp) - # Check only the format of common headers with custom matcher - self.assertThat(resp, custom_matchers.AreAllWellFormatted()) diff --git a/tempest/api/object_storage/test_object_expiry.py b/tempest/api/object_storage/test_object_expiry.py deleted file mode 100644 index ed1be9081..000000000 --- a/tempest/api/object_storage/test_object_expiry.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 time - -from tempest.api.object_storage import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ObjectExpiryTest(base.BaseObjectTest): - @classmethod - def resource_setup(cls): - super(ObjectExpiryTest, cls).resource_setup() - cls.container_name = cls.create_container() - - def setUp(self): - super(ObjectExpiryTest, self).setUp() - # create object - self.object_name, _ = self.create_object( - self.container_name) - - @classmethod - def resource_cleanup(cls): - cls.delete_containers() - super(ObjectExpiryTest, cls).resource_cleanup() - - def _test_object_expiry(self, metadata): - # update object metadata - resp, _ = \ - self.object_client.update_object_metadata(self.container_name, - self.object_name, - metadata, - metadata_prefix='') - # verify object metadata - resp, _ = \ - self.object_client.list_object_metadata(self.container_name, - self.object_name) - self.assertHeaders(resp, 'Object', 'HEAD') - self.assertIn('x-delete-at', resp) - # we want to ensure that we will sleep long enough for things to - # actually expire, so figure out how many secs in the future that is. - sleepy_time = int(resp['x-delete-at']) - int(time.time()) - sleepy_time = sleepy_time if sleepy_time > 0 else 0 - resp, _ = self.object_client.get_object(self.container_name, - self.object_name) - self.assertHeaders(resp, 'Object', 'GET') - self.assertIn('x-delete-at', resp) - - # add several seconds for safety. - time.sleep(sleepy_time) - - # Checking whether object still exists for several seconds: - # sometimes object is not deleted immediately, so we are making - # get calls for an approximately 1 minute in a total. Get calls - # can take 3s each sometimes so we are making the requests in - # exponential periodicity - for i in range(1, 6): - time.sleep(2 ** i) - try: - self.object_client.get_object(self.container_name, - self.object_name) - except lib_exc.NotFound: - break - - # object should not be there anymore - self.assertRaises(lib_exc.NotFound, - self.object_client.get_object, - self.container_name, - self.object_name) - - @decorators.idempotent_id('fb024a42-37f3-4ba5-9684-4f40a7910b41') - def test_get_object_after_expiry_time(self): - # the 10s is important, because the get calls can take 3s each - # some times - metadata = {'X-Delete-After': '10'} - self._test_object_expiry(metadata) - - @decorators.idempotent_id('e592f18d-679c-48fe-9e36-4be5f47102c5') - def test_get_object_at_expiry_time(self): - metadata = {'X-Delete-At': str(int(time.time()) + 10)} - self._test_object_expiry(metadata) diff --git a/tempest/api/object_storage/test_object_formpost.py b/tempest/api/object_storage/test_object_formpost.py deleted file mode 100644 index 3a2233a6e..000000000 --- a/tempest/api/object_storage/test_object_formpost.py +++ /dev/null @@ -1,127 +0,0 @@ -# Copyright (C) 2013 eNovance SAS -# -# 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 hashlib -import hmac -import time - -from six.moves.urllib import parse as urlparse - -from tempest.api.object_storage import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - - -class ObjectFormPostTest(base.BaseObjectTest): - - metadata = {} - containers = [] - - @classmethod - def resource_setup(cls): - super(ObjectFormPostTest, cls).resource_setup() - cls.container_name = cls.create_container() - cls.object_name = data_utils.rand_name(name='ObjectTemp') - - cls.key = 'Meta' - cls.metadata = {'Temp-URL-Key': cls.key} - cls.account_client.create_update_or_delete_account_metadata( - create_update_metadata=cls.metadata) - - def setUp(self): - super(ObjectFormPostTest, self).setUp() - - # make sure the metadata has been set - account_client_metadata, _ = \ - self.account_client.list_account_metadata() - self.assertIn('x-account-meta-temp-url-key', - account_client_metadata) - self.assertEqual( - account_client_metadata['x-account-meta-temp-url-key'], - self.key) - - @classmethod - def resource_cleanup(cls): - cls.account_client.create_update_or_delete_account_metadata( - delete_metadata=cls.metadata) - cls.delete_containers() - super(ObjectFormPostTest, cls).resource_cleanup() - - def get_multipart_form(self, expires=600): - path = "%s/%s/%s" % ( - urlparse.urlparse(self.container_client.base_url).path, - self.container_name, - self.object_name) - - redirect = '' - max_file_size = 104857600 - max_file_count = 10 - expires += int(time.time()) - hmac_body = '%s\n%s\n%s\n%s\n%s' % (path, - redirect, - max_file_size, - max_file_count, - expires) - - signature = hmac.new( - self.key.encode(), hmac_body.encode(), hashlib.sha1 - ).hexdigest() - - fields = {'redirect': redirect, - 'max_file_size': str(max_file_size), - 'max_file_count': str(max_file_count), - 'expires': str(expires), - 'signature': signature} - - boundary = '--boundary--' - data = [] - for (key, value) in fields.items(): - data.append('--' + boundary) - data.append('Content-Disposition: form-data; name="%s"' % key) - data.append('') - data.append(value) - - data.append('--' + boundary) - data.append('Content-Disposition: form-data; ' - 'name="file1"; filename="testfile"') - data.append('Content-Type: application/octet-stream') - data.append('') - data.append('hello world') - - data.append('--' + boundary + '--') - data.append('') - - body = '\r\n'.join(data) - content_type = 'multipart/form-data; boundary=%s' % boundary - return body, content_type - - @decorators.idempotent_id('80fac02b-6e54-4f7b-be0d-a965b5cbef76') - @test.requires_ext(extension='formpost', service='object') - def test_post_object_using_form(self): - body, content_type = self.get_multipart_form() - - headers = {'Content-Type': content_type, - 'Content-Length': str(len(body))} - - url = "%s/%s" % (self.container_name, self.object_name) - - resp, body = self.object_client.post(url, body, headers=headers) - self.assertHeaders(resp, "Object", "POST") - - # Ensure object is available - resp, body = self.object_client.get("%s/%s%s" % ( - self.container_name, self.object_name, "testfile")) - self.assertHeaders(resp, "Object", "GET") - self.assertEqual(body.decode(), "hello world") diff --git a/tempest/api/object_storage/test_object_formpost_negative.py b/tempest/api/object_storage/test_object_formpost_negative.py deleted file mode 100644 index c56d91a00..000000000 --- a/tempest/api/object_storage/test_object_formpost_negative.py +++ /dev/null @@ -1,143 +0,0 @@ -# Copyright (C) 2013 eNovance SAS -# -# 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 hashlib -import hmac -import time - -from six.moves.urllib import parse as urlparse - -from tempest.api.object_storage import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - - -class ObjectFormPostNegativeTest(base.BaseObjectTest): - - metadata = {} - containers = [] - - @classmethod - def resource_setup(cls): - super(ObjectFormPostNegativeTest, cls).resource_setup() - cls.container_name = cls.create_container() - cls.object_name = data_utils.rand_name(name='ObjectTemp') - - cls.key = 'Meta' - cls.metadata = {'Temp-URL-Key': cls.key} - cls.account_client.create_update_or_delete_account_metadata( - create_update_metadata=cls.metadata) - - def setUp(self): - super(ObjectFormPostNegativeTest, self).setUp() - - # make sure the metadata has been set - account_client_metadata, _ = \ - self.account_client.list_account_metadata() - self.assertIn('x-account-meta-temp-url-key', - account_client_metadata) - self.assertEqual( - account_client_metadata['x-account-meta-temp-url-key'], - self.key) - - @classmethod - def resource_cleanup(cls): - cls.account_client.create_update_or_delete_account_metadata( - delete_metadata=cls.metadata) - cls.delete_containers() - super(ObjectFormPostNegativeTest, cls).resource_cleanup() - - def get_multipart_form(self, expires=600): - path = "%s/%s/%s" % ( - urlparse.urlparse(self.container_client.base_url).path, - self.container_name, - self.object_name) - - redirect = '' - max_file_size = 104857600 - max_file_count = 10 - expires += int(time.time()) - hmac_body = '%s\n%s\n%s\n%s\n%s' % (path, - redirect, - max_file_size, - max_file_count, - expires) - - signature = hmac.new( - self.key.encode(), hmac_body.encode(), hashlib.sha1 - ).hexdigest() - - fields = {'redirect': redirect, - 'max_file_size': str(max_file_size), - 'max_file_count': str(max_file_count), - 'expires': str(expires), - 'signature': signature} - - boundary = '--boundary--' - data = [] - for (key, value) in fields.items(): - data.append('--' + boundary) - data.append('Content-Disposition: form-data; name="%s"' % key) - data.append('') - data.append(value) - - data.append('--' + boundary) - data.append('Content-Disposition: form-data; ' - 'name="file1"; filename="testfile"') - data.append('Content-Type: application/octet-stream') - data.append('') - data.append('hello world') - - data.append('--' + boundary + '--') - data.append('') - - body = '\r\n'.join(data) - content_type = 'multipart/form-data; boundary=%s' % boundary - return body, content_type - - @decorators.idempotent_id('d3fb3c4d-e627-48ce-9379-a1631f21336d') - @test.requires_ext(extension='formpost', service='object') - @decorators.attr(type=['negative']) - def test_post_object_using_form_expired(self): - body, content_type = self.get_multipart_form(expires=1) - time.sleep(2) - - headers = {'Content-Type': content_type, - 'Content-Length': str(len(body))} - - url = "%s/%s" % (self.container_name, self.object_name) - exc = self.assertRaises( - lib_exc.Unauthorized, - self.object_client.post, - url, body, headers=headers) - self.assertIn('FormPost: Form Expired', str(exc)) - - @decorators.idempotent_id('b277257f-113c-4499-b8d1-5fead79f7360') - @test.requires_ext(extension='formpost', service='object') - @decorators.attr(type=['negative']) - def test_post_object_using_form_invalid_signature(self): - self.key = "Wrong" - body, content_type = self.get_multipart_form() - - headers = {'Content-Type': content_type, - 'Content-Length': str(len(body))} - - url = "%s/%s" % (self.container_name, self.object_name) - exc = self.assertRaises( - lib_exc.Unauthorized, - self.object_client.post, - url, body, headers=headers) - self.assertIn('FormPost: Invalid Signature', str(exc)) diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py deleted file mode 100644 index b29a77f03..000000000 --- a/tempest/api/object_storage/test_object_services.py +++ /dev/null @@ -1,1060 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 hashlib -import random -import re -import time -import zlib - -from tempest.api.object_storage import base -from tempest.common import custom_matchers -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class ObjectTest(base.BaseObjectTest): - - @classmethod - def resource_setup(cls): - super(ObjectTest, cls).resource_setup() - cls.container_name = cls.create_container() - - @classmethod - def resource_cleanup(cls): - cls.delete_containers() - super(ObjectTest, cls).resource_cleanup() - - def _upload_segments(self): - # create object - object_name = data_utils.rand_name(name='LObject') - data = data_utils.arbitrary_string() - segments = 10 - data_segments = [data + str(i) for i in range(segments)] - # uploading segments - for i in range(segments): - self.object_client.create_object_segments( - self.container_name, object_name, i, data_segments[i]) - - return object_name, data_segments - - def _copy_object_2d(self, src_object_name, metadata=None): - dst_object_name = data_utils.rand_name(name='TestObject') - resp, _ = self.object_client.copy_object_2d_way(self.container_name, - src_object_name, - dst_object_name, - metadata=metadata) - return dst_object_name, resp - - def _check_copied_obj(self, dst_object_name, src_body, - in_meta=None, not_in_meta=None): - resp, dest_body = self.object_client.get_object(self.container_name, - dst_object_name) - - self.assertEqual(src_body, dest_body) - if in_meta: - for meta_key in in_meta: - self.assertIn('x-object-meta-' + meta_key, resp) - if not_in_meta: - for meta_key in not_in_meta: - self.assertNotIn('x-object-meta-' + meta_key, resp) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('5b4ce26f-3545-46c9-a2ba-5754358a4c62') - def test_create_object(self): - # create object - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - resp, _ = self.object_client.create_object(self.container_name, - object_name, data) - # create another object - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - resp, _ = self.object_client.create_object(self.container_name, - object_name, data) - self.assertHeaders(resp, 'Object', 'PUT') - - # check uploaded content - _, body = self.object_client.get_object(self.container_name, - object_name) - self.assertEqual(data, body) - - @decorators.idempotent_id('5daebb1d-f0d5-4dc9-b541-69672eff00b0') - def test_create_object_with_content_disposition(self): - # create object with content_disposition - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - metadata = {} - metadata['content-disposition'] = 'inline' - resp, _ = self.object_client.create_object( - self.container_name, - object_name, - data, - metadata=metadata) - self.assertHeaders(resp, 'Object', 'PUT') - - resp, body = self.object_client.get_object( - self.container_name, - object_name, - metadata=None) - self.assertIn('content-disposition', resp) - self.assertEqual(resp['content-disposition'], 'inline') - self.assertEqual(body, data) - - @decorators.idempotent_id('605f8317-f945-4bee-ae91-013f1da8f0a0') - def test_create_object_with_content_encoding(self): - # create object with content_encoding - object_name = data_utils.rand_name(name='TestObject') - - # put compressed string - data_before = b'x' * 2000 - data = zlib.compress(data_before) - metadata = {} - metadata['content-encoding'] = 'deflate' - - resp, _ = self.object_client.create_object( - self.container_name, - object_name, - data, - metadata=metadata) - self.assertHeaders(resp, 'Object', 'PUT') - - # download compressed object - metadata = {} - metadata['accept-encoding'] = 'deflate' - resp, body = self.object_client.get_object( - self.container_name, - object_name, - metadata=metadata) - self.assertEqual(body, data_before) - - @decorators.idempotent_id('73820093-0503-40b1-a478-edf0e69c7d1f') - def test_create_object_with_etag(self): - # create object with etag - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - md5 = hashlib.md5(data).hexdigest() - metadata = {'Etag': md5} - resp, _ = self.object_client.create_object( - self.container_name, - object_name, - data, - metadata=metadata) - self.assertHeaders(resp, 'Object', 'PUT') - - # check uploaded content - _, body = self.object_client.get_object(self.container_name, - object_name) - self.assertEqual(data, body) - - @decorators.idempotent_id('84dafe57-9666-4f6d-84c8-0814d37923b8') - def test_create_object_with_expect_continue(self): - # create object with expect_continue - - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - - status, _ = self.object_client.create_object_continue( - self.container_name, object_name, data) - - self.assertEqual(status, 201) - - # check uploaded content - _, body = self.object_client.get_object(self.container_name, - object_name) - self.assertEqual(data, body) - - @decorators.idempotent_id('4f84422a-e2f2-4403-b601-726a4220b54e') - def test_create_object_with_transfer_encoding(self): - # create object with transfer_encoding - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes(1024) - _, _, resp_headers = self.object_client.put_object_with_chunk( - container=self.container_name, - name=object_name, - contents=data_utils.chunkify(data, 512) - ) - self.assertHeaders(resp_headers, 'Object', 'PUT') - - # check uploaded content - _, body = self.object_client.get_object(self.container_name, - object_name) - self.assertEqual(data, body) - - @decorators.idempotent_id('0f3d62a6-47e3-4554-b0e5-1a5dc372d501') - def test_create_object_with_x_fresh_metadata(self): - # create object with x_fresh_metadata - object_name_base = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - metadata_1 = {'X-Object-Meta-test-meta': 'Meta'} - self.object_client.create_object(self.container_name, - object_name_base, - data, - metadata=metadata_1) - object_name = data_utils.rand_name(name='TestObject') - metadata_2 = {'X-Copy-From': '%s/%s' % (self.container_name, - object_name_base), - 'X-Fresh-Metadata': 'true'} - resp, _ = self.object_client.create_object( - self.container_name, - object_name, - '', - metadata=metadata_2) - self.assertHeaders(resp, 'Object', 'PUT') - - resp, body = self.object_client.get_object(self.container_name, - object_name) - self.assertNotIn('x-object-meta-test-meta', resp) - self.assertEqual(data, body) - - @decorators.idempotent_id('1c7ed3e4-2099-406b-b843-5301d4811baf') - def test_create_object_with_x_object_meta(self): - # create object with object_meta - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - metadata = {'X-Object-Meta-test-meta': 'Meta'} - resp, _ = self.object_client.create_object( - self.container_name, - object_name, - data, - metadata=metadata) - self.assertHeaders(resp, 'Object', 'PUT') - - resp, body = self.object_client.get_object(self.container_name, - object_name) - self.assertIn('x-object-meta-test-meta', resp) - self.assertEqual(resp['x-object-meta-test-meta'], 'Meta') - self.assertEqual(data, body) - - @decorators.idempotent_id('e4183917-33db-4153-85cc-4dacbb938865') - def test_create_object_with_x_object_metakey(self): - # create object with the blank value of metadata - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - metadata = {'X-Object-Meta-test-meta': ''} - resp, _ = self.object_client.create_object( - self.container_name, - object_name, - data, - metadata=metadata) - self.assertHeaders(resp, 'Object', 'PUT') - - resp, body = self.object_client.get_object(self.container_name, - object_name) - self.assertIn('x-object-meta-test-meta', resp) - self.assertEqual(resp['x-object-meta-test-meta'], '') - self.assertEqual(data, body) - - @decorators.idempotent_id('ce798afc-b278-45de-a5ce-2ea124b98b99') - def test_create_object_with_x_remove_object_meta(self): - # create object with x_remove_object_meta - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - metadata_add = {'X-Object-Meta-test-meta': 'Meta'} - self.object_client.create_object(self.container_name, - object_name, - data, - metadata=metadata_add) - metadata_remove = {'X-Remove-Object-Meta-test-meta': 'Meta'} - resp, _ = self.object_client.create_object( - self.container_name, - object_name, - data, - metadata=metadata_remove) - self.assertHeaders(resp, 'Object', 'PUT') - - resp, body = self.object_client.get_object(self.container_name, - object_name) - self.assertNotIn('x-object-meta-test-meta', resp) - self.assertEqual(data, body) - - @decorators.idempotent_id('ad21e342-7916-4f9e-ab62-a1f885f2aaf9') - def test_create_object_with_x_remove_object_metakey(self): - # create object with the blank value of remove metadata - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - metadata_add = {'X-Object-Meta-test-meta': 'Meta'} - self.object_client.create_object(self.container_name, - object_name, - data, - metadata=metadata_add) - metadata_remove = {'X-Remove-Object-Meta-test-meta': ''} - resp, _ = self.object_client.create_object( - self.container_name, - object_name, - data, - metadata=metadata_remove) - self.assertHeaders(resp, 'Object', 'PUT') - - resp, body = self.object_client.get_object(self.container_name, - object_name) - self.assertNotIn('x-object-meta-test-meta', resp) - self.assertEqual(data, body) - - @decorators.idempotent_id('17738d45-03bd-4d45-9e0b-7b2f58f98687') - def test_delete_object(self): - # create object - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - resp, _ = self.object_client.create_object(self.container_name, - object_name, data) - # delete object - resp, _ = self.object_client.delete_object(self.container_name, - object_name) - self.assertHeaders(resp, 'Object', 'DELETE') - - @decorators.attr(type='smoke') - @decorators.idempotent_id('7a94c25d-66e6-434c-9c38-97d4e2c29945') - def test_update_object_metadata(self): - # update object metadata - object_name, _ = self.create_object(self.container_name) - - metadata = {'X-Object-Meta-test-meta': 'Meta'} - resp, _ = self.object_client.update_object_metadata( - self.container_name, - object_name, - metadata, - metadata_prefix='') - self.assertHeaders(resp, 'Object', 'POST') - - resp, _ = self.object_client.list_object_metadata( - self.container_name, - object_name) - self.assertIn('x-object-meta-test-meta', resp) - self.assertEqual(resp['x-object-meta-test-meta'], 'Meta') - - @decorators.idempotent_id('48650ed0-c189-4e1e-ad6b-1d4770c6e134') - def test_update_object_metadata_with_remove_metadata(self): - # update object metadata with remove metadata - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - create_metadata = {'X-Object-Meta-test-meta1': 'Meta1'} - self.object_client.create_object(self.container_name, - object_name, - data, - metadata=create_metadata) - - update_metadata = {'X-Remove-Object-Meta-test-meta1': 'Meta1'} - resp, _ = self.object_client.update_object_metadata( - self.container_name, - object_name, - update_metadata, - metadata_prefix='') - self.assertHeaders(resp, 'Object', 'POST') - - resp, _ = self.object_client.list_object_metadata( - self.container_name, - object_name) - self.assertNotIn('x-object-meta-test-meta1', resp) - - @decorators.idempotent_id('f726174b-2ded-4708-bff7-729d12ce1f84') - def test_update_object_metadata_with_create_and_remove_metadata(self): - # creation and deletion of metadata with one request - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - create_metadata = {'X-Object-Meta-test-meta1': 'Meta1'} - self.object_client.create_object(self.container_name, - object_name, - data, - metadata=create_metadata) - - update_metadata = {'X-Object-Meta-test-meta2': 'Meta2', - 'X-Remove-Object-Meta-test-meta1': 'Meta1'} - resp, _ = self.object_client.update_object_metadata( - self.container_name, - object_name, - update_metadata, - metadata_prefix='') - self.assertHeaders(resp, 'Object', 'POST') - - resp, _ = self.object_client.list_object_metadata( - self.container_name, - object_name) - self.assertNotIn('x-object-meta-test-meta1', resp) - self.assertIn('x-object-meta-test-meta2', resp) - self.assertEqual(resp['x-object-meta-test-meta2'], 'Meta2') - - @decorators.idempotent_id('08854588-6449-4bb7-8cca-f2e1040f5e6f') - def test_update_object_metadata_with_x_object_manifest(self): - # update object metadata with x_object_manifest - - # uploading segments - object_name, _ = self._upload_segments() - # creating a manifest file - data_empty = '' - self.object_client.create_object(self.container_name, - object_name, - data_empty, - metadata=None) - object_prefix = '%s/%s' % (self.container_name, object_name) - update_metadata = {'X-Object-Manifest': object_prefix} - resp, _ = self.object_client.update_object_metadata( - self.container_name, - object_name, - update_metadata, - metadata_prefix='') - self.assertHeaders(resp, 'Object', 'POST') - - resp, _ = self.object_client.list_object_metadata( - self.container_name, - object_name) - self.assertIn('x-object-manifest', resp) - self.assertNotEmpty(resp['x-object-manifest']) - - @decorators.idempotent_id('0dbbe89c-6811-4d84-a2df-eca2bdd40c0e') - def test_update_object_metadata_with_x_object_metakey(self): - # update object metadata with a blank value of metadata - object_name, _ = self.create_object(self.container_name) - - update_metadata = {'X-Object-Meta-test-meta': ''} - resp, _ = self.object_client.update_object_metadata( - self.container_name, - object_name, - update_metadata, - metadata_prefix='') - self.assertHeaders(resp, 'Object', 'POST') - - resp, _ = self.object_client.list_object_metadata( - self.container_name, - object_name) - self.assertIn('x-object-meta-test-meta', resp) - self.assertEqual(resp['x-object-meta-test-meta'], '') - - @decorators.idempotent_id('9a88dca4-b684-425b-806f-306cd0e57e42') - def test_update_object_metadata_with_x_remove_object_metakey(self): - # update object metadata with a blank value of remove metadata - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.arbitrary_string() - create_metadata = {'X-Object-Meta-test-meta': 'Meta'} - self.object_client.create_object(self.container_name, - object_name, - data, - metadata=create_metadata) - - update_metadata = {'X-Remove-Object-Meta-test-meta': ''} - resp, _ = self.object_client.update_object_metadata( - self.container_name, - object_name, - update_metadata, - metadata_prefix='') - self.assertHeaders(resp, 'Object', 'POST') - - resp, _ = self.object_client.list_object_metadata( - self.container_name, - object_name) - self.assertNotIn('x-object-meta-test-meta', resp) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('9a447cf6-de06-48de-8226-a8c6ed31caf2') - def test_list_object_metadata(self): - # get object metadata - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - metadata = {'X-Object-Meta-test-meta': 'Meta'} - self.object_client.create_object(self.container_name, - object_name, - data, - metadata=metadata) - - resp, _ = self.object_client.list_object_metadata( - self.container_name, - object_name) - self.assertHeaders(resp, 'Object', 'HEAD') - self.assertIn('x-object-meta-test-meta', resp) - self.assertEqual(resp['x-object-meta-test-meta'], 'Meta') - - @decorators.idempotent_id('170fb90e-f5c3-4b1f-ae1b-a18810821172') - def test_list_no_object_metadata(self): - # get empty list of object metadata - object_name, _ = self.create_object(self.container_name) - - resp, _ = self.object_client.list_object_metadata( - self.container_name, - object_name) - self.assertHeaders(resp, 'Object', 'HEAD') - self.assertNotIn('x-object-meta-', str(resp)) - - @decorators.idempotent_id('23a3674c-d6de-46c3-86af-ff92bfc8a3da') - def test_list_object_metadata_with_x_object_manifest(self): - # get object metadata with x_object_manifest - - # uploading segments - object_name, _ = self._upload_segments() - # creating a manifest file - object_prefix = '%s/%s' % (self.container_name, object_name) - metadata = {'X-Object-Manifest': object_prefix} - data_empty = '' - resp, _ = self.object_client.create_object( - self.container_name, - object_name, - data_empty, - metadata=metadata) - - resp, _ = self.object_client.list_object_metadata( - self.container_name, - object_name) - - # Check only the existence of common headers with custom matcher - self.assertThat(resp, custom_matchers.ExistsAllResponseHeaders( - 'Object', 'HEAD')) - self.assertIn('x-object-manifest', resp) - - # Etag value of a large object is enclosed in double-quotations. - # This is a special case, therefore the formats of response headers - # are checked without a custom matcher. - self.assertTrue(resp['etag'].startswith('\"')) - self.assertTrue(resp['etag'].endswith('\"')) - self.assertTrue(resp['etag'].strip('\"').isalnum()) - self.assertTrue(re.match(r"^\d+\.?\d*\Z", resp['x-timestamp'])) - self.assertNotEmpty(resp['content-type']) - self.assertTrue(re.match("^tx[0-9a-f]{21}-[0-9a-f]{10}.*", - resp['x-trans-id'])) - self.assertNotEmpty(resp['date']) - self.assertEqual(resp['accept-ranges'], 'bytes') - self.assertEqual(resp['x-object-manifest'], - '%s/%s' % (self.container_name, object_name)) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('02610ba7-86b7-4272-9ed8-aa8d417cb3cd') - def test_get_object(self): - # retrieve object's data (in response body) - - # create object - object_name, data = self.create_object(self.container_name) - # get object - resp, body = self.object_client.get_object(self.container_name, - object_name) - self.assertHeaders(resp, 'Object', 'GET') - - self.assertEqual(body, data) - - @decorators.idempotent_id('005f9bf6-e06d-41ec-968e-96c78e0b1d82') - def test_get_object_with_metadata(self): - # get object with metadata - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - metadata = {'X-Object-Meta-test-meta': 'Meta'} - self.object_client.create_object(self.container_name, - object_name, - data, - metadata=metadata) - resp, body = self.object_client.get_object( - self.container_name, - object_name, - metadata=None) - self.assertHeaders(resp, 'Object', 'GET') - self.assertIn('x-object-meta-test-meta', resp) - self.assertEqual(resp['x-object-meta-test-meta'], 'Meta') - self.assertEqual(body, data) - - @decorators.idempotent_id('05a1890e-7db9-4a6c-90a8-ce998a2bddfa') - def test_get_object_with_range(self): - # get object with range - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes(100) - self.object_client.create_object(self.container_name, - object_name, - data, - metadata=None) - rand_num = random.randint(3, len(data) - 1) - metadata = {'Range': 'bytes=%s-%s' % (rand_num - 3, rand_num - 1)} - resp, body = self.object_client.get_object( - self.container_name, - object_name, - metadata=metadata) - self.assertHeaders(resp, 'Object', 'GET') - self.assertEqual(body, data[rand_num - 3: rand_num]) - - @decorators.idempotent_id('11b4515b-7ba7-4ca8-8838-357ded86fc10') - def test_get_object_with_x_object_manifest(self): - # get object with x_object_manifest - - # uploading segments - object_name, data_segments = self._upload_segments() - # creating a manifest file - object_prefix = '%s/%s' % (self.container_name, object_name) - metadata = {'X-Object-Manifest': object_prefix} - data_empty = '' - resp, body = self.object_client.create_object( - self.container_name, - object_name, - data_empty, - metadata=metadata) - - resp, body = self.object_client.get_object( - self.container_name, - object_name, - metadata=None) - - # Check only the existence of common headers with custom matcher - self.assertThat(resp, custom_matchers.ExistsAllResponseHeaders( - 'Object', 'GET')) - self.assertIn('x-object-manifest', resp) - - # Etag value of a large object is enclosed in double-quotations. - # This is a special case, therefore the formats of response headers - # are checked without a custom matcher. - self.assertTrue(resp['etag'].startswith('\"')) - self.assertTrue(resp['etag'].endswith('\"')) - self.assertTrue(resp['etag'].strip('\"').isalnum()) - self.assertTrue(re.match(r"^\d+\.?\d*\Z", resp['x-timestamp'])) - self.assertNotEmpty(resp['content-type']) - self.assertTrue(re.match("^tx[0-9a-f]{21}-[0-9a-f]{10}.*", - resp['x-trans-id'])) - self.assertNotEmpty(resp['date']) - self.assertEqual(resp['accept-ranges'], 'bytes') - self.assertEqual(resp['x-object-manifest'], - '%s/%s' % (self.container_name, object_name)) - - self.assertEqual(''.join(data_segments), body.decode()) - - @decorators.idempotent_id('c05b4013-e4de-47af-be84-e598062b16fc') - def test_get_object_with_if_match(self): - # get object with if_match - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes(10) - create_md5 = hashlib.md5(data).hexdigest() - create_metadata = {'Etag': create_md5} - self.object_client.create_object(self.container_name, - object_name, - data, - metadata=create_metadata) - - list_metadata = {'If-Match': create_md5} - resp, body = self.object_client.get_object( - self.container_name, - object_name, - metadata=list_metadata) - self.assertHeaders(resp, 'Object', 'GET') - self.assertEqual(body, data) - - @decorators.idempotent_id('be133639-e5d2-4313-9b1f-2d59fc054a16') - def test_get_object_with_if_modified_since(self): - # get object with if_modified_since - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - time_now = time.time() - self.object_client.create_object(self.container_name, - object_name, - data, - metadata=None) - - http_date = time.ctime(time_now - 86400) - list_metadata = {'If-Modified-Since': http_date} - resp, body = self.object_client.get_object( - self.container_name, - object_name, - metadata=list_metadata) - self.assertHeaders(resp, 'Object', 'GET') - self.assertEqual(body, data) - - @decorators.idempotent_id('641500d5-1612-4042-a04d-01fc4528bc30') - def test_get_object_with_if_none_match(self): - # get object with if_none_match - object_name = data_utils.rand_name(name='TestObject') - data = data_utils.random_bytes() - create_md5 = hashlib.md5(data).hexdigest() - create_metadata = {'Etag': create_md5} - self.object_client.create_object(self.container_name, - object_name, - data, - metadata=create_metadata) - - list_data = data_utils.random_bytes() - list_md5 = hashlib.md5(list_data).hexdigest() - list_metadata = {'If-None-Match': list_md5} - resp, body = self.object_client.get_object( - self.container_name, - object_name, - metadata=list_metadata) - self.assertHeaders(resp, 'Object', 'GET') - self.assertEqual(body, data) - - @decorators.idempotent_id('0aa1201c-10aa-467a-bee7-63cbdd463152') - def test_get_object_with_if_unmodified_since(self): - # get object with if_unmodified_since - object_name, data = self.create_object(self.container_name) - - time_now = time.time() - http_date = time.ctime(time_now + 86400) - list_metadata = {'If-Unmodified-Since': http_date} - resp, body = self.object_client.get_object( - self.container_name, - object_name, - metadata=list_metadata) - self.assertHeaders(resp, 'Object', 'GET') - self.assertEqual(body, data) - - @decorators.idempotent_id('94587078-475f-48f9-a40f-389c246e31cd') - def test_get_object_with_x_newest(self): - # get object with x_newest - object_name, data = self.create_object(self.container_name) - - list_metadata = {'X-Newest': 'true'} - resp, body = self.object_client.get_object( - self.container_name, - object_name, - metadata=list_metadata) - self.assertHeaders(resp, 'Object', 'GET') - self.assertEqual(body, data) - - @decorators.idempotent_id('1a9ab572-1b66-4981-8c21-416e2a5e6011') - def test_copy_object_in_same_container(self): - # create source object - src_object_name = data_utils.rand_name(name='SrcObject') - src_data = data_utils.random_bytes(size=len(src_object_name) * 2) - resp, _ = self.object_client.create_object(self.container_name, - src_object_name, - src_data) - # create destination object - dst_object_name = data_utils.rand_name(name='DstObject') - dst_data = data_utils.random_bytes(size=len(dst_object_name) * 3) - resp, _ = self.object_client.create_object(self.container_name, - dst_object_name, - dst_data) - # copy source object to destination - resp, _ = self.object_client.copy_object_in_same_container( - self.container_name, src_object_name, dst_object_name) - self.assertHeaders(resp, 'Object', 'PUT') - - # check data - resp, body = self.object_client.get_object(self.container_name, - dst_object_name) - self.assertEqual(body, src_data) - - @decorators.idempotent_id('2248abba-415d-410b-9c30-22dff9cd6e67') - def test_copy_object_to_itself(self): - # change the content type of an existing object - - # create object - object_name, _ = self.create_object(self.container_name) - # get the old content type - resp_tmp, _ = self.object_client.list_object_metadata( - self.container_name, object_name) - # change the content type of the object - metadata = {'content-type': 'text/plain; charset=UTF-8'} - self.assertNotEqual(resp_tmp['content-type'], metadata['content-type']) - resp, _ = self.object_client.copy_object_in_same_container( - self.container_name, object_name, object_name, metadata) - self.assertHeaders(resp, 'Object', 'PUT') - - # check the content type - resp, _ = self.object_client.list_object_metadata(self.container_name, - object_name) - self.assertEqual(resp['content-type'], metadata['content-type']) - - @decorators.idempotent_id('06f90388-2d0e-40aa-934c-e9a8833e958a') - def test_copy_object_2d_way(self): - # create source object - src_object_name = data_utils.rand_name(name='SrcObject') - src_data = data_utils.random_bytes(size=len(src_object_name) * 2) - resp, _ = self.object_client.create_object(self.container_name, - src_object_name, src_data) - # create destination object - dst_object_name = data_utils.rand_name(name='DstObject') - dst_data = data_utils.random_bytes(size=len(dst_object_name) * 3) - resp, _ = self.object_client.create_object(self.container_name, - dst_object_name, dst_data) - # copy source object to destination - resp, _ = self.object_client.copy_object_2d_way(self.container_name, - src_object_name, - dst_object_name) - self.assertHeaders(resp, 'Object', 'COPY') - self.assertEqual( - resp['x-copied-from'], - self.container_name + "/" + src_object_name) - - # check data - self._check_copied_obj(dst_object_name, src_data) - - @decorators.idempotent_id('aa467252-44f3-472a-b5ae-5b57c3c9c147') - def test_copy_object_across_containers(self): - # create a container to use as a source container - src_container_name = data_utils.rand_name(name='TestSourceContainer') - self.container_client.create_container(src_container_name) - self.containers.append(src_container_name) - # create a container to use as a destination container - dst_container_name = data_utils.rand_name( - name='TestDestinationContainer') - self.container_client.create_container(dst_container_name) - self.containers.append(dst_container_name) - # create object in source container - object_name = data_utils.rand_name(name='Object') - data = data_utils.random_bytes(size=len(object_name) * 2) - resp, _ = self.object_client.create_object(src_container_name, - object_name, data) - # set object metadata - meta_key = data_utils.rand_name(name='test') - meta_value = data_utils.rand_name(name='MetaValue') - orig_metadata = {meta_key: meta_value} - resp, _ = self.object_client.update_object_metadata(src_container_name, - object_name, - orig_metadata) - self.assertHeaders(resp, 'Object', 'POST') - - # copy object from source container to destination container - resp, _ = self.object_client.copy_object_across_containers( - src_container_name, object_name, dst_container_name, - object_name) - self.assertHeaders(resp, 'Object', 'PUT') - - # check if object is present in destination container - resp, body = self.object_client.get_object(dst_container_name, - object_name) - self.assertEqual(body, data) - actual_meta_key = 'x-object-meta-' + meta_key - self.assertIn(actual_meta_key, resp) - self.assertEqual(resp[actual_meta_key], meta_value) - - @decorators.idempotent_id('5a9e2cc6-85b6-46fc-916d-0cbb7a88e5fd') - def test_copy_object_with_x_fresh_metadata(self): - # create source object - metadata = {'x-object-meta-src': 'src_value'} - src_object_name, data = self.create_object(self.container_name, - metadata=metadata) - - # copy source object with x_fresh_metadata header - metadata = {'X-Fresh-Metadata': 'true'} - dst_object_name, resp = self._copy_object_2d(src_object_name, - metadata) - - self.assertHeaders(resp, 'Object', 'COPY') - - self.assertNotIn('x-object-meta-src', resp) - self.assertEqual(resp['x-copied-from'], - self.container_name + "/" + src_object_name) - - # check that destination object does NOT have any object-meta - self._check_copied_obj(dst_object_name, data, not_in_meta=["src"]) - - @decorators.idempotent_id('a28a8b99-e701-4d7e-9d84-3b66f121460b') - def test_copy_object_with_x_object_metakey(self): - # create source object - metadata = {'x-object-meta-src': 'src_value'} - src_obj_name, data = self.create_object(self.container_name, - metadata=metadata) - - # copy source object to destination with x-object-meta-key - metadata = {'x-object-meta-test': ''} - dst_obj_name, resp = self._copy_object_2d(src_obj_name, metadata) - - self.assertHeaders(resp, 'Object', 'COPY') - - expected = {'x-object-meta-test': '', - 'x-object-meta-src': 'src_value', - 'x-copied-from': self.container_name + "/" + src_obj_name} - for key, value in expected.items(): - self.assertIn(key, resp) - self.assertEqual(value, resp[key]) - - # check destination object - self._check_copied_obj(dst_obj_name, data, in_meta=["test", "src"]) - - @decorators.idempotent_id('edabedca-24c3-4322-9b70-d6d9f942a074') - def test_copy_object_with_x_object_meta(self): - # create source object - metadata = {'x-object-meta-src': 'src_value'} - src_obj_name, data = self.create_object(self.container_name, - metadata=metadata) - - # copy source object to destination with object metadata - metadata = {'x-object-meta-test': 'value'} - dst_obj_name, resp = self._copy_object_2d(src_obj_name, metadata) - - self.assertHeaders(resp, 'Object', 'COPY') - - expected = {'x-object-meta-test': 'value', - 'x-object-meta-src': 'src_value', - 'x-copied-from': self.container_name + "/" + src_obj_name} - for key, value in expected.items(): - self.assertIn(key, resp) - self.assertEqual(value, resp[key]) - - # check destination object - self._check_copied_obj(dst_obj_name, data, in_meta=["test", "src"]) - - @decorators.idempotent_id('e3e6a64a-9f50-4955-b987-6ce6767c97fb') - def test_object_upload_in_segments(self): - # create object - object_name = data_utils.rand_name(name='LObject') - data = data_utils.arbitrary_string() - segments = 10 - data_segments = [data + str(i) for i in range(segments)] - # uploading segments - for i in range(segments): - resp, _ = self.object_client.create_object_segments( - self.container_name, object_name, i, data_segments[i]) - # creating a manifest file - metadata = {'X-Object-Manifest': '%s/%s/' - % (self.container_name, object_name)} - resp, _ = self.object_client.create_object(self.container_name, - object_name, data='') - self.assertHeaders(resp, 'Object', 'PUT') - - resp, _ = self.object_client.update_object_metadata( - self.container_name, object_name, metadata, metadata_prefix='') - self.assertHeaders(resp, 'Object', 'POST') - - resp, _ = self.object_client.list_object_metadata( - self.container_name, object_name) - - # Etag value of a large object is enclosed in double-quotations. - # After etag quotes are checked they are removed and the response is - # checked if all common headers are present and well formatted - self.assertTrue(resp['etag'].startswith('\"')) - self.assertTrue(resp['etag'].endswith('\"')) - resp['etag'] = resp['etag'].strip('"') - self.assertHeaders(resp, 'Object', 'HEAD') - - self.assertIn('x-object-manifest', resp) - self.assertEqual(resp['x-object-manifest'], - '%s/%s/' % (self.container_name, object_name)) - - # downloading the object - resp, body = self.object_client.get_object( - self.container_name, object_name) - self.assertEqual(''.join(data_segments), body.decode()) - - @decorators.idempotent_id('50d01f12-526f-4360-9ac2-75dd508d7b68') - def test_get_object_if_different(self): - # http://en.wikipedia.org/wiki/HTTP_ETag - # Make a conditional request for an object using the If-None-Match - # header, it should get downloaded only if the local file is different, - # otherwise the response code should be 304 Not Modified - object_name, data = self.create_object(self.container_name) - # local copy is identical, no download - md5 = hashlib.md5(data).hexdigest() - headers = {'If-None-Match': md5} - url = "%s/%s" % (self.container_name, object_name) - resp, _ = self.object_client.get(url, headers=headers) - self.assertEqual(resp['status'], '304') - - # When the file is not downloaded from Swift server, response does - # not contain 'X-Timestamp' header. This is the special case, therefore - # the existence of response headers is checked without custom matcher. - self.assertIn('date', resp) - # Check only the format of common headers with custom matcher - self.assertThat(resp, custom_matchers.AreAllWellFormatted()) - - # local copy is different, download - local_data = "something different" - md5 = hashlib.md5(local_data.encode()).hexdigest() - headers = {'If-None-Match': md5} - resp, _ = self.object_client.get(url, headers=headers) - self.assertHeaders(resp, 'Object', 'GET') - - -class PublicObjectTest(base.BaseObjectTest): - - credentials = [['operator', CONF.object_storage.operator_role], - ['operator_alt', CONF.object_storage.operator_role]] - - @classmethod - def setup_credentials(cls): - super(PublicObjectTest, cls).setup_credentials() - cls.os = cls.os_roles_operator - cls.os_alt = cls.os_roles_operator_alt - - @classmethod - def setup_clients(cls): - super(PublicObjectTest, cls).setup_clients() - cls.identity_client_alt = cls.os_alt.identity_client - - def setUp(self): - super(PublicObjectTest, self).setUp() - self.container_name = data_utils.rand_name(name='TestContainer') - self.container_client.create_container(self.container_name) - - def tearDown(self): - self.delete_containers([self.container_name]) - super(PublicObjectTest, self).tearDown() - - @decorators.idempotent_id('07c9cf95-c0d4-4b49-b9c8-0ef2c9b27193') - def test_access_public_container_object_without_using_creds(self): - # make container public-readable and access an object in it object - # anonymously, without using credentials - - # update container metadata to make it publicly readable - cont_headers = {'X-Container-Read': '.r:*,.rlistings'} - resp_meta, body = self.container_client.update_container_metadata( - self.container_name, metadata=cont_headers, metadata_prefix='') - self.assertHeaders(resp_meta, 'Container', 'POST') - - # create object - object_name = data_utils.rand_name(name='Object') - data = data_utils.random_bytes(size=len(object_name)) - resp, _ = self.object_client.create_object(self.container_name, - object_name, data) - self.assertHeaders(resp, 'Object', 'PUT') - - # list container metadata - resp_meta, _ = self.container_client.list_container_metadata( - self.container_name) - self.assertHeaders(resp_meta, 'Container', 'HEAD') - - self.assertIn('x-container-read', resp_meta) - self.assertEqual(resp_meta['x-container-read'], '.r:*,.rlistings') - - # trying to get object with empty headers as it is public readable - self.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=None - ) - resp, body = self.object_client.get_object( - self.container_name, object_name) - self.assertHeaders(resp, 'Object', 'GET') - - self.assertEqual(body, data) - - @decorators.idempotent_id('54e2a2fe-42dc-491b-8270-8e4217dd4cdc') - def test_access_public_object_with_another_user_creds(self): - # make container public-readable and access an object in it using - # another user's credentials - cont_headers = {'X-Container-Read': '.r:*,.rlistings'} - resp_meta, body = self.container_client.update_container_metadata( - self.container_name, metadata=cont_headers, - metadata_prefix='') - self.assertHeaders(resp_meta, 'Container', 'POST') - - # create object - object_name = data_utils.rand_name(name='Object') - data = data_utils.random_bytes(size=len(object_name)) - resp, _ = self.object_client.create_object(self.container_name, - object_name, data) - self.assertHeaders(resp, 'Object', 'PUT') - - # list container metadata - resp, _ = self.container_client.list_container_metadata( - self.container_name) - self.assertHeaders(resp, 'Container', 'HEAD') - - self.assertIn('x-container-read', resp) - self.assertEqual(resp['x-container-read'], '.r:*,.rlistings') - - # get auth token of alternative user - alt_auth_data = self.identity_client_alt.auth_provider.auth_data - self.object_client.auth_provider.set_alt_auth_data( - request_part='headers', - auth_data=alt_auth_data - ) - # access object using alternate user creds - resp, body = self.object_client.get_object( - self.container_name, object_name) - self.assertHeaders(resp, 'Object', 'GET') - - self.assertEqual(body, data) diff --git a/tempest/api/object_storage/test_object_slo.py b/tempest/api/object_storage/test_object_slo.py deleted file mode 100644 index 894e42d5b..000000000 --- a/tempest/api/object_storage/test_object_slo.py +++ /dev/null @@ -1,177 +0,0 @@ -# Copyright 2013 NTT Corporation -# -# 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 hashlib - -from oslo_serialization import jsonutils as json - -from tempest.api.object_storage import base -from tempest.common import custom_matchers -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest import test - -# Each segment, except for the final one, must be at least 1 megabyte -MIN_SEGMENT_SIZE = 1024 * 1024 - - -class ObjectSloTest(base.BaseObjectTest): - - def setUp(self): - super(ObjectSloTest, self).setUp() - self.container_name = self.create_container() - self.objects = [] - - def tearDown(self): - for obj in self.objects: - test_utils.call_and_ignore_notfound_exc( - self.object_client.delete_object, - self.container_name, obj) - self.container_client.delete_container(self.container_name) - super(ObjectSloTest, self).tearDown() - - def _create_object(self, container_name, object_name, data, params=None): - resp, _ = self.object_client.create_object(container_name, - object_name, - data, - params) - self.objects.append(object_name) - - return resp - - def _create_manifest(self): - # Create a manifest file for SLO uploading - object_name = data_utils.rand_name(name='TestObject') - object_name_base_1 = object_name + '_01' - object_name_base_2 = object_name + '_02' - data_size = MIN_SEGMENT_SIZE - self.content = data_utils.random_bytes(data_size) - self._create_object(self.container_name, - object_name_base_1, - self.content) - self._create_object(self.container_name, - object_name_base_2, - self.content) - - path_object_1 = '/%s/%s' % (self.container_name, - object_name_base_1) - path_object_2 = '/%s/%s' % (self.container_name, - object_name_base_2) - data_manifest = [{'path': path_object_1, - 'etag': hashlib.md5(self.content).hexdigest(), - 'size_bytes': data_size}, - {'path': path_object_2, - 'etag': hashlib.md5(self.content).hexdigest(), - 'size_bytes': data_size}] - - return json.dumps(data_manifest) - - def _create_large_object(self): - # Create a large object for preparation of testing various SLO - # features - manifest = self._create_manifest() - - params = {'multipart-manifest': 'put'} - object_name = data_utils.rand_name(name='TestObject') - self._create_object(self.container_name, - object_name, - manifest, - params) - return object_name - - def _assertHeadersSLO(self, resp, method): - # When sending GET or HEAD requests to SLO the response contains - # 'X-Static-Large-Object' header - if method in ('GET', 'HEAD'): - self.assertIn('x-static-large-object', resp) - self.assertEqual(resp['x-static-large-object'], 'True') - - # Etag value of a large object is enclosed in double-quotations. - # After etag quotes are checked they are removed and the response is - # checked if all common headers are present and well formatted - self.assertTrue(resp['etag'].startswith('\"')) - self.assertTrue(resp['etag'].endswith('\"')) - resp['etag'] = resp['etag'].strip('"') - self.assertHeaders(resp, 'Object', method) - - @decorators.idempotent_id('2c3f24a6-36e8-4711-9aa2-800ee1fc7b5b') - @test.requires_ext(extension='slo', service='object') - def test_upload_manifest(self): - # create static large object from multipart manifest - manifest = self._create_manifest() - - params = {'multipart-manifest': 'put'} - object_name = data_utils.rand_name(name='TestObject') - resp = self._create_object(self.container_name, - object_name, - manifest, - params) - - self._assertHeadersSLO(resp, 'PUT') - - @decorators.idempotent_id('e69ad766-e1aa-44a2-bdd2-bf62c09c1456') - @test.requires_ext(extension='slo', service='object') - def test_list_large_object_metadata(self): - # list static large object metadata using multipart manifest - object_name = self._create_large_object() - - resp, _ = self.object_client.list_object_metadata( - self.container_name, - object_name) - - self._assertHeadersSLO(resp, 'HEAD') - - @decorators.idempotent_id('49bc49bc-dd1b-4c0f-904e-d9f10b830ee8') - @test.requires_ext(extension='slo', service='object') - def test_retrieve_large_object(self): - # list static large object using multipart manifest - object_name = self._create_large_object() - - resp, body = self.object_client.get_object( - self.container_name, - object_name) - - self._assertHeadersSLO(resp, 'GET') - - sum_data = self.content + self.content - self.assertEqual(body, sum_data) - - @decorators.idempotent_id('87b6dfa1-abe9-404d-8bf0-6c3751e6aa77') - @test.requires_ext(extension='slo', service='object') - def test_delete_large_object(self): - # delete static large object using multipart manifest - object_name = self._create_large_object() - - params_del = {'multipart-manifest': 'delete'} - resp, _ = self.object_client.delete_object( - self.container_name, - object_name, - params=params_del) - - # When deleting SLO using multipart manifest, the response contains - # not 'content-length' but 'transfer-encoding' header. This is the - # special case, therefore the existence of response headers is checked - # outside of custom matcher. - self.assertIn('transfer-encoding', resp) - self.assertIn('content-type', resp) - self.assertIn('x-trans-id', resp) - self.assertIn('date', resp) - - # Check only the format of common headers with custom matcher - self.assertThat(resp, custom_matchers.AreAllWellFormatted()) - - resp, body = self.container_client.list_container_contents( - self.container_name) - self.assertEqual(int(resp['x-container-object-count']), 0) diff --git a/tempest/api/object_storage/test_object_temp_url.py b/tempest/api/object_storage/test_object_temp_url.py deleted file mode 100644 index 91bc6770c..000000000 --- a/tempest/api/object_storage/test_object_temp_url.py +++ /dev/null @@ -1,188 +0,0 @@ -# Copyright (C) 2013 eNovance SAS -# -# 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 hashlib -import hmac -import time - -from six.moves.urllib import parse as urlparse - -from tempest.api.object_storage import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - - -class ObjectTempUrlTest(base.BaseObjectTest): - - @classmethod - def resource_setup(cls): - super(ObjectTempUrlTest, cls).resource_setup() - # create a container - cls.container_name = cls.create_container() - - # update account metadata - cls.key = 'Meta' - cls.metadatas = [] - metadata = {'Temp-URL-Key': cls.key} - cls.metadatas.append(metadata) - cls.account_client.create_update_or_delete_account_metadata( - create_update_metadata=metadata) - - # create an object - cls.object_name, cls.content = cls.create_object(cls.container_name) - - @classmethod - def resource_cleanup(cls): - for metadata in cls.metadatas: - cls.account_client.create_update_or_delete_account_metadata( - delete_metadata=metadata) - - cls.delete_containers() - - super(ObjectTempUrlTest, cls).resource_cleanup() - - def setUp(self): - super(ObjectTempUrlTest, self).setUp() - - # make sure the metadata has been set - account_client_metadata, _ = \ - self.account_client.list_account_metadata() - self.assertIn('x-account-meta-temp-url-key', - account_client_metadata) - self.assertEqual( - account_client_metadata['x-account-meta-temp-url-key'], - self.key) - - def _get_expiry_date(self, expiration_time=1000): - return int(time.time() + expiration_time) - - def _get_temp_url(self, container, object_name, method, expires, - key): - """Create the temporary URL.""" - - path = "%s/%s/%s" % ( - urlparse.urlparse(self.object_client.base_url).path, - container, object_name) - - hmac_body = '%s\n%s\n%s' % (method, expires, path) - sig = hmac.new( - key.encode(), hmac_body.encode(), hashlib.sha1 - ).hexdigest() - - url = "%s/%s?temp_url_sig=%s&temp_url_expires=%s" % (container, - object_name, - sig, expires) - - return url - - @decorators.idempotent_id('f91c96d4-1230-4bba-8eb9-84476d18d991') - @test.requires_ext(extension='tempurl', service='object') - def test_get_object_using_temp_url(self): - expires = self._get_expiry_date() - - # get a temp URL for the created object - url = self._get_temp_url(self.container_name, - self.object_name, "GET", - expires, self.key) - - # trying to get object using temp url within expiry time - resp, body = self.object_client.get(url) - self.assertHeaders(resp, 'Object', 'GET') - self.assertEqual(body, self.content) - - # Testing a HEAD on this Temp URL - resp, body = self.object_client.head(url) - self.assertHeaders(resp, 'Object', 'HEAD') - - @decorators.idempotent_id('671f9583-86bd-4128-a034-be282a68c5d8') - @test.requires_ext(extension='tempurl', service='object') - def test_get_object_using_temp_url_key_2(self): - key2 = 'Meta2-' - metadata = {'Temp-URL-Key-2': key2} - self.account_client.create_update_or_delete_account_metadata( - create_update_metadata=metadata) - self.metadatas.append(metadata) - - # make sure the metadata has been set - account_client_metadata, _ = \ - self.account_client.list_account_metadata() - self.assertIn('x-account-meta-temp-url-key-2', - account_client_metadata) - self.assertEqual( - account_client_metadata['x-account-meta-temp-url-key-2'], - key2) - - expires = self._get_expiry_date() - url = self._get_temp_url(self.container_name, - self.object_name, "GET", - expires, key2) - _, body = self.object_client.get(url) - self.assertEqual(body, self.content) - - @decorators.idempotent_id('9b08dade-3571-4152-8a4f-a4f2a873a735') - @test.requires_ext(extension='tempurl', service='object') - def test_put_object_using_temp_url(self): - new_data = data_utils.random_bytes(size=len(self.object_name)) - - expires = self._get_expiry_date() - url = self._get_temp_url(self.container_name, - self.object_name, "PUT", - expires, self.key) - - # trying to put random data in the object using temp url - resp, body = self.object_client.put(url, new_data, None) - self.assertHeaders(resp, 'Object', 'PUT') - - # Testing a HEAD on this Temp URL - resp, body = self.object_client.head(url) - self.assertHeaders(resp, 'Object', 'HEAD') - - # Validate that the content of the object has been modified - url = self._get_temp_url(self.container_name, - self.object_name, "GET", - expires, self.key) - - _, body = self.object_client.get(url) - self.assertEqual(body, new_data) - - @decorators.idempotent_id('249a0111-5ad3-4534-86a7-1993d55f9185') - @test.requires_ext(extension='tempurl', service='object') - def test_head_object_using_temp_url(self): - expires = self._get_expiry_date() - - # get a temp URL for the created object - url = self._get_temp_url(self.container_name, - self.object_name, "HEAD", - expires, self.key) - - # Testing a HEAD on this Temp URL - resp, _ = self.object_client.head(url) - self.assertHeaders(resp, 'Object', 'HEAD') - - @decorators.idempotent_id('9d9cfd90-708b-465d-802c-e4a8090b823d') - @test.requires_ext(extension='tempurl', service='object') - def test_get_object_using_temp_url_with_inline_query_parameter(self): - expires = self._get_expiry_date() - - # get a temp URL for the created object - url = self._get_temp_url(self.container_name, self.object_name, "GET", - expires, self.key) - url = url + '&inline' - - # trying to get object using temp url within expiry time - resp, body = self.object_client.get(url) - self.assertHeaders(resp, 'Object', 'GET') - self.assertEqual(body, self.content) - self.assertEqual(resp['content-disposition'], 'inline') diff --git a/tempest/api/object_storage/test_object_temp_url_negative.py b/tempest/api/object_storage/test_object_temp_url_negative.py deleted file mode 100644 index 3edaa8665..000000000 --- a/tempest/api/object_storage/test_object_temp_url_negative.py +++ /dev/null @@ -1,110 +0,0 @@ -# Copyright (C) 2013 eNovance SAS -# -# 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 hashlib -import hmac -import time - -from six.moves.urllib import parse as urlparse - -from tempest.api.object_storage import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - - -class ObjectTempUrlNegativeTest(base.BaseObjectTest): - - metadata = {} - containers = [] - - @classmethod - def resource_setup(cls): - super(ObjectTempUrlNegativeTest, cls).resource_setup() - - cls.container_name = cls.create_container() - - # update account metadata - cls.key = 'Meta' - cls.metadata = {'Temp-URL-Key': cls.key} - cls.account_client.create_update_or_delete_account_metadata( - create_update_metadata=cls.metadata) - cls.account_client_metadata, _ = \ - cls.account_client.list_account_metadata() - - @classmethod - def resource_cleanup(cls): - cls.account_client.create_update_or_delete_account_metadata( - delete_metadata=cls.metadata) - - cls.delete_containers() - - super(ObjectTempUrlNegativeTest, cls).resource_cleanup() - - def setUp(self): - super(ObjectTempUrlNegativeTest, self).setUp() - # make sure the metadata has been set - self.assertIn('x-account-meta-temp-url-key', - self.account_client_metadata) - - self.assertEqual( - self.account_client_metadata['x-account-meta-temp-url-key'], - self.key) - - # create object - self.object_name = data_utils.rand_name(name='ObjectTemp') - self.content = data_utils.arbitrary_string(size=len(self.object_name), - base_text=self.object_name) - self.object_client.create_object(self.container_name, - self.object_name, self.content) - - def _get_expiry_date(self, expiration_time=1000): - return int(time.time() + expiration_time) - - def _get_temp_url(self, container, object_name, method, expires, - key): - """Create the temporary URL.""" - - path = "%s/%s/%s" % ( - urlparse.urlparse(self.object_client.base_url).path, - container, object_name) - - hmac_body = '%s\n%s\n%s' % (method, expires, path) - sig = hmac.new( - key.encode(), hmac_body.encode(), hashlib.sha1 - ).hexdigest() - - url = "%s/%s?temp_url_sig=%s&temp_url_expires=%s" % (container, - object_name, - sig, expires) - - return url - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5a583aca-c804-41ba-9d9a-e7be132bdf0b') - @test.requires_ext(extension='tempurl', service='object') - def test_get_object_after_expiration_time(self): - - expires = self._get_expiry_date(1) - # get a temp URL for the created object - url = self._get_temp_url(self.container_name, - self.object_name, "GET", - expires, self.key) - - # temp URL is valid for 1 seconds, let's wait 2 - time.sleep(2) - - self.assertRaises(lib_exc.Unauthorized, - self.object_client.get, url) diff --git a/tempest/api/object_storage/test_object_version.py b/tempest/api/object_storage/test_object_version.py deleted file mode 100644 index dc0d179ec..000000000 --- a/tempest/api/object_storage/test_object_version.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 testtools - -from tempest.api.object_storage import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class ContainerTest(base.BaseObjectTest): - @classmethod - def resource_setup(cls): - super(ContainerTest, cls).resource_setup() - cls.containers = [] - - @classmethod - def resource_cleanup(cls): - cls.delete_containers() - super(ContainerTest, cls).resource_cleanup() - - def assertContainer(self, container, count, byte, versioned): - resp, _ = self.container_client.list_container_metadata(container) - self.assertHeaders(resp, 'Container', 'HEAD') - header_value = resp.get('x-container-object-count', 'Missing Header') - self.assertEqual(header_value, count) - header_value = resp.get('x-container-bytes-used', 'Missing Header') - self.assertEqual(header_value, byte) - header_value = resp.get('x-versions-location', 'Missing Header') - self.assertEqual(header_value, versioned) - - @decorators.idempotent_id('a151e158-dcbf-4a1f-a1e7-46cd65895a6f') - @testtools.skipIf( - not CONF.object_storage_feature_enabled.object_versioning, - 'Object-versioning is disabled') - def test_versioned_container(self): - # create container - vers_container_name = data_utils.rand_name(name='TestVersionContainer') - resp, body = self.container_client.create_container( - vers_container_name) - self.containers.append(vers_container_name) - self.assertHeaders(resp, 'Container', 'PUT') - self.assertContainer(vers_container_name, '0', '0', 'Missing Header') - - base_container_name = data_utils.rand_name(name='TestBaseContainer') - headers = {'X-versions-Location': vers_container_name} - resp, body = self.container_client.create_container( - base_container_name, - metadata=headers, - metadata_prefix='') - self.containers.append(base_container_name) - self.assertHeaders(resp, 'Container', 'PUT') - self.assertContainer(base_container_name, '0', '0', - vers_container_name) - object_name = data_utils.rand_name(name='TestObject') - # create object - data_1 = data_utils.random_bytes() - resp, _ = self.object_client.create_object(base_container_name, - object_name, data_1) - # create 2nd version of object - data_2 = data_utils.random_bytes() - resp, _ = self.object_client.create_object(base_container_name, - object_name, data_2) - resp, body = self.object_client.get_object(base_container_name, - object_name) - self.assertEqual(body, data_2) - # delete object version 2 - resp, _ = self.object_client.delete_object(base_container_name, - object_name) - self.assertContainer(base_container_name, '1', '1024', - vers_container_name) - resp, body = self.object_client.get_object(base_container_name, - object_name) - self.assertEqual(body, data_1) - # delete object version 1 - resp, _ = self.object_client.delete_object(base_container_name, - object_name) - # containers should be empty - self.assertContainer(base_container_name, '0', '0', - vers_container_name) - self.assertContainer(vers_container_name, '0', '0', - 'Missing Header') diff --git a/tempest/api/volume/__init__.py b/tempest/api/volume/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/volume/admin/__init__.py b/tempest/api/volume/admin/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/api/volume/admin/test_backends_capabilities.py b/tempest/api/volume/admin/test_backends_capabilities.py deleted file mode 100644 index 607fc43e6..000000000 --- a/tempest/api/volume/admin/test_backends_capabilities.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# 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 operator - -from tempest.api.volume import base -from tempest.lib import decorators - - -class BackendsCapabilitiesAdminTestsJSON(base.BaseVolumeAdminTest): - - CAPABILITIES = ('namespace', - 'vendor_name', - 'volume_backend_name', - 'pool_name', - 'driver_version', - 'storage_protocol', - 'display_name', - 'description', - 'visibility', - 'properties') - - @classmethod - def resource_setup(cls): - super(BackendsCapabilitiesAdminTestsJSON, cls).resource_setup() - # Get host list, formation: host@backend-name - cls.hosts = [ - pool['name'] for pool in - cls.admin_scheduler_stats_client.list_pools()['pools'] - ] - - @decorators.idempotent_id('3750af44-5ea2-4cd4-bc3e-56e7e6caf854') - def test_get_capabilities_backend(self): - # Test backend properties - backend = self.admin_capabilities_client.show_backend_capabilities( - self.hosts[0]) - - # Verify getting capabilities parameters from a backend - for key in self.CAPABILITIES: - self.assertIn(key, backend) - - @decorators.idempotent_id('a9035743-d46a-47c5-9cb7-3c80ea16dea0') - def test_compare_volume_stats_values(self): - # Test values comparison between show_backend_capabilities - # to show_pools - VOLUME_STATS = ('vendor_name', - 'volume_backend_name', - 'storage_protocol') - - # Get list backend capabilities using show_pools - cinder_pools = [ - pool['capabilities'] for pool in - self.admin_scheduler_stats_client.list_pools(detail=True)['pools'] - ] - - # Get list backends capabilities using show_backend_capabilities - capabilities = [ - self.admin_capabilities_client.show_backend_capabilities( - host=host) for host in self.hosts - ] - - # Returns a tuple of VOLUME_STATS values - expected_list = list(map(operator.itemgetter(*VOLUME_STATS), - cinder_pools)) - observed_list = list(map(operator.itemgetter(*VOLUME_STATS), - capabilities)) - self.assertEqual(expected_list, observed_list) diff --git a/tempest/api/volume/admin/test_group_types.py b/tempest/api/volume/admin/test_group_types.py deleted file mode 100644 index 0df5fbd88..000000000 --- a/tempest/api/volume/admin/test_group_types.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright (C) 2017 Dell Inc. or its subsidiaries. -# 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 tempest.api.volume import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class GroupTypesTest(base.BaseVolumeAdminTest): - _api_version = 3 - min_microversion = '3.11' - max_microversion = 'latest' - - @decorators.idempotent_id('dd71e5f9-393e-4d4f-90e9-fa1b8d278864') - def test_group_type_create_list_show(self): - # Create/list/show group type. - name = data_utils.rand_name(self.__class__.__name__ + '-group-type') - description = data_utils.rand_name("group-type-description") - group_specs = {"consistent_group_snapshot_enabled": " False"} - params = {'name': name, - 'description': description, - 'group_specs': group_specs, - 'is_public': True} - body = self.create_group_type(**params) - self.assertIn('name', body) - err_msg = ("The created group_type %(var)s is not equal to the " - "requested %(var)s") - self.assertEqual(name, body['name'], err_msg % {"var": "name"}) - self.assertEqual(description, body['description'], - err_msg % {"var": "description"}) - - group_list = ( - self.admin_group_types_client.list_group_types()['group_types']) - self.assertIsInstance(group_list, list) - self.assertNotEmpty(group_list) - - fetched_group_type = self.admin_group_types_client.show_group_type( - body['id'])['group_type'] - for key in params.keys(): - self.assertEqual(params[key], fetched_group_type[key], - '%s of the fetched group_type is different ' - 'from the created group_type' % key) diff --git a/tempest/api/volume/admin/test_groups.py b/tempest/api/volume/admin/test_groups.py deleted file mode 100644 index 8609bdb30..000000000 --- a/tempest/api/volume/admin/test_groups.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright (C) 2017 Dell Inc. or its subsidiaries. -# 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 tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class GroupsTest(base.BaseVolumeAdminTest): - _api_version = 3 - min_microversion = '3.14' - max_microversion = 'latest' - - def _delete_group(self, grp_id, delete_volumes=True): - self.admin_groups_client.delete_group(grp_id, delete_volumes) - vols = self.admin_volume_client.list_volumes(detail=True)['volumes'] - for vol in vols: - if vol['group_id'] == grp_id: - self.admin_volume_client.wait_for_resource_deletion(vol['id']) - self.admin_groups_client.wait_for_resource_deletion(grp_id) - - @decorators.idempotent_id('4b111d28-b73d-4908-9bd2-03dc2992e4d4') - def test_group_create_show_list_delete(self): - # Create volume type - volume_type = self.create_volume_type() - - # Create group type - group_type = self.create_group_type() - - # Create group - grp1_name = data_utils.rand_name('Group1') - grp1 = self.admin_groups_client.create_group( - group_type=group_type['id'], - volume_types=[volume_type['id']], - name=grp1_name)['group'] - waiters.wait_for_volume_resource_status( - self.admin_groups_client, grp1['id'], 'available') - grp1_id = grp1['id'] - - grp2_name = data_utils.rand_name('Group2') - grp2 = self.admin_groups_client.create_group( - group_type=group_type['id'], - volume_types=[volume_type['id']], - name=grp2_name)['group'] - waiters.wait_for_volume_resource_status( - self.admin_groups_client, grp2['id'], 'available') - grp2_id = grp2['id'] - - # Create volume - vol1_name = data_utils.rand_name("volume") - params = {'name': vol1_name, - 'volume_type': volume_type['id'], - 'group_id': grp1['id'], - 'size': CONF.volume.volume_size} - vol1 = self.admin_volume_client.create_volume(**params)['volume'] - self.assertEqual(grp1['id'], vol1['group_id']) - waiters.wait_for_volume_resource_status( - self.admin_volume_client, vol1['id'], 'available') - vol1_id = vol1['id'] - - # Get a given group - grp1 = self.admin_groups_client.show_group(grp1['id'])['group'] - self.assertEqual(grp1_name, grp1['name']) - self.assertEqual(grp1_id, grp1['id']) - - grp2 = self.admin_groups_client.show_group(grp2['id'])['group'] - self.assertEqual(grp2_name, grp2['name']) - self.assertEqual(grp2_id, grp2['id']) - - # Get all groups with detail - grps = self.admin_groups_client.list_groups( - detail=True)['groups'] - filtered_grps = [g for g in grps if g['id'] in [grp1_id, grp2_id]] - self.assertEqual(2, len(filtered_grps)) - for grp in filtered_grps: - self.assertEqual([volume_type['id']], grp['volume_types']) - self.assertEqual(group_type['id'], grp['group_type']) - - vols = self.admin_volume_client.list_volumes( - detail=True)['volumes'] - filtered_vols = [v for v in vols if v['id'] in [vol1_id]] - self.assertEqual(1, len(filtered_vols)) - for vol in filtered_vols: - self.assertEqual(grp1_id, vol['group_id']) - - # Delete group - # grp1 has a volume so delete_volumes flag is set to True by default - self._delete_group(grp1_id) - # grp2 is empty so delete_volumes flag can be set to False - self._delete_group(grp2_id, delete_volumes=False) - grps = self.admin_groups_client.list_groups( - detail=True)['groups'] - self.assertEmpty(grps) diff --git a/tempest/api/volume/admin/test_multi_backend.py b/tempest/api/volume/admin/test_multi_backend.py deleted file mode 100644 index 2db801025..000000000 --- a/tempest/api/volume/admin/test_multi_backend.py +++ /dev/null @@ -1,141 +0,0 @@ -# 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 six -from tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class VolumeMultiBackendTest(base.BaseVolumeAdminTest): - - @classmethod - def skip_checks(cls): - super(VolumeMultiBackendTest, cls).skip_checks() - - if not CONF.volume_feature_enabled.multi_backend: - raise cls.skipException("Cinder multi-backend feature disabled") - - @classmethod - def resource_setup(cls): - super(VolumeMultiBackendTest, cls).resource_setup() - - # read backend name from a list . - backend_names = set(CONF.volume.backend_names) - - cls.volume_id_list_with_prefix = [] - cls.volume_id_list_without_prefix = [] - - # Volume/Type creation (uses volume_backend_name) - # It is not allowed to create the same backend name twice - if len(backend_names) < 2: - raise cls.skipException("Requires at least two different " - "backend names") - for backend_name in backend_names: - # Volume/Type creation (uses backend_name) - cls._create_type_and_volume(backend_name, False) - # Volume/Type creation (uses capabilities:volume_backend_name) - cls._create_type_and_volume(backend_name, True) - - @classmethod - def _create_type_and_volume(cls, backend_name_key, with_prefix): - # Volume/Type creation - type_name = data_utils.rand_name(cls.__name__ + '-Type') - vol_name = data_utils.rand_name(cls.__name__ + '-Volume') - spec_key_with_prefix = "capabilities:volume_backend_name" - spec_key_without_prefix = "volume_backend_name" - if with_prefix: - extra_specs = {spec_key_with_prefix: backend_name_key} - else: - extra_specs = {spec_key_without_prefix: backend_name_key} - cls.create_volume_type(name=type_name, - extra_specs=extra_specs) - - params = {'name': vol_name, 'volume_type': type_name, - 'size': CONF.volume.volume_size} - cls.volume = cls.admin_volume_client.create_volume( - **params)['volume'] - if with_prefix: - cls.volume_id_list_with_prefix.append(cls.volume['id']) - else: - cls.volume_id_list_without_prefix.append( - cls.volume['id']) - waiters.wait_for_volume_resource_status(cls.admin_volume_client, - cls.volume['id'], 'available') - - @classmethod - def resource_cleanup(cls): - # volumes deletion - vid_prefix = getattr(cls, 'volume_id_list_with_prefix', []) - for volume_id in vid_prefix: - cls.admin_volume_client.delete_volume(volume_id) - cls.admin_volume_client.wait_for_resource_deletion(volume_id) - - vid_no_pre = getattr(cls, 'volume_id_list_without_prefix', []) - for volume_id in vid_no_pre: - cls.admin_volume_client.delete_volume(volume_id) - cls.admin_volume_client.wait_for_resource_deletion(volume_id) - - super(VolumeMultiBackendTest, cls).resource_cleanup() - - @decorators.idempotent_id('c1a41f3f-9dad-493e-9f09-3ff197d477cc') - def test_backend_name_reporting(self): - # get volume id which created by type without prefix - for volume_id in self.volume_id_list_without_prefix: - self._test_backend_name_reporting_by_volume_id(volume_id) - - @decorators.idempotent_id('f38e647f-ab42-4a31-a2e7-ca86a6485215') - def test_backend_name_reporting_with_prefix(self): - # get volume id which created by type with prefix - for volume_id in self.volume_id_list_with_prefix: - self._test_backend_name_reporting_by_volume_id(volume_id) - - @decorators.idempotent_id('46435ab1-a0af-4401-8373-f14e66b0dd58') - def test_backend_name_distinction(self): - # get volume ids which created by type without prefix - self._test_backend_name_distinction(self.volume_id_list_without_prefix) - - @decorators.idempotent_id('4236305b-b65a-4bfc-a9d2-69cb5b2bf2ed') - def test_backend_name_distinction_with_prefix(self): - # get volume ids which created by type without prefix - self._test_backend_name_distinction(self.volume_id_list_with_prefix) - - def _get_volume_host(self, volume_id): - return self.admin_volume_client.show_volume( - volume_id)['volume']['os-vol-host-attr:host'] - - def _test_backend_name_reporting_by_volume_id(self, volume_id): - # this test checks if os-vol-attr:host is populated correctly after - # the multi backend feature has been enabled - # if multi-backend is enabled: os-vol-attr:host should be like: - # host@backend_name - volume = self.admin_volume_client.show_volume(volume_id)['volume'] - - volume1_host = volume['os-vol-host-attr:host'] - msg = ("multi-backend reporting incorrect values for volume %s" % - volume_id) - self.assertGreater(len(volume1_host.split("@")), 1, msg) - - def _test_backend_name_distinction(self, volume_id_list): - # this test checks that the volumes created at setUp don't - # belong to the same backend (if they are, than the - # volume backend distinction is not working properly) - volume_hosts = [self._get_volume_host(volume) for volume in - volume_id_list] - # assert that volumes are each created on separate hosts: - msg = ("volumes %s were created in the same backend" % ", " - .join(volume_hosts)) - six.assertCountEqual(self, volume_hosts, set(volume_hosts), msg) diff --git a/tempest/api/volume/admin/test_qos.py b/tempest/api/volume/admin/test_qos.py deleted file mode 100644 index e31c0ef29..000000000 --- a/tempest/api/volume/admin/test_qos.py +++ /dev/null @@ -1,159 +0,0 @@ -# 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 tempest.api.volume import base -from tempest.common import waiters -from tempest.lib.common.utils import data_utils as utils -from tempest.lib import decorators - - -class QosSpecsTestJSON(base.BaseVolumeAdminTest): - """Test the Cinder QoS-specs. - - Tests for create, list, delete, show, associate, - disassociate, set/unset key APIs. - """ - - @classmethod - def resource_setup(cls): - super(QosSpecsTestJSON, cls).resource_setup() - # Create admin qos client - # Create a test shared qos-specs for tests - cls.qos_name = utils.rand_name(cls.__name__ + '-QoS') - cls.qos_consumer = 'front-end' - - cls.created_qos = cls.create_test_qos_specs(cls.qos_name, - cls.qos_consumer, - read_iops_sec='2000') - - def _create_delete_test_qos_with_given_consumer(self, consumer): - name = utils.rand_name(self.__class__.__name__ + '-qos') - qos = {'name': name, 'consumer': consumer} - body = self.create_test_qos_specs(name, consumer) - for key in ['name', 'consumer']: - self.assertEqual(qos[key], body[key]) - - self.admin_volume_qos_client.delete_qos(body['id']) - self.admin_volume_qos_client.wait_for_resource_deletion(body['id']) - - # validate the deletion - list_qos = self.admin_volume_qos_client.list_qos()['qos_specs'] - self.assertNotIn(body, list_qos) - - def _test_associate_qos(self, vol_type_id): - self.admin_volume_qos_client.associate_qos( - self.created_qos['id'], vol_type_id) - - @decorators.idempotent_id('7e15f883-4bef-49a9-95eb-f94209a1ced1') - def test_create_delete_qos_with_front_end_consumer(self): - """Tests the creation and deletion of QoS specs - - With consumer as front end - """ - self._create_delete_test_qos_with_given_consumer('front-end') - - @decorators.idempotent_id('b115cded-8f58-4ee4-aab5-9192cfada08f') - def test_create_delete_qos_with_back_end_consumer(self): - """Tests the creation and deletion of QoS specs - - With consumer as back-end - """ - self._create_delete_test_qos_with_given_consumer('back-end') - - @decorators.idempotent_id('f88d65eb-ea0d-487d-af8d-71f4011575a4') - def test_create_delete_qos_with_both_consumer(self): - """Tests the creation and deletion of QoS specs - - With consumer as both front end and back end - """ - self._create_delete_test_qos_with_given_consumer('both') - - @decorators.idempotent_id('7aa214cc-ac1a-4397-931f-3bb2e83bb0fd') - def test_get_qos(self): - """Tests the detail of a given qos-specs""" - body = self.admin_volume_qos_client.show_qos( - self.created_qos['id'])['qos_specs'] - self.assertEqual(self.qos_name, body['name']) - self.assertEqual(self.qos_consumer, body['consumer']) - - @decorators.idempotent_id('75e04226-bcf7-4595-a34b-fdf0736f38fc') - def test_list_qos(self): - """Tests the list of all qos-specs""" - body = self.admin_volume_qos_client.list_qos()['qos_specs'] - self.assertIn(self.created_qos, body) - - @decorators.idempotent_id('ed00fd85-4494-45f2-8ceb-9e2048919aed') - def test_set_unset_qos_key(self): - """Test the addition of a specs key to qos-specs""" - args = {'iops_bytes': '500'} - body = self.admin_volume_qos_client.set_qos_key( - self.created_qos['id'], - iops_bytes='500')['qos_specs'] - self.assertEqual(args, body) - body = self.admin_volume_qos_client.show_qos( - self.created_qos['id'])['qos_specs'] - self.assertEqual(args['iops_bytes'], body['specs']['iops_bytes']) - - # test the deletion of a specs key from qos-specs - keys = ['iops_bytes'] - self.admin_volume_qos_client.unset_qos_key(self.created_qos['id'], - keys) - operation = 'qos-key-unset' - waiters.wait_for_qos_operations(self.admin_volume_qos_client, - self.created_qos['id'], - operation, keys) - body = self.admin_volume_qos_client.show_qos( - self.created_qos['id'])['qos_specs'] - self.assertNotIn(keys[0], body['specs']) - - @decorators.idempotent_id('1dd93c76-6420-485d-a771-874044c416ac') - def test_associate_disassociate_qos(self): - """Test the following operations : - - 1. associate_qos - 2. get_association_qos - 3. disassociate_qos - 4. disassociate_all_qos - """ - - # create a test volume-type - vol_type = [] - for _ in range(0, 3): - vol_type.append(self.create_volume_type()) - - # associate the qos-specs with volume-types - for i in range(0, 3): - self._test_associate_qos(vol_type[i]['id']) - - # get the association of the qos-specs - body = self.admin_volume_qos_client.show_association_qos( - self.created_qos['id'])['qos_associations'] - associations = [association['id'] for association in body] - for i in range(0, 3): - self.assertIn(vol_type[i]['id'], associations) - - # disassociate a volume-type with qos-specs - self.admin_volume_qos_client.disassociate_qos( - self.created_qos['id'], vol_type[0]['id']) - operation = 'disassociate' - waiters.wait_for_qos_operations(self.admin_volume_qos_client, - self.created_qos['id'], operation, - vol_type[0]['id']) - - # disassociate all volume-types from qos-specs - self.admin_volume_qos_client.disassociate_all_qos( - self.created_qos['id']) - operation = 'disassociate-all' - waiters.wait_for_qos_operations(self.admin_volume_qos_client, - self.created_qos['id'], operation) diff --git a/tempest/api/volume/admin/test_snapshot_manage.py b/tempest/api/volume/admin/test_snapshot_manage.py deleted file mode 100644 index 9ff7160a4..000000000 --- a/tempest/api/volume/admin/test_snapshot_manage.py +++ /dev/null @@ -1,98 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# 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 tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions - -CONF = config.CONF - - -class SnapshotManageAdminTest(base.BaseVolumeAdminTest): - """Unmanage & manage snapshots - - This feature provides the ability to import/export volume snapshot - from one Cinder to another and to import snapshots that have not been - managed by Cinder from a storage back end to Cinder - """ - - @classmethod - def skip_checks(cls): - super(SnapshotManageAdminTest, cls).skip_checks() - - if not CONF.volume_feature_enabled.manage_snapshot: - raise cls.skipException("Manage snapshot tests are disabled") - - if len(CONF.volume.manage_snapshot_ref) != 2: - msg = ("Manage snapshot ref is not correctly configured, " - "it should be a list of two elements") - raise exceptions.InvalidConfiguration(msg) - - @decorators.idempotent_id('0132f42d-0147-4b45-8501-cc504bbf7810') - def test_unmanage_manage_snapshot(self): - # Create a volume - volume = self.create_volume() - - # Create a snapshot - snapshot = self.create_snapshot(volume_id=volume['id']) - - # Unmanage the snapshot - # Unmanage snapshot function works almost the same as delete snapshot, - # but it does not delete the snapshot data - self.admin_snapshots_client.unmanage_snapshot(snapshot['id']) - self.admin_snapshots_client.wait_for_resource_deletion(snapshot['id']) - - # Verify the original snapshot does not exist in snapshot list - params = {'all_tenants': 1} - all_snapshots = self.admin_snapshots_client.list_snapshots( - detail=True, params=params)['snapshots'] - self.assertNotIn(snapshot['id'], [v['id'] for v in all_snapshots]) - - # Manage the snapshot - name = data_utils.rand_name(self.__class__.__name__ + - '-Managed-Snapshot') - description = data_utils.rand_name(self.__class__.__name__ + - '-Managed-Snapshot-Description') - metadata = {"manage-snap-meta1": "value1", - "manage-snap-meta2": "value2", - "manage-snap-meta3": "value3"} - snapshot_ref = { - 'volume_id': volume['id'], - 'ref': {CONF.volume.manage_snapshot_ref[0]: - CONF.volume.manage_snapshot_ref[1] % snapshot['id']}, - 'name': name, - 'description': description, - 'metadata': metadata - } - new_snapshot = self.admin_snapshot_manage_client.manage_snapshot( - **snapshot_ref)['snapshot'] - self.addCleanup(self.delete_snapshot, new_snapshot['id'], - self.admin_snapshots_client) - - # Wait for the snapshot to be available after manage operation - waiters.wait_for_volume_resource_status(self.admin_snapshots_client, - new_snapshot['id'], - 'available') - - # Verify the managed snapshot has the expected parent volume - # and the expected field values. - new_snapshot_info = self.admin_snapshots_client.show_snapshot( - new_snapshot['id'])['snapshot'] - self.assertEqual(snapshot['size'], new_snapshot_info['size']) - for key in ['volume_id', 'name', 'description', 'metadata']: - self.assertEqual(snapshot_ref[key], new_snapshot_info[key]) diff --git a/tempest/api/volume/admin/test_snapshots_actions.py b/tempest/api/volume/admin/test_snapshots_actions.py deleted file mode 100644 index 471f39a11..000000000 --- a/tempest/api/volume/admin/test_snapshots_actions.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD -# 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 tempest.api.volume import base -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class SnapshotsActionsTest(base.BaseVolumeAdminTest): - @classmethod - def skip_checks(cls): - super(SnapshotsActionsTest, cls).skip_checks() - if not CONF.volume_feature_enabled.snapshot: - raise cls.skipException("Cinder snapshot feature disabled") - - @classmethod - def resource_setup(cls): - super(SnapshotsActionsTest, cls).resource_setup() - - # Create a test shared volume for tests - cls.volume = cls.create_volume() - - # Create a test shared snapshot for tests - cls.snapshot = cls.create_snapshot(volume_id=cls.volume['id']) - - def tearDown(self): - # Set snapshot's status to available after test - status = 'available' - snapshot_id = self.snapshot['id'] - self.admin_snapshots_client.reset_snapshot_status(snapshot_id, - status) - super(SnapshotsActionsTest, self).tearDown() - - def _create_reset_and_force_delete_temp_snapshot(self, status=None): - # Create snapshot, reset snapshot status, - # and force delete temp snapshot - temp_snapshot = self.create_snapshot(volume_id=self.volume['id']) - if status: - self.admin_snapshots_client.\ - reset_snapshot_status(temp_snapshot['id'], status) - self.admin_snapshots_client.\ - force_delete_snapshot(temp_snapshot['id']) - self.snapshots_client.wait_for_resource_deletion(temp_snapshot['id']) - - def _get_progress_alias(self): - return 'os-extended-snapshot-attributes:progress' - - @decorators.idempotent_id('3e13ca2f-48ea-49f3-ae1a-488e9180d535') - def test_reset_snapshot_status(self): - # Reset snapshot status to creating - status = 'creating' - self.admin_snapshots_client.\ - reset_snapshot_status(self.snapshot['id'], status) - snapshot_get = self.admin_snapshots_client.show_snapshot( - self.snapshot['id'])['snapshot'] - self.assertEqual(status, snapshot_get['status']) - - @decorators.idempotent_id('41288afd-d463-485e-8f6e-4eea159413eb') - def test_update_snapshot_status(self): - # Reset snapshot status to creating - status = 'creating' - self.admin_snapshots_client.\ - reset_snapshot_status(self.snapshot['id'], status) - - # Update snapshot status to error - progress = '80%' - status = 'error' - progress_alias = self._get_progress_alias() - self.snapshots_client.update_snapshot_status(self.snapshot['id'], - status=status, - progress=progress) - snapshot_get = self.admin_snapshots_client.show_snapshot( - self.snapshot['id'])['snapshot'] - self.assertEqual(status, snapshot_get['status']) - self.assertEqual(progress, snapshot_get[progress_alias]) - - @decorators.idempotent_id('05f711b6-e629-4895-8103-7ca069f2073a') - def test_snapshot_force_delete_when_snapshot_is_creating(self): - # test force delete when status of snapshot is creating - self._create_reset_and_force_delete_temp_snapshot('creating') - - @decorators.idempotent_id('92ce8597-b992-43a1-8868-6316b22a969e') - def test_snapshot_force_delete_when_snapshot_is_deleting(self): - # test force delete when status of snapshot is deleting - self._create_reset_and_force_delete_temp_snapshot('deleting') - - @decorators.idempotent_id('645a4a67-a1eb-4e8e-a547-600abac1525d') - def test_snapshot_force_delete_when_snapshot_is_error(self): - # test force delete when status of snapshot is error - self._create_reset_and_force_delete_temp_snapshot('error') - - @decorators.idempotent_id('bf89080f-8129-465e-9327-b2f922666ba5') - def test_snapshot_force_delete_when_snapshot_is_error_deleting(self): - # test force delete when status of snapshot is error_deleting - self._create_reset_and_force_delete_temp_snapshot('error_deleting') diff --git a/tempest/api/volume/admin/test_user_messages.py b/tempest/api/volume/admin/test_user_messages.py deleted file mode 100755 index 20c3538cd..000000000 --- a/tempest/api/volume/admin/test_user_messages.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright 2016 Andrew Kerr -# 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 tempest.api.volume import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - -MESSAGE_KEYS = [ - 'created_at', - 'event_id', - 'guaranteed_until', - 'id', - 'message_level', - 'request_id', - 'resource_type', - 'resource_uuid', - 'user_message', - 'links'] - - -class UserMessagesTest(base.BaseVolumeAdminTest): - _api_version = 3 - min_microversion = '3.3' - max_microversion = 'latest' - - def _create_user_message(self): - """Trigger a 'no valid host' situation to generate a message.""" - bad_protocol = data_utils.rand_name('storage_protocol') - bad_vendor = data_utils.rand_name('vendor_name') - extra_specs = {'storage_protocol': bad_protocol, - 'vendor_name': bad_vendor} - vol_type_name = data_utils.rand_name( - self.__class__.__name__ + '-volume-type') - bogus_type = self.create_volume_type( - name=vol_type_name, extra_specs=extra_specs) - params = {'volume_type': bogus_type['id'], - 'size': CONF.volume.volume_size} - volume = self.create_volume(wait_until="error", **params) - messages = self.messages_client.list_messages()['messages'] - message_id = None - for message in messages: - if message['resource_uuid'] == volume['id']: - message_id = message['id'] - break - self.assertIsNotNone(message_id, 'No user message generated for ' - 'volume %s' % volume['id']) - return message_id - - @decorators.idempotent_id('50f29e6e-f363-42e1-8ad1-f67ae7fd4d5a') - def test_list_messages(self): - self._create_user_message() - messages = self.messages_client.list_messages()['messages'] - self.assertIsInstance(messages, list) - for message in messages: - for key in MESSAGE_KEYS: - self.assertIn(key, message.keys(), - 'Missing expected key %s' % key) - - @decorators.idempotent_id('55a4a61e-c7b2-4ba0-a05d-b914bdef3070') - def test_show_message(self): - message_id = self._create_user_message() - self.addCleanup(self.messages_client.delete_message, message_id) - - message = self.messages_client.show_message(message_id)['message'] - - for key in MESSAGE_KEYS: - self.assertIn(key, message.keys(), 'Missing expected key %s' % key) - - @decorators.idempotent_id('c6eb6901-cdcc-490f-b735-4fe251842aed') - def test_delete_message(self): - message_id = self._create_user_message() - self.messages_client.delete_message(message_id) - self.messages_client.wait_for_resource_deletion(message_id) diff --git a/tempest/api/volume/admin/test_volume_hosts.py b/tempest/api/volume/admin/test_volume_hosts.py deleted file mode 100644 index e4ec44264..000000000 --- a/tempest/api/volume/admin/test_volume_hosts.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 random - -from tempest.api.volume import base -from tempest.lib import decorators - - -class VolumeHostsAdminTestsJSON(base.BaseVolumeAdminTest): - - @decorators.idempotent_id('d5f3efa2-6684-4190-9ced-1c2f526352ad') - def test_list_hosts(self): - hosts = self.admin_hosts_client.list_hosts()['hosts'] - self.assertGreaterEqual(len(hosts), 2, - "The count of volume hosts is < 2, " - "response of list hosts is: %s" % hosts) - - # Check elements in volume hosts list - host_list_keys = ['service', 'host_name', 'last-update', - 'zone', 'service-status', 'service-state'] - for host in hosts: - for key in host_list_keys: - self.assertIn(key, host) - - @decorators.idempotent_id('21168d57-b373-4b71-a3ac-f2c88f0c5d31') - def test_show_host(self): - hosts = self.admin_hosts_client.list_hosts()['hosts'] - self.assertGreaterEqual(len(hosts), 2, - "The count of volume hosts is < 2, " - "response of list hosts is: %s" % hosts) - - # Note(jeremyZ): Host in volume is always presented in two formats: - # or @. Since Mitaka is EOL, - # both formats can be chosen for test. - host_names = [host['host_name'] for host in hosts] - self.assertNotEmpty(host_names, "No available volume host is found, " - "all hosts that found are: %s" % hosts) - - # Choose a random host to get and check its elements - host_details = self.admin_hosts_client.show_host( - random.choice(host_names))['host'] - self.assertNotEmpty(host_details) - host_detail_keys = ['project', 'volume_count', 'snapshot_count', - 'host', 'total_volume_gb', 'total_snapshot_gb'] - for detail in host_details: - self.assertIn('resource', detail) - for key in host_detail_keys: - self.assertIn(key, detail['resource']) diff --git a/tempest/api/volume/admin/test_volume_manage.py b/tempest/api/volume/admin/test_volume_manage.py deleted file mode 100644 index 4b352e0c5..000000000 --- a/tempest/api/volume/admin/test_volume_manage.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# 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 tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions - -CONF = config.CONF - - -class VolumeManageAdminTest(base.BaseVolumeAdminTest): - - @classmethod - def skip_checks(cls): - super(VolumeManageAdminTest, cls).skip_checks() - - if not CONF.volume_feature_enabled.manage_volume: - raise cls.skipException("Manage volume tests are disabled") - - if len(CONF.volume.manage_volume_ref) != 2: - msg = ("Manage volume ref is not correctly configured, " - "it should be a list of two elements") - raise exceptions.InvalidConfiguration(msg) - - @decorators.idempotent_id('70076c71-0ce1-4208-a8ff-36a66e65cc1e') - def test_unmanage_manage_volume(self): - # Create original volume - org_vol_id = self.create_volume()['id'] - org_vol_info = self.admin_volume_client.show_volume( - org_vol_id)['volume'] - - # Unmanage the original volume - self.admin_volume_client.unmanage_volume(org_vol_id) - self.admin_volume_client.wait_for_resource_deletion(org_vol_id) - - # Verify the original volume does not exist in volume list - params = {'all_tenants': 1} - all_tenants_volumes = self.admin_volume_client.list_volumes( - detail=True, params=params)['volumes'] - self.assertNotIn(org_vol_id, [v['id'] for v in all_tenants_volumes]) - - # Manage volume - new_vol_name = data_utils.rand_name( - self.__class__.__name__ + '-volume') - new_vol_ref = { - 'name': new_vol_name, - 'host': org_vol_info['os-vol-host-attr:host'], - 'ref': {CONF.volume.manage_volume_ref[0]: - CONF.volume.manage_volume_ref[1] % org_vol_id}, - 'volume_type': org_vol_info['volume_type'], - 'availability_zone': org_vol_info['availability_zone']} - new_vol_id = self.admin_volume_manage_client.manage_volume( - **new_vol_ref)['volume']['id'] - self.addCleanup(self.delete_volume, - self.admin_volume_client, new_vol_id) - waiters.wait_for_volume_resource_status(self.admin_volume_client, - new_vol_id, 'available') - - # Compare the managed volume with the original - new_vol_info = self.admin_volume_client.show_volume( - new_vol_id)['volume'] - self.assertNotIn(new_vol_id, [org_vol_id]) - self.assertEqual(new_vol_info['name'], new_vol_name) - for key in ['size', - 'volume_type', - 'availability_zone', - 'os-vol-host-attr:host']: - self.assertEqual(new_vol_info[key], org_vol_info[key]) diff --git a/tempest/api/volume/admin/test_volume_pools.py b/tempest/api/volume/admin/test_volume_pools.py deleted file mode 100644 index d389c26d2..000000000 --- a/tempest/api/volume/admin/test_volume_pools.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# 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 tempest.api.volume import base -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class VolumePoolsAdminTestsJSON(base.BaseVolumeAdminTest): - def _assert_pools(self, with_detail=False): - cinder_pools = self.admin_scheduler_stats_client.list_pools( - detail=with_detail)['pools'] - self.assertIn('name', cinder_pools[0]) - if with_detail: - self.assertIn(CONF.volume.vendor_name, - [pool['capabilities']['vendor_name'] - for pool in cinder_pools]) - - @decorators.idempotent_id('0248a46c-e226-4933-be10-ad6fca8227e7') - def test_get_pools_without_details(self): - self._assert_pools() - - @decorators.idempotent_id('d4bb61f7-762d-4437-b8a4-5785759a0ced') - def test_get_pools_with_details(self): - self._assert_pools(with_detail=True) diff --git a/tempest/api/volume/admin/test_volume_quota_classes.py b/tempest/api/volume/admin/test_volume_quota_classes.py deleted file mode 100644 index f551575c0..000000000 --- a/tempest/api/volume/admin/test_volume_quota_classes.py +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# 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 random - -from oslo_log import log as logging -from testtools import matchers - -from tempest.api.volume import base -from tempest.common import tempest_fixtures as fixtures -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -LOG = logging.getLogger(__name__) -QUOTA_KEYS = ['gigabytes', 'snapshots', 'volumes', 'backups', - 'backup_gigabytes', 'per_volume_gigabytes'] - - -class VolumeQuotaClassesTest(base.BaseVolumeAdminTest): - - def setUp(self): - # Note(jeremy.zhang): All test cases in this class need to externally - # lock on doing anything with default quota values. - self.useFixture(fixtures.LockFixture('volume_quotas')) - super(VolumeQuotaClassesTest, self).setUp() - - def _restore_default_quotas(self, original_defaults): - LOG.debug("Restoring volume quota class defaults") - self.admin_quota_classes_client.update_quota_class_set( - 'default', **original_defaults) - - @decorators.idempotent_id('abb9198e-67d0-4b09-859f-4f4a1418f176') - def test_show_default_quota(self): - default_quotas = self.admin_quota_classes_client.show_quota_class_set( - 'default')['quota_class_set'] - self.assertIn('id', default_quotas) - self.assertEqual('default', default_quotas.pop('id')) - for key in QUOTA_KEYS: - self.assertIn(key, default_quotas) - - @decorators.idempotent_id('a7644c63-2669-467a-b00e-452dd5c5397b') - def test_update_default_quota(self): - LOG.debug("Get the current default quota class values") - body = self.admin_quota_classes_client.show_quota_class_set( - 'default')['quota_class_set'] - - # Note(jeremyZ) Only include specified quota keys to avoid the conflict - # that other tests may create/delete volume types or update volume - # type's default quotas in concurrency running. - update_kwargs = {key: body[key] for key in body if key in QUOTA_KEYS} - - # Restore the defaults when the test is done. - self.addCleanup(self._restore_default_quotas, update_kwargs.copy()) - - # Note(jeremyZ) Increment some of the values for updating the default - # quota class. For safety, only items with value >= 0 will be updated, - # and items with value < 0 (-1 means unlimited) will be ignored. - for quota, default in update_kwargs.items(): - if default >= 0: - update_kwargs[quota] = default + 1 - - # Create a volume type for updating default quotas class. - volume_type_name = self.create_volume_type()['name'] - for key in ['volumes', 'snapshots', 'gigabytes']: - update_kwargs['%s_%s' % (key, volume_type_name)] = \ - random.randint(1, 10) - - LOG.debug("Update limits for the default quota class set") - update_body = self.admin_quota_classes_client.update_quota_class_set( - 'default', **update_kwargs)['quota_class_set'] - self.assertThat(update_body.items(), - matchers.ContainsAll(update_kwargs.items())) - - # Verify current project's default quotas. - default_quotas = self.admin_quotas_client.show_default_quota_set( - self.os_admin.credentials.tenant_id)['quota_set'] - self.assertThat(default_quotas.items(), - matchers.ContainsAll(update_kwargs.items())) - - # Verify a new project's default quotas. - project_name = data_utils.rand_name('quota_class_tenant') - description = data_utils.rand_name('desc_') - project_id = self.identity_utils.create_project( - name=project_name, description=description)['id'] - self.addCleanup(self.identity_utils.delete_project, project_id) - default_quotas = self.admin_quotas_client.show_default_quota_set( - project_id)['quota_set'] - self.assertThat(default_quotas.items(), - matchers.ContainsAll(update_kwargs.items())) diff --git a/tempest/api/volume/admin/test_volume_quotas.py b/tempest/api/volume/admin/test_volume_quotas.py deleted file mode 100644 index 754104e04..000000000 --- a/tempest/api/volume/admin/test_volume_quotas.py +++ /dev/null @@ -1,183 +0,0 @@ -# Copyright (C) 2014 eNovance SAS -# -# 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 tempest.api.volume import base -from tempest.common import tempest_fixtures as fixtures -from tempest.common import waiters -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -QUOTA_KEYS = ['gigabytes', 'snapshots', 'volumes', 'backups'] -QUOTA_USAGE_KEYS = ['reserved', 'limit', 'in_use'] - - -class BaseVolumeQuotasAdminTestJSON(base.BaseVolumeAdminTest): - force_tenant_isolation = True - - credentials = ['primary', 'alt', 'admin'] - - def setUp(self): - # NOTE(jeremy.zhang): Avoid conflicts with volume quota class tests. - self.useFixture(fixtures.LockFixture('volume_quotas')) - super(BaseVolumeQuotasAdminTestJSON, self).setUp() - - @classmethod - def setup_credentials(cls): - super(BaseVolumeQuotasAdminTestJSON, cls).setup_credentials() - cls.demo_tenant_id = cls.os_primary.credentials.tenant_id - cls.alt_client = cls.os_alt.volumes_client_latest - - @classmethod - def setup_clients(cls): - super(BaseVolumeQuotasAdminTestJSON, cls).setup_clients() - cls.transfer_client = cls.os_primary.volume_transfers_v2_client - cls.alt_transfer_client = cls.os_alt.volume_transfers_v2_client - - @decorators.idempotent_id('59eada70-403c-4cef-a2a3-a8ce2f1b07a0') - def test_list_quotas(self): - quotas = (self.admin_quotas_client.show_quota_set(self.demo_tenant_id) - ['quota_set']) - for key in QUOTA_KEYS: - self.assertIn(key, quotas) - - @decorators.idempotent_id('2be020a2-5fdd-423d-8d35-a7ffbc36e9f7') - def test_list_default_quotas(self): - quotas = self.admin_quotas_client.show_default_quota_set( - self.demo_tenant_id)['quota_set'] - for key in QUOTA_KEYS: - self.assertIn(key, quotas) - - @decorators.idempotent_id('3d45c99e-cc42-4424-a56e-5cbd212b63a6') - def test_update_all_quota_resources_for_tenant(self): - # Admin can update all the resource quota limits for a tenant - default_quota_set = self.admin_quotas_client.show_default_quota_set( - self.demo_tenant_id)['quota_set'] - new_quota_set = {'gigabytes': 1009, - 'volumes': 11, - 'snapshots': 11, - 'backups': 11} - - # Update limits for all quota resources - quota_set = self.admin_quotas_client.update_quota_set( - self.demo_tenant_id, - **new_quota_set)['quota_set'] - - cleanup_quota_set = dict( - (k, v) for k, v in default_quota_set.items() - if k in QUOTA_KEYS) - self.addCleanup(self.admin_quotas_client.update_quota_set, - self.demo_tenant_id, **cleanup_quota_set) - # test that the specific values we set are actually in - # the final result. There is nothing here that ensures there - # would be no other values in there. - self.assertDictContainsSubset(new_quota_set, quota_set) - - @decorators.idempotent_id('18c51ae9-cb03-48fc-b234-14a19374dbed') - def test_show_quota_usage(self): - quota_usage = self.admin_quotas_client.show_quota_set( - self.os_admin.credentials.tenant_id, - params={'usage': True})['quota_set'] - for key in QUOTA_KEYS: - self.assertIn(key, quota_usage) - for usage_key in QUOTA_USAGE_KEYS: - self.assertIn(usage_key, quota_usage[key]) - - @decorators.idempotent_id('ae8b6091-48ad-4bfa-a188-bbf5cc02115f') - def test_quota_usage(self): - quota_usage = self.admin_quotas_client.show_quota_set( - self.demo_tenant_id, params={'usage': True})['quota_set'] - - volume = self.create_volume() - self.addCleanup(self.delete_volume, - self.admin_volume_client, volume['id']) - - new_quota_usage = self.admin_quotas_client.show_quota_set( - self.demo_tenant_id, params={'usage': True})['quota_set'] - - self.assertEqual(quota_usage['volumes']['in_use'] + 1, - new_quota_usage['volumes']['in_use']) - - self.assertEqual(quota_usage['gigabytes']['in_use'] + - volume["size"], - new_quota_usage['gigabytes']['in_use']) - - @decorators.idempotent_id('874b35a9-51f1-4258-bec5-cd561b6690d3') - def test_delete_quota(self): - # Admin can delete the resource quota set for a project - project_name = data_utils.rand_name('quota_tenant') - description = data_utils.rand_name('desc_') - project = self.identity_utils.create_project(project_name, - description=description) - project_id = project['id'] - self.addCleanup(self.identity_utils.delete_project, project_id) - quota_set_default = self.admin_quotas_client.show_default_quota_set( - project_id)['quota_set'] - volume_default = quota_set_default['volumes'] - - self.admin_quotas_client.update_quota_set( - project_id, volumes=(volume_default + 5)) - - self.admin_quotas_client.delete_quota_set(project_id) - quota_set_new = (self.admin_quotas_client.show_quota_set(project_id) - ['quota_set']) - self.assertEqual(volume_default, quota_set_new['volumes']) - - @decorators.idempotent_id('8911036f-9d54-4720-80cc-a1c9796a8805') - def test_quota_usage_after_volume_transfer(self): - # Create a volume for transfer - volume = self.create_volume() - self.addCleanup(self.delete_volume, - self.admin_volume_client, volume['id']) - - # List of tenants quota usage pre-transfer - primary_quota = self.admin_quotas_client.show_quota_set( - self.demo_tenant_id, params={'usage': True})['quota_set'] - - alt_quota = self.admin_quotas_client.show_quota_set( - self.alt_client.tenant_id, params={'usage': True})['quota_set'] - - # Creates a volume transfer - transfer = self.transfer_client.create_volume_transfer( - volume_id=volume['id'])['transfer'] - transfer_id = transfer['id'] - auth_key = transfer['auth_key'] - - # Accepts a volume transfer - self.alt_transfer_client.accept_volume_transfer( - transfer_id, auth_key=auth_key) - - # Verify volume transferred is available - waiters.wait_for_volume_resource_status( - self.alt_client, volume['id'], 'available') - - # List of tenants quota usage post transfer - new_primary_quota = self.admin_quotas_client.show_quota_set( - self.demo_tenant_id, params={'usage': True})['quota_set'] - - new_alt_quota = self.admin_quotas_client.show_quota_set( - self.alt_client.tenant_id, params={'usage': True})['quota_set'] - - # Verify tenants quota usage was updated - self.assertEqual(primary_quota['volumes']['in_use'] - - new_primary_quota['volumes']['in_use'], - new_alt_quota['volumes']['in_use'] - - alt_quota['volumes']['in_use']) - - self.assertEqual(alt_quota['gigabytes']['in_use'] + - volume['size'], - new_alt_quota['gigabytes']['in_use']) - - self.assertEqual(primary_quota['gigabytes']['in_use'] - - volume['size'], - new_primary_quota['gigabytes']['in_use']) diff --git a/tempest/api/volume/admin/test_volume_quotas_negative.py b/tempest/api/volume/admin/test_volume_quotas_negative.py deleted file mode 100644 index d127b5f39..000000000 --- a/tempest/api/volume/admin/test_volume_quotas_negative.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# 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 tempest.api.volume import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class BaseVolumeQuotasNegativeTestJSON(base.BaseVolumeAdminTest): - force_tenant_isolation = True - - @classmethod - def setup_credentials(cls): - super(BaseVolumeQuotasNegativeTestJSON, cls).setup_credentials() - cls.demo_tenant_id = cls.os_primary.credentials.tenant_id - - @classmethod - def resource_setup(cls): - super(BaseVolumeQuotasNegativeTestJSON, cls).resource_setup() - cls.shared_quota_set = {'gigabytes': 2 * CONF.volume.volume_size, - 'volumes': 1} - - # NOTE(gfidente): no need to restore original quota set - # after the tests as they only work with dynamic credentials. - cls.admin_quotas_client.update_quota_set( - cls.demo_tenant_id, - **cls.shared_quota_set) - - # NOTE(gfidente): no need to delete in tearDown as - # they are created using utility wrapper methods. - cls.volume = cls.create_volume() - - @decorators.attr(type='negative') - @decorators.idempotent_id('bf544854-d62a-47f2-a681-90f7a47d86b6') - def test_quota_volumes(self): - self.assertRaises(lib_exc.OverLimit, - self.volumes_client.create_volume, - size=CONF.volume.volume_size) - - @decorators.attr(type='negative') - @decorators.idempotent_id('2dc27eee-8659-4298-b900-169d71a91374') - def test_quota_volume_gigabytes(self): - # NOTE(gfidente): quota set needs to be changed for this test - # or we may be limited by the volumes or snaps quota number, not by - # actual gigs usage; next line ensures shared set is restored. - self.addCleanup(self.admin_quotas_client.update_quota_set, - self.demo_tenant_id, - **self.shared_quota_set) - new_quota_set = {'gigabytes': CONF.volume.volume_size, - 'volumes': 2, 'snapshots': 1} - self.admin_quotas_client.update_quota_set( - self.demo_tenant_id, - **new_quota_set) - self.assertRaises(lib_exc.OverLimit, - self.volumes_client.create_volume, - size=CONF.volume.volume_size) diff --git a/tempest/api/volume/admin/test_volume_retype_with_migration.py b/tempest/api/volume/admin/test_volume_retype_with_migration.py deleted file mode 100644 index 94d5299b5..000000000 --- a/tempest/api/volume/admin/test_volume_retype_with_migration.py +++ /dev/null @@ -1,109 +0,0 @@ -# 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 oslo_log import log as logging - -from tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - -LOG = logging.getLogger(__name__) - - -class VolumeRetypeWithMigrationTest(base.BaseVolumeAdminTest): - - @classmethod - def skip_checks(cls): - super(VolumeRetypeWithMigrationTest, cls).skip_checks() - - if not CONF.volume_feature_enabled.multi_backend: - raise cls.skipException("Cinder multi-backend feature disabled.") - - if len(set(CONF.volume.backend_names)) < 2: - raise cls.skipException("Requires at least two different " - "backend names") - - @classmethod - def resource_setup(cls): - super(VolumeRetypeWithMigrationTest, cls).resource_setup() - # read backend name from a list. - backend_src = CONF.volume.backend_names[0] - backend_dst = CONF.volume.backend_names[1] - - extra_specs_src = {"volume_backend_name": backend_src} - extra_specs_dst = {"volume_backend_name": backend_dst} - - src_vol_type = cls.create_volume_type(extra_specs=extra_specs_src) - cls.dst_vol_type = cls.create_volume_type(extra_specs=extra_specs_dst) - - cls.src_vol = cls.create_volume(volume_type=src_vol_type['name']) - - @classmethod - def resource_cleanup(cls): - # When retyping a volume, Cinder creates an internal volume in the - # target backend. The volume in the source backend is deleted after - # the migration, so we need to wait for Cinder delete this volume - # before deleting the types we've created. - - # This list should return 2 volumes until the copy and cleanup - # process is finished. - fetched_list = cls.admin_volume_client.list_volumes( - params={'all_tenants': True, - 'display_name': cls.src_vol['name']})['volumes'] - - for fetched_vol in fetched_list: - if fetched_vol['id'] != cls.src_vol['id']: - # This is the Cinder internal volume - LOG.debug('Waiting for internal volume %s deletion', - fetched_vol['id']) - cls.admin_volume_client.wait_for_resource_deletion( - fetched_vol['id']) - break - - super(VolumeRetypeWithMigrationTest, cls).resource_cleanup() - - @decorators.idempotent_id('a1a41f3f-9dad-493e-9f09-3ff197d477cd') - def test_available_volume_retype_with_migration(self): - - keys_with_no_change = ('id', 'size', 'description', 'name', 'user_id', - 'os-vol-tenant-attr:tenant_id') - keys_with_change = ('volume_type', 'os-vol-host-attr:host') - - volume_source = self.admin_volume_client.show_volume( - self.src_vol['id'])['volume'] - - # TODO(erlon): change this to volumes_client client after Bug - # #1657806 is fixed - self.admin_volume_client.retype_volume( - self.src_vol['id'], - new_type=self.dst_vol_type['name'], - migration_policy='on-demand') - - waiters.wait_for_volume_retype(self.volumes_client, self.src_vol['id'], - self.dst_vol_type['name']) - volume_dest = self.admin_volume_client.show_volume( - self.src_vol['id'])['volume'] - - # Check the volume information after the migration. - self.assertEqual('success', - volume_dest['os-vol-mig-status-attr:migstat']) - self.assertEqual('success', volume_dest['migration_status']) - - for key in keys_with_no_change: - self.assertEqual(volume_source[key], volume_dest[key]) - - for key in keys_with_change: - self.assertNotEqual(volume_source[key], volume_dest[key]) diff --git a/tempest/api/volume/admin/test_volume_services.py b/tempest/api/volume/admin/test_volume_services.py deleted file mode 100644 index 293af81ca..000000000 --- a/tempest/api/volume/admin/test_volume_services.py +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright 2014 NEC Corporation -# 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 tempest.api.volume import base -from tempest.lib import decorators - - -def _get_host(host): - return host.split('@')[0] - - -class VolumesServicesTestJSON(base.BaseVolumeAdminTest): - """Tests Volume Services API. - - volume service list requires admin privileges. - """ - - @classmethod - def resource_setup(cls): - super(VolumesServicesTestJSON, cls).resource_setup() - cls.services = (cls.admin_volume_services_client.list_services() - ['services']) - # NOTE: Cinder service-list API returns the list contains - # "@" like "nova-compute01@lvmdriver-1". - # So here picks up as a host. - cls.host_name = _get_host(cls.services[0]['host']) - cls.binary_name = cls.services[0]['binary'] - - @decorators.idempotent_id('e0218299-0a59-4f43-8b2b-f1c035b3d26d') - def test_list_services(self): - services = (self.admin_volume_services_client.list_services() - ['services']) - self.assertNotEmpty(services) - - @decorators.idempotent_id('63a3e1ca-37ee-4983-826d-83276a370d25') - def test_get_service_by_service_binary_name(self): - services = (self.admin_volume_services_client.list_services( - binary=self.binary_name)['services']) - self.assertNotEmpty(services) - for service in services: - self.assertEqual(self.binary_name, service['binary']) - - @decorators.idempotent_id('178710e4-7596-4e08-9333-745cb8bc4f8d') - def test_get_service_by_host_name(self): - services_on_host = [service for service in self.services if - _get_host(service['host']) == self.host_name] - - services = (self.admin_volume_services_client.list_services( - host=self.host_name)['services']) - - # we could have a periodic job checkin between the 2 service - # lookups, so only compare binary lists. - s1 = map(lambda x: x['binary'], services) - s2 = map(lambda x: x['binary'], services_on_host) - # sort the lists before comparing, to take out dependency - # on order. - self.assertEqual(sorted(s1), sorted(s2)) - - @decorators.idempotent_id('67ec6902-f91d-4dec-91fa-338523208bbc') - def test_get_service_by_volume_host_name(self): - volume_id = self.create_volume()['id'] - volume = self.admin_volume_client.show_volume(volume_id)['volume'] - hostname = _get_host(volume['os-vol-host-attr:host']) - - services = (self.admin_volume_services_client.list_services( - host=hostname, binary='cinder-volume')['services']) - - self.assertNotEmpty(services, - 'cinder-volume not found on host %s' % hostname) - self.assertEqual(hostname, _get_host(services[0]['host'])) - self.assertEqual('cinder-volume', services[0]['binary']) - - @decorators.idempotent_id('ffa6167c-4497-4944-a464-226bbdb53908') - def test_get_service_by_service_and_host_name(self): - - services = (self.admin_volume_services_client.list_services( - host=self.host_name, binary=self.binary_name))['services'] - - self.assertNotEmpty(services) - self.assertEqual(self.host_name, _get_host(services[0]['host'])) - self.assertEqual(self.binary_name, services[0]['binary']) diff --git a/tempest/api/volume/admin/test_volume_snapshot_quotas_negative.py b/tempest/api/volume/admin/test_volume_snapshot_quotas_negative.py deleted file mode 100644 index 0f4e90fd3..000000000 --- a/tempest/api/volume/admin/test_volume_snapshot_quotas_negative.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# 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 tempest.api.volume import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class VolumeSnapshotQuotasNegativeTestJSON(base.BaseVolumeAdminTest): - force_tenant_isolation = True - - @classmethod - def skip_checks(cls): - super(VolumeSnapshotQuotasNegativeTestJSON, cls).skip_checks() - if not CONF.volume_feature_enabled.snapshot: - raise cls.skipException('Cinder volume snapshots are disabled') - - @classmethod - def setup_credentials(cls): - super(VolumeSnapshotQuotasNegativeTestJSON, cls).setup_credentials() - cls.demo_tenant_id = cls.os_primary.credentials.tenant_id - - @classmethod - def resource_setup(cls): - super(VolumeSnapshotQuotasNegativeTestJSON, cls).resource_setup() - cls.default_volume_size = CONF.volume.volume_size - cls.shared_quota_set = {'gigabytes': 3 * cls.default_volume_size, - 'volumes': 1, 'snapshots': 1} - - # NOTE(gfidente): no need to restore original quota set - # after the tests as they only work with tenant isolation. - cls.admin_quotas_client.update_quota_set( - cls.demo_tenant_id, - **cls.shared_quota_set) - - # NOTE(gfidente): no need to delete in tearDown as - # they are created using utility wrapper methods. - cls.volume = cls.create_volume() - cls.snapshot = cls.create_snapshot(volume_id=cls.volume['id']) - - @decorators.attr(type='negative') - @decorators.idempotent_id('02bbf63f-6c05-4357-9d98-2926a94064ff') - def test_quota_volume_snapshots(self): - self.assertRaises(lib_exc.OverLimit, - self.snapshots_client.create_snapshot, - volume_id=self.volume['id']) - - @decorators.attr(type='negative') - @decorators.idempotent_id('c99a1ca9-6cdf-498d-9fdf-25832babef27') - def test_quota_volume_gigabytes_snapshots(self): - self.addCleanup(self.admin_quotas_client.update_quota_set, - self.demo_tenant_id, - **self.shared_quota_set) - new_quota_set = {'gigabytes': 2 * self.default_volume_size, - 'volumes': 1, 'snapshots': 2} - self.admin_quotas_client.update_quota_set( - self.demo_tenant_id, - **new_quota_set) - self.assertRaises(lib_exc.OverLimit, - self.snapshots_client.create_snapshot, - volume_id=self.volume['id']) diff --git a/tempest/api/volume/admin/test_volume_type_access.py b/tempest/api/volume/admin/test_volume_type_access.py deleted file mode 100644 index e93bcb5ff..000000000 --- a/tempest/api/volume/admin/test_volume_type_access.py +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# 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 operator - -from tempest.api.volume import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class VolumeTypesAccessTest(base.BaseVolumeAdminTest): - - credentials = ['primary', 'alt', 'admin'] - - @classmethod - def setup_clients(cls): - super(VolumeTypesAccessTest, cls).setup_clients() - cls.alt_client = cls.os_alt.volumes_client_latest - - @decorators.idempotent_id('d4dd0027-835f-4554-a6e5-50903fb79184') - def test_volume_type_access_add(self): - # Creating a NON public volume type - params = {'os-volume-type-access:is_public': False} - volume_type = self.create_volume_type(**params) - - # Try creating a volume from volume type in primary tenant - self.assertRaises(lib_exc.NotFound, self.volumes_client.create_volume, - volume_type=volume_type['id'], - size=CONF.volume.volume_size) - - # Adding volume type access for primary tenant - self.admin_volume_types_client.add_type_access( - volume_type['id'], project=self.volumes_client.tenant_id) - self.addCleanup(self.admin_volume_types_client.remove_type_access, - volume_type['id'], - project=self.volumes_client.tenant_id) - - # Creating a volume from primary tenant - volume = self.create_volume(volume_type=volume_type['id']) - # Validating the created volume is based on the volume type - self.assertEqual(volume_type['name'], volume['volume_type']) - - @decorators.idempotent_id('5220eb28-a435-43ce-baaf-ed46f0e95159') - def test_volume_type_access_list(self): - # Creating a NON public volume type - params = {'os-volume-type-access:is_public': False} - volume_type = self.create_volume_type(**params) - - # Adding volume type access for primary tenant - self.admin_volume_types_client.add_type_access( - volume_type['id'], project=self.volumes_client.tenant_id) - self.addCleanup(self.admin_volume_types_client.remove_type_access, - volume_type['id'], - project=self.volumes_client.tenant_id) - - # Adding volume type access for alt tenant - self.admin_volume_types_client.add_type_access( - volume_type['id'], project=self.alt_client.tenant_id) - self.addCleanup(self.admin_volume_types_client.remove_type_access, - volume_type['id'], - project=self.alt_client.tenant_id) - - # List tenant access for the given volume type - type_access_list = self.admin_volume_types_client.list_type_access( - volume_type['id'])['volume_type_access'] - volume_type_ids = [ - vol_type['volume_type_id'] for vol_type in type_access_list - ] - - # Validating volume type available for only two tenants - self.assertEqual(2, volume_type_ids.count(volume_type['id'])) - - # Validating the permitted tenants are the expected tenants - self.assertIn(self.volumes_client.tenant_id, - map(operator.itemgetter('project_id'), type_access_list)) - self.assertIn(self.alt_client.tenant_id, - map(operator.itemgetter('project_id'), type_access_list)) diff --git a/tempest/api/volume/admin/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py deleted file mode 100644 index af1024c93..000000000 --- a/tempest/api/volume/admin/test_volume_types.py +++ /dev/null @@ -1,194 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class VolumeTypesTest(base.BaseVolumeAdminTest): - - @decorators.idempotent_id('9d9b28e3-1b2e-4483-a2cc-24aa0ea1de54') - def test_volume_type_list(self): - # List volume types. - body = \ - self.admin_volume_types_client.list_volume_types()['volume_types'] - self.assertIsInstance(body, list) - - @decorators.idempotent_id('c03cc62c-f4e9-4623-91ec-64ce2f9c1260') - def test_volume_crud_with_volume_type_and_extra_specs(self): - # Create/update/get/delete volume with volume_type and extra spec. - volume_types = list() - vol_name = data_utils.rand_name(self.__class__.__name__ + '-volume') - proto = CONF.volume.storage_protocol - vendor = CONF.volume.vendor_name - extra_specs = {"storage_protocol": proto, - "vendor_name": vendor} - # Create two volume_types - for _ in range(2): - vol_type = self.create_volume_type( - extra_specs=extra_specs) - volume_types.append(vol_type) - params = {'name': vol_name, - 'volume_type': volume_types[0]['id'], - 'size': CONF.volume.volume_size} - - # Create volume - volume = self.create_volume(**params) - self.assertEqual(volume_types[0]['name'], volume["volume_type"]) - self.assertEqual(volume['name'], vol_name, - "The created volume name is not equal " - "to the requested name") - self.assertIsNotNone(volume['id'], - "Field volume id is empty or not found.") - - # Update volume with new volume_type - self.volumes_client.retype_volume(volume['id'], - new_type=volume_types[1]['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') - - # Get volume details and Verify - fetched_volume = self.volumes_client.show_volume( - volume['id'])['volume'] - self.assertEqual(volume_types[1]['name'], - fetched_volume['volume_type'], - 'The fetched Volume type is different ' - 'from updated volume type') - self.assertEqual(vol_name, fetched_volume['name'], - 'The fetched Volume is different ' - 'from the created Volume') - self.assertEqual(volume['id'], fetched_volume['id'], - 'The fetched Volume is different ' - 'from the created Volume') - - @decorators.idempotent_id('4e955c3b-49db-4515-9590-0c99f8e471ad') - def test_volume_type_create_get_delete(self): - # Create/get volume type. - name = data_utils.rand_name(self.__class__.__name__ + '-volume-type') - description = data_utils.rand_name("volume-type-description") - proto = CONF.volume.storage_protocol - vendor = CONF.volume.vendor_name - extra_specs = {"storage_protocol": proto, - "vendor_name": vendor} - params = {'name': name, - 'description': description, - 'extra_specs': extra_specs, - 'os-volume-type-access:is_public': True} - body = self.create_volume_type(**params) - self.assertIn('name', body) - self.assertEqual(name, body['name'], - "The created volume_type name is not equal " - "to the requested name") - self.assertEqual(description, body['description'], - "The created volume_type_description name is " - "not equal to the requested name") - self.assertIsNotNone(body['id'], - "Field volume_type id is empty or not found.") - fetched_volume_type = self.admin_volume_types_client.show_volume_type( - body['id'])['volume_type'] - self.assertEqual(name, fetched_volume_type['name'], - 'The fetched Volume_type is different ' - 'from the created Volume_type') - self.assertEqual(str(body['id']), fetched_volume_type['id'], - 'The fetched Volume_type is different ' - 'from the created Volume_type') - self.assertEqual(extra_specs, fetched_volume_type['extra_specs'], - 'The fetched Volume_type is different ' - 'from the created Volume_type') - self.assertEqual(description, fetched_volume_type['description']) - self.assertEqual(body['is_public'], - fetched_volume_type['is_public']) - self.assertEqual( - body['os-volume-type-access:is_public'], - fetched_volume_type['os-volume-type-access:is_public']) - - @decorators.idempotent_id('7830abd0-ff99-4793-a265-405684a54d46') - def test_volume_type_encryption_create_get_update_delete(self): - # Create/get/update/delete encryption type. - create_kwargs = {'provider': 'LuksEncryptor', - 'control_location': 'front-end'} - volume_type_id = self.create_volume_type()['id'] - - # Create encryption type - encryption_type = \ - self.admin_encryption_types_client.create_encryption_type( - volume_type_id, **create_kwargs)['encryption'] - self.assertIn('volume_type_id', encryption_type) - for key in create_kwargs: - self.assertEqual(create_kwargs[key], encryption_type[key], - 'The created encryption_type %s is different ' - 'from the requested encryption_type' % key) - - # Get encryption type - encrypt_type_id = encryption_type['volume_type_id'] - fetched_encryption_type = ( - self.admin_encryption_types_client.show_encryption_type( - encrypt_type_id)) - for key in create_kwargs: - self.assertEqual(create_kwargs[key], fetched_encryption_type[key], - 'The fetched encryption_type %s is different ' - 'from the created encryption_type' % key) - - # Update encryption type - update_kwargs = {'key_size': 128, - 'provider': 'SomeProvider', - 'cipher': 'aes-xts-plain64', - 'control_location': 'back-end'} - self.admin_encryption_types_client.update_encryption_type( - encrypt_type_id, **update_kwargs) - updated_encryption_type = ( - self.admin_encryption_types_client.show_encryption_type( - encrypt_type_id)) - for key in update_kwargs: - self.assertEqual(update_kwargs[key], updated_encryption_type[key], - 'The fetched encryption_type %s is different ' - 'from the updated encryption_type' % key) - - # Delete encryption type - self.admin_encryption_types_client.delete_encryption_type( - encrypt_type_id) - self.admin_encryption_types_client.wait_for_resource_deletion( - encrypt_type_id) - deleted_encryption_type = ( - self.admin_encryption_types_client.show_encryption_type( - encrypt_type_id)) - self.assertEmpty(deleted_encryption_type) - - @decorators.idempotent_id('cf9f07c6-db9e-4462-a243-5933ad65e9c8') - def test_volume_type_update(self): - # Create volume type - volume_type = self.create_volume_type() - - # New volume type details - name = data_utils.rand_name("volume-type") - description = data_utils.rand_name("volume-type-description") - is_public = not volume_type['is_public'] - - # Update volume type details - kwargs = {'name': name, - 'description': description, - 'is_public': is_public} - updated_vol_type = self.admin_volume_types_client.update_volume_type( - volume_type['id'], **kwargs)['volume_type'] - - # Verify volume type details were updated - self.assertEqual(name, updated_vol_type['name']) - self.assertEqual(description, updated_vol_type['description']) - self.assertEqual(is_public, updated_vol_type['is_public']) diff --git a/tempest/api/volume/admin/test_volume_types_extra_specs.py b/tempest/api/volume/admin/test_volume_types_extra_specs.py deleted file mode 100644 index b5a2fb72a..000000000 --- a/tempest/api/volume/admin/test_volume_types_extra_specs.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.volume import base -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class VolumeTypesExtraSpecsTest(base.BaseVolumeAdminTest): - - @classmethod - def resource_setup(cls): - super(VolumeTypesExtraSpecsTest, cls).resource_setup() - cls.volume_type = cls.create_volume_type() - - @decorators.idempotent_id('b42923e9-0452-4945-be5b-d362ae533e60') - def test_volume_type_extra_specs_list(self): - # List Volume types extra specs. - extra_specs = {"spec1": "val1"} - body = self.admin_volume_types_client.create_volume_type_extra_specs( - self.volume_type['id'], extra_specs)['extra_specs'] - self.assertEqual(extra_specs, body, - "Volume type extra spec incorrectly created") - body = self.admin_volume_types_client.list_volume_types_extra_specs( - self.volume_type['id'])['extra_specs'] - self.assertIsInstance(body, dict) - self.assertIn('spec1', body) - - @decorators.idempotent_id('0806db36-b4a0-47a1-b6f3-c2e7f194d017') - def test_volume_type_extra_specs_update(self): - # Update volume type extra specs - extra_specs = {"spec2": "val1"} - body = self.admin_volume_types_client.create_volume_type_extra_specs( - self.volume_type['id'], extra_specs)['extra_specs'] - self.assertEqual(extra_specs, body, - "Volume type extra spec incorrectly created") - spec_key = "spec2" - extra_spec = {spec_key: "val2"} - body = self.admin_volume_types_client.update_volume_type_extra_specs( - self.volume_type['id'], spec_key, extra_spec) - self.assertIn(spec_key, body) - self.assertEqual(extra_spec[spec_key], body[spec_key], - "Volume type extra spec incorrectly updated") - - @decorators.idempotent_id('d4772798-601f-408a-b2a5-29e8a59d1220') - def test_volume_type_extra_spec_create_get_delete(self): - # Create/Get/Delete volume type extra spec. - spec_key = "spec3" - extra_specs = {spec_key: "val1"} - body = self.admin_volume_types_client.create_volume_type_extra_specs( - self.volume_type['id'], - extra_specs)['extra_specs'] - self.assertEqual(extra_specs, body, - "Volume type extra spec incorrectly created") - - body = self.admin_volume_types_client.show_volume_type_extra_specs( - self.volume_type['id'], - spec_key) - self.assertEqual(extra_specs, body, - "Volume type extra spec incorrectly fetched") - - self.admin_volume_types_client.delete_volume_type_extra_specs( - self.volume_type['id'], spec_key) - self.assertRaises( - lib_exc.NotFound, - self.admin_volume_types_client.show_volume_type_extra_specs, - self.volume_type['id'], spec_key) diff --git a/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py b/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py deleted file mode 100644 index 4fa934e10..000000000 --- a/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py +++ /dev/null @@ -1,137 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.volume import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class ExtraSpecsNegativeTest(base.BaseVolumeAdminTest): - - @classmethod - def resource_setup(cls): - super(ExtraSpecsNegativeTest, cls).resource_setup() - extra_specs = {"spec1": "val1"} - cls.volume_type = cls.create_volume_type(extra_specs=extra_specs) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('08961d20-5cbb-4910-ac0f-89ad6dbb2da1') - def test_update_no_body(self): - # Should not update volume type extra specs with no body - self.assertRaises( - lib_exc.BadRequest, - self.admin_volume_types_client.update_volume_type_extra_specs, - self.volume_type['id'], "spec1", None) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('25e5a0ee-89b3-4c53-8310-236f76c75365') - def test_update_nonexistent_extra_spec_id(self): - # Should not update volume type extra specs with nonexistent id. - extra_spec = {"spec1": "val2"} - self.assertRaises( - lib_exc.BadRequest, - self.admin_volume_types_client.update_volume_type_extra_specs, - self.volume_type['id'], data_utils.rand_uuid(), - extra_spec) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9bf7a657-b011-4aec-866d-81c496fbe5c8') - def test_update_none_extra_spec_id(self): - # Should not update volume type extra specs with none id. - extra_spec = {"spec1": "val2"} - self.assertRaises( - lib_exc.BadRequest, - self.admin_volume_types_client.update_volume_type_extra_specs, - self.volume_type['id'], None, extra_spec) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('a77dfda2-9100-448e-9076-ed1711f4bdfc') - def test_update_multiple_extra_spec(self): - # Should not update volume type extra specs with multiple specs as - # body. - extra_spec = {"spec1": "val2", "spec2": "val1"} - self.assertRaises( - lib_exc.BadRequest, - self.admin_volume_types_client.update_volume_type_extra_specs, - self.volume_type['id'], list(extra_spec)[0], - extra_spec) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('49d5472c-a53d-4eab-a4d3-450c4db1c545') - def test_create_nonexistent_type_id(self): - # Should not create volume type extra spec for nonexistent volume - # type id. - extra_specs = {"spec2": "val1"} - self.assertRaises( - lib_exc.NotFound, - self.admin_volume_types_client.create_volume_type_extra_specs, - data_utils.rand_uuid(), extra_specs) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('c821bdc8-43a4-4bf4-86c8-82f3858d5f7d') - def test_create_none_body(self): - # Should not create volume type extra spec for none POST body. - self.assertRaises( - lib_exc.BadRequest, - self.admin_volume_types_client.create_volume_type_extra_specs, - self.volume_type['id'], None) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('bc772c71-1ed4-4716-b945-8b5ed0f15e87') - def test_create_invalid_body(self): - # Should not create volume type extra spec for invalid POST body. - self.assertRaises( - lib_exc.BadRequest, - self.admin_volume_types_client.create_volume_type_extra_specs, - self.volume_type['id'], extra_specs=['invalid']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('031cda8b-7d23-4246-8bf6-bbe73fd67074') - def test_delete_nonexistent_volume_type_id(self): - # Should not delete volume type extra spec for nonexistent - # type id. - self.assertRaises( - lib_exc.NotFound, - self.admin_volume_types_client.delete_volume_type_extra_specs, - data_utils.rand_uuid(), "spec1") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('dee5cf0c-cdd6-4353-b70c-e847050d71fb') - def test_list_nonexistent_volume_type_id(self): - # Should not list volume type extra spec for nonexistent type id. - self.assertRaises( - lib_exc.NotFound, - self.admin_volume_types_client.list_volume_types_extra_specs, - data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9f402cbd-1838-4eb4-9554-126a6b1908c9') - def test_get_nonexistent_volume_type_id(self): - # Should not get volume type extra spec for nonexistent type id. - self.assertRaises( - lib_exc.NotFound, - self.admin_volume_types_client.show_volume_type_extra_specs, - data_utils.rand_uuid(), "spec1") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('c881797d-12ff-4f1a-b09d-9f6212159753') - def test_get_nonexistent_extra_spec_id(self): - # Should not get volume type extra spec for nonexistent extra spec - # id. - self.assertRaises( - lib_exc.NotFound, - self.admin_volume_types_client.show_volume_type_extra_specs, - self.volume_type['id'], data_utils.rand_uuid()) diff --git a/tempest/api/volume/admin/test_volume_types_negative.py b/tempest/api/volume/admin/test_volume_types_negative.py deleted file mode 100644 index 4cad52a7c..000000000 --- a/tempest/api/volume/admin/test_volume_types_negative.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.volume import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - - -class VolumeTypesNegativeTest(base.BaseVolumeAdminTest): - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('b48c98f2-e662-4885-9b71-032256906314') - def test_create_with_nonexistent_volume_type(self): - # Should not be able to create volume with nonexistent volume_type. - params = {'name': data_utils.rand_uuid(), - 'volume_type': data_utils.rand_uuid()} - self.assertRaises(lib_exc.NotFound, - self.volumes_client.create_volume, **params) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('878b4e57-faa2-4659-b0d1-ce740a06ae81') - def test_create_with_empty_name(self): - # Should not be able to create volume type with an empty name. - self.assertRaises( - lib_exc.BadRequest, - self.admin_volume_types_client.create_volume_type, name='') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('994610d6-0476-4018-a644-a2602ef5d4aa') - def test_get_nonexistent_type_id(self): - # Should not be able to get volume type with nonexistent type id. - self.assertRaises(lib_exc.NotFound, - self.admin_volume_types_client.show_volume_type, - data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('6b3926d2-7d73-4896-bc3d-e42dfd11a9f6') - def test_delete_nonexistent_type_id(self): - # Should not be able to delete volume type with nonexistent type id. - self.assertRaises(lib_exc.NotFound, - self.admin_volume_types_client.delete_volume_type, - data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('8c09f849-f225-4d78-ba87-bffd9a5e0c6f') - def test_create_volume_with_private_volume_type(self): - # Should not be able to create volume with private volume type. - params = {'os-volume-type-access:is_public': False} - volume_type = self.create_volume_type(**params) - self.assertRaises(lib_exc.NotFound, - self.create_volume, volume_type=volume_type['id']) diff --git a/tempest/api/volume/admin/test_volumes_actions.py b/tempest/api/volume/admin/test_volumes_actions.py deleted file mode 100644 index b81a477a6..000000000 --- a/tempest/api/volume/admin/test_volumes_actions.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD -# 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 tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class VolumesActionsTest(base.BaseVolumeAdminTest): - - def _create_reset_and_force_delete_temp_volume(self, status=None): - # Create volume, reset volume status, and force delete temp volume - temp_volume = self.create_volume() - if status: - self.admin_volume_client.reset_volume_status( - temp_volume['id'], status=status) - self.admin_volume_client.force_delete_volume(temp_volume['id']) - self.volumes_client.wait_for_resource_deletion(temp_volume['id']) - - @decorators.idempotent_id('d063f96e-a2e0-4f34-8b8a-395c42de1845') - def test_volume_reset_status(self): - # test volume reset status : available->error->available - volume = self.create_volume() - self.addCleanup(self.admin_volume_client.reset_volume_status, - volume['id'], status='available') - for status in ['error', 'available', 'maintenance']: - self.admin_volume_client.reset_volume_status( - volume['id'], status=status) - volume_get = self.admin_volume_client.show_volume( - volume['id'])['volume'] - self.assertEqual(status, volume_get['status']) - - @decorators.idempotent_id('21737d5a-92f2-46d7-b009-a0cc0ee7a570') - def test_volume_force_delete_when_volume_is_creating(self): - # test force delete when status of volume is creating - self._create_reset_and_force_delete_temp_volume('creating') - - @decorators.idempotent_id('db8d607a-aa2e-4beb-b51d-d4005c232011') - def test_volume_force_delete_when_volume_is_attaching(self): - # test force delete when status of volume is attaching - self._create_reset_and_force_delete_temp_volume('attaching') - - @decorators.idempotent_id('3e33a8a8-afd4-4d64-a86b-c27a185c5a4a') - def test_volume_force_delete_when_volume_is_error(self): - # test force delete when status of volume is error - self._create_reset_and_force_delete_temp_volume('error') - - @decorators.idempotent_id('b957cabd-1486-4e21-90cf-a9ed3c39dfb2') - def test_volume_force_delete_when_volume_is_maintenance(self): - # test force delete when status of volume is maintenance - self._create_reset_and_force_delete_temp_volume('maintenance') - - @decorators.idempotent_id('d38285d9-929d-478f-96a5-00e66a115b81') - @test.services('compute') - def test_force_detach_volume(self): - # Create a server and a volume - server_id = self.create_server()['id'] - volume_id = self.create_volume()['id'] - - # Attach volume - self.volumes_client.attach_volume( - volume_id, - instance_uuid=server_id, - mountpoint='/dev/%s' % CONF.compute.volume_device_name) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume_id, 'in-use') - self.addCleanup(waiters.wait_for_volume_resource_status, - self.volumes_client, volume_id, 'available') - self.addCleanup(self.volumes_client.detach_volume, volume_id) - attachment = self.volumes_client.show_volume( - volume_id)['volume']['attachments'][0] - - # Reset volume's status to error - self.admin_volume_client.reset_volume_status(volume_id, status='error') - - # Force detach volume - self.admin_volume_client.force_detach_volume( - volume_id, connector=None, - attachment_id=attachment['attachment_id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume_id, 'available') - vol_info = self.volumes_client.show_volume(volume_id)['volume'] - self.assertIn('attachments', vol_info) - self.assertEmpty(vol_info['attachments']) diff --git a/tempest/api/volume/admin/test_volumes_backup.py b/tempest/api/volume/admin/test_volumes_backup.py deleted file mode 100644 index afc328117..000000000 --- a/tempest/api/volume/admin/test_volumes_backup.py +++ /dev/null @@ -1,138 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# 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 oslo_serialization import base64 -from oslo_serialization import jsonutils as json - -from tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -CONF = config.CONF - - -class VolumesBackupsAdminTest(base.BaseVolumeAdminTest): - - @classmethod - def skip_checks(cls): - super(VolumesBackupsAdminTest, cls).skip_checks() - if not CONF.volume_feature_enabled.backup: - raise cls.skipException("Cinder backup feature disabled") - - def _delete_backup(self, backup_id): - self.admin_backups_client.delete_backup(backup_id) - self.admin_backups_client.wait_for_resource_deletion(backup_id) - - def _decode_url(self, backup_url): - return json.loads(base64.decode_as_text(backup_url)) - - def _encode_backup(self, backup): - retval = json.dumps(backup) - return base64.encode_as_text(retval) - - def _modify_backup_url(self, backup_url, changes): - backup = self._decode_url(backup_url) - backup.update(changes) - return self._encode_backup(backup) - - @decorators.idempotent_id('a99c54a1-dd80-4724-8a13-13bf58d4068d') - def test_volume_backup_export_import(self): - """Test backup export import functionality. - - Cinder allows exporting DB backup information through its API so it can - be imported back in case of a DB loss. - """ - volume = self.create_volume() - # Create backup - backup_name = data_utils.rand_name(self.__class__.__name__ + '-Backup') - backup = (self.create_backup(backup_client=self.admin_backups_client, - volume_id=volume['id'], - name=backup_name)) - self.assertEqual(backup_name, backup['name']) - - # Export Backup - export_backup = (self.admin_backups_client.export_backup(backup['id']) - ['backup-record']) - self.assertIn('backup_service', export_backup) - self.assertIn('backup_url', export_backup) - self.assertTrue(export_backup['backup_service'].startswith( - 'cinder.backup.drivers')) - self.assertIsNotNone(export_backup['backup_url']) - - # NOTE(geguileo): Backups are imported with the same backup id - # (important for incremental backups among other things), so we cannot - # import the exported backup information as it is, because that Backup - # ID already exists. So we'll fake the data by changing the backup id - # in the exported backup DB info we have retrieved before importing it - # back. - new_id = data_utils.rand_uuid() - new_url = self._modify_backup_url( - export_backup['backup_url'], {'id': new_id}) - - # Import Backup - import_backup = self.admin_backups_client.import_backup( - backup_service=export_backup['backup_service'], - backup_url=new_url)['backup'] - - # NOTE(geguileo): We delete both backups, but only one of those - # deletions will delete data from the backup back-end because they - # were both pointing to the same backend data. - self.addCleanup(self._delete_backup, new_id) - self.assertIn("id", import_backup) - self.assertEqual(new_id, import_backup['id']) - waiters.wait_for_volume_resource_status(self.admin_backups_client, - import_backup['id'], - 'available') - - # Verify Import Backup - backups = self.admin_backups_client.list_backups( - detail=True)['backups'] - self.assertIn(new_id, [b['id'] for b in backups]) - - # Restore backup - restore = self.admin_backups_client.restore_backup( - backup['id'])['restore'] - self.addCleanup(self.admin_volume_client.delete_volume, - restore['volume_id']) - self.assertEqual(backup['id'], restore['backup_id']) - waiters.wait_for_volume_resource_status(self.admin_volume_client, - restore['volume_id'], - 'available') - - # Verify if restored volume is there in volume list - volumes = self.admin_volume_client.list_volumes()['volumes'] - self.assertIn(restore['volume_id'], [v['id'] for v in volumes]) - waiters.wait_for_volume_resource_status(self.admin_backups_client, - import_backup['id'], - 'available') - - @decorators.idempotent_id('47a35425-a891-4e13-961c-c45deea21e94') - def test_volume_backup_reset_status(self): - # Create a volume - volume = self.create_volume() - # Create a backup - backup_name = data_utils.rand_name( - self.__class__.__name__ + '-Backup') - backup = self.create_backup(backup_client=self.admin_backups_client, - volume_id=volume['id'], - name=backup_name) - self.assertEqual(backup_name, backup['name']) - # Reset backup status to error - self.admin_backups_client.reset_backup_status(backup_id=backup['id'], - status="error") - waiters.wait_for_volume_resource_status(self.admin_backups_client, - backup['id'], 'error') diff --git a/tempest/api/volume/admin/test_volumes_list.py b/tempest/api/volume/admin/test_volumes_list.py deleted file mode 100644 index 9d98b7aa9..000000000 --- a/tempest/api/volume/admin/test_volumes_list.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# 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 operator - -from tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class VolumesListAdminTestJSON(base.BaseVolumeAdminTest): - - @classmethod - def resource_setup(cls): - super(VolumesListAdminTestJSON, cls).resource_setup() - # Create 3 test volumes - # NOTE(zhufl): When using pre-provisioned credentials, the project - # may have volumes other than those created below. - cls.volume_list = cls.volumes_client.list_volumes()['volumes'] - for _ in range(3): - volume = cls.create_volume() - # Fetch volume details - volume_details = cls.volumes_client.show_volume( - volume['id'])['volume'] - cls.volume_list.append(volume_details) - - @decorators.idempotent_id('5866286f-3290-4cfd-a414-088aa6cdc469') - def test_volume_list_param_tenant(self): - # Test to list volumes from single tenant - # Create a volume in admin tenant - adm_vol = self.admin_volume_client.create_volume( - size=CONF.volume.volume_size)['volume'] - waiters.wait_for_volume_resource_status(self.admin_volume_client, - adm_vol['id'], 'available') - self.addCleanup(self.admin_volume_client.delete_volume, adm_vol['id']) - params = {'all_tenants': 1, - 'project_id': self.volumes_client.tenant_id} - # Getting volume list from primary tenant using admin credentials - fetched_list = self.admin_volume_client.list_volumes( - detail=True, params=params)['volumes'] - # Verifying fetched volume ids list is related to primary tenant - fetched_list_ids = map(operator.itemgetter('id'), fetched_list) - expected_list_ids = map(operator.itemgetter('id'), self.volume_list) - self.assertEqual(sorted(expected_list_ids), sorted(fetched_list_ids)) - # Verifying tenant id of volumes fetched list is related to - # primary tenant - fetched_tenant_id = [operator.itemgetter( - 'os-vol-tenant-attr:tenant_id')(item) for item in fetched_list] - expected_tenant_id = [self.volumes_client.tenant_id] * \ - len(self.volume_list) - self.assertEqual(expected_tenant_id, fetched_tenant_id) diff --git a/tempest/api/volume/api_microversion_fixture.py b/tempest/api/volume/api_microversion_fixture.py deleted file mode 100644 index 7bbe67497..000000000 --- a/tempest/api/volume/api_microversion_fixture.py +++ /dev/null @@ -1,30 +0,0 @@ -# -# 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 fixtures - -from tempest.lib.services.volume import base_client - - -class APIMicroversionFixture(fixtures.Fixture): - - def __init__(self, volume_microversion): - self.volume_microversion = volume_microversion - - def _setUp(self): - super(APIMicroversionFixture, self)._setUp() - base_client.VOLUME_MICROVERSION = self.volume_microversion - self.addCleanup(self._reset_volume_microversion) - - def _reset_volume_microversion(self): - base_client.VOLUME_MICROVERSION = None diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py deleted file mode 100644 index ef69ba3de..000000000 --- a/tempest/api/volume/base.py +++ /dev/null @@ -1,341 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.volume import api_microversion_fixture -from tempest.common import compute -from tempest.common import waiters -from tempest import config -from tempest.lib.common import api_version_utils -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import exceptions -import tempest.test - -CONF = config.CONF - - -class BaseVolumeTest(api_version_utils.BaseMicroversionTest, - tempest.test.BaseTestCase): - """Base test case class for all Cinder API tests.""" - - _api_version = 2 - credentials = ['primary'] - - @classmethod - def skip_checks(cls): - super(BaseVolumeTest, cls).skip_checks() - - if not CONF.service_available.cinder: - skip_msg = ("%s skipped as Cinder is not available" % cls.__name__) - raise cls.skipException(skip_msg) - if cls._api_version == 2: - if not CONF.volume_feature_enabled.api_v2: - msg = "Volume API v2 is disabled" - raise cls.skipException(msg) - elif cls._api_version == 3: - if not CONF.volume_feature_enabled.api_v3: - msg = "Volume API v3 is disabled" - raise cls.skipException(msg) - else: - msg = ("Invalid Cinder API version (%s)" % cls._api_version) - raise exceptions.InvalidConfiguration(msg) - - api_version_utils.check_skip_with_microversion( - cls.min_microversion, cls.max_microversion, - CONF.volume.min_microversion, CONF.volume.max_microversion) - - @classmethod - def setup_credentials(cls): - cls.set_network_resources() - super(BaseVolumeTest, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(BaseVolumeTest, cls).setup_clients() - cls.servers_client = cls.os_primary.servers_client - - if CONF.service_available.glance: - cls.images_client = cls.os_primary.image_client_v2 - - if cls._api_version == 3: - cls.backups_client = cls.os_primary.backups_v3_client - cls.volumes_client = cls.os_primary.volumes_v3_client - else: - cls.backups_client = cls.os_primary.backups_v2_client - cls.volumes_client = cls.os_primary.volumes_v2_client - - cls.snapshots_client = cls.os_primary.snapshots_v2_client - cls.volumes_extension_client =\ - cls.os_primary.volumes_v2_extension_client - cls.availability_zone_client = ( - cls.os_primary.volume_v2_availability_zone_client) - cls.volume_limits_client = cls.os_primary.volume_v2_limits_client - cls.messages_client = cls.os_primary.volume_v3_messages_client - cls.versions_client = cls.os_primary.volume_v3_versions_client - cls.groups_client = cls.os_primary.groups_v3_client - - def setUp(self): - super(BaseVolumeTest, self).setUp() - self.useFixture(api_microversion_fixture.APIMicroversionFixture( - self.request_microversion)) - - @classmethod - def resource_setup(cls): - super(BaseVolumeTest, cls).resource_setup() - cls.request_microversion = ( - api_version_utils.select_request_microversion( - cls.min_microversion, - CONF.volume.min_microversion)) - - cls.snapshots = [] - cls.volumes = [] - cls.image_ref = CONF.compute.image_ref - cls.flavor_ref = CONF.compute.flavor_ref - cls.build_interval = CONF.volume.build_interval - cls.build_timeout = CONF.volume.build_timeout - - @classmethod - def resource_cleanup(cls): - cls.clear_snapshots() - cls.clear_volumes() - super(BaseVolumeTest, cls).resource_cleanup() - - @classmethod - def create_volume(cls, wait_until='available', **kwargs): - """Wrapper utility that returns a test volume. - - :param wait_until: wait till volume status. - """ - if 'size' not in kwargs: - kwargs['size'] = CONF.volume.volume_size - - if 'imageRef' in kwargs: - image = cls.images_client.show_image(kwargs['imageRef']) - min_disk = image['min_disk'] - kwargs['size'] = max(kwargs['size'], min_disk) - - if 'name' not in kwargs: - name = data_utils.rand_name(cls.__name__ + '-Volume') - kwargs['name'] = name - - volume = cls.volumes_client.create_volume(**kwargs)['volume'] - cls.volumes.append(volume) - waiters.wait_for_volume_resource_status(cls.volumes_client, - volume['id'], wait_until) - return volume - - @classmethod - def create_snapshot(cls, volume_id=1, **kwargs): - """Wrapper utility that returns a test snapshot.""" - if 'name' not in kwargs: - name = data_utils.rand_name(cls.__name__ + '-Snapshot') - kwargs['name'] = name - - snapshot = cls.snapshots_client.create_snapshot( - volume_id=volume_id, **kwargs)['snapshot'] - cls.snapshots.append(snapshot['id']) - waiters.wait_for_volume_resource_status(cls.snapshots_client, - snapshot['id'], 'available') - return snapshot - - def create_backup(self, volume_id, backup_client=None, **kwargs): - """Wrapper utility that returns a test backup.""" - if backup_client is None: - backup_client = self.backups_client - if 'name' not in kwargs: - name = data_utils.rand_name(self.__class__.__name__ + '-Backup') - kwargs['name'] = name - - backup = backup_client.create_backup( - volume_id=volume_id, **kwargs)['backup'] - self.addCleanup(backup_client.delete_backup, backup['id']) - waiters.wait_for_volume_resource_status(backup_client, backup['id'], - 'available') - return backup - - # NOTE(afazekas): these create_* and clean_* could be defined - # only in a single location in the source, and could be more general. - - @staticmethod - def delete_volume(client, volume_id): - """Delete volume by the given client""" - client.delete_volume(volume_id) - client.wait_for_resource_deletion(volume_id) - - def delete_snapshot(self, snapshot_id, snapshots_client=None): - """Delete snapshot by the given client""" - if snapshots_client is None: - snapshots_client = self.snapshots_client - snapshots_client.delete_snapshot(snapshot_id) - snapshots_client.wait_for_resource_deletion(snapshot_id) - if snapshot_id in self.snapshots: - self.snapshots.remove(snapshot_id) - - def attach_volume(self, server_id, volume_id): - """Attach a volume to a server""" - self.servers_client.attach_volume( - server_id, volumeId=volume_id, - device='/dev/%s' % CONF.compute.volume_device_name) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume_id, 'in-use') - self.addCleanup(waiters.wait_for_volume_resource_status, - self.volumes_client, volume_id, 'available') - self.addCleanup(self.servers_client.detach_volume, server_id, - volume_id) - - @classmethod - def clear_volumes(cls): - for volume in cls.volumes: - try: - cls.volumes_client.delete_volume(volume['id']) - except Exception: - pass - - for volume in cls.volumes: - try: - cls.volumes_client.wait_for_resource_deletion(volume['id']) - except Exception: - pass - - @classmethod - def clear_snapshots(cls): - for snapshot in cls.snapshots: - test_utils.call_and_ignore_notfound_exc( - cls.snapshots_client.delete_snapshot, snapshot) - - for snapshot in cls.snapshots: - test_utils.call_and_ignore_notfound_exc( - cls.snapshots_client.wait_for_resource_deletion, - snapshot) - - def create_server(self, wait_until='ACTIVE', **kwargs): - name = kwargs.pop( - 'name', - data_utils.rand_name(self.__class__.__name__ + '-instance')) - - tenant_network = self.get_tenant_network() - body, _ = compute.create_test_server( - self.os_primary, - tenant_network=tenant_network, - name=name, - wait_until=wait_until, - **kwargs) - - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - waiters.wait_for_server_termination, - self.servers_client, body['id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.servers_client.delete_server, body['id']) - return body - - -class BaseVolumeAdminTest(BaseVolumeTest): - """Base test case class for all Volume Admin API tests.""" - - credentials = ['primary', 'admin'] - - @classmethod - def setup_clients(cls): - super(BaseVolumeAdminTest, cls).setup_clients() - - cls.admin_volume_qos_client = cls.os_admin.volume_qos_v2_client - cls.admin_volume_services_client = \ - cls.os_admin.volume_services_v2_client - cls.admin_volume_types_client = cls.os_admin.volume_types_v2_client - cls.admin_volume_manage_client = cls.os_admin.volume_manage_v2_client - cls.admin_volume_client = cls.os_admin.volumes_v2_client - if cls._api_version == 3: - cls.admin_volume_client = cls.os_admin.volumes_v3_client - cls.admin_hosts_client = cls.os_admin.volume_hosts_v2_client - cls.admin_snapshot_manage_client = \ - cls.os_admin.snapshot_manage_v2_client - cls.admin_snapshots_client = cls.os_admin.snapshots_v2_client - cls.admin_backups_client = cls.os_admin.backups_v2_client - cls.admin_encryption_types_client = \ - cls.os_admin.encryption_types_v2_client - cls.admin_quota_classes_client = \ - cls.os_admin.volume_quota_classes_v2_client - cls.admin_quotas_client = cls.os_admin.volume_quotas_v2_client - cls.admin_volume_limits_client = cls.os_admin.volume_v2_limits_client - cls.admin_capabilities_client = \ - cls.os_admin.volume_capabilities_v2_client - cls.admin_scheduler_stats_client = \ - cls.os_admin.volume_scheduler_stats_v2_client - cls.admin_messages_client = cls.os_admin.volume_v3_messages_client - cls.admin_groups_client = cls.os_admin.groups_v3_client - cls.admin_group_types_client = cls.os_admin.group_types_v3_client - - @classmethod - def resource_setup(cls): - super(BaseVolumeAdminTest, cls).resource_setup() - - cls.qos_specs = [] - cls.volume_types = [] - - @classmethod - def resource_cleanup(cls): - cls.clear_qos_specs() - super(BaseVolumeAdminTest, cls).resource_cleanup() - cls.clear_volume_types() - - @classmethod - def create_test_qos_specs(cls, name=None, consumer=None, **kwargs): - """create a test Qos-Specs.""" - name = name or data_utils.rand_name(cls.__name__ + '-QoS') - consumer = consumer or 'front-end' - qos_specs = cls.admin_volume_qos_client.create_qos( - name=name, consumer=consumer, **kwargs)['qos_specs'] - cls.qos_specs.append(qos_specs['id']) - return qos_specs - - @classmethod - def create_volume_type(cls, name=None, **kwargs): - """Create a test volume-type""" - name = name or data_utils.rand_name(cls.__name__ + '-volume-type') - volume_type = cls.admin_volume_types_client.create_volume_type( - name=name, **kwargs)['volume_type'] - cls.volume_types.append(volume_type['id']) - return volume_type - - def create_group_type(self, name=None, **kwargs): - """Create a test group-type""" - name = name or data_utils.rand_name( - self.__class__.__name__ + '-group-type') - group_type = self.admin_group_types_client.create_group_type( - name=name, **kwargs)['group_type'] - self.addCleanup(self.admin_group_types_client.delete_group_type, - group_type['id']) - return group_type - - @classmethod - def clear_qos_specs(cls): - for qos_id in cls.qos_specs: - test_utils.call_and_ignore_notfound_exc( - cls.admin_volume_qos_client.delete_qos, qos_id) - - for qos_id in cls.qos_specs: - test_utils.call_and_ignore_notfound_exc( - cls.admin_volume_qos_client.wait_for_resource_deletion, qos_id) - - @classmethod - def clear_volume_types(cls): - for vol_type in cls.volume_types: - test_utils.call_and_ignore_notfound_exc( - cls.admin_volume_types_client.delete_volume_type, vol_type) - - for vol_type in cls.volume_types: - test_utils.call_and_ignore_notfound_exc( - cls.admin_volume_types_client.wait_for_resource_deletion, - vol_type) diff --git a/tempest/api/volume/test_availability_zone.py b/tempest/api/volume/test_availability_zone.py deleted file mode 100644 index d0a87db59..000000000 --- a/tempest/api/volume/test_availability_zone.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2014 NEC Corporation -# 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 tempest.api.volume import base -from tempest.lib import decorators - - -class AvailabilityZoneTestJSON(base.BaseVolumeTest): - """Tests Availability Zone API List""" - - @classmethod - def setup_clients(cls): - super(AvailabilityZoneTestJSON, cls).setup_clients() - cls.client = cls.availability_zone_client - - @decorators.idempotent_id('01f1ae88-eba9-4c6b-a011-6f7ace06b725') - def test_get_availability_zone_list(self): - # List of availability zone - availability_zone = (self.client.list_availability_zones() - ['availabilityZoneInfo']) - self.assertNotEmpty(availability_zone) diff --git a/tempest/api/volume/test_extensions.py b/tempest/api/volume/test_extensions.py deleted file mode 100644 index 39ce00c49..000000000 --- a/tempest/api/volume/test_extensions.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2013 IBM 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 oslo_log import log as logging - -from tempest.api.volume import base -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -LOG = logging.getLogger(__name__) - - -class ExtensionsTestJSON(base.BaseVolumeTest): - - @decorators.idempotent_id('94607eb0-43a5-47ca-82aa-736b41bd2e2c') - def test_list_extensions(self): - # List of all extensions - extensions = (self.volumes_extension_client.list_extensions() - ['extensions']) - if not CONF.volume_feature_enabled.api_extensions: - raise self.skipException('There are not any extensions configured') - extension_list = [extension.get('alias') for extension in extensions] - LOG.debug("Cinder extensions: %s", ','.join(extension_list)) - ext = CONF.volume_feature_enabled.api_extensions[0] - if ext == 'all': - self.assertIn('Hosts', map(lambda x: x['name'], extensions)) - elif ext: - self.assertIn(ext, map(lambda x: x['alias'], extensions)) - else: - raise self.skipException('There are not any extensions configured') diff --git a/tempest/api/volume/test_image_metadata.py b/tempest/api/volume/test_image_metadata.py deleted file mode 100644 index 77baf18bf..000000000 --- a/tempest/api/volume/test_image_metadata.py +++ /dev/null @@ -1,72 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# 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 testtools import matchers - -from tempest.api.volume import base -from tempest import config -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class VolumesImageMetadata(base.BaseVolumeTest): - - @classmethod - def skip_checks(cls): - super(VolumesImageMetadata, cls).skip_checks() - if not CONF.service_available.glance: - skip_msg = ("%s skipped as Glance is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def resource_setup(cls): - super(VolumesImageMetadata, cls).resource_setup() - # Create a volume from image ID - cls.volume = cls.create_volume(imageRef=CONF.compute.image_ref) - - @decorators.idempotent_id('03efff0b-5c75-4822-8f10-8789ac15b13e') - @test.services('image') - def test_update_image_metadata(self): - # Update image metadata - image_metadata = {'image_id': '5137a025-3c5f-43c1-bc64-5f41270040a5', - 'image_name': 'image', - 'kernel_id': '6ff710d2-942b-4d6b-9168-8c9cc2404ab1', - 'ramdisk_id': 'somedisk'} - self.volumes_client.update_volume_image_metadata(self.volume['id'], - **image_metadata) - - # Fetch image metadata from the volume - volume_image_metadata = self.volumes_client.show_volume( - self.volume['id'])['volume']['volume_image_metadata'] - - # Verify image metadata was updated - self.assertThat(volume_image_metadata.items(), - matchers.ContainsAll(image_metadata.items())) - - # Delete one item from image metadata of the volume - self.volumes_client.delete_volume_image_metadata(self.volume['id'], - 'ramdisk_id') - del image_metadata['ramdisk_id'] - - # Fetch the new image metadata from the volume - volume_image_metadata = self.volumes_client.show_volume( - self.volume['id'])['volume']['volume_image_metadata'] - - # Verify image metadata was updated after item deletion - self.assertThat(volume_image_metadata.items(), - matchers.ContainsAll(image_metadata.items())) - self.assertNotIn('ramdisk_id', volume_image_metadata) diff --git a/tempest/api/volume/test_snapshot_metadata.py b/tempest/api/volume/test_snapshot_metadata.py deleted file mode 100644 index e6fe25d08..000000000 --- a/tempest/api/volume/test_snapshot_metadata.py +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD -# 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 testtools import matchers - -from tempest.api.volume import base -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class SnapshotMetadataTestJSON(base.BaseVolumeTest): - @classmethod - def skip_checks(cls): - super(SnapshotMetadataTestJSON, cls).skip_checks() - if not CONF.volume_feature_enabled.snapshot: - raise cls.skipException("Cinder snapshot feature disabled") - - @classmethod - def resource_setup(cls): - super(SnapshotMetadataTestJSON, cls).resource_setup() - # Create a volume - cls.volume = cls.create_volume() - # Create a snapshot - cls.snapshot = cls.create_snapshot(volume_id=cls.volume['id']) - - def tearDown(self): - # Update the metadata to {} - self.snapshots_client.update_snapshot_metadata( - self.snapshot['id'], metadata={}) - super(SnapshotMetadataTestJSON, self).tearDown() - - @decorators.idempotent_id('a2f20f99-e363-4584-be97-bc33afb1a56c') - def test_crud_snapshot_metadata(self): - # Create metadata for the snapshot - metadata = {"key1": "value1", - "key2": "value2", - "key3": "value3"} - update = {"key3": "value3_update", - "key4": "value4"} - expect = {"key4": "value4"} - # Create metadata - body = self.snapshots_client.create_snapshot_metadata( - self.snapshot['id'], metadata)['metadata'] - self.assertThat(body.items(), matchers.ContainsAll(metadata.items())) - - # Get the metadata of the snapshot - body = self.snapshots_client.show_snapshot_metadata( - self.snapshot['id'])['metadata'] - self.assertThat(body.items(), matchers.ContainsAll(metadata.items()), - 'Create snapshot metadata failed') - - # Update metadata - body = self.snapshots_client.update_snapshot_metadata( - self.snapshot['id'], metadata=update)['metadata'] - self.assertEqual(update, body) - body = self.snapshots_client.show_snapshot_metadata( - self.snapshot['id'])['metadata'] - self.assertEqual(update, body, 'Update snapshot metadata failed') - - # Delete one item metadata of the snapshot - self.snapshots_client.delete_snapshot_metadata_item( - self.snapshot['id'], "key3") - body = self.snapshots_client.show_snapshot_metadata( - self.snapshot['id'])['metadata'] - self.assertThat(body.items(), matchers.ContainsAll(expect.items()), - 'Delete one item metadata of the snapshot failed') - self.assertNotIn("key3", body) - - @decorators.idempotent_id('e8ff85c5-8f97-477f-806a-3ac364a949ed') - def test_update_show_snapshot_metadata_item(self): - # Update metadata item for the snapshot - metadata = {"key1": "value1", - "key2": "value2", - "key3": "value3"} - update_item = {"key3": "value3_update"} - expect = {"key1": "value1", - "key2": "value2", - "key3": "value3_update"} - # Create metadata for the snapshot - self.snapshots_client.create_snapshot_metadata( - self.snapshot['id'], metadata) - # Get the metadata of the snapshot - body = self.snapshots_client.show_snapshot_metadata( - self.snapshot['id'])['metadata'] - self.assertThat(body.items(), matchers.ContainsAll(metadata.items())) - # Update metadata item - body = self.snapshots_client.update_snapshot_metadata_item( - self.snapshot['id'], "key3", meta=update_item)['meta'] - self.assertEqual(update_item, body) - - # Get a specific metadata item of the snapshot - body = self.snapshots_client.show_snapshot_metadata_item( - self.snapshot['id'], "key3")['meta'] - self.assertEqual({"key3": expect['key3']}, body) - - # Get the metadata of the snapshot - body = self.snapshots_client.show_snapshot_metadata( - self.snapshot['id'])['metadata'] - self.assertThat(body.items(), matchers.ContainsAll(expect.items())) diff --git a/tempest/api/volume/test_versions.py b/tempest/api/volume/test_versions.py deleted file mode 100644 index 0083a3b09..000000000 --- a/tempest/api/volume/test_versions.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2017 NEC Corporation. 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 tempest.api.volume import base -from tempest.lib import decorators - - -class VersionsTest(base.BaseVolumeTest): - - _api_version = 3 - - @decorators.idempotent_id('77838fc4-b49b-4c64-9533-166762517369') - @decorators.attr(type='smoke') - def test_list_versions(self): - # NOTE: The version data is checked on service client side - # with JSON-Schema validation. It is enough to just call - # the API here. - self.versions_client.list_versions()['versions'] diff --git a/tempest/api/volume/test_volume_absolute_limits.py b/tempest/api/volume/test_volume_absolute_limits.py deleted file mode 100644 index 401846895..000000000 --- a/tempest/api/volume/test_volume_absolute_limits.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# 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 tempest.api.volume import base -from tempest import config -from tempest.lib import decorators - - -CONF = config.CONF - - -# NOTE(zhufl): This inherits from BaseVolumeAdminTest because -# it requires force_tenant_isolation=True, which need admin -# credentials to create non-admin users for the tests. -class AbsoluteLimitsTests(base.BaseVolumeAdminTest): # noqa - - # avoid existing volumes of pre-defined tenant - force_tenant_isolation = True - - @classmethod - def resource_setup(cls): - super(AbsoluteLimitsTests, cls).resource_setup() - # Create a shared volume for tests - cls.volume = cls.create_volume() - - @decorators.idempotent_id('8e943f53-e9d6-4272-b2e9-adcf2f7c29ad') - def test_get_volume_absolute_limits(self): - # get volume limit for a tenant - absolute_limits = \ - self.volume_limits_client.show_limits( - )['limits']['absolute'] - - # verify volume limits and defaults per tenants - self.assertEqual(absolute_limits['totalGigabytesUsed'], - CONF.volume.volume_size) - self.assertEqual(absolute_limits['totalVolumesUsed'], 1) - self.assertEqual(absolute_limits['totalSnapshotsUsed'], 0) - self.assertEqual(absolute_limits['totalBackupsUsed'], 0) - self.assertEqual(absolute_limits['totalBackupGigabytesUsed'], 0) diff --git a/tempest/api/volume/test_volume_delete_cascade.py b/tempest/api/volume/test_volume_delete_cascade.py deleted file mode 100644 index bb32c114a..000000000 --- a/tempest/api/volume/test_volume_delete_cascade.py +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# 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 operator - -import testtools - -from tempest.api.volume import base -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class VolumesDeleteCascade(base.BaseVolumeTest): - """Delete a volume with associated snapshots. - - Cinder provides the ability to delete a volume with its - associated snapshots. - It is allow a volume and its snapshots to be removed in one operation - both for usability and performance reasons. - """ - - @classmethod - def skip_checks(cls): - super(VolumesDeleteCascade, cls).skip_checks() - if not CONF.volume_feature_enabled.snapshot: - raise cls.skipException("Cinder snapshot feature disabled") - - def _assert_cascade_delete(self, volume_id): - # Fetch volume ids - volume_list = [ - vol['id'] for vol in - self.volumes_client.list_volumes()['volumes'] - ] - - # Verify the parent volume was deleted - self.assertNotIn(volume_id, volume_list) - - # List snapshots - snapshot_list = self.snapshots_client.list_snapshots()['snapshots'] - - # Verify snapshots were deleted - self.assertNotIn(volume_id, map(operator.itemgetter('volume_id'), - snapshot_list)) - - @decorators.idempotent_id('994e2d40-de37-46e8-b328-a58fba7e4a95') - def test_volume_delete_cascade(self): - # The case validates the ability to delete a volume - # with associated snapshots. - - # Create a volume - volume = self.create_volume() - - for _ in range(2): - self.create_snapshot(volume['id']) - - # Delete the parent volume with associated snapshots - self.volumes_client.delete_volume(volume['id'], cascade=True) - self.volumes_client.wait_for_resource_deletion(volume['id']) - - # Verify volume parent was deleted with its associated snapshots - self._assert_cascade_delete(volume['id']) - - @decorators.idempotent_id('59a77ede-609b-4ee8-9f68-fc3c6ffe97b5') - @testtools.skipIf(CONF.volume.storage_protocol == 'ceph', - 'Skip because of Bug#1677525') - def test_volume_from_snapshot_cascade_delete(self): - # The case validates the ability to delete a volume with - # associated snapshot while there is another volume created - # from that snapshot. - - # Create a volume - volume = self.create_volume() - - snapshot = self.create_snapshot(volume['id']) - - # Create volume from snapshot - volume_snap = self.create_volume(snapshot_id=snapshot['id']) - volume_details = self.volumes_client.show_volume( - volume_snap['id'])['volume'] - self.assertEqual(snapshot['id'], volume_details['snapshot_id']) - - # Delete the parent volume with associated snapshot - self.volumes_client.delete_volume(volume['id'], cascade=True) - self.volumes_client.wait_for_resource_deletion(volume['id']) - - # Verify volume parent was deleted with its associated snapshot - self._assert_cascade_delete(volume['id']) diff --git a/tempest/api/volume/test_volume_metadata.py b/tempest/api/volume/test_volume_metadata.py deleted file mode 100644 index d203b2d60..000000000 --- a/tempest/api/volume/test_volume_metadata.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright 2013 Huawei Technologies Co.,LTD -# 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 testtools import matchers - -from tempest.api.volume import base -from tempest.lib import decorators - - -class VolumesMetadataTest(base.BaseVolumeTest): - - @classmethod - def resource_setup(cls): - super(VolumesMetadataTest, cls).resource_setup() - # Create a volume - cls.volume = cls.create_volume() - - def tearDown(self): - # Update the metadata to {} - self.volumes_client.update_volume_metadata(self.volume['id'], {}) - super(VolumesMetadataTest, self).tearDown() - - @decorators.idempotent_id('6f5b125b-f664-44bf-910f-751591fe5769') - def test_crud_volume_metadata(self): - # Create metadata for the volume - metadata = {"key1": "value1", - "key2": "value2", - "key3": "value3", - "key4": ""} - update = {"key4": "value4", - "key1": "value1_update"} - expected = {"key4": "value4"} - - body = self.volumes_client.create_volume_metadata(self.volume['id'], - metadata)['metadata'] - self.assertThat(body.items(), matchers.ContainsAll(metadata.items())) - # Get the metadata of the volume - body = self.volumes_client.show_volume_metadata( - self.volume['id'])['metadata'] - self.assertThat(body.items(), matchers.ContainsAll(metadata.items()), - 'Create metadata for the volume failed') - - # Update metadata - body = self.volumes_client.update_volume_metadata( - self.volume['id'], update)['metadata'] - self.assertEqual(update, body) - body = self.volumes_client.show_volume_metadata( - self.volume['id'])['metadata'] - self.assertEqual(update, body, 'Update metadata failed') - - # Delete one item metadata of the volume - self.volumes_client.delete_volume_metadata_item( - self.volume['id'], "key1") - body = self.volumes_client.show_volume_metadata( - self.volume['id'])['metadata'] - self.assertNotIn("key1", body) - self.assertThat(body.items(), matchers.ContainsAll(expected.items()), - 'Delete one item metadata of the volume failed') - - @decorators.idempotent_id('862261c5-8df4-475a-8c21-946e50e36a20') - def test_update_show_volume_metadata_item(self): - # Update metadata item for the volume - metadata = {"key1": "value1", - "key2": "value2", - "key3": "value3"} - update_item = {"key3": "value3_update"} - expect = {"key1": "value1", - "key2": "value2", - "key3": "value3_update"} - # Create metadata for the volume - body = self.volumes_client.create_volume_metadata( - self.volume['id'], metadata)['metadata'] - self.assertThat(body.items(), - matchers.ContainsAll(metadata.items())) - # Update metadata item - body = self.volumes_client.update_volume_metadata_item( - self.volume['id'], "key3", update_item)['meta'] - self.assertEqual(update_item, body) - - # Get a specific metadata item of the volume - body = self.volumes_client.show_volume_metadata_item( - self.volume['id'], "key3")['meta'] - self.assertEqual({"key3": expect['key3']}, body) - - # Get the metadata of the volume - body = self.volumes_client.show_volume_metadata( - self.volume['id'])['metadata'] - self.assertThat(body.items(), matchers.ContainsAll(expect.items())) diff --git a/tempest/api/volume/test_volume_transfers.py b/tempest/api/volume/test_volume_transfers.py deleted file mode 100644 index 4108da5dd..000000000 --- a/tempest/api/volume/test_volume_transfers.py +++ /dev/null @@ -1,100 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 tempest.api.volume import base -from tempest.common import waiters -from tempest.lib import decorators - - -class VolumesTransfersTest(base.BaseVolumeTest): - - credentials = ['primary', 'alt', 'admin'] - - @classmethod - def setup_clients(cls): - super(VolumesTransfersTest, cls).setup_clients() - - cls.client = cls.os_primary.volume_transfers_v2_client - cls.alt_client = cls.os_alt.volume_transfers_v2_client - cls.alt_volumes_client = cls.os_alt.volumes_v2_client - cls.adm_volumes_client = cls.os_admin.volumes_v2_client - - @decorators.idempotent_id('4d75b645-a478-48b1-97c8-503f64242f1a') - def test_create_get_list_accept_volume_transfer(self): - # Create a volume first - volume = self.create_volume() - self.addCleanup(self.delete_volume, - self.adm_volumes_client, - volume['id']) - - # Create a volume transfer - transfer = self.client.create_volume_transfer( - volume_id=volume['id'])['transfer'] - transfer_id = transfer['id'] - auth_key = transfer['auth_key'] - waiters.wait_for_volume_resource_status( - self.volumes_client, volume['id'], 'awaiting-transfer') - - # Get a volume transfer - body = self.client.show_volume_transfer(transfer_id)['transfer'] - self.assertEqual(volume['id'], body['volume_id']) - - # List volume transfers, the result should be greater than - # or equal to 1 - body = self.client.list_volume_transfers()['transfers'] - self.assertNotEmpty(body) - - # Accept a volume transfer by alt_tenant - body = self.alt_client.accept_volume_transfer( - transfer_id, auth_key=auth_key)['transfer'] - for key in ['id', 'name', 'links', 'volume_id']: - self.assertIn(key, body) - waiters.wait_for_volume_resource_status(self.alt_volumes_client, - volume['id'], 'available') - accepted_volume = self.alt_volumes_client.show_volume( - volume['id'])['volume'] - self.assertEqual(self.os_alt.credentials.user_id, - accepted_volume['user_id']) - self.assertEqual(self.os_alt.credentials.project_id, - accepted_volume['os-vol-tenant-attr:tenant_id']) - - @decorators.idempotent_id('ab526943-b725-4c07-b875-8e8ef87a2c30') - def test_create_list_delete_volume_transfer(self): - # Create a volume first - volume = self.create_volume() - self.addCleanup(self.delete_volume, - self.adm_volumes_client, - volume['id']) - - # Create a volume transfer - transfer_id = self.client.create_volume_transfer( - volume_id=volume['id'])['transfer']['id'] - waiters.wait_for_volume_resource_status( - self.volumes_client, volume['id'], 'awaiting-transfer') - - # List all volume transfers with details, check the detail-specific - # elements, and look for the created transfer. - transfers = self.client.list_volume_transfers(detail=True)['transfers'] - self.assertNotEmpty(transfers) - for transfer in transfers: - self.assertIn('created_at', transfer) - volume_list = [transfer['volume_id'] for transfer in transfers] - self.assertIn(volume['id'], volume_list, - 'Transfer not found for volume %s' % volume['id']) - - # Delete a volume transfer - self.client.delete_volume_transfer(transfer_id) - waiters.wait_for_volume_resource_status( - self.volumes_client, volume['id'], 'available') diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py deleted file mode 100644 index c4d10c3d1..000000000 --- a/tempest/api/volume/test_volumes_actions.py +++ /dev/null @@ -1,141 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class VolumesActionsTest(base.BaseVolumeTest): - - @classmethod - def resource_setup(cls): - super(VolumesActionsTest, cls).resource_setup() - - # Create a test shared volume for attach/detach tests - cls.volume = cls.create_volume() - - @decorators.idempotent_id('fff42874-7db5-4487-a8e1-ddda5fb5288d') - @decorators.attr(type='smoke') - @test.services('compute') - def test_attach_detach_volume_to_instance(self): - # Create a server - server = self.create_server() - # Volume is attached and detached successfully from an instance - self.volumes_client.attach_volume(self.volume['id'], - instance_uuid=server['id'], - mountpoint='/dev/%s' % - CONF.compute.volume_device_name) - waiters.wait_for_volume_resource_status(self.volumes_client, - self.volume['id'], 'in-use') - self.volumes_client.detach_volume(self.volume['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - self.volume['id'], 'available') - - @decorators.idempotent_id('63e21b4c-0a0c-41f6-bfc3-7c2816815599') - def test_volume_bootable(self): - # Verify that a volume bootable flag is retrieved - for bool_bootable in [True, False]: - self.volumes_client.set_bootable_volume(self.volume['id'], - bootable=bool_bootable) - fetched_volume = self.volumes_client.show_volume( - self.volume['id'])['volume'] - # Get Volume information - # NOTE(masayukig): 'bootable' is "true" or "false" in the current - # cinder implementation. So we need to cast boolean values to str - # and make it lower to compare here. - self.assertEqual(str(bool_bootable).lower(), - fetched_volume['bootable']) - - @decorators.idempotent_id('9516a2c8-9135-488c-8dd6-5677a7e5f371') - @test.services('compute') - def test_get_volume_attachment(self): - # Create a server - server = self.create_server() - # Verify that a volume's attachment information is retrieved - self.volumes_client.attach_volume(self.volume['id'], - instance_uuid=server['id'], - mountpoint='/dev/%s' % - CONF.compute.volume_device_name) - waiters.wait_for_volume_resource_status(self.volumes_client, - self.volume['id'], - 'in-use') - self.addCleanup(waiters.wait_for_volume_resource_status, - self.volumes_client, - self.volume['id'], 'available') - self.addCleanup(self.volumes_client.detach_volume, self.volume['id']) - volume = self.volumes_client.show_volume(self.volume['id'])['volume'] - self.assertIn('attachments', volume) - attachment = volume['attachments'][0] - - self.assertEqual('/dev/%s' % - CONF.compute.volume_device_name, - attachment['device']) - self.assertEqual(server['id'], attachment['server_id']) - self.assertEqual(self.volume['id'], attachment['id']) - self.assertEqual(self.volume['id'], attachment['volume_id']) - - @decorators.idempotent_id('d8f1ca95-3d5b-44a3-b8ca-909691c9532d') - @test.services('image') - def test_volume_upload(self): - # NOTE(gfidente): the volume uploaded in Glance comes from setUpClass, - # it is shared with the other tests. After it is uploaded in Glance, - # there is no way to delete it from Cinder, so we delete it from Glance - # using the Glance images_client and from Cinder via tearDownClass. - image_name = data_utils.rand_name(self.__class__.__name__ + '-Image') - body = self.volumes_client.upload_volume( - self.volume['id'], image_name=image_name, - disk_format=CONF.volume.disk_format)['os-volume_upload_image'] - image_id = body["image_id"] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.images_client.delete_image, - image_id) - waiters.wait_for_image_status(self.images_client, image_id, 'active') - waiters.wait_for_volume_resource_status(self.volumes_client, - self.volume['id'], 'available') - - @decorators.idempotent_id('92c4ef64-51b2-40c0-9f7e-4749fbaaba33') - def test_reserve_unreserve_volume(self): - # Mark volume as reserved. - self.volumes_client.reserve_volume(self.volume['id']) - # To get the volume info - body = self.volumes_client.show_volume(self.volume['id'])['volume'] - self.assertIn('attaching', body['status']) - # Unmark volume as reserved. - self.volumes_client.unreserve_volume(self.volume['id']) - # To get the volume info - body = self.volumes_client.show_volume(self.volume['id'])['volume'] - self.assertIn('available', body['status']) - - @decorators.idempotent_id('fff74e1e-5bd3-4b33-9ea9-24c103bc3f59') - def test_volume_readonly_update(self): - for readonly in [True, False]: - # Update volume readonly - self.volumes_client.update_volume_readonly(self.volume['id'], - readonly=readonly) - # Get Volume information - fetched_volume = self.volumes_client.show_volume( - self.volume['id'])['volume'] - # NOTE(masayukig): 'readonly' is "True" or "False" in the current - # cinder implementation. So we need to cast boolean values to str - # to compare here. - self.assertEqual(str(readonly), - fetched_volume['metadata']['readonly']) diff --git a/tempest/api/volume/test_volumes_backup.py b/tempest/api/volume/test_volumes_backup.py deleted file mode 100644 index 1f91db67d..000000000 --- a/tempest/api/volume/test_volumes_backup.py +++ /dev/null @@ -1,178 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# 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 testtools -from testtools import matchers - -from tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class VolumesBackupsTest(base.BaseVolumeTest): - - @classmethod - def skip_checks(cls): - super(VolumesBackupsTest, cls).skip_checks() - if not CONF.volume_feature_enabled.backup: - raise cls.skipException("Cinder backup feature disabled") - - def restore_backup(self, backup_id): - # Restore a backup - restored_volume = self.backups_client.restore_backup( - backup_id)['restore'] - - # Delete backup - self.addCleanup(self.volumes_client.delete_volume, - restored_volume['volume_id']) - self.assertEqual(backup_id, restored_volume['backup_id']) - waiters.wait_for_volume_resource_status(self.backups_client, - backup_id, 'available') - waiters.wait_for_volume_resource_status(self.volumes_client, - restored_volume['volume_id'], - 'available') - return restored_volume - - @testtools.skipIf(CONF.volume.storage_protocol == 'ceph', - 'ceph does not support arbitrary container names') - @decorators.idempotent_id('a66eb488-8ee1-47d4-8e9f-575a095728c6') - def test_volume_backup_create_get_detailed_list_restore_delete(self): - # Create a volume with metadata - metadata = {"vol-meta1": "value1", - "vol-meta2": "value2", - "vol-meta3": "value3"} - volume = self.create_volume(metadata=metadata) - self.addCleanup(self.volumes_client.delete_volume, - volume['id']) - - # Create a backup - backup_name = data_utils.rand_name( - self.__class__.__name__ + '-Backup') - description = data_utils.rand_name("volume-backup-description") - backup = self.create_backup(volume_id=volume['id'], - name=backup_name, - description=description, - container='container') - self.assertEqual(backup_name, backup['name']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') - - # Get a given backup - backup = self.backups_client.show_backup(backup['id'])['backup'] - self.assertEqual(backup_name, backup['name']) - self.assertEqual(description, backup['description']) - self.assertEqual('container', backup['container']) - - # Get all backups with detail - backups = self.backups_client.list_backups( - detail=True)['backups'] - self.assertIn((backup['name'], backup['id']), - [(m['name'], m['id']) for m in backups]) - - restored_volume = self.restore_backup(backup['id']) - - restored_volume_metadata = self.volumes_client.show_volume( - restored_volume['volume_id'])['volume']['metadata'] - - # Verify the backups has been restored successfully - # with the metadata of the source volume. - self.assertThat(restored_volume_metadata.items(), - matchers.ContainsAll(metadata.items())) - - @decorators.idempotent_id('07af8f6d-80af-44c9-a5dc-c8427b1b62e6') - @test.services('compute') - def test_backup_create_attached_volume(self): - """Test backup create using force flag. - - Cinder allows to create a volume backup, whether the volume status - is "available" or "in-use". - """ - # Create a server - volume = self.create_volume() - self.addCleanup(self.volumes_client.delete_volume, - volume['id']) - server = self.create_server() - # Attach volume to instance - self.attach_volume(server['id'], volume['id']) - # Create backup using force flag - backup_name = data_utils.rand_name( - self.__class__.__name__ + '-Backup') - backup = self.create_backup(volume_id=volume['id'], - name=backup_name, force=True) - self.assertEqual(backup_name, backup['name']) - - @decorators.idempotent_id('2a8ba340-dff2-4511-9db7-646f07156b15') - @test.services('image') - def test_bootable_volume_backup_and_restore(self): - # Create volume from image - img_uuid = CONF.compute.image_ref - volume = self.create_volume(imageRef=img_uuid) - - volume_details = self.volumes_client.show_volume( - volume['id'])['volume'] - self.assertEqual('true', volume_details['bootable']) - - # Create a backup - backup = self.create_backup(volume_id=volume['id']) - - # Restore the backup - restored_volume_id = self.restore_backup(backup['id'])['volume_id'] - - # Verify the restored backup volume is bootable - restored_volume_info = self.volumes_client.show_volume( - restored_volume_id)['volume'] - - self.assertEqual('true', restored_volume_info['bootable']) - - -class VolumesBackupsV39Test(base.BaseVolumeTest): - - _api_version = 3 - min_microversion = '3.9' - max_microversion = 'latest' - - @classmethod - def skip_checks(cls): - super(VolumesBackupsV39Test, cls).skip_checks() - if not CONF.volume_feature_enabled.backup: - raise cls.skipException("Cinder backup feature disabled") - - @decorators.idempotent_id('9b374cbc-be5f-4d37-8848-7efb8a873dcc') - def test_update_backup(self): - # Create volume and backup - volume = self.create_volume() - backup = self.create_backup(volume_id=volume['id']) - - # Update backup and assert response body for update_backup method - update_kwargs = { - 'name': data_utils.rand_name(self.__class__.__name__ + '-Backup'), - 'description': data_utils.rand_name("volume-backup-description") - } - update_backup = self.backups_client.update_backup( - backup['id'], **update_kwargs)['backup'] - self.assertEqual(backup['id'], update_backup['id']) - self.assertEqual(update_kwargs['name'], update_backup['name']) - self.assertIn('links', update_backup) - - # Assert response body for show_backup method - retrieved_backup = self.backups_client.show_backup( - backup['id'])['backup'] - for key in update_kwargs: - self.assertEqual(update_kwargs[key], retrieved_backup[key]) diff --git a/tempest/api/volume/test_volumes_clone.py b/tempest/api/volume/test_volumes_clone.py deleted file mode 100644 index 927bfa5a2..000000000 --- a/tempest/api/volume/test_volumes_clone.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# 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 tempest.api.volume import base -from tempest import config -from tempest.lib import decorators -from tempest import test - - -CONF = config.CONF - - -class VolumesCloneTest(base.BaseVolumeTest): - - @classmethod - def skip_checks(cls): - super(VolumesCloneTest, cls).skip_checks() - if not CONF.volume_feature_enabled.clone: - raise cls.skipException("Cinder volume clones are disabled") - - def _verify_volume_clone(self, source_volume, cloned_volume, - bootable='false', extra_size=0): - - cloned_vol_details = self.volumes_client.show_volume( - cloned_volume['id'])['volume'] - - self.assertEqual(source_volume['id'], - cloned_vol_details['source_volid']) - self.assertEqual(source_volume['size'] + extra_size, - cloned_vol_details['size']) - self.assertEqual(bootable, cloned_vol_details['bootable']) - - @decorators.idempotent_id('9adae371-a257-43a5-9555-dc7c88e66e0e') - def test_create_from_volume(self): - # Creates a volume from another volume passing a size different from - # the source volume. - src_size = CONF.volume.volume_size - - src_vol = self.create_volume(size=src_size) - # Destination volume bigger than source - dst_vol = self.create_volume(source_volid=src_vol['id'], - size=src_size + 1) - - self._verify_volume_clone(src_vol, dst_vol, extra_size=1) - - @decorators.idempotent_id('cbbcd7c6-5a6c-481a-97ac-ca55ab715d16') - @test.services('image') - def test_create_from_bootable_volume(self): - # Create volume from image - img_uuid = CONF.compute.image_ref - src_vol = self.create_volume(imageRef=img_uuid) - - # Create a volume from the bootable volume - cloned_vol = self.create_volume(source_volid=src_vol['id']) - - self._verify_volume_clone(src_vol, cloned_vol, bootable='true') diff --git a/tempest/api/volume/test_volumes_clone_negative.py b/tempest/api/volume/test_volumes_clone_negative.py deleted file mode 100644 index bba7a0bb8..000000000 --- a/tempest/api/volume/test_volumes_clone_negative.py +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# 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 tempest.api.volume import base -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions - -CONF = config.CONF - - -class VolumesCloneNegativeTest(base.BaseVolumeTest): - - @classmethod - def skip_checks(cls): - super(VolumesCloneNegativeTest, cls).skip_checks() - if not CONF.volume_feature_enabled.clone: - raise cls.skipException("Cinder volume clones are disabled") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9adae371-a257-43a5-459a-dc7c88e66e0e') - def test_create_from_volume_decreasing_size(self): - # Creates a volume from another volume passing a size different from - # the source volume. - src_size = CONF.volume.volume_size + 1 - src_vol = self.create_volume(size=src_size) - - # Destination volume smaller than source - self.assertRaises(exceptions.BadRequest, - self.volumes_client.create_volume, - size=src_size - 1, - source_volid=src_vol['id']) diff --git a/tempest/api/volume/test_volumes_extend.py b/tempest/api/volume/test_volumes_extend.py deleted file mode 100644 index 1eb76a06a..000000000 --- a/tempest/api/volume/test_volumes_extend.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 testtools - -from tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class VolumesExtendTest(base.BaseVolumeTest): - - @decorators.idempotent_id('9a36df71-a257-43a5-9555-dc7c88e66e0e') - def test_volume_extend(self): - # Extend Volume Test. - volume = self.create_volume() - extend_size = volume['size'] + 1 - self.volumes_client.extend_volume(volume['id'], - new_size=extend_size) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') - volume = self.volumes_client.show_volume(volume['id'])['volume'] - self.assertEqual(volume['size'], extend_size) - - @decorators.idempotent_id('86be1cba-2640-11e5-9c82-635fb964c912') - @testtools.skipUnless(CONF.volume_feature_enabled.snapshot, - "Cinder volume snapshots are disabled") - @decorators.skip_because(bug='1687044') - def test_volume_extend_when_volume_has_snapshot(self): - volume = self.create_volume() - self.create_snapshot(volume['id']) - - extend_size = volume['size'] + 1 - self.volumes_client.extend_volume(volume['id'], new_size=extend_size) - - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') - resized_volume = self.volumes_client.show_volume( - volume['id'])['volume'] - self.assertEqual(extend_size, resized_volume['size']) diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py deleted file mode 100644 index ec9a0dd9f..000000000 --- a/tempest/api/volume/test_volumes_get.py +++ /dev/null @@ -1,153 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 testtools -from testtools import matchers - -from tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest import test - -CONF = config.CONF - - -class VolumesGetTest(base.BaseVolumeTest): - - def _volume_create_get_update_delete(self, **kwargs): - # Create a volume, Get it's details and Delete the volume - v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume') - metadata = {'Type': 'Test'} - # Create a volume - kwargs['name'] = v_name - kwargs['metadata'] = metadata - volume = self.volumes_client.create_volume(**kwargs)['volume'] - self.assertIn('id', volume) - self.addCleanup(self.delete_volume, self.volumes_client, volume['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') - self.assertIn('name', volume) - self.assertEqual(volume['name'], v_name, - "The created volume name is not equal " - "to the requested name") - - # Get Volume information - fetched_volume = self.volumes_client.show_volume( - volume['id'])['volume'] - self.assertEqual(v_name, - fetched_volume['name'], - 'The fetched Volume name is different ' - 'from the created Volume') - self.assertEqual(volume['id'], - fetched_volume['id'], - 'The fetched Volume id is different ' - 'from the created Volume') - self.assertThat(fetched_volume['metadata'].items(), - matchers.ContainsAll(metadata.items()), - 'The fetched Volume metadata misses data ' - 'from the created Volume') - - if 'imageRef' in kwargs: - self.assertEqual('true', fetched_volume['bootable']) - else: - self.assertEqual('false', fetched_volume['bootable']) - - # Update Volume - # Test volume update when display_name is same with original value - params = {'name': v_name} - self.volumes_client.update_volume(volume['id'], **params) - # Test volume update when display_name is new - new_v_name = data_utils.rand_name( - self.__class__.__name__ + '-new-Volume') - new_desc = 'This is the new description of volume' - params = {'name': new_v_name, - 'description': new_desc} - update_volume = self.volumes_client.update_volume( - volume['id'], **params)['volume'] - # Assert response body for update_volume method - self.assertEqual(new_v_name, update_volume['name']) - self.assertEqual(new_desc, update_volume['description']) - # Assert response body for show_volume method - updated_volume = self.volumes_client.show_volume( - volume['id'])['volume'] - self.assertEqual(volume['id'], updated_volume['id']) - self.assertEqual(new_v_name, updated_volume['name']) - self.assertEqual(new_desc, updated_volume['description']) - self.assertThat(updated_volume['metadata'].items(), - matchers.ContainsAll(metadata.items()), - 'The fetched Volume metadata misses data ' - 'from the created Volume') - - # Test volume create when display_name is none and display_description - # contains specific characters, - # then test volume update if display_name is duplicated - new_v_desc = data_utils.rand_name('@#$%^* description') - params = {'description': new_v_desc, - 'availability_zone': volume['availability_zone'], - 'size': CONF.volume.volume_size} - new_volume = self.volumes_client.create_volume(**params)['volume'] - self.assertIn('id', new_volume) - self.addCleanup(self.delete_volume, self.volumes_client, - new_volume['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - new_volume['id'], 'available') - - params = {'name': volume['name'], - 'description': volume['description']} - self.volumes_client.update_volume(new_volume['id'], **params) - - if 'imageRef' in kwargs: - self.assertEqual('true', updated_volume['bootable']) - else: - self.assertEqual('false', updated_volume['bootable']) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('27fb0e9f-fb64-41dd-8bdb-1ffa762f0d51') - def test_volume_create_get_update_delete(self): - self._volume_create_get_update_delete(size=CONF.volume.volume_size) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('54a01030-c7fc-447c-86ee-c1182beae638') - @test.services('image') - def test_volume_create_get_update_delete_from_image(self): - image = self.images_client.show_image(CONF.compute.image_ref) - min_disk = image['min_disk'] - disk_size = max(min_disk, CONF.volume.volume_size) - self._volume_create_get_update_delete( - imageRef=CONF.compute.image_ref, size=disk_size) - - @decorators.idempotent_id('3f591b4a-7dc6-444c-bd51-77469506b3a1') - @testtools.skipUnless(CONF.volume_feature_enabled.clone, - 'Cinder volume clones are disabled') - def test_volume_create_get_update_delete_as_clone(self): - origin = self.create_volume() - self._volume_create_get_update_delete(source_volid=origin['id'], - size=CONF.volume.volume_size) - - -class VolumesSummaryTest(base.BaseVolumeTest): - - _api_version = 3 - min_microversion = '3.12' - max_microversion = 'latest' - - @decorators.idempotent_id('c4f2431e-4920-4736-9e00-4040386b6feb') - def test_show_volume_summary(self): - volume_summary = \ - self.volumes_client.show_volume_summary()['volume-summary'] - for key in ['total_size', 'total_count']: - self.assertIn(key, volume_summary) diff --git a/tempest/api/volume/test_volumes_list.py b/tempest/api/volume/test_volumes_list.py deleted file mode 100644 index 8593d3a8e..000000000 --- a/tempest/api/volume/test_volumes_list.py +++ /dev/null @@ -1,380 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# Copyright 2013 IBM 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 operator -import random - -from six.moves.urllib import parse -from testtools import matchers - -from tempest.api.volume import base -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - - -class VolumesListTestJSON(base.BaseVolumeTest): - # NOTE: This test creates a number of 1G volumes. To run successfully, - # ensure that the backing file for the volume group that Nova uses - # has space for at least 3 1G volumes! - # If you are running a Devstack environment, ensure that the - # VOLUME_BACKING_FILE_SIZE is at least 4G in your localrc - - VOLUME_FIELDS = ('id', 'name') - - def assertVolumesIn(self, fetched_list, expected_list, fields=None): - """Check out the list. - - This function is aim at check out whether all of the volumes in - expected_list are in fetched_list. - """ - if fields: - fieldsgetter = operator.itemgetter(*fields) - expected_list = map(fieldsgetter, expected_list) - fetched_list = [fieldsgetter(item) for item in fetched_list] - - missing_vols = [v for v in expected_list if v not in fetched_list] - if not missing_vols: - return - - def str_vol(vol): - return "%s:%s" % (vol['id'], vol[self.name]) - - raw_msg = "Could not find volumes %s in expected list %s; fetched %s" - self.fail(raw_msg % ([str_vol(v) for v in missing_vols], - [str_vol(v) for v in expected_list], - [str_vol(v) for v in fetched_list])) - - @classmethod - def resource_setup(cls): - super(VolumesListTestJSON, cls).resource_setup() - cls.name = cls.VOLUME_FIELDS[1] - - existing_volumes = cls.volumes_client.list_volumes()['volumes'] - cls.volume_id_list = [vol['id'] for vol in existing_volumes] - - # Create 3 test volumes - cls.volume_list = [] - cls.metadata = {'Type': 'work'} - for _ in range(3): - volume = cls.create_volume(metadata=cls.metadata) - volume = cls.volumes_client.show_volume(volume['id'])['volume'] - cls.volume_list.append(volume) - cls.volume_id_list.append(volume['id']) - - def _list_by_param_value_and_assert(self, params, with_detail=False): - """list or list_details with given params and validates result""" - if with_detail: - fetched_vol_list = \ - self.volumes_client.list_volumes(detail=True, - params=params)['volumes'] - else: - fetched_vol_list = self.volumes_client.list_volumes( - params=params)['volumes'] - - # Validating params of fetched volumes - if with_detail: - for volume in fetched_vol_list: - for key in params: - msg = "Failed to list volumes %s by %s" % \ - ('details' if with_detail else '', key) - if key == 'metadata': - self.assertThat( - volume[key].items(), - matchers.ContainsAll(params[key].items()), - msg) - else: - self.assertEqual(params[key], volume[key], msg) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('0b6ddd39-b948-471f-8038-4787978747c4') - def test_volume_list(self): - # Get a list of Volumes - # Fetch all volumes - fetched_list = self.volumes_client.list_volumes()['volumes'] - self.assertVolumesIn(fetched_list, self.volume_list, - fields=self.VOLUME_FIELDS) - - @decorators.idempotent_id('adcbb5a7-5ad8-4b61-bd10-5380e111a877') - def test_volume_list_with_details(self): - # Get a list of Volumes with details - # Fetch all Volumes - fetched_list = self.volumes_client.list_volumes(detail=True)['volumes'] - self.assertVolumesIn(fetched_list, self.volume_list) - - @decorators.idempotent_id('a28e8da4-0b56-472f-87a8-0f4d3f819c02') - def test_volume_list_by_name(self): - volume = self.volume_list[data_utils.rand_int_id(0, 2)] - params = {self.name: volume[self.name]} - fetched_vol = self.volumes_client.list_volumes( - params=params)['volumes'] - self.assertEqual(1, len(fetched_vol), str(fetched_vol)) - self.assertEqual(fetched_vol[0][self.name], - volume[self.name]) - - @decorators.idempotent_id('2de3a6d4-12aa-403b-a8f2-fdeb42a89623') - def test_volume_list_details_by_name(self): - volume = self.volume_list[data_utils.rand_int_id(0, 2)] - params = {self.name: volume[self.name]} - fetched_vol = self.volumes_client.list_volumes( - detail=True, params=params)['volumes'] - self.assertEqual(1, len(fetched_vol), str(fetched_vol)) - self.assertEqual(fetched_vol[0][self.name], - volume[self.name]) - - @decorators.idempotent_id('39654e13-734c-4dab-95ce-7613bf8407ce') - def test_volumes_list_by_status(self): - params = {'status': 'available'} - fetched_list = self.volumes_client.list_volumes( - params=params)['volumes'] - self._list_by_param_value_and_assert(params) - self.assertVolumesIn(fetched_list, self.volume_list, - fields=self.VOLUME_FIELDS) - - @decorators.idempotent_id('2943f712-71ec-482a-bf49-d5ca06216b9f') - def test_volumes_list_details_by_status(self): - params = {'status': 'available'} - fetched_list = self.volumes_client.list_volumes( - detail=True, params=params)['volumes'] - for volume in fetched_list: - self.assertEqual('available', volume['status']) - self.assertVolumesIn(fetched_list, self.volume_list) - - @decorators.idempotent_id('2016a942-3020-40d7-95ce-7613bf8407ce') - def test_volumes_list_by_bootable(self): - """Check out volumes. - - This test function is aim at check out whether all of the volumes - in volume_list are not a bootable volume. - """ - params = {'bootable': 'false'} - fetched_list = self.volumes_client.list_volumes( - params=params)['volumes'] - self._list_by_param_value_and_assert(params) - self.assertVolumesIn(fetched_list, self.volume_list, - fields=self.VOLUME_FIELDS) - - @decorators.idempotent_id('2016a939-72ec-482a-bf49-d5ca06216b9f') - def test_volumes_list_details_by_bootable(self): - params = {'bootable': 'false'} - fetched_list = self.volumes_client.list_volumes( - detail=True, params=params)['volumes'] - for volume in fetched_list: - self.assertEqual('false', volume['bootable']) - self.assertVolumesIn(fetched_list, self.volume_list) - - @decorators.idempotent_id('c0cfa863-3020-40d7-b587-e35f597d5d87') - def test_volumes_list_by_availability_zone(self): - volume = self.volume_list[data_utils.rand_int_id(0, 2)] - zone = volume['availability_zone'] - params = {'availability_zone': zone} - fetched_list = self.volumes_client.list_volumes( - params=params)['volumes'] - self._list_by_param_value_and_assert(params) - self.assertVolumesIn(fetched_list, self.volume_list, - fields=self.VOLUME_FIELDS) - - @decorators.idempotent_id('e1b80d13-94f0-4ba2-a40e-386af29f8db1') - def test_volumes_list_details_by_availability_zone(self): - volume = self.volume_list[data_utils.rand_int_id(0, 2)] - zone = volume['availability_zone'] - params = {'availability_zone': zone} - fetched_list = self.volumes_client.list_volumes( - detail=True, params=params)['volumes'] - for volume in fetched_list: - self.assertEqual(zone, volume['availability_zone']) - self.assertVolumesIn(fetched_list, self.volume_list) - - @decorators.idempotent_id('b5ebea1b-0603-40a0-bb41-15fcd0a53214') - def test_volume_list_with_param_metadata(self): - # Test to list volumes when metadata param is given - params = {'metadata': self.metadata} - self._list_by_param_value_and_assert(params) - - @decorators.idempotent_id('1ca92d3c-4a8e-4b43-93f5-e4c7fb3b291d') - def test_volume_list_with_detail_param_metadata(self): - # Test to list volumes details when metadata param is given - params = {'metadata': self.metadata} - self._list_by_param_value_and_assert(params, with_detail=True) - - @decorators.idempotent_id('777c87c1-2fc4-4883-8b8e-5c0b951d1ec8') - def test_volume_list_param_display_name_and_status(self): - # Test to list volume when display name and status param is given - volume = self.volume_list[data_utils.rand_int_id(0, 2)] - params = {self.name: volume[self.name], - 'status': 'available'} - self._list_by_param_value_and_assert(params) - - @decorators.idempotent_id('856ab8ca-6009-4c37-b691-be1065528ad4') - def test_volume_list_with_detail_param_display_name_and_status(self): - # Test to list volume when name and status param is given - volume = self.volume_list[data_utils.rand_int_id(0, 2)] - params = {self.name: volume[self.name], - 'status': 'available'} - self._list_by_param_value_and_assert(params, with_detail=True) - - @decorators.idempotent_id('2a7064eb-b9c3-429b-b888-33928fc5edd3') - def test_volume_list_details_with_multiple_params(self): - # List volumes detail using combined condition - def _list_details_with_multiple_params(limit=2, - status='available', - sort_dir='asc', - sort_key='id'): - params = {'limit': limit, - 'status': status, - 'sort_dir': sort_dir, - 'sort_key': sort_key - } - fetched_volume = self.volumes_client.list_volumes( - detail=True, params=params)['volumes'] - self.assertEqual(limit, len(fetched_volume), - "The count of volumes is %s, expected:%s " % - (len(fetched_volume), limit)) - self.assertEqual(status, fetched_volume[0]['status']) - self.assertEqual(status, fetched_volume[1]['status']) - val0 = fetched_volume[0][sort_key] - val1 = fetched_volume[1][sort_key] - if sort_dir == 'asc': - self.assertLess(val0, val1, - "list is not in asc order with sort_key: %s." - " %s" % (sort_key, fetched_volume)) - elif sort_dir == 'desc': - self.assertGreater(val0, val1, - "list is not in desc order with sort_key: " - "%s. %s" % (sort_key, fetched_volume)) - - _list_details_with_multiple_params() - _list_details_with_multiple_params(sort_dir='desc') - - def _test_pagination(self, resource, ids=None, limit=1, **kwargs): - """Check list pagination functionality for a resource. - - This method requests the list of resources and follows pagination - links. - - If an iterable is supplied in ids it will check that all ids are - retrieved and that only those are listed, that we will get a next - link for an empty page if the number of items is divisible by used - limit (this is expected behavior). - - We can specify number of items per request using limit argument. - """ - - # Get list method for the type of resource from the client - client = getattr(self, resource + '_client') - method = getattr(client, 'list_' + resource) - - # Include limit in params for list request - params = kwargs.pop('params', {}) - params['limit'] = limit - - # Store remaining items we are expecting from list - if ids is not None: - remaining = list(ids) - else: - remaining = None - - # Mark that the current iteration is not from a 'next' link - next = None - - while True: - # Get a list page - response = method(params=params, **kwargs) - - # If we have to check ids - if remaining is not None: - # Confirm we receive expected number of elements - num_expected = min(len(remaining), limit) - self.assertEqual(num_expected, len(response[resource]), - 'Requested %(#expect)d but got %(#received)d ' - % {'#expect': num_expected, - '#received': len(response[resource])}) - - # For each received element - for element in response[resource]: - element_id = element['id'] - # Check it's one of expected ids - self.assertIn(element_id, - ids, - 'Id %(id)s is not in expected ids %(ids)s' % - {'id': element_id, 'ids': ids}) - # If not in remaining, we have received it twice - self.assertIn(element_id, - remaining, - 'Id %s was received twice' % element_id) - # We no longer expect it - remaining.remove(element_id) - - # If the current iteration is from a 'next' link, check that the - # absolute url is the same as the one used for this request - if next: - self.assertEqual(next, response.response['content-location']) - - # Get next from response - next = None - for link in response.get(resource + '_links', ()): - if link['rel'] == 'next': - next = link['href'] - break - - # Check if we have next and we shouldn't or the other way around - if remaining is not None: - if remaining or (num_expected and len(ids) % limit == 0): - self.assertIsNotNone(next, 'Missing link to next page') - else: - self.assertIsNone(next, 'Unexpected link to next page') - - # If we can follow to the next page, get params from url to make - # request in the form of a relative URL - if next: - params = parse.urlparse(next).query - - # If cannot follow make sure it's because we have finished - else: - self.assertEmpty(remaining or [], - 'No more pages reported, but still ' - 'missing ids %s' % remaining) - break - - @decorators.idempotent_id('e9138a2c-f67b-4796-8efa-635c196d01de') - def test_volume_list_details_pagination(self): - self._test_pagination('volumes', ids=self.volume_id_list, detail=True) - - @decorators.idempotent_id('af55e775-8e4b-4feb-8719-215c43b0238c') - def test_volume_list_pagination(self): - self._test_pagination('volumes', ids=self.volume_id_list, detail=False) - - @decorators.idempotent_id('46eff077-100b-427f-914e-3db2abcdb7e2') - def test_volume_list_with_detail_param_marker(self): - # Choosing a random volume from a list of volumes for 'marker' - # parameter - marker = random.choice(self.volume_id_list) - - # Though Cinder volumes are returned sorted by ID by default - # this is implicit. Let make this explicit in case Cinder - # folks change their minds. - params = {'marker': marker, 'sort': 'id:asc'} - - # Running volume list using marker parameter - vol_with_marker = self.volumes_client.list_volumes( - detail=True, params=params)['volumes'] - - expected_volumes_id = { - id for id in self.volume_id_list if id > marker - } - - self.assertEqual( - expected_volumes_id, {v['id'] for v in vol_with_marker} - ) diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py deleted file mode 100644 index 4e19e620f..000000000 --- a/tempest/api/volume/test_volumes_negative.py +++ /dev/null @@ -1,322 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 six - -from tempest.api.volume import base -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class VolumesNegativeTest(base.BaseVolumeTest): - - @classmethod - def resource_setup(cls): - super(VolumesNegativeTest, cls).resource_setup() - - # Create a test shared instance and volume for attach/detach tests - cls.volume = cls.create_volume() - cls.mountpoint = "/dev/vdc" - - def create_image(self): - # Create image - image_name = data_utils.rand_name(self.__class__.__name__ + "-image") - image = self.images_client.create_image( - name=image_name, - container_format=CONF.image.container_formats[0], - disk_format=CONF.image.disk_formats[0], - visibility='private', - min_disk=CONF.volume.volume_size + 1) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.images_client.delete_image, image['id']) - - # Upload image with 1KB data - image_file = six.BytesIO(data_utils.random_bytes()) - self.images_client.store_image_file(image['id'], image_file) - waiters.wait_for_image_status(self.images_client, - image['id'], 'active') - return image - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f131c586-9448-44a4-a8b0-54ca838aa43e') - def test_volume_get_nonexistent_volume_id(self): - # Should not be able to get a non-existent volume - self.assertRaises(lib_exc.NotFound, self.volumes_client.show_volume, - data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('555efa6e-efcd-44ef-8a3b-4a7ca4837a29') - def test_volume_delete_nonexistent_volume_id(self): - # Should not be able to delete a non-existent Volume - self.assertRaises(lib_exc.NotFound, self.volumes_client.delete_volume, - data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1ed83a8a-682d-4dfb-a30e-ee63ffd6c049') - def test_create_volume_with_invalid_size(self): - # Should not be able to create volume with invalid size in request - self.assertRaises(lib_exc.BadRequest, - self.volumes_client.create_volume, size='#$%') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9387686f-334f-4d31-a439-33494b9e2683') - def test_create_volume_without_passing_size(self): - # Should not be able to create volume without passing size - # in request - self.assertRaises(lib_exc.BadRequest, - self.volumes_client.create_volume, size='') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('41331caa-eaf4-4001-869d-bc18c1869360') - def test_create_volume_with_size_zero(self): - # Should not be able to create volume with size zero - self.assertRaises(lib_exc.BadRequest, - self.volumes_client.create_volume, size='0') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('8b472729-9eba-446e-a83b-916bdb34bef7') - def test_create_volume_with_size_negative(self): - # Should not be able to create volume with size negative - self.assertRaises(lib_exc.BadRequest, - self.volumes_client.create_volume, size='-1') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('10254ed8-3849-454e-862e-3ab8e6aa01d2') - def test_create_volume_with_nonexistent_volume_type(self): - # Should not be able to create volume with non-existent volume type - self.assertRaises(lib_exc.NotFound, self.volumes_client.create_volume, - size='1', volume_type=data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0c36f6ae-4604-4017-b0a9-34fdc63096f9') - def test_create_volume_with_nonexistent_snapshot_id(self): - # Should not be able to create volume with non-existent snapshot - self.assertRaises(lib_exc.NotFound, self.volumes_client.create_volume, - size='1', snapshot_id=data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('47c73e08-4be8-45bb-bfdf-0c4e79b88344') - def test_create_volume_with_nonexistent_source_volid(self): - # Should not be able to create volume with non-existent source volume - self.assertRaises(lib_exc.NotFound, self.volumes_client.create_volume, - size='1', source_volid=data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0186422c-999a-480e-a026-6a665744c30c') - def test_update_volume_with_nonexistent_volume_id(self): - self.assertRaises(lib_exc.NotFound, self.volumes_client.update_volume, - volume_id=data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e66e40d6-65e6-4e75-bdc7-636792fa152d') - def test_update_volume_with_invalid_volume_id(self): - self.assertRaises(lib_exc.NotFound, self.volumes_client.update_volume, - volume_id=data_utils.rand_name('invalid')) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('72aeca85-57a5-4c1f-9057-f320f9ea575b') - def test_update_volume_with_empty_volume_id(self): - self.assertRaises(lib_exc.NotFound, self.volumes_client.update_volume, - volume_id='') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('30799cfd-7ee4-446c-b66c-45b383ed211b') - def test_get_invalid_volume_id(self): - # Should not be able to get volume with invalid id - self.assertRaises(lib_exc.NotFound, self.volumes_client.show_volume, - data_utils.rand_name('invalid')) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('c6c3db06-29ad-4e91-beb0-2ab195fe49e3') - def test_get_volume_without_passing_volume_id(self): - # Should not be able to get volume when empty ID is passed - self.assertRaises(lib_exc.NotFound, - self.volumes_client.show_volume, '') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('1f035827-7c32-4019-9240-b4ec2dbd9dfd') - def test_delete_invalid_volume_id(self): - # Should not be able to delete volume when invalid ID is passed - self.assertRaises(lib_exc.NotFound, self.volumes_client.delete_volume, - data_utils.rand_name('invalid')) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('441a1550-5d44-4b30-af0f-a6d402f52026') - def test_delete_volume_without_passing_volume_id(self): - # Should not be able to delete volume when empty ID is passed - self.assertRaises(lib_exc.NotFound, - self.volumes_client.delete_volume, '') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('f5e56b0a-5d02-43c1-a2a7-c9b792c2e3f6') - @test.services('compute') - def test_attach_volumes_with_nonexistent_volume_id(self): - server = self.create_server() - - self.assertRaises(lib_exc.NotFound, - self.volumes_client.attach_volume, - data_utils.rand_uuid(), - instance_uuid=server['id'], - mountpoint=self.mountpoint) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9f9c24e4-011d-46b5-b992-952140ce237a') - def test_detach_volumes_with_invalid_volume_id(self): - self.assertRaises(lib_exc.NotFound, - self.volumes_client.detach_volume, - 'xxx') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e0c75c74-ee34-41a9-9288-2a2051452854') - def test_volume_extend_with_size_smaller_than_original_size(self): - # Extend volume with smaller size than original size. - extend_size = 0 - self.assertRaises(lib_exc.BadRequest, - self.volumes_client.extend_volume, - self.volume['id'], new_size=extend_size) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5d0b480d-e833-439f-8a5a-96ad2ed6f22f') - def test_volume_extend_with_non_number_size(self): - # Extend volume when size is non number. - extend_size = 'abc' - self.assertRaises(lib_exc.BadRequest, - self.volumes_client.extend_volume, - self.volume['id'], new_size=extend_size) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('355218f1-8991-400a-a6bb-971239287d92') - def test_volume_extend_with_None_size(self): - # Extend volume with None size. - extend_size = None - self.assertRaises(lib_exc.BadRequest, - self.volumes_client.extend_volume, - self.volume['id'], new_size=extend_size) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('8f05a943-013c-4063-ac71-7baf561e82eb') - def test_volume_extend_with_nonexistent_volume_id(self): - # Extend volume size when volume is nonexistent. - extend_size = self.volume['size'] + 1 - self.assertRaises(lib_exc.NotFound, self.volumes_client.extend_volume, - data_utils.rand_uuid(), new_size=extend_size) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('aff8ba64-6d6f-4f2e-bc33-41a08ee9f115') - def test_volume_extend_without_passing_volume_id(self): - # Extend volume size when passing volume id is None. - extend_size = self.volume['size'] + 1 - self.assertRaises(lib_exc.NotFound, self.volumes_client.extend_volume, - None, new_size=extend_size) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ac6084c0-0546-45f9-b284-38a367e0e0e2') - def test_reserve_volume_with_nonexistent_volume_id(self): - self.assertRaises(lib_exc.NotFound, - self.volumes_client.reserve_volume, - data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('eb467654-3dc1-4a72-9b46-47c29d22654c') - def test_unreserve_volume_with_nonexistent_volume_id(self): - self.assertRaises(lib_exc.NotFound, - self.volumes_client.unreserve_volume, - data_utils.rand_uuid()) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('449c4ed2-ecdd-47bb-98dc-072aeccf158c') - def test_reserve_volume_with_negative_volume_status(self): - # Mark volume as reserved. - self.volumes_client.reserve_volume(self.volume['id']) - # Mark volume which is marked as reserved before - self.assertRaises(lib_exc.BadRequest, - self.volumes_client.reserve_volume, - self.volume['id']) - # Unmark volume as reserved. - self.volumes_client.unreserve_volume(self.volume['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('0f4aa809-8c7b-418f-8fb3-84c7a5dfc52f') - def test_list_volumes_with_nonexistent_name(self): - v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume') - params = {'name': v_name} - fetched_volume = self.volumes_client.list_volumes( - params=params)['volumes'] - self.assertEmpty(fetched_volume) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('9ca17820-a0e7-4cbd-a7fa-f4468735e359') - def test_list_volumes_detail_with_nonexistent_name(self): - v_name = data_utils.rand_name(self.__class__.__name__ + '-Volume') - params = {'name': v_name} - fetched_volume = \ - self.volumes_client.list_volumes( - detail=True, params=params)['volumes'] - self.assertEmpty(fetched_volume) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('143b279b-7522-466b-81be-34a87d564a7c') - def test_list_volumes_with_invalid_status(self): - params = {'status': 'null'} - fetched_volume = self.volumes_client.list_volumes( - params=params)['volumes'] - self.assertEmpty(fetched_volume) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('ba94b27b-be3f-496c-a00e-0283b373fa75') - def test_list_volumes_detail_with_invalid_status(self): - params = {'status': 'null'} - fetched_volume = \ - self.volumes_client.list_volumes(detail=True, - params=params)['volumes'] - self.assertEmpty(fetched_volume) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('5b810c91-0ad1-47ce-aee8-615f789be78f') - @test.services('image') - def test_create_volume_from_image_with_decreasing_size(self): - # Create image - image = self.create_image() - - # Note(jeremyZ): To shorten the test time (uploading a big size image - # is time-consuming), here just consider the scenario that volume size - # is smaller than the min_disk of image. - self.assertRaises(lib_exc.BadRequest, - self.volumes_client.create_volume, - size=CONF.volume.volume_size, - imageRef=image['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('d15e7f35-2cfc-48c8-9418-c8223a89bcbb') - @test.services('image') - def test_create_volume_from_deactivated_image(self): - # Create image - image = self.create_image() - - # Deactivate the image - self.images_client.deactivate_image(image['id']) - body = self.images_client.show_image(image['id']) - self.assertEqual("deactivated", body['status']) - # Try creating a volume from deactivated image - self.assertRaises(lib_exc.BadRequest, - self.create_volume, - imageRef=image['id']) diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py deleted file mode 100644 index e68ab7e2a..000000000 --- a/tempest/api/volume/test_volumes_snapshots.py +++ /dev/null @@ -1,165 +0,0 @@ -# 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 testtools -from testtools import matchers - -from tempest.api.volume import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest import test - -CONF = config.CONF - - -class VolumesSnapshotTestJSON(base.BaseVolumeTest): - - @classmethod - def skip_checks(cls): - super(VolumesSnapshotTestJSON, cls).skip_checks() - if not CONF.volume_feature_enabled.snapshot: - raise cls.skipException("Cinder volume snapshots are disabled") - - @classmethod - def resource_setup(cls): - super(VolumesSnapshotTestJSON, cls).resource_setup() - cls.volume_origin = cls.create_volume() - - @decorators.idempotent_id('8567b54c-4455-446d-a1cf-651ddeaa3ff2') - @test.services('compute') - def test_snapshot_create_delete_with_volume_in_use(self): - # Create a test instance - server = self.create_server() - self.attach_volume(server['id'], self.volume_origin['id']) - - # Snapshot a volume which attached to an instance with force=False - self.assertRaises(lib_exc.BadRequest, self.create_snapshot, - self.volume_origin['id'], force=False) - - # Snapshot a volume attached to an instance - snapshot1 = self.create_snapshot(self.volume_origin['id'], force=True) - snapshot2 = self.create_snapshot(self.volume_origin['id'], force=True) - snapshot3 = self.create_snapshot(self.volume_origin['id'], force=True) - - # Delete the snapshots. Some snapshot implementations can take - # different paths according to order they are deleted. - self.delete_snapshot(snapshot1['id']) - self.delete_snapshot(snapshot3['id']) - self.delete_snapshot(snapshot2['id']) - - @decorators.idempotent_id('5210a1de-85a0-11e6-bb21-641c676a5d61') - @test.services('compute') - def test_snapshot_create_offline_delete_online(self): - - # Create a snapshot while it is not attached - snapshot1 = self.create_snapshot(self.volume_origin['id']) - - # Create a server and attach it - server = self.create_server() - self.attach_volume(server['id'], self.volume_origin['id']) - - # Now that the volume is attached, create another snapshots - snapshot2 = self.create_snapshot(self.volume_origin['id'], force=True) - snapshot3 = self.create_snapshot(self.volume_origin['id'], force=True) - - # Delete the snapshots. Some snapshot implementations can take - # different paths according to order they are deleted. - self.delete_snapshot(snapshot3['id']) - self.delete_snapshot(snapshot1['id']) - self.delete_snapshot(snapshot2['id']) - - @decorators.idempotent_id('2a8abbe4-d871-46db-b049-c41f5af8216e') - def test_snapshot_create_get_list_update_delete(self): - # Create a snapshot with metadata - metadata = {"snap-meta1": "value1", - "snap-meta2": "value2", - "snap-meta3": "value3"} - snapshot = self.create_snapshot(self.volume_origin['id'], - metadata=metadata) - - # Get the snap and check for some of its details - snap_get = self.snapshots_client.show_snapshot( - snapshot['id'])['snapshot'] - self.assertEqual(self.volume_origin['id'], - snap_get['volume_id'], - "Referred volume origin mismatch") - self.assertEqual(self.volume_origin['size'], snap_get['size']) - - # Verify snapshot metadata - self.assertThat(snap_get['metadata'].items(), - matchers.ContainsAll(metadata.items())) - - # Compare also with the output from the list action - tracking_data = (snapshot['id'], snapshot['name']) - snaps_list = self.snapshots_client.list_snapshots()['snapshots'] - snaps_data = [(f['id'], f['name']) for f in snaps_list] - self.assertIn(tracking_data, snaps_data) - - # Updates snapshot with new values - new_s_name = data_utils.rand_name( - self.__class__.__name__ + '-new-snap') - new_desc = 'This is the new description of snapshot.' - params = {'name': new_s_name, - 'description': new_desc} - update_snapshot = self.snapshots_client.update_snapshot( - snapshot['id'], **params)['snapshot'] - # Assert response body for update_snapshot method - self.assertEqual(new_s_name, update_snapshot['name']) - self.assertEqual(new_desc, update_snapshot['description']) - # Assert response body for show_snapshot method - updated_snapshot = self.snapshots_client.show_snapshot( - snapshot['id'])['snapshot'] - self.assertEqual(new_s_name, updated_snapshot['name']) - self.assertEqual(new_desc, updated_snapshot['description']) - - # Delete the snapshot - self.delete_snapshot(snapshot['id']) - - @decorators.idempotent_id('677863d1-3142-456d-b6ac-9924f667a7f4') - def test_volume_from_snapshot(self): - # Creates a volume from a snapshot passing a size - # different from the source - src_size = CONF.volume.volume_size - - src_vol = self.create_volume(size=src_size) - src_snap = self.create_snapshot(src_vol['id']) - # Destination volume bigger than source snapshot - dst_vol = self.create_volume(snapshot_id=src_snap['id'], - size=src_size + 1) - # NOTE(zhufl): dst_vol is created based on snapshot, so dst_vol - # should be deleted before deleting snapshot, otherwise deleting - # snapshot will end with status 'error-deleting'. This depends on - # the implementation mechanism of vendors, generally speaking, - # some verdors will use "virtual disk clone" which will promote - # disk clone speed, and in this situation the "disk clone" - # is just a relationship between volume and snapshot. - self.addCleanup(self.delete_volume, self.volumes_client, dst_vol['id']) - - volume = self.volumes_client.show_volume(dst_vol['id'])['volume'] - # Should allow - self.assertEqual(volume['snapshot_id'], src_snap['id']) - self.assertEqual(volume['size'], src_size + 1) - - @decorators.idempotent_id('bbcfa285-af7f-479e-8c1a-8c34fc16543c') - @testtools.skipUnless(CONF.volume_feature_enabled.backup, - "Cinder backup is disabled") - def test_snapshot_backup(self): - # Create a snapshot - snapshot = self.create_snapshot(volume_id=self.volume_origin['id']) - - backup = self.create_backup(volume_id=self.volume_origin['id'], - snapshot_id=snapshot['id']) - backup_info = self.backups_client.show_backup(backup['id'])['backup'] - self.assertEqual(self.volume_origin['id'], backup_info['volume_id']) - self.assertEqual(snapshot['id'], backup_info['snapshot_id']) diff --git a/tempest/api/volume/test_volumes_snapshots_list.py b/tempest/api/volume/test_volumes_snapshots_list.py deleted file mode 100644 index 507df1faa..000000000 --- a/tempest/api/volume/test_volumes_snapshots_list.py +++ /dev/null @@ -1,160 +0,0 @@ -# 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 tempest.api.volume import base -from tempest import config -from tempest.lib import decorators - -CONF = config.CONF - - -class VolumesSnapshotListTestJSON(base.BaseVolumeTest): - - @classmethod - def skip_checks(cls): - super(VolumesSnapshotListTestJSON, cls).skip_checks() - if not CONF.volume_feature_enabled.snapshot: - raise cls.skipException("Cinder volume snapshots are disabled") - - @classmethod - def resource_setup(cls): - super(VolumesSnapshotListTestJSON, cls).resource_setup() - cls.snapshot_id_list = [] - volume_origin = cls.create_volume() - - # Create snapshots with params - for _ in range(3): - snapshot = cls.create_snapshot(volume_origin['id']) - cls.snapshot_id_list.append(snapshot['id']) - cls.snapshot = snapshot - - def _list_by_param_values_and_assert(self, with_detail=False, **params): - """list or list_details with given params and validates result.""" - - fetched_snap_list = self.snapshots_client.list_snapshots( - detail=with_detail, **params)['snapshots'] - - # Validating params of fetched snapshots - for snap in fetched_snap_list: - for key in params: - msg = "Failed to list snapshots %s by %s" % \ - ('details' if with_detail else '', key) - self.assertEqual(params[key], snap[key], msg) - - def _list_snapshots_by_param_limit(self, limit, expected_elements): - """list snapshots by limit param""" - # Get snapshots list using limit parameter - fetched_snap_list = self.snapshots_client.list_snapshots( - limit=limit)['snapshots'] - # Validating filtered snapshots length equals to expected_elements - self.assertEqual(expected_elements, len(fetched_snap_list)) - - @decorators.idempotent_id('59f41f43-aebf-48a9-ab5d-d76340fab32b') - def test_snapshots_list_with_params(self): - """list snapshots with params.""" - # Verify list snapshots by display_name filter - params = {'name': self.snapshot['name']} - self._list_by_param_values_and_assert(**params) - - # Verify list snapshots by status filter - params = {'status': 'available'} - self._list_by_param_values_and_assert(**params) - - # Verify list snapshots by status and display name filter - params = {'status': 'available', - 'name': self.snapshot['name']} - self._list_by_param_values_and_assert(**params) - - @decorators.idempotent_id('220a1022-1fcd-4a74-a7bd-6b859156cda2') - def test_snapshots_list_details_with_params(self): - """list snapshot details with params.""" - # Verify list snapshot details by display_name filter - params = {'name': self.snapshot['name']} - self._list_by_param_values_and_assert(with_detail=True, **params) - # Verify list snapshot details by status filter - params = {'status': 'available'} - self._list_by_param_values_and_assert(with_detail=True, **params) - # Verify list snapshot details by status and display name filter - params = {'status': 'available', - 'name': self.snapshot['name']} - self._list_by_param_values_and_assert(with_detail=True, **params) - - @decorators.idempotent_id('db4d8e0a-7a2e-41cc-a712-961f6844e896') - def test_snapshot_list_param_limit(self): - # List returns limited elements - self._list_snapshots_by_param_limit(limit=1, expected_elements=1) - - @decorators.idempotent_id('a1427f61-420e-48a5-b6e3-0b394fa95400') - def test_snapshot_list_param_limit_equals_infinite(self): - # List returns all elements when request limit exceeded - # snapshots number - snap_list = self.snapshots_client.list_snapshots()['snapshots'] - self._list_snapshots_by_param_limit(limit=100000, - expected_elements=len(snap_list)) - - @decorators.idempotent_id('e3b44b7f-ae87-45b5-8a8c-66110eb24d0a') - def test_snapshot_list_param_limit_equals_zero(self): - # List returns zero elements - self._list_snapshots_by_param_limit(limit=0, expected_elements=0) - - def _list_snapshots_param_sort(self, sort_key, sort_dir): - """list snapshots by sort param""" - snap_list = self.snapshots_client.list_snapshots( - sort_key=sort_key, sort_dir=sort_dir)['snapshots'] - self.assertNotEmpty(snap_list) - if sort_key is 'display_name': - sort_key = 'name' - # Note: On Cinder API, 'display_name' works as a sort key - # on a request, a volume name appears as 'name' on the response. - # So Tempest needs to change the key name here for this inconsistent - # API behavior. - sorted_list = [snapshot[sort_key] for snapshot in snap_list] - msg = 'The list of snapshots was not sorted correctly.' - self.assertEqual(sorted(sorted_list, reverse=(sort_dir == 'desc')), - sorted_list, msg) - - @decorators.idempotent_id('c5513ada-64c1-4d28-83b9-af3307ec1388') - def test_snapshot_list_param_sort_id_asc(self): - self._list_snapshots_param_sort(sort_key='id', sort_dir='asc') - - @decorators.idempotent_id('8a7fe058-0b41-402a-8afd-2dbc5a4a718b') - def test_snapshot_list_param_sort_id_desc(self): - self._list_snapshots_param_sort(sort_key='id', sort_dir='desc') - - @decorators.idempotent_id('4052c3a0-2415-440a-a8cc-305a875331b0') - def test_snapshot_list_param_sort_created_at_asc(self): - self._list_snapshots_param_sort(sort_key='created_at', sort_dir='asc') - - @decorators.idempotent_id('dcbbe24a-f3c0-4ec8-9274-55d48db8d1cf') - def test_snapshot_list_param_sort_created_at_desc(self): - self._list_snapshots_param_sort(sort_key='created_at', sort_dir='desc') - - @decorators.idempotent_id('d58b5fed-0c37-42d3-8c5d-39014ac13c00') - def test_snapshot_list_param_sort_name_asc(self): - self._list_snapshots_param_sort(sort_key='display_name', - sort_dir='asc') - - @decorators.idempotent_id('96ba6f4d-1f18-47e1-b4bc-76edc6c21250') - def test_snapshot_list_param_sort_name_desc(self): - self._list_snapshots_param_sort(sort_key='display_name', - sort_dir='desc') - - @decorators.idempotent_id('05489dde-44bc-4961-a1f5-3ce7ee7824f7') - def test_snapshot_list_param_marker(self): - # The list of snapshots should end before the provided marker - params = {'marker': self.snapshot_id_list[1]} - snap_list = self.snapshots_client.list_snapshots(**params)['snapshots'] - fetched_list_id = [snap['id'] for snap in snap_list] - # Verify the list of snapshots ends before the provided - # marker(second snapshot), therefore only the first snapshot - # should displayed. - self.assertEqual(self.snapshot_id_list[:1], fetched_list_id) diff --git a/tempest/api/volume/test_volumes_snapshots_negative.py b/tempest/api/volume/test_volumes_snapshots_negative.py deleted file mode 100644 index ea5f03685..000000000 --- a/tempest/api/volume/test_volumes_snapshots_negative.py +++ /dev/null @@ -1,83 +0,0 @@ -# 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 tempest.api.volume import base -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF - - -class VolumesSnapshotNegativeTestJSON(base.BaseVolumeTest): - - @classmethod - def skip_checks(cls): - super(VolumesSnapshotNegativeTestJSON, cls).skip_checks() - if not CONF.volume_feature_enabled.snapshot: - raise cls.skipException("Cinder volume snapshots are disabled") - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('e3e466af-70ab-4f4b-a967-ab04e3532ea7') - def test_create_snapshot_with_nonexistent_volume_id(self): - # Create a snapshot with nonexistent volume id - s_name = data_utils.rand_name(self.__class__.__name__ + '-snap') - self.assertRaises(lib_exc.NotFound, - self.snapshots_client.create_snapshot, - volume_id=data_utils.rand_uuid(), - display_name=s_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('bb9da53e-d335-4309-9c15-7e76fd5e4d6d') - def test_create_snapshot_without_passing_volume_id(self): - # Create a snapshot without passing volume id - s_name = data_utils.rand_name(self.__class__.__name__ + '-snap') - self.assertRaises(lib_exc.NotFound, - self.snapshots_client.create_snapshot, - volume_id=None, display_name=s_name) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('677863d1-34f9-456d-b6ac-9924f667a7f4') - def test_volume_from_snapshot_decreasing_size(self): - # Creates a volume a snapshot passing a size different from the source - src_size = CONF.volume.volume_size + 1 - - src_vol = self.create_volume(size=src_size) - src_snap = self.create_snapshot(src_vol['id']) - - # Destination volume smaller than source - self.assertRaises(lib_exc.BadRequest, - self.volumes_client.create_volume, - size=src_size - 1, - snapshot_id=src_snap['id']) - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('8fd92339-e22f-4591-86b4-1e2215372a40') - def test_list_snapshot_invalid_param_limit(self): - self.assertRaises(lib_exc.BadRequest, - self.snapshots_client.list_snapshots, - limit='invalid') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('27b5f37f-bf69-4e8c-986e-c44f3d6819b8') - def test_list_snapshots_invalid_param_sort(self): - self.assertRaises(lib_exc.BadRequest, - self.snapshots_client.list_snapshots, - sort_key='invalid') - - @decorators.attr(type=['negative']) - @decorators.idempotent_id('b68deeda-ca79-4a32-81af-5c51179e553a') - def test_list_snapshots_invalid_param_marker(self): - self.assertRaises(lib_exc.NotFound, - self.snapshots_client.list_snapshots, - marker=data_utils.rand_uuid()) diff --git a/tempest/clients.py b/tempest/clients.py deleted file mode 100644 index 85c2242fc..000000000 --- a/tempest/clients.py +++ /dev/null @@ -1,316 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest import config -from tempest.lib import auth -from tempest.lib import exceptions as lib_exc -from tempest.lib.services import clients -from tempest.services import object_storage - -CONF = config.CONF - - -class Manager(clients.ServiceClients): - """Top level manager for OpenStack tempest clients""" - - default_params = config.service_client_config() - - def __init__(self, credentials, scope='project'): - """Initialization of Manager class. - - Setup all services clients and make them available for tests cases. - :param credentials: type Credentials or TestResources - :param scope: default scope for tokens produced by the auth provider - """ - _, identity_uri = get_auth_provider_class(credentials) - super(Manager, self).__init__( - credentials=credentials, identity_uri=identity_uri, scope=scope, - region=CONF.identity.region) - # TODO(andreaf) When clients are initialised without the right - # parameters available, the calls below will trigger a KeyError. - # We should catch that and raise a better error. - self._set_compute_clients() - self._set_identity_clients() - self._set_volume_clients() - self._set_object_storage_clients() - self._set_image_clients() - self._set_network_clients() - - def _set_network_clients(self): - self.network_agents_client = self.network.AgentsClient() - self.network_extensions_client = self.network.ExtensionsClient() - self.networks_client = self.network.NetworksClient() - self.subnetpools_client = self.network.SubnetpoolsClient() - self.subnets_client = self.network.SubnetsClient() - self.ports_client = self.network.PortsClient() - self.network_quotas_client = self.network.QuotasClient() - self.floating_ips_client = self.network.FloatingIPsClient() - self.metering_labels_client = self.network.MeteringLabelsClient() - self.metering_label_rules_client = ( - self.network.MeteringLabelRulesClient()) - self.routers_client = self.network.RoutersClient() - self.security_group_rules_client = ( - self.network.SecurityGroupRulesClient()) - self.security_groups_client = self.network.SecurityGroupsClient() - self.network_versions_client = self.network.NetworkVersionsClient() - self.service_providers_client = self.network.ServiceProvidersClient() - self.tags_client = self.network.TagsClient() - - def _set_image_clients(self): - if CONF.service_available.glance: - self.image_client = self.image_v1.ImagesClient() - self.image_member_client = self.image_v1.ImageMembersClient() - self.image_client_v2 = self.image_v2.ImagesClient() - self.image_member_client_v2 = self.image_v2.ImageMembersClient() - self.namespaces_client = self.image_v2.NamespacesClient() - self.resource_types_client = self.image_v2.ResourceTypesClient() - self.namespace_objects_client = \ - self.image_v2.NamespaceObjectsClient() - self.schemas_client = self.image_v2.SchemasClient() - self.namespace_properties_client = \ - self.image_v2.NamespacePropertiesClient() - self.namespace_tags_client = \ - self.image_v2.NamespaceTagsClient() - self.image_versions_client = \ - self.image_v2.VersionsClient() - - def _set_compute_clients(self): - self.agents_client = self.compute.AgentsClient() - self.compute_networks_client = self.compute.NetworksClient() - self.migrations_client = self.compute.MigrationsClient() - self.security_group_default_rules_client = ( - self.compute.SecurityGroupDefaultRulesClient()) - self.certificates_client = self.compute.CertificatesClient() - eip = CONF.compute_feature_enabled.enable_instance_password - self.servers_client = self.compute.ServersClient( - enable_instance_password=eip) - self.server_groups_client = self.compute.ServerGroupsClient() - self.limits_client = self.compute.LimitsClient() - self.compute_images_client = self.compute.ImagesClient() - self.keypairs_client = self.compute.KeyPairsClient() - self.quotas_client = self.compute.QuotasClient() - self.quota_classes_client = self.compute.QuotaClassesClient() - self.flavors_client = self.compute.FlavorsClient() - self.extensions_client = self.compute.ExtensionsClient() - self.floating_ip_pools_client = self.compute.FloatingIPPoolsClient() - self.floating_ips_bulk_client = self.compute.FloatingIPsBulkClient() - self.compute_floating_ips_client = self.compute.FloatingIPsClient() - self.compute_security_group_rules_client = ( - self.compute.SecurityGroupRulesClient()) - self.compute_security_groups_client = ( - self.compute.SecurityGroupsClient()) - self.interfaces_client = self.compute.InterfacesClient() - self.fixed_ips_client = self.compute.FixedIPsClient() - self.availability_zone_client = self.compute.AvailabilityZoneClient() - self.aggregates_client = self.compute.AggregatesClient() - self.services_client = self.compute.ServicesClient() - self.tenant_usages_client = self.compute.TenantUsagesClient() - self.hosts_client = self.compute.HostsClient() - self.hypervisor_client = self.compute.HypervisorClient() - self.instance_usages_audit_log_client = ( - self.compute.InstanceUsagesAuditLogClient()) - self.tenant_networks_client = self.compute.TenantNetworksClient() - - # NOTE: The following client needs special timeout values because - # the API is a proxy for the other component. - params_volume = { - 'build_interval': CONF.volume.build_interval, - 'build_timeout': CONF.volume.build_timeout - } - self.volumes_extensions_client = self.compute.VolumesClient( - **params_volume) - self.compute_versions_client = self.compute.VersionsClient( - **params_volume) - self.snapshots_extensions_client = self.compute.SnapshotsClient( - **params_volume) - - def _set_identity_clients(self): - # Clients below use the admin endpoint type of Keystone API v2 - params_v2_admin = { - 'endpoint_type': CONF.identity.v2_admin_endpoint_type} - self.endpoints_client = self.identity_v2.EndpointsClient( - **params_v2_admin) - self.identity_client = self.identity_v2.IdentityClient( - **params_v2_admin) - self.tenants_client = self.identity_v2.TenantsClient( - **params_v2_admin) - self.roles_client = self.identity_v2.RolesClient(**params_v2_admin) - self.users_client = self.identity_v2.UsersClient(**params_v2_admin) - self.identity_services_client = self.identity_v2.ServicesClient( - **params_v2_admin) - - # Clients below use the public endpoint type of Keystone API v2 - params_v2_public = { - 'endpoint_type': CONF.identity.v2_public_endpoint_type} - self.identity_public_client = self.identity_v2.IdentityClient( - **params_v2_public) - self.tenants_public_client = self.identity_v2.TenantsClient( - **params_v2_public) - self.users_public_client = self.identity_v2.UsersClient( - **params_v2_public) - - # Clients below use the endpoint type of Keystone API v3, which is set - # in endpoint_type - params_v3 = {'endpoint_type': CONF.identity.v3_endpoint_type} - self.domains_client = self.identity_v3.DomainsClient(**params_v3) - self.identity_v3_client = self.identity_v3.IdentityClient(**params_v3) - self.trusts_client = self.identity_v3.TrustsClient(**params_v3) - self.users_v3_client = self.identity_v3.UsersClient(**params_v3) - self.endpoints_v3_client = self.identity_v3.EndPointsClient( - **params_v3) - self.roles_v3_client = self.identity_v3.RolesClient(**params_v3) - self.inherited_roles_client = self.identity_v3.InheritedRolesClient( - **params_v3) - self.role_assignments_client = self.identity_v3.RoleAssignmentsClient( - **params_v3) - self.identity_services_v3_client = self.identity_v3.ServicesClient( - **params_v3) - self.policies_client = self.identity_v3.PoliciesClient(**params_v3) - self.projects_client = self.identity_v3.ProjectsClient(**params_v3) - self.regions_client = self.identity_v3.RegionsClient(**params_v3) - self.credentials_client = self.identity_v3.CredentialsClient( - **params_v3) - self.groups_client = self.identity_v3.GroupsClient(**params_v3) - self.identity_versions_v3_client = self.identity_v3.VersionsClient( - **params_v3) - self.oauth_consumers_client = self.identity_v3.OAUTHConsumerClient( - **params_v3) - self.oauth_token_client = self.identity_v3.OAUTHTokenClient( - **params_v3) - self.domain_config_client = self.identity_v3.DomainConfigurationClient( - **params_v3) - self.endpoint_filter_client = \ - self.identity_v3.EndPointsFilterClient(**params_v3) - self.endpoint_groups_client = self.identity_v3.EndPointGroupsClient( - **params_v3) - self.catalog_client = self.identity_v3.CatalogClient(**params_v3) - - # Token clients do not use the catalog. They only need default_params. - # They read auth_url, so they should only be set if the corresponding - # API version is marked as enabled - if CONF.identity_feature_enabled.api_v2: - if CONF.identity.uri: - self.token_client = self.identity_v2.TokenClient( - auth_url=CONF.identity.uri) - else: - msg = 'Identity v2 API enabled, but no identity.uri set' - raise lib_exc.InvalidConfiguration(msg) - if CONF.identity_feature_enabled.api_v3: - if CONF.identity.uri_v3: - self.token_v3_client = self.identity_v3.V3TokenClient( - auth_url=CONF.identity.uri_v3) - else: - msg = 'Identity v3 API enabled, but no identity.uri_v3 set' - raise lib_exc.InvalidConfiguration(msg) - - def _set_volume_clients(self): - - if CONF.volume_feature_enabled.api_v1: - self.backups_client = self.volume_v1.BackupsClient() - self.encryption_types_client = \ - self.volume_v1.EncryptionTypesClient() - self.snapshots_client = self.volume_v1.SnapshotsClient() - self.volume_availability_zone_client = \ - self.volume_v1.AvailabilityZoneClient() - self.volume_hosts_client = self.volume_v1.HostsClient() - self.volume_limits_client = self.volume_v1.LimitsClient() - self.volume_qos_client = self.volume_v1.QosSpecsClient() - self.volume_quotas_client = self.volume_v1.QuotasClient() - self.volume_services_client = self.volume_v1.ServicesClient() - self.volume_types_client = self.volume_v1.TypesClient() - self.volumes_client = self.volume_v1.VolumesClient() - self.volumes_extension_client = self.volume_v1.ExtensionsClient() - - if CONF.volume_feature_enabled.api_v2: - self.backups_v2_client = self.volume_v2.BackupsClient() - self.encryption_types_v2_client = \ - self.volume_v2.EncryptionTypesClient() - self.snapshot_manage_v2_client = \ - self.volume_v2.SnapshotManageClient() - self.snapshots_v2_client = self.volume_v2.SnapshotsClient() - self.volume_capabilities_v2_client = \ - self.volume_v2.CapabilitiesClient() - self.volume_manage_v2_client = self.volume_v2.VolumeManageClient() - self.volume_qos_v2_client = self.volume_v2.QosSpecsClient() - self.volume_services_v2_client = self.volume_v2.ServicesClient() - self.volume_types_v2_client = self.volume_v2.TypesClient() - self.volume_hosts_v2_client = self.volume_v2.HostsClient() - self.volume_quotas_v2_client = self.volume_v2.QuotasClient() - self.volume_quota_classes_v2_client = \ - self.volume_v2.QuotaClassesClient() - self.volume_scheduler_stats_v2_client = \ - self.volume_v2.SchedulerStatsClient() - self.volume_transfers_v2_client = \ - self.volume_v2.TransfersClient() - self.volume_v2_availability_zone_client = \ - self.volume_v2.AvailabilityZoneClient() - self.volume_v2_limits_client = self.volume_v2.LimitsClient() - self.volumes_v2_client = self.volume_v2.VolumesClient() - self.volumes_v2_extension_client = \ - self.volume_v2.ExtensionsClient() - - # Set default client for users that don't need explicit version - self.volumes_client_latest = self.volumes_v2_client - - if CONF.volume_feature_enabled.api_v3: - self.backups_v3_client = self.volume_v3.BackupsClient() - self.group_types_v3_client = self.volume_v3.GroupTypesClient() - self.groups_v3_client = self.volume_v3.GroupsClient() - self.volume_v3_messages_client = self.volume_v3.MessagesClient() - self.volume_v3_versions_client = self.volume_v3.VersionsClient() - self.volumes_v3_client = self.volume_v3.VolumesClient() - - # Set default client for users that don't need explicit version - self.volumes_client_latest = self.volumes_v3_client - - def _set_object_storage_clients(self): - # NOTE(andreaf) Load configuration from config. Once object storage - # is in lib, configuration will be pulled directly from the registry - # and this will not be required anymore. - params = config.service_client_config('object-storage') - - self.account_client = object_storage.AccountClient(self.auth_provider, - **params) - self.bulk_client = object_storage.BulkMiddlewareClient( - self.auth_provider, **params) - self.capabilities_client = object_storage.CapabilitiesClient( - self.auth_provider, **params) - self.container_client = object_storage.ContainerClient( - self.auth_provider, **params) - self.object_client = object_storage.ObjectClient(self.auth_provider, - **params) - - -def get_auth_provider_class(credentials): - if isinstance(credentials, auth.KeystoneV3Credentials): - return auth.KeystoneV3AuthProvider, CONF.identity.uri_v3 - else: - return auth.KeystoneV2AuthProvider, CONF.identity.uri - - -def get_auth_provider(credentials, pre_auth=False, scope='project'): - # kwargs for auth provider match the common ones used by service clients - default_params = config.service_client_config() - if credentials is None: - raise lib_exc.InvalidCredentials( - 'Credentials must be specified') - auth_provider_class, auth_url = get_auth_provider_class( - credentials) - _auth_provider = auth_provider_class(credentials, auth_url, - scope=scope, - **default_params) - if pre_auth: - _auth_provider.set_auth() - return _auth_provider diff --git a/tempest/cmd/__init__.py b/tempest/cmd/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/cmd/account_generator.py b/tempest/cmd/account_generator.py deleted file mode 100755 index 8636405b4..000000000 --- a/tempest/cmd/account_generator.py +++ /dev/null @@ -1,310 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2015 Mirantis, Inc. -# -# 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. - -""" -Utility for creating **accounts.yaml** file for concurrent test runs. -Creates one primary user, one alt user, one swift admin, one stack owner -and one admin (optionally) for each concurrent thread. The utility creates -user for each tenant. The **accounts.yaml** file will be valid and contain -credentials for created users, so each user will be in separate tenant and -have the username, tenant_name, password and roles. - -**Usage:** ``tempest account-generator [-h] [OPTIONS] accounts_file.yaml``. - -Positional Arguments --------------------- -**accounts_file.yaml** (Required) Provide an output accounts yaml file. Utility -creates a .yaml file in the directory where the command is ran. The appropriate -name for the file is *accounts.yaml* and it should be placed in *tempest/etc* -directory. - -Authentication --------------- - -Account generator creates users and tenants so it needs the admin credentials -of your cloud to operate properly. The corresponding info can be given either -through CLI options or environment variables. - -You're probably familiar with these, but just to remind: - -======== ======================== ==================== -Param CLI Environment Variable -======== ======================== ==================== -Username --os-username OS_USERNAME -Password --os-password OS_PASSWORD -Project --os-project-name OS_PROJECT_NAME -Tenant --os-tenant-name (depr.) OS_TENANT_NAME -Domain --os-domain-name OS_DOMAIN_NAME -======== ======================== ==================== - -Optional Arguments ------------------- -**-h**, **--help** (Optional) Shows help message with the description of -utility and its arguments, and exits. - -**c /etc/tempest.conf**, **--config-file /etc/tempest.conf** (Optional) Path to -tempest config file. - -**--os-username ** (Optional) Name used for authentication with -the OpenStack Identity service. Defaults to env[OS_USERNAME]. Note: User should -have permissions to create new user accounts and tenants. - -**--os-password ** (Optional) Password used for authentication -with the OpenStack Identity service. Defaults to env[OS_PASSWORD]. - -**--os-project-name ** (Optional) Project to request -authorization on. Defaults to env[OS_PROJECT_NAME]. - -**--os-tenant-name ** (Optional, deprecated) Tenant to -request authorization on. Defaults to env[OS_TENANT_NAME]. - -**--os-domain-name ** (Optional) Domain the user and project -belong to. Defaults to env[OS_DOMAIN_NAME]. - -**--tag TAG** (Optional) Resources tag. Each created resource (user, project) -will have the prefix with the given TAG in its name. Using tag is recommended -for the further using, cleaning resources. - -**-r CONCURRENCY**, **--concurrency CONCURRENCY** (Required) Concurrency count -(default: 1). The number of accounts required can be estimated as -CONCURRENCY x 2. Each user provided in *accounts.yaml* file will be in -a different tenant. This is required to provide isolation between test for -running in parallel. - -**--with-admin** (Optional) Creates admin for each concurrent group -(default: False). - -**-i VERSION**, **--identity-version VERSION** (Optional) Provisions accounts -using the specified version of the identity API. (default: '3'). - -To see help on specific argument, please do: ``tempest account-generator -[OPTIONS] -h``. -""" -import argparse -import os -import traceback - -from cliff import command -from oslo_log import log as logging -import yaml - -from tempest.common import credentials_factory -from tempest import config -from tempest.lib.common import dynamic_creds - - -LOG = None -CONF = config.CONF -DESCRIPTION = ('Create accounts.yaml file for concurrent test runs.%s' - 'One primary user, one alt user, ' - 'one swift admin, one stack owner ' - 'and one admin (optionally) will be created ' - 'for each concurrent thread.' % os.linesep) - - -def setup_logging(): - global LOG - logging.setup(CONF, __name__) - LOG = logging.getLogger(__name__) - - -def get_credential_provider(opts): - identity_version = "".join(['v', str(opts.identity_version)]) - # NOTE(andreaf) For now tempest.conf controls whether resources will - # actually be created. Once we remove the dependency from tempest.conf - # we will need extra CLI option(s) to control this. - network_resources = {'router': True, - 'network': True, - 'subnet': True, - 'dhcp': True} - admin_creds_dict = {'username': opts.os_username, - 'password': opts.os_password} - _project_name = opts.os_project_name or opts.os_tenant_name - if opts.identity_version == 3: - admin_creds_dict['project_name'] = _project_name - admin_creds_dict['domain_name'] = opts.os_domain_name or 'Default' - elif opts.identity_version == 2: - admin_creds_dict['tenant_name'] = _project_name - admin_creds = credentials_factory.get_credentials( - fill_in=False, identity_version=identity_version, **admin_creds_dict) - return dynamic_creds.DynamicCredentialProvider( - name=opts.tag, - network_resources=network_resources, - **credentials_factory.get_dynamic_provider_params( - identity_version, admin_creds=admin_creds)) - - -def generate_resources(cred_provider, admin): - # Create the list of resources to be provisioned for each process - # NOTE(andreaf) get_credentials expects a string for types or a list for - # roles. Adding all required inputs to the spec list. - spec = ['primary', 'alt'] - if CONF.service_available.swift: - spec.append([CONF.object_storage.operator_role]) - spec.append([CONF.object_storage.reseller_admin_role]) - if CONF.service_available.heat: - spec.append([CONF.orchestration.stack_owner_role, - CONF.object_storage.operator_role]) - if admin: - spec.append('admin') - resources = [] - for cred_type in spec: - resources.append((cred_type, cred_provider.get_credentials( - credential_type=cred_type))) - return resources - - -def dump_accounts(resources, identity_version, account_file): - accounts = [] - for resource in resources: - cred_type, test_resource = resource - account = { - 'username': test_resource.username, - 'password': test_resource.password - } - if identity_version == 3: - account['project_name'] = test_resource.project_name - account['domain_name'] = test_resource.domain_name - else: - account['project_name'] = test_resource.tenant_name - - # If the spec includes 'admin' credentials are defined via type, - # else they are defined via list of roles. - if cred_type == 'admin': - account['types'] = [cred_type] - elif cred_type not in ['primary', 'alt']: - account['roles'] = cred_type - - if test_resource.network: - account['resources'] = {} - if test_resource.network: - account['resources']['network'] = test_resource.network['name'] - accounts.append(account) - if os.path.exists(account_file): - os.rename(account_file, '.'.join((account_file, 'bak'))) - with open(account_file, 'w') as f: - yaml.safe_dump(accounts, f, default_flow_style=False) - LOG.info('%s generated successfully!', account_file) - - -def _parser_add_args(parser): - parser.add_argument('-c', '--config-file', - metavar='/etc/tempest.conf', - help='path to tempest config file') - parser.add_argument('--os-username', - metavar='', - default=os.environ.get('OS_USERNAME'), - help='User should have permissions ' - 'to create new user accounts and ' - 'tenants. Defaults to env[OS_USERNAME].') - parser.add_argument('--os-password', - metavar='', - default=os.environ.get('OS_PASSWORD'), - help='Defaults to env[OS_PASSWORD].') - parser.add_argument('--os-project-name', - metavar='', - default=os.environ.get('OS_PROJECT_NAME'), - help='Defaults to env[OS_PROJECT_NAME].') - parser.add_argument('--os-tenant-name', - metavar='', - default=os.environ.get('OS_TENANT_NAME'), - help='Defaults to env[OS_TENANT_NAME].') - parser.add_argument('--os-domain-name', - metavar='', - default=os.environ.get('OS_DOMAIN_NAME'), - help='Defaults to env[OS_DOMAIN_NAME].') - parser.add_argument('--tag', - default='', - required=False, - dest='tag', - help='Resources tag') - parser.add_argument('-r', '--concurrency', - default=1, - type=int, - required=False, - dest='concurrency', - help='Concurrency count') - parser.add_argument('--with-admin', - action='store_true', - dest='admin', - help='Creates admin for each concurrent group') - parser.add_argument('-i', '--identity-version', - default=3, - choices=[2, 3], - type=int, - required=False, - dest='identity_version', - help='Version of the Identity API to use') - parser.add_argument('accounts', - metavar='accounts_file.yaml', - help='Output accounts yaml file') - - -def get_options(): - usage_string = ('tempest account-generator [-h] ...\n\n' - 'To see help on specific argument, do:\n' - 'tempest account-generator -h') - parser = argparse.ArgumentParser( - description=DESCRIPTION, - formatter_class=argparse.ArgumentDefaultsHelpFormatter, - usage=usage_string - ) - - _parser_add_args(parser) - opts = parser.parse_args() - return opts - - -class TempestAccountGenerator(command.Command): - - def get_parser(self, prog_name): - parser = super(TempestAccountGenerator, self).get_parser(prog_name) - _parser_add_args(parser) - return parser - - def take_action(self, parsed_args): - try: - main(parsed_args) - except Exception: - LOG.exception("Failure generating test accounts.") - traceback.print_exc() - raise - - def get_description(self): - return DESCRIPTION - - -def main(opts=None): - setup_logging() - if not opts: - LOG.warning("Use of: 'tempest-account-generator' is deprecated, " - "please use: 'tempest account-generator'") - opts = get_options() - if opts.config_file: - config.CONF.set_config_path(opts.config_file) - if opts.os_tenant_name: - LOG.warning("'os-tenant-name' and 'OS_TENANT_NAME' are both " - "deprecated, please use 'os-project-name' or " - "'OS_PROJECT_NAME' instead") - resources = [] - for count in range(opts.concurrency): - # Use N different cred_providers to obtain different sets of creds - cred_provider = get_credential_provider(opts) - resources.extend(generate_resources(cred_provider, opts.admin)) - dump_accounts(resources, opts.identity_version, opts.accounts) - -if __name__ == "__main__": - main() diff --git a/tempest/cmd/cleanup.py b/tempest/cmd/cleanup.py deleted file mode 100644 index ac73cbfa9..000000000 --- a/tempest/cmd/cleanup.py +++ /dev/null @@ -1,317 +0,0 @@ -#!/usr/bin/env python -# -# Copyright 2014 Dell Inc. -# 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. - -""" -Utility for cleaning up environment after Tempest test run - -**Usage:** ``tempest cleanup [--help] [OPTIONS]`` - -If run with no arguments, ``tempest cleanup`` will query your OpenStack -deployment and build a list of resources to delete and destroy them. This list -will exclude the resources from ``saved_state.json`` and will include the -configured admin account if the ``--delete-tempest-conf-objects`` flag is -specified. By default the admin project is not deleted and the admin user -specified in ``tempest.conf`` is never deleted. - -Example Run ------------ - -**WARNING: If step 1 is skipped in the example below, the cleanup procedure -may delete resources that existed in the cloud before the test run. This -may cause an unwanted destruction of cloud resources, so use caution with -this command.** - -``$ tempest cleanup --init-saved-state`` - -``$ # Actual running of Tempest tests`` - -``$ tempest cleanup`` - -Runtime Arguments ------------------ - -**--init-saved-state**: Initializes the saved state of the OpenStack deployment -and will output a ``saved_state.json`` file containing resources from your -deployment that will be preserved from the cleanup command. This should be -done prior to running Tempest tests. - -**--delete-tempest-conf-objects**: If option is present, then the command will -delete the admin project in addition to the resources associated with them on -clean up. If option is not present, the command will delete the resources -associated with the Tempest and alternate Tempest users and projects but will -not delete the projects themselves. - -**--dry-run**: Creates a report (``./dry_run.json``) of the projects that will -be cleaned up (in the ``_tenants_to_clean`` dictionary [1]_) and the global -objects that will be removed (domains, flavors, images, roles, projects, -and users). Once the cleanup command is executed (e.g. run without -parameters), running it again with **--dry-run** should yield an empty report. - -**--help**: Print the help text for the command and parameters. - -.. [1] The ``_tenants_to_clean`` dictionary in ``dry_run.json`` lists the - projects that ``tempest cleanup`` will loop through to delete child - objects, but the command will, by default, not delete the projects - themselves. This may differ from the ``tenants`` list as you can clean - the Tempest and alternate Tempest users and projects but they will not be - deleted unless the **--delete-tempest-conf-objects** flag is used to - force their deletion. - -""" -import sys -import traceback - -from cliff import command -from oslo_log import log as logging -from oslo_serialization import jsonutils as json - -from tempest import clients -from tempest.cmd import cleanup_service -from tempest.common import credentials_factory as credentials -from tempest.common import identity -from tempest import config - -SAVED_STATE_JSON = "saved_state.json" -DRY_RUN_JSON = "dry_run.json" -LOG = logging.getLogger(__name__) -CONF = config.CONF - - -class TempestCleanup(command.Command): - - def take_action(self, parsed_args): - try: - self.init(parsed_args) - if not parsed_args.init_saved_state: - self._cleanup() - except Exception: - LOG.exception("Failure during cleanup") - traceback.print_exc() - raise - - def init(self, parsed_args): - cleanup_service.init_conf() - self.options = parsed_args - self.admin_mgr = credentials.AdminManager() - self.dry_run_data = {} - self.json_data = {} - - self.admin_id = "" - self.admin_role_id = "" - self.admin_tenant_id = "" - self._init_admin_ids() - - self.admin_role_added = [] - - # available services - self.tenant_services = cleanup_service.get_tenant_cleanup_services() - self.global_services = cleanup_service.get_global_cleanup_services() - - if parsed_args.init_saved_state: - self._init_state() - return - - self._load_json() - - def _cleanup(self): - print("Begin cleanup") - is_dry_run = self.options.dry_run - is_preserve = not self.options.delete_tempest_conf_objects - is_save_state = False - - if is_dry_run: - self.dry_run_data["_tenants_to_clean"] = {} - - admin_mgr = self.admin_mgr - # Always cleanup tempest and alt tempest tenants unless - # they are in saved state json. Therefore is_preserve is False - kwargs = {'data': self.dry_run_data, - 'is_dry_run': is_dry_run, - 'saved_state_json': self.json_data, - 'is_preserve': False, - 'is_save_state': is_save_state} - tenant_service = cleanup_service.TenantService(admin_mgr, **kwargs) - tenants = tenant_service.list() - print("Process %s tenants" % len(tenants)) - - # Loop through list of tenants and clean them up. - for tenant in tenants: - self._add_admin(tenant['id']) - self._clean_tenant(tenant) - - kwargs = {'data': self.dry_run_data, - 'is_dry_run': is_dry_run, - 'saved_state_json': self.json_data, - 'is_preserve': is_preserve, - 'is_save_state': is_save_state} - for service in self.global_services: - svc = service(admin_mgr, **kwargs) - svc.run() - - if is_dry_run: - with open(DRY_RUN_JSON, 'w+') as f: - f.write(json.dumps(self.dry_run_data, sort_keys=True, - indent=2, separators=(',', ': '))) - - self._remove_admin_user_roles() - - def _remove_admin_user_roles(self): - tenant_ids = self.admin_role_added - LOG.debug("Removing admin user roles where needed for tenants: %s", - tenant_ids) - for tenant_id in tenant_ids: - self._remove_admin_role(tenant_id) - - def _clean_tenant(self, tenant): - print("Cleaning tenant: %s " % tenant['name']) - is_dry_run = self.options.dry_run - dry_run_data = self.dry_run_data - is_preserve = not self.options.delete_tempest_conf_objects - tenant_id = tenant['id'] - tenant_name = tenant['name'] - tenant_data = None - if is_dry_run: - tenant_data = dry_run_data["_tenants_to_clean"][tenant_id] = {} - tenant_data['name'] = tenant_name - - kwargs = {"username": CONF.auth.admin_username, - "password": CONF.auth.admin_password, - "tenant_name": tenant['name']} - mgr = clients.Manager(credentials=credentials.get_credentials( - **kwargs)) - kwargs = {'data': tenant_data, - 'is_dry_run': is_dry_run, - 'saved_state_json': None, - 'is_preserve': is_preserve, - 'is_save_state': False, - 'tenant_id': tenant_id} - for service in self.tenant_services: - svc = service(mgr, **kwargs) - svc.run() - - def _init_admin_ids(self): - tn_cl = self.admin_mgr.tenants_client - rl_cl = self.admin_mgr.roles_client - - tenant = identity.get_tenant_by_name(tn_cl, - CONF.auth.admin_project_name) - self.admin_tenant_id = tenant['id'] - - user = identity.get_user_by_username(tn_cl, self.admin_tenant_id, - CONF.auth.admin_username) - self.admin_id = user['id'] - - roles = rl_cl.list_roles()['roles'] - for role in roles: - if role['name'] == CONF.identity.admin_role: - self.admin_role_id = role['id'] - break - - def get_parser(self, prog_name): - parser = super(TempestCleanup, self).get_parser(prog_name) - parser.add_argument('--init-saved-state', action="store_true", - dest='init_saved_state', default=False, - help="Creates JSON file: " + SAVED_STATE_JSON + - ", representing the current state of your " - "deployment, specifically object types " - "tempest creates and destroys during a run. " - "You must run with this flag prior to " - "executing cleanup in normal mode, which is with " - "no arguments.") - parser.add_argument('--delete-tempest-conf-objects', - action="store_true", - dest='delete_tempest_conf_objects', - default=False, - help="Force deletion of the tempest and " - "alternate tempest users and tenants.") - parser.add_argument('--dry-run', action="store_true", - dest='dry_run', default=False, - help="Generate JSON file:" + DRY_RUN_JSON + - ", that reports the objects that would have " - "been deleted had a full cleanup been run.") - return parser - - def get_description(self): - return 'Cleanup after tempest run' - - def _add_admin(self, tenant_id): - rl_cl = self.admin_mgr.roles_client - needs_role = True - roles = rl_cl.list_user_roles_on_project(tenant_id, - self.admin_id)['roles'] - for role in roles: - if role['id'] == self.admin_role_id: - needs_role = False - LOG.debug("User already had admin privilege for this tenant") - if needs_role: - LOG.debug("Adding admin privilege for : %s", tenant_id) - rl_cl.create_user_role_on_project(tenant_id, self.admin_id, - self.admin_role_id) - self.admin_role_added.append(tenant_id) - - def _remove_admin_role(self, tenant_id): - LOG.debug("Remove admin user role for tenant: %s", tenant_id) - # Must initialize AdminManager for each user role - # Otherwise authentication exception is thrown, weird - id_cl = credentials.AdminManager().identity_client - if (self._tenant_exists(tenant_id)): - try: - id_cl.delete_role_from_user_on_project(tenant_id, - self.admin_id, - self.admin_role_id) - except Exception as ex: - LOG.exception("Failed removing role from tenant which still" - "exists, exception: %s", ex) - - def _tenant_exists(self, tenant_id): - tn_cl = self.admin_mgr.tenants_client - try: - t = tn_cl.show_tenant(tenant_id) - LOG.debug("Tenant is: %s", str(t)) - return True - except Exception as ex: - LOG.debug("Tenant no longer exists? %s", ex) - return False - - def _init_state(self): - print("Initializing saved state.") - data = {} - admin_mgr = self.admin_mgr - kwargs = {'data': data, - 'is_dry_run': False, - 'saved_state_json': data, - 'is_preserve': False, - 'is_save_state': True} - for service in self.global_services: - svc = service(admin_mgr, **kwargs) - svc.run() - - with open(SAVED_STATE_JSON, 'w+') as f: - f.write(json.dumps(data, - sort_keys=True, indent=2, separators=(',', ': '))) - - def _load_json(self): - try: - with open(SAVED_STATE_JSON) as json_file: - self.json_data = json.load(json_file) - - except IOError as ex: - LOG.exception("Failed loading saved state, please be sure you" - " have first run cleanup with --init-saved-state " - "flag prior to running tempest. Exception: %s", ex) - sys.exit(ex) - except Exception as ex: - LOG.exception("Exception parsing saved state json : %s", ex) - sys.exit(ex) diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py deleted file mode 100644 index 11cd4bb6b..000000000 --- a/tempest/cmd/cleanup_service.py +++ /dev/null @@ -1,990 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2015 Dell Inc. -# -# 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 oslo_log import log as logging - -from tempest.common import credentials_factory as credentials -from tempest.common import identity -from tempest.common.utils import net_info -from tempest import config -from tempest import test - -LOG = logging.getLogger(__name__) -CONF = config.CONF - -CONF_FLAVORS = None -CONF_IMAGES = None -CONF_NETWORKS = [] -CONF_PRIV_NETWORK_NAME = None -CONF_PUB_NETWORK = None -CONF_PUB_ROUTER = None -CONF_TENANTS = None -CONF_USERS = None - -IS_CINDER = None -IS_GLANCE = None -IS_HEAT = None -IS_NEUTRON = None -IS_NOVA = None - - -def init_conf(): - global CONF_FLAVORS - global CONF_IMAGES - global CONF_NETWORKS - global CONF_PRIV_NETWORK - global CONF_PRIV_NETWORK_NAME - global CONF_PUB_NETWORK - global CONF_PUB_ROUTER - global CONF_TENANTS - global CONF_USERS - global IS_CINDER - global IS_GLANCE - global IS_HEAT - global IS_NEUTRON - global IS_NOVA - - IS_CINDER = CONF.service_available.cinder - IS_GLANCE = CONF.service_available.glance - IS_HEAT = CONF.service_available.heat - IS_NEUTRON = CONF.service_available.neutron - IS_NOVA = CONF.service_available.nova - - CONF_FLAVORS = [CONF.compute.flavor_ref, CONF.compute.flavor_ref_alt] - CONF_IMAGES = [CONF.compute.image_ref, CONF.compute.image_ref_alt] - CONF_PRIV_NETWORK_NAME = CONF.compute.fixed_network_name - CONF_PUB_NETWORK = CONF.network.public_network_id - CONF_PUB_ROUTER = CONF.network.public_router_id - CONF_TENANTS = [CONF.auth.admin_project_name] - CONF_USERS = [CONF.auth.admin_username] - - if IS_NEUTRON: - CONF_PRIV_NETWORK = _get_network_id(CONF.compute.fixed_network_name, - CONF.auth.admin_project_name) - CONF_NETWORKS = [CONF_PUB_NETWORK, CONF_PRIV_NETWORK] - - -def _get_network_id(net_name, project_name): - am = credentials.AdminManager() - net_cl = am.networks_client - tn_cl = am.tenants_client - - networks = net_cl.list_networks() - tenant = identity.get_tenant_by_name(tn_cl, project_name) - t_id = tenant['id'] - n_id = None - for net in networks['networks']: - if (net['tenant_id'] == t_id and net['name'] == net_name): - n_id = net['id'] - break - return n_id - - -class BaseService(object): - def __init__(self, kwargs): - self.client = None - for key, value in kwargs.items(): - setattr(self, key, value) - - self.tenant_filter = {} - if hasattr(self, 'tenant_id'): - self.tenant_filter['tenant_id'] = self.tenant_id - - def _filter_by_tenant_id(self, item_list): - if (item_list is None - or not item_list - or not hasattr(self, 'tenant_id') - or self.tenant_id is None - or 'tenant_id' not in item_list[0]): - return item_list - - return [item for item in item_list - if item['tenant_id'] == self.tenant_id] - - def list(self): - pass - - def delete(self): - pass - - def dry_run(self): - pass - - def save_state(self): - pass - - def run(self): - if self.is_dry_run: - self.dry_run() - elif self.is_save_state: - self.save_state() - else: - self.delete() - - -class SnapshotService(BaseService): - - def __init__(self, manager, **kwargs): - super(SnapshotService, self).__init__(kwargs) - self.client = manager.snapshots_client - - def list(self): - client = self.client - snaps = client.list_snapshots()['snapshots'] - LOG.debug("List count, %s Snapshots", len(snaps)) - return snaps - - def delete(self): - snaps = self.list() - client = self.client - for snap in snaps: - try: - client.delete_snapshot(snap['id']) - except Exception: - LOG.exception("Delete Snapshot exception.") - - def dry_run(self): - snaps = self.list() - self.data['snapshots'] = snaps - - -class ServerService(BaseService): - def __init__(self, manager, **kwargs): - super(ServerService, self).__init__(kwargs) - self.client = manager.servers_client - self.server_groups_client = manager.server_groups_client - - def list(self): - client = self.client - servers_body = client.list_servers() - servers = servers_body['servers'] - LOG.debug("List count, %s Servers", len(servers)) - return servers - - def delete(self): - client = self.client - servers = self.list() - for server in servers: - try: - client.delete_server(server['id']) - except Exception: - LOG.exception("Delete Server exception.") - - def dry_run(self): - servers = self.list() - self.data['servers'] = servers - - -class ServerGroupService(ServerService): - - def list(self): - client = self.server_groups_client - sgs = client.list_server_groups()['server_groups'] - LOG.debug("List count, %s Server Groups", len(sgs)) - return sgs - - def delete(self): - client = self.client - sgs = self.list() - for sg in sgs: - try: - client.delete_server_group(sg['id']) - except Exception: - LOG.exception("Delete Server Group exception.") - - def dry_run(self): - sgs = self.list() - self.data['server_groups'] = sgs - - -class StackService(BaseService): - def __init__(self, manager, **kwargs): - super(StackService, self).__init__(kwargs) - params = config.service_client_config('orchestration') - self.client = manager.orchestration.OrchestrationClient( - manager.auth_provider, **params) - - def list(self): - client = self.client - stacks = client.list_stacks()['stacks'] - LOG.debug("List count, %s Stacks", len(stacks)) - return stacks - - def delete(self): - client = self.client - stacks = self.list() - for stack in stacks: - try: - client.delete_stack(stack['id']) - except Exception: - LOG.exception("Delete Stack exception.") - - def dry_run(self): - stacks = self.list() - self.data['stacks'] = stacks - - -class KeyPairService(BaseService): - def __init__(self, manager, **kwargs): - super(KeyPairService, self).__init__(kwargs) - self.client = manager.keypairs_client - - def list(self): - client = self.client - keypairs = client.list_keypairs()['keypairs'] - LOG.debug("List count, %s Keypairs", len(keypairs)) - return keypairs - - def delete(self): - client = self.client - keypairs = self.list() - for k in keypairs: - try: - name = k['keypair']['name'] - client.delete_keypair(name) - except Exception: - LOG.exception("Delete Keypairs exception.") - - def dry_run(self): - keypairs = self.list() - self.data['keypairs'] = keypairs - - -class SecurityGroupService(BaseService): - def __init__(self, manager, **kwargs): - super(SecurityGroupService, self).__init__(kwargs) - self.client = manager.compute_security_groups_client - - def list(self): - client = self.client - secgrps = client.list_security_groups()['security_groups'] - secgrp_del = [grp for grp in secgrps if grp['name'] != 'default'] - LOG.debug("List count, %s Security Groups", len(secgrp_del)) - return secgrp_del - - def delete(self): - client = self.client - secgrp_del = self.list() - for g in secgrp_del: - try: - client.delete_security_group(g['id']) - except Exception: - LOG.exception("Delete Security Groups exception.") - - def dry_run(self): - secgrp_del = self.list() - self.data['security_groups'] = secgrp_del - - -class FloatingIpService(BaseService): - def __init__(self, manager, **kwargs): - super(FloatingIpService, self).__init__(kwargs) - self.client = manager.compute_floating_ips_client - - def list(self): - client = self.client - floating_ips = client.list_floating_ips()['floating_ips'] - LOG.debug("List count, %s Floating IPs", len(floating_ips)) - return floating_ips - - def delete(self): - client = self.client - floating_ips = self.list() - for f in floating_ips: - try: - client.delete_floating_ip(f['id']) - except Exception: - LOG.exception("Delete Floating IPs exception.") - - def dry_run(self): - floating_ips = self.list() - self.data['floating_ips'] = floating_ips - - -class VolumeService(BaseService): - def __init__(self, manager, **kwargs): - super(VolumeService, self).__init__(kwargs) - self.client = manager.volumes_client - - def list(self): - client = self.client - vols = client.list_volumes()['volumes'] - LOG.debug("List count, %s Volumes", len(vols)) - return vols - - def delete(self): - client = self.client - vols = self.list() - for v in vols: - try: - client.delete_volume(v['id']) - except Exception: - LOG.exception("Delete Volume exception.") - - def dry_run(self): - vols = self.list() - self.data['volumes'] = vols - - -class VolumeQuotaService(BaseService): - def __init__(self, manager, **kwargs): - super(VolumeQuotaService, self).__init__(kwargs) - self.client = manager.volume_quotas_client - - def delete(self): - client = self.client - try: - client.delete_quota_set(self.tenant_id) - except Exception: - LOG.exception("Delete Volume Quotas exception.") - - def dry_run(self): - quotas = self.client.show_quota_set( - self.tenant_id, params={'usage': True})['quota_set'] - self.data['volume_quotas'] = quotas - - -class NovaQuotaService(BaseService): - def __init__(self, manager, **kwargs): - super(NovaQuotaService, self).__init__(kwargs) - self.client = manager.quotas_client - self.limits_client = manager.limits_client - - def delete(self): - client = self.client - try: - client.delete_quota_set(self.tenant_id) - except Exception: - LOG.exception("Delete Quotas exception.") - - def dry_run(self): - client = self.limits_client - quotas = client.show_limits()['limits'] - self.data['compute_quotas'] = quotas['absolute'] - - -# Begin network service classes -class NetworkService(BaseService): - def __init__(self, manager, **kwargs): - super(NetworkService, self).__init__(kwargs) - self.networks_client = manager.networks_client - self.subnets_client = manager.subnets_client - self.ports_client = manager.ports_client - self.floating_ips_client = manager.floating_ips_client - self.metering_labels_client = manager.metering_labels_client - self.metering_label_rules_client = manager.metering_label_rules_client - self.security_groups_client = manager.security_groups_client - self.routers_client = manager.routers_client - - def _filter_by_conf_networks(self, item_list): - if not item_list or not all(('network_id' in i for i in item_list)): - return item_list - - return [item for item in item_list if item['network_id'] - not in CONF_NETWORKS] - - def list(self): - client = self.networks_client - networks = client.list_networks(**self.tenant_filter) - networks = networks['networks'] - # filter out networks declared in tempest.conf - if self.is_preserve: - networks = [network for network in networks - if network['id'] not in CONF_NETWORKS] - LOG.debug("List count, %s Networks", networks) - return networks - - def delete(self): - client = self.networks_client - networks = self.list() - for n in networks: - try: - client.delete_network(n['id']) - except Exception: - LOG.exception("Delete Network exception.") - - def dry_run(self): - networks = self.list() - self.data['networks'] = networks - - -class NetworkFloatingIpService(NetworkService): - - def list(self): - client = self.floating_ips_client - flips = client.list_floatingips(**self.tenant_filter) - flips = flips['floatingips'] - LOG.debug("List count, %s Network Floating IPs", len(flips)) - return flips - - def delete(self): - client = self.client - flips = self.list() - for flip in flips: - try: - client.delete_floatingip(flip['id']) - except Exception: - LOG.exception("Delete Network Floating IP exception.") - - def dry_run(self): - flips = self.list() - self.data['floating_ips'] = flips - - -class NetworkRouterService(NetworkService): - - def list(self): - client = self.routers_client - routers = client.list_routers(**self.tenant_filter) - routers = routers['routers'] - if self.is_preserve: - routers = [router for router in routers - if router['id'] != CONF_PUB_ROUTER] - - LOG.debug("List count, %s Routers", len(routers)) - return routers - - def delete(self): - client = self.routers_client - ports_client = self.ports_client - routers = self.list() - for router in routers: - try: - rid = router['id'] - ports = [port for port - in ports_client.list_ports(device_id=rid)['ports'] - if net_info.is_router_interface_port(port)] - for port in ports: - client.remove_router_interface(rid, port_id=port['id']) - client.delete_router(rid) - except Exception: - LOG.exception("Delete Router exception.") - - def dry_run(self): - routers = self.list() - self.data['routers'] = routers - - -class NetworkHealthMonitorService(NetworkService): - - def list(self): - client = self.client - hms = client.list_health_monitors() - hms = hms['health_monitors'] - hms = self._filter_by_tenant_id(hms) - LOG.debug("List count, %s Health Monitors", len(hms)) - return hms - - def delete(self): - client = self.client - hms = self.list() - for hm in hms: - try: - client.delete_health_monitor(hm['id']) - except Exception: - LOG.exception("Delete Health Monitor exception.") - - def dry_run(self): - hms = self.list() - self.data['health_monitors'] = hms - - -class NetworkMemberService(NetworkService): - - def list(self): - client = self.client - members = client.list_members() - members = members['members'] - members = self._filter_by_tenant_id(members) - LOG.debug("List count, %s Members", len(members)) - return members - - def delete(self): - client = self.client - members = self.list() - for member in members: - try: - client.delete_member(member['id']) - except Exception: - LOG.exception("Delete Member exception.") - - def dry_run(self): - members = self.list() - self.data['members'] = members - - -class NetworkVipService(NetworkService): - - def list(self): - client = self.client - vips = client.list_vips() - vips = vips['vips'] - vips = self._filter_by_tenant_id(vips) - LOG.debug("List count, %s VIPs", len(vips)) - return vips - - def delete(self): - client = self.client - vips = self.list() - for vip in vips: - try: - client.delete_vip(vip['id']) - except Exception: - LOG.exception("Delete VIP exception.") - - def dry_run(self): - vips = self.list() - self.data['vips'] = vips - - -class NetworkPoolService(NetworkService): - - def list(self): - client = self.client - pools = client.list_pools() - pools = pools['pools'] - pools = self._filter_by_tenant_id(pools) - LOG.debug("List count, %s Pools", len(pools)) - return pools - - def delete(self): - client = self.client - pools = self.list() - for pool in pools: - try: - client.delete_pool(pool['id']) - except Exception: - LOG.exception("Delete Pool exception.") - - def dry_run(self): - pools = self.list() - self.data['pools'] = pools - - -class NetworkMeteringLabelRuleService(NetworkService): - - def list(self): - client = self.metering_label_rules_client - rules = client.list_metering_label_rules() - rules = rules['metering_label_rules'] - rules = self._filter_by_tenant_id(rules) - LOG.debug("List count, %s Metering Label Rules", len(rules)) - return rules - - def delete(self): - client = self.metering_label_rules_client - rules = self.list() - for rule in rules: - try: - client.delete_metering_label_rule(rule['id']) - except Exception: - LOG.exception("Delete Metering Label Rule exception.") - - def dry_run(self): - rules = self.list() - self.data['rules'] = rules - - -class NetworkMeteringLabelService(NetworkService): - - def list(self): - client = self.metering_labels_client - labels = client.list_metering_labels() - labels = labels['metering_labels'] - labels = self._filter_by_tenant_id(labels) - LOG.debug("List count, %s Metering Labels", len(labels)) - return labels - - def delete(self): - client = self.metering_labels_client - labels = self.list() - for label in labels: - try: - client.delete_metering_label(label['id']) - except Exception: - LOG.exception("Delete Metering Label exception.") - - def dry_run(self): - labels = self.list() - self.data['labels'] = labels - - -class NetworkPortService(NetworkService): - - def list(self): - client = self.ports_client - ports = [port for port in - client.list_ports(**self.tenant_filter)['ports'] - if port["device_owner"] == "" or - port["device_owner"].startswith("compute:")] - - if self.is_preserve: - ports = self._filter_by_conf_networks(ports) - - LOG.debug("List count, %s Ports", len(ports)) - return ports - - def delete(self): - client = self.ports_client - ports = self.list() - for port in ports: - try: - client.delete_port(port['id']) - except Exception: - LOG.exception("Delete Port exception.") - - def dry_run(self): - ports = self.list() - self.data['ports'] = ports - - -class NetworkSecGroupService(NetworkService): - def list(self): - client = self.security_groups_client - filter = self.tenant_filter - # cannot delete default sec group so never show it. - secgroups = [secgroup for secgroup in - client.list_security_groups(**filter)['security_groups'] - if secgroup['name'] != 'default'] - - if self.is_preserve: - secgroups = self._filter_by_conf_networks(secgroups) - LOG.debug("List count, %s security_groups", len(secgroups)) - return secgroups - - def delete(self): - client = self.client - secgroups = self.list() - for secgroup in secgroups: - try: - client.delete_secgroup(secgroup['id']) - except Exception: - LOG.exception("Delete security_group exception.") - - def dry_run(self): - secgroups = self.list() - self.data['secgroups'] = secgroups - - -class NetworkSubnetService(NetworkService): - - def list(self): - client = self.subnets_client - subnets = client.list_subnets(**self.tenant_filter) - subnets = subnets['subnets'] - if self.is_preserve: - subnets = self._filter_by_conf_networks(subnets) - LOG.debug("List count, %s Subnets", len(subnets)) - return subnets - - def delete(self): - client = self.subnets_client - subnets = self.list() - for subnet in subnets: - try: - client.delete_subnet(subnet['id']) - except Exception: - LOG.exception("Delete Subnet exception.") - - def dry_run(self): - subnets = self.list() - self.data['subnets'] = subnets - - -# begin global services -class FlavorService(BaseService): - def __init__(self, manager, **kwargs): - super(FlavorService, self).__init__(kwargs) - self.client = manager.flavors_client - - def list(self): - client = self.client - flavors = client.list_flavors({"is_public": None})['flavors'] - if not self.is_save_state: - # recreate list removing saved flavors - flavors = [flavor for flavor in flavors if flavor['id'] - not in self.saved_state_json['flavors'].keys()] - - if self.is_preserve: - flavors = [flavor for flavor in flavors - if flavor['id'] not in CONF_FLAVORS] - LOG.debug("List count, %s Flavors after reconcile", len(flavors)) - return flavors - - def delete(self): - client = self.client - flavors = self.list() - for flavor in flavors: - try: - client.delete_flavor(flavor['id']) - except Exception: - LOG.exception("Delete Flavor exception.") - - def dry_run(self): - flavors = self.list() - self.data['flavors'] = flavors - - def save_state(self): - flavors = self.list() - self.data['flavors'] = {} - for flavor in flavors: - self.data['flavors'][flavor['id']] = flavor['name'] - - -class ImageService(BaseService): - def __init__(self, manager, **kwargs): - super(ImageService, self).__init__(kwargs) - self.client = manager.compute_images_client - - def list(self): - client = self.client - images = client.list_images({"all_tenants": True})['images'] - if not self.is_save_state: - images = [image for image in images if image['id'] - not in self.saved_state_json['images'].keys()] - if self.is_preserve: - images = [image for image in images - if image['id'] not in CONF_IMAGES] - LOG.debug("List count, %s Images after reconcile", len(images)) - return images - - def delete(self): - client = self.client - images = self.list() - for image in images: - try: - client.delete_image(image['id']) - except Exception: - LOG.exception("Delete Image exception.") - - def dry_run(self): - images = self.list() - self.data['images'] = images - - def save_state(self): - self.data['images'] = {} - images = self.list() - for image in images: - self.data['images'][image['id']] = image['name'] - - -class IdentityService(BaseService): - def __init__(self, manager, **kwargs): - super(IdentityService, self).__init__(kwargs) - self.client = manager.identity_client - - -class UserService(BaseService): - - def __init__(self, manager, **kwargs): - super(UserService, self).__init__(kwargs) - self.client = manager.users_client - - def list(self): - users = self.client.list_users()['users'] - - if not self.is_save_state: - users = [user for user in users if user['id'] - not in self.saved_state_json['users'].keys()] - - if self.is_preserve: - users = [user for user in users if user['name'] - not in CONF_USERS] - - elif not self.is_save_state: # Never delete admin user - users = [user for user in users if user['name'] != - CONF.auth.admin_username] - - LOG.debug("List count, %s Users after reconcile", len(users)) - return users - - def delete(self): - users = self.list() - for user in users: - try: - self.client.delete_user(user['id']) - except Exception: - LOG.exception("Delete User exception.") - - def dry_run(self): - users = self.list() - self.data['users'] = users - - def save_state(self): - users = self.list() - self.data['users'] = {} - for user in users: - self.data['users'][user['id']] = user['name'] - - -class RoleService(BaseService): - - def __init__(self, manager, **kwargs): - super(RoleService, self).__init__(kwargs) - self.client = manager.roles_client - - def list(self): - try: - roles = self.client.list_roles()['roles'] - # reconcile roles with saved state and never list admin role - if not self.is_save_state: - roles = [role for role in roles if - (role['id'] not in - self.saved_state_json['roles'].keys() - and role['name'] != CONF.identity.admin_role)] - LOG.debug("List count, %s Roles after reconcile", len(roles)) - return roles - except Exception: - LOG.exception("Cannot retrieve Roles.") - return [] - - def delete(self): - roles = self.list() - for role in roles: - try: - self.client.delete_role(role['id']) - except Exception: - LOG.exception("Delete Role exception.") - - def dry_run(self): - roles = self.list() - self.data['roles'] = roles - - def save_state(self): - roles = self.list() - self.data['roles'] = {} - for role in roles: - self.data['roles'][role['id']] = role['name'] - - -class TenantService(BaseService): - - def __init__(self, manager, **kwargs): - super(TenantService, self).__init__(kwargs) - self.client = manager.tenants_client - - def list(self): - tenants = self.client.list_tenants()['tenants'] - if not self.is_save_state: - tenants = [tenant for tenant in tenants if (tenant['id'] - not in self.saved_state_json['tenants'].keys() - and tenant['name'] != CONF.auth.admin_project_name)] - - if self.is_preserve: - tenants = [tenant for tenant in tenants if tenant['name'] - not in CONF_TENANTS] - - LOG.debug("List count, %s Tenants after reconcile", len(tenants)) - return tenants - - def delete(self): - tenants = self.list() - for tenant in tenants: - try: - self.client.delete_tenant(tenant['id']) - except Exception: - LOG.exception("Delete Tenant exception.") - - def dry_run(self): - tenants = self.list() - self.data['tenants'] = tenants - - def save_state(self): - tenants = self.list() - self.data['tenants'] = {} - for tenant in tenants: - self.data['tenants'][tenant['id']] = tenant['name'] - - -class DomainService(BaseService): - - def __init__(self, manager, **kwargs): - super(DomainService, self).__init__(kwargs) - self.client = manager.domains_client - - def list(self): - client = self.client - domains = client.list_domains()['domains'] - if not self.is_save_state: - domains = [domain for domain in domains if domain['id'] - not in self.saved_state_json['domains'].keys()] - - LOG.debug("List count, %s Domains after reconcile", len(domains)) - return domains - - def delete(self): - client = self.client - domains = self.list() - for domain in domains: - try: - client.update_domain(domain['id'], enabled=False) - client.delete_domain(domain['id']) - except Exception: - LOG.exception("Delete Domain exception.") - - def dry_run(self): - domains = self.list() - self.data['domains'] = domains - - def save_state(self): - domains = self.list() - self.data['domains'] = {} - for domain in domains: - self.data['domains'][domain['id']] = domain['name'] - - -def get_tenant_cleanup_services(): - tenant_services = [] - # TODO(gmann): Tempest should provide some plugin hook for cleanup - # script extension to plugin tests also. - if IS_NOVA: - tenant_services.append(ServerService) - tenant_services.append(KeyPairService) - tenant_services.append(SecurityGroupService) - tenant_services.append(ServerGroupService) - if not IS_NEUTRON: - tenant_services.append(FloatingIpService) - tenant_services.append(NovaQuotaService) - if IS_HEAT: - tenant_services.append(StackService) - if IS_NEUTRON: - tenant_services.append(NetworkFloatingIpService) - if test.is_extension_enabled('metering', 'network'): - tenant_services.append(NetworkMeteringLabelRuleService) - tenant_services.append(NetworkMeteringLabelService) - tenant_services.append(NetworkRouterService) - tenant_services.append(NetworkPortService) - tenant_services.append(NetworkSubnetService) - tenant_services.append(NetworkService) - tenant_services.append(NetworkSecGroupService) - if IS_CINDER: - tenant_services.append(SnapshotService) - tenant_services.append(VolumeService) - tenant_services.append(VolumeQuotaService) - return tenant_services - - -def get_global_cleanup_services(): - global_services = [] - if IS_NOVA: - global_services.append(FlavorService) - if IS_GLANCE: - global_services.append(ImageService) - global_services.append(UserService) - global_services.append(TenantService) - global_services.append(DomainService) - global_services.append(RoleService) - return global_services diff --git a/tempest/cmd/config-generator.tempest.conf b/tempest/cmd/config-generator.tempest.conf deleted file mode 100644 index b8f16d92d..000000000 --- a/tempest/cmd/config-generator.tempest.conf +++ /dev/null @@ -1,5 +0,0 @@ -[DEFAULT] -output_file = etc/tempest.conf.sample -namespace = tempest.config -namespace = oslo.concurrency -namespace = oslo.log diff --git a/tempest/cmd/init.py b/tempest/cmd/init.py deleted file mode 100644 index 7634d9e1a..000000000 --- a/tempest/cmd/init.py +++ /dev/null @@ -1,183 +0,0 @@ -# Copyright 2015 Hewlett-Packard Development Company, L.P. -# -# 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 os -import shutil -import sys - -from cliff import command -from oslo_config import generator -from oslo_log import log as logging -from six import moves -from testrepository import commands - -from tempest.cmd import workspace - -LOG = logging.getLogger(__name__) - -TESTR_CONF = """[DEFAULT] -test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \\ - OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \\ - OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-500} \\ - ${PYTHON:-python} -m subunit.run discover -t %s %s $LISTOPT $IDOPTION -test_id_option=--load-list $IDFILE -test_list_option=--list -group_regex=([^\.]*\.)* -""" - - -def get_tempest_default_config_dir(): - """Get default config directory of tempest - - There are 3 dirs that get tried in priority order. First is /etc/tempest, - if that doesn't exist it looks for a tempest dir in the XDG_CONFIG_HOME - dir (defaulting to ~/.config/tempest) and last it tries for a - ~/.tempest/etc directory. If none of these exist a ~/.tempest/etc - directory will be created. - - :return: default config dir - """ - global_conf_dir = '/etc/tempest' - xdg_config = os.environ.get('XDG_CONFIG_HOME', - os.path.expanduser('~/.config')) - user_xdg_global_path = os.path.join(xdg_config, 'tempest') - user_global_path = os.path.join(os.path.expanduser('~'), '.tempest/etc') - if os.path.isdir(global_conf_dir): - return global_conf_dir - elif os.path.isdir(user_xdg_global_path): - return user_xdg_global_path - elif os.path.isdir(user_global_path): - return user_global_path - else: - os.makedirs(user_global_path) - return user_global_path - - -class TempestInit(command.Command): - """Setup a local working environment for running tempest""" - - def get_parser(self, prog_name): - parser = super(TempestInit, self).get_parser(prog_name) - parser.add_argument('dir', nargs='?', default=os.getcwd(), - help="The path to the workspace directory. If you " - "omit this argument, the workspace directory is " - "your current directory") - parser.add_argument('--config-dir', '-c', default=None) - parser.add_argument('--show-global-config-dir', '-s', - action='store_true', dest='show_global_dir', - help="Print the global config dir location, " - "then exit") - parser.add_argument('--name', help="The workspace name", default=None) - parser.add_argument('--workspace-path', default=None, - help="The path to the workspace file, the default " - "is ~/.tempest/workspace.yaml") - return parser - - def generate_testr_conf(self, local_path): - testr_conf_path = os.path.join(local_path, '.testr.conf') - top_level_path = os.path.dirname(os.path.dirname(__file__)) - discover_path = os.path.join(top_level_path, 'test_discover') - testr_conf = TESTR_CONF % (top_level_path, discover_path) - with open(testr_conf_path, 'w+') as testr_conf_file: - testr_conf_file.write(testr_conf) - - def get_configparser(self, conf_path): - config_parse = moves.configparser.ConfigParser() - config_parse.optionxform = str - # get any existing values if a config file already exists - if os.path.isfile(conf_path): - # use read() for Python 2 and 3 compatibility - config_parse.read(conf_path) - return config_parse - - def update_local_conf(self, conf_path, lock_dir, log_dir): - config_parse = self.get_configparser(conf_path) - # Set local lock_dir in tempest conf - if not config_parse.has_section('oslo_concurrency'): - config_parse.add_section('oslo_concurrency') - config_parse.set('oslo_concurrency', 'lock_path', lock_dir) - # Set local log_dir in tempest conf - config_parse.set('DEFAULT', 'log_dir', log_dir) - # Set default log filename to tempest.log - config_parse.set('DEFAULT', 'log_file', 'tempest.log') - - # write out a new file with the updated configurations - with open(conf_path, 'w+') as conf_file: - config_parse.write(conf_file) - - def copy_config(self, etc_dir, config_dir): - if os.path.isdir(config_dir): - shutil.copytree(config_dir, etc_dir) - else: - LOG.warning("Global config dir %s can't be found", config_dir) - - def generate_sample_config(self, local_dir): - conf_generator = os.path.join(os.path.dirname(__file__), - 'config-generator.tempest.conf') - output_file = os.path.join(local_dir, 'etc/tempest.conf.sample') - if os.path.isfile(conf_generator): - generator.main(['--config-file', conf_generator, '--output-file', - output_file]) - else: - LOG.warning("Skipping sample config generation because global " - "config file %s can't be found", conf_generator) - - def create_working_dir(self, local_dir, config_dir): - # make sure we are working with abspath however tempest init is called - local_dir = os.path.abspath(local_dir) - # Create local dir if missing - if not os.path.isdir(local_dir): - LOG.debug('Creating local working dir: %s', local_dir) - os.mkdir(local_dir) - elif not os.listdir(local_dir) == []: - raise OSError("Directory you are trying to initialize already " - "exists and is not empty: %s" % local_dir) - - lock_dir = os.path.join(local_dir, 'tempest_lock') - etc_dir = os.path.join(local_dir, 'etc') - config_path = os.path.join(etc_dir, 'tempest.conf') - log_dir = os.path.join(local_dir, 'logs') - testr_dir = os.path.join(local_dir, '.testrepository') - # Create lock dir - if not os.path.isdir(lock_dir): - LOG.debug('Creating lock dir: %s', lock_dir) - os.mkdir(lock_dir) - # Create log dir - if not os.path.isdir(log_dir): - LOG.debug('Creating log dir: %s', log_dir) - os.mkdir(log_dir) - # Create and copy local etc dir - self.copy_config(etc_dir, config_dir) - # Generate the sample config file - self.generate_sample_config(local_dir) - # Update local confs to reflect local paths - self.update_local_conf(config_path, lock_dir, log_dir) - # Generate a testr conf file - self.generate_testr_conf(local_dir) - # setup local testr working dir - if not os.path.isdir(testr_dir): - commands.run_argv(['testr', 'init', '-d', local_dir], sys.stdin, - sys.stdout, sys.stderr) - - def take_action(self, parsed_args): - workspace_manager = workspace.WorkspaceManager( - parsed_args.workspace_path) - name = parsed_args.name or parsed_args.dir.split(os.path.sep)[-1] - config_dir = parsed_args.config_dir or get_tempest_default_config_dir() - if parsed_args.show_global_dir: - print("Global config dir is located at: %s" % config_dir) - sys.exit(0) - self.create_working_dir(parsed_args.dir, config_dir) - workspace_manager.register_new_workspace( - name, parsed_args.dir, init=True) diff --git a/tempest/cmd/list_plugins.py b/tempest/cmd/list_plugins.py deleted file mode 100644 index 86732da54..000000000 --- a/tempest/cmd/list_plugins.py +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env python - -# 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. - -""" -Utility for listing all currently installed Tempest plugins. - -**Usage:** ``tempest list-plugins``. -""" - -from cliff import command -import prettytable - -from tempest.test_discover import plugins as plg - - -class TempestListPlugins(command.Command): - def take_action(self, parsed_args): - self._list_plugins() - - def get_description(self): - return 'List all tempest plugins' - - def _list_plugins(self): - plugins = plg.TempestTestPluginManager() - - output = prettytable.PrettyTable(["Name", "EntryPoint"]) - for plugin in plugins.ext_plugins.extensions: - output.add_row([ - plugin.name, plugin.entry_point_target]) - - print(output) diff --git a/tempest/cmd/main.py b/tempest/cmd/main.py deleted file mode 100644 index 1090c41b1..000000000 --- a/tempest/cmd/main.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2015 Dell Inc. -# 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 sys - -from cliff import app -from cliff import commandmanager -from oslo_log import log as logging -from pbr import version - - -class Main(app.App): - - log = logging.getLogger(__name__) - - def __init__(self): - super(Main, self).__init__( - description='Tempest cli application', - version=version.VersionInfo('tempest').version_string_with_vcs(), - command_manager=commandmanager.CommandManager('tempest.cm'), - deferred_help=True, - ) - - def initialize_app(self, argv): - self.log.debug('tempest initialize_app') - - def prepare_to_run_command(self, cmd): - self.log.debug('prepare_to_run_command %s', cmd.__class__.__name__) - - def clean_up(self, cmd, result, err): - self.log.debug('tempest clean_up %s', cmd.__class__.__name__) - if err: - self.log.debug('tempest got an error: %s', err) - - -def main(argv=sys.argv[1:]): - the_app = Main() - return the_app.run(argv) - - -if __name__ == '__main__': - sys.exit(main(sys.argv[1:])) diff --git a/tempest/cmd/run.py b/tempest/cmd/run.py deleted file mode 100644 index 350dd0bde..000000000 --- a/tempest/cmd/run.py +++ /dev/null @@ -1,350 +0,0 @@ -# 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. - -""" -Runs tempest tests - -This command is used for running the tempest tests - -Test Selection -============== -Tempest run has several options: - - * **--regex/-r**: This is a selection regex like what testr uses. It will run - any tests that match on re.match() with the regex - * **--smoke/-s**: Run all the tests tagged as smoke - -There are also the **--blacklist-file** and **--whitelist-file** options that -let you pass a filepath to tempest run with the file format being a line -separated regex, with '#' used to signify the start of a comment on a line. -For example:: - - # Regex file - ^regex1 # Match these tests - .*regex2 # Match those tests - -The blacklist file will be used to construct a negative lookahead regex and -the whitelist file will simply OR all the regexes in the file. The whitelist -and blacklist file options are mutually exclusive so you can't use them -together. However, you can combine either with a normal regex or the *--smoke* -flag. When used with a blacklist file the generated regex will be combined to -something like:: - - ^((?!black_regex1|black_regex2).)*$cli_regex1 - -When combined with a whitelist file all the regexes from the file and the CLI -regexes will be ORed. - -You can also use the **--list-tests** option in conjunction with selection -arguments to list which tests will be run. - -Test Execution -============== -There are several options to control how the tests are executed. By default -tempest will run in parallel with a worker for each CPU present on the machine. -If you want to adjust the number of workers use the **--concurrency** option -and if you want to run tests serially use **--serial/-t** - -Running with Workspaces ------------------------ -Tempest run enables you to run your tempest tests from any setup tempest -workspace it relies on you having setup a tempest workspace with either the -``tempest init`` or ``tempest workspace`` commands. Then using the -``--workspace`` CLI option you can specify which one of your workspaces you -want to run tempest from. Using this option you don't have to run Tempest -directly with you current working directory being the workspace, Tempest will -take care of managing everything to be executed from there. - -Running from Anywhere ---------------------- -Tempest run provides you with an option to execute tempest from anywhere on -your system. You are required to provide a config file in this case with the -``--config-file`` option. When run tempest will create a .testrepository -directory and a .testr.conf file in your current working directory. This way -you can use testr commands directly to inspect the state of the previous run. - -Test Output -=========== -By default tempest run's output to STDOUT will be generated using the -subunit-trace output filter. But, if you would prefer a subunit v2 stream be -output to STDOUT use the **--subunit** flag - -Combining Runs -============== - -There are certain situations in which you want to split a single run of tempest -across 2 executions of tempest run. (for example to run part of the tests -serially and others in parallel) To accomplish this but still treat the results -as a single run you can leverage the **--combine** option which will append -the current run's results with the previous runs. -""" - -import io -import os -import sys -import tempfile -import threading - -from cliff import command -from os_testr import regex_builder -from os_testr import subunit_trace -from oslo_serialization import jsonutils as json -import six -from testrepository.commands import run_argv - -from tempest.cmd import cleanup_service -from tempest.cmd import init -from tempest.cmd import workspace -from tempest.common import credentials_factory as credentials -from tempest import config - - -CONF = config.CONF -SAVED_STATE_JSON = "saved_state.json" - - -class TempestRun(command.Command): - - def _set_env(self, config_file=None): - if config_file: - CONF.set_config_path(os.path.abspath(config_file)) - # NOTE(mtreinish): This is needed so that testr doesn't gobble up any - # stacktraces on failure. - if 'TESTR_PDB' in os.environ: - return - else: - os.environ["TESTR_PDB"] = "" - # NOTE(dims): most of our .testr.conf try to test for PYTHON - # environment variable and fall back to "python", under python3 - # if it does not exist. we should set it to the python3 executable - # to deal with this situation better for now. - if six.PY3 and 'PYTHON' not in os.environ: - os.environ['PYTHON'] = sys.executable - - def _create_testrepository(self): - if not os.path.isdir('.testrepository'): - returncode = run_argv(['testr', 'init'], sys.stdin, sys.stdout, - sys.stderr) - if returncode: - sys.exit(returncode) - - def _create_testr_conf(self): - top_level_path = os.path.dirname(os.path.dirname(__file__)) - discover_path = os.path.join(top_level_path, 'test_discover') - file_contents = init.TESTR_CONF % (top_level_path, discover_path) - with open('.testr.conf', 'w+') as testr_conf_file: - testr_conf_file.write(file_contents) - - def take_action(self, parsed_args): - returncode = 0 - if parsed_args.config_file: - self._set_env(parsed_args.config_file) - else: - self._set_env() - # Workspace execution mode - if parsed_args.workspace: - workspace_mgr = workspace.WorkspaceManager( - parsed_args.workspace_path) - path = workspace_mgr.get_workspace(parsed_args.workspace) - if not path: - sys.exit( - "The %r workspace isn't registered in " - "%r. Use 'tempest init' to " - "register the workspace." % - (parsed_args.workspace, workspace_mgr.path)) - os.chdir(path) - # NOTE(mtreinish): tempest init should create a .testrepository dir - # but since workspaces can be imported let's sanity check and - # ensure that one is created - self._create_testrepository() - # Local execution mode - elif os.path.isfile('.testr.conf'): - # If you're running in local execution mode and there is not a - # testrepository dir create one - self._create_testrepository() - # local execution with config file mode - elif parsed_args.config_file: - self._create_testr_conf() - self._create_testrepository() - else: - print("No .testr.conf file was found for local execution") - sys.exit(2) - if parsed_args.state: - self._init_state() - else: - pass - - if parsed_args.combine: - temp_stream = tempfile.NamedTemporaryFile() - return_code = run_argv(['tempest', 'last', '--subunit'], sys.stdin, - temp_stream, sys.stderr) - if return_code > 0: - sys.exit(return_code) - - regex = self._build_regex(parsed_args) - if parsed_args.list_tests: - argv = ['tempest', 'list-tests', regex] - returncode = run_argv(argv, sys.stdin, sys.stdout, sys.stderr) - else: - options = self._build_options(parsed_args) - returncode = self._run(regex, options) - if returncode > 0: - sys.exit(returncode) - - if parsed_args.combine: - return_code = run_argv(['tempest', 'last', '--subunit'], sys.stdin, - temp_stream, sys.stderr) - if return_code > 0: - sys.exit(return_code) - returncode = run_argv(['tempest', 'load', temp_stream.name], - sys.stdin, sys.stdout, sys.stderr) - sys.exit(returncode) - - def get_description(self): - return 'Run tempest' - - def _init_state(self): - print("Initializing saved state.") - data = {} - self.global_services = cleanup_service.get_global_cleanup_services() - self.admin_mgr = credentials.AdminManager() - admin_mgr = self.admin_mgr - kwargs = {'data': data, - 'is_dry_run': False, - 'saved_state_json': data, - 'is_preserve': False, - 'is_save_state': True} - for service in self.global_services: - svc = service(admin_mgr, **kwargs) - svc.run() - - with open(SAVED_STATE_JSON, 'w+') as f: - f.write(json.dumps(data, - sort_keys=True, indent=2, separators=(',', ': '))) - - def get_parser(self, prog_name): - parser = super(TempestRun, self).get_parser(prog_name) - parser = self._add_args(parser) - return parser - - def _add_args(self, parser): - # workspace args - parser.add_argument('--workspace', default=None, - help='Name of tempest workspace to use for running' - ' tests. You can see a list of workspaces ' - 'with tempest workspace list') - parser.add_argument('--workspace-path', default=None, - dest='workspace_path', - help="The path to the workspace file, the default " - "is ~/.tempest/workspace.yaml") - # Configuration flags - parser.add_argument('--config-file', default=None, dest='config_file', - help='Configuration file to run tempest with') - # test selection args - regex = parser.add_mutually_exclusive_group() - regex.add_argument('--smoke', '-s', action='store_true', - help="Run the smoke tests only") - regex.add_argument('--regex', '-r', default='', - help='A normal testr selection regex used to ' - 'specify a subset of tests to run') - list_selector = parser.add_mutually_exclusive_group() - list_selector.add_argument('--whitelist-file', '--whitelist_file', - help="Path to a whitelist file, this file " - "contains a separate regex on each " - "newline.") - list_selector.add_argument('--blacklist-file', '--blacklist_file', - help='Path to a blacklist file, this file ' - 'contains a separate regex exclude on ' - 'each newline') - # list only args - parser.add_argument('--list-tests', '-l', action='store_true', - help='List tests', - default=False) - # execution args - parser.add_argument('--concurrency', '-w', - help="The number of workers to use, defaults to " - "the number of cpus") - parallel = parser.add_mutually_exclusive_group() - parallel.add_argument('--parallel', dest='parallel', - action='store_true', - help='Run tests in parallel (this is the' - ' default)') - parallel.add_argument('--serial', '-t', dest='parallel', - action='store_false', - help='Run tests serially') - parser.add_argument('--save-state', dest='state', - action='store_true', - help="To save the state of the cloud before " - "running tempest.") - # output args - parser.add_argument("--subunit", action='store_true', - help='Enable subunit v2 output') - parser.add_argument("--combine", action='store_true', - help='Combine the output of this run with the ' - "previous run's as a combined stream in the " - "testr repository after it finish") - - parser.set_defaults(parallel=True) - return parser - - def _build_regex(self, parsed_args): - regex = '' - if parsed_args.smoke: - regex = 'smoke' - elif parsed_args.regex: - regex = parsed_args.regex - if parsed_args.whitelist_file or parsed_args.blacklist_file: - regex = regex_builder.construct_regex(parsed_args.blacklist_file, - parsed_args.whitelist_file, - regex, False) - return regex - - def _build_options(self, parsed_args): - options = [] - if parsed_args.subunit: - options.append("--subunit") - if parsed_args.parallel: - options.append("--parallel") - if parsed_args.concurrency: - options.append("--concurrency=%s" % parsed_args.concurrency) - return options - - def _run(self, regex, options): - returncode = 0 - argv = ['tempest', 'run', regex] + options - if '--subunit' in options: - returncode = run_argv(argv, sys.stdin, sys.stdout, sys.stderr) - else: - argv.append('--subunit') - stdin = io.StringIO() - stdout_r, stdout_w = os.pipe() - subunit_w = os.fdopen(stdout_w, 'wt') - subunit_r = os.fdopen(stdout_r) - returncodes = {} - - def run_argv_thread(): - returncodes['testr'] = run_argv(argv, stdin, subunit_w, - sys.stderr) - subunit_w.close() - - run_thread = threading.Thread(target=run_argv_thread) - run_thread.start() - returncodes['subunit-trace'] = subunit_trace.trace( - subunit_r, sys.stdout, post_fails=True, print_failures=True) - run_thread.join() - subunit_r.close() - # python version of pipefail - if returncodes['testr']: - returncode = returncodes['testr'] - elif returncodes['subunit-trace']: - returncode = returncodes['subunit-trace'] - return returncode diff --git a/tempest/cmd/subunit_describe_calls.py b/tempest/cmd/subunit_describe_calls.py deleted file mode 100644 index 8ee305582..000000000 --- a/tempest/cmd/subunit_describe_calls.py +++ /dev/null @@ -1,317 +0,0 @@ -# Copyright 2016 Rackspace -# -# 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. - -""" -subunit-describe-calls is a parser for subunit streams to determine what REST -API calls are made inside of a test and in what order they are called. - -Runtime Arguments ------------------ - -**--subunit, -s**: (Optional) The path to the subunit file being parsed, -defaults to stdin - -**--non-subunit-name, -n**: (Optional) The file_name that the logs are being -stored in - -**--output-file, -o**: (Optional) The path where the JSON output will be -written to. This contains more information than is present in stdout. - -**--ports, -p**: (Optional) The path to a JSON file describing the ports being -used by different services - -Usage ------ - -subunit-describe-calls will take in either stdin subunit v1 or v2 stream or a -file path which contains either a subunit v1 or v2 stream passed via the ---subunit parameter. This is then parsed checking for details contained in the -file_bytes of the --non-subunit-name parameter (the default is pythonlogging -which is what Tempest uses to store logs). By default the OpenStack Kilo -release port defaults (http://bit.ly/22jpF5P) are used unless a file is -provided via the --ports option. The resulting output is dumped in JSON output -to the path provided in the --output-file option. - -Ports file JSON structure -^^^^^^^^^^^^^^^^^^^^^^^^^ -:: - - { - "": "", - ... - } - - -Output file JSON structure -^^^^^^^^^^^^^^^^^^^^^^^^^^ -:: - - { - "full_test_name[with_id_and_tags]": [ - { - "name": "The ClassName.MethodName that made the call", - "verb": "HTTP Verb", - "service": "Name of the service", - "url": "A shortened version of the URL called", - "status_code": "The status code of the response", - "request_headers": "The headers of the request", - "request_body": "The body of the request", - "response_headers": "The headers of the response", - "response_body": "The body of the response" - } - ] - } -""" -import argparse -import collections -import io -import json -import os -import re -import sys - -import subunit -import testtools - - -class UrlParser(testtools.TestResult): - uuid_re = re.compile(r'(^|[^0-9a-f])[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-' - '[0-9a-f]{4}-[0-9a-f]{12}([^0-9a-f]|$)') - id_re = re.compile(r'(^|[^0-9a-z])[0-9a-z]{8}[0-9a-z]{4}[0-9a-z]{4}' - '[0-9a-z]{4}[0-9a-z]{12}([^0-9a-z]|$)') - ip_re = re.compile(r'(^|[^0-9])[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]' - '{1,3}([^0-9]|$)') - url_re = re.compile(r'.*INFO.*Request \((?P.*)\): (?P[\d]{3}) ' - '(?P\w*) (?P.*) .*') - port_re = re.compile(r'.*:(?P\d+).*') - path_re = re.compile(r'http[s]?://[^/]*/(?P.*)') - request_re = re.compile(r'.* Request - Headers: (?P.*)') - response_re = re.compile(r'.* Response - Headers: (?P.*)') - body_re = re.compile(r'.*Body: (?P.*)') - - # Based on mitaka defaults: - # http://docs.openstack.org/mitaka/config-reference/ - # firewalls-default-ports.html - services = { - "8776": "Block Storage", - "8774": "Nova", - "8773": "Nova-API", "8775": "Nova-API", - "8386": "Sahara", - "35357": "Keystone", "5000": "Keystone", - "9292": "Glance", "9191": "Glance", - "9696": "Neutron", - "6000": "Swift", "6001": "Swift", "6002": "Swift", - "8004": "Heat", "8000": "Heat", "8003": "Heat", - "8777": "Ceilometer", - "80": "Horizon", - "8080": "Swift", - "443": "SSL", - "873": "rsync", - "3260": "iSCSI", - "3306": "MySQL", - "5672": "AMQP"} - - def __init__(self, services=None): - super(UrlParser, self).__init__() - self.test_logs = {} - self.services = services or self.services - - def addSuccess(self, test, details=None): - output = test.shortDescription() or test.id() - calls = self.parse_details(details) - self.test_logs.update({output: calls}) - - def addSkip(self, test, err, details=None): - output = test.shortDescription() or test.id() - calls = self.parse_details(details) - self.test_logs.update({output: calls}) - - def addError(self, test, err, details=None): - output = test.shortDescription() or test.id() - calls = self.parse_details(details) - self.test_logs.update({output: calls}) - - def addFailure(self, test, err, details=None): - output = test.shortDescription() or test.id() - calls = self.parse_details(details) - self.test_logs.update({output: calls}) - - def stopTestRun(self): - super(UrlParser, self).stopTestRun() - - def startTestRun(self): - super(UrlParser, self).startTestRun() - - def parse_details(self, details): - if details is None: - return - - calls = [] - for _, detail in details.items(): - in_request = False - in_response = False - current_call = {} - for line in detail.as_text().split("\n"): - url_match = self.url_re.match(line) - request_match = self.request_re.match(line) - response_match = self.response_re.match(line) - body_match = self.body_re.match(line) - - if url_match is not None: - if current_call != {}: - calls.append(current_call.copy()) - current_call = {} - in_request, in_response = False, False - current_call.update({ - "name": url_match.group("name"), - "verb": url_match.group("verb"), - "status_code": url_match.group("code"), - "service": self.get_service(url_match.group("url")), - "url": self.url_path(url_match.group("url"))}) - elif request_match is not None: - in_request, in_response = True, False - current_call.update( - {"request_headers": request_match.group("headers")}) - elif in_request and body_match is not None: - in_request = False - current_call.update( - {"request_body": body_match.group( - "body")}) - elif response_match is not None: - in_request, in_response = False, True - current_call.update( - {"response_headers": response_match.group( - "headers")}) - elif in_response and body_match is not None: - in_response = False - current_call.update( - {"response_body": body_match.group("body")}) - if current_call != {}: - calls.append(current_call.copy()) - - return calls - - def get_service(self, url): - match = self.port_re.match(url) - if match is not None: - return self.services.get(match.group("port"), "Unknown") - return "Unknown" - - def url_path(self, url): - match = self.path_re.match(url) - if match is not None: - path = match.group("path") - path = self.uuid_re.sub(r'\1\2', path) - path = self.ip_re.sub(r'\1\2', path) - path = self.id_re.sub(r'\1\2', path) - return path - return url - - -class FileAccumulator(testtools.StreamResult): - - def __init__(self, non_subunit_name='pythonlogging'): - super(FileAccumulator, self).__init__() - self.route_codes = collections.defaultdict(io.BytesIO) - self.non_subunit_name = non_subunit_name - - def status(self, **kwargs): - if kwargs.get('file_name') != self.non_subunit_name: - return - file_bytes = kwargs.get('file_bytes') - if not file_bytes: - return - route_code = kwargs.get('route_code') - stream = self.route_codes[route_code] - stream.write(file_bytes) - - -class ArgumentParser(argparse.ArgumentParser): - def __init__(self): - desc = "Outputs all HTTP calls a given test made that were logged." - super(ArgumentParser, self).__init__(description=desc) - - self.prog = "subunit-describe-calls" - - self.add_argument( - "-s", "--subunit", metavar="", - nargs="?", type=argparse.FileType('rb'), default=sys.stdin, - help="The path to the subunit output file.") - - self.add_argument( - "-n", "--non-subunit-name", metavar="", - default="pythonlogging", - help="The name used in subunit to describe the file contents.") - - self.add_argument( - "-o", "--output-file", metavar="", default=None, - help="The output file name for the json.") - - self.add_argument( - "-p", "--ports", metavar="", default=None, - help="A JSON file describing the ports for each service.") - - -def parse(stream, non_subunit_name, ports): - if ports is not None and os.path.exists(ports): - ports = json.loads(open(ports).read()) - - url_parser = UrlParser(ports) - suite = subunit.ByteStreamToStreamResult( - stream, non_subunit_name=non_subunit_name) - result = testtools.StreamToExtendedDecorator(url_parser) - accumulator = FileAccumulator(non_subunit_name) - result = testtools.StreamResultRouter(result) - result.add_rule(accumulator, 'test_id', test_id=None) - result.startTestRun() - suite.run(result) - - for bytes_io in accumulator.route_codes.values(): # v1 processing - bytes_io.seek(0) - suite = subunit.ProtocolTestCase(bytes_io) - suite.run(url_parser) - result.stopTestRun() - - return url_parser - - -def output(url_parser, output_file): - if output_file is not None: - with open(output_file, "w") as outfile: - outfile.write(json.dumps(url_parser.test_logs)) - return - - for test_name in url_parser.test_logs: - items = url_parser.test_logs[test_name] - sys.stdout.write('{0}\n'.format(test_name)) - if not items: - sys.stdout.write('\n') - continue - for item in items: - sys.stdout.write('\t- {0} {1} request for {2} to {3}\n'.format( - item.get('status_code'), item.get('verb'), - item.get('service'), item.get('url'))) - sys.stdout.write('\n') - - -def entry_point(): - cl_args = ArgumentParser().parse_args() - parser = parse(cl_args.subunit, cl_args.non_subunit_name, cl_args.ports) - output(parser, cl_args.output_file) - - -if __name__ == "__main__": - entry_point() diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py deleted file mode 100644 index 8e71ecca1..000000000 --- a/tempest/cmd/verify_tempest_config.py +++ /dev/null @@ -1,428 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2013 IBM Corp. -# -# 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 argparse -import os -import re -import sys -import traceback - -from cliff import command -from oslo_log import log as logging -from oslo_serialization import jsonutils as json -from six import moves -from six.moves.urllib import parse as urlparse - -from tempest import clients -from tempest.common import credentials_factory as credentials -from tempest import config -import tempest.lib.common.http - - -CONF = config.CONF -CONF_PARSER = None - -LOG = logging.getLogger(__name__) - - -def _get_config_file(): - default_config_dir = os.path.join(os.path.abspath( - os.path.dirname(os.path.dirname(os.path.dirname(__file__)))), "etc") - default_config_file = "tempest.conf" - - conf_dir = os.environ.get('TEMPEST_CONFIG_DIR', default_config_dir) - conf_file = os.environ.get('TEMPEST_CONFIG', default_config_file) - path = os.path.join(conf_dir, conf_file) - fd = open(path, 'r+') - return fd - - -def change_option(option, group, value): - if not CONF_PARSER.has_section(group): - CONF_PARSER.add_section(group) - CONF_PARSER.set(group, option, str(value)) - - -def print_and_or_update(option, group, value, update): - print('Config option %s in group %s should be changed to: %s' - % (option, group, value)) - if update: - change_option(option, group, value) - - -def contains_version(prefix, versions): - return any([x for x in versions if x.startswith(prefix)]) - - -def verify_glance_api_versions(os, update): - # Check glance api versions - _, versions = os.image_client.get_versions() - if CONF.image_feature_enabled.api_v1 != contains_version('v1.', versions): - print_and_or_update('api_v1', 'image-feature-enabled', - not CONF.image_feature_enabled.api_v1, update) - if CONF.image_feature_enabled.api_v2 != contains_version('v2.', versions): - print_and_or_update('api_v2', 'image-feature-enabled', - not CONF.image_feature_enabled.api_v2, update) - - -def _remove_version_project(url_path): - # The regex matches strings like /v2.0, /v3/, /v2.1/project-id/ - return re.sub(r'/v\d+(\.\d+)?(/[^/]+)?', '', url_path) - - -def _get_unversioned_endpoint(base_url): - endpoint_parts = urlparse.urlparse(base_url) - new_path = _remove_version_project(endpoint_parts.path) - endpoint_parts = endpoint_parts._replace(path=new_path) - endpoint = urlparse.urlunparse(endpoint_parts) - return endpoint - - -def _get_api_versions(os, service): - client_dict = { - 'nova': os.servers_client, - 'keystone': os.identity_client, - 'cinder': os.volumes_client_latest, - } - if service != 'keystone' and service != 'cinder': - # Since keystone and cinder may be listening on a path, - # do not remove the path. - client_dict[service].skip_path() - endpoint = _get_unversioned_endpoint(client_dict[service].base_url) - - http = tempest.lib.common.http.ClosingHttp( - CONF.identity.disable_ssl_certificate_validation, - CONF.identity.ca_certificates_file) - - __, body = http.request(endpoint, 'GET') - client_dict[service].reset_path() - try: - body = json.loads(body) - except ValueError: - LOG.error( - 'Failed to get a JSON response from unversioned endpoint %s ' - '(versioned endpoint was %s). Response is:\n%s', - endpoint, client_dict[service].base_url, body[:100]) - raise - if service == 'keystone': - versions = map(lambda x: x['id'], body['versions']['values']) - else: - versions = map(lambda x: x['id'], body['versions']) - return list(versions) - - -def verify_keystone_api_versions(os, update): - # Check keystone api versions - versions = _get_api_versions(os, 'keystone') - if (CONF.identity_feature_enabled.api_v2 != - contains_version('v2.', versions)): - print_and_or_update('api_v2', 'identity-feature-enabled', - not CONF.identity_feature_enabled.api_v2, update) - if (CONF.identity_feature_enabled.api_v3 != - contains_version('v3.', versions)): - print_and_or_update('api_v3', 'identity-feature-enabled', - not CONF.identity_feature_enabled.api_v3, update) - - -def verify_cinder_api_versions(os, update): - # Check cinder api versions - versions = _get_api_versions(os, 'cinder') - if (CONF.volume_feature_enabled.api_v1 != - contains_version('v1.', versions)): - print_and_or_update('api_v1', 'volume-feature-enabled', - not CONF.volume_feature_enabled.api_v1, update) - if (CONF.volume_feature_enabled.api_v2 != - contains_version('v2.', versions)): - print_and_or_update('api_v2', 'volume-feature-enabled', - not CONF.volume_feature_enabled.api_v2, update) - if (CONF.volume_feature_enabled.api_v3 != - contains_version('v3.', versions)): - print_and_or_update('api_v3', 'volume-feature-enabled', - not CONF.volume_feature_enabled.api_v3, update) - - -def verify_api_versions(os, service, update): - verify = { - 'cinder': verify_cinder_api_versions, - 'glance': verify_glance_api_versions, - 'keystone': verify_keystone_api_versions, - } - if service not in verify: - return - verify[service](os, update) - - -def get_extension_client(os, service): - extensions_client = { - 'nova': os.extensions_client, - 'neutron': os.network_extensions_client, - 'swift': os.capabilities_client, - # NOTE: Cinder v3 API is current and v2 and v1 are deprecated. - # V3 extension API is the same as v2, so we reuse the v2 client - # for v3 API also. - 'cinder': os.volumes_v2_extension_client, - } - - if service not in extensions_client: - print('No tempest extensions client for %s' % service) - sys.exit(1) - return extensions_client[service] - - -def get_enabled_extensions(service): - extensions_options = { - 'nova': CONF.compute_feature_enabled.api_extensions, - 'cinder': CONF.volume_feature_enabled.api_extensions, - 'neutron': CONF.network_feature_enabled.api_extensions, - 'swift': CONF.object_storage_feature_enabled.discoverable_apis, - } - if service not in extensions_options: - print('No supported extensions list option for %s' % service) - sys.exit(1) - return extensions_options[service] - - -def verify_extensions(os, service, results): - extensions_client = get_extension_client(os, service) - if service != 'swift': - resp = extensions_client.list_extensions() - else: - resp = extensions_client.list_capabilities() - # For Nova, Cinder and Neutron we use the alias name rather than the - # 'name' field because the alias is considered to be the canonical - # name. - if isinstance(resp, dict): - if service == 'swift': - # Remove Swift general information from extensions list - resp.pop('swift') - extensions = resp.keys() - else: - extensions = map(lambda x: x['alias'], resp['extensions']) - - else: - extensions = map(lambda x: x['alias'], resp) - extensions = list(extensions) - if not results.get(service): - results[service] = {} - extensions_opt = get_enabled_extensions(service) - if extensions_opt[0] == 'all': - results[service]['extensions'] = extensions - return results - # Verify that all configured extensions are actually enabled - for extension in extensions_opt: - results[service][extension] = extension in extensions - # Verify that there aren't additional extensions enabled that aren't - # specified in the config list - for extension in extensions: - if extension not in extensions_opt: - results[service][extension] = False - return results - - -def display_results(results, update, replace): - update_dict = { - 'swift': 'object-storage-feature-enabled', - 'nova': 'compute-feature-enabled', - 'cinder': 'volume-feature-enabled', - 'neutron': 'network-feature-enabled', - } - for service in results: - # If all extensions are specified as being enabled there is no way to - # verify this so we just assume this to be true - if results[service].get('extensions'): - if replace: - output_list = results[service].get('extensions') - else: - output_list = ['all'] - else: - extension_list = get_enabled_extensions(service) - output_list = [] - for extension in results[service]: - if not results[service][extension]: - if extension in extension_list: - print("%s extension: %s should not be included in the " - "list of enabled extensions" % (service, - extension)) - else: - print("%s extension: %s should be included in the list" - " of enabled extensions" % (service, extension)) - output_list.append(extension) - else: - output_list.append(extension) - if update: - # Sort List - output_list.sort() - # Convert list to a string - output_string = ', '.join(output_list) - if service == 'swift': - change_option('discoverable_apis', update_dict[service], - output_string) - else: - change_option('api_extensions', update_dict[service], - output_string) - - -def check_service_availability(os, update): - services = [] - avail_services = [] - codename_match = { - 'volume': 'cinder', - 'network': 'neutron', - 'image': 'glance', - 'object_storage': 'swift', - 'compute': 'nova', - 'orchestration': 'heat', - 'baremetal': 'ironic', - 'identity': 'keystone', - } - # Get catalog list for endpoints to use for validation - _token, auth_data = os.auth_provider.get_auth() - if os.auth_version == 'v2': - catalog_key = 'serviceCatalog' - else: - catalog_key = 'catalog' - for entry in auth_data[catalog_key]: - services.append(entry['type']) - # Pull all catalog types from config file and compare against endpoint list - for cfgname in dir(CONF._config): - cfg = getattr(CONF, cfgname) - catalog_type = getattr(cfg, 'catalog_type', None) - if not catalog_type: - continue - else: - if cfgname == 'identity': - # Keystone is a required service for tempest - continue - if catalog_type not in services: - if getattr(CONF.service_available, codename_match[cfgname]): - print('Endpoint type %s not found either disable service ' - '%s or fix the catalog_type in the config file' % ( - catalog_type, codename_match[cfgname])) - if update: - change_option(codename_match[cfgname], - 'service_available', False) - else: - if not getattr(CONF.service_available, - codename_match[cfgname]): - print('Endpoint type %s is available, service %s should be' - ' set as available in the config file.' % ( - catalog_type, codename_match[cfgname])) - if update: - change_option(codename_match[cfgname], - 'service_available', True) - # If we are going to enable this we should allow - # extension checks. - avail_services.append(codename_match[cfgname]) - else: - avail_services.append(codename_match[cfgname]) - return avail_services - - -def _parser_add_args(parser): - parser.add_argument('-u', '--update', action='store_true', - help='Update the config file with results from api ' - 'queries. This assumes whatever is set in the ' - 'config file is incorrect. In the case of ' - 'endpoint checks where it could either be the ' - 'incorrect catalog type or the service available ' - 'option the service available option is assumed ' - 'to be incorrect and is thus changed') - parser.add_argument('-o', '--output', - help="Output file to write an updated config file to. " - "This has to be a separate file from the " - "original config file. If one isn't specified " - "with -u the new config file will be printed to " - "STDOUT") - parser.add_argument('-r', '--replace-ext', action='store_true', - help="If specified the all option will be replaced " - "with a full list of extensions") - - -def parse_args(): - parser = argparse.ArgumentParser() - _parser_add_args(parser) - opts = parser.parse_args() - return opts - - -def main(opts=None): - print('Running config verification...') - if opts is None: - print("Use of: 'verify-tempest-config' is deprecated, " - "please use: 'tempest verify-config'") - opts = parse_args() - update = opts.update - replace = opts.replace_ext - global CONF_PARSER - - if update: - conf_file = _get_config_file() - CONF_PARSER = moves.configparser.ConfigParser() - CONF_PARSER.optionxform = str - CONF_PARSER.readfp(conf_file) - - # Indicate not to create network resources as part of getting credentials - net_resources = { - 'network': False, - 'router': False, - 'subnet': False, - 'dhcp': False - } - icreds = credentials.get_credentials_provider( - 'verify_tempest_config', network_resources=net_resources) - try: - os = clients.Manager(icreds.get_primary_creds().credentials) - services = check_service_availability(os, update) - results = {} - for service in ['nova', 'cinder', 'neutron', 'swift']: - if service not in services: - continue - results = verify_extensions(os, service, results) - - # Verify API versions of all services in the keystone catalog and - # keystone itself. - services.append('keystone') - for service in services: - verify_api_versions(os, service, update) - - display_results(results, update, replace) - if update: - conf_file.close() - if opts.output: - with open(opts.output, 'w+') as outfile: - CONF_PARSER.write(outfile) - finally: - icreds.clear_creds() - - -class TempestVerifyConfig(command.Command): - """Verify your current tempest configuration""" - - def get_parser(self, prog_name): - parser = super(TempestVerifyConfig, self).get_parser(prog_name) - _parser_add_args(parser) - return parser - - def take_action(self, parsed_args): - try: - main(parsed_args) - except Exception: - LOG.exception("Failure verifying configuration.") - traceback.print_exc() - raise - -if __name__ == "__main__": - main() diff --git a/tempest/cmd/workspace.py b/tempest/cmd/workspace.py deleted file mode 100644 index 8166b4f8c..000000000 --- a/tempest/cmd/workspace.py +++ /dev/null @@ -1,262 +0,0 @@ -# Copyright 2016 Rackspace -# -# 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. - -""" -Manages Tempest workspaces - -This command is used for managing tempest workspaces - -Commands -======== - -list ----- -Outputs the name and path of all known tempest workspaces - -register --------- -Registers a new tempest workspace via a given --name and --path - -rename ------- -Renames a tempest workspace from --old-name to --new-name - -move ----- -Changes the path of a given tempest workspace --name to --path - -remove ------- -Deletes the entry for a given tempest workspace --name - ---rmdir Deletes the given tempest workspace directory - -General Options -=============== - - **--workspace_path**: Allows the user to specify a different location for the - workspace.yaml file containing the workspace definitions - instead of ~/.tempest/workspace.yaml -""" - -import os -import shutil -import sys - -from cliff import command -from cliff import lister -from oslo_concurrency import lockutils -import yaml - -from tempest import config - -CONF = config.CONF - - -class WorkspaceManager(object): - def __init__(self, path=None): - lockutils.get_lock_path(CONF) - self.path = path or os.path.join( - os.path.expanduser("~"), ".tempest", "workspace.yaml") - if not os.path.isdir(os.path.dirname(self.path)): - os.makedirs(self.path.rsplit(os.path.sep, 1)[0]) - self.workspaces = {} - - @lockutils.synchronized('workspaces', external=True) - def get_workspace(self, name): - """Returns the workspace that has the given name - - If the workspace isn't registered then `None` is returned. - """ - self._populate() - return self.workspaces.get(name) - - @lockutils.synchronized('workspaces', external=True) - def rename_workspace(self, old_name, new_name): - self._populate() - self._name_exists(old_name) - self._workspace_name_exists(new_name) - self.workspaces[new_name] = self.workspaces.pop(old_name) - self._write_file() - - @lockutils.synchronized('workspaces', external=True) - def move_workspace(self, name, path): - self._populate() - path = os.path.abspath(os.path.expanduser(path)) - self._name_exists(name) - self._validate_path(path) - self.workspaces[name] = path - self._write_file() - - def _name_exists(self, name): - if name not in self.workspaces: - print("A workspace was not found with name: {0}".format(name)) - sys.exit(1) - - @lockutils.synchronized('workspaces', external=True) - def remove_workspace_entry(self, name): - self._populate() - self._name_exists(name) - workspace_path = self.workspaces.pop(name) - self._write_file() - return workspace_path - - @lockutils.synchronized('workspaces', external=True) - def remove_workspace_directory(self, workspace_path): - shutil.rmtree(workspace_path) - - @lockutils.synchronized('workspaces', external=True) - def list_workspaces(self): - self._populate() - self._validate_workspaces() - return self.workspaces - - def _workspace_name_exists(self, name): - if name in self.workspaces: - print("A workspace already exists with name: {0}.".format( - name)) - sys.exit(1) - - def _validate_path(self, path): - if not os.path.exists(path): - print("Path does not exist.") - sys.exit(1) - - @lockutils.synchronized('workspaces', external=True) - def register_new_workspace(self, name, path, init=False): - """Adds the new workspace and writes out the new workspace config""" - self._populate() - path = os.path.abspath(os.path.expanduser(path)) - # This only happens when register is called from outside of init - if not init: - self._validate_path(path) - self._workspace_name_exists(name) - self.workspaces[name] = path - self._write_file() - - def _validate_workspaces(self): - if self.workspaces is not None: - self.workspaces = {n: p for n, p in self.workspaces.items() - if os.path.exists(p)} - self._write_file() - - def _write_file(self): - with open(self.path, 'w') as f: - f.write(yaml.dump(self.workspaces)) - - def _populate(self): - if not os.path.isfile(self.path): - return - with open(self.path, 'r') as f: - self.workspaces = yaml.safe_load(f) or {} - - -def add_global_arguments(parser): - parser.add_argument( - '--workspace-path', required=False, default=None, - help="The path to the workspace file, the default is " - "~/.tempest/workspace.yaml") - return parser - - -class TempestWorkspaceRegister(command.Command): - def get_description(self): - return ('Registers a new tempest workspace via a given ' - '--name and --path') - - def get_parser(self, prog_name): - parser = super(TempestWorkspaceRegister, self).get_parser(prog_name) - add_global_arguments(parser) - parser.add_argument('--name', required=True) - parser.add_argument('--path', required=True) - - return parser - - def take_action(self, parsed_args): - self.manager = WorkspaceManager(parsed_args.workspace_path) - self.manager.register_new_workspace(parsed_args.name, parsed_args.path) - sys.exit(0) - - -class TempestWorkspaceRename(command.Command): - def get_description(self): - return 'Renames a tempest workspace from --old-name to --new-name' - - def get_parser(self, prog_name): - parser = super(TempestWorkspaceRename, self).get_parser(prog_name) - add_global_arguments(parser) - parser.add_argument('--old-name', required=True) - parser.add_argument('--new-name', required=True) - - return parser - - def take_action(self, parsed_args): - self.manager = WorkspaceManager(parsed_args.workspace_path) - self.manager.rename_workspace( - parsed_args.old_name, parsed_args.new_name) - sys.exit(0) - - -class TempestWorkspaceMove(command.Command): - def get_description(self): - return 'Changes the path of a given tempest workspace --name to --path' - - def get_parser(self, prog_name): - parser = super(TempestWorkspaceMove, self).get_parser(prog_name) - add_global_arguments(parser) - parser.add_argument('--name', required=True) - parser.add_argument('--path', required=True) - - return parser - - def take_action(self, parsed_args): - self.manager = WorkspaceManager(parsed_args.workspace_path) - self.manager.move_workspace(parsed_args.name, parsed_args.path) - sys.exit(0) - - -class TempestWorkspaceRemove(command.Command): - def get_description(self): - return 'Deletes the entry for a given tempest workspace --name' - - def get_parser(self, prog_name): - parser = super(TempestWorkspaceRemove, self).get_parser(prog_name) - add_global_arguments(parser) - parser.add_argument('--name', required=True) - parser.add_argument('--rmdir', action='store_true', - help='Deletes the given workspace directory') - - return parser - - def take_action(self, parsed_args): - self.manager = WorkspaceManager(parsed_args.workspace_path) - workspace_path = self.manager.remove_workspace_entry(parsed_args.name) - if parsed_args.rmdir: - self.manager.remove_workspace_directory(workspace_path) - sys.exit(0) - - -class TempestWorkspaceList(lister.Lister): - def get_description(self): - return 'Outputs the name and path of all known tempest workspaces' - - def get_parser(self, prog_name): - parser = super(TempestWorkspaceList, self).get_parser(prog_name) - add_global_arguments(parser) - return parser - - def take_action(self, parsed_args): - self.manager = WorkspaceManager(parsed_args.workspace_path) - return (("Name", "Path"), - ((n, p) for n, p in self.manager.list_workspaces().items())) diff --git a/tempest/common/__init__.py b/tempest/common/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/common/compute.py b/tempest/common/compute.py deleted file mode 100644 index e3fbfb8b3..000000000 --- a/tempest/common/compute.py +++ /dev/null @@ -1,363 +0,0 @@ -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# 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 base64 -import socket -import ssl -import struct -import textwrap - -import six -from six.moves.urllib import parse as urlparse - -from oslo_log import log as logging -from oslo_utils import excutils - -from tempest.common import waiters -from tempest import config -from tempest.lib.common import fixed_network -from tempest.lib.common import rest_client -from tempest.lib.common.utils import data_utils - -if six.PY2: - ord_func = ord -else: - ord_func = int - -CONF = config.CONF - -LOG = logging.getLogger(__name__) - - -def create_test_server(clients, validatable=False, validation_resources=None, - tenant_network=None, wait_until=None, - volume_backed=False, name=None, flavor=None, - image_id=None, **kwargs): - """Common wrapper utility returning a test server. - - This method is a common wrapper returning a test server that can be - pingable or sshable. - - :param clients: Client manager which provides OpenStack Tempest clients. - :param validatable: Whether the server will be pingable or sshable. - :param validation_resources: Resources created for the connection to the - server. Include a keypair, a security group and an IP. - :param tenant_network: Tenant network to be used for creating a server. - :param wait_until: Server status to wait for the server to reach after - its creation. - :param volume_backed: Whether the server is volume backed or not. - If this is true, a volume will be created and - create server will be requested with - 'block_device_mapping_v2' populated with below - values: - -------------------------------------------- - bd_map_v2 = [{ - 'uuid': volume['volume']['id'], - 'source_type': 'volume', - 'destination_type': 'volume', - 'boot_index': 0, - 'delete_on_termination': True}] - kwargs['block_device_mapping_v2'] = bd_map_v2 - --------------------------------------------- - If server needs to be booted from volume with other - combination of bdm inputs than mentioned above, then - pass the bdm inputs explicitly as kwargs and image_id - as empty string (''). - :param name: Name of the server to be provisioned. If not defined a random - string ending with '-instance' will be generated. - :param flavor: Flavor of the server to be provisioned. If not defined, - CONF.compute.flavor_ref will be used instead. - :param image_id: ID of the image to be used to provision the server. If not - defined, CONF.compute.image_ref will be used instead. - :returns: a tuple - """ - - # TODO(jlanoux) add support of wait_until PINGABLE/SSHABLE - - if name is None: - name = data_utils.rand_name(__name__ + "-instance") - if flavor is None: - flavor = CONF.compute.flavor_ref - if image_id is None: - image_id = CONF.compute.image_ref - - kwargs = fixed_network.set_networks_kwarg( - tenant_network, kwargs) or {} - - multiple_create_request = (max(kwargs.get('min_count', 0), - kwargs.get('max_count', 0)) > 1) - - if CONF.validation.run_validation and validatable: - # As a first implementation, multiple pingable or sshable servers will - # not be supported - if multiple_create_request: - msg = ("Multiple pingable or sshable servers not supported at " - "this stage.") - raise ValueError(msg) - - if 'security_groups' in kwargs: - kwargs['security_groups'].append( - {'name': validation_resources['security_group']['name']}) - else: - try: - kwargs['security_groups'] = [ - {'name': validation_resources['security_group']['name']}] - except KeyError: - LOG.debug("No security group provided.") - - if 'key_name' not in kwargs: - try: - kwargs['key_name'] = validation_resources['keypair']['name'] - except KeyError: - LOG.debug("No key provided.") - - if CONF.validation.connect_method == 'floating': - if wait_until is None: - wait_until = 'ACTIVE' - - if 'user_data' not in kwargs: - # If nothing overrides the default user data script then run - # a simple script on the host to print networking info. This is - # to aid in debugging ssh failures. - script = ''' - #!/bin/sh - echo "Printing {user} user authorized keys" - cat ~{user}/.ssh/authorized_keys || true - '''.format(user=CONF.validation.image_ssh_user) - script_clean = textwrap.dedent(script).lstrip().encode('utf8') - script_b64 = base64.b64encode(script_clean) - kwargs['user_data'] = script_b64 - - if volume_backed: - volume_name = data_utils.rand_name(__name__ + '-volume') - volumes_client = clients.volumes_v2_client - params = {'name': volume_name, - 'imageRef': image_id, - 'size': CONF.volume.volume_size} - volume = volumes_client.create_volume(**params) - waiters.wait_for_volume_resource_status(volumes_client, - volume['volume']['id'], - 'available') - - bd_map_v2 = [{ - 'uuid': volume['volume']['id'], - 'source_type': 'volume', - 'destination_type': 'volume', - 'boot_index': 0, - 'delete_on_termination': True}] - kwargs['block_device_mapping_v2'] = bd_map_v2 - - # Since this is boot from volume an image does not need - # to be specified. - image_id = '' - - body = clients.servers_client.create_server(name=name, imageRef=image_id, - flavorRef=flavor, - **kwargs) - - # handle the case of multiple servers - if multiple_create_request: - # Get servers created which name match with name param. - body_servers = clients.servers_client.list_servers() - servers = \ - [s for s in body_servers['servers'] if s['name'].startswith(name)] - else: - body = rest_client.ResponseBody(body.response, body['server']) - servers = [body] - - # The name of the method to associate a floating IP to as server is too - # long for PEP8 compliance so: - assoc = clients.compute_floating_ips_client.associate_floating_ip_to_server - - if wait_until: - for server in servers: - try: - waiters.wait_for_server_status( - clients.servers_client, server['id'], wait_until) - - # Multiple validatable servers are not supported for now. Their - # creation will fail with the condition above (l.58). - if CONF.validation.run_validation and validatable: - if CONF.validation.connect_method == 'floating': - assoc(floating_ip=validation_resources[ - 'floating_ip']['ip'], - server_id=servers[0]['id']) - - except Exception: - with excutils.save_and_reraise_exception(): - for server in servers: - try: - clients.servers_client.delete_server( - server['id']) - except Exception: - LOG.exception('Deleting server %s failed', - server['id']) - for server in servers: - # NOTE(artom) If the servers were booted with volumes - # and with delete_on_termination=False we need to wait - # for the servers to go away before proceeding with - # cleanup, otherwise we'll attempt to delete the - # volumes while they're still attached to servers that - # are in the process of being deleted. - try: - waiters.wait_for_server_termination( - clients.servers_client, server['id']) - except Exception: - LOG.exception('Server %s failed to delete in time', - server['id']) - - return body, servers - - -def shelve_server(servers_client, server_id, force_shelve_offload=False): - """Common wrapper utility to shelve server. - - This method is a common wrapper to make server in 'SHELVED' - or 'SHELVED_OFFLOADED' state. - - :param servers_clients: Compute servers client instance. - :param server_id: Server to make in shelve state - :param force_shelve_offload: Forcefully offload shelve server if it - is configured not to offload server - automatically after offload time. - """ - servers_client.shelve_server(server_id) - - offload_time = CONF.compute.shelved_offload_time - if offload_time >= 0: - waiters.wait_for_server_status(servers_client, server_id, - 'SHELVED_OFFLOADED', - extra_timeout=offload_time) - else: - waiters.wait_for_server_status(servers_client, server_id, 'SHELVED') - if force_shelve_offload: - servers_client.shelve_offload_server(server_id) - waiters.wait_for_server_status(servers_client, server_id, - 'SHELVED_OFFLOADED') - - -def create_websocket(url): - url = urlparse.urlparse(url) - if url.scheme == 'https': - client_socket = ssl.wrap_socket(socket.socket(socket.AF_INET, - socket.SOCK_STREAM)) - else: - client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - client_socket.connect((url.hostname, url.port)) - # Turn the Socket into a WebSocket to do the communication - return _WebSocket(client_socket, url) - - -class _WebSocket(object): - def __init__(self, client_socket, url): - """Contructor for the WebSocket wrapper to the socket.""" - self._socket = client_socket - # cached stream for early frames. - self.cached_stream = b'' - # Upgrade the HTTP connection to a WebSocket - self._upgrade(url) - - def _recv(self, recv_size): - """Wrapper to receive data from the cached stream or socket.""" - if recv_size <= 0: - return None - - data_from_cached = b'' - data_from_socket = b'' - if len(self.cached_stream) > 0: - read_from_cached = min(len(self.cached_stream), recv_size) - data_from_cached += self.cached_stream[:read_from_cached] - self.cached_stream = self.cached_stream[read_from_cached:] - recv_size -= read_from_cached - if recv_size > 0: - data_from_socket = self._socket.recv(recv_size) - return data_from_cached + data_from_socket - - def receive_frame(self): - """Wrapper for receiving data to parse the WebSocket frame format""" - # We need to loop until we either get some bytes back in the frame - # or no data was received (meaning the socket was closed). This is - # done to handle the case where we get back some empty frames - while True: - header = self._recv(2) - # If we didn't receive any data, just return None - if not header: - return None - # We will make the assumption that we are only dealing with - # frames less than 125 bytes here (for the negotiation) and - # that only the 2nd byte contains the length, and since the - # server doesn't do masking, we can just read the data length - if ord_func(header[1]) & 127 > 0: - return self._recv(ord_func(header[1]) & 127) - - def send_frame(self, data): - """Wrapper for sending data to add in the WebSocket frame format.""" - frame_bytes = list() - # For the first byte, want to say we are sending binary data (130) - frame_bytes.append(130) - # Only sending negotiation data so don't need to worry about > 125 - # We do need to add the bit that says we are masking the data - frame_bytes.append(len(data) | 128) - # We don't really care about providing a random mask for security - # So we will just hard-code a value since a test program - mask = [7, 2, 1, 9] - for i in range(len(mask)): - frame_bytes.append(mask[i]) - # Mask each of the actual data bytes that we are going to send - for i in range(len(data)): - frame_bytes.append(ord_func(data[i]) ^ mask[i % 4]) - # Convert our integer list to a binary array of bytes - frame_bytes = struct.pack('!%iB' % len(frame_bytes), * frame_bytes) - self._socket.sendall(frame_bytes) - - def close(self): - """Helper method to close the connection.""" - # Close down the real socket connection and exit the test program - if self._socket is not None: - self._socket.shutdown(1) - self._socket.close() - self._socket = None - - def _upgrade(self, url): - """Upgrade the HTTP connection to a WebSocket and verify.""" - # The real request goes to the /websockify URI always - reqdata = 'GET /websockify HTTP/1.1\r\n' - reqdata += 'Host: %s:%s\r\n' % (url.hostname, url.port) - # Tell the HTTP Server to Upgrade the connection to a WebSocket - reqdata += 'Upgrade: websocket\r\nConnection: Upgrade\r\n' - # The token=xxx is sent as a Cookie not in the URI - reqdata += 'Cookie: %s\r\n' % url.query - # Use a hard-coded WebSocket key since a test program - reqdata += 'Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n' - reqdata += 'Sec-WebSocket-Version: 13\r\n' - # We are choosing to use binary even though browser may do Base64 - reqdata += 'Sec-WebSocket-Protocol: binary\r\n\r\n' - # Send the HTTP GET request and get the response back - self._socket.sendall(reqdata.encode('utf8')) - self.response = data = self._socket.recv(4096) - # Loop through & concatenate all of the data in the response body - end_loc = self.response.find(b'\r\n\r\n') - while data and end_loc < 0: - data = self._socket.recv(4096) - self.response += data - end_loc = self.response.find(b'\r\n\r\n') - - if len(self.response) > end_loc + 4: - # In case some frames (e.g. the first RFP negotiation) have - # arrived, cache it for next reading. - self.cached_stream = self.response[end_loc + 4:] - # ensure response ends with '\r\n\r\n'. - self.response = self.response[:end_loc + 4] diff --git a/tempest/common/credentials_factory.py b/tempest/common/credentials_factory.py deleted file mode 100644 index fd875be2d..000000000 --- a/tempest/common/credentials_factory.py +++ /dev/null @@ -1,314 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# 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 oslo_concurrency import lockutils - -from tempest import clients -from tempest import config -from tempest.lib import auth -from tempest.lib.common import dynamic_creds -from tempest.lib.common import preprov_creds -from tempest.lib import exceptions - -CONF = config.CONF - - -"""This module provides factories of credential and credential providers - -Credentials providers and clients are (going to be) part of tempest.lib, -and so they may not hold any dependency to tempest configuration. - -Methods in this module collect the relevant configuration details and pass -them to credentials providers and clients, so that test can have easy -access to these features. - -Client managers with hard-coded configured credentials are also moved here, -to avoid circular dependencies.""" - -# === Credential Providers - - -# Subset of the parameters of credential providers that depend on configuration -def _get_common_provider_params(identity_version): - if identity_version == 'v3': - identity_uri = CONF.identity.uri_v3 - elif identity_version == 'v2': - identity_uri = CONF.identity.uri - return { - 'identity_version': identity_version, - 'identity_uri': identity_uri, - 'credentials_domain': CONF.auth.default_credentials_domain_name, - 'admin_role': CONF.identity.admin_role - } - - -def get_dynamic_provider_params(identity_version, admin_creds=None): - """Dynamic provider parameters setup from config - - This helper returns a dict of parameter that can be used to initialise - a `DynamicCredentialProvider` according to tempest configuration. - Parameters that are not configuration specific (name, network_resources) - are not returned. - - :param identity_version: 'v2' or 'v3' - :param admin_creds: An object of type `auth.Credentials`. If None, it - is built from the configuration file as well. - :returns A dict with the parameters - """ - _common_params = _get_common_provider_params(identity_version) - admin_creds = admin_creds or get_configured_admin_credentials( - fill_in=True, identity_version=identity_version) - if identity_version == 'v3': - endpoint_type = CONF.identity.v3_endpoint_type - elif identity_version == 'v2': - endpoint_type = CONF.identity.v2_admin_endpoint_type - return dict(_common_params, **dict([ - ('admin_creds', admin_creds), - ('identity_admin_domain_scope', CONF.identity.admin_domain_scope), - ('identity_admin_role', CONF.identity.admin_role), - ('extra_roles', CONF.auth.tempest_roles), - ('neutron_available', CONF.service_available.neutron), - ('project_network_cidr', CONF.network.project_network_cidr), - ('project_network_mask_bits', CONF.network.project_network_mask_bits), - ('public_network_id', CONF.network.public_network_id), - ('create_networks', (CONF.auth.create_isolated_networks and not - CONF.network.shared_physical_network)), - ('resource_prefix', CONF.resources_prefix), - ('identity_admin_endpoint_type', endpoint_type) - ])) - - -def get_preprov_provider_params(identity_version): - """Pre-provisioned provider parameters setup from config - - This helper returns a dict of parameter that can be used to initialise - a `PreProvisionedCredentialProvider` according to tempest configuration. - Parameters that are not configuration specific (name) are not returned. - - :param identity_version: 'v2' or 'v3' - :returns A dict with the parameters - """ - _common_params = _get_common_provider_params(identity_version) - reseller_admin_role = CONF.object_storage.reseller_admin_role - return dict(_common_params, **dict([ - ('accounts_lock_dir', lockutils.get_lock_path(CONF)), - ('test_accounts_file', CONF.auth.test_accounts_file), - ('object_storage_operator_role', CONF.object_storage.operator_role), - ('object_storage_reseller_admin_role', reseller_admin_role) - ])) - - -def get_credentials_provider(name, network_resources=None, - force_tenant_isolation=False, - identity_version=None): - """Return the right implementation of CredentialProvider based on config - - This helper returns the right implementation of CredentialProvider based on - config and on the value of force_tenant_isolation. - - :param name: When provided, it makes it possible to associate credential - artifacts back to the owner (test class). - :param network_resources: Dictionary of network resources to be allocated - for each test account. Only valid for the dynamic - credentials provider. - :param force_tenant_isolation: Always return a `DynamicCredentialProvider`, - regardless of the configuration. - :param identity_version: Use the specified identity API version, regardless - of the configuration. Valid values are 'v2', 'v3'. - """ - # If a test requires a new account to work, it can have it via forcing - # dynamic credentials. A new account will be produced only for that test. - # In case admin credentials are not available for the account creation, - # the test should be skipped else it would fail. - identity_version = identity_version or CONF.identity.auth_version - if CONF.auth.use_dynamic_credentials or force_tenant_isolation: - return dynamic_creds.DynamicCredentialProvider( - name=name, - network_resources=network_resources, - **get_dynamic_provider_params(identity_version)) - else: - if CONF.auth.test_accounts_file: - # Most params are not relevant for pre-created accounts - return preprov_creds.PreProvisionedCredentialProvider( - name=name, - **get_preprov_provider_params(identity_version)) - else: - raise exceptions.InvalidConfiguration( - 'A valid credential provider is needed') - - -def is_admin_available(identity_version): - """Helper to check for admin credentials - - Helper function to check if a set of admin credentials is available so we - can do a single call from skip_checks. - This helper depends on identity_version as there may be admin credentials - available for v2 but not for v3. - - :param identity_version: 'v2' or 'v3' - """ - is_admin = True - # If dynamic credentials is enabled admin will be available - if CONF.auth.use_dynamic_credentials: - return is_admin - # Check whether test accounts file has the admin specified or not - elif CONF.auth.test_accounts_file: - check_accounts = preprov_creds.PreProvisionedCredentialProvider( - name='check_admin', - **get_preprov_provider_params(identity_version)) - if not check_accounts.admin_available(): - is_admin = False - else: - try: - get_configured_admin_credentials(fill_in=False, - identity_version=identity_version) - except exceptions.InvalidConfiguration: - is_admin = False - return is_admin - - -def is_alt_available(identity_version): - """Helper to check for alt credentials - - Helper function to check if a second set of credentials is available (aka - alt credentials) so we can do a single call from skip_checks. - This helper depends on identity_version as there may be alt credentials - available for v2 but not for v3. - - :param identity_version: 'v2' or 'v3' - """ - # If dynamic credentials is enabled alt will be available - if CONF.auth.use_dynamic_credentials: - return True - # Check whether test accounts file has the admin specified or not - if CONF.auth.test_accounts_file: - check_accounts = preprov_creds.PreProvisionedCredentialProvider( - name='check_alt', - **get_preprov_provider_params(identity_version)) - else: - raise exceptions.InvalidConfiguration( - 'A valid credential provider is needed') - - try: - if not check_accounts.is_multi_user(): - return False - else: - return True - except exceptions.InvalidConfiguration: - return False - -# === Credentials - -# Type of credentials available from configuration -CREDENTIAL_TYPES = { - 'identity_admin': ('auth', 'admin'), - 'user': ('identity', None), - 'alt_user': ('identity', 'alt') -} - -DEFAULT_PARAMS = { - 'disable_ssl_certificate_validation': - CONF.identity.disable_ssl_certificate_validation, - 'ca_certs': CONF.identity.ca_certificates_file, - 'trace_requests': CONF.debug.trace_requests -} - - -def get_configured_admin_credentials(fill_in=True, identity_version=None): - """Get admin credentials from the config file - - Read credentials from configuration, builds a Credentials object based on - the specified or configured version - - :param fill_in: If True, a request to the Token API is submitted, and the - credential object is filled in with all names and IDs from - the token API response. - :param identity_version: The identity version to talk to and the type of - credentials object to be created. 'v2' or 'v3'. - :returns: An object of a sub-type of `auth.Credentials` - """ - identity_version = identity_version or CONF.identity.auth_version - - if identity_version not in ('v2', 'v3'): - raise exceptions.InvalidConfiguration( - 'Unsupported auth version: %s' % identity_version) - - conf_attributes = ['username', 'password', - 'project_name'] - - if identity_version == 'v3': - conf_attributes.append('domain_name') - # Read the parts of credentials from config - params = DEFAULT_PARAMS.copy() - for attr in conf_attributes: - params[attr] = getattr(CONF.auth, 'admin_' + attr) - # Build and validate credentials. We are reading configured credentials, - # so validate them even if fill_in is False - credentials = get_credentials(fill_in=fill_in, - identity_version=identity_version, **params) - if not fill_in: - if not credentials.is_valid(): - msg = ("The admin credentials are incorrectly set in the config " - "file for identity version %s. Double check that all " - "required values are assigned.") - raise exceptions.InvalidConfiguration(msg % identity_version) - return credentials - - -# Wrapper around auth.get_credentials to use the configured identity version -# if none is specified -def get_credentials(fill_in=True, identity_version=None, **kwargs): - """Get credentials from dict based on config - - Wrapper around auth.get_credentials to use the configured identity version - if none is specified. - - :param fill_in: If True, a request to the Token API is submitted, and the - credential object is filled in with all names and IDs from - the token API response. - :param identity_version: The identity version to talk to and the type of - credentials object to be created. 'v2' or 'v3'. - :param kwargs: Attributes to be used to build the Credentials object. - :returns: An object of a sub-type of `auth.Credentials` - """ - params = dict(DEFAULT_PARAMS, **kwargs) - identity_version = identity_version or CONF.identity.auth_version - # In case of "v3" add the domain from config if not specified - # To honour the "default_credentials_domain_name", if not domain - # field is specified at all, add it the credential dict. - if identity_version == 'v3': - domain_fields = set(x for x in auth.KeystoneV3Credentials.ATTRIBUTES - if 'domain' in x) - if not domain_fields.intersection(kwargs.keys()): - domain_name = CONF.auth.default_credentials_domain_name - # NOTE(andreaf) Setting domain_name implicitly sets user and - # project domain names, if they are None - params['domain_name'] = domain_name - - auth_url = CONF.identity.uri_v3 - else: - auth_url = CONF.identity.uri - return auth.get_credentials(auth_url, - fill_in=fill_in, - identity_version=identity_version, - **params) - -# === Credential / client managers - - -class AdminManager(clients.Manager): - """Manager that uses admin credentials for its managed client objects""" - - def __init__(self): - super(AdminManager, self).__init__( - credentials=get_configured_admin_credentials()) diff --git a/tempest/common/custom_matchers.py b/tempest/common/custom_matchers.py deleted file mode 100644 index ed11b21ef..000000000 --- a/tempest/common/custom_matchers.py +++ /dev/null @@ -1,319 +0,0 @@ -# Copyright 2013 NTT Corporation -# -# 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 re - -from testtools import helpers - - -class ExistsAllResponseHeaders(object): - """Specific matcher to check the existence of Swift's response headers - - This matcher checks the existence of common headers for each HTTP method - or the target, which means account, container or object. - When checking the existence of 'specific' headers such as - X-Account-Meta-* or X-Object-Manifest for example, those headers must be - checked in each test code. - """ - - def __init__(self, target, method, policies=None): - """Initialization of ExistsAllResponseHeaders - - param: target Account/Container/Object - param: method PUT/GET/HEAD/DELETE/COPY/POST - """ - self.target = target - self.method = method - self.policies = policies or [] - - def _content_length_required(self, resp): - # Verify whether given HTTP response must contain content-length. - # Take into account the exceptions defined in RFC 7230. - if resp.status in range(100, 200) or resp.status == 204: - return False - - return True - - def match(self, actual): - """Check headers - - param: actual HTTP response object containing headers and status - """ - # Check common headers for all HTTP methods. - # - # Please note that for 1xx and 204 responses Content-Length presence - # is not checked intensionally. According to RFC 7230 a server MUST - # NOT send the header in such responses. Thus, clients should not - # depend on this header. However, the standard does not require them - # to validate the server's behavior. We leverage that to not refuse - # any implementation violating it like Swift [1] or some versions of - # Ceph RadosGW [2]. - # [1] https://bugs.launchpad.net/swift/+bug/1537811 - # [2] http://tracker.ceph.com/issues/13582 - if ('content-length' not in actual and - self._content_length_required(actual)): - return NonExistentHeader('content-length') - if 'content-type' not in actual: - return NonExistentHeader('content-type') - if 'x-trans-id' not in actual: - return NonExistentHeader('x-trans-id') - if 'date' not in actual: - return NonExistentHeader('date') - - # Check headers for a specific method or target - if self.method == 'GET' or self.method == 'HEAD': - if 'x-timestamp' not in actual: - return NonExistentHeader('x-timestamp') - if 'accept-ranges' not in actual: - return NonExistentHeader('accept-ranges') - if self.target == 'Account': - if 'x-account-bytes-used' not in actual: - return NonExistentHeader('x-account-bytes-used') - if 'x-account-container-count' not in actual: - return NonExistentHeader('x-account-container-count') - if 'x-account-object-count' not in actual: - return NonExistentHeader('x-account-object-count') - if int(actual['x-account-container-count']) > 0: - acct_header = "x-account-storage-policy-" - matched_policy_count = 0 - - # Loop through the policies and look for account - # usage data. There should be at least 1 set - for policy in self.policies: - front_header = acct_header + policy['name'].lower() - - usage_policies = [ - front_header + '-bytes-used', - front_header + '-object-count', - front_header + '-container-count' - ] - - # There should be 3 usage values for a give storage - # policy in an account bytes, object count, and - # container count - policy_hdrs = sum(1 for use_hdr in usage_policies - if use_hdr in actual) - - # If there are less than 3 headers here then 1 is - # missing, let's figure out which one and report - if policy_hdrs == 3: - matched_policy_count = matched_policy_count + 1 - else: - if policy_hdrs > 0 and policy_hdrs < 3: - for use_hdr in usage_policies: - if use_hdr not in actual: - return NonExistentHeader(use_hdr) - - # Only flag an error if actual policies have been read and - # no usage has been found - if self.policies and matched_policy_count == 0: - return GenericError("No storage policy usage headers") - - elif self.target == 'Container': - if 'x-container-bytes-used' not in actual: - return NonExistentHeader('x-container-bytes-used') - if 'x-container-object-count' not in actual: - return NonExistentHeader('x-container-object-count') - if 'x-storage-policy' not in actual: - return NonExistentHeader('x-storage-policy') - else: - policy_name = actual['x-storage-policy'] - - # loop through the policies and ensure that - # the value in the container header matches - # one of the storage policies - for policy in self.policies: - if policy['name'] == policy_name: - break - else: - # Ensure that there are actual policies stored - if self.policies: - return InvalidHeaderValue('x-storage-policy', - policy_name) - elif self.target == 'Object': - if 'etag' not in actual: - return NonExistentHeader('etag') - if 'last-modified' not in actual: - return NonExistentHeader('last-modified') - elif self.method == 'PUT': - if self.target == 'Object': - if 'etag' not in actual: - return NonExistentHeader('etag') - if 'last-modified' not in actual: - return NonExistentHeader('last-modified') - elif self.method == 'COPY': - if self.target == 'Object': - if 'etag' not in actual: - return NonExistentHeader('etag') - if 'last-modified' not in actual: - return NonExistentHeader('last-modified') - if 'x-copied-from' not in actual: - return NonExistentHeader('x-copied-from') - if 'x-copied-from-last-modified' not in actual: - return NonExistentHeader('x-copied-from-last-modified') - - return None - - -class GenericError(object): - """Informs an error message of a generic error during header evaluation""" - - def __init__(self, body): - self.body = body - - def describe(self): - return "%s" % self.body - - def get_details(self): - return {} - - -class NonExistentHeader(object): - """Informs an error message in the case of missing a certain header""" - - def __init__(self, header): - self.header = header - - def describe(self): - return "%s header does not exist" % self.header - - def get_details(self): - return {} - - -class InvalidHeaderValue(object): - """Informs an error message when a header contains a bad value""" - - def __init__(self, header, value): - self.header = header - self.value = value - - def describe(self): - return "InvalidValue (%s, %s)" % (self.header, self.value) - - def get_details(self): - return {} - - -class AreAllWellFormatted(object): - """Specific matcher to check the correctness of formats of values - - This matcher checks the format of values of response headers. - When checking the format of values of 'specific' headers such as - X-Account-Meta-* or X-Object-Manifest for example, those values must be - checked in each test code. - """ - - def match(self, actual): - for key, value in actual.items(): - if key in ('content-length', 'x-account-bytes-used', - 'x-account-container-count', 'x-account-object-count', - 'x-container-bytes-used', 'x-container-object-count')\ - and not value.isdigit(): - return InvalidFormat(key, value) - elif key in ('content-type', 'date', 'last-modified', - 'x-copied-from-last-modified') and not value: - return InvalidFormat(key, value) - elif key == 'x-timestamp' and not re.match("^\d+\.?\d*\Z", value): - return InvalidFormat(key, value) - elif key == 'x-copied-from' and not re.match("\S+/\S+", value): - return InvalidFormat(key, value) - elif key == 'x-trans-id' and \ - not re.match("^tx[0-9a-f]{21}-[0-9a-f]{10}.*", value): - return InvalidFormat(key, value) - elif key == 'accept-ranges' and not value == 'bytes': - return InvalidFormat(key, value) - elif key == 'etag' and not value.isalnum(): - return InvalidFormat(key, value) - elif key == 'transfer-encoding' and not value == 'chunked': - return InvalidFormat(key, value) - - return None - - -class InvalidFormat(object): - """Informs an error message if a format of a certain header is invalid""" - - def __init__(self, key, value): - self.key = key - self.value = value - - def describe(self): - return "InvalidFormat (%s, %s)" % (self.key, self.value) - - def get_details(self): - return {} - - -class MatchesDictExceptForKeys(object): - """Matches two dictionaries. - - Verifies all items are equals except for those identified by a list of keys - """ - - def __init__(self, expected, excluded_keys=None): - self.expected = expected - self.excluded_keys = excluded_keys if excluded_keys is not None else [] - - def match(self, actual): - filtered_expected = helpers.dict_subtract(self.expected, - self.excluded_keys) - filtered_actual = helpers.dict_subtract(actual, - self.excluded_keys) - if filtered_actual != filtered_expected: - return DictMismatch(filtered_expected, filtered_actual) - - -class DictMismatch(object): - """Mismatch between two dicts describes deltas""" - - def __init__(self, expected, actual): - self.expected = expected - self.actual = actual - self.intersect = set(self.expected) & set(self.actual) - self.symmetric_diff = set(self.expected) ^ set(self.actual) - - def _format_dict(self, dict_to_format): - # Ensure the error string dict is printed in a set order - # NOTE(mtreinish): needed to ensure a deterministic error msg for - # testing. Otherwise the error message will be dependent on the - # dict ordering. - dict_string = "{" - for key in sorted(dict_to_format): - dict_string += "'%s': %s, " % (key, dict_to_format[key]) - dict_string = dict_string[:-2] + '}' - return dict_string - - def describe(self): - msg = "" - if self.symmetric_diff: - only_expected = helpers.dict_subtract(self.expected, self.actual) - only_actual = helpers.dict_subtract(self.actual, self.expected) - if only_expected: - msg += "Only in expected:\n %s\n" % self._format_dict( - only_expected) - if only_actual: - msg += "Only in actual:\n %s\n" % self._format_dict( - only_actual) - diff_set = set(o for o in self.intersect if - self.expected[o] != self.actual[o]) - if diff_set: - msg += "Differences:\n" - for o in diff_set: - msg += " %s: expected %s, actual %s\n" % ( - o, self.expected[o], self.actual[o]) - return msg - - def get_details(self): - return {} diff --git a/tempest/common/identity.py b/tempest/common/identity.py deleted file mode 100644 index 469defed3..000000000 --- a/tempest/common/identity.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2015 NEC Corporation -# 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 tempest.lib import exceptions as lib_exc - - -def get_tenant_by_name(client, tenant_name): - tenants = client.list_tenants()['tenants'] - for tenant in tenants: - if tenant['name'] == tenant_name: - return tenant - raise lib_exc.NotFound('No such tenant(%s) in %s' % (tenant_name, tenants)) - - -def get_user_by_username(client, tenant_id, username): - users = client.list_tenant_users(tenant_id)['users'] - for user in users: - if user['name'] == username: - return user - raise lib_exc.NotFound('No such user(%s) in %s' % (username, users)) diff --git a/tempest/common/image.py b/tempest/common/image.py deleted file mode 100644 index 3618f7e13..000000000 --- a/tempest/common/image.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2016 NEC Corporation -# 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 copy - - -def get_image_meta_from_headers(resp): - meta = {'properties': {}} - for key in resp.response: - value = resp.response[key] - if key.startswith('x-image-meta-property-'): - _key = key[22:] - meta['properties'][_key] = value - elif key.startswith('x-image-meta-'): - _key = key[13:] - meta[_key] = value - - for key in ['is_public', 'protected', 'deleted']: - if key in meta: - meta[key] = meta[key].strip().lower() in ('t', 'true', 'yes', '1') - - for key in ['size', 'min_ram', 'min_disk']: - if key in meta: - try: - meta[key] = int(meta[key]) - except ValueError: - pass - return meta - - -def image_meta_to_headers(**metadata): - headers = {} - fields_copy = copy.deepcopy(metadata) - - copy_from = fields_copy.pop('copy_from', None) - purge = fields_copy.pop('purge_props', None) - - if purge is not None: - headers['x-glance-registry-purge-props'] = purge - - if copy_from is not None: - headers['x-glance-api-copy-from'] = copy_from - - for key, value in fields_copy.pop('properties', {}).items(): - headers['x-image-meta-property-%s' % key] = str(value) - - for key, value in fields_copy.pop('api', {}).items(): - headers['x-glance-api-property-%s' % key] = str(value) - - for key, value in fields_copy.items(): - headers['x-image-meta-%s' % key] = str(value) - - return headers diff --git a/tempest/common/tempest_fixtures.py b/tempest/common/tempest_fixtures.py deleted file mode 100644 index d416857ae..000000000 --- a/tempest/common/tempest_fixtures.py +++ /dev/null @@ -1,21 +0,0 @@ -# Copyright 2013 IBM 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 oslo_concurrency.fixture import lockutils - - -class LockFixture(lockutils.LockFixture): - def __init__(self, name): - super(LockFixture, self).__init__(name, 'tempest-') diff --git a/tempest/common/utils/__init__.py b/tempest/common/utils/__init__.py deleted file mode 100644 index 84e31d0d4..000000000 --- a/tempest/common/utils/__init__.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# -# 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 functools import partial - -from tempest import config -from tempest.lib.common.utils import data_utils as lib_data_utils - -CONF = config.CONF - - -class DataUtils(object): - def __getattr__(self, attr): - - if attr == 'rand_name': - # NOTE(flwang): This is a proxy to generate a random name that - # includes a random number and a prefix if one is configured in - # CONF.resources_prefix - attr_obj = partial(lib_data_utils.rand_name, - prefix=CONF.resources_prefix) - else: - attr_obj = getattr(lib_data_utils, attr) - - self.__dict__[attr] = attr_obj - return attr_obj - -data_utils = DataUtils() diff --git a/tempest/common/utils/linux/__init__.py b/tempest/common/utils/linux/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py deleted file mode 100644 index 99a628eed..000000000 --- a/tempest/common/utils/linux/remote_client.py +++ /dev/null @@ -1,157 +0,0 @@ -# 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 re -import time - -from oslo_log import log as logging - -from tempest import config -from tempest.lib.common.utils.linux import remote_client -import tempest.lib.exceptions - -CONF = config.CONF - -LOG = logging.getLogger(__name__) - - -class RemoteClient(remote_client.RemoteClient): - - # TODO(oomichi): Make this class deprecated after migrating - # necessary methods to tempest.lib and cleaning - # unnecessary methods up from this class. - def __init__(self, ip_address, username, password=None, pkey=None, - server=None, servers_client=None): - """Executes commands in a VM over ssh - - :param ip_address: IP address to ssh to - :param username: ssh username - :param password: ssh password (optional) - :param pkey: ssh public key (optional) - :param server: server dict, used for debugging purposes - :param servers_client: servers client, used for debugging purposes - """ - super(RemoteClient, self).__init__( - ip_address, username, password=password, pkey=pkey, - server=server, servers_client=servers_client, - ssh_timeout=CONF.validation.ssh_timeout, - connect_timeout=CONF.validation.connect_timeout, - console_output_enabled=CONF.compute_feature_enabled.console_output, - ssh_shell_prologue=CONF.validation.ssh_shell_prologue, - ping_count=CONF.validation.ping_count, - ping_size=CONF.validation.ping_size) - - # Note that this method will not work on SLES11 guests, as they do - # not support the TYPE column on lsblk - def get_disks(self): - # Select root disk devices as shown by lsblk - command = 'lsblk -lb --nodeps' - output = self.exec_command(command) - selected = [] - pos = None - for l in output.splitlines(): - if pos is None and l.find("TYPE") > 0: - pos = l.find("TYPE") - # Show header line too - selected.append(l) - # lsblk lists disk type in a column right-aligned with TYPE - elif pos is not None and pos > 0 and l[pos:pos + 4] == "disk": - selected.append(l) - - if selected: - return "\n".join(selected) - else: - msg = "'TYPE' column is requred but the output doesn't have it: " - raise tempest.lib.exceptions.TempestException(msg + output) - - def get_boot_time(self): - cmd = 'cut -f1 -d. /proc/uptime' - boot_secs = self.exec_command(cmd) - boot_time = time.time() - int(boot_secs) - return time.localtime(boot_time) - - def write_to_console(self, message): - message = re.sub("([$\\`])", "\\\\\\\\\\1", message) - # usually to /dev/ttyS0 - cmd = 'sudo sh -c "echo \\"%s\\" >/dev/console"' % message - return self.exec_command(cmd) - - def get_mac_address(self, nic=""): - show_nic = "show {nic} ".format(nic=nic) if nic else "" - cmd = "ip addr %s| awk '/ether/ {print $2}'" % show_nic - return self.exec_command(cmd).strip().lower() - - def get_nic_name_by_mac(self, address): - cmd = "ip -o link | awk '/%s/ {print $2}'" % address - nic = self.exec_command(cmd) - return nic.strip().strip(":").split('@')[0].lower() - - def get_nic_name_by_ip(self, address): - cmd = "ip -o addr | awk '/%s/ {print $2}'" % address - nic = self.exec_command(cmd) - return nic.strip().strip(":").split('@')[0].lower() - - def get_dns_servers(self): - cmd = 'cat /etc/resolv.conf' - resolve_file = self.exec_command(cmd).strip().split('\n') - entries = (l.split() for l in resolve_file) - dns_servers = [l[1] for l in entries - if len(l) and l[0] == 'nameserver'] - return dns_servers - - def _renew_lease_udhcpc(self, fixed_ip=None): - """Renews DHCP lease via udhcpc client. """ - file_path = '/var/run/udhcpc.' - nic_name = self.get_nic_name_by_ip(fixed_ip) - pid = self.exec_command('cat {path}{nic}.pid'. - format(path=file_path, nic=nic_name)) - pid = pid.strip() - cmd = 'sudo /bin/kill -{sig} {pid}'.format(pid=pid, sig='USR1') - self.exec_command(cmd) - - def _renew_lease_dhclient(self, fixed_ip=None): - """Renews DHCP lease via dhclient client. """ - cmd = "sudo /sbin/dhclient -r && sudo /sbin/dhclient" - self.exec_command(cmd) - - def renew_lease(self, fixed_ip=None, dhcp_client='udhcpc'): - """Wrapper method for renewing DHCP lease via given client - - Supporting: - * udhcpc - * dhclient - """ - # TODO(yfried): add support for dhcpcd - supported_clients = ['udhcpc', 'dhclient'] - if dhcp_client not in supported_clients: - raise tempest.lib.exceptions.InvalidConfiguration( - '%s DHCP client unsupported' % dhcp_client) - if dhcp_client == 'udhcpc' and not fixed_ip: - raise ValueError("need to set 'fixed_ip' for udhcpc client") - return getattr(self, '_renew_lease_' + dhcp_client)(fixed_ip=fixed_ip) - - def mount(self, dev_name, mount_path='/mnt'): - cmd_mount = 'sudo mount /dev/%s %s' % (dev_name, mount_path) - self.exec_command(cmd_mount) - - def umount(self, mount_path='/mnt'): - self.exec_command('sudo umount %s' % mount_path) - - def make_fs(self, dev_name, fs='ext4'): - cmd_mkfs = 'sudo /usr/sbin/mke2fs -t %s /dev/%s' % (fs, dev_name) - try: - self.exec_command(cmd_mkfs) - except tempest.lib.exceptions.SSHExecCommandFailed: - LOG.error("Couldn't mke2fs") - cmd_why = 'sudo ls -lR /dev' - LOG.info("Contents of /dev: %s", self.exec_command(cmd_why)) - raise diff --git a/tempest/common/utils/net_info.py b/tempest/common/utils/net_info.py deleted file mode 100644 index 9b0a08377..000000000 --- a/tempest/common/utils/net_info.py +++ /dev/null @@ -1,25 +0,0 @@ -# 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 re - -RE_OWNER = re.compile('^network:.*router_.*interface.*') - - -def _is_owner_router_interface(owner): - return bool(RE_OWNER.match(owner)) - - -def is_router_interface_port(port): - """Based on the port attributes determines is it a router interface.""" - return _is_owner_router_interface(port['device_owner']) diff --git a/tempest/common/utils/net_utils.py b/tempest/common/utils/net_utils.py deleted file mode 100644 index 867b3dd02..000000000 --- a/tempest/common/utils/net_utils.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2016 Hewlett Packard Enterprise Development Company -# -# 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 netaddr - -from tempest.lib import exceptions as lib_exc - - -def get_unused_ip_addresses(ports_client, subnets_client, - network_id, subnet_id, count): - - """Return a list with the specified number of unused IP addresses - - This method uses the given ports_client to find the specified number of - unused IP addresses on the given subnet using the supplied subnets_client - """ - - ports = ports_client.list_ports(network_id=network_id)['ports'] - subnet = subnets_client.show_subnet(subnet_id) - ip_net = netaddr.IPNetwork(subnet['subnet']['cidr']) - subnet_set = netaddr.IPSet(ip_net.iter_hosts()) - alloc_set = netaddr.IPSet() - - # prune out any addresses already allocated to existing ports - for port in ports: - for fixed_ip in port.get('fixed_ips'): - alloc_set.add(fixed_ip['ip_address']) - - # exclude gateway_ip of subnet - gateway_ip = subnet['subnet']['gateway_ip'] - if gateway_ip: - alloc_set.add(gateway_ip) - - av_set = subnet_set - alloc_set - addrs = [] - for cidr in reversed(av_set.iter_cidrs()): - for ip in reversed(cidr): - addrs.append(str(ip)) - if len(addrs) == count: - return addrs - msg = "Insufficient IP addresses available" - raise lib_exc.BadRequest(message=msg) - - -def get_ping_payload_size(mtu, ip_version): - """Return the maximum size of ping payload that will fit into MTU.""" - if not mtu: - return None - if ip_version == 4: - ip_header = 20 - icmp_header = 8 - else: - ip_header = 40 - icmp_header = 4 - res = mtu - ip_header - icmp_header - if res < 0: - raise lib_exc.BadRequest( - message='MTU = %(mtu)d is too low for IPv%(ip_version)d' % { - 'mtu': mtu, - 'ip_version': ip_version, - }) - return res diff --git a/tempest/common/validation_resources.py b/tempest/common/validation_resources.py deleted file mode 100644 index 9e83a073b..000000000 --- a/tempest/common/validation_resources.py +++ /dev/null @@ -1,154 +0,0 @@ -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# 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 oslo_log import log as logging - -from tempest import config - -from tempest.lib.common.utils import data_utils -from tempest.lib import exceptions as lib_exc - -CONF = config.CONF -LOG = logging.getLogger(__name__) - - -def _create_neutron_sec_group_rules(os, sec_group): - sec_group_rules_client = os.security_group_rules_client - ethertype = 'IPv4' - if CONF.validation.ip_version_for_ssh == 6: - ethertype = 'IPv6' - - sec_group_rules_client.create_security_group_rule( - security_group_id=sec_group['id'], - protocol='tcp', - ethertype=ethertype, - port_range_min=22, - port_range_max=22, - direction='ingress') - sec_group_rules_client.create_security_group_rule( - security_group_id=sec_group['id'], - protocol='icmp', - ethertype=ethertype, - direction='ingress') - - -def create_ssh_security_group(os, add_rule=False): - security_groups_client = os.compute_security_groups_client - security_group_rules_client = os.compute_security_group_rules_client - sg_name = data_utils.rand_name('securitygroup-') - sg_description = data_utils.rand_name('description-') - security_group = security_groups_client.create_security_group( - name=sg_name, description=sg_description)['security_group'] - if add_rule: - if CONF.service_available.neutron: - _create_neutron_sec_group_rules(os, security_group) - else: - security_group_rules_client.create_security_group_rule( - parent_group_id=security_group['id'], ip_protocol='tcp', - from_port=22, to_port=22) - security_group_rules_client.create_security_group_rule( - parent_group_id=security_group['id'], ip_protocol='icmp', - from_port=-1, to_port=-1) - LOG.debug("SSH Validation resource security group with tcp and icmp " - "rules %s created", sg_name) - return security_group - - -def create_validation_resources(os, validation_resources=None): - # Create and Return the validation resources required to validate a VM - validation_data = {} - if validation_resources: - if validation_resources['keypair']: - keypair_name = data_utils.rand_name('keypair') - validation_data.update(os.keypairs_client.create_keypair( - name=keypair_name)) - LOG.debug("Validation resource key %s created", keypair_name) - add_rule = False - if validation_resources['security_group']: - if validation_resources['security_group_rules']: - add_rule = True - validation_data['security_group'] = \ - create_ssh_security_group(os, add_rule) - if validation_resources['floating_ip']: - if CONF.service_available.neutron: - floatingip = os.floating_ips_client.create_floatingip( - floating_network_id=CONF.network.public_network_id) - # validation_resources['floating_ip'] has historically looked - # like a compute API POST /os-floating-ips response, so we need - # to mangle it a bit for a Neutron response with different - # fields. - validation_data['floating_ip'] = floatingip['floatingip'] - validation_data['floating_ip']['ip'] = ( - floatingip['floatingip']['floating_ip_address']) - else: - # NOTE(mriedem): The os-floating-ips compute API was deprecated - # in the 2.36 microversion. Any tests for CRUD operations on - # floating IPs using the compute API should be capped at 2.35. - validation_data.update( - os.compute_floating_ips_client.create_floating_ip( - pool=CONF.network.floating_network_name)) - return validation_data - - -def clear_validation_resources(os, validation_data=None): - # Cleanup the vm validation resources - has_exception = None - if validation_data: - if 'keypair' in validation_data: - keypair_client = os.keypairs_client - keypair_name = validation_data['keypair']['name'] - try: - keypair_client.delete_keypair(keypair_name) - except lib_exc.NotFound: - LOG.warning( - "Keypair %s is not found when attempting to delete", - keypair_name - ) - except Exception as exc: - LOG.exception('Exception raised while deleting key %s', - keypair_name) - if not has_exception: - has_exception = exc - if 'security_group' in validation_data: - security_group_client = os.compute_security_groups_client - sec_id = validation_data['security_group']['id'] - try: - security_group_client.delete_security_group(sec_id) - security_group_client.wait_for_resource_deletion(sec_id) - except lib_exc.NotFound: - LOG.warning("Security group %s is not found when attempting " - "to delete", sec_id) - except lib_exc.Conflict as exc: - LOG.exception('Conflict while deleting security ' - 'group %s VM might not be deleted', sec_id) - if not has_exception: - has_exception = exc - except Exception as exc: - LOG.exception('Exception raised while deleting security ' - 'group %s', sec_id) - if not has_exception: - has_exception = exc - if 'floating_ip' in validation_data: - floating_client = os.compute_floating_ips_client - fip_id = validation_data['floating_ip']['id'] - try: - floating_client.delete_floating_ip(fip_id) - except lib_exc.NotFound: - LOG.warning('Floating ip %s not found while attempting to ' - 'delete', fip_id) - except Exception as exc: - LOG.exception('Exception raised while deleting ip %s', fip_id) - if not has_exception: - has_exception = exc - if has_exception: - raise has_exception diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py deleted file mode 100644 index cf187e6bf..000000000 --- a/tempest/common/waiters.py +++ /dev/null @@ -1,288 +0,0 @@ -# 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 re -import time - -from oslo_log import log as logging - -from tempest.common import image as common_image -from tempest import config -from tempest import exceptions -from tempest.lib.common.utils import test_utils -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.image.v1 import images_client as images_v1_client - -CONF = config.CONF -LOG = logging.getLogger(__name__) - - -def _get_task_state(body): - return body.get('OS-EXT-STS:task_state', None) - - -# NOTE(afazekas): This function needs to know a token and a subject. -def wait_for_server_status(client, server_id, status, ready_wait=True, - extra_timeout=0, raise_on_error=True): - """Waits for a server to reach a given status.""" - - # NOTE(afazekas): UNKNOWN status possible on ERROR - # or in a very early stage. - body = client.show_server(server_id)['server'] - old_status = server_status = body['status'] - old_task_state = task_state = _get_task_state(body) - start_time = int(time.time()) - timeout = client.build_timeout + extra_timeout - while True: - # NOTE(afazekas): Now the BUILD status only reached - # between the UNKNOWN->ACTIVE transition. - # TODO(afazekas): enumerate and validate the stable status set - if status == 'BUILD' and server_status != 'UNKNOWN': - return - if server_status == status: - if ready_wait: - if status == 'BUILD': - return - # NOTE(afazekas): The instance is in "ready for action state" - # when no task in progress - if task_state is None: - # without state api extension 3 sec usually enough - time.sleep(CONF.compute.ready_wait) - return - else: - return - - time.sleep(client.build_interval) - body = client.show_server(server_id)['server'] - server_status = body['status'] - task_state = _get_task_state(body) - if (server_status != old_status) or (task_state != old_task_state): - LOG.info('State transition "%s" ==> "%s" after %d second wait', - '/'.join((old_status, str(old_task_state))), - '/'.join((server_status, str(task_state))), - time.time() - start_time) - if (server_status == 'ERROR') and raise_on_error: - if 'fault' in body: - raise exceptions.BuildErrorException(body['fault'], - server_id=server_id) - else: - raise exceptions.BuildErrorException(server_id=server_id) - - timed_out = int(time.time()) - start_time >= timeout - - if timed_out: - expected_task_state = 'None' if ready_wait else 'n/a' - message = ('Server %(server_id)s failed to reach %(status)s ' - 'status and task state "%(expected_task_state)s" ' - 'within the required time (%(timeout)s s).' % - {'server_id': server_id, - 'status': status, - 'expected_task_state': expected_task_state, - 'timeout': timeout}) - message += ' Current status: %s.' % server_status - message += ' Current task state: %s.' % task_state - caller = test_utils.find_test_caller() - if caller: - message = '(%s) %s' % (caller, message) - raise lib_exc.TimeoutException(message) - old_status = server_status - old_task_state = task_state - - -def wait_for_server_termination(client, server_id, ignore_error=False): - """Waits for server to reach termination.""" - try: - body = client.show_server(server_id)['server'] - except lib_exc.NotFound: - return - old_status = server_status = body['status'] - old_task_state = task_state = _get_task_state(body) - start_time = int(time.time()) - while True: - time.sleep(client.build_interval) - try: - body = client.show_server(server_id)['server'] - except lib_exc.NotFound: - return - server_status = body['status'] - task_state = _get_task_state(body) - if (server_status != old_status) or (task_state != old_task_state): - LOG.info('State transition "%s" ==> "%s" after %d second wait', - '/'.join((old_status, str(old_task_state))), - '/'.join((server_status, str(task_state))), - time.time() - start_time) - if server_status == 'ERROR' and not ignore_error: - raise lib_exc.DeleteErrorException(resource_id=server_id) - - if int(time.time()) - start_time >= client.build_timeout: - raise lib_exc.TimeoutException - old_status = server_status - old_task_state = task_state - - -def wait_for_image_status(client, image_id, status): - """Waits for an image to reach a given status. - - The client should have a show_image(image_id) method to get the image. - The client should also have build_interval and build_timeout attributes. - """ - if isinstance(client, images_v1_client.ImagesClient): - # The 'check_image' method is used here because the show_image method - # returns image details plus the image itself which is very expensive. - # The 'check_image' method returns just image details. - def _show_image_v1(image_id): - resp = client.check_image(image_id) - return common_image.get_image_meta_from_headers(resp) - - show_image = _show_image_v1 - else: - show_image = client.show_image - - current_status = 'An unknown status' - start = int(time.time()) - while int(time.time()) - start < client.build_timeout: - image = show_image(image_id) - # Compute image client returns response wrapped in 'image' element - # which is not the case with Glance image client. - if 'image' in image: - image = image['image'] - - current_status = image['status'] - if current_status == status: - return - if current_status.lower() == 'killed': - raise exceptions.ImageKilledException(image_id=image_id, - status=status) - if current_status.lower() == 'error': - raise exceptions.AddImageException(image_id=image_id) - - time.sleep(client.build_interval) - - message = ('Image %(image_id)s failed to reach %(status)s state ' - '(current state %(current_status)s) within the required ' - 'time (%(timeout)s s).' % {'image_id': image_id, - 'status': status, - 'current_status': current_status, - 'timeout': client.build_timeout}) - caller = test_utils.find_test_caller() - if caller: - message = '(%s) %s' % (caller, message) - raise lib_exc.TimeoutException(message) - - -def wait_for_volume_resource_status(client, resource_id, statuses): - """Waits for a volume resource to reach any of the specified statuses. - - This function is a common function for volume, snapshot and backup - resources. The function extracts the name of the desired resource from - the client class name of the resource. - """ - if not isinstance(statuses, list): - statuses = [statuses] - resource_name = re.findall(r'(Volume|Snapshot|Backup|Group)', - client.__class__.__name__)[0].lower() - show_resource = getattr(client, 'show_' + resource_name) - resource_status = show_resource(resource_id)[resource_name]['status'] - start = int(time.time()) - - while resource_status not in statuses: - time.sleep(client.build_interval) - resource_status = show_resource(resource_id)[ - '{}'.format(resource_name)]['status'] - if resource_status == 'error' and resource_status not in statuses: - raise exceptions.VolumeResourceBuildErrorException( - resource_name=resource_name, resource_id=resource_id) - if resource_name == 'volume' and resource_status == 'error_restoring': - raise exceptions.VolumeRestoreErrorException(volume_id=resource_id) - - if int(time.time()) - start >= client.build_timeout: - message = ('%s %s failed to reach %s status (current %s) ' - 'within the required time (%s s).' % - (resource_name, resource_id, statuses, resource_status, - client.build_timeout)) - raise lib_exc.TimeoutException(message) - - -def wait_for_volume_retype(client, volume_id, new_volume_type): - """Waits for a Volume to have a new volume type.""" - body = client.show_volume(volume_id)['volume'] - current_volume_type = body['volume_type'] - start = int(time.time()) - - while current_volume_type != new_volume_type: - time.sleep(client.build_interval) - body = client.show_volume(volume_id)['volume'] - current_volume_type = body['volume_type'] - - if int(time.time()) - start >= client.build_timeout: - message = ('Volume %s failed to reach %s volume type (current %s) ' - 'within the required time (%s s).' % - (volume_id, new_volume_type, current_volume_type, - client.build_timeout)) - raise lib_exc.TimeoutException(message) - - -def wait_for_qos_operations(client, qos_id, operation, args=None): - """Waits for a qos operations to be completed. - - NOTE : operation value is required for wait_for_qos_operations() - operation = 'qos-key' / 'disassociate' / 'disassociate-all' - args = keys[] when operation = 'qos-key' - args = volume-type-id disassociated when operation = 'disassociate' - args = None when operation = 'disassociate-all' - """ - start_time = int(time.time()) - while True: - if operation == 'qos-key-unset': - body = client.show_qos(qos_id)['qos_specs'] - if not any(key in body['specs'] for key in args): - return - elif operation == 'disassociate': - body = client.show_association_qos(qos_id)['qos_associations'] - if not any(args in body[i]['id'] for i in range(0, len(body))): - return - elif operation == 'disassociate-all': - body = client.show_association_qos(qos_id)['qos_associations'] - if not body: - return - else: - msg = (" operation value is either not defined or incorrect.") - raise lib_exc.UnprocessableEntity(msg) - - if int(time.time()) - start_time >= client.build_timeout: - raise lib_exc.TimeoutException - time.sleep(client.build_interval) - - -def wait_for_interface_status(client, server_id, port_id, status): - """Waits for an interface to reach a given status.""" - body = (client.show_interface(server_id, port_id) - ['interfaceAttachment']) - interface_status = body['port_state'] - start = int(time.time()) - - while(interface_status != status): - time.sleep(client.build_interval) - body = (client.show_interface(server_id, port_id) - ['interfaceAttachment']) - interface_status = body['port_state'] - - timed_out = int(time.time()) - start >= client.build_timeout - - if interface_status != status and timed_out: - message = ('Interface %s failed to reach %s status ' - '(current %s) within the required time (%s s).' % - (port_id, status, interface_status, - client.build_timeout)) - raise lib_exc.TimeoutException(message) - - return body diff --git a/tempest/config.py b/tempest/config.py deleted file mode 100644 index af9eefc0a..000000000 --- a/tempest/config.py +++ /dev/null @@ -1,1460 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 __future__ import print_function - -import functools -import os -import tempfile - -import debtcollector.removals -from oslo_concurrency import lockutils -from oslo_config import cfg -from oslo_log import log as logging -import testtools - -from tempest.lib import exceptions -from tempest.lib.services import clients -from tempest.test_discover import plugins - - -# TODO(marun) Replace use of oslo_config's global ConfigOpts -# (cfg.CONF) instance with a local instance (cfg.ConfigOpts()) once -# the cli tests move to the clients. The cli tests rely on oslo -# incubator modules that use the global cfg.CONF. -_CONF = cfg.CONF - - -def register_opt_group(conf, opt_group, options): - if opt_group: - conf.register_group(opt_group) - for opt in options: - conf.register_opt(opt, group=getattr(opt_group, 'name', None)) - - -auth_group = cfg.OptGroup(name='auth', - title="Options for authentication and credentials") - - -AuthGroup = [ - cfg.StrOpt('test_accounts_file', - help="Path to the yaml file that contains the list of " - "credentials to use for running tests. If used when " - "running in parallel you have to make sure sufficient " - "credentials are provided in the accounts file. For " - "example if no tests with roles are being run it requires " - "at least `2 * CONC` distinct accounts configured in " - " the `test_accounts_file`, with CONC == the " - "number of concurrent test processes."), - cfg.BoolOpt('use_dynamic_credentials', - default=True, - help="Allows test cases to create/destroy projects and " - "users. This option requires that OpenStack Identity " - "API admin credentials are known. If false, isolated " - "test cases and parallel execution, can still be " - "achieved configuring a list of test accounts", - deprecated_opts=[cfg.DeprecatedOpt('allow_tenant_isolation', - group='auth'), - cfg.DeprecatedOpt('allow_tenant_isolation', - group='compute'), - cfg.DeprecatedOpt('allow_tenant_isolation', - group='orchestration')]), - cfg.ListOpt('tempest_roles', - help="Roles to assign to all users created by tempest", - default=[]), - cfg.StrOpt('default_credentials_domain_name', - default='Default', - help="Default domain used when getting v3 credentials. " - "This is the name keystone uses for v2 compatibility.", - deprecated_opts=[cfg.DeprecatedOpt( - 'tenant_isolation_domain_name', - group='auth')]), - cfg.BoolOpt('create_isolated_networks', - default=True, - help="If use_dynamic_credentials is set to True and Neutron " - "is enabled Tempest will try to create a usable network, " - "subnet, and router when needed for each project it " - "creates. However in some neutron configurations, like " - "with VLAN provider networks, this doesn't work. So if " - "set to False the isolated networks will not be created"), - cfg.StrOpt('admin_username', - help="Username for an administrative user. This is needed for " - "authenticating requests made by project isolation to " - "create users and projects", - deprecated_group='identity'), - cfg.StrOpt('admin_project_name', - help="Project name to use for an administrative user. This is " - "needed for authenticating requests made by project " - "isolation to create users and projects", - deprecated_opts=[cfg.DeprecatedOpt('admin_tenant_name', - group='auth'), - cfg.DeprecatedOpt('admin_tenant_name', - group='identity')]), - cfg.StrOpt('admin_password', - help="Password to use for an administrative user. This is " - "needed for authenticating requests made by project " - "isolation to create users and projects", - secret=True, - deprecated_group='identity'), - cfg.StrOpt('admin_domain_name', - help="Admin domain name for authentication (Keystone V3)." - "The same domain applies to user and project", - deprecated_group='identity'), -] - -identity_group = cfg.OptGroup(name='identity', - title="Keystone Configuration Options") - -IdentityGroup = [ - cfg.StrOpt('catalog_type', - default='identity', - help="Catalog type of the Identity service."), - cfg.BoolOpt('disable_ssl_certificate_validation', - default=False, - help="Set to True if using self-signed SSL certificates."), - cfg.StrOpt('ca_certificates_file', - default=None, - help='Specify a CA bundle file to use in verifying a ' - 'TLS (https) server certificate.'), - cfg.StrOpt('uri', - help="Full URI of the OpenStack Identity API (Keystone), v2"), - cfg.StrOpt('uri_v3', - help='Full URI of the OpenStack Identity API (Keystone), v3'), - cfg.StrOpt('auth_version', - default='v3', - help="Identity API version to be used for authentication " - "for API tests."), - cfg.StrOpt('region', - default='RegionOne', - help="The identity region name to use. Also used as the other " - "services' region name unless they are set explicitly. " - "If no such region is found in the service catalog, the " - "first found one is used."), - cfg.StrOpt('v2_admin_endpoint_type', - default='adminURL', - choices=['public', 'admin', 'internal', - 'publicURL', 'adminURL', 'internalURL'], - help="The admin endpoint type to use for OpenStack Identity " - "(Keystone) API v2"), - cfg.StrOpt('v2_public_endpoint_type', - default='publicURL', - choices=['public', 'admin', 'internal', - 'publicURL', 'adminURL', 'internalURL'], - help="The public endpoint type to use for OpenStack Identity " - "(Keystone) API v2", - deprecated_opts=[cfg.DeprecatedOpt('endpoint_type', - group='identity')]), - cfg.StrOpt('v3_endpoint_type', - default='adminURL', - choices=['public', 'admin', 'internal', - 'publicURL', 'adminURL', 'internalURL'], - help="The endpoint type to use for OpenStack Identity " - "(Keystone) API v3. The default value adminURL is " - "deprecated and will be modified to publicURL in " - "the next release."), - cfg.StrOpt('admin_role', - default='admin', - help="Role required to administrate keystone."), - cfg.StrOpt('default_domain_id', - default='default', - help="ID of the default domain"), - cfg.BoolOpt('admin_domain_scope', - default=False, - help="Whether keystone identity v3 policy required " - "a domain scoped token to use admin APIs"), - # Security Compliance (PCI-DSS) - cfg.IntOpt('user_lockout_failure_attempts', - default=2, - help="The number of unsuccessful login attempts the user is " - "allowed before having the account locked."), - cfg.IntOpt('user_lockout_duration', - default=5, - help="The number of seconds a user account will remain " - "locked."), - cfg.IntOpt('user_unique_last_password_count', - default=2, - help="The number of passwords for a user that must be unique " - "before an old password can be reused."), -] - -service_clients_group = cfg.OptGroup(name='service-clients', - title="Service Clients Options") - -ServiceClientsGroup = [ - cfg.IntOpt('http_timeout', - default=60, - help='Timeout in seconds to wait for the http request to ' - 'return'), -] - -identity_feature_group = cfg.OptGroup(name='identity-feature-enabled', - title='Enabled Identity Features') - -IdentityFeatureGroup = [ - cfg.BoolOpt('trust', - default=True, - help='Does the identity service have delegation and ' - 'impersonation enabled'), - cfg.BoolOpt('api_v2', - default=True, - help='Is the v2 identity API enabled'), - cfg.BoolOpt('api_v2_admin', - default=True, - help="Is the v2 identity admin API available? This setting " - "only applies if api_v2 is set to True."), - cfg.BoolOpt('api_v3', - default=True, - help='Is the v3 identity API enabled'), - cfg.ListOpt('api_extensions', - default=['all'], - help="A list of enabled identity extensions with a special " - "entry all which indicates every extension is enabled. " - "Empty list indicates all extensions are disabled. " - "To get the list of extensions run: 'keystone discover'"), - # TODO(rodrigods): This is a feature flag for bug 1590578 which is fixed - # in Newton and Ocata. This option can be removed after Mitaka is end of - # life. - cfg.BoolOpt('forbid_global_implied_dsr', - default=False, - help='Does the environment forbid global roles implying ' - 'domain specific ones?', - deprecated_for_removal=True, - deprecated_reason="This feature flag was introduced to " - "support testing of old OpenStack versions, " - "which are not supported anymore"), - cfg.BoolOpt('security_compliance', - default=False, - help='Does the environment have the security compliance ' - 'settings enabled?') -] - -compute_group = cfg.OptGroup(name='compute', - title='Compute Service Options') - -ComputeGroup = [ - cfg.StrOpt('image_ref', - help="Valid primary image reference to be used in tests. " - "This is a required option"), - cfg.StrOpt('image_ref_alt', - help="Valid secondary image reference to be used in tests. " - "This is a required option, but if only one image is " - "available duplicate the value of image_ref above"), - cfg.StrOpt('flavor_ref', - default="1", - help="Valid primary flavor to use in tests."), - cfg.StrOpt('flavor_ref_alt', - default="2", - help='Valid secondary flavor to be used in tests.'), - cfg.IntOpt('build_interval', - default=1, - help="Time in seconds between build status checks."), - cfg.IntOpt('build_timeout', - default=300, - help="Timeout in seconds to wait for an instance to build. " - "Other services that do not define build_timeout will " - "inherit this value."), - cfg.IntOpt('ready_wait', - default=0, - help="Additional wait time for clean state, when there is " - "no OS-EXT-STS extension available"), - cfg.StrOpt('fixed_network_name', - help="Name of the fixed network that is visible to all test " - "projects. If multiple networks are available for a " - "project, this is the network which will be used for " - "creating servers if tempest does not create a network or " - "a network is not specified elsewhere. It may be used for " - "ssh validation only if floating IPs are disabled."), - cfg.StrOpt('catalog_type', - default='compute', - help="Catalog type of the Compute service."), - cfg.StrOpt('region', - default='', - help="The compute region name to use. If empty, the value " - "of identity.region is used instead. If no such region " - "is found in the service catalog, the first found one is " - "used."), - cfg.StrOpt('endpoint_type', - default='publicURL', - choices=['public', 'admin', 'internal', - 'publicURL', 'adminURL', 'internalURL'], - help="The endpoint type to use for the compute service."), - cfg.StrOpt('volume_device_name', - default='vdb', - help="Expected device name when a volume is attached to " - "an instance. Not all hypervisors guarantee that they " - "will respect the user defined device name, tests may " - "fail if inappropriate device name is set."), - cfg.IntOpt('shelved_offload_time', - default=0, - help='Time in seconds before a shelved instance is eligible ' - 'for removing from a host. -1 never offload, 0 offload ' - 'when shelved. This time should be the same as the time ' - 'of nova.conf, and some tests will run for as long as the ' - 'time.'), - cfg.IntOpt('min_compute_nodes', - default=1, - help=('The minimum number of compute nodes expected. This will ' - 'be utilized by some multinode specific tests to ensure ' - 'that requests match the expected size of the cluster ' - 'you are testing with.')), - cfg.StrOpt('hypervisor_type', - default=None, - help="Hypervisor type of the test target on heterogeneous " - "compute environment. The value can be 'QEMU', 'xen' or " - "something."), - cfg.StrOpt('min_microversion', - default=None, - help="Lower version of the test target microversion range. " - "The format is 'X.Y', where 'X' and 'Y' are int values. " - "Tempest selects tests based on the range between " - "min_microversion and max_microversion. " - "If both values are not specified, Tempest avoids tests " - "which require a microversion. Valid values are string " - "with format 'X.Y' or string 'latest'"), - cfg.StrOpt('max_microversion', - default=None, - help="Upper version of the test target microversion range. " - "The format is 'X.Y', where 'X' and 'Y' are int values. " - "Tempest selects tests based on the range between " - "min_microversion and max_microversion. " - "If both values are not specified, Tempest avoids tests " - "which require a microversion. Valid values are string " - "with format 'X.Y' or string 'latest'"), -] - -compute_features_group = cfg.OptGroup(name='compute-feature-enabled', - title="Enabled Compute Service Features") - -ComputeFeaturesGroup = [ - cfg.BoolOpt('disk_config', - default=True, - help="If false, skip disk config tests"), - cfg.ListOpt('api_extensions', - default=['all'], - help='A list of enabled compute extensions with a special ' - 'entry all which indicates every extension is enabled. ' - 'Each extension should be specified with alias name. ' - 'Empty list indicates all extensions are disabled', - deprecated_for_removal=True, - deprecated_reason='The Nova extensions API and mechanism ' - 'is deprecated. This option will be ' - 'removed when all releases supported ' - 'by tempest no longer contain the Nova ' - 'extensions API and mechanism.'), - cfg.BoolOpt('change_password', - default=False, - help="Does the test environment support changing the admin " - "password?"), - cfg.BoolOpt('console_output', - default=True, - help="Does the test environment support obtaining instance " - "serial console output?"), - cfg.BoolOpt('resize', - default=False, - help="Does the test environment support resizing? When you " - "enable this feature, 'flavor_ref_alt' should be set and " - "it should refer to a larger flavor than 'flavor_ref' " - "one."), - cfg.BoolOpt('pause', - default=True, - help="Does the test environment support pausing?"), - cfg.BoolOpt('shelve', - default=True, - help="Does the test environment support shelving/unshelving?"), - cfg.BoolOpt('suspend', - default=True, - help="Does the test environment support suspend/resume?"), - cfg.BoolOpt('cold_migration', - default=True, - help="Does the test environment support cold migration?"), - cfg.BoolOpt('live_migration', - default=True, - help="Does the test environment support live migration?"), - cfg.BoolOpt('live_migrate_back_and_forth', - default=False, - help="Does the test environment support live migrating " - "VM back and forth between different versions of " - "nova-compute?"), - cfg.BoolOpt('metadata_service', - default=True, - help="Does the test environment support metadata service? " - "Ignored unless validation.run_validation=true."), - cfg.BoolOpt('block_migration_for_live_migration', - default=False, - help="Does the test environment use block devices for live " - "migration"), - cfg.BoolOpt('block_migrate_cinder_iscsi', - default=False, - help="Does the test environment support block migration with " - "Cinder iSCSI volumes. Note: libvirt >= 1.2.17 is required " - "to support this if using the libvirt compute driver."), - cfg.BoolOpt('vnc_console', - default=False, - help='Enable VNC console. This configuration value should ' - 'be same as [nova.vnc]->vnc_enabled in nova.conf'), - cfg.BoolOpt('spice_console', - default=False, - help='Enable Spice console. This configuration value should ' - 'be same as [nova.spice]->enabled in nova.conf'), - cfg.BoolOpt('rdp_console', - default=False, - help='Enable RDP console. This configuration value should ' - 'be same as [nova.rdp]->enabled in nova.conf'), - cfg.BoolOpt('serial_console', - default=False, - help='Enable serial console. This configuration value ' - 'should be the same as [nova.serial_console]->enabled ' - 'in nova.conf'), - cfg.BoolOpt('rescue', - default=True, - help='Does the test environment support instance rescue ' - 'mode?'), - cfg.BoolOpt('enable_instance_password', - default=True, - help='Enables returning of the instance password by the ' - 'relevant server API calls such as create, rebuild ' - 'or rescue. This configuration value should be same as ' - 'nova.conf: DEFAULT.enable_instance_password'), - cfg.BoolOpt('interface_attach', - default=True, - help='Does the test environment support dynamic network ' - 'interface attachment?'), - cfg.BoolOpt('snapshot', - default=True, - help='Does the test environment support creating snapshot ' - 'images of running instances?'), - cfg.BoolOpt('nova_cert', - default=False, - help='Does the test environment have the nova cert running?', - deprecated_for_removal=True, - deprecated_reason="On Nova side, the nova-cert service is " - "deprecated and the service will be removed " - "as early as Ocata."), - cfg.BoolOpt('personality', - default=False, - help='Does the test environment support server personality'), - cfg.BoolOpt('attach_encrypted_volume', - default=True, - help='Does the test environment support attaching an ' - 'encrypted volume to a running server instance? This may ' - 'depend on the combination of compute_driver in nova and ' - 'the volume_driver(s) in cinder.'), - cfg.BoolOpt('config_drive', - default=True, - help='Enable special configuration drive with metadata.'), - cfg.ListOpt('scheduler_available_filters', - default=['all'], - help="A list of enabled filters that nova will accept as hints" - " to the scheduler when creating a server. A special " - "entry 'all' indicates all filters that are included " - "with nova are enabled. Empty list indicates all filters " - "are disabled. The full list of available filters is in " - "nova.conf: DEFAULT.scheduler_available_filters. If the " - "default value is overridden in nova.conf by the test " - "environment (which means that a different set of " - "filters is enabled than what is included in Nova by " - "default) then, this option must be configured to " - "contain the same filters that Nova uses in the test " - "environment."), - cfg.BoolOpt('swap_volume', - default=False, - help='Does the test environment support in-place swapping of ' - 'volumes attached to a server instance?'), -] - - -image_group = cfg.OptGroup(name='image', - title="Image Service Options") - -ImageGroup = [ - cfg.StrOpt('catalog_type', - default='image', - help='Catalog type of the Image service.'), - cfg.StrOpt('region', - default='', - help="The image region name to use. If empty, the value " - "of identity.region is used instead. If no such region " - "is found in the service catalog, the first found one is " - "used."), - cfg.StrOpt('endpoint_type', - default='publicURL', - choices=['public', 'admin', 'internal', - 'publicURL', 'adminURL', 'internalURL'], - help="The endpoint type to use for the image service."), - cfg.StrOpt('http_image', - default='http://download.cirros-cloud.net/0.3.1/' - 'cirros-0.3.1-x86_64-uec.tar.gz', - help='http accessible image'), - cfg.IntOpt('build_timeout', - default=300, - help="Timeout in seconds to wait for an image to " - "become available."), - cfg.IntOpt('build_interval', - default=1, - help="Time in seconds between image operation status " - "checks."), - cfg.ListOpt('container_formats', - default=['ami', 'ari', 'aki', 'bare', 'ovf', 'ova'], - help="A list of image's container formats " - "users can specify."), - cfg.ListOpt('disk_formats', - default=['ami', 'ari', 'aki', 'vhd', 'vmdk', 'raw', 'qcow2', - 'vdi', 'iso', 'vhdx'], - help="A list of image's disk formats " - "users can specify.") -] - -image_feature_group = cfg.OptGroup(name='image-feature-enabled', - title='Enabled image service features') - -ImageFeaturesGroup = [ - cfg.BoolOpt('api_v2', - default=True, - help="Is the v2 image API enabled", - deprecated_for_removal=True, - deprecated_reason='Glance v1 APIs are deprecated and v2 APIs ' - 'are current one. In future, Tempest will ' - 'test v2 APIs only so this config option ' - 'will be removed.'), - cfg.BoolOpt('api_v1', - default=True, - help="Is the v1 image API enabled", - deprecated_for_removal=True, - deprecated_reason='Glance v1 APIs are deprecated and v2 APIs ' - 'are current one. In future, Tempest will ' - 'test v2 APIs only so this config option ' - 'will be removed.'), - cfg.BoolOpt('deactivate_image', - default=False, - help="Is the deactivate-image feature enabled." - " The feature has been integrated since Kilo.", - deprecated_for_removal=True, - deprecated_reason="All supported versions of OpenStack now " - "support the 'deactivate_image' feature"), -] - -network_group = cfg.OptGroup(name='network', - title='Network Service Options') - -NetworkGroup = [ - cfg.StrOpt('catalog_type', - default='network', - help='Catalog type of the Neutron service.'), - cfg.StrOpt('region', - default='', - help="The network region name to use. If empty, the value " - "of identity.region is used instead. If no such region " - "is found in the service catalog, the first found one is " - "used."), - cfg.StrOpt('endpoint_type', - default='publicURL', - choices=['public', 'admin', 'internal', - 'publicURL', 'adminURL', 'internalURL'], - help="The endpoint type to use for the network service."), - cfg.StrOpt('project_network_cidr', - default="10.100.0.0/16", - help="The cidr block to allocate project ipv4 subnets from"), - cfg.IntOpt('project_network_mask_bits', - default=28, - help="The mask bits for project ipv4 subnets"), - cfg.StrOpt('project_network_v6_cidr', - default="2003::/48", - help="The cidr block to allocate project ipv6 subnets from"), - cfg.IntOpt('project_network_v6_mask_bits', - default=64, - help="The mask bits for project ipv6 subnets"), - cfg.BoolOpt('project_networks_reachable', - default=False, - help="Whether project networks can be reached directly from " - "the test client. This must be set to True when the " - "'fixed' connect_method is selected."), - cfg.StrOpt('public_network_id', - default="", - help="Id of the public network that provides external " - "connectivity"), - cfg.StrOpt('floating_network_name', - help="Default floating network name. Used to allocate floating " - "IPs when neutron is enabled."), - cfg.StrOpt('public_router_id', - default="", - help="Id of the public router that provides external " - "connectivity. This should only be used when Neutron's " - "'allow_overlapping_ips' is set to 'False' in " - "neutron.conf. usually not needed past 'Grizzly' release"), - cfg.IntOpt('build_timeout', - default=300, - help="Timeout in seconds to wait for network operation to " - "complete."), - cfg.IntOpt('build_interval', - default=1, - help="Time in seconds between network operation status " - "checks."), - cfg.ListOpt('dns_servers', - default=["8.8.8.8", "8.8.4.4"], - help="List of dns servers which should be used" - " for subnet creation"), - cfg.StrOpt('port_vnic_type', - choices=[None, 'normal', 'direct', 'macvtap'], - help="vnic_type to use when Launching instances" - " with pre-configured ports." - " Supported ports are:" - " ['normal','direct','macvtap']"), - cfg.ListOpt('default_network', - default=["1.0.0.0/16", "2.0.0.0/16"], - help="List of ip pools" - " for subnetpools creation"), - cfg.BoolOpt('shared_physical_network', - default=False, - help="The environment does not support network separation " - "between tenants."), -] - -network_feature_group = cfg.OptGroup(name='network-feature-enabled', - title='Enabled network service features') - -NetworkFeaturesGroup = [ - cfg.BoolOpt('ipv6', - default=True, - help="Allow the execution of IPv6 tests"), - cfg.ListOpt('api_extensions', - default=['all'], - help="A list of enabled network extensions with a special " - "entry all which indicates every extension is enabled. " - "Empty list indicates all extensions are disabled. " - "To get the list of extensions run: 'neutron ext-list'"), - cfg.BoolOpt('ipv6_subnet_attributes', - default=False, - help="Allow the execution of IPv6 subnet tests that use " - "the extended IPv6 attributes ipv6_ra_mode " - "and ipv6_address_mode" - ), - cfg.BoolOpt('port_admin_state_change', - default=True, - help="Does the test environment support changing" - " port admin state"), - cfg.BoolOpt('port_security', - default=False, - help="Does the test environment support port security?"), - cfg.BoolOpt('floating_ips', - default=True, - help='Does the test environment support floating_ips') -] - -validation_group = cfg.OptGroup(name='validation', - title='SSH Validation options') - -ValidationGroup = [ - cfg.BoolOpt('run_validation', - default=False, - help='Enable ssh on created servers and creation of additional' - ' validation resources to enable remote access'), - cfg.BoolOpt('security_group', - default=True, - help='Enable/disable security groups.'), - cfg.BoolOpt('security_group_rules', - default=True, - help='Enable/disable security group rules.'), - cfg.StrOpt('connect_method', - default='floating', - choices=['fixed', 'floating'], - help='Default IP type used for validation: ' - '-fixed: uses the first IP belonging to the fixed network ' - '-floating: creates and uses a floating IP'), - cfg.StrOpt('auth_method', - default='keypair', - choices=['keypair'], - help='Default authentication method to the instance. ' - 'Only ssh via keypair is supported for now. ' - 'Additional methods will be handled in a separate spec.'), - cfg.IntOpt('ip_version_for_ssh', - default=4, - help='Default IP version for ssh connections.'), - cfg.IntOpt('ping_timeout', - default=120, - help='Timeout in seconds to wait for ping to succeed.'), - cfg.IntOpt('connect_timeout', - default=60, - help='Timeout in seconds to wait for the TCP connection to be ' - 'successful.'), - cfg.IntOpt('ssh_timeout', - default=300, - help='Timeout in seconds to wait for the ssh banner.'), - cfg.StrOpt('image_ssh_user', - default="root", - help="User name used to authenticate to an instance."), - cfg.StrOpt('image_ssh_password', - default="password", - help="Password used to authenticate to an instance."), - cfg.StrOpt('ssh_shell_prologue', - default="set -eu -o pipefail; PATH=$$PATH:/sbin;", - help="Shell fragments to use before executing a command " - "when sshing to a guest."), - cfg.IntOpt('ping_size', - default=56, - help="The packet size for ping packets originating " - "from remote linux hosts"), - cfg.IntOpt('ping_count', - default=1, - help="The number of ping packets originating from remote " - "linux hosts"), - cfg.StrOpt('floating_ip_range', - default='10.0.0.0/29', - help='Unallocated floating IP range, which will be used to ' - 'test the floating IP bulk feature for CRUD operation. ' - 'This block must not overlap an existing floating IP ' - 'pool.'), - cfg.StrOpt('network_for_ssh', - default='public', - help="Network used for SSH connections. Ignored if " - "connect_method=floating."), -] - -volume_group = cfg.OptGroup(name='volume', - title='Block Storage Options') - -VolumeGroup = [ - cfg.IntOpt('build_interval', - default=1, - help='Time in seconds between volume availability checks.'), - cfg.IntOpt('build_timeout', - default=300, - help='Timeout in seconds to wait for a volume to become ' - 'available.'), - cfg.StrOpt('catalog_type', - default='volume', - help="Catalog type of the Volume Service"), - cfg.StrOpt('region', - default='', - help="The volume region name to use. If empty, the value " - "of identity.region is used instead. If no such region " - "is found in the service catalog, the first found one is " - "used."), - cfg.StrOpt('endpoint_type', - default='publicURL', - choices=['public', 'admin', 'internal', - 'publicURL', 'adminURL', 'internalURL'], - help="The endpoint type to use for the volume service."), - cfg.ListOpt('backend_names', - default=['BACKEND_1', 'BACKEND_2'], - help='A list of backend names separated by comma. ' - 'The backend name must be declared in cinder.conf'), - cfg.StrOpt('storage_protocol', - default='iSCSI', - help='Backend protocol to target when creating volume types'), - cfg.StrOpt('vendor_name', - default='Open Source', - help='Backend vendor to target when creating volume types'), - cfg.StrOpt('disk_format', - default='raw', - help='Disk format to use when copying a volume to image'), - cfg.IntOpt('volume_size', - default=1, - help='Default size in GB for volumes created by volumes tests'), - cfg.ListOpt('manage_volume_ref', - default=['source-name', 'volume-%s'], - help="A reference to existing volume for volume manage. " - "It contains two elements, the first is ref type " - "(like 'source-name', 'source-id', etc), the second is " - "volume name template used in storage backend"), - cfg.ListOpt('manage_snapshot_ref', - default=['source-name', '_snapshot-%s'], - help="A reference to existing snapshot for snapshot manage. " - "It contains two elements, the first is ref type " - "(like 'source-name', 'source-id', etc), the second is " - "snapshot name template used in storage backend"), - cfg.StrOpt('min_microversion', - default=None, - help="Lower version of the test target microversion range. " - "The format is 'X.Y', where 'X' and 'Y' are int values. " - "Tempest selects tests based on the range between " - "min_microversion and max_microversion. " - "If both values are not specified, Tempest avoids tests " - "which require a microversion. Valid values are string " - "with format 'X.Y' or string 'latest'",), - cfg.StrOpt('max_microversion', - default=None, - help="Upper version of the test target microversion range. " - "The format is 'X.Y', where 'X' and 'Y' are int values. " - "Tempest selects tests based on the range between " - "min_microversion and max_microversion. " - "If both values are not specified, Tempest avoids tests " - "which require a microversion. Valid values are string " - "with format 'X.Y' or string 'latest'",), -] - -volume_feature_group = cfg.OptGroup(name='volume-feature-enabled', - title='Enabled Cinder Features') - -VolumeFeaturesGroup = [ - cfg.BoolOpt('multi_backend', - default=False, - help="Runs Cinder multi-backend test (requires 2 backends)"), - cfg.BoolOpt('backup', - default=True, - help='Runs Cinder volumes backup test'), - cfg.BoolOpt('snapshot', - default=True, - help='Runs Cinder volume snapshot test'), - cfg.BoolOpt('clone', - default=True, - help='Runs Cinder volume clone test'), - cfg.BoolOpt('manage_snapshot', - default=False, - help='Runs Cinder manage snapshot tests'), - cfg.BoolOpt('manage_volume', - default=False, - help='Runs Cinder manage volume tests'), - cfg.ListOpt('api_extensions', - default=['all'], - help='A list of enabled volume extensions with a special ' - 'entry all which indicates every extension is enabled. ' - 'Empty list indicates all extensions are disabled'), - cfg.BoolOpt('api_v1', - default=False, - help="Is the v1 volume API enabled", - deprecated_for_removal=True, - deprecated_reason="The v1 volume API has been deprecated " - "since Juno release, and the API will be " - "removed."), - cfg.BoolOpt('api_v2', - default=True, - help="Is the v2 volume API enabled"), - cfg.BoolOpt('api_v3', - default=True, - help="Is the v3 volume API enabled") -] - - -object_storage_group = cfg.OptGroup(name='object-storage', - title='Object Storage Service Options') - -ObjectStoreGroup = [ - cfg.StrOpt('catalog_type', - default='object-store', - help="Catalog type of the Object-Storage service."), - cfg.StrOpt('region', - default='', - help="The object-storage region name to use. If empty, the " - "value of identity.region is used instead. If no such " - "region is found in the service catalog, the first found " - "one is used."), - cfg.StrOpt('endpoint_type', - default='publicURL', - choices=['public', 'admin', 'internal', - 'publicURL', 'adminURL', 'internalURL'], - help="The endpoint type to use for the object-store service."), - cfg.IntOpt('container_sync_timeout', - default=600, - help="Number of seconds to time on waiting for a container " - "to container synchronization complete."), - cfg.IntOpt('container_sync_interval', - default=5, - help="Number of seconds to wait while looping to check the " - "status of a container to container synchronization"), - cfg.StrOpt('operator_role', - default='Member', - help="Role to add to users created for swift tests to " - "enable creating containers"), - cfg.StrOpt('reseller_admin_role', - default='ResellerAdmin', - help="User role that has reseller admin"), - cfg.StrOpt('realm_name', - default='realm1', - help="Name of sync realm. A sync realm is a set of clusters " - "that have agreed to allow container syncing with each " - "other. Set the same realm name as Swift's " - "container-sync-realms.conf"), - cfg.StrOpt('cluster_name', - default='name1', - help="One name of cluster which is set in the realm whose name " - "is set in 'realm_name' item in this file. Set the " - "same cluster name as Swift's container-sync-realms.conf"), -] - -object_storage_feature_group = cfg.OptGroup( - name='object-storage-feature-enabled', - title='Enabled object-storage features') - -ObjectStoreFeaturesGroup = [ - cfg.ListOpt('discoverable_apis', - default=['all'], - help="A list of the enabled optional discoverable apis. " - "A single entry, all, indicates that all of these " - "features are expected to be enabled"), - cfg.BoolOpt('container_sync', - default=True, - help="Execute (old style) container-sync tests"), - cfg.BoolOpt('object_versioning', - default=True, - help="Execute object-versioning tests"), - cfg.BoolOpt('discoverability', - default=True, - help="Execute discoverability tests"), -] - -orchestration_group = cfg.OptGroup(name='orchestration', - title='Orchestration Service Options') - -OrchestrationGroup = [ - cfg.StrOpt('catalog_type', - default='orchestration', - help="Catalog type of the Orchestration service.", - deprecated_for_removal=True, - deprecated_reason='Heat support will be removed from Tempest'), - cfg.StrOpt('region', - default='', - help="The orchestration region name to use. If empty, the " - "value of identity.region is used instead. If no such " - "region is found in the service catalog, the first found " - "one is used.", - deprecated_for_removal=True, - deprecated_reason='Heat support will be removed from Tempest'), - cfg.StrOpt('endpoint_type', - default='publicURL', - choices=['public', 'admin', 'internal', - 'publicURL', 'adminURL', 'internalURL'], - help="The endpoint type to use for the orchestration service.", - deprecated_for_removal=True, - deprecated_reason='Heat support will be removed from Tempest'), - cfg.StrOpt('stack_owner_role', default='heat_stack_owner', - help='Role required for users to be able to manage stacks', - deprecated_for_removal=True, - deprecated_reason='Heat support will be removed from Tempest'), - cfg.IntOpt('build_interval', - default=1, - help="Time in seconds between build status checks.", - deprecated_for_removal=True, - deprecated_reason='Heat support will be removed from Tempest'), - cfg.IntOpt('build_timeout', - default=1200, - help="Timeout in seconds to wait for a stack to build.", - deprecated_for_removal=True, - deprecated_reason='Heat support will be removed from Tempest'), - cfg.StrOpt('instance_type', - default='m1.micro', - help="Instance type for tests. Needs to be big enough for a " - "full OS plus the test workload", - deprecated_for_removal=True, - deprecated_reason='Heat support will be removed from Tempest'), - cfg.StrOpt('keypair_name', - help="Name of existing keypair to launch servers with.", - deprecated_for_removal=True, - deprecated_reason='Heat support will be removed from Tempest'), - cfg.IntOpt('max_template_size', - default=524288, - help="Value must match heat configuration of the same name.", - deprecated_for_removal=True, - deprecated_reason='Heat support will be removed from Tempest'), - cfg.IntOpt('max_resources_per_stack', - default=1000, - help="Value must match heat configuration of the same name.", - deprecated_for_removal=True, - deprecated_reason='Heat support will be removed from Tempest'), -] - - -scenario_group = cfg.OptGroup(name='scenario', title='Scenario Test Options') - -ScenarioGroup = [ - cfg.StrOpt('img_dir', - default='/opt/stack/new/devstack/files/images/' - 'cirros-0.3.1-x86_64-uec', - help='Directory containing image files', - deprecated_for_removal=True), - cfg.StrOpt('img_file', deprecated_name='qcow2_img_file', - default='cirros-0.3.1-x86_64-disk.img', - help='Image file name'), - cfg.StrOpt('img_disk_format', - default='qcow2', - help='Image disk format'), - cfg.StrOpt('img_container_format', - default='bare', - help='Image container format'), - cfg.DictOpt('img_properties', help='Glance image properties. ' - 'Use for custom images which require them'), - cfg.StrOpt('ami_img_file', - default='cirros-0.3.1-x86_64-blank.img', - help='AMI image file name', - deprecated_for_removal=True), - cfg.StrOpt('ari_img_file', - default='cirros-0.3.1-x86_64-initrd', - help='ARI image file name', - deprecated_for_removal=True), - cfg.StrOpt('aki_img_file', - default='cirros-0.3.1-x86_64-vmlinuz', - help='AKI image file name', - deprecated_for_removal=True), - # TODO(yfried): add support for dhcpcd - cfg.StrOpt('dhcp_client', - default='udhcpc', - choices=["udhcpc", "dhclient", ""], - help='DHCP client used by images to renew DCHP lease. ' - 'If left empty, update operation will be skipped. ' - 'Supported clients: "udhcpc", "dhclient"') -] - - -service_available_group = cfg.OptGroup(name="service_available", - title="Available OpenStack Services") - -ServiceAvailableGroup = [ - cfg.BoolOpt('cinder', - default=True, - help="Whether or not cinder is expected to be available"), - cfg.BoolOpt('neutron', - default=False, - help="Whether or not neutron is expected to be available"), - cfg.BoolOpt('glance', - default=True, - help="Whether or not glance is expected to be available"), - cfg.BoolOpt('swift', - default=True, - help="Whether or not swift is expected to be available"), - cfg.BoolOpt('nova', - default=True, - help="Whether or not nova is expected to be available"), - cfg.BoolOpt('heat', - default=False, - help="Whether or not Heat is expected to be available", - deprecated_for_removal=True, - deprecated_reason='Heat support will be removed from Tempest'), -] - -debug_group = cfg.OptGroup(name="debug", - title="Debug System") - -DebugGroup = [ - cfg.StrOpt('trace_requests', - default='', - help="""A regex to determine which requests should be traced. - -This is a regex to match the caller for rest client requests to be able to -selectively trace calls out of specific classes and methods. It largely -exists for test development, and is not expected to be used in a real deploy -of tempest. This will be matched against the discovered ClassName:method -in the test environment. - -Expected values for this field are: - - * ClassName:test_method_name - traces one test_method - * ClassName:setUp(Class) - traces specific setup functions - * ClassName:tearDown(Class) - traces specific teardown functions - * ClassName:_run_cleanups - traces the cleanup functions - -If nothing is specified, this feature is not enabled. To trace everything -specify .* as the regex. -""") -] - -DefaultGroup = [ - cfg.StrOpt('resources_prefix', - default='tempest', - help="Prefix to be added when generating the name for " - "test resources. It can be used to discover all " - "resources associated with a specific test run when " - "running tempest on a real-life cloud", - deprecated_for_removal=True, - deprecated_reason="It is enough to add 'tempest' as this " - "prefix to ideintify resources which are " - "created by Tempest and no projects set " - "this option on OpenStack dev community."), - cfg.BoolOpt('pause_teardown', - default=False, - help="""Whether to pause a test in global teardown. - -The best use case is investigating used resources of one test. -A test can be run as follows: - $ ostestr --pdb TEST_ID -or - $ python -m testtools.run TEST_ID"""), -] - -_opts = [ - (auth_group, AuthGroup), - (compute_group, ComputeGroup), - (compute_features_group, ComputeFeaturesGroup), - (identity_group, IdentityGroup), - (service_clients_group, ServiceClientsGroup), - (identity_feature_group, IdentityFeatureGroup), - (image_group, ImageGroup), - (image_feature_group, ImageFeaturesGroup), - (network_group, NetworkGroup), - (network_feature_group, NetworkFeaturesGroup), - (validation_group, ValidationGroup), - (volume_group, VolumeGroup), - (volume_feature_group, VolumeFeaturesGroup), - (object_storage_group, ObjectStoreGroup), - (object_storage_feature_group, ObjectStoreFeaturesGroup), - (orchestration_group, OrchestrationGroup), - (scenario_group, ScenarioGroup), - (service_available_group, ServiceAvailableGroup), - (debug_group, DebugGroup), - (None, DefaultGroup) -] - - -def register_opts(): - ext_plugins = plugins.TempestTestPluginManager() - # Register in-tree tempest config options - for g, o in _opts: - register_opt_group(_CONF, g, o) - # Call external plugin config option registration - ext_plugins.register_plugin_opts(_CONF) - - -def list_opts(): - """Return a list of oslo.config options available. - - The purpose of this is to allow tools like the Oslo sample config file - generator to discover the options exposed to users. - """ - ext_plugins = plugins.TempestTestPluginManager() - # Make a shallow copy of the options list that can be - # extended by plugins. Send back the group object - # to allow group help text to be generated. - opt_list = [(g, o) for g, o in _opts] - opt_list.extend(ext_plugins.get_plugin_options_list()) - return opt_list - - -# this should never be called outside of this class -class TempestConfigPrivate(object): - """Provides OpenStack configuration information.""" - - DEFAULT_CONFIG_DIR = os.path.join(os.getcwd(), "etc") - - DEFAULT_CONFIG_FILE = "tempest.conf" - - def __getattr__(self, attr): - # Handles config options from the default group - return getattr(_CONF, attr) - - def _set_attrs(self): - # This methods ensures that config options in Tempest as well as - # in Tempest plugins can be accessed via: - # CONF.. - # where: - # normalised_group_name = group_name.replace('-', '_') - # Attributes are set at __init__ time *only* for known option groups - self.auth = _CONF.auth - self.compute = _CONF.compute - self.compute_feature_enabled = _CONF['compute-feature-enabled'] - self.identity = _CONF.identity - self.service_clients = _CONF['service-clients'] - self.identity_feature_enabled = _CONF['identity-feature-enabled'] - self.image = _CONF.image - self.image_feature_enabled = _CONF['image-feature-enabled'] - self.network = _CONF.network - self.network_feature_enabled = _CONF['network-feature-enabled'] - self.validation = _CONF.validation - self.volume = _CONF.volume - self.volume_feature_enabled = _CONF['volume-feature-enabled'] - self.object_storage = _CONF['object-storage'] - self.object_storage_feature_enabled = _CONF[ - 'object-storage-feature-enabled'] - self.orchestration = _CONF.orchestration - self.scenario = _CONF.scenario - self.service_available = _CONF.service_available - self.debug = _CONF.debug - logging.tempest_set_log_file('tempest.log') - # Setting attributes for plugins - # NOTE(andreaf) Plugins have no access to the TempestConfigPrivate - # instance at discovery time, so they have no way of setting these - # aliases themselves. - ext_plugins = plugins.TempestTestPluginManager() - for group, _ in ext_plugins.get_plugin_options_list(): - if isinstance(group, cfg.OptGroup): - # If we have an OptGroup - group_name = group.name - group_dest = group.dest - else: - # If we have a group name as a string - group_name = group - group_dest = group.replace('-', '_') - # NOTE(andreaf) We can set the attribute safely here since in - # case of name conflict we would not have reached this point. - setattr(self, group_dest, _CONF[group_name]) - - def __init__(self, parse_conf=True, config_path=None): - """Initialize a configuration from a conf directory and conf file.""" - super(TempestConfigPrivate, self).__init__() - config_files = [] - failsafe_path = "/etc/tempest/" + self.DEFAULT_CONFIG_FILE - - if config_path: - path = config_path - else: - # Environment variables override defaults... - conf_dir = os.environ.get('TEMPEST_CONFIG_DIR', - self.DEFAULT_CONFIG_DIR) - conf_file = os.environ.get('TEMPEST_CONFIG', - self.DEFAULT_CONFIG_FILE) - - path = os.path.join(conf_dir, conf_file) - - if not os.path.isfile(path): - path = failsafe_path - - # only parse the config file if we expect one to exist. This is needed - # to remove an issue with the config file up to date checker. - if parse_conf: - config_files.append(path) - logging.register_options(_CONF) - if os.path.isfile(path): - _CONF([], project='tempest', default_config_files=config_files) - else: - _CONF([], project='tempest') - - logging_cfg_path = "%s/logging.conf" % os.path.dirname(path) - if ((not hasattr(_CONF, 'log_config_append') or - _CONF.log_config_append is None) and - os.path.isfile(logging_cfg_path)): - # if logging conf is in place we need to set log_config_append - _CONF.log_config_append = logging_cfg_path - - logging.setup(_CONF, 'tempest') - LOG = logging.getLogger('tempest') - LOG.info("Using tempest config file %s", path) - register_opts() - self._set_attrs() - if parse_conf: - _CONF.log_opt_values(LOG, logging.DEBUG) - - -class TempestConfigProxy(object): - _config = None - _path = None - - _extra_log_defaults = [ - ('paramiko.transport', logging.INFO), - ('requests.packages.urllib3.connectionpool', logging.WARN), - ] - - def _fix_log_levels(self): - """Tweak the oslo log defaults.""" - for name, level in self._extra_log_defaults: - logging.getLogger(name).logger.setLevel(level) - - def __getattr__(self, attr): - if not self._config: - self._fix_log_levels() - lock_dir = os.path.join(tempfile.gettempdir(), 'tempest-lock') - lockutils.set_defaults(lock_dir) - self._config = TempestConfigPrivate(config_path=self._path) - - # Pushing tempest internal service client configuration to the - # service clients register. Doing this in the config module ensures - # that the configuration is available by the time we register the - # service clients. - # NOTE(andreaf) This has to be done at the time the first - # attribute is accessed, to ensure all plugins have been already - # loaded, options registered, and _config is set. - _register_tempest_service_clients() - - # Registering service clients and pushing their configuration to - # the service clients register. Doing this in the config module - # ensures that the configuration is available by the time we - # discover tests from plugins. - plugins.TempestTestPluginManager()._register_service_clients() - - return getattr(self._config, attr) - - def set_config_path(self, path): - self._path = path - - -CONF = TempestConfigProxy() - - -@debtcollector.removals.remove( - message='use testtools.skipUnless instead', removal_version='Queens') -def skip_unless_config(*args): - """Decorator to raise a skip if a config opt doesn't exist or is False - - :param str group: The first arg, the option group to check - :param str name: The second arg, the option name to check - :param str msg: Optional third arg, the skip msg to use if a skip is raised - :raises testtools.TestCaseskipException: If the specified config option - doesn't exist or it exists and evaluates to False - """ - def decorator(f): - group = args[0] - name = args[1] - - @functools.wraps(f) - def wrapper(self, *func_args, **func_kwargs): - if not hasattr(CONF, group): - msg = "Config group %s doesn't exist" % group - raise testtools.TestCase.skipException(msg) - - conf_group = getattr(CONF, group) - if not hasattr(conf_group, name): - msg = "Config option %s.%s doesn't exist" % (group, - name) - raise testtools.TestCase.skipException(msg) - - value = getattr(conf_group, name) - if not value: - if len(args) == 3: - msg = args[2] - else: - msg = "Config option %s.%s is false" % (group, - name) - raise testtools.TestCase.skipException(msg) - return f(self, *func_args, **func_kwargs) - return wrapper - return decorator - - -@debtcollector.removals.remove( - message='use testtools.skipIf instead', removal_version='Queens') -def skip_if_config(*args): - """Raise a skipException if a config exists and is True - - :param str group: The first arg, the option group to check - :param str name: The second arg, the option name to check - :param str msg: Optional third arg, the skip msg to use if a skip is raised - :raises testtools.TestCase.skipException: If the specified config option - exists and evaluates to True - """ - def decorator(f): - group = args[0] - name = args[1] - - @functools.wraps(f) - def wrapper(self, *func_args, **func_kwargs): - if hasattr(CONF, group): - conf_group = getattr(CONF, group) - if hasattr(conf_group, name): - value = getattr(conf_group, name) - if value: - if len(args) == 3: - msg = args[2] - else: - msg = "Config option %s.%s is false" % (group, - name) - raise testtools.TestCase.skipException(msg) - return f(self, *func_args, **func_kwargs) - return wrapper - return decorator - - -def service_client_config(service_client_name=None): - """Return a dict with the parameters to init service clients - - Extracts from CONF the settings specific to the service_client_name and - api_version, and formats them as dict ready to be passed to the service - clients __init__: - - * `region` (default to identity) - * `catalog_type` - * `endpoint_type` - * `build_timeout` (object-storage and identity default to compute) - * `build_interval` (object-storage and identity default to compute) - - The following common settings are always returned, even if - `service_client_name` is None: - - * `disable_ssl_certificate_validation` - * `ca_certs` - * `trace_requests` - * `http_timeout` - - The dict returned by this does not fit a few service clients: - - * The endpoint type is not returned for identity client, since it takes - three different values for v2 admin, v2 public and v3 - * The `ServersClient` from compute accepts an optional - `enable_instance_password` parameter, which is not returned. - * The `VolumesClient` for both v1 and v2 volume accept an optional - `default_volume_size` parameter, which is not returned. - * The `TokenClient` and `V3TokenClient` have a very different - interface, only auth_url is needed for them. - - :param service_client_name: str Name of the service. Supported values are - 'compute', 'identity', 'image', 'network', 'object-storage', 'volume' - :return: dictionary of __init__ parameters for the service clients - :rtype: dict - """ - _parameters = { - 'disable_ssl_certificate_validation': - CONF.identity.disable_ssl_certificate_validation, - 'ca_certs': CONF.identity.ca_certificates_file, - 'trace_requests': CONF.debug.trace_requests, - 'http_timeout': CONF.service_clients.http_timeout - } - - if service_client_name is None: - return _parameters - - # Get the group of options first, by normalising the service_group_name - # Services with a '-' in the name have an '_' in the option group name - config_group = service_client_name.replace('-', '_') - # NOTE(andreaf) Check if the config group exists. This allows for this - # helper to be used for settings from registered plugins as well - try: - options = getattr(CONF, config_group) - except cfg.NoSuchOptError: - # Option group not defined - raise exceptions.UnknownServiceClient(services=service_client_name) - # Set endpoint_type - # Identity uses different settings depending on API version, so do not - # return the endpoint at all. - if service_client_name != 'identity': - _parameters['endpoint_type'] = getattr(options, 'endpoint_type') - # Set build_* - # Object storage and identity groups do not have conf settings for - # build_* parameters, and we default to compute in any case - for setting in ['build_timeout', 'build_interval']: - if not hasattr(options, setting) or not getattr(options, setting): - _parameters[setting] = getattr(CONF.compute, setting) - else: - _parameters[setting] = getattr(options, setting) - # Set region - # If a service client does not define region or region is not set - # default to the identity region - if not hasattr(options, 'region') or not getattr(options, 'region'): - _parameters['region'] = CONF.identity.region - else: - _parameters['region'] = getattr(options, 'region') - # Set service - _parameters['service'] = getattr(options, 'catalog_type') - return _parameters - - -def _register_tempest_service_clients(): - # Register tempest own service clients using the same mechanism used - # for external plugins. - # The configuration data is pushed to the registry so that automatic - # configuration of tempest own service clients is possible both for - # tempest as well as for the plugins. - service_clients = clients.tempest_modules() - registry = clients.ClientsRegistry() - all_clients = [] - for service_client in service_clients: - module = service_clients[service_client] - configs = service_client.split('.')[0] - service_client_data = dict( - name=service_client.replace('.', '_'), - service_version=service_client, - module_path=module.__name__, - client_names=module.__all__, - **service_client_config(configs) - ) - all_clients.append(service_client_data) - # NOTE(andreaf) Internal service clients do not actually belong - # to a plugin, so using '__tempest__' to indicate a virtual plugin - # which holds internal service clients. - registry.register_service_client('__tempest__', all_clients) diff --git a/tempest/exceptions.py b/tempest/exceptions.py deleted file mode 100644 index b5b2d71cf..000000000 --- a/tempest/exceptions.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.lib import exceptions - - -class BuildErrorException(exceptions.TempestException): - message = "Server %(server_id)s failed to build and is in ERROR status" - - -class SnapshotNotFoundException(exceptions.TempestException): - message = "Server snapshot image %(image_id)s not found." - - -class ImageKilledException(exceptions.TempestException): - message = "Image %(image_id)s 'killed' while waiting for '%(status)s'" - - -class AddImageException(exceptions.TempestException): - message = "Image %(image_id)s failed to become ACTIVE in the allotted time" - - -class VolumeResourceBuildErrorException(exceptions.TempestException): - message = ("%(resource_name)s %(resource_id)s failed to build and is in " - "ERROR status") - - -class VolumeRestoreErrorException(exceptions.TempestException): - message = "Volume %(volume_id)s failed to restore and is in ERROR status" - - -class StackBuildErrorException(exceptions.TempestException): - message = ("Stack %(stack_identifier)s is in %(stack_status)s status " - "due to '%(stack_status_reason)s'") - - -class ServerUnreachable(exceptions.TempestException): - message = ("Server %(server_id)s is not reachable via " - "the configured network") - - -class RFCViolation(exceptions.RestClientException): - message = "RFC Violation" diff --git a/tempest/hacking/__init__.py b/tempest/hacking/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py deleted file mode 100644 index 067da09a5..000000000 --- a/tempest/hacking/checks.py +++ /dev/null @@ -1,311 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# 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 os -import re - -import pep8 - - -PYTHON_CLIENTS = ['cinder', 'glance', 'keystone', 'nova', 'swift', 'neutron', - 'ironic', 'heat', 'sahara'] - -PYTHON_CLIENT_RE = re.compile('import (%s)client' % '|'.join(PYTHON_CLIENTS)) -TEST_DEFINITION = re.compile(r'^\s*def test.*') -SETUP_TEARDOWN_CLASS_DEFINITION = re.compile(r'^\s+def (setUp|tearDown)Class') -SCENARIO_DECORATOR = re.compile(r'\s*@.*services\((.*)\)') -VI_HEADER_RE = re.compile(r"^#\s+vim?:.+") -RAND_NAME_HYPHEN_RE = re.compile(r".*rand_name\(.+[\-\_][\"\']\)") -mutable_default_args = re.compile(r"^\s*def .+\((.+=\{\}|.+=\[\])") -TESTTOOLS_SKIP_DECORATOR = re.compile(r'\s*@testtools\.skip\((.*)\)') -METHOD = re.compile(r"^ def .+") -METHOD_GET_RESOURCE = re.compile(r"^\s*def (list|show)\_.+") -METHOD_DELETE_RESOURCE = re.compile(r"^\s*def delete_.+") -CLASS = re.compile(r"^class .+") - - -def import_no_clients_in_api_and_scenario_tests(physical_line, filename): - """Check for client imports from tempest/api & tempest/scenario tests - - T102: Cannot import OpenStack python clients - """ - - if "tempest/api" in filename or "tempest/scenario" in filename: - res = PYTHON_CLIENT_RE.match(physical_line) - if res: - return (physical_line.find(res.group(1)), - ("T102: python clients import not allowed" - " in tempest/api/* or tempest/scenario/* tests")) - - -def scenario_tests_need_service_tags(physical_line, filename, - previous_logical): - """Check that scenario tests have service tags - - T104: Scenario tests require a services decorator - """ - - if 'tempest/scenario/' in filename and '/test_' in filename: - if TEST_DEFINITION.match(physical_line): - if not SCENARIO_DECORATOR.match(previous_logical): - return (physical_line.find('def'), - "T104: Scenario tests require a service decorator") - - -def no_setup_teardown_class_for_tests(physical_line, filename): - - if pep8.noqa(physical_line): - return - - if 'tempest/test.py' in filename or 'tempest/lib/' in filename: - return - - if SETUP_TEARDOWN_CLASS_DEFINITION.match(physical_line): - return (physical_line.find('def'), - "T105: (setUp|tearDown)Class can not be used in tests") - - -def no_vi_headers(physical_line, line_number, lines): - """Check for vi editor configuration in source files. - - By default vi modelines can only appear in the first or - last 5 lines of a source file. - - T106 - """ - # NOTE(gilliard): line_number is 1-indexed - if line_number <= 5 or line_number > len(lines) - 5: - if VI_HEADER_RE.match(physical_line): - return 0, "T106: Don't put vi configuration in source files" - - -def service_tags_not_in_module_path(physical_line, filename): - """Check that a service tag isn't in the module path - - A service tag should only be added if the service name isn't already in - the module path. - - T107 - """ - # NOTE(mtreinish) Scenario tests always need service tags, but subdirs are - # created for services like heat which would cause false negatives for - # those tests, so just exclude the scenario tests. - if 'tempest/scenario' not in filename: - matches = SCENARIO_DECORATOR.match(physical_line) - if matches: - services = matches.group(1).split(',') - for service in services: - service_name = service.strip().strip("'") - modulepath = os.path.split(filename)[0] - if service_name in modulepath: - return (physical_line.find(service_name), - "T107: service tag should not be in path") - - -def no_hyphen_at_end_of_rand_name(logical_line, filename): - """Check no hyphen at the end of rand_name() argument - - T108 - """ - msg = "T108: hyphen should not be specified at the end of rand_name()" - if RAND_NAME_HYPHEN_RE.match(logical_line): - return 0, msg - - -def no_mutable_default_args(logical_line): - """Check that mutable object isn't used as default argument - - N322: Method's default argument shouldn't be mutable - """ - msg = "N322: Method's default argument shouldn't be mutable!" - if mutable_default_args.match(logical_line): - yield (0, msg) - - -def no_testtools_skip_decorator(logical_line): - """Check that methods do not have the testtools.skip decorator - - T109 - """ - if TESTTOOLS_SKIP_DECORATOR.match(logical_line): - yield (0, "T109: Cannot use testtools.skip decorator; instead use " - "decorators.skip_because from tempest.lib") - - -def _common_service_clients_check(logical_line, physical_line, filename, - ignored_list_file=None): - if not re.match('tempest/(lib/)?services/.*', filename): - return False - - if ignored_list_file is not None: - ignored_list = [] - with open('tempest/hacking/' + ignored_list_file) as f: - for line in f: - ignored_list.append(line.strip()) - - if filename in ignored_list: - return False - - if not METHOD.match(physical_line): - return False - - if pep8.noqa(physical_line): - return False - - return True - - -def get_resources_on_service_clients(logical_line, physical_line, filename, - line_number, lines): - """Check that service client names of GET should be consistent - - T110 - """ - if not _common_service_clients_check(logical_line, physical_line, - filename, 'ignored_list_T110.txt'): - return - - for line in lines[line_number:]: - if METHOD.match(line) or CLASS.match(line): - # the end of a method - return - - if 'self.get(' not in line and ('self.show_resource(' not in line and - 'self.list_resources(' not in line): - continue - - if METHOD_GET_RESOURCE.match(logical_line): - return - - msg = ("T110: [GET /resources] methods should be list_s" - " or show_") - yield (0, msg) - - -def delete_resources_on_service_clients(logical_line, physical_line, filename, - line_number, lines): - """Check that service client names of DELETE should be consistent - - T111 - """ - if not _common_service_clients_check(logical_line, physical_line, - filename, 'ignored_list_T111.txt'): - return - - for line in lines[line_number:]: - if METHOD.match(line) or CLASS.match(line): - # the end of a method - return - - if 'self.delete(' not in line and 'self.delete_resource(' not in line: - continue - - if METHOD_DELETE_RESOURCE.match(logical_line): - return - - msg = ("T111: [DELETE /resources/] methods should be " - "delete_") - yield (0, msg) - - -def dont_import_local_tempest_into_lib(logical_line, filename): - """Check that tempest.lib should not import local tempest code - - T112 - """ - if 'tempest/lib/' not in filename: - return - - if not ('from tempest' in logical_line - or 'import tempest' in logical_line): - return - - if ('from tempest.lib' in logical_line - or 'import tempest.lib' in logical_line): - return - - msg = ("T112: tempest.lib should not import local tempest code to avoid " - "circular dependency") - yield (0, msg) - - -def use_rand_uuid_instead_of_uuid4(logical_line, filename): - """Check that tests use data_utils.rand_uuid() instead of uuid.uuid4() - - T113 - """ - if 'tempest/lib/' in filename: - return - - if 'uuid.uuid4()' not in logical_line: - return - - msg = ("T113: Tests should use data_utils.rand_uuid()/rand_uuid_hex() " - "instead of uuid.uuid4()/uuid.uuid4().hex") - yield (0, msg) - - -def dont_use_config_in_tempest_lib(logical_line, filename): - """Check that tempest.lib doesn't use tempest config - - T114 - """ - - if 'tempest/lib/' not in filename: - return - - if ('tempest.config' in logical_line - or 'from tempest import config' in logical_line - or 'oslo_config' in logical_line): - msg = ('T114: tempest.lib can not have any dependency on tempest ' - 'config.') - yield(0, msg) - - -def dont_put_admin_tests_on_nonadmin_path(logical_line, physical_line, - filename): - """Check admin tests should exist under admin path - - T115 - """ - - if 'tempest/api/' not in filename: - return - - if pep8.noqa(physical_line): - return - - if not re.match('class .*Test.*\(.*Admin.*\):', logical_line): - return - - if not re.match('.\/tempest\/api\/.*\/admin\/.*', filename): - msg = 'T115: All admin tests should exist under admin path.' - yield(0, msg) - - -def factory(register): - register(import_no_clients_in_api_and_scenario_tests) - register(scenario_tests_need_service_tags) - register(no_setup_teardown_class_for_tests) - register(no_vi_headers) - register(service_tags_not_in_module_path) - register(no_hyphen_at_end_of_rand_name) - register(no_mutable_default_args) - register(no_testtools_skip_decorator) - register(get_resources_on_service_clients) - register(delete_resources_on_service_clients) - register(dont_import_local_tempest_into_lib) - register(dont_use_config_in_tempest_lib) - register(use_rand_uuid_instead_of_uuid4) - register(dont_put_admin_tests_on_nonadmin_path) diff --git a/tempest/hacking/ignored_list_T110.txt b/tempest/hacking/ignored_list_T110.txt deleted file mode 100644 index 0e7e894ca..000000000 --- a/tempest/hacking/ignored_list_T110.txt +++ /dev/null @@ -1 +0,0 @@ -./tempest/services/object_storage/object_client.py diff --git a/tempest/lib/__init__.py b/tempest/lib/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/__init__.py b/tempest/lib/api_schema/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/__init__.py b/tempest/lib/api_schema/response/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/__init__.py b/tempest/lib/api_schema/response/compute/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_1/__init__.py b/tempest/lib/api_schema/response/compute/v2_1/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_1/agents.py b/tempest/lib/api_schema/response/compute/v2_1/agents.py deleted file mode 100644 index 6f712b41e..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/agents.py +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright 2014 NEC Corporation. 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. - -common_agent_info = { - 'type': 'object', - 'properties': { - 'agent_id': {'type': ['integer', 'string']}, - 'hypervisor': {'type': 'string'}, - 'os': {'type': 'string'}, - 'architecture': {'type': 'string'}, - 'version': {'type': 'string'}, - 'url': {'type': 'string', 'format': 'uri'}, - 'md5hash': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['agent_id', 'hypervisor', 'os', 'architecture', - 'version', 'url', 'md5hash'] -} - -list_agents = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'agents': { - 'type': 'array', - 'items': common_agent_info - } - }, - 'additionalProperties': False, - 'required': ['agents'] - } -} - -create_agent = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'agent': common_agent_info - }, - 'additionalProperties': False, - 'required': ['agent'] - } -} - -update_agent = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'agent': { - 'type': 'object', - 'properties': { - 'agent_id': {'type': ['integer', 'string']}, - 'version': {'type': 'string'}, - 'url': {'type': 'string', 'format': 'uri'}, - 'md5hash': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['agent_id', 'version', 'url', 'md5hash'] - } - }, - 'additionalProperties': False, - 'required': ['agent'] - } -} - -delete_agent = { - 'status_code': [200] -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/aggregates.py b/tempest/lib/api_schema/response/compute/v2_1/aggregates.py deleted file mode 100644 index 3289a34a7..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/aggregates.py +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 copy - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -# create-aggregate api doesn't have 'hosts' and 'metadata' attributes. -aggregate_for_create = { - 'type': 'object', - 'properties': { - 'availability_zone': {'type': ['string', 'null']}, - 'created_at': parameter_types.date_time, - 'deleted': {'type': 'boolean'}, - 'deleted_at': parameter_types.date_time_or_null, - 'id': {'type': 'integer'}, - 'name': {'type': 'string'}, - 'updated_at': parameter_types.date_time_or_null - }, - 'additionalProperties': False, - 'required': ['availability_zone', 'created_at', 'deleted', - 'deleted_at', 'id', 'name', 'updated_at'], -} - -common_aggregate_info = copy.deepcopy(aggregate_for_create) -common_aggregate_info['properties'].update({ - 'hosts': {'type': 'array'}, - 'metadata': {'type': 'object'} -}) -common_aggregate_info['required'].extend(['hosts', 'metadata']) - -list_aggregates = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'aggregates': { - 'type': 'array', - 'items': common_aggregate_info - } - }, - 'additionalProperties': False, - 'required': ['aggregates'], - } -} - -get_aggregate = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'aggregate': common_aggregate_info - }, - 'additionalProperties': False, - 'required': ['aggregate'], - } -} - -aggregate_set_metadata = get_aggregate -# The 'updated_at' attribute of 'update_aggregate' can't be null. -update_aggregate = copy.deepcopy(get_aggregate) -update_aggregate['response_body']['properties']['aggregate']['properties'][ - 'updated_at'] = parameter_types.date_time - -delete_aggregate = { - 'status_code': [200] -} - -create_aggregate = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'aggregate': aggregate_for_create - }, - 'additionalProperties': False, - 'required': ['aggregate'], - } -} - -aggregate_add_remove_host = get_aggregate diff --git a/tempest/lib/api_schema/response/compute/v2_1/availability_zone.py b/tempest/lib/api_schema/response/compute/v2_1/availability_zone.py deleted file mode 100644 index 0dc28c378..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/availability_zone.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 copy - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - - -base = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'availabilityZoneInfo': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'zoneName': {'type': 'string'}, - 'zoneState': { - 'type': 'object', - 'properties': { - 'available': {'type': 'boolean'} - }, - 'additionalProperties': False, - 'required': ['available'] - }, - # NOTE: Here is the difference between detail and - # non-detail. - 'hosts': {'type': 'null'} - }, - 'additionalProperties': False, - 'required': ['zoneName', 'zoneState', 'hosts'] - } - } - }, - 'additionalProperties': False, - 'required': ['availabilityZoneInfo'] - } -} - -detail = { - 'type': ['object', 'null'], - 'patternProperties': { - # NOTE: Here is for a hostname - '^[a-zA-Z0-9-_.]+$': { - 'type': 'object', - 'patternProperties': { - # NOTE: Here is for a service name - '^.*$': { - 'type': 'object', - 'properties': { - 'available': {'type': 'boolean'}, - 'active': {'type': 'boolean'}, - 'updated_at': parameter_types.date_time_or_null - }, - 'additionalProperties': False, - 'required': ['available', 'active', 'updated_at'] - } - } - } - } -} - -list_availability_zone_list = copy.deepcopy(base) - -list_availability_zone_list_detail = copy.deepcopy(base) -list_availability_zone_list_detail['response_body']['properties'][ - 'availabilityZoneInfo']['items']['properties']['hosts'] = detail diff --git a/tempest/lib/api_schema/response/compute/v2_1/baremetal_nodes.py b/tempest/lib/api_schema/response/compute/v2_1/baremetal_nodes.py deleted file mode 100644 index d1ee87728..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/baremetal_nodes.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 copy - -node = { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'interfaces': {'type': 'array'}, - 'host': {'type': 'string'}, - 'task_state': {'type': ['string', 'null']}, - 'cpus': {'type': ['integer', 'string']}, - 'memory_mb': {'type': ['integer', 'string']}, - 'disk_gb': {'type': ['integer', 'string']}, - }, - 'additionalProperties': False, - 'required': ['id', 'interfaces', 'host', 'task_state', 'cpus', 'memory_mb', - 'disk_gb'] -} - -list_baremetal_nodes = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'nodes': { - 'type': 'array', - 'items': node - } - }, - 'additionalProperties': False, - 'required': ['nodes'] - } -} - -baremetal_node = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'node': node - }, - 'additionalProperties': False, - 'required': ['node'] - } -} -get_baremetal_node = copy.deepcopy(baremetal_node) -get_baremetal_node['response_body']['properties']['node'][ - 'properties'].update({'instance_uuid': {'type': ['string', 'null']}}) -get_baremetal_node['response_body']['properties']['node'][ - 'required'].append('instance_uuid') diff --git a/tempest/lib/api_schema/response/compute/v2_1/certificates.py b/tempest/lib/api_schema/response/compute/v2_1/certificates.py deleted file mode 100644 index 4e7cbe4d2..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/certificates.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 copy - -_common_schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'certificate': { - 'type': 'object', - 'properties': { - 'data': {'type': 'string'}, - 'private_key': {'type': 'string'}, - }, - 'additionalProperties': False, - 'required': ['data', 'private_key'] - } - }, - 'additionalProperties': False, - 'required': ['certificate'] - } -} - -get_certificate = copy.deepcopy(_common_schema) -get_certificate['response_body']['properties']['certificate'][ - 'properties']['private_key'].update({'type': 'null'}) - -create_certificate = copy.deepcopy(_common_schema) diff --git a/tempest/lib/api_schema/response/compute/v2_1/extensions.py b/tempest/lib/api_schema/response/compute/v2_1/extensions.py deleted file mode 100644 index b5962d752..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/extensions.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -list_extensions = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'extensions': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'updated': parameter_types.date_time, - 'name': {'type': 'string'}, - 'links': {'type': 'array'}, - 'namespace': { - 'type': 'string', - 'format': 'uri' - }, - 'alias': {'type': 'string'}, - 'description': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['updated', 'name', 'links', 'namespace', - 'alias', 'description'] - } - } - }, - 'additionalProperties': False, - 'required': ['extensions'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/fixed_ips.py b/tempest/lib/api_schema/response/compute/v2_1/fixed_ips.py deleted file mode 100644 index a653213f0..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/fixed_ips.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -get_fixed_ip = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'fixed_ip': { - 'type': 'object', - 'properties': { - 'address': parameter_types.ip_address, - 'cidr': {'type': 'string'}, - 'host': {'type': 'string'}, - 'hostname': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['address', 'cidr', 'host', 'hostname'] - } - }, - 'additionalProperties': False, - 'required': ['fixed_ip'] - } -} - -reserve_unreserve_fixed_ip = { - 'status_code': [202] -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/flavors.py b/tempest/lib/api_schema/response/compute/v2_1/flavors.py deleted file mode 100644 index 547d94d57..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/flavors.py +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -list_flavors = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'flavors': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - 'links': parameter_types.links, - 'id': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['name', 'links', 'id'] - } - }, - 'flavors_links': parameter_types.links - }, - 'additionalProperties': False, - # NOTE(gmann): flavors_links attribute is not necessary - # to be present always So it is not 'required'. - 'required': ['flavors'] - } -} - -common_flavor_info = { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'}, - 'links': parameter_types.links, - 'ram': {'type': 'integer'}, - 'vcpus': {'type': 'integer'}, - # 'swap' attributes comes as integer value but if it is empty - # it comes as "". So defining type of as string and integer. - 'swap': {'type': ['integer', 'string']}, - 'disk': {'type': 'integer'}, - 'id': {'type': 'string'}, - 'OS-FLV-DISABLED:disabled': {'type': 'boolean'}, - 'os-flavor-access:is_public': {'type': 'boolean'}, - 'rxtx_factor': {'type': 'number'}, - 'OS-FLV-EXT-DATA:ephemeral': {'type': 'integer'} - }, - 'additionalProperties': False, - # 'OS-FLV-DISABLED', 'os-flavor-access', 'rxtx_factor' and - # 'OS-FLV-EXT-DATA' are API extensions. So they are not 'required'. - 'required': ['name', 'links', 'ram', 'vcpus', 'swap', 'disk', 'id'] -} - -list_flavors_details = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'flavors': { - 'type': 'array', - 'items': common_flavor_info - }, - # NOTE(gmann): flavors_links attribute is not necessary - # to be present always So it is not 'required'. - 'flavors_links': parameter_types.links - }, - 'additionalProperties': False, - 'required': ['flavors'] - } -} - -unset_flavor_extra_specs = { - 'status_code': [200] -} - -create_get_flavor_details = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'flavor': common_flavor_info - }, - 'additionalProperties': False, - 'required': ['flavor'] - } -} - -delete_flavor = { - 'status_code': [202] -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/flavors_access.py b/tempest/lib/api_schema/response/compute/v2_1/flavors_access.py deleted file mode 100644 index a4d6af0d7..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/flavors_access.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright 2014 NEC Corporation. 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. - -add_remove_list_flavor_access = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'flavor_access': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'flavor_id': {'type': 'string'}, - 'tenant_id': {'type': 'string'}, - }, - 'additionalProperties': False, - 'required': ['flavor_id', 'tenant_id'], - } - } - }, - 'additionalProperties': False, - 'required': ['flavor_access'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/flavors_extra_specs.py b/tempest/lib/api_schema/response/compute/v2_1/flavors_extra_specs.py deleted file mode 100644 index a438d4869..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/flavors_extra_specs.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2014 NEC Corporation. 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. - -set_get_flavor_extra_specs = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'extra_specs': { - 'type': 'object', - 'patternProperties': { - '^[a-zA-Z0-9_\-\. :]+$': {'type': 'string'} - } - } - }, - 'additionalProperties': False, - 'required': ['extra_specs'] - } -} - -set_get_flavor_extra_specs_key = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'patternProperties': { - '^[a-zA-Z0-9_\-\. :]+$': {'type': 'string'} - } - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/floating_ips.py b/tempest/lib/api_schema/response/compute/v2_1/floating_ips.py deleted file mode 100644 index 0c665905f..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/floating_ips.py +++ /dev/null @@ -1,148 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -common_floating_ip_info = { - 'type': 'object', - 'properties': { - # NOTE: Now the type of 'id' is integer, but - # here allows 'string' also because we will be - # able to change it to 'uuid' in the future. - 'id': {'type': ['integer', 'string']}, - 'pool': {'type': ['string', 'null']}, - 'instance_id': {'type': ['string', 'null']}, - 'ip': parameter_types.ip_address, - 'fixed_ip': parameter_types.ip_address - }, - 'additionalProperties': False, - 'required': ['id', 'pool', 'instance_id', - 'ip', 'fixed_ip'], - -} -list_floating_ips = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'floating_ips': { - 'type': 'array', - 'items': common_floating_ip_info - }, - }, - 'additionalProperties': False, - 'required': ['floating_ips'], - } -} - -create_get_floating_ip = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'floating_ip': common_floating_ip_info - }, - 'additionalProperties': False, - 'required': ['floating_ip'], - } -} - -list_floating_ip_pools = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'floating_ip_pools': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'name': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['name'], - } - } - }, - 'additionalProperties': False, - 'required': ['floating_ip_pools'], - } -} - -add_remove_floating_ip = { - 'status_code': [202] -} - -create_floating_ips_bulk = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'floating_ips_bulk_create': { - 'type': 'object', - 'properties': { - 'interface': {'type': ['string', 'null']}, - 'ip_range': {'type': 'string'}, - 'pool': {'type': ['string', 'null']}, - }, - 'additionalProperties': False, - 'required': ['interface', 'ip_range', 'pool'], - } - }, - 'additionalProperties': False, - 'required': ['floating_ips_bulk_create'], - } -} - -delete_floating_ips_bulk = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'floating_ips_bulk_delete': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['floating_ips_bulk_delete'], - } -} - -list_floating_ips_bulk = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'floating_ip_info': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'address': parameter_types.ip_address, - 'instance_uuid': {'type': ['string', 'null']}, - 'interface': {'type': ['string', 'null']}, - 'pool': {'type': ['string', 'null']}, - 'project_id': {'type': ['string', 'null']}, - 'fixed_ip': parameter_types.ip_address - }, - 'additionalProperties': False, - # NOTE: fixed_ip is introduced after JUNO release, - # So it is not defined as 'required'. - 'required': ['address', 'instance_uuid', 'interface', - 'pool', 'project_id'], - } - } - }, - 'additionalProperties': False, - 'required': ['floating_ip_info'], - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/hosts.py b/tempest/lib/api_schema/response/compute/v2_1/hosts.py deleted file mode 100644 index cae343597..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/hosts.py +++ /dev/null @@ -1,119 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 copy - - -list_hosts = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'hosts': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'host_name': {'type': 'string'}, - 'service': {'type': 'string'}, - 'zone': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['host_name', 'service', 'zone'] - } - } - }, - 'additionalProperties': False, - 'required': ['hosts'] - } -} - -get_host_detail = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'host': { - 'type': 'array', - 'item': { - 'type': 'object', - 'properties': { - 'resource': { - 'type': 'object', - 'properties': { - 'cpu': {'type': 'integer'}, - 'disk_gb': {'type': 'integer'}, - 'host': {'type': 'string'}, - 'memory_mb': {'type': 'integer'}, - 'project': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['cpu', 'disk_gb', 'host', - 'memory_mb', 'project'] - } - }, - 'additionalProperties': False, - 'required': ['resource'] - } - } - }, - 'additionalProperties': False, - 'required': ['host'] - } -} - -startup_host = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'host': {'type': 'string'}, - 'power_action': {'enum': ['startup']} - }, - 'additionalProperties': False, - 'required': ['host', 'power_action'] - } -} - -# The 'power_action' attribute of 'shutdown_host' API is 'shutdown' -shutdown_host = copy.deepcopy(startup_host) - -shutdown_host['response_body']['properties']['power_action'] = { - 'enum': ['shutdown'] -} - -# The 'power_action' attribute of 'reboot_host' API is 'reboot' -reboot_host = copy.deepcopy(startup_host) - -reboot_host['response_body']['properties']['power_action'] = { - 'enum': ['reboot'] -} - -update_host = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'host': {'type': 'string'}, - 'maintenance_mode': {'enum': ['on_maintenance', - 'off_maintenance']}, - 'status': {'enum': ['enabled', 'disabled']} - }, - 'additionalProperties': False, - 'anyOf': [ - {'required': ['host', 'status']}, - {'required': ['host', 'maintenance_mode']} - ] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/hypervisors.py b/tempest/lib/api_schema/response/compute/v2_1/hypervisors.py deleted file mode 100644 index d15b4f66a..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/hypervisors.py +++ /dev/null @@ -1,195 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 copy - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -get_hypervisor_statistics = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'hypervisor_statistics': { - 'type': 'object', - 'properties': { - 'count': {'type': 'integer'}, - 'current_workload': {'type': 'integer'}, - 'disk_available_least': {'type': ['integer', 'null']}, - 'free_disk_gb': {'type': 'integer'}, - 'free_ram_mb': {'type': 'integer'}, - 'local_gb': {'type': 'integer'}, - 'local_gb_used': {'type': 'integer'}, - 'memory_mb': {'type': 'integer'}, - 'memory_mb_used': {'type': 'integer'}, - 'running_vms': {'type': 'integer'}, - 'vcpus': {'type': 'integer'}, - 'vcpus_used': {'type': 'integer'} - }, - 'additionalProperties': False, - 'required': ['count', 'current_workload', - 'disk_available_least', 'free_disk_gb', - 'free_ram_mb', 'local_gb', 'local_gb_used', - 'memory_mb', 'memory_mb_used', 'running_vms', - 'vcpus', 'vcpus_used'] - } - }, - 'additionalProperties': False, - 'required': ['hypervisor_statistics'] - } -} - - -hypervisor_detail = { - 'type': 'object', - 'properties': { - 'status': {'type': 'string'}, - 'state': {'type': 'string'}, - 'cpu_info': {'type': 'string'}, - 'current_workload': {'type': 'integer'}, - 'disk_available_least': {'type': ['integer', 'null']}, - 'host_ip': parameter_types.ip_address, - 'free_disk_gb': {'type': 'integer'}, - 'free_ram_mb': {'type': 'integer'}, - 'hypervisor_hostname': {'type': 'string'}, - 'hypervisor_type': {'type': 'string'}, - 'hypervisor_version': {'type': 'integer'}, - 'id': {'type': ['integer', 'string']}, - 'local_gb': {'type': 'integer'}, - 'local_gb_used': {'type': 'integer'}, - 'memory_mb': {'type': 'integer'}, - 'memory_mb_used': {'type': 'integer'}, - 'running_vms': {'type': 'integer'}, - 'service': { - 'type': 'object', - 'properties': { - 'host': {'type': 'string'}, - 'id': {'type': ['integer', 'string']}, - 'disabled_reason': {'type': ['string', 'null']} - }, - 'additionalProperties': False, - 'required': ['host', 'id'] - }, - 'vcpus': {'type': 'integer'}, - 'vcpus_used': {'type': 'integer'} - }, - 'additionalProperties': False, - # NOTE: When loading os-hypervisor-status extension, - # a response contains status and state. So these params - # should not be required. - 'required': ['cpu_info', 'current_workload', - 'disk_available_least', 'host_ip', - 'free_disk_gb', 'free_ram_mb', - 'hypervisor_hostname', 'hypervisor_type', - 'hypervisor_version', 'id', 'local_gb', - 'local_gb_used', 'memory_mb', 'memory_mb_used', - 'running_vms', 'service', 'vcpus', 'vcpus_used'] -} - -list_hypervisors_detail = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'hypervisors': { - 'type': 'array', - 'items': hypervisor_detail - } - }, - 'additionalProperties': False, - 'required': ['hypervisors'] - } -} - -get_hypervisor = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'hypervisor': hypervisor_detail - }, - 'additionalProperties': False, - 'required': ['hypervisor'] - } -} - -list_search_hypervisors = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'hypervisors': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'status': {'type': 'string'}, - 'state': {'type': 'string'}, - 'id': {'type': ['integer', 'string']}, - 'hypervisor_hostname': {'type': 'string'} - }, - 'additionalProperties': False, - # NOTE: When loading os-hypervisor-status extension, - # a response contains status and state. So these params - # should not be required. - 'required': ['id', 'hypervisor_hostname'] - } - } - }, - 'additionalProperties': False, - 'required': ['hypervisors'] - } -} - -get_hypervisor_uptime = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'hypervisor': { - 'type': 'object', - 'properties': { - 'status': {'type': 'string'}, - 'state': {'type': 'string'}, - 'id': {'type': ['integer', 'string']}, - 'hypervisor_hostname': {'type': 'string'}, - 'uptime': {'type': 'string'} - }, - 'additionalProperties': False, - # NOTE: When loading os-hypervisor-status extension, - # a response contains status and state. So these params - # should not be required. - 'required': ['id', 'hypervisor_hostname', 'uptime'] - } - }, - 'additionalProperties': False, - 'required': ['hypervisor'] - } -} - -get_hypervisors_servers = copy.deepcopy(list_search_hypervisors) -get_hypervisors_servers['response_body']['properties']['hypervisors']['items'][ - 'properties']['servers'] = { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'uuid': {'type': 'string'}, - 'name': {'type': 'string'} - }, - 'additionalProperties': False, - } - } -# In V2 API, if there is no servers (VM) on the Hypervisor host then 'servers' -# attribute will not be present in response body So it is not 'required'. diff --git a/tempest/lib/api_schema/response/compute/v2_1/images.py b/tempest/lib/api_schema/response/compute/v2_1/images.py deleted file mode 100644 index 156ff4ac6..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/images.py +++ /dev/null @@ -1,156 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 copy - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -image_links = copy.deepcopy(parameter_types.links) -image_links['items']['properties'].update({'type': {'type': 'string'}}) - -image_status_enums = ['ACTIVE', 'SAVING', 'DELETED', 'ERROR', 'UNKNOWN'] - -common_image_schema = { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'status': {'enum': image_status_enums}, - 'updated': parameter_types.date_time, - 'links': image_links, - 'name': {'type': ['string', 'null']}, - 'created': parameter_types.date_time, - 'minDisk': {'type': 'integer'}, - 'minRam': {'type': 'integer'}, - 'progress': {'type': 'integer'}, - 'metadata': {'type': 'object'}, - 'server': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'links': parameter_types.links - }, - 'additionalProperties': False, - 'required': ['id', 'links'] - }, - 'OS-EXT-IMG-SIZE:size': {'type': ['integer', 'null']}, - 'OS-DCF:diskConfig': {'type': 'string'} - }, - 'additionalProperties': False, - # 'server' attributes only comes in response body if image is - # associated with any server. 'OS-EXT-IMG-SIZE:size' & 'OS-DCF:diskConfig' - # are API extension, So those are not defined as 'required'. - 'required': ['id', 'status', 'updated', 'links', 'name', - 'created', 'minDisk', 'minRam', 'progress', - 'metadata'] -} - -get_image = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'image': common_image_schema - }, - 'additionalProperties': False, - 'required': ['image'] - } -} - -list_images = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'images': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'links': image_links, - 'name': {'type': ['string', 'null']} - }, - 'additionalProperties': False, - 'required': ['id', 'links', 'name'] - } - }, - 'images_links': parameter_types.links - }, - 'additionalProperties': False, - # NOTE(gmann): images_links attribute is not necessary to be - # present always So it is not 'required'. - 'required': ['images'] - } -} - -create_image = { - 'status_code': [202], - 'response_header': { - 'type': 'object', - 'properties': parameter_types.response_header - } -} -create_image['response_header']['properties'].update( - {'location': { - 'type': 'string', - 'format': 'uri'} - } -) -create_image['response_header']['required'] = ['location'] - -delete = { - 'status_code': [204] -} - -image_metadata = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'metadata': {'type': 'object'} - }, - 'additionalProperties': False, - 'required': ['metadata'] - } -} - -image_meta_item = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'meta': {'type': 'object'} - }, - 'additionalProperties': False, - 'required': ['meta'] - } -} - -list_images_details = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'images': { - 'type': 'array', - 'items': common_image_schema - }, - 'images_links': parameter_types.links - }, - 'additionalProperties': False, - # NOTE(gmann): images_links attribute is not necessary to be - # present always So it is not 'required'. - 'required': ['images'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/instance_usage_audit_logs.py b/tempest/lib/api_schema/response/compute/v2_1/instance_usage_audit_logs.py deleted file mode 100644 index 15224c5a0..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/instance_usage_audit_logs.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright 2014 NEC Corporation. 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. - -common_instance_usage_audit_log = { - 'type': 'object', - 'properties': { - 'hosts_not_run': { - 'type': 'array', - 'items': {'type': 'string'} - }, - 'log': { - 'type': 'object', - 'patternProperties': { - # NOTE: Here is a host name. - '^.+$': { - 'type': 'object', - 'properties': { - 'state': {'type': 'string'}, - 'instances': {'type': 'integer'}, - 'errors': {'type': 'integer'}, - 'message': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['state', 'instances', 'errors', 'message'] - } - } - }, - 'num_hosts': {'type': 'integer'}, - 'num_hosts_done': {'type': 'integer'}, - 'num_hosts_not_run': {'type': 'integer'}, - 'num_hosts_running': {'type': 'integer'}, - 'overall_status': {'type': 'string'}, - 'period_beginning': {'type': 'string'}, - 'period_ending': {'type': 'string'}, - 'total_errors': {'type': 'integer'}, - 'total_instances': {'type': 'integer'} - }, - 'additionalProperties': False, - 'required': ['hosts_not_run', 'log', 'num_hosts', 'num_hosts_done', - 'num_hosts_not_run', 'num_hosts_running', 'overall_status', - 'period_beginning', 'period_ending', 'total_errors', - 'total_instances'] -} - -get_instance_usage_audit_log = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'instance_usage_audit_log': common_instance_usage_audit_log - }, - 'additionalProperties': False, - 'required': ['instance_usage_audit_log'] - } -} - -list_instance_usage_audit_log = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'instance_usage_audit_logs': common_instance_usage_audit_log - }, - 'additionalProperties': False, - 'required': ['instance_usage_audit_logs'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/interfaces.py b/tempest/lib/api_schema/response/compute/v2_1/interfaces.py deleted file mode 100644 index 99847502c..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/interfaces.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -interface_common_info = { - 'type': 'object', - 'properties': { - 'port_state': {'type': 'string'}, - 'fixed_ips': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'subnet_id': { - 'type': 'string', - 'format': 'uuid' - }, - 'ip_address': parameter_types.ip_address - }, - 'additionalProperties': False, - 'required': ['subnet_id', 'ip_address'] - } - }, - 'port_id': {'type': 'string', 'format': 'uuid'}, - 'net_id': {'type': 'string', 'format': 'uuid'}, - 'mac_addr': parameter_types.mac_address - }, - 'additionalProperties': False, - 'required': ['port_state', 'fixed_ips', 'port_id', 'net_id', 'mac_addr'] -} - -get_create_interfaces = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'interfaceAttachment': interface_common_info - }, - 'additionalProperties': False, - 'required': ['interfaceAttachment'] - } -} - -list_interfaces = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'interfaceAttachments': { - 'type': 'array', - 'items': interface_common_info - } - }, - 'additionalProperties': False, - 'required': ['interfaceAttachments'] - } -} - -delete_interface = { - 'status_code': [202] -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/keypairs.py b/tempest/lib/api_schema/response/compute/v2_1/keypairs.py deleted file mode 100644 index e7dcf791d..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/keypairs.py +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -get_keypair = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'keypair': { - 'type': 'object', - 'properties': { - 'public_key': {'type': 'string'}, - 'name': {'type': 'string'}, - 'fingerprint': {'type': 'string'}, - 'user_id': {'type': 'string'}, - 'deleted': {'type': 'boolean'}, - 'created_at': parameter_types.date_time, - 'updated_at': parameter_types.date_time_or_null, - 'deleted_at': parameter_types.date_time_or_null, - 'id': {'type': 'integer'} - - }, - 'additionalProperties': False, - 'required': ['public_key', 'name', 'fingerprint', 'user_id', - 'deleted', 'created_at', 'updated_at', - 'deleted_at', 'id'] - } - }, - 'additionalProperties': False, - 'required': ['keypair'] - } -} - -create_keypair = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'keypair': { - 'type': 'object', - 'properties': { - 'fingerprint': {'type': 'string'}, - 'name': {'type': 'string'}, - 'public_key': {'type': 'string'}, - 'user_id': {'type': 'string'}, - 'private_key': {'type': 'string'} - }, - 'additionalProperties': False, - # When create keypair API is being called with 'Public key' - # (Importing keypair) then, response body does not contain - # 'private_key' So it is not defined as 'required' - 'required': ['fingerprint', 'name', 'public_key', 'user_id'] - } - }, - 'additionalProperties': False, - 'required': ['keypair'] - } -} - -delete_keypair = { - 'status_code': [202], -} - -list_keypairs = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'keypairs': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'keypair': { - 'type': 'object', - 'properties': { - 'public_key': {'type': 'string'}, - 'name': {'type': 'string'}, - 'fingerprint': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['public_key', 'name', 'fingerprint'] - } - }, - 'additionalProperties': False, - 'required': ['keypair'] - } - } - }, - 'additionalProperties': False, - 'required': ['keypairs'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/limits.py b/tempest/lib/api_schema/response/compute/v2_1/limits.py deleted file mode 100644 index 81f175fa7..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/limits.py +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright 2014 NEC Corporation. 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. - -get_limit = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'limits': { - 'type': 'object', - 'properties': { - 'absolute': { - 'type': 'object', - 'properties': { - 'maxTotalRAMSize': {'type': 'integer'}, - 'totalCoresUsed': {'type': 'integer'}, - 'maxTotalInstances': {'type': 'integer'}, - 'maxTotalFloatingIps': {'type': 'integer'}, - 'totalSecurityGroupsUsed': {'type': 'integer'}, - 'maxTotalCores': {'type': 'integer'}, - 'totalFloatingIpsUsed': {'type': 'integer'}, - 'maxSecurityGroups': {'type': 'integer'}, - 'maxServerMeta': {'type': 'integer'}, - 'maxPersonality': {'type': 'integer'}, - 'maxImageMeta': {'type': 'integer'}, - 'maxPersonalitySize': {'type': 'integer'}, - 'maxSecurityGroupRules': {'type': 'integer'}, - 'maxTotalKeypairs': {'type': 'integer'}, - 'totalRAMUsed': {'type': 'integer'}, - 'totalInstancesUsed': {'type': 'integer'}, - 'maxServerGroupMembers': {'type': 'integer'}, - 'maxServerGroups': {'type': 'integer'}, - 'totalServerGroupsUsed': {'type': 'integer'} - }, - 'additionalProperties': False, - # NOTE(gmann): maxServerGroupMembers, maxServerGroups - # and totalServerGroupsUsed are API extension, - # and some environments return a response without these - # attributes.So they are not 'required'. - 'required': ['maxImageMeta', - 'maxPersonality', - 'maxPersonalitySize', - 'maxSecurityGroupRules', - 'maxSecurityGroups', - 'maxServerMeta', - 'maxTotalCores', - 'maxTotalFloatingIps', - 'maxTotalInstances', - 'maxTotalKeypairs', - 'maxTotalRAMSize', - 'totalCoresUsed', - 'totalFloatingIpsUsed', - 'totalInstancesUsed', - 'totalRAMUsed', - 'totalSecurityGroupsUsed'] - }, - 'rate': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'limit': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'next-available': - {'type': 'string'}, - 'remaining': - {'type': 'integer'}, - 'unit': - {'type': 'string'}, - 'value': - {'type': 'integer'}, - 'verb': - {'type': 'string'} - }, - 'additionalProperties': False, - } - }, - 'regex': {'type': 'string'}, - 'uri': {'type': 'string'} - }, - 'additionalProperties': False, - } - } - }, - 'additionalProperties': False, - 'required': ['absolute', 'rate'] - } - }, - 'additionalProperties': False, - 'required': ['limits'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/migrations.py b/tempest/lib/api_schema/response/compute/v2_1/migrations.py deleted file mode 100644 index c50286d27..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/migrations.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -list_migrations = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'migrations': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': 'integer'}, - 'status': {'type': ['string', 'null']}, - 'instance_uuid': {'type': ['string', 'null']}, - 'source_node': {'type': ['string', 'null']}, - 'source_compute': {'type': ['string', 'null']}, - 'dest_node': {'type': ['string', 'null']}, - 'dest_compute': {'type': ['string', 'null']}, - 'dest_host': {'type': ['string', 'null']}, - 'old_instance_type_id': {'type': ['integer', 'null']}, - 'new_instance_type_id': {'type': ['integer', 'null']}, - 'created_at': parameter_types.date_time, - 'updated_at': parameter_types.date_time_or_null - }, - 'additionalProperties': False, - 'required': [ - 'id', 'status', 'instance_uuid', 'source_node', - 'source_compute', 'dest_node', 'dest_compute', - 'dest_host', 'old_instance_type_id', - 'new_instance_type_id', 'created_at', 'updated_at' - ] - } - } - }, - 'additionalProperties': False, - 'required': ['migrations'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/parameter_types.py b/tempest/lib/api_schema/response/compute/v2_1/parameter_types.py deleted file mode 100644 index a3c9099ea..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/parameter_types.py +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright 2014 NEC Corporation. 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. - -links = { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'href': { - 'type': 'string', - 'format': 'uri' - }, - 'rel': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['href', 'rel'] - } -} - -mac_address = { - 'type': 'string', - 'pattern': '(?:[a-f0-9]{2}:){5}[a-f0-9]{2}' -} - -ip_address = { - 'oneOf': [ - { - 'type': 'string', - 'oneOf': [ - {'format': 'ipv4'}, - {'format': 'ipv6'} - ] - }, - {'type': 'null'} - ] -} - -access_ip_v4 = { - 'type': 'string', - 'oneOf': [{'format': 'ipv4'}, {'enum': ['']}] -} - -access_ip_v6 = { - 'type': 'string', - 'oneOf': [{'format': 'ipv6'}, {'enum': ['']}] -} - -addresses = { - 'type': 'object', - 'patternProperties': { - # NOTE: Here is for 'private' or something. - '^[a-zA-Z0-9-_.]+$': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'version': {'type': 'integer'}, - 'addr': { - 'type': 'string', - 'oneOf': [ - {'format': 'ipv4'}, - {'format': 'ipv6'} - ] - } - }, - 'additionalProperties': False, - 'required': ['version', 'addr'] - } - } - } -} - -date_time = { - 'type': 'string', - 'format': 'iso8601-date-time' -} - -date_time_or_null = { - 'type': ['string', 'null'], - 'format': 'iso8601-date-time' -} - -response_header = { - 'connection': {'type': 'string'}, - 'content-length': {'type': 'string'}, - 'content-type': {'type': 'string'}, - 'status': {'type': 'string'}, - 'x-compute-request-id': {'type': 'string'}, - 'vary': {'type': 'string'}, - 'x-openstack-nova-api-version': {'type': 'string'}, - # NOTE(gmann): Validating this as string only as this - # date in header is returned in different format than - # ISO 8601 date time format which is not consistent with - # other date-time format in nova. - # This API is already deprecated so not worth to fix - # on nova side. - 'date': { - 'type': 'string' - } -} - -power_state = { - 'type': 'integer', - # 0: NOSTATE - # 1: RUNNING - # 3: PAUSED - # 4: SHUTDOWN - # 6: CRASHED - # 7: SUSPENDED - 'enum': [0, 1, 3, 4, 6, 7] -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/quota_classes.py b/tempest/lib/api_schema/response/compute/v2_1/quota_classes.py deleted file mode 100644 index 03d7f1281..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/quota_classes.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2014 IBM Corporation. -# 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 copy - -from tempest.lib.api_schema.response.compute.v2_1 import quotas - -# NOTE(mriedem): os-quota-class-sets responses are the same as os-quota-sets -# except for the key in the response body is quota_class_set instead of -# quota_set, so update this copy of the schema from os-quota-sets. -get_quota_class_set = copy.deepcopy(quotas.get_quota_set) -get_quota_class_set['response_body']['properties']['quota_class_set'] = ( - get_quota_class_set['response_body']['properties'].pop('quota_set')) -get_quota_class_set['response_body']['required'] = ['quota_class_set'] - -update_quota_class_set = copy.deepcopy(quotas.update_quota_set) -update_quota_class_set['response_body']['properties']['quota_class_set'] = ( - update_quota_class_set['response_body']['properties'].pop('quota_set')) -update_quota_class_set['response_body']['required'] = ['quota_class_set'] diff --git a/tempest/lib/api_schema/response/compute/v2_1/quotas.py b/tempest/lib/api_schema/response/compute/v2_1/quotas.py deleted file mode 100644 index 44f5bdfd2..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/quotas.py +++ /dev/null @@ -1,183 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 copy - -update_quota_set = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'quota_set': { - 'type': 'object', - 'properties': { - 'instances': {'type': 'integer'}, - 'cores': {'type': 'integer'}, - 'ram': {'type': 'integer'}, - 'floating_ips': {'type': 'integer'}, - 'fixed_ips': {'type': 'integer'}, - 'metadata_items': {'type': 'integer'}, - 'key_pairs': {'type': 'integer'}, - 'security_groups': {'type': 'integer'}, - 'security_group_rules': {'type': 'integer'}, - 'server_group_members': {'type': 'integer'}, - 'server_groups': {'type': 'integer'}, - 'injected_files': {'type': 'integer'}, - 'injected_file_content_bytes': {'type': 'integer'}, - 'injected_file_path_bytes': {'type': 'integer'} - }, - 'additionalProperties': False, - # NOTE: server_group_members and server_groups are represented - # when enabling quota_server_group extension. So they should - # not be required. - 'required': ['instances', 'cores', 'ram', - 'floating_ips', 'fixed_ips', - 'metadata_items', 'key_pairs', - 'security_groups', 'security_group_rules', - 'injected_files', 'injected_file_content_bytes', - 'injected_file_path_bytes'] - } - }, - 'additionalProperties': False, - 'required': ['quota_set'] - } -} - -get_quota_set = copy.deepcopy(update_quota_set) -get_quota_set['response_body']['properties']['quota_set']['properties'][ - 'id'] = {'type': 'string'} -get_quota_set['response_body']['properties']['quota_set']['required'].extend([ - 'id']) - -get_quota_set_details = copy.deepcopy(get_quota_set) -get_quota_set_details['response_body']['properties']['quota_set'][ - 'properties'] = { - 'id': {'type': 'string'}, - 'instances': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'cores': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'ram': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'floating_ips': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'fixed_ips': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'metadata_items': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'key_pairs': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'security_groups': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'security_group_rules': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'server_group_members': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'server_groups': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'injected_files': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'injected_file_content_bytes': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - }, - 'injected_file_path_bytes': { - 'type': 'object', - 'properties': { - 'reserved': {'type': 'integer'}, - 'limit': {'type': 'integer'}, - 'in_use': {'type': 'integer'} - } - } -} - -delete_quota = { - 'status_code': [202] -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/security_group_default_rule.py b/tempest/lib/api_schema/response/compute/v2_1/security_group_default_rule.py deleted file mode 100644 index 2ec282698..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/security_group_default_rule.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2014 NEC Corporation. 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. - -common_security_group_default_rule_info = { - 'type': 'object', - 'properties': { - 'from_port': {'type': 'integer'}, - 'id': {'type': 'integer'}, - 'ip_protocol': {'type': 'string'}, - 'ip_range': { - 'type': 'object', - 'properties': { - 'cidr': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['cidr'], - }, - 'to_port': {'type': 'integer'}, - }, - 'additionalProperties': False, - 'required': ['from_port', 'id', 'ip_protocol', 'ip_range', 'to_port'], -} - -create_get_security_group_default_rule = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'security_group_default_rule': - common_security_group_default_rule_info - }, - 'additionalProperties': False, - 'required': ['security_group_default_rule'] - } -} - -delete_security_group_default_rule = { - 'status_code': [204] -} - -list_security_group_default_rules = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'security_group_default_rules': { - 'type': 'array', - 'items': common_security_group_default_rule_info - } - }, - 'additionalProperties': False, - 'required': ['security_group_default_rules'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/security_groups.py b/tempest/lib/api_schema/response/compute/v2_1/security_groups.py deleted file mode 100644 index 5ed5a5c80..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/security_groups.py +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright 2014 NEC Corporation. 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. - -common_security_group_rule = { - 'from_port': {'type': ['integer', 'null']}, - 'to_port': {'type': ['integer', 'null']}, - 'group': { - 'type': 'object', - 'properties': { - 'tenant_id': {'type': 'string'}, - 'name': {'type': 'string'} - }, - 'additionalProperties': False, - }, - 'ip_protocol': {'type': ['string', 'null']}, - # 'parent_group_id' can be UUID so defining it as 'string' also. - 'parent_group_id': {'type': ['string', 'integer', 'null']}, - 'ip_range': { - 'type': 'object', - 'properties': { - 'cidr': {'type': 'string'} - }, - 'additionalProperties': False, - # When optional argument is provided in request body - # like 'group_id' then, attribute 'cidr' does not - # comes in response body. So it is not 'required'. - }, - 'id': {'type': ['string', 'integer']} -} - -common_security_group = { - 'type': 'object', - 'properties': { - 'id': {'type': ['integer', 'string']}, - 'name': {'type': 'string'}, - 'tenant_id': {'type': 'string'}, - 'rules': { - 'type': 'array', - 'items': { - 'type': ['object', 'null'], - 'properties': common_security_group_rule, - 'additionalProperties': False, - } - }, - 'description': {'type': 'string'}, - }, - 'additionalProperties': False, - 'required': ['id', 'name', 'tenant_id', 'rules', 'description'], -} - -list_security_groups = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'security_groups': { - 'type': 'array', - 'items': common_security_group - } - }, - 'additionalProperties': False, - 'required': ['security_groups'] - } -} - -get_security_group = create_security_group = update_security_group = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'security_group': common_security_group - }, - 'additionalProperties': False, - 'required': ['security_group'] - } -} - -delete_security_group = { - 'status_code': [202] -} - -create_security_group_rule = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'security_group_rule': { - 'type': 'object', - 'properties': common_security_group_rule, - 'additionalProperties': False, - 'required': ['from_port', 'to_port', 'group', 'ip_protocol', - 'parent_group_id', 'id', 'ip_range'] - } - }, - 'additionalProperties': False, - 'required': ['security_group_rule'] - } -} - -delete_security_group_rule = { - 'status_code': [202] -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/servers.py b/tempest/lib/api_schema/response/compute/v2_1/servers.py deleted file mode 100644 index 2954de005..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/servers.py +++ /dev/null @@ -1,596 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 copy - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -create_server = { - 'status_code': [202], - 'response_body': { - 'type': 'object', - 'properties': { - 'server': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'security_groups': {'type': 'array'}, - 'links': parameter_types.links, - 'OS-DCF:diskConfig': {'type': 'string'} - }, - 'additionalProperties': False, - # NOTE: OS-DCF:diskConfig & security_groups are API extension, - # and some environments return a response without these - # attributes.So they are not 'required'. - 'required': ['id', 'links'] - } - }, - 'additionalProperties': False, - 'required': ['server'] - } -} - -create_server_with_admin_pass = copy.deepcopy(create_server) -create_server_with_admin_pass['response_body']['properties']['server'][ - 'properties'].update({'adminPass': {'type': 'string'}}) -create_server_with_admin_pass['response_body']['properties']['server'][ - 'required'].append('adminPass') - -list_servers = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'servers': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'links': parameter_types.links, - 'name': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['id', 'links', 'name'] - } - }, - 'servers_links': parameter_types.links - }, - 'additionalProperties': False, - # NOTE(gmann): servers_links attribute is not necessary to be - # present always So it is not 'required'. - 'required': ['servers'] - } -} - -delete_server = { - 'status_code': [204], -} - -common_show_server = { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'name': {'type': 'string'}, - 'status': {'type': 'string'}, - 'image': {'oneOf': [ - {'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'links': parameter_types.links - }, - 'additionalProperties': False, - 'required': ['id', 'links']}, - {'type': ['string', 'null']} - ]}, - 'flavor': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'links': parameter_types.links - }, - # NOTE(gmann): This will be empty object if there is no - # flavor info present in DB. This can happen when flavor info is - # deleted after server creation. - 'additionalProperties': False - }, - 'fault': { - 'type': 'object', - 'properties': { - 'code': {'type': 'integer'}, - 'created': {'type': 'string'}, - 'message': {'type': 'string'}, - 'details': {'type': 'string'}, - }, - 'additionalProperties': False, - # NOTE(gmann): 'details' is not necessary to be present - # in the 'fault'. So it is not defined as 'required'. - 'required': ['code', 'created', 'message'] - }, - 'user_id': {'type': 'string'}, - 'tenant_id': {'type': 'string'}, - 'created': parameter_types.date_time, - 'updated': parameter_types.date_time, - 'progress': {'type': 'integer'}, - 'metadata': {'type': 'object'}, - 'links': parameter_types.links, - 'addresses': parameter_types.addresses, - 'hostId': {'type': 'string'}, - 'OS-DCF:diskConfig': {'type': 'string'}, - 'accessIPv4': parameter_types.access_ip_v4, - 'accessIPv6': parameter_types.access_ip_v6 - }, - 'additionalProperties': False, - # NOTE(GMann): 'progress' attribute is present in the response - # only when server's status is one of the progress statuses - # ("ACTIVE","BUILD", "REBUILD", "RESIZE","VERIFY_RESIZE") - # 'fault' attribute is present in the response - # only when server's status is one of the "ERROR", "DELETED". - # OS-DCF:diskConfig and accessIPv4/v6 are API - # extensions, and some environments return a response - # without these attributes.So these are not defined as 'required'. - 'required': ['id', 'name', 'status', 'image', 'flavor', - 'user_id', 'tenant_id', 'created', 'updated', - 'metadata', 'links', 'addresses', 'hostId'] -} - -update_server = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'server': common_show_server - }, - 'additionalProperties': False, - 'required': ['server'] - } -} - -server_detail = copy.deepcopy(common_show_server) -server_detail['properties'].update({ - 'key_name': {'type': ['string', 'null']}, - 'security_groups': {'type': 'array'}, - - # NOTE: Non-admin users also can see "OS-SRV-USG" and "OS-EXT-AZ" - # attributes. - 'OS-SRV-USG:launched_at': {'type': ['string', 'null']}, - 'OS-SRV-USG:terminated_at': {'type': ['string', 'null']}, - 'OS-EXT-AZ:availability_zone': {'type': 'string'}, - - # NOTE: Admin users only can see "OS-EXT-STS" and "OS-EXT-SRV-ATTR" - # attributes. - 'OS-EXT-STS:task_state': {'type': ['string', 'null']}, - 'OS-EXT-STS:vm_state': {'type': 'string'}, - 'OS-EXT-STS:power_state': parameter_types.power_state, - 'OS-EXT-SRV-ATTR:host': {'type': ['string', 'null']}, - 'OS-EXT-SRV-ATTR:instance_name': {'type': 'string'}, - 'OS-EXT-SRV-ATTR:hypervisor_hostname': {'type': ['string', 'null']}, - 'os-extended-volumes:volumes_attached': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'} - }, - 'additionalProperties': False, - }, - }, - 'config_drive': {'type': 'string'} -}) -server_detail['properties']['addresses']['patternProperties'][ - '^[a-zA-Z0-9-_.]+$']['items']['properties'].update({ - 'OS-EXT-IPS:type': {'type': 'string'}, - 'OS-EXT-IPS-MAC:mac_addr': parameter_types.mac_address}) -# NOTE(gmann): Update OS-EXT-IPS:type and OS-EXT-IPS-MAC:mac_addr -# attributes in server address. Those are API extension, -# and some environments return a response without -# these attributes. So they are not 'required'. - -get_server = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'server': server_detail - }, - 'additionalProperties': False, - 'required': ['server'] - } -} - -list_servers_detail = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'servers': { - 'type': 'array', - 'items': server_detail - }, - 'servers_links': parameter_types.links - }, - 'additionalProperties': False, - # NOTE(gmann): servers_links attribute is not necessary to be - # present always So it is not 'required'. - 'required': ['servers'] - } -} - -rebuild_server = copy.deepcopy(update_server) -rebuild_server['status_code'] = [202] - -rebuild_server_with_admin_pass = copy.deepcopy(rebuild_server) -rebuild_server_with_admin_pass['response_body']['properties']['server'][ - 'properties'].update({'adminPass': {'type': 'string'}}) -rebuild_server_with_admin_pass['response_body']['properties']['server'][ - 'required'].append('adminPass') - -rescue_server = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'additionalProperties': False, - } -} - -rescue_server_with_admin_pass = copy.deepcopy(rescue_server) -rescue_server_with_admin_pass['response_body'].update( - {'properties': {'adminPass': {'type': 'string'}}}) -rescue_server_with_admin_pass['response_body'].update( - {'required': ['adminPass']}) - - -list_virtual_interfaces = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'virtual_interfaces': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'mac_address': parameter_types.mac_address, - 'OS-EXT-VIF-NET:net_id': {'type': 'string'} - }, - 'additionalProperties': False, - # 'OS-EXT-VIF-NET:net_id' is API extension So it is - # not defined as 'required' - 'required': ['id', 'mac_address'] - } - } - }, - 'additionalProperties': False, - 'required': ['virtual_interfaces'] - } -} - -common_attach_volume_info = { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'device': {'type': ['string', 'null']}, - 'volumeId': {'type': 'string'}, - 'serverId': {'type': ['integer', 'string']} - }, - 'additionalProperties': False, - # 'device' is optional in response. - 'required': ['id', 'volumeId', 'serverId'] -} - -attach_volume = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'volumeAttachment': common_attach_volume_info - }, - 'additionalProperties': False, - 'required': ['volumeAttachment'] - } -} - -detach_volume = { - 'status_code': [202] -} - -show_volume_attachment = copy.deepcopy(attach_volume) -show_volume_attachment['response_body']['properties'][ - 'volumeAttachment']['properties'].update({'serverId': {'type': 'string'}}) - -list_volume_attachments = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'volumeAttachments': { - 'type': 'array', - 'items': common_attach_volume_info - } - }, - 'additionalProperties': False, - 'required': ['volumeAttachments'] - } -} -list_volume_attachments['response_body']['properties'][ - 'volumeAttachments']['items']['properties'].update( - {'serverId': {'type': 'string'}}) - -list_addresses_by_network = { - 'status_code': [200], - 'response_body': parameter_types.addresses -} - -list_addresses = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'addresses': parameter_types.addresses - }, - 'additionalProperties': False, - 'required': ['addresses'] - } -} - -common_server_group = { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'name': {'type': 'string'}, - 'policies': { - 'type': 'array', - 'items': {'type': 'string'} - }, - # 'members' attribute contains the array of instance's UUID of - # instances present in server group - 'members': { - 'type': 'array', - 'items': {'type': 'string'} - }, - 'metadata': {'type': 'object'} - }, - 'additionalProperties': False, - 'required': ['id', 'name', 'policies', 'members', 'metadata'] -} - -create_show_server_group = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'server_group': common_server_group - }, - 'additionalProperties': False, - 'required': ['server_group'] - } -} - -delete_server_group = { - 'status_code': [204] -} - -list_server_groups = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'server_groups': { - 'type': 'array', - 'items': common_server_group - } - }, - 'additionalProperties': False, - 'required': ['server_groups'] - } -} - -instance_actions = { - 'type': 'object', - 'properties': { - 'action': {'type': 'string'}, - 'request_id': {'type': 'string'}, - 'user_id': {'type': 'string'}, - 'project_id': {'type': 'string'}, - 'start_time': parameter_types.date_time, - 'message': {'type': ['string', 'null']}, - 'instance_uuid': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['action', 'request_id', 'user_id', 'project_id', - 'start_time', 'message', 'instance_uuid'] -} - -instance_action_events = { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'event': {'type': 'string'}, - 'start_time': parameter_types.date_time, - # The finish_time, result and optionally traceback are all - # possibly None (null) until the event is actually finished. - # The traceback would only be set if there was an error, but - # when the event is complete both finish_time and result will - # be set. - 'finish_time': parameter_types.date_time_or_null, - 'result': {'type': ['string', 'null']}, - 'traceback': {'type': ['string', 'null']} - }, - 'additionalProperties': False, - 'required': ['event', 'start_time', 'finish_time', 'result', - 'traceback'] - } -} - -list_instance_actions = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'instanceActions': { - 'type': 'array', - 'items': instance_actions - } - }, - 'additionalProperties': False, - 'required': ['instanceActions'] - } -} - -instance_actions_with_events = copy.deepcopy(instance_actions) -instance_actions_with_events['properties'].update({ - 'events': instance_action_events}) -# 'events' does not come in response body always so it is not -# defined as 'required' - -show_instance_action = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'instanceAction': instance_actions_with_events - }, - 'additionalProperties': False, - 'required': ['instanceAction'] - } -} - -show_password = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'password': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['password'] - } -} - -get_vnc_console = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'console': { - 'type': 'object', - 'properties': { - 'type': {'type': 'string'}, - 'url': { - 'type': 'string', - 'format': 'uri' - } - }, - 'additionalProperties': False, - 'required': ['type', 'url'] - } - }, - 'additionalProperties': False, - 'required': ['console'] - } -} - -get_console_output = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'output': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['output'] - } -} - -set_server_metadata = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'metadata': { - 'type': 'object', - 'patternProperties': { - '^.+$': {'type': 'string'} - } - } - }, - 'additionalProperties': False, - 'required': ['metadata'] - } -} - -list_server_metadata = copy.deepcopy(set_server_metadata) - -update_server_metadata = copy.deepcopy(set_server_metadata) - -delete_server_metadata_item = { - 'status_code': [204] -} - -set_show_server_metadata_item = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'meta': { - 'type': 'object', - 'patternProperties': { - '^.+$': {'type': 'string'} - } - } - }, - 'additionalProperties': False, - 'required': ['meta'] - } -} - -server_actions_common_schema = { - 'status_code': [202] -} - -server_actions_delete_password = { - 'status_code': [204] -} - -server_actions_confirm_resize = copy.deepcopy( - server_actions_delete_password) - -update_attached_volume = { - 'status_code': [202] -} - -evacuate_server = { - 'status_code': [200] -} - -evacuate_server_with_admin_pass = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'adminPass': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['adminPass'] - } -} - -show_server_diagnostics = { - 'status_code': [200], - 'response_body': { - 'type': 'object' - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/services.py b/tempest/lib/api_schema/response/compute/v2_1/services.py deleted file mode 100644 index 3b58ece48..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/services.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -list_services = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'services': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': ['integer', 'string'], - 'pattern': '^[a-zA-Z!]*@[0-9]+$'}, - 'zone': {'type': 'string'}, - 'host': {'type': 'string'}, - 'state': {'type': 'string'}, - 'binary': {'type': 'string'}, - 'status': {'type': 'string'}, - 'updated_at': parameter_types.date_time_or_null, - 'disabled_reason': {'type': ['string', 'null']} - }, - 'additionalProperties': False, - 'required': ['id', 'zone', 'host', 'state', 'binary', - 'status', 'updated_at', 'disabled_reason'] - } - } - }, - 'additionalProperties': False, - 'required': ['services'] - } -} - -enable_disable_service = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'service': { - 'type': 'object', - 'properties': { - 'status': {'type': 'string'}, - 'binary': {'type': 'string'}, - 'host': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['status', 'binary', 'host'] - } - }, - 'additionalProperties': False, - 'required': ['service'] - } -} - -disable_log_reason = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'service': { - 'type': 'object', - 'properties': { - 'disabled_reason': {'type': 'string'}, - 'binary': {'type': 'string'}, - 'host': {'type': 'string'}, - 'status': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['disabled_reason', 'binary', 'host', 'status'] - } - }, - 'additionalProperties': False, - 'required': ['service'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/snapshots.py b/tempest/lib/api_schema/response/compute/v2_1/snapshots.py deleted file mode 100644 index 826f85413..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/snapshots.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2015 Fujitsu(fnst) Corporation -# 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 tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -common_snapshot_info = { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'volumeId': {'type': 'string'}, - 'status': {'type': 'string'}, - 'size': {'type': 'integer'}, - 'createdAt': parameter_types.date_time, - 'displayName': {'type': ['string', 'null']}, - 'displayDescription': {'type': ['string', 'null']} - }, - 'additionalProperties': False, - 'required': ['id', 'volumeId', 'status', 'size', - 'createdAt', 'displayName', 'displayDescription'] -} - -create_get_snapshot = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'snapshot': common_snapshot_info - }, - 'additionalProperties': False, - 'required': ['snapshot'] - } -} - -list_snapshots = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'snapshots': { - 'type': 'array', - 'items': common_snapshot_info - } - }, - 'additionalProperties': False, - 'required': ['snapshots'] - } -} - -delete_snapshot = { - 'status_code': [202] -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/tenant_networks.py b/tempest/lib/api_schema/response/compute/v2_1/tenant_networks.py deleted file mode 100644 index ddfab9619..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/tenant_networks.py +++ /dev/null @@ -1,53 +0,0 @@ -# Copyright 2015 NEC Corporation. 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. - -param_network = { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'cidr': {'type': ['string', 'null']}, - 'label': {'type': 'string'} - }, - 'additionalProperties': False, - 'required': ['id', 'cidr', 'label'] -} - - -list_tenant_networks = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'networks': { - 'type': 'array', - 'items': param_network - } - }, - 'additionalProperties': False, - 'required': ['networks'] - } -} - - -get_tenant_network = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'network': param_network - }, - 'additionalProperties': False, - 'required': ['network'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/tenant_usages.py b/tempest/lib/api_schema/response/compute/v2_1/tenant_usages.py deleted file mode 100644 index b531d2e75..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/tenant_usages.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 copy - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -_server_usages = { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'ended_at': parameter_types.date_time_or_null, - 'flavor': {'type': 'string'}, - 'hours': {'type': 'number'}, - 'instance_id': {'type': 'string'}, - 'local_gb': {'type': 'integer'}, - 'memory_mb': {'type': 'integer'}, - 'name': {'type': 'string'}, - 'started_at': parameter_types.date_time, - 'state': {'type': 'string'}, - 'tenant_id': {'type': 'string'}, - 'uptime': {'type': 'integer'}, - 'vcpus': {'type': 'integer'}, - }, - 'required': ['ended_at', 'flavor', 'hours', 'instance_id', 'local_gb', - 'memory_mb', 'name', 'started_at', 'state', 'tenant_id', - 'uptime', 'vcpus'] - } -} - -_tenant_usage_list = { - 'type': 'object', - 'properties': { - 'server_usages': _server_usages, - 'start': parameter_types.date_time, - 'stop': parameter_types.date_time, - 'tenant_id': {'type': 'string'}, - 'total_hours': {'type': 'number'}, - 'total_local_gb_usage': {'type': 'number'}, - 'total_memory_mb_usage': {'type': 'number'}, - 'total_vcpus_usage': {'type': 'number'}, - }, - 'required': ['start', 'stop', 'tenant_id', - 'total_hours', 'total_local_gb_usage', - 'total_memory_mb_usage', 'total_vcpus_usage'] -} - -# 'required' of get_tenant is different from list_tenant's. -_tenant_usage_get = copy.deepcopy(_tenant_usage_list) -_tenant_usage_get['required'] = ['server_usages', 'start', 'stop', 'tenant_id', - 'total_hours', 'total_local_gb_usage', - 'total_memory_mb_usage', 'total_vcpus_usage'] - -list_tenant_usage = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'tenant_usages': { - 'type': 'array', - 'items': _tenant_usage_list - } - }, - 'required': ['tenant_usages'] - } -} - -get_tenant_usage = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'tenant_usage': _tenant_usage_get - }, - 'required': ['tenant_usage'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/versions.py b/tempest/lib/api_schema/response/compute/v2_1/versions.py deleted file mode 100644 index 7f5623928..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/versions.py +++ /dev/null @@ -1,112 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 copy - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types - - -_version = { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'links': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'href': {'type': 'string', 'format': 'uri'}, - 'rel': {'type': 'string'}, - 'type': {'type': 'string'}, - }, - 'required': ['href', 'rel'], - 'additionalProperties': False - } - }, - 'status': {'type': 'string'}, - 'updated': parameter_types.date_time, - 'version': {'type': 'string'}, - 'min_version': {'type': 'string'}, - 'media-types': { - 'type': 'array', - 'properties': { - 'base': {'type': 'string'}, - 'type': {'type': 'string'}, - } - }, - }, - # NOTE: version and min_version have been added since Kilo, - # so they should not be required. - # NOTE(sdague): media-types only shows up in single version requests. - 'required': ['id', 'links', 'status', 'updated'], - 'additionalProperties': False -} - -list_versions = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'versions': { - 'type': 'array', - 'items': _version - } - }, - 'required': ['versions'], - 'additionalProperties': False - } -} - - -_detail_get_version = copy.deepcopy(_version) -_detail_get_version['properties'].pop('min_version') -_detail_get_version['properties'].pop('version') -_detail_get_version['properties'].pop('updated') -_detail_get_version['properties']['media-types'] = { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'base': {'type': 'string'}, - 'type': {'type': 'string'} - } - } -} -_detail_get_version['required'] = ['id', 'links', 'status', 'media-types'] - -get_version = { - 'status_code': [300], - 'response_body': { - 'type': 'object', - 'properties': { - 'choices': { - 'type': 'array', - 'items': _detail_get_version - } - }, - 'required': ['choices'], - 'additionalProperties': False - } -} - -get_one_version = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'version': _version - }, - 'additionalProperties': False - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_1/volumes.py b/tempest/lib/api_schema/response/compute/v2_1/volumes.py deleted file mode 100644 index c35dae981..000000000 --- a/tempest/lib/api_schema/response/compute/v2_1/volumes.py +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -create_get_volume = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'volume': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'status': {'type': 'string'}, - 'displayName': {'type': ['string', 'null']}, - 'availabilityZone': {'type': 'string'}, - 'createdAt': parameter_types.date_time, - 'displayDescription': {'type': ['string', 'null']}, - 'volumeType': {'type': ['string', 'null']}, - 'snapshotId': {'type': ['string', 'null']}, - 'metadata': {'type': 'object'}, - 'size': {'type': 'integer'}, - 'attachments': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'device': {'type': 'string'}, - 'volumeId': {'type': 'string'}, - 'serverId': {'type': 'string'} - }, - 'additionalProperties': False, - # NOTE- If volume is not attached to any server - # then, 'attachments' attributes comes as array - # with empty objects "[{}]" due to that elements - # of 'attachments' cannot defined as 'required'. - # If it would come as empty array "[]" then, - # those elements can be defined as 'required'. - } - } - }, - 'additionalProperties': False, - 'required': ['id', 'status', 'displayName', 'availabilityZone', - 'createdAt', 'displayDescription', 'volumeType', - 'snapshotId', 'metadata', 'size', 'attachments'] - } - }, - 'additionalProperties': False, - 'required': ['volume'] - } -} - -list_volumes = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'volumes': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'status': {'type': 'string'}, - 'displayName': {'type': ['string', 'null']}, - 'availabilityZone': {'type': 'string'}, - 'createdAt': parameter_types.date_time, - 'displayDescription': {'type': ['string', 'null']}, - 'volumeType': {'type': ['string', 'null']}, - 'snapshotId': {'type': ['string', 'null']}, - 'metadata': {'type': 'object'}, - 'size': {'type': 'integer'}, - 'attachments': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'device': {'type': 'string'}, - 'volumeId': {'type': 'string'}, - 'serverId': {'type': 'string'} - }, - 'additionalProperties': False, - # NOTE- If volume is not attached to any server - # then, 'attachments' attributes comes as array - # with empty object "[{}]" due to that elements - # of 'attachments' cannot defined as 'required' - # If it would come as empty array "[]" then, - # those elements can be defined as 'required'. - } - } - }, - 'additionalProperties': False, - 'required': ['id', 'status', 'displayName', - 'availabilityZone', 'createdAt', - 'displayDescription', 'volumeType', - 'snapshotId', 'metadata', 'size', - 'attachments'] - } - } - }, - 'additionalProperties': False, - 'required': ['volumes'] - } -} - -delete_volume = { - 'status_code': [202] -} diff --git a/tempest/lib/api_schema/response/compute/v2_11/__init__.py b/tempest/lib/api_schema/response/compute/v2_11/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_11/services.py b/tempest/lib/api_schema/response/compute/v2_11/services.py deleted file mode 100644 index 18b833bd2..000000000 --- a/tempest/lib/api_schema/response/compute/v2_11/services.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 copy - -from tempest.lib.api_schema.response.compute.v2_1 import services - - -list_services = copy.deepcopy(services.list_services) -list_services['response_body']['properties']['services']['items'][ - 'properties']['forced_down'] = {'type': 'boolean'} -list_services['response_body']['properties']['services']['items'][ - 'required'].append('forced_down') - -update_forced_down = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'service': { - 'type': 'object', - 'properties': { - 'binary': {'type': 'string'}, - 'host': {'type': 'string'}, - 'forced_down': {'type': 'boolean'} - }, - 'additionalProperties': False, - 'required': ['binary', 'host', 'forced_down'] - } - }, - 'additionalProperties': False, - 'required': ['service'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_13/__init__.py b/tempest/lib/api_schema/response/compute/v2_13/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_13/servers.py b/tempest/lib/api_schema/response/compute/v2_13/servers.py deleted file mode 100644 index a90f3e4f2..000000000 --- a/tempest/lib/api_schema/response/compute/v2_13/servers.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2017 NTT Corporation. 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 copy - -from tempest.lib.api_schema.response.compute.v2_1 import servers - - -common_server_group = copy.deepcopy(servers.common_server_group) -common_server_group['properties']['project_id'] = {'type': 'string'} -common_server_group['properties']['user_id'] = {'type': 'string'} -common_server_group['required'].append('project_id') -common_server_group['required'].append('user_id') - -create_show_server_group = copy.deepcopy(servers.create_show_server_group) -create_show_server_group['response_body']['properties'][ - 'server_group'] = common_server_group - -delete_server_group = copy.deepcopy(servers.delete_server_group) - -list_server_groups = copy.deepcopy(servers.list_server_groups) -list_server_groups['response_body']['properties']['server_groups'][ - 'items'] = common_server_group diff --git a/tempest/lib/api_schema/response/compute/v2_16/__init__.py b/tempest/lib/api_schema/response/compute/v2_16/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_16/servers.py b/tempest/lib/api_schema/response/compute/v2_16/servers.py deleted file mode 100644 index 3eb658f4e..000000000 --- a/tempest/lib/api_schema/response/compute/v2_16/servers.py +++ /dev/null @@ -1,160 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 copy - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types -from tempest.lib.api_schema.response.compute.v2_9 import servers - -# Compute microversion 2.16: -# 1. New attributes in 'server' dict. -# 'host_status' - -server_detail = { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'name': {'type': 'string'}, - 'status': {'type': 'string'}, - 'image': {'oneOf': [ - {'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'links': parameter_types.links - }, - 'additionalProperties': False, - 'required': ['id', 'links']}, - {'type': ['string', 'null']} - ]}, - 'flavor': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'links': parameter_types.links - }, - 'additionalProperties': False, - 'required': ['id', 'links'] - }, - 'fault': { - 'type': 'object', - 'properties': { - 'code': {'type': 'integer'}, - 'created': {'type': 'string'}, - 'message': {'type': 'string'}, - 'details': {'type': 'string'}, - }, - 'additionalProperties': False, - # NOTE(gmann): 'details' is not necessary to be present - # in the 'fault'. So it is not defined as 'required'. - 'required': ['code', 'created', 'message'] - }, - 'user_id': {'type': 'string'}, - 'tenant_id': {'type': 'string'}, - 'created': {'type': 'string'}, - 'updated': {'type': 'string'}, - 'progress': {'type': 'integer'}, - 'metadata': {'type': 'object'}, - 'links': parameter_types.links, - 'addresses': parameter_types.addresses, - 'hostId': {'type': 'string'}, - 'OS-DCF:diskConfig': {'type': 'string'}, - 'accessIPv4': parameter_types.access_ip_v4, - 'accessIPv6': parameter_types.access_ip_v6, - 'key_name': {'type': ['string', 'null']}, - 'security_groups': {'type': 'array'}, - 'OS-SRV-USG:launched_at': {'type': ['string', 'null']}, - 'OS-SRV-USG:terminated_at': {'type': ['string', 'null']}, - 'OS-EXT-AZ:availability_zone': {'type': 'string'}, - 'OS-EXT-STS:task_state': {'type': ['string', 'null']}, - 'OS-EXT-STS:vm_state': {'type': 'string'}, - 'OS-EXT-STS:power_state': parameter_types.power_state, - 'OS-EXT-SRV-ATTR:host': {'type': ['string', 'null']}, - 'OS-EXT-SRV-ATTR:instance_name': {'type': 'string'}, - 'OS-EXT-SRV-ATTR:hypervisor_hostname': {'type': ['string', 'null']}, - 'config_drive': {'type': 'string'}, - 'os-extended-volumes:volumes_attached': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'delete_on_termination': {'type': 'boolean'} - }, - 'additionalProperties': False, - }, - }, - 'OS-EXT-SRV-ATTR:reservation_id': {'type': ['string', 'null']}, - 'OS-EXT-SRV-ATTR:launch_index': {'type': 'integer'}, - 'OS-EXT-SRV-ATTR:kernel_id': {'type': ['string', 'null']}, - 'OS-EXT-SRV-ATTR:ramdisk_id': {'type': ['string', 'null']}, - 'OS-EXT-SRV-ATTR:hostname': {'type': 'string'}, - 'OS-EXT-SRV-ATTR:root_device_name': {'type': ['string', 'null']}, - 'OS-EXT-SRV-ATTR:user_data': {'type': ['string', 'null']}, - 'locked': {'type': 'boolean'}, - # NOTE(gmann): new attributes in version 2.16 - 'host_status': {'type': 'string'} - }, - 'additionalProperties': False, - # NOTE(gmann): 'progress' attribute is present in the response - # only when server's status is one of the progress statuses - # ("ACTIVE","BUILD", "REBUILD", "RESIZE","VERIFY_RESIZE") - # 'fault' attribute is present in the response - # only when server's status is one of the "ERROR", "DELETED". - # OS-DCF:diskConfig and accessIPv4/v6 are API - # extensions, and some environments return a response - # without these attributes.So these are not defined as 'required'. - 'required': ['id', 'name', 'status', 'image', 'flavor', - 'user_id', 'tenant_id', 'created', 'updated', - 'metadata', 'links', 'addresses', 'hostId'] -} - -server_detail['properties']['addresses']['patternProperties'][ - '^[a-zA-Z0-9-_.]+$']['items']['properties'].update({ - 'OS-EXT-IPS:type': {'type': 'string'}, - 'OS-EXT-IPS-MAC:mac_addr': parameter_types.mac_address}) -# NOTE(gmann)dd: Update OS-EXT-IPS:type and OS-EXT-IPS-MAC:mac_addr -# attributes in server address. Those are API extension, -# and some environments return a response without -# these attributes. So they are not 'required'. - -get_server = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'server': server_detail - }, - 'additionalProperties': False, - 'required': ['server'] - } -} - -list_servers_detail = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'servers': { - 'type': 'array', - 'items': server_detail - }, - 'servers_links': parameter_types.links - }, - 'additionalProperties': False, - # NOTE(gmann): servers_links attribute is not necessary to be - # present always So it is not 'required'. - 'required': ['servers'] - } -} - -list_servers = copy.deepcopy(servers.list_servers) diff --git a/tempest/lib/api_schema/response/compute/v2_19/__init__.py b/tempest/lib/api_schema/response/compute/v2_19/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_19/servers.py b/tempest/lib/api_schema/response/compute/v2_19/servers.py deleted file mode 100644 index 05cc32c5b..000000000 --- a/tempest/lib/api_schema/response/compute/v2_19/servers.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 copy - -from tempest.lib.api_schema.response.compute.v2_1 import servers as serversv21 -from tempest.lib.api_schema.response.compute.v2_16 import servers \ - as serversv216 - -list_servers = copy.deepcopy(serversv216.list_servers) - -get_server = copy.deepcopy(serversv216.get_server) -get_server['response_body']['properties']['server'][ - 'properties'].update({'description': {'type': ['string', 'null']}}) -get_server['response_body']['properties']['server'][ - 'required'].append('description') - -list_servers_detail = copy.deepcopy(serversv216.list_servers_detail) -list_servers_detail['response_body']['properties']['servers']['items'][ - 'properties'].update({'description': {'type': ['string', 'null']}}) -list_servers_detail['response_body']['properties']['servers']['items'][ - 'required'].append('description') - -update_server = copy.deepcopy(serversv21.update_server) -update_server['response_body']['properties']['server'][ - 'properties'].update({'description': {'type': ['string', 'null']}}) -update_server['response_body']['properties']['server'][ - 'required'].append('description') - -rebuild_server = copy.deepcopy(serversv21.rebuild_server) -rebuild_server['response_body']['properties']['server'][ - 'properties'].update({'description': {'type': ['string', 'null']}}) -rebuild_server['response_body']['properties']['server'][ - 'required'].append('description') - -rebuild_server_with_admin_pass = copy.deepcopy( - serversv21.rebuild_server_with_admin_pass) -rebuild_server_with_admin_pass['response_body']['properties']['server'][ - 'properties'].update({'description': {'type': ['string', 'null']}}) -rebuild_server_with_admin_pass['response_body']['properties']['server'][ - 'required'].append('description') diff --git a/tempest/lib/api_schema/response/compute/v2_2/__init__.py b/tempest/lib/api_schema/response/compute/v2_2/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_2/keypairs.py b/tempest/lib/api_schema/response/compute/v2_2/keypairs.py deleted file mode 100644 index 0bb7771c9..000000000 --- a/tempest/lib/api_schema/response/compute/v2_2/keypairs.py +++ /dev/null @@ -1,41 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 copy - -from tempest.lib.api_schema.response.compute.v2_1 import keypairs - -get_keypair = copy.deepcopy(keypairs.get_keypair) -get_keypair['response_body']['properties']['keypair'][ - 'properties'].update({'type': {'type': 'string'}}) -get_keypair['response_body']['properties']['keypair'][ - 'required'].append('type') - -create_keypair = copy.deepcopy(keypairs.create_keypair) -create_keypair['status_code'] = [201] -create_keypair['response_body']['properties']['keypair'][ - 'properties'].update({'type': {'type': 'string'}}) -create_keypair['response_body']['properties']['keypair'][ - 'required'].append('type') - -delete_keypair = { - 'status_code': [204], -} - -list_keypairs = copy.deepcopy(keypairs.list_keypairs) -list_keypairs['response_body']['properties']['keypairs'][ - 'items']['properties']['keypair'][ - 'properties'].update({'type': {'type': 'string'}}) -list_keypairs['response_body']['properties']['keypairs'][ - 'items']['properties']['keypair']['required'].append('type') diff --git a/tempest/lib/api_schema/response/compute/v2_23/__init__.py b/tempest/lib/api_schema/response/compute/v2_23/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_23/migrations.py b/tempest/lib/api_schema/response/compute/v2_23/migrations.py deleted file mode 100644 index 3cd0f6ec1..000000000 --- a/tempest/lib/api_schema/response/compute/v2_23/migrations.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 tempest.lib.api_schema.response.compute.v2_1 import parameter_types - -# Compute microversion 2.23: -# New attributes in 'migrations' list. -# 'migration_type' -# 'links' - -list_migrations = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'migrations': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': 'integer'}, - 'status': {'type': ['string', 'null']}, - 'instance_uuid': {'type': ['string', 'null']}, - 'source_node': {'type': ['string', 'null']}, - 'source_compute': {'type': ['string', 'null']}, - 'dest_node': {'type': ['string', 'null']}, - 'dest_compute': {'type': ['string', 'null']}, - 'dest_host': {'type': ['string', 'null']}, - 'old_instance_type_id': {'type': ['integer', 'null']}, - 'new_instance_type_id': {'type': ['integer', 'null']}, - 'created_at': {'type': 'string'}, - 'updated_at': {'type': ['string', 'null']}, - # New attributes in version 2.23 - 'migration_type': {'type': ['string', 'null']}, - 'links': parameter_types.links - }, - 'additionalProperties': False, - 'required': [ - 'id', 'status', 'instance_uuid', 'source_node', - 'source_compute', 'dest_node', 'dest_compute', - 'dest_host', 'old_instance_type_id', - 'new_instance_type_id', 'created_at', 'updated_at', - 'migration_type' - ] - } - } - }, - 'additionalProperties': False, - 'required': ['migrations'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_26/__init__.py b/tempest/lib/api_schema/response/compute/v2_26/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_26/servers.py b/tempest/lib/api_schema/response/compute/v2_26/servers.py deleted file mode 100644 index b03bdf6fa..000000000 --- a/tempest/lib/api_schema/response/compute/v2_26/servers.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright 2016 IBM Corp. -# Copyright 2017 AT&T Corp. -# -# 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 copy - -from tempest.lib.api_schema.response.compute.v2_1 import servers as servers21 -from tempest.lib.api_schema.response.compute.v2_19 import servers as servers219 - -# The 2.26 microversion changes the server GET and (detailed) LIST responses to -# include the server 'tags' which is just a list of strings. - -tag_items = { - 'type': 'array', - 'maxItems': 50, - 'items': { - 'type': 'string', - 'pattern': '^[^,/]*$', - 'maxLength': 60 - } -} - -get_server = copy.deepcopy(servers219.get_server) -get_server['response_body']['properties']['server'][ - 'properties'].update({'tags': tag_items}) -get_server['response_body']['properties']['server'][ - 'required'].append('tags') - -list_servers_detail = copy.deepcopy(servers219.list_servers_detail) -list_servers_detail['response_body']['properties']['servers']['items'][ - 'properties'].update({'tags': tag_items}) -list_servers_detail['response_body']['properties']['servers']['items'][ - 'required'].append('tags') - -# list response schema wasn't changed for v2.26 so use v2.1 - -list_servers = copy.deepcopy(servers21.list_servers) - -list_tags = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'tags': tag_items, - }, - 'additionalProperties': False, - 'required': ['tags'] - } -} - -update_all_tags = copy.deepcopy(list_tags) - -delete_all_tags = {'status_code': [204]} - -check_tag_existence = {'status_code': [204]} - -update_tag = { - 'status_code': [201, 204], - 'response_header': { - 'type': 'object', - 'properties': { - 'location': { - 'type': 'string' - } - }, - 'required': ['location'] - } -} - -delete_tag = {'status_code': [204]} diff --git a/tempest/lib/api_schema/response/compute/v2_3/__init__.py b/tempest/lib/api_schema/response/compute/v2_3/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_3/servers.py b/tempest/lib/api_schema/response/compute/v2_3/servers.py deleted file mode 100644 index f24103ea2..000000000 --- a/tempest/lib/api_schema/response/compute/v2_3/servers.py +++ /dev/null @@ -1,166 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 copy - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types -from tempest.lib.api_schema.response.compute.v2_1 import servers - -# Compute microversion 2.3: -# 1. New attributes in 'os-extended-volumes:volumes_attached' dict. -# 'delete_on_termination' -# 2. New attributes in 'server' dict. -# 'OS-EXT-SRV-ATTR:reservation_id' -# 'OS-EXT-SRV-ATTR:launch_index' -# 'OS-EXT-SRV-ATTR:kernel_id' -# 'OS-EXT-SRV-ATTR:ramdisk_id' -# 'OS-EXT-SRV-ATTR:hostname' -# 'OS-EXT-SRV-ATTR:root_device_name' -# 'OS-EXT-SRV-ATTR:user_data' - -server_detail = { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'name': {'type': 'string'}, - 'status': {'type': 'string'}, - 'image': {'oneOf': [ - {'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'links': parameter_types.links - }, - 'additionalProperties': False, - 'required': ['id', 'links']}, - {'type': ['string', 'null']} - ]}, - 'flavor': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'links': parameter_types.links - }, - 'additionalProperties': False, - 'required': ['id', 'links'] - }, - 'fault': { - 'type': 'object', - 'properties': { - 'code': {'type': 'integer'}, - 'created': {'type': 'string'}, - 'message': {'type': 'string'}, - 'details': {'type': 'string'}, - }, - 'additionalProperties': False, - # NOTE(gmann): 'details' is not necessary to be present - # in the 'fault'. So it is not defined as 'required'. - 'required': ['code', 'created', 'message'] - }, - 'user_id': {'type': 'string'}, - 'tenant_id': {'type': 'string'}, - 'created': {'type': 'string'}, - 'updated': {'type': 'string'}, - 'progress': {'type': 'integer'}, - 'metadata': {'type': 'object'}, - 'links': parameter_types.links, - 'addresses': parameter_types.addresses, - 'hostId': {'type': 'string'}, - 'OS-DCF:diskConfig': {'type': 'string'}, - 'accessIPv4': parameter_types.access_ip_v4, - 'accessIPv6': parameter_types.access_ip_v6, - 'key_name': {'type': ['string', 'null']}, - 'security_groups': {'type': 'array'}, - 'OS-SRV-USG:launched_at': {'type': ['string', 'null']}, - 'OS-SRV-USG:terminated_at': {'type': ['string', 'null']}, - 'OS-EXT-AZ:availability_zone': {'type': 'string'}, - 'OS-EXT-STS:task_state': {'type': ['string', 'null']}, - 'OS-EXT-STS:vm_state': {'type': 'string'}, - 'OS-EXT-STS:power_state': parameter_types.power_state, - 'OS-EXT-SRV-ATTR:host': {'type': ['string', 'null']}, - 'OS-EXT-SRV-ATTR:instance_name': {'type': 'string'}, - 'OS-EXT-SRV-ATTR:hypervisor_hostname': {'type': ['string', 'null']}, - 'config_drive': {'type': 'string'}, - # NOTE(gmann): new attributes in version 2.3 - 'os-extended-volumes:volumes_attached': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': 'string'}, - 'delete_on_termination': {'type': 'boolean'} - }, - 'additionalProperties': False, - }, - }, - 'OS-EXT-SRV-ATTR:reservation_id': {'type': ['string', 'null']}, - 'OS-EXT-SRV-ATTR:launch_index': {'type': 'integer'}, - 'OS-EXT-SRV-ATTR:kernel_id': {'type': ['string', 'null']}, - 'OS-EXT-SRV-ATTR:ramdisk_id': {'type': ['string', 'null']}, - 'OS-EXT-SRV-ATTR:hostname': {'type': 'string'}, - 'OS-EXT-SRV-ATTR:root_device_name': {'type': ['string', 'null']}, - 'OS-EXT-SRV-ATTR:user_data': {'type': ['string', 'null']}, - }, - 'additionalProperties': False, - # NOTE(gmann): 'progress' attribute is present in the response - # only when server's status is one of the progress statuses - # ("ACTIVE","BUILD", "REBUILD", "RESIZE","VERIFY_RESIZE") - # 'fault' attribute is present in the response - # only when server's status is one of the "ERROR", "DELETED". - # OS-DCF:diskConfig and accessIPv4/v6 are API - # extensions, and some environments return a response - # without these attributes.So these are not defined as 'required'. - 'required': ['id', 'name', 'status', 'image', 'flavor', - 'user_id', 'tenant_id', 'created', 'updated', - 'metadata', 'links', 'addresses', 'hostId'] -} - -server_detail['properties']['addresses']['patternProperties'][ - '^[a-zA-Z0-9-_.]+$']['items']['properties'].update({ - 'OS-EXT-IPS:type': {'type': 'string'}, - 'OS-EXT-IPS-MAC:mac_addr': parameter_types.mac_address}) -# NOTE(gmann)dd: Update OS-EXT-IPS:type and OS-EXT-IPS-MAC:mac_addr -# attributes in server address. Those are API extension, -# and some environments return a response without -# these attributes. So they are not 'required'. - -get_server = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'server': server_detail - }, - 'additionalProperties': False, - 'required': ['server'] - } -} - -list_servers_detail = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'servers': { - 'type': 'array', - 'items': server_detail - }, - 'servers_links': parameter_types.links - }, - 'additionalProperties': False, - # NOTE(gmann): servers_links attribute is not necessary to be - # present always So it is not 'required'. - 'required': ['servers'] - } -} - -list_servers = copy.deepcopy(servers.list_servers) diff --git a/tempest/lib/api_schema/response/compute/v2_47/__init__.py b/tempest/lib/api_schema/response/compute/v2_47/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_47/servers.py b/tempest/lib/api_schema/response/compute/v2_47/servers.py deleted file mode 100644 index 37a084f1c..000000000 --- a/tempest/lib/api_schema/response/compute/v2_47/servers.py +++ /dev/null @@ -1,39 +0,0 @@ -# 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 copy - -from tempest.lib.api_schema.response.compute.v2_26 import servers as servers226 - -flavor = { - 'type': 'object', - 'properties': { - 'original_name': {'type': 'string'}, - 'disk': {'type': 'integer'}, - 'ephemeral': {'type': 'integer'}, - 'ram': {'type': 'integer'}, - 'swap': {'type': 'integer'}, - 'vcpus': {'type': 'integer'}, - 'extra_specs': { - 'type': 'object', - 'patternProperties': { - '^[a-zA-Z0-9_\-\. :]+$': {'type': 'string'} - } - } - }, - 'additionalProperties': False, - 'required': ['original_name', 'disk', 'ephemeral', 'ram', 'swap', 'vcpus'] -} - -get_server = copy.deepcopy(servers226.get_server) -get_server['response_body']['properties']['server'][ - 'properties'].update({'flavor': flavor}) diff --git a/tempest/lib/api_schema/response/compute/v2_48/__init__.py b/tempest/lib/api_schema/response/compute/v2_48/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_48/servers.py b/tempest/lib/api_schema/response/compute/v2_48/servers.py deleted file mode 100644 index 59047583a..000000000 --- a/tempest/lib/api_schema/response/compute/v2_48/servers.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright 2017 Mirantis Inc. -# -# 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 copy - -from tempest.lib.api_schema.response.compute.v2_1 import parameter_types -from tempest.lib.api_schema.response.compute.v2_47 import servers as servers247 - - -show_server_diagnostics = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'state': { - 'type': 'string', 'enum': [ - 'pending', 'running', 'paused', 'shutdown', 'crashed', - 'suspended'] - }, - 'driver': { - 'type': 'string', 'enum': [ - 'libvirt', 'xenapi', 'vmwareapi', 'ironic', 'hyperv'] - }, - 'hypervisor': {'type': ['string', 'null']}, - 'hypervisor_os': {'type': ['string', 'null']}, - 'uptime': {'type': ['integer', 'null']}, - 'config_drive': {'type': 'boolean'}, - 'num_cpus': {'type': 'integer'}, - 'num_nics': {'type': 'integer'}, - 'num_disks': {'type': 'integer'}, - 'memory_details': { - 'type': 'object', - 'properties': { - 'maximum': {'type': ['integer', 'null']}, - 'used': {'type': ['integer', 'null']} - }, - 'additionalProperties': False, - 'required': ['maximum', 'used'] - }, - 'cpu_details': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'id': {'type': ['integer', 'null']}, - 'time': {'type': ['integer', 'null']}, - 'utilisation': {'type': ['integer', 'null']} - }, - 'additionalProperties': False, - 'required': ['id', 'time', 'utilisation'] - } - }, - 'nic_details': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'mac_address': {'oneOf': [parameter_types.mac_address, - {'type': 'null'}]}, - 'rx_octets': {'type': ['integer', 'null']}, - 'rx_errors': {'type': ['integer', 'null']}, - 'rx_drop': {'type': ['integer', 'null']}, - 'rx_packets': {'type': ['integer', 'null']}, - 'rx_rate': {'type': ['integer', 'null']}, - 'tx_octets': {'type': ['integer', 'null']}, - 'tx_errors': {'type': ['integer', 'null']}, - 'tx_drop': {'type': ['integer', 'null']}, - 'tx_packets': {'type': ['integer', 'null']}, - 'tx_rate': {'type': ['integer', 'null']} - }, - 'additionalProperties': False, - 'required': ['mac_address', 'rx_octets', 'rx_errors', - 'rx_drop', - 'rx_packets', 'rx_rate', 'tx_octets', - 'tx_errors', - 'tx_drop', 'tx_packets', 'tx_rate'] - } - }, - 'disk_details': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'read_bytes': {'type': ['integer', 'null']}, - 'read_requests': {'type': ['integer', 'null']}, - 'write_bytes': {'type': ['integer', 'null']}, - 'write_requests': {'type': ['integer', 'null']}, - 'errors_count': {'type': ['integer', 'null']} - }, - 'additionalProperties': False, - 'required': ['read_bytes', 'read_requests', 'write_bytes', - 'write_requests', 'errors_count'] - } - } - }, - 'additionalProperties': False, - 'required': [ - 'state', 'driver', 'hypervisor', 'hypervisor_os', 'uptime', - 'config_drive', 'num_cpus', 'num_nics', 'num_disks', - 'memory_details', 'cpu_details', 'nic_details', 'disk_details'], - } -} - -get_server = copy.deepcopy(servers247.get_server) diff --git a/tempest/lib/api_schema/response/compute/v2_6/__init__.py b/tempest/lib/api_schema/response/compute/v2_6/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_6/servers.py b/tempest/lib/api_schema/response/compute/v2_6/servers.py deleted file mode 100644 index 29b3e8600..000000000 --- a/tempest/lib/api_schema/response/compute/v2_6/servers.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2016 IBM Corp. -# -# 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 copy - -from tempest.lib.api_schema.response.compute.v2_3 import servers - -list_servers = copy.deepcopy(servers.list_servers) -get_server = copy.deepcopy(servers.get_server) -list_servers_detail = copy.deepcopy(servers.list_servers_detail) - -# NOTE: The consolidated remote console API got introduced with v2.6 -# with bp/consolidate-console-api. See Nova commit 578bafeda -get_remote_consoles = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'remote_console': { - 'type': 'object', - 'properties': { - 'protocol': {'enum': ['vnc', 'rdp', 'serial', 'spice']}, - 'type': {'enum': ['novnc', 'xpvnc', 'rdp-html5', - 'spice-html5', 'serial']}, - 'url': { - 'type': 'string', - 'format': 'uri' - } - }, - 'additionalProperties': False, - 'required': ['protocol', 'type', 'url'] - } - }, - 'additionalProperties': False, - 'required': ['remote_console'] - } -} diff --git a/tempest/lib/api_schema/response/compute/v2_9/__init__.py b/tempest/lib/api_schema/response/compute/v2_9/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/compute/v2_9/servers.py b/tempest/lib/api_schema/response/compute/v2_9/servers.py deleted file mode 100644 index e260e48ce..000000000 --- a/tempest/lib/api_schema/response/compute/v2_9/servers.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 copy - -from tempest.lib.api_schema.response.compute.v2_6 import servers - -list_servers = copy.deepcopy(servers.list_servers) - -get_server = copy.deepcopy(servers.get_server) -get_server['response_body']['properties']['server'][ - 'properties'].update({'locked': {'type': 'boolean'}}) -get_server['response_body']['properties']['server'][ - 'required'].append('locked') - -list_servers_detail = copy.deepcopy(servers.list_servers_detail) -list_servers_detail['response_body']['properties']['servers']['items'][ - 'properties'].update({'locked': {'type': 'boolean'}}) -list_servers_detail['response_body']['properties']['servers']['items'][ - 'required'].append('locked') diff --git a/tempest/lib/api_schema/response/volume/__init__.py b/tempest/lib/api_schema/response/volume/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/api_schema/response/volume/versions.py b/tempest/lib/api_schema/response/volume/versions.py deleted file mode 100644 index 2391a8c86..000000000 --- a/tempest/lib/api_schema/response/volume/versions.py +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2015 NEC Corporation. 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. - - -list_versions = { - 'status_code': [300], - 'response_body': { - 'type': 'object', - 'properties': { - 'versions': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'status': {'type': 'string'}, - 'updated': {'type': 'string'}, - 'id': {'type': 'string'}, - 'links': { - 'type': 'array', - 'items': { - 'type': 'object', - 'properties': { - 'href': {'type': 'string', - 'format': 'uri'}, - 'rel': {'type': 'string'}, - 'type': {'type': 'string'}, - }, - 'required': ['href', 'rel'] - } - }, - 'min_version': {'type': 'string'}, - 'version': {'type': 'string'}, - 'media-types': { - 'type': 'array', - 'properties': { - 'base': {'type': 'string'}, - 'type': {'type': 'string'} - }, - 'required': ['base', 'type'] - } - }, - 'required': ['status', 'updated', 'id', 'links', - 'min_version', 'version', 'media-types'] - } - } - }, - 'required': ['versions'], - } -} diff --git a/tempest/lib/auth.py b/tempest/lib/auth.py deleted file mode 100644 index ab4308fed..000000000 --- a/tempest/lib/auth.py +++ /dev/null @@ -1,851 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P. -# Copyright 2016 Rackspace Inc. -# 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 abc -import copy -import datetime -import re - -from oslo_log import log as logging -import six -from six.moves.urllib import parse as urlparse - -from tempest.lib import exceptions -from tempest.lib.services.identity.v2 import token_client as json_v2id -from tempest.lib.services.identity.v3 import token_client as json_v3id - -ISO8601_FLOAT_SECONDS = '%Y-%m-%dT%H:%M:%S.%fZ' -ISO8601_INT_SECONDS = '%Y-%m-%dT%H:%M:%SZ' -LOG = logging.getLogger(__name__) - - -def replace_version(url, new_version): - parts = urlparse.urlparse(url) - version_path = '/%s' % new_version - path, subs = re.subn(r'(^|/)+v\d+(?:\.\d+)?', - version_path, - parts.path, - count=1) - if not subs: - path = '%s%s' % (parts.path.rstrip('/'), version_path) - url = urlparse.urlunparse((parts.scheme, - parts.netloc, - path, - parts.params, - parts.query, - parts.fragment)) - return url - - -def apply_url_filters(url, filters): - if filters.get('api_version', None) is not None: - url = replace_version(url, filters['api_version']) - parts = urlparse.urlparse(url) - if filters.get('skip_path', None) is not None and parts.path != '': - url = urlparse.urlunparse((parts.scheme, - parts.netloc, - '/', - parts.params, - parts.query, - parts.fragment)) - - return url - - -@six.add_metaclass(abc.ABCMeta) -class AuthProvider(object): - """Provide authentication""" - - SCOPES = set(['project']) - - def __init__(self, credentials, scope='project'): - """Auth provider __init__ - - :param credentials: credentials for authentication - :param scope: the default scope to be used by the credential providers - when requesting a token. Valid values depend on the - AuthProvider class implementation, and are defined in - the set SCOPES. Default value is 'project'. - """ - if self.check_credentials(credentials): - self.credentials = credentials - else: - if isinstance(credentials, Credentials): - password = credentials.get('password') - message = "Credentials are: " + str(credentials) - if password is None: - message += " Password is not defined." - else: - message += " Password is defined." - raise exceptions.InvalidCredentials(message) - else: - raise TypeError("credentials object is of type %s, which is" - " not a valid Credentials object type." % - credentials.__class__.__name__) - self._scope = None - self.scope = scope - self.cache = None - self.alt_auth_data = None - self.alt_part = None - - def __str__(self): - return "Creds :{creds}, cached auth data: {cache}".format( - creds=self.credentials, cache=self.cache) - - @abc.abstractmethod - def _decorate_request(self, filters, method, url, headers=None, body=None, - auth_data=None): - """Decorate request with authentication data""" - return - - @abc.abstractmethod - def _get_auth(self): - return - - @abc.abstractmethod - def _fill_credentials(self, auth_data_body): - return - - def fill_credentials(self): - """Fill credentials object with data from auth""" - auth_data = self.get_auth() - self._fill_credentials(auth_data[1]) - return self.credentials - - @classmethod - def check_credentials(cls, credentials): - """Verify credentials are valid.""" - return isinstance(credentials, Credentials) and credentials.is_valid() - - @property - def auth_data(self): - """Auth data for set scope""" - return self.get_auth() - - @property - def scope(self): - """Scope used in auth requests""" - return self._scope - - @auth_data.deleter - def auth_data(self): - self.clear_auth() - - def get_auth(self): - """Returns auth from cache if available, else auth first""" - if self.cache is None or self.is_expired(self.cache): - self.set_auth() - return self.cache - - def set_auth(self): - """Forces setting auth. - - Forces setting auth, ignores cache if it exists. - Refills credentials. - """ - self.cache = self._get_auth() - self._fill_credentials(self.cache[1]) - - def clear_auth(self): - """Clear access cache - - Can be called to clear the access cache so that next request - will fetch a new token and base_url. - """ - self.cache = None - self.credentials.reset() - - @abc.abstractmethod - def is_expired(self, auth_data): - return - - def auth_request(self, method, url, headers=None, body=None, filters=None): - """Obtains auth data and decorates a request with that. - - :param method: HTTP method of the request - :param url: relative URL of the request (path) - :param headers: HTTP headers of the request - :param body: HTTP body in case of POST / PUT - :param filters: select a base URL out of the catalog - :return: a Tuple (url, headers, body) - """ - orig_req = dict(url=url, headers=headers, body=body) - - auth_url, auth_headers, auth_body = self._decorate_request( - filters, method, url, headers, body) - auth_req = dict(url=auth_url, headers=auth_headers, body=auth_body) - - # Overwrite part if the request if it has been requested - if self.alt_part is not None: - if self.alt_auth_data is not None: - alt_url, alt_headers, alt_body = self._decorate_request( - filters, method, url, headers, body, - auth_data=self.alt_auth_data) - alt_auth_req = dict(url=alt_url, headers=alt_headers, - body=alt_body) - if auth_req[self.alt_part] == alt_auth_req[self.alt_part]: - raise exceptions.BadAltAuth(part=self.alt_part) - auth_req[self.alt_part] = alt_auth_req[self.alt_part] - - else: - # If the requested part is not affected by auth, we are - # not altering auth as expected, raise an exception - if auth_req[self.alt_part] == orig_req[self.alt_part]: - raise exceptions.BadAltAuth(part=self.alt_part) - # If alt auth data is None, skip auth in the requested part - auth_req[self.alt_part] = orig_req[self.alt_part] - - # Next auth request will be normal, unless otherwise requested - self.reset_alt_auth_data() - - return auth_req['url'], auth_req['headers'], auth_req['body'] - - def reset_alt_auth_data(self): - """Configure auth provider to provide valid authentication data""" - self.alt_part = None - self.alt_auth_data = None - - def set_alt_auth_data(self, request_part, auth_data): - """Alternate auth data on next request - - Configure auth provider to provide alt authentication data - on a part of the *next* auth_request. If credentials are None, - set invalid data. - - :param request_part: request part to contain invalid auth: url, - headers, body - :param auth_data: alternative auth_data from which to get the - invalid data to be injected - """ - self.alt_part = request_part - self.alt_auth_data = auth_data - - @abc.abstractmethod - def base_url(self, filters, auth_data=None): - """Extracts the base_url based on provided filters""" - return - - @scope.setter - def scope(self, value): - """Set the scope to be used in token requests - - :param scope: scope to be used. If the scope is different, clear caches - """ - if value not in self.SCOPES: - raise exceptions.InvalidScope( - scope=value, auth_provider=self.__class__.__name__) - if value != self.scope: - self.clear_auth() - self._scope = value - - -class KeystoneAuthProvider(AuthProvider): - - EXPIRY_DATE_FORMATS = (ISO8601_FLOAT_SECONDS, ISO8601_INT_SECONDS) - - token_expiry_threshold = datetime.timedelta(seconds=60) - - def __init__(self, credentials, auth_url, - disable_ssl_certificate_validation=None, - ca_certs=None, trace_requests=None, scope='project', - http_timeout=None): - super(KeystoneAuthProvider, self).__init__(credentials, scope) - self.dscv = disable_ssl_certificate_validation - self.ca_certs = ca_certs - self.trace_requests = trace_requests - self.http_timeout = http_timeout - self.auth_url = auth_url - self.auth_client = self._auth_client(auth_url) - - def _decorate_request(self, filters, method, url, headers=None, body=None, - auth_data=None): - if auth_data is None: - auth_data = self.get_auth() - token, _ = auth_data - base_url = self.base_url(filters=filters, auth_data=auth_data) - # build authenticated request - # returns new request, it does not touch the original values - _headers = copy.deepcopy(headers) if headers is not None else {} - _headers['X-Auth-Token'] = str(token) - if url is None or url == "": - _url = base_url - else: - # Join base URL and url, and remove multiple contiguous slashes - _url = "/".join([base_url, url]) - parts = [x for x in urlparse.urlparse(_url)] - parts[2] = re.sub("/{2,}", "/", parts[2]) - _url = urlparse.urlunparse(parts) - # no change to method or body - return str(_url), _headers, body - - @abc.abstractmethod - def _auth_client(self): - return - - @abc.abstractmethod - def _auth_params(self): - """Auth parameters to be passed to the token request - - By default all fields available in Credentials are passed to the - token request. Scope may affect this. - """ - return - - def _get_auth(self): - # Bypasses the cache - auth_func = getattr(self.auth_client, 'get_token') - auth_params = self._auth_params() - - # returns token, auth_data - token, auth_data = auth_func(**auth_params) - return token, auth_data - - def _parse_expiry_time(self, expiry_string): - expiry = None - for date_format in self.EXPIRY_DATE_FORMATS: - try: - expiry = datetime.datetime.strptime( - expiry_string, date_format) - except ValueError: - pass - if expiry is None: - raise ValueError( - "time data '{data}' does not match any of the" - "expected formats: {formats}".format( - data=expiry_string, formats=self.EXPIRY_DATE_FORMATS)) - return expiry - - def get_token(self): - return self.get_auth()[0] - - -class KeystoneV2AuthProvider(KeystoneAuthProvider): - """Provides authentication based on the Identity V2 API - - The Keystone Identity V2 API defines both unscoped and project scoped - tokens. This auth provider only implements 'project'. - """ - - SCOPES = set(['project']) - - def _auth_client(self, auth_url): - return json_v2id.TokenClient( - auth_url, disable_ssl_certificate_validation=self.dscv, - ca_certs=self.ca_certs, trace_requests=self.trace_requests, - http_timeout=self.http_timeout) - - def _auth_params(self): - """Auth parameters to be passed to the token request - - All fields available in Credentials are passed to the token request. - """ - return dict( - user=self.credentials.username, - password=self.credentials.password, - tenant=self.credentials.tenant_name, - auth_data=True) - - def _fill_credentials(self, auth_data_body): - tenant = auth_data_body['token']['tenant'] - user = auth_data_body['user'] - if self.credentials.tenant_name is None: - self.credentials.tenant_name = tenant['name'] - if self.credentials.tenant_id is None: - self.credentials.tenant_id = tenant['id'] - if self.credentials.username is None: - self.credentials.username = user['name'] - if self.credentials.user_id is None: - self.credentials.user_id = user['id'] - - def base_url(self, filters, auth_data=None): - """Base URL from catalog - - :param filters: Used to filter results - - Filters can be: - - - service: service type name such as compute, image, etc. - - region: service region name - - name: service name, only if service exists - - endpoint_type: type of endpoint such as - adminURL, publicURL, internalURL - - api_version: the version of api used to replace catalog version - - skip_path: skips the suffix path of the url and uses base URL - - :rtype: string - :return: url with filters applied - """ - if auth_data is None: - auth_data = self.get_auth() - token, _auth_data = auth_data - service = filters.get('service') - region = filters.get('region') - name = filters.get('name') - endpoint_type = filters.get('endpoint_type', 'publicURL') - - if service is None: - raise exceptions.EndpointNotFound("No service provided") - - _base_url = None - for ep in _auth_data['serviceCatalog']: - if ep["type"] == service: - if name is not None and ep["name"] != name: - continue - for _ep in ep['endpoints']: - if region is not None and _ep['region'] == region: - _base_url = _ep.get(endpoint_type) - if not _base_url: - # No region or name matching, use the first - _base_url = ep['endpoints'][0].get(endpoint_type) - break - if _base_url is None: - raise exceptions.EndpointNotFound( - "service: %s, region: %s, endpoint_type: %s, name: %s" % - (service, region, endpoint_type, name)) - return apply_url_filters(_base_url, filters) - - def is_expired(self, auth_data): - _, access = auth_data - expiry = self._parse_expiry_time(access['token']['expires']) - return (expiry - self.token_expiry_threshold <= - datetime.datetime.utcnow()) - - -class KeystoneV3AuthProvider(KeystoneAuthProvider): - """Provides authentication based on the Identity V3 API""" - - SCOPES = set(['project', 'domain', 'unscoped', None]) - - def _auth_client(self, auth_url): - return json_v3id.V3TokenClient( - auth_url, disable_ssl_certificate_validation=self.dscv, - ca_certs=self.ca_certs, trace_requests=self.trace_requests, - http_timeout=self.http_timeout) - - def _auth_params(self): - """Auth parameters to be passed to the token request - - Fields available in Credentials are passed to the token request, - depending on the value of scope. Valid values for scope are: "project", - "domain". Any other string (e.g. "unscoped") or None will lead to an - unscoped token request. - """ - - auth_params = dict( - user_id=self.credentials.user_id, - username=self.credentials.username, - user_domain_id=self.credentials.user_domain_id, - user_domain_name=self.credentials.user_domain_name, - password=self.credentials.password, - auth_data=True) - - if self.scope == 'project': - auth_params.update( - project_domain_id=self.credentials.project_domain_id, - project_domain_name=self.credentials.project_domain_name, - project_id=self.credentials.project_id, - project_name=self.credentials.project_name) - - if self.scope == 'domain': - auth_params.update( - domain_id=self.credentials.domain_id, - domain_name=self.credentials.domain_name) - - return auth_params - - def _fill_credentials(self, auth_data_body): - # project or domain, depending on the scope - project = auth_data_body.get('project', None) - domain = auth_data_body.get('domain', None) - # user is always there - user = auth_data_body['user'] - # Set project fields - if project is not None: - if self.credentials.project_name is None: - self.credentials.project_name = project['name'] - if self.credentials.project_id is None: - self.credentials.project_id = project['id'] - if self.credentials.project_domain_id is None: - self.credentials.project_domain_id = project['domain']['id'] - if self.credentials.project_domain_name is None: - self.credentials.project_domain_name = ( - project['domain']['name']) - # Set domain fields - if domain is not None: - if self.credentials.domain_id is None: - self.credentials.domain_id = domain['id'] - if self.credentials.domain_name is None: - self.credentials.domain_name = domain['name'] - # Set user fields - if self.credentials.username is None: - self.credentials.username = user['name'] - if self.credentials.user_id is None: - self.credentials.user_id = user['id'] - if self.credentials.user_domain_id is None: - self.credentials.user_domain_id = user['domain']['id'] - if self.credentials.user_domain_name is None: - self.credentials.user_domain_name = user['domain']['name'] - - def base_url(self, filters, auth_data=None): - """Base URL from catalog - - If scope is not 'project', it may be that there is not catalog in - the auth_data. In such case, as long as the requested service is - 'identity', we can use the original auth URL to build the base_url. - - :param filters: Used to filter results - - Filters can be: - - - service: service type name such as compute, image, etc. - - region: service region name - - name: service name, only if service exists - - endpoint_type: type of endpoint such as - adminURL, publicURL, internalURL - - api_version: the version of api used to replace catalog version - - skip_path: skips the suffix path of the url and uses base URL - - :rtype: string - :return: url with filters applied - """ - if auth_data is None: - auth_data = self.get_auth() - token, _auth_data = auth_data - service = filters.get('service') - region = filters.get('region') - name = filters.get('name') - endpoint_type = filters.get('endpoint_type', 'public') - - if service is None: - raise exceptions.EndpointNotFound("No service provided") - - if 'URL' in endpoint_type: - endpoint_type = endpoint_type.replace('URL', '') - _base_url = None - catalog = _auth_data.get('catalog', []) - - # Select entries with matching service type - service_catalog = [ep for ep in catalog if ep['type'] == service] - if service_catalog: - if name is not None: - service_catalog = ( - [ep for ep in service_catalog if ep['name'] == name]) - if service_catalog: - service_catalog = service_catalog[0]['endpoints'] - else: - raise exceptions.EndpointNotFound(name) - else: - service_catalog = service_catalog[0]['endpoints'] - else: - if not catalog and service == 'identity': - # NOTE(andreaf) If there's no catalog at all and the service - # is identity, it's a valid use case. Having a non-empty - # catalog with no identity in it is not valid instead. - msg = ('Got an empty catalog. Scope: %s. ' - 'Falling back to configured URL for %s: %s') - LOG.debug(msg, self.scope, service, self.auth_url) - return apply_url_filters(self.auth_url, filters) - else: - # No matching service - msg = ('No matching service found in the catalog.\n' - 'Scope: %s, Credentials: %s\n' - 'Auth data: %s\n' - 'Service: %s, Region: %s, endpoint_type: %s\n' - 'Catalog: %s') - raise exceptions.EndpointNotFound(msg % ( - self.scope, self.credentials, _auth_data, service, region, - endpoint_type, catalog)) - # Filter by endpoint type (interface) - filtered_catalog = [ep for ep in service_catalog if - ep['interface'] == endpoint_type] - if not filtered_catalog: - # No matching type, keep all and try matching by region at least - filtered_catalog = service_catalog - # Filter by region - filtered_catalog = [ep for ep in filtered_catalog if - ep['region'] == region] - if not filtered_catalog: - # No matching region (or name), take the first endpoint - filtered_catalog = [service_catalog[0]] - # There should be only one match. If not take the first. - _base_url = filtered_catalog[0].get('url', None) - if _base_url is None: - raise exceptions.EndpointNotFound(service) - return apply_url_filters(_base_url, filters) - - def is_expired(self, auth_data): - _, access = auth_data - expiry = self._parse_expiry_time(access['expires_at']) - return (expiry - self.token_expiry_threshold <= - datetime.datetime.utcnow()) - - -def is_identity_version_supported(identity_version): - return identity_version in IDENTITY_VERSION - - -def get_credentials(auth_url, fill_in=True, identity_version='v2', - disable_ssl_certificate_validation=None, ca_certs=None, - trace_requests=None, http_timeout=None, **kwargs): - """Builds a credentials object based on the configured auth_version - - :param auth_url (string): Full URI of the OpenStack Identity API(Keystone) - which is used to fetch the token from Identity service. - :param fill_in (boolean): obtain a token and fill in all credential - details provided by the identity service. When fill_in is not - specified, credentials are not validated. Validation can be invoked - by invoking ``is_valid()`` - :param identity_version (string): identity API version is used to - select the matching auth provider and credentials class - :param disable_ssl_certificate_validation: whether to enforce SSL - certificate validation in SSL API requests to the auth system - :param ca_certs: CA certificate bundle for validation of certificates - in SSL API requests to the auth system - :param trace_requests: trace in log API requests to the auth system - :param http_timeout: timeout in seconds to wait for the http request to - return - :param kwargs (dict): Dict of credential key/value pairs - - Examples: - - Returns credentials from the provided parameters: - >>> get_credentials(username='foo', password='bar') - - Returns credentials including IDs: - >>> get_credentials(username='foo', password='bar', fill_in=True) - """ - if not is_identity_version_supported(identity_version): - raise exceptions.InvalidIdentityVersion( - identity_version=identity_version) - - credential_class, auth_provider_class = IDENTITY_VERSION.get( - identity_version) - - creds = credential_class(**kwargs) - # Fill in the credentials fields that were not specified - if fill_in: - dscv = disable_ssl_certificate_validation - auth_provider = auth_provider_class( - creds, auth_url, disable_ssl_certificate_validation=dscv, - ca_certs=ca_certs, trace_requests=trace_requests, - http_timeout=http_timeout) - creds = auth_provider.fill_credentials() - return creds - - -class Credentials(object): - """Set of credentials for accessing OpenStack services - - ATTRIBUTES: list of valid class attributes representing credentials. - """ - - ATTRIBUTES = [] - COLLISIONS = [] - - def __init__(self, **kwargs): - """Enforce the available attributes at init time (only). - - Additional attributes can still be set afterwards if tests need - to do so. - """ - self._initial = kwargs - self._apply_credentials(kwargs) - - def _apply_credentials(self, attr): - for (key1, key2) in self.COLLISIONS: - val1 = attr.get(key1) - val2 = attr.get(key2) - if val1 and val2 and val1 != val2: - msg = ('Cannot have conflicting values for %s and %s' % - (key1, key2)) - raise exceptions.InvalidCredentials(msg) - for key in attr: - if key in self.ATTRIBUTES: - setattr(self, key, attr[key]) - else: - msg = '%s is not a valid attr for %s' % (key, self.__class__) - raise exceptions.InvalidCredentials(msg) - - def __str__(self): - """Represent only attributes included in self.ATTRIBUTES""" - attrs = [attr for attr in self.ATTRIBUTES if attr is not 'password'] - _repr = dict((k, getattr(self, k)) for k in attrs) - return str(_repr) - - def __eq__(self, other): - """Credentials are equal if attributes in self.ATTRIBUTES are equal""" - return str(self) == str(other) - - def __ne__(self, other): - """Contrary to the __eq__""" - return not self.__eq__(other) - - def __getattr__(self, key): - # If an attribute is set, __getattr__ is not invoked - # If an attribute is not set, and it is a known one, return None - if key in self.ATTRIBUTES: - return None - else: - raise AttributeError - - def __delitem__(self, key): - # For backwards compatibility, support dict behaviour - if key in self.ATTRIBUTES: - delattr(self, key) - else: - raise AttributeError - - def get(self, item, default=None): - # In this patch act as dict for backward compatibility - try: - return getattr(self, item) - except AttributeError: - return default - - def get_init_attributes(self): - return self._initial.keys() - - def is_valid(self): - raise NotImplementedError - - def reset(self): - # First delete all known attributes - for key in self.ATTRIBUTES: - if getattr(self, key) is not None: - delattr(self, key) - # Then re-apply initial setup - self._apply_credentials(self._initial) - - -class KeystoneV2Credentials(Credentials): - - ATTRIBUTES = ['username', 'password', 'tenant_name', 'user_id', - 'tenant_id', 'project_id', 'project_name'] - COLLISIONS = [('project_name', 'tenant_name'), ('project_id', 'tenant_id')] - - def __str__(self): - """Represent only attributes included in self.ATTRIBUTES""" - attrs = [attr for attr in self.ATTRIBUTES if attr is not 'password'] - _repr = dict((k, getattr(self, k)) for k in attrs) - return str(_repr) - - def __setattr__(self, key, value): - # NOTE(andreaf) In order to ease the migration towards 'project' we - # support v2 credentials configured with 'project' and translate it - # to tenant on the fly. The original kwargs are stored for clients - # that may rely on them. We also set project when tenant is defined - # so clients can rely on project being part of credentials. - parent = super(KeystoneV2Credentials, self) - # for project_* set tenant only - if key == 'project_id': - parent.__setattr__('tenant_id', value) - elif key == 'project_name': - parent.__setattr__('tenant_name', value) - if key == 'tenant_id': - parent.__setattr__('project_id', value) - elif key == 'tenant_name': - parent.__setattr__('project_name', value) - # trigger default behaviour for all attributes - parent.__setattr__(key, value) - - def is_valid(self): - """Check of credentials (no API call) - - Minimum set of valid credentials, are username and password. - Tenant is optional. - """ - return None not in (self.username, self.password) - - -class KeystoneV3Credentials(Credentials): - """Credentials suitable for the Keystone Identity V3 API""" - - ATTRIBUTES = ['domain_id', 'domain_name', 'password', 'username', - 'project_domain_id', 'project_domain_name', 'project_id', - 'project_name', 'tenant_id', 'tenant_name', 'user_domain_id', - 'user_domain_name', 'user_id'] - COLLISIONS = [('project_name', 'tenant_name'), ('project_id', 'tenant_id')] - - def __setattr__(self, key, value): - parent = super(KeystoneV3Credentials, self) - # for tenant_* set both project and tenant - if key == 'tenant_id': - parent.__setattr__('project_id', value) - elif key == 'tenant_name': - parent.__setattr__('project_name', value) - # for project_* set both project and tenant - if key == 'project_id': - parent.__setattr__('tenant_id', value) - elif key == 'project_name': - parent.__setattr__('tenant_name', value) - # for *_domain_* set both user and project if not set yet - if key == 'user_domain_id': - if self.project_domain_id is None: - parent.__setattr__('project_domain_id', value) - if key == 'project_domain_id': - if self.user_domain_id is None: - parent.__setattr__('user_domain_id', value) - if key == 'user_domain_name': - if self.project_domain_name is None: - parent.__setattr__('project_domain_name', value) - if key == 'project_domain_name': - if self.user_domain_name is None: - parent.__setattr__('user_domain_name', value) - # support domain_name coming from config - if key == 'domain_name': - if self.user_domain_name is None: - parent.__setattr__('user_domain_name', value) - if self.project_domain_name is None: - parent.__setattr__('project_domain_name', value) - # finally trigger default behaviour for all attributes - parent.__setattr__(key, value) - - def is_valid(self): - """Check of credentials (no API call) - - Valid combinations of v3 credentials (excluding token) - - User id, password (optional domain) - - User name, password and its domain id/name - For the scope, valid combinations are: - - None - - Project id (optional domain) - - Project name and its domain id/name - - Domain id - - Domain name - """ - valid_user_domain = any( - [self.user_domain_id is not None, - self.user_domain_name is not None]) - valid_project_domain = any( - [self.project_domain_id is not None, - self.project_domain_name is not None]) - valid_user = any( - [self.user_id is not None, - self.username is not None and valid_user_domain]) - valid_project_scope = any( - [self.project_name is None and self.project_id is None, - self.project_id is not None, - self.project_name is not None and valid_project_domain]) - valid_domain_scope = any( - [self.domain_id is None and self.domain_name is None, - self.domain_id or self.domain_name]) - return all([self.password is not None, - valid_user, - valid_project_scope and valid_domain_scope]) - - -IDENTITY_VERSION = {'v2': (KeystoneV2Credentials, KeystoneV2AuthProvider), - 'v3': (KeystoneV3Credentials, KeystoneV3AuthProvider)} diff --git a/tempest/lib/base.py b/tempest/lib/base.py deleted file mode 100644 index 33a32eefc..000000000 --- a/tempest/lib/base.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 os - -import fixtures -import testtools - - -class BaseTestCase(testtools.testcase.WithAttributes, testtools.TestCase): - setUpClassCalled = False - - # NOTE(sdague): log_format is defined inline here instead of using the oslo - # default because going through the config path recouples config to the - # stress tests too early, and depending on testr order will fail unit tests - log_format = ('%(asctime)s %(process)d %(levelname)-8s ' - '[%(name)s] %(message)s') - - @classmethod - def setUpClass(cls): - if hasattr(super(BaseTestCase, cls), 'setUpClass'): - super(BaseTestCase, cls).setUpClass() - cls.setUpClassCalled = True - - @classmethod - def tearDownClass(cls): - if hasattr(super(BaseTestCase, cls), 'tearDownClass'): - super(BaseTestCase, cls).tearDownClass() - - def setUp(self): - super(BaseTestCase, self).setUp() - if not self.setUpClassCalled: - raise RuntimeError("setUpClass does not calls the super's " - "setUpClass in the " - + self.__class__.__name__) - test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0) - try: - test_timeout = int(test_timeout) - except ValueError: - test_timeout = 0 - if test_timeout > 0: - self.useFixture(fixtures.Timeout(test_timeout, gentle=True)) - - if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or - os.environ.get('OS_STDOUT_CAPTURE') == '1'): - stdout = self.useFixture(fixtures.StringStream('stdout')).stream - self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout)) - if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or - os.environ.get('OS_STDERR_CAPTURE') == '1'): - stderr = self.useFixture(fixtures.StringStream('stderr')).stream - self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr)) - if (os.environ.get('OS_LOG_CAPTURE') != 'False' and - os.environ.get('OS_LOG_CAPTURE') != '0'): - self.useFixture(fixtures.LoggerFixture(nuke_handlers=False, - format=self.log_format, - level=None)) diff --git a/tempest/lib/cli/__init__.py b/tempest/lib/cli/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/cli/base.py b/tempest/lib/cli/base.py deleted file mode 100644 index 5468a7bcd..000000000 --- a/tempest/lib/cli/base.py +++ /dev/null @@ -1,416 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 os -import shlex -import subprocess - -from oslo_log import log as logging -import six - -from tempest.lib import base -import tempest.lib.cli.output_parser -from tempest.lib import exceptions - - -LOG = logging.getLogger(__name__) - - -def execute(cmd, action, flags='', params='', fail_ok=False, - merge_stderr=False, cli_dir='/usr/bin', prefix=''): - """Executes specified command for the given action. - - :param cmd: command to be executed - :type cmd: string - :param action: string of the cli command to run - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: string of any optional positional args to use - :type params: string - :param fail_ok: boolean if True an exception is not raised when the - cli return code is non-zero - :type fail_ok: boolean - :param merge_stderr: boolean if True the stderr buffer is merged into - stdout - :type merge_stderr: boolean - :param cli_dir: The path where the cmd can be executed - :type cli_dir: string - :param prefix: prefix to insert before command - :type prefix: string - """ - cmd = ' '.join([prefix, os.path.join(cli_dir, cmd), - flags, action, params]) - cmd = cmd.strip() - LOG.info("running: '%s'", cmd) - if six.PY2: - cmd = cmd.encode('utf-8') - cmd = shlex.split(cmd) - result = '' - result_err = '' - stdout = subprocess.PIPE - stderr = subprocess.STDOUT if merge_stderr else subprocess.PIPE - proc = subprocess.Popen(cmd, stdout=stdout, stderr=stderr) - result, result_err = proc.communicate() - if not fail_ok and proc.returncode != 0: - raise exceptions.CommandFailed(proc.returncode, - cmd, - result, - result_err) - if six.PY2: - return result - else: - return os.fsdecode(result) - - -class CLIClient(object): - """Class to use OpenStack official python client CLI's with auth - - :param username: The username to authenticate with - :type username: string - :param password: The password to authenticate with - :type password: string - :param tenant_name: The name of the tenant to use with the client calls - :type tenant_name: string - :param uri: The auth uri for the OpenStack Deployment - :type uri: string - :param cli_dir: The path where the python client binaries are installed. - defaults to /usr/bin - :type cli_dir: string - :param insecure: if True, --insecure is passed to python client binaries. - :type insecure: boolean - :param prefix: prefix to insert before commands - :type prefix: string - """ - - def __init__(self, username='', password='', tenant_name='', uri='', - cli_dir='', insecure=False, prefix='', *args, **kwargs): - """Initialize a new CLIClient object.""" - super(CLIClient, self).__init__() - self.cli_dir = cli_dir if cli_dir else '/usr/bin' - self.username = username - self.tenant_name = tenant_name - self.password = password - self.uri = uri - self.insecure = insecure - self.prefix = prefix - - def nova(self, action, flags='', params='', fail_ok=False, - endpoint_type='publicURL', merge_stderr=False): - """Executes nova command for the given action. - - :param action: the cli command to run using nova - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: any optional positional args to use - :type params: string - :param fail_ok: if True an exception is not raised when the - cli return code is non-zero - :type fail_ok: boolean - :param endpoint_type: the type of endpoint for the service - :type endpoint_type: string - :param merge_stderr: if True the stderr buffer is merged into stdout - :type merge_stderr: boolean - """ - flags += ' --os-endpoint-type %s' % endpoint_type - return self.cmd_with_auth( - 'nova', action, flags, params, fail_ok, merge_stderr) - - def nova_manage(self, action, flags='', params='', fail_ok=False, - merge_stderr=False): - """Executes nova-manage command for the given action. - - :param action: the cli command to run using nova-manage - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: any optional positional args to use - :type params: string - :param fail_ok: if True an exception is not raised when the - cli return code is non-zero - :type fail_ok: boolean - :param merge_stderr: if True the stderr buffer is merged into stdout - :type merge_stderr: boolean - """ - return execute( - 'nova-manage', action, flags, params, fail_ok, merge_stderr, - self.cli_dir) - - def keystone(self, action, flags='', params='', fail_ok=False, - merge_stderr=False): - """Executes keystone command for the given action. - - :param action: the cli command to run using keystone - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: any optional positional args to use - :type params: string - :param fail_ok: if True an exception is not raised when the - cli return code is non-zero - :type fail_ok: boolean - :param merge_stderr: if True the stderr buffer is merged into stdout - :type merge_stderr: boolean - """ - return self.cmd_with_auth( - 'keystone', action, flags, params, fail_ok, merge_stderr) - - def glance(self, action, flags='', params='', fail_ok=False, - endpoint_type='publicURL', merge_stderr=False): - """Executes glance command for the given action. - - :param action: the cli command to run using glance - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: any optional positional args to use - :type params: string - :param fail_ok: if True an exception is not raised when the - cli return code is non-zero - :type fail_ok: boolean - :param endpoint_type: the type of endpoint for the service - :type endpoint_type: string - :param merge_stderr: if True the stderr buffer is merged into stdout - :type merge_stderr: boolean - """ - flags += ' --os-endpoint-type %s' % endpoint_type - return self.cmd_with_auth( - 'glance', action, flags, params, fail_ok, merge_stderr) - - def ceilometer(self, action, flags='', params='', - fail_ok=False, endpoint_type='publicURL', - merge_stderr=False): - """Executes ceilometer command for the given action. - - :param action: the cli command to run using ceilometer - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: any optional positional args to use - :type params: string - :param fail_ok: if True an exception is not raised when the - cli return code is non-zero - :type fail_ok: boolean - :param endpoint_type: the type of endpoint for the service - :type endpoint_type: string - :param merge_stderr: if True the stderr buffer is merged into stdout - :type merge_stderr: boolean - """ - flags += ' --os-endpoint-type %s' % endpoint_type - return self.cmd_with_auth( - 'ceilometer', action, flags, params, fail_ok, merge_stderr) - - def heat(self, action, flags='', params='', - fail_ok=False, endpoint_type='publicURL', merge_stderr=False): - """Executes heat command for the given action. - - :param action: the cli command to run using heat - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: any optional positional args to use - :type params: string - :param fail_ok: if True an exception is not raised when the - cli return code is non-zero - :type fail_ok: boolean - :param endpoint_type: the type of endpoint for the service - :type endpoint_type: string - :param merge_stderr: if True the stderr buffer is merged into stdout - :type merge_stderr: boolean - """ - flags += ' --os-endpoint-type %s' % endpoint_type - return self.cmd_with_auth( - 'heat', action, flags, params, fail_ok, merge_stderr) - - def cinder(self, action, flags='', params='', fail_ok=False, - endpoint_type='publicURL', merge_stderr=False): - """Executes cinder command for the given action. - - :param action: the cli command to run using cinder - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: any optional positional args to use - :type params: string - :param fail_ok: if True an exception is not raised when the - cli return code is non-zero - :type fail_ok: boolean - :param endpoint_type: the type of endpoint for the service - :type endpoint_type: string - :param merge_stderr: if True the stderr buffer is merged into stdout - :type merge_stderr: boolean - """ - flags += ' --endpoint-type %s' % endpoint_type - return self.cmd_with_auth( - 'cinder', action, flags, params, fail_ok, merge_stderr) - - def swift(self, action, flags='', params='', fail_ok=False, - endpoint_type='publicURL', merge_stderr=False): - """Executes swift command for the given action. - - :param action: the cli command to run using swift - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: any optional positional args to use - :type params: string - :param fail_ok: if True an exception is not raised when the - cli return code is non-zero - :type fail_ok: boolean - :param endpoint_type: the type of endpoint for the service - :type endpoint_type: string - :param merge_stderr: if True the stderr buffer is merged into stdout - :type merge_stderr: boolean - """ - flags += ' --os-endpoint-type %s' % endpoint_type - return self.cmd_with_auth( - 'swift', action, flags, params, fail_ok, merge_stderr) - - def neutron(self, action, flags='', params='', fail_ok=False, - endpoint_type='publicURL', merge_stderr=False): - """Executes neutron command for the given action. - - :param action: the cli command to run using neutron - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: any optional positional args to use - :type params: string - :param fail_ok: if True an exception is not raised when the - cli return code is non-zero - :type fail_ok: boolean - :param endpoint_type: the type of endpoint for the service - :type endpoint_type: string - :param merge_stderr: if True the stderr buffer is merged into stdout - :type merge_stderr: boolean - """ - flags += ' --endpoint-type %s' % endpoint_type - return self.cmd_with_auth( - 'neutron', action, flags, params, fail_ok, merge_stderr) - - def sahara(self, action, flags='', params='', - fail_ok=False, endpoint_type='publicURL', merge_stderr=True): - """Executes sahara command for the given action. - - :param action: the cli command to run using sahara - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: any optional positional args to use - :type params: string - :param fail_ok: if True an exception is not raised when the - cli return code is non-zero - :type fail_ok: boolean - :param endpoint_type: the type of endpoint for the service - :type endpoint_type: string - :param merge_stderr: if True the stderr buffer is merged into stdout - :type merge_stderr: boolean - """ - flags += ' --endpoint-type %s' % endpoint_type - return self.cmd_with_auth( - 'sahara', action, flags, params, fail_ok, merge_stderr) - - def openstack(self, action, flags='', params='', fail_ok=False, - merge_stderr=False): - """Executes openstack command for the given action. - - :param action: the cli command to run using openstack - :type action: string - :param flags: any optional cli flags to use - :type flags: string - :param params: any optional positional args to use - :type params: string - :param fail_ok: if True an exception is not raised when the - cli return code is non-zero - :type fail_ok: boolean - :param merge_stderr: if True the stderr buffer is merged into stdout - :type merge_stderr: boolean - """ - return self.cmd_with_auth( - 'openstack', action, flags, params, fail_ok, merge_stderr) - - def cmd_with_auth(self, cmd, action, flags='', params='', - fail_ok=False, merge_stderr=False): - """Executes given command with auth attributes appended. - - :param cmd: command to be executed - :type cmd: string - :param action: command on cli to run - :type action: string - :param flags: optional cli flags to use - :type flags: string - :param params: optional positional args to use - :type params: string - :param fail_ok: if True an exception is not raised when the cli return - code is non-zero - :type fail_ok: boolean - :param merge_stderr: if True the stderr buffer is merged into stdout - :type merge_stderr: boolean - """ - creds = ('--os-username %s --os-tenant-name %s --os-password %s ' - '--os-auth-url %s' % - (self.username, - self.tenant_name, - self.password, - self.uri)) - if self.insecure: - flags = creds + ' --insecure ' + flags - else: - flags = creds + ' ' + flags - return execute(cmd, action, flags, params, fail_ok, merge_stderr, - self.cli_dir, prefix=self.prefix) - - -class ClientTestBase(base.BaseTestCase): - """Base test class for testing the OpenStack client CLI interfaces.""" - - def setUp(self): - super(ClientTestBase, self).setUp() - self.clients = self._get_clients() - self.parser = tempest.lib.cli.output_parser - - def _get_clients(self): - """Abstract method to initialize CLIClient object. - - This method must be overloaded in child test classes. It should be - used to initialize the CLIClient object with the appropriate - credentials during the setUp() phase of tests. - """ - raise NotImplementedError - - def assertTableStruct(self, items, field_names): - """Verify that all items has keys listed in field_names. - - :param items: items to assert are field names in the output table - :type items: list - :param field_names: field names from the output table of the cmd - :type field_names: list - """ - for item in items: - for field in field_names: - self.assertIn(field, item) - - def assertFirstLineStartsWith(self, lines, beginning): - """Verify that the first line starts with a string - - :param lines: strings for each line of output - :type lines: list - :param beginning: verify this is at the beginning of the first line - :type beginning: string - """ - self.assertTrue(lines[0].startswith(beginning), - msg=('Beginning of first line has invalid content: %s' - % lines[:3])) diff --git a/tempest/lib/cli/output_parser.py b/tempest/lib/cli/output_parser.py deleted file mode 100644 index 2edd5c16f..000000000 --- a/tempest/lib/cli/output_parser.py +++ /dev/null @@ -1,171 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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. - -"""Collection of utilities for parsing CLI clients output.""" - -import re - -from oslo_log import log as logging - -from tempest.lib import exceptions - - -LOG = logging.getLogger(__name__) - - -delimiter_line = re.compile('^\+\-[\+\-]+\-\+$') - - -def details_multiple(output_lines, with_label=False): - """Return list of dicts with item details from cli output tables. - - If with_label is True, key '__label' is added to each items dict. - For more about 'label' see OutputParser.tables(). - """ - items = [] - tables_ = tables(output_lines) - for table_ in tables_: - if ('Property' not in table_['headers'] - or 'Value' not in table_['headers']): - raise exceptions.InvalidStructure() - item = {} - for value in table_['values']: - item[value[0]] = value[1] - if with_label: - item['__label'] = table_['label'] - items.append(item) - return items - - -def details(output_lines, with_label=False): - """Return dict with details of first item (table) found in output.""" - items = details_multiple(output_lines, with_label) - return items[0] - - -def listing(output_lines): - """Return list of dicts with basic item info parsed from cli output.""" - - items = [] - table_ = table(output_lines) - for row in table_['values']: - item = {} - for col_idx, col_key in enumerate(table_['headers']): - item[col_key] = row[col_idx] - items.append(item) - return items - - -def tables(output_lines): - """Find all ascii-tables in output and parse them. - - Return list of tables parsed from cli output as dicts. - (see OutputParser.table()) - - And, if found, label key (separated line preceding the table) - is added to each tables dict. - """ - tables_ = [] - - table_ = [] - label = None - - start = False - header = False - - if not isinstance(output_lines, list): - output_lines = output_lines.split('\n') - - for line in output_lines: - if delimiter_line.match(line): - if not start: - start = True - elif not header: - # we are after head area - header = True - else: - # table ends here - start = header = None - table_.append(line) - - parsed = table(table_) - parsed['label'] = label - tables_.append(parsed) - - table_ = [] - label = None - continue - if start: - table_.append(line) - else: - if label is None: - label = line - else: - LOG.warning('Invalid line between tables: %s', line) - if table_: - LOG.warning('Missing end of table') - - return tables_ - - -def table(output_lines): - """Parse single table from cli output. - - Return dict with list of column names in 'headers' key and - rows in 'values' key. - """ - table_ = {'headers': [], 'values': []} - columns = None - - if not isinstance(output_lines, list): - output_lines = output_lines.split('\n') - - if not output_lines[-1]: - # skip last line if empty (just newline at the end) - output_lines = output_lines[:-1] - - for line in output_lines: - if delimiter_line.match(line): - columns = _table_columns(line) - continue - if '|' not in line: - LOG.warning('skipping invalid table line: %s', line) - continue - row = [] - for col in columns: - row.append(line[col[0]:col[1]].strip()) - if table_['headers']: - table_['values'].append(row) - else: - table_['headers'] = row - - return table_ - - -def _table_columns(first_table_row): - """Find column ranges in output line. - - Return list of tuples (start,end) for each column - detected by plus (+) characters in delimiter line. - """ - positions = [] - start = 1 # there is '+' at 0 - while start < len(first_table_row): - end = first_table_row.find('+', start) - if end == -1: - break - positions.append((start, end)) - start = end + 1 - return positions diff --git a/tempest/lib/cmd/__init__.py b/tempest/lib/cmd/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/cmd/check_uuid.py b/tempest/lib/cmd/check_uuid.py deleted file mode 100755 index 101d692c2..000000000 --- a/tempest/lib/cmd/check_uuid.py +++ /dev/null @@ -1,362 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2014 Mirantis, Inc. -# -# 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 argparse -import ast -import importlib -import inspect -import os -import sys -import unittest -import uuid - -from oslo_utils import uuidutils -import six.moves.urllib.parse as urlparse - -DECORATOR_MODULE = 'decorators' -DECORATOR_NAME = 'idempotent_id' -DECORATOR_IMPORT = 'tempest.%s' % DECORATOR_MODULE -IMPORT_LINE = 'from tempest.lib import %s' % DECORATOR_MODULE -DECORATOR_TEMPLATE = "@%s.%s('%%s')" % (DECORATOR_MODULE, - DECORATOR_NAME) -UNIT_TESTS_EXCLUDE = 'tempest.tests' - - -class SourcePatcher(object): - - """"Lazy patcher for python source files""" - - def __init__(self): - self.source_files = None - self.patches = None - self.clear() - - def clear(self): - """Clear inner state""" - self.source_files = {} - self.patches = {} - - @staticmethod - def _quote(s): - return urlparse.quote(s) - - @staticmethod - def _unquote(s): - return urlparse.unquote(s) - - def add_patch(self, filename, patch, line_no): - """Add lazy patch""" - if filename not in self.source_files: - with open(filename) as f: - self.source_files[filename] = self._quote(f.read()) - patch_id = uuidutils.generate_uuid() - if not patch.endswith('\n'): - patch += '\n' - self.patches[patch_id] = self._quote(patch) - lines = self.source_files[filename].split(self._quote('\n')) - lines[line_no - 1] = ''.join(('{%s:s}' % patch_id, lines[line_no - 1])) - self.source_files[filename] = self._quote('\n').join(lines) - - @staticmethod - def _save_changes(filename, source): - print('%s fixed' % filename) - with open(filename, 'w') as f: - f.write(source) - - def apply_patches(self): - """Apply all patches""" - for filename in self.source_files: - patched_source = self._unquote( - self.source_files[filename].format(**self.patches) - ) - self._save_changes(filename, patched_source) - self.clear() - - -class TestChecker(object): - - def __init__(self, package): - self.package = package - self.base_path = os.path.abspath(os.path.dirname(package.__file__)) - - def _path_to_package(self, path): - relative_path = path[len(self.base_path) + 1:] - if relative_path: - return '.'.join((self.package.__name__,) + - tuple(relative_path.split('/'))) - else: - return self.package.__name__ - - def _modules_search(self): - """Recursive search for python modules in base package""" - modules = [] - for root, dirs, files in os.walk(self.base_path): - if not os.path.exists(os.path.join(root, '__init__.py')): - continue - root_package = self._path_to_package(root) - for item in files: - if item.endswith('.py'): - module_name = '.'.join((root_package, - os.path.splitext(item)[0])) - if not module_name.startswith(UNIT_TESTS_EXCLUDE): - modules.append(module_name) - return modules - - @staticmethod - def _get_idempotent_id(test_node): - "Return key-value dict with metadata from @decorators.idempotent_id" - idempotent_id = None - for decorator in test_node.decorator_list: - if (hasattr(decorator, 'func') and - hasattr(decorator.func, 'attr') and - decorator.func.attr == DECORATOR_NAME and - hasattr(decorator.func, 'value') and - decorator.func.value.id == DECORATOR_MODULE): - for arg in decorator.args: - idempotent_id = ast.literal_eval(arg) - return idempotent_id - - @staticmethod - def _is_decorator(line): - return line.strip().startswith('@') - - @staticmethod - def _is_def(line): - return line.strip().startswith('def ') - - def _add_uuid_to_test(self, patcher, test_node, source_path): - with open(source_path) as src: - src_lines = src.read().split('\n') - lineno = test_node.lineno - insert_position = lineno - while True: - if (self._is_def(src_lines[lineno - 1]) or - (self._is_decorator(src_lines[lineno - 1]) and - (DECORATOR_TEMPLATE.split('(')[0] <= - src_lines[lineno - 1].strip().split('(')[0]))): - insert_position = lineno - break - lineno += 1 - patcher.add_patch( - source_path, - ' ' * test_node.col_offset + DECORATOR_TEMPLATE % uuid.uuid4(), - insert_position - ) - - @staticmethod - def _is_test_case(module, node): - if (node.__class__ is ast.ClassDef and - hasattr(module, node.name) and - inspect.isclass(getattr(module, node.name))): - return issubclass(getattr(module, node.name), unittest.TestCase) - - @staticmethod - def _is_test_method(node): - return (node.__class__ is ast.FunctionDef - and node.name.startswith('test_')) - - @staticmethod - def _next_node(body, node): - if body.index(node) < len(body): - return body[body.index(node) + 1] - - @staticmethod - def _import_name(node): - if isinstance(node, ast.Import): - return node.names[0].name - elif isinstance(node, ast.ImportFrom): - return '%s.%s' % (node.module, node.names[0].name) - - def _add_import_for_test_uuid(self, patcher, src_parsed, source_path): - with open(source_path) as f: - src_lines = f.read().split('\n') - line_no = 0 - tempest_imports = [node for node in src_parsed.body - if self._import_name(node) and - 'tempest.' in self._import_name(node)] - if not tempest_imports: - import_snippet = '\n'.join(('', IMPORT_LINE, '')) - else: - for node in tempest_imports: - if self._import_name(node) < DECORATOR_IMPORT: - continue - else: - line_no = node.lineno - import_snippet = IMPORT_LINE - break - else: - line_no = tempest_imports[-1].lineno - while True: - if (not src_lines[line_no - 1] or - getattr(self._next_node(src_parsed.body, - tempest_imports[-1]), - 'lineno') == line_no or - line_no == len(src_lines)): - break - line_no += 1 - import_snippet = '\n'.join((IMPORT_LINE, '')) - patcher.add_patch(source_path, import_snippet, line_no) - - def get_tests(self): - """Get test methods with sources from base package with metadata""" - tests = {} - for module_name in self._modules_search(): - tests[module_name] = {} - module = importlib.import_module(module_name) - source_path = '.'.join( - (os.path.splitext(module.__file__)[0], 'py') - ) - with open(source_path, 'r') as f: - source = f.read() - tests[module_name]['source_path'] = source_path - tests[module_name]['tests'] = {} - source_parsed = ast.parse(source) - tests[module_name]['ast'] = source_parsed - tests[module_name]['import_valid'] = ( - hasattr(module, DECORATOR_MODULE) and - inspect.ismodule(getattr(module, DECORATOR_MODULE)) - ) - test_cases = (node for node in source_parsed.body - if self._is_test_case(module, node)) - for node in test_cases: - for subnode in filter(self._is_test_method, node.body): - test_name = '%s.%s' % (node.name, subnode.name) - tests[module_name]['tests'][test_name] = subnode - return tests - - @staticmethod - def _filter_tests(function, tests): - """Filter tests with condition 'function(test_node) == True'""" - result = {} - for module_name in tests: - for test_name in tests[module_name]['tests']: - if function(module_name, test_name, tests): - if module_name not in result: - result[module_name] = { - 'ast': tests[module_name]['ast'], - 'source_path': tests[module_name]['source_path'], - 'import_valid': tests[module_name]['import_valid'], - 'tests': {} - } - result[module_name]['tests'][test_name] = \ - tests[module_name]['tests'][test_name] - return result - - def find_untagged(self, tests): - """Filter all tests without uuid in metadata""" - def check_uuid_in_meta(module_name, test_name, tests): - idempotent_id = self._get_idempotent_id( - tests[module_name]['tests'][test_name]) - return not idempotent_id - return self._filter_tests(check_uuid_in_meta, tests) - - def report_collisions(self, tests): - """Reports collisions if there are any - - Returns true if collisions exist. - """ - uuids = {} - - def report(module_name, test_name, tests): - test_uuid = self._get_idempotent_id( - tests[module_name]['tests'][test_name]) - if not test_uuid: - return - if test_uuid in uuids: - error_str = "%s:%s\n uuid %s collision: %s<->%s\n%s:%s" % ( - tests[module_name]['source_path'], - tests[module_name]['tests'][test_name].lineno, - test_uuid, - test_name, - uuids[test_uuid]['test_name'], - uuids[test_uuid]['source_path'], - uuids[test_uuid]['test_node'].lineno, - ) - print(error_str) - print("cannot automatically resolve the collision, please " - "manually remove the duplicate value on the new test.") - return True - else: - uuids[test_uuid] = { - 'module': module_name, - 'test_name': test_name, - 'test_node': tests[module_name]['tests'][test_name], - 'source_path': tests[module_name]['source_path'] - } - return bool(self._filter_tests(report, tests)) - - def report_untagged(self, tests): - """Reports untagged tests if there are any - - Returns true if untagged tests exist. - """ - def report(module_name, test_name, tests): - error_str = ("%s:%s\nmissing @decorators.idempotent_id" - "('...')\n%s\n") % ( - tests[module_name]['source_path'], - tests[module_name]['tests'][test_name].lineno, - test_name - ) - print(error_str) - return True - return bool(self._filter_tests(report, tests)) - - def fix_tests(self, tests): - """Add uuids to all specified in tests and fix it in source files""" - patcher = SourcePatcher() - for module_name in tests: - add_import_once = True - for test_name in tests[module_name]['tests']: - if not tests[module_name]['import_valid'] and add_import_once: - self._add_import_for_test_uuid( - patcher, - tests[module_name]['ast'], - tests[module_name]['source_path'] - ) - add_import_once = False - self._add_uuid_to_test( - patcher, tests[module_name]['tests'][test_name], - tests[module_name]['source_path']) - patcher.apply_patches() - - -def run(): - parser = argparse.ArgumentParser() - parser.add_argument('--package', action='store', dest='package', - default='tempest', type=str, - help='Package with tests') - parser.add_argument('--fix', action='store_true', dest='fix_tests', - help='Attempt to fix tests without UUIDs') - args = parser.parse_args() - sys.path.append(os.path.join(os.path.dirname(__file__), '..')) - pkg = importlib.import_module(args.package) - checker = TestChecker(pkg) - errors = False - tests = checker.get_tests() - untagged = checker.find_untagged(tests) - errors = checker.report_collisions(tests) or errors - if args.fix_tests and untagged: - checker.fix_tests(untagged) - else: - errors = checker.report_untagged(untagged) or errors - if errors: - sys.exit("@decorators.idempotent_id existence and uniqueness checks " - "failed\n" - "Run 'tox -v -e uuidgen' to automatically fix tests with\n" - "missing @decorators.idempotent_id decorators.") - -if __name__ == '__main__': - run() diff --git a/tempest/lib/cmd/skip_tracker.py b/tempest/lib/cmd/skip_tracker.py deleted file mode 100755 index 87806b7fc..000000000 --- a/tempest/lib/cmd/skip_tracker.py +++ /dev/null @@ -1,168 +0,0 @@ -#!/usr/bin/env python2 - -# Copyright 2012 OpenStack Foundation -# 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. - -""" -Track test skips via launchpadlib API and raise alerts if a bug -is fixed but a skip is still in the Tempest test code -""" - -import argparse -import os -import re - -from oslo_log import log as logging - -try: - from launchpadlib import launchpad -except ImportError: - launchpad = None - -LPCACHEDIR = os.path.expanduser('~/.launchpadlib/cache') -LOG = logging.getLogger(__name__) - -BASEDIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../..')) -TESTDIR = os.path.join(BASEDIR, 'tempest') - - -def parse_args(): - parser = argparse.ArgumentParser() - parser.add_argument('test_path', nargs='?', default=TESTDIR, - help='Path of test dir') - return parser.parse_args() - - -def info(msg, *args, **kwargs): - LOG.info(msg, *args, **kwargs) - - -def debug(msg, *args, **kwargs): - LOG.debug(msg, *args, **kwargs) - - -def find_skips(start): - """Find the entire list of skipped tests. - - Returns a list of tuples (method, bug) that represent - test methods that have been decorated to skip because of - a particular bug. - """ - results = {} - debug("Searching in %s", start) - for root, _dirs, files in os.walk(start): - for name in files: - if name.startswith('test_') and name.endswith('py'): - path = os.path.join(root, name) - debug("Searching in %s", path) - temp_result = find_skips_in_file(path) - for method_name, bug_no in temp_result: - if results.get(bug_no): - result_dict = results.get(bug_no) - if result_dict.get(name): - result_dict[name].append(method_name) - else: - result_dict[name] = [method_name] - results[bug_no] = result_dict - else: - results[bug_no] = {name: [method_name]} - return results - - -def find_skips_in_file(path): - """Return the skip tuples in a test file.""" - BUG_RE = re.compile(r'\s*@.*skip_because\(bug=[\'"](\d+)[\'"]') - DEF_RE = re.compile(r'\s*def (\w+)\(') - bug_found = False - results = [] - with open(path, 'rb') as content: - lines = content.readlines() - for x, line in enumerate(lines): - if not bug_found: - res = BUG_RE.match(line) - if res: - bug_no = int(res.group(1)) - debug("Found bug skip %s on line %d", bug_no, x + 1) - bug_found = True - else: - res = DEF_RE.match(line) - if res: - method = res.group(1) - debug("Found test method %s skips for bug %d", - method, bug_no) - results.append((method, bug_no)) - bug_found = False - return results - - -def get_results(result_dict): - results = [] - for bug_no in result_dict: - for method in result_dict[bug_no]: - results.append((method, bug_no)) - return results - - -def main(): - parser = parse_args() - results = find_skips(parser.test_path) - unique_bugs = sorted(set([bug for (method, bug) in get_results(results)])) - unskips = [] - duplicates = [] - info("Total bug skips found: %d", len(results)) - info("Total unique bugs causing skips: %d", len(unique_bugs)) - if launchpad is not None: - lp = launchpad.Launchpad.login_anonymously('grabbing bugs', - 'production', - LPCACHEDIR) - else: - print("To check the bug status launchpadlib should be installed") - exit(1) - - for bug_no in unique_bugs: - bug = lp.bugs[bug_no] - duplicate = bug.duplicate_of_link - if duplicate is not None: - dup_id = duplicate.split('/')[-1] - duplicates.append((bug_no, dup_id)) - for task in bug.bug_tasks: - info("Bug #%7s (%12s - %12s)", bug_no, - task.importance, task.status) - if task.status in ('Fix Released', 'Fix Committed'): - unskips.append(bug_no) - - for bug_id, dup_id in duplicates: - if bug_id not in unskips: - dup_bug = lp.bugs[dup_id] - for task in dup_bug.bug_tasks: - info("Bug #%7s is a duplicate of Bug#%7s (%12s - %12s)", - bug_id, dup_id, task.importance, task.status) - if task.status in ('Fix Released', 'Fix Committed'): - unskips.append(bug_id) - - unskips = sorted(set(unskips)) - if unskips: - print("The following bugs have been fixed and the corresponding skips") - print("should be removed from the test cases:") - print() - for bug in unskips: - message = " %7s in " % bug - locations = ["%s" % x for x in results[bug].keys()] - message += " and ".join(locations) - print(message) - - -if __name__ == '__main__': - main() diff --git a/tempest/lib/common/__init__.py b/tempest/lib/common/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/common/api_version_request.py b/tempest/lib/common/api_version_request.py deleted file mode 100644 index b2b68a6b2..000000000 --- a/tempest/lib/common/api_version_request.py +++ /dev/null @@ -1,159 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# 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 re - -from tempest.lib import exceptions - - -# Define the minimum and maximum version of the API across all of the -# REST API. The format of the version is: -# X.Y where: -# -# - X will only be changed if a significant backwards incompatible API -# change is made which affects the API as whole. That is, something -# that is only very very rarely incremented. -# -# - Y when you make any change to the API. Note that this includes -# semantic changes which may not affect the input or output formats or -# even originate in the API code layer. We are not distinguishing -# between backwards compatible and backwards incompatible changes in -# the versioning system. It must be made clear in the documentation as -# to what is a backwards compatible change and what is a backwards -# incompatible one. - -class APIVersionRequest(object): - """This class represents an API Version Request. - - This class provides convenience methods for manipulation - and comparison of version numbers that we need to do to - implement microversions. - - :param version_string: String representation of APIVersionRequest. - Correct format is 'X.Y', where 'X' and 'Y' are int values. - None value should be used to create Null APIVersionRequest, - which is equal to 0.0 - """ - - # NOTE: This 'latest' version is a magic number, we assume any - # projects(Nova, etc.) never achieve this number. - latest_ver_major = 99999 - latest_ver_minor = 99999 - - def __init__(self, version_string=None): - """Create an API version request object.""" - # NOTE(gmann): 'version_string' as String "None" will be considered as - # invalid version string. - self.ver_major = 0 - self.ver_minor = 0 - - if version_string is not None: - match = re.match(r"^([1-9]\d*)\.([1-9]\d*|0)$", - version_string) - if match: - self.ver_major = int(match.group(1)) - self.ver_minor = int(match.group(2)) - elif version_string == 'latest': - self.ver_major = self.latest_ver_major - self.ver_minor = self.latest_ver_minor - else: - raise exceptions.InvalidAPIVersionString( - version=version_string) - - def __str__(self): - """Debug/Logging representation of object.""" - return ("API Version Request: %s" % self.get_string()) - - def is_null(self): - """Checks whether version is null. - - Return True if version object is null otherwise False. - - :returns: boolean - """ - return self.ver_major == 0 and self.ver_minor == 0 - - def _format_type_error(self, other): - return TypeError("'%(other)s' should be an instance of '%(cls)s'" % - {"other": other, "cls": self.__class__}) - - def __lt__(self, other): - if not isinstance(other, APIVersionRequest): - raise self._format_type_error(other) - - return ((self.ver_major, self.ver_minor) < - (other.ver_major, other.ver_minor)) - - def __eq__(self, other): - if not isinstance(other, APIVersionRequest): - raise self._format_type_error(other) - - return ((self.ver_major, self.ver_minor) == - (other.ver_major, other.ver_minor)) - - def __gt__(self, other): - if not isinstance(other, APIVersionRequest): - raise self._format_type_error(other) - - return ((self.ver_major, self.ver_minor) > - (other.ver_major, other.ver_minor)) - - def __le__(self, other): - return self < other or self == other - - def __ne__(self, other): - return not self.__eq__(other) - - def __ge__(self, other): - return self > other or self == other - - def matches(self, min_version, max_version): - """Matches the version object. - - Returns whether the version object represents a version - greater than or equal to the minimum version and less than - or equal to the maximum version. - - :param min_version: Minimum acceptable version. - :param max_version: Maximum acceptable version. - :returns: boolean - - If min_version is null then there is no minimum limit. - If max_version is null then there is no maximum limit. - If self is null then raise ValueError - """ - - if self.is_null(): - raise ValueError - if max_version.is_null() and min_version.is_null(): - return True - elif max_version.is_null(): - return min_version <= self - elif min_version.is_null(): - return self <= max_version - else: - return min_version <= self <= max_version - - def get_string(self): - """Version string representation. - - Converts object to string representation which if used to create - an APIVersionRequest object results in the same version request. - """ - if self.is_null(): - return None - if (self.ver_major == self.latest_ver_major and - self.ver_minor == self.latest_ver_minor): - return 'latest' - return "%s.%s" % (self.ver_major, self.ver_minor) diff --git a/tempest/lib/common/api_version_utils.py b/tempest/lib/common/api_version_utils.py deleted file mode 100644 index 1371b3c66..000000000 --- a/tempest/lib/common/api_version_utils.py +++ /dev/null @@ -1,122 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 testtools - -from tempest.lib.common import api_version_request -from tempest.lib import exceptions - - -LATEST_MICROVERSION = 'latest' - - -class BaseMicroversionTest(object): - """Mixin class for API microversion test class.""" - - # NOTE: Basically, each microversion is small API change and we - # can use the same tests for most microversions in most cases. - # So it is nice to define the test class as possible to run - # for all microversions. We need to define microversion range - # (min_microversion, max_microversion) on each test class if necessary. - min_microversion = None - max_microversion = LATEST_MICROVERSION - - -def check_skip_with_microversion(test_min_version, test_max_version, - cfg_min_version, cfg_max_version): - """Checks API microversions range and returns whether test needs to be skip - - Compare the test and configured microversion range and returns - whether test microversion range is out of configured one. - This method can be used to skip the test based on configured and test - microversion range. - - :param test_min_version: Test Minimum Microversion - :param test_max_version: Test Maximum Microversion - :param cfg_min_version: Configured Minimum Microversion - :param cfg_max_version: Configured Maximum Microversion - :returns: boolean - """ - - min_version = api_version_request.APIVersionRequest(test_min_version) - max_version = api_version_request.APIVersionRequest(test_max_version) - config_min_version = api_version_request.APIVersionRequest(cfg_min_version) - config_max_version = api_version_request.APIVersionRequest(cfg_max_version) - if ((min_version > max_version) or - (config_min_version > config_max_version)): - msg = ("Test Class versions [%s - %s]. " - "Configuration versions [%s - %s]." - % (min_version.get_string(), - max_version.get_string(), - config_min_version.get_string(), - config_max_version.get_string())) - raise exceptions.InvalidAPIVersionRange(msg) - - # NOTE: Select tests which are in range of configuration like - # config min config max - # ----------------+--------------------------+---------------- - # ...don't-select| - # ...select... ...select... ...select... - # |don't-select... - # ......................select............................ - if (max_version < config_min_version or - config_max_version < min_version): - msg = ("The microversion range[%s - %s] of this test is out of the " - "configuration range[%s - %s]." - % (min_version.get_string(), - max_version.get_string(), - config_min_version.get_string(), - config_max_version.get_string())) - raise testtools.TestCase.skipException(msg) - - -def select_request_microversion(test_min_version, cfg_min_version): - """Select microversion from test and configuration min version. - - Compare requested microversion and return the maximum - microversion out of those. - - :param test_min_version: Test Minimum Microversion - :param cfg_min_version: Configured Minimum Microversion - :returns: Selected microversion string - """ - - test_version = api_version_request.APIVersionRequest(test_min_version) - cfg_version = api_version_request.APIVersionRequest(cfg_min_version) - max_version = cfg_version if cfg_version >= test_version else test_version - return max_version.get_string() - - -def assert_version_header_matches_request(api_microversion_header_name, - api_microversion, - response_header): - """Checks API microversion in response header - - Verify whether microversion is present in response header - and with specified 'api_microversion' value. - - :param api_microversion_header_name: Microversion header name - Example- "X-OpenStack-Nova-API-Version" - :param api_microversion: Microversion number like "2.10" - :param response_header: Response header where microversion is - expected to be present. - """ - api_microversion_header_name = api_microversion_header_name.lower() - if (api_microversion_header_name not in response_header or - api_microversion != response_header[api_microversion_header_name]): - msg = ("Microversion header '%s' with value '%s' does not match in " - "response - %s. " % (api_microversion_header_name, - api_microversion, - response_header)) - raise exceptions.InvalidHTTPResponseHeader(msg) diff --git a/tempest/lib/common/cred_client.py b/tempest/lib/common/cred_client.py deleted file mode 100644 index a81f53c9c..000000000 --- a/tempest/lib/common/cred_client.py +++ /dev/null @@ -1,212 +0,0 @@ -# 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 abc - -from oslo_log import log as logging -import six - -from tempest.lib import auth -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.identity.v2 import identity_client as v2_identity - -LOG = logging.getLogger(__name__) - - -@six.add_metaclass(abc.ABCMeta) -class CredsClient(object): - """This class is a wrapper around the identity clients - - to provide a single interface for managing credentials in both v2 and v3 - cases. It's not bound to created credentials, only to a specific set of - admin credentials used for generating credentials. - """ - - def __init__(self, identity_client, projects_client, users_client, - roles_client): - # The client implies version and credentials - self.identity_client = identity_client - self.users_client = users_client - self.projects_client = projects_client - self.roles_client = roles_client - - def create_user(self, username, password, project, email): - params = {'name': username, - 'password': password, - self.project_id_param: project['id'], - 'email': email} - user = self.users_client.create_user(**params) - if 'user' in user: - user = user['user'] - return user - - def delete_user(self, user_id): - self.users_client.delete_user(user_id) - - @abc.abstractmethod - def create_project(self, name, description): - pass - - def _check_role_exists(self, role_name): - try: - roles = self._list_roles() - lc_role_name = role_name.lower() - role = next(r for r in roles if r['name'].lower() == lc_role_name) - except StopIteration: - return None - return role - - def create_user_role(self, role_name): - if not self._check_role_exists(role_name): - self.roles_client.create_role(name=role_name) - - def assign_user_role(self, user, project, role_name): - role = self._check_role_exists(role_name) - if not role: - msg = 'No "%s" role found' % role_name - raise lib_exc.NotFound(msg) - try: - self.roles_client.create_user_role_on_project(project['id'], - user['id'], - role['id']) - except lib_exc.Conflict: - LOG.debug("Role %s already assigned on project %s for user %s", - role['id'], project['id'], user['id']) - - @abc.abstractmethod - def get_credentials(self, user, project, password): - """Produces a Credentials object from the details provided - - :param user: a user dict - :param project: a project dict - :param password: the password as a string - :return: a Credentials object with all the available credential details - """ - pass - - def _list_roles(self): - roles = self.roles_client.list_roles()['roles'] - return roles - - -class V2CredsClient(CredsClient): - project_id_param = 'tenantId' - - def __init__(self, identity_client, projects_client, users_client, - roles_client): - super(V2CredsClient, self).__init__(identity_client, - projects_client, - users_client, - roles_client) - - def create_project(self, name, description): - tenant = self.projects_client.create_tenant( - name=name, description=description)['tenant'] - return tenant - - def delete_project(self, project_id): - self.projects_client.delete_tenant(project_id) - - def get_credentials(self, user, project, password): - # User and project already include both ID and name here, - # so there's no need to use the fill_in mode - return auth.get_credentials( - auth_url=None, - fill_in=False, - identity_version='v2', - username=user['name'], user_id=user['id'], - tenant_name=project['name'], tenant_id=project['id'], - password=password) - - -class V3CredsClient(CredsClient): - project_id_param = 'project_id' - - def __init__(self, identity_client, projects_client, users_client, - roles_client, domains_client, domain_name): - super(V3CredsClient, self).__init__(identity_client, projects_client, - users_client, roles_client) - self.domains_client = domains_client - - try: - # Domain names must be unique, in any case a list is returned, - # selecting the first (and only) element - self.creds_domain = self.domains_client.list_domains( - name=domain_name)['domains'][0] - except lib_exc.NotFound: - # TODO(andrea) we could probably create the domain on the fly - msg = "Requested domain %s could not be found" % domain_name - raise lib_exc.InvalidCredentials(msg) - - def create_project(self, name, description): - project = self.projects_client.create_project( - name=name, description=description, - domain_id=self.creds_domain['id'])['project'] - return project - - def delete_project(self, project_id): - self.projects_client.delete_project(project_id) - - def get_credentials(self, user, project, password): - # User, project and domain already include both ID and name here, - # so there's no need to use the fill_in mode. - # NOTE(andreaf) We need to set all fields in the returned credentials. - # Scope is then used to pick only those relevant for the type of - # token needed by each service client. - return auth.get_credentials( - auth_url=None, - fill_in=False, - identity_version='v3', - username=user['name'], user_id=user['id'], - project_name=project['name'], project_id=project['id'], - password=password, - project_domain_id=self.creds_domain['id'], - project_domain_name=self.creds_domain['name'], - domain_id=self.creds_domain['id'], - domain_name=self.creds_domain['name']) - - def assign_user_role_on_domain(self, user, role_name, domain=None): - """Assign the specified role on a domain - - :param user: a user dict - :param role_name: name of the role to be assigned - :param domain: (optional) The domain to assign the role on. If not - specified the default domain of cred_client - """ - # NOTE(andreaf) This method is very specific to the v3 case, and - # because of that it's not defined in the parent class. - if domain is None: - domain = self.creds_domain - role = self._check_role_exists(role_name) - if not role: - msg = 'No "%s" role found' % role_name - raise lib_exc.NotFound(msg) - try: - self.roles_client.create_user_role_on_domain( - domain['id'], user['id'], role['id']) - except lib_exc.Conflict: - LOG.debug("Role %s already assigned on domain %s for user %s", - role['id'], domain['id'], user['id']) - - -def get_creds_client(identity_client, - projects_client, - users_client, - roles_client, - domains_client=None, - project_domain_name=None): - if isinstance(identity_client, v2_identity.IdentityClient): - return V2CredsClient(identity_client, projects_client, users_client, - roles_client) - else: - return V3CredsClient(identity_client, projects_client, users_client, - roles_client, domains_client, project_domain_name) diff --git a/tempest/lib/common/cred_provider.py b/tempest/lib/common/cred_provider.py deleted file mode 100644 index 42ed41b39..000000000 --- a/tempest/lib/common/cred_provider.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright (c) 2014 Deutsche Telekom AG -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# 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 abc - -import six - -from tempest.lib import auth -from tempest.lib import exceptions - - -@six.add_metaclass(abc.ABCMeta) -class CredentialProvider(object): - def __init__(self, identity_version, name=None, - network_resources=None, credentials_domain=None, - admin_role=None, identity_uri=None): - """A CredentialProvider supplies credentials to test classes. - - :param identity_version: Identity version of the credentials provided - :param name: Name of the calling test. Included in provisioned - credentials when credentials are provisioned on the fly - :param network_resources: Network resources required for the - credentials - :param credentials_domain: Domain credentials belong to - :param admin_role: Name of the role of the admin account - :param identity_uri: Identity URI of the target cloud. This *must* be - specified for anything to work. - """ - self.identity_version = identity_version - self.identity_uri = identity_uri - self.name = name or "test_creds" - self.network_resources = network_resources - self.credentials_domain = credentials_domain or 'Default' - self.admin_role = admin_role - if not auth.is_identity_version_supported(self.identity_version): - raise exceptions.InvalidIdentityVersion( - identity_version=self.identity_version) - - @abc.abstractmethod - def get_primary_creds(self): - return - - @abc.abstractmethod - def get_admin_creds(self): - return - - @abc.abstractmethod - def get_alt_creds(self): - return - - @abc.abstractmethod - def clear_creds(self): - return - - @abc.abstractmethod - def is_multi_user(self): - return - - @abc.abstractmethod - def is_multi_tenant(self): - return - - @abc.abstractmethod - def get_creds_by_roles(self, roles, force_new=False): - return - - @abc.abstractmethod - def is_role_available(self, role): - return - - -class TestResources(object): - """Readonly Credentials, with network resources added.""" - - def __init__(self, credentials): - self._credentials = credentials - self.network = None - self.subnet = None - self.router = None - - def __getattr__(self, item): - return getattr(self._credentials, item) - - def __str__(self): - _format = "Credentials: %s, Network: %s, Subnet: %s, Router: %s" - return _format % (self._credentials, self.network, self.subnet, - self.router) - - def set_resources(self, **kwargs): - for key in kwargs: - if hasattr(self, key): - setattr(self, key, kwargs[key]) - - @property - def credentials(self): - return self._credentials diff --git a/tempest/lib/common/dynamic_creds.py b/tempest/lib/common/dynamic_creds.py deleted file mode 100644 index 90e67b4d4..000000000 --- a/tempest/lib/common/dynamic_creds.py +++ /dev/null @@ -1,477 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# 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 ipaddress - -import netaddr -from oslo_log import log as logging -import six - -from tempest.lib.common import cred_client -from tempest.lib.common import cred_provider -from tempest.lib.common.utils import data_utils -from tempest.lib import exceptions as lib_exc -from tempest.lib.services import clients - -LOG = logging.getLogger(__name__) - - -class DynamicCredentialProvider(cred_provider.CredentialProvider): - - def __init__(self, identity_version, name=None, network_resources=None, - credentials_domain=None, admin_role=None, admin_creds=None, - identity_admin_domain_scope=False, - identity_admin_role='admin', extra_roles=None, - neutron_available=False, create_networks=True, - project_network_cidr=None, project_network_mask_bits=None, - public_network_id=None, resource_prefix=None, - identity_admin_endpoint_type='public', identity_uri=None): - """Creates credentials dynamically for tests - - A credential provider that, based on an initial set of - admin credentials, creates new credentials on the fly for - tests to use and then discard. - - :param str identity_version: identity API version to use `v2` or `v3` - :param str admin_role: name of the admin role added to admin users - :param str name: names of dynamic resources include this parameter - when specified - :param str credentials_domain: name of the domain where the users - are created. If not defined, the project - domain from admin_credentials is used - :param dict network_resources: network resources to be created for - the created credentials - :param Credentials admin_creds: initial admin credentials - :param bool identity_admin_domain_scope: Set to true if admin should be - scoped to the domain. By - default this is False and the - admin role is scoped to the - project. - :param str identity_admin_role: The role name to use for admin - :param list extra_roles: A list of strings for extra roles that should - be assigned to all created users - :param bool neutron_available: Whether we are running in an environemnt - with neutron - :param bool create_networks: Whether dynamic project networks should be - created or not - :param project_network_cidr: The CIDR to use for created project - networks - :param project_network_mask_bits: The network mask bits to use for - created project networks - :param public_network_id: The id for the public network to use - :param identity_admin_endpoint_type: The endpoint type for identity - admin clients. Defaults to public. - :param identity_uri: Identity URI of the target cloud - """ - super(DynamicCredentialProvider, self).__init__( - identity_version=identity_version, identity_uri=identity_uri, - admin_role=admin_role, name=name, - credentials_domain=credentials_domain, - network_resources=network_resources) - self.network_resources = network_resources - self._creds = {} - self.ports = [] - self.resource_prefix = resource_prefix or '' - self.neutron_available = neutron_available - self.create_networks = create_networks - self.project_network_cidr = project_network_cidr - self.project_network_mask_bits = project_network_mask_bits - self.public_network_id = public_network_id - self.default_admin_creds = admin_creds - self.identity_admin_domain_scope = identity_admin_domain_scope - self.identity_admin_role = identity_admin_role or 'admin' - self.identity_admin_endpoint_type = identity_admin_endpoint_type - self.extra_roles = extra_roles or [] - (self.identity_admin_client, - self.tenants_admin_client, - self.users_admin_client, - self.roles_admin_client, - self.domains_admin_client, - self.networks_admin_client, - self.routers_admin_client, - self.subnets_admin_client, - self.ports_admin_client, - self.security_groups_admin_client) = self._get_admin_clients( - identity_admin_endpoint_type) - # Domain where isolated credentials are provisioned (v3 only). - # Use that of the admin account is None is configured. - self.creds_domain_name = None - if self.identity_version == 'v3': - self.creds_domain_name = ( - self.default_admin_creds.project_domain_name or - self.credentials_domain) - self.creds_client = cred_client.get_creds_client( - self.identity_admin_client, - self.tenants_admin_client, - self.users_admin_client, - self.roles_admin_client, - self.domains_admin_client, - self.creds_domain_name) - - def _get_admin_clients(self, endpoint_type): - """Returns a tuple with instances of the following admin clients - - (in this order): - identity - network - """ - os = clients.ServiceClients(self.default_admin_creds, - self.identity_uri) - params = {'endpoint_type': endpoint_type} - if self.identity_version == 'v2': - return (os.identity_v2.IdentityClient(**params), - os.identity_v2.TenantsClient(**params), - os.identity_v2.UsersClient(**params), - os.identity_v2.RolesClient(**params), None, - os.network.NetworksClient(), - os.network.RoutersClient(), - os.network.SubnetsClient(), - os.network.PortsClient(), - os.network.SecurityGroupsClient()) - else: - # We use a dedicated client manager for identity client in case we - # need a different token scope for them. - scope = 'domain' if self.identity_admin_domain_scope else 'project' - identity_os = clients.ServiceClients(self.default_admin_creds, - self.identity_uri, - scope=scope) - return (identity_os.identity_v3.IdentityClient(**params), - identity_os.identity_v3.ProjectsClient(**params), - identity_os.identity_v3.UsersClient(**params), - identity_os.identity_v3.RolesClient(**params), - identity_os.identity_v3.DomainsClient(**params), - os.network.NetworksClient(), - os.network.RoutersClient(), - os.network.SubnetsClient(), - os.network.PortsClient(), - os.network.SecurityGroupsClient()) - - def _create_creds(self, admin=False, roles=None): - """Create credentials with random name. - - Creates project and user. When admin flag is True create user - with admin role. Assign user with additional roles (for example - _member_) and roles requested by caller. - - :param admin: Flag if to assign to the user admin role - :type admin: bool - :param roles: Roles to assign for the user - :type roles: list - :return: Readonly Credentials with network resources - """ - root = self.name - - project_name = data_utils.rand_name(root, prefix=self.resource_prefix) - project_desc = project_name + "-desc" - project = self.creds_client.create_project( - name=project_name, description=project_desc) - - # NOTE(andreaf) User and project can be distinguished from the context, - # having the same ID in both makes it easier to match them and debug. - username = project_name - user_password = data_utils.rand_password() - email = data_utils.rand_name( - root, prefix=self.resource_prefix) + "@example.com" - user = self.creds_client.create_user( - username, user_password, project, email) - role_assigned = False - if admin: - self.creds_client.assign_user_role(user, project, self.admin_role) - role_assigned = True - if (self.identity_version == 'v3' and - self.identity_admin_domain_scope): - self.creds_client.assign_user_role_on_domain( - user, self.identity_admin_role) - # Add roles specified in config file - for conf_role in self.extra_roles: - self.creds_client.assign_user_role(user, project, conf_role) - role_assigned = True - # Add roles requested by caller - if roles: - for role in roles: - self.creds_client.assign_user_role(user, project, role) - role_assigned = True - # NOTE(mtreinish) For a user to have access to a project with v3 auth - # it must beassigned a role on the project. So we need to ensure that - # our newly created user has a role on the newly created project. - if self.identity_version == 'v3' and not role_assigned: - try: - self.creds_client.create_user_role('Member') - except lib_exc.Conflict: - LOG.warning('Member role already exists, ignoring conflict.') - self.creds_client.assign_user_role(user, project, 'Member') - - creds = self.creds_client.get_credentials(user, project, user_password) - return cred_provider.TestResources(creds) - - def _create_network_resources(self, tenant_id): - """The function creates network resources in the given tenant. - - The function checks if network_resources class member is empty, - In case it is, it will create a network, a subnet and a router for - the tenant according to the given tenant id parameter. - Otherwise it will create a network resource according - to the values from network_resources dict. - - :param tenant_id: The tenant id to create resources for. - :type tenant_id: str - :raises: InvalidConfiguration, Exception - :returns: network resources(network,subnet,router) - :rtype: tuple - """ - network = None - subnet = None - router = None - # Make sure settings - if self.network_resources: - if self.network_resources['router']: - if (not self.network_resources['subnet'] or - not self.network_resources['network']): - raise lib_exc.InvalidConfiguration( - 'A router requires a subnet and network') - elif self.network_resources['subnet']: - if not self.network_resources['network']: - raise lib_exc.InvalidConfiguration( - 'A subnet requires a network') - elif self.network_resources['dhcp']: - raise lib_exc.InvalidConfiguration('DHCP requires a subnet') - - rand_name_root = data_utils.rand_name( - self.name, prefix=self.resource_prefix) - if not self.network_resources or self.network_resources['network']: - network_name = rand_name_root + "-network" - network = self._create_network(network_name, tenant_id) - try: - if not self.network_resources or self.network_resources['subnet']: - subnet_name = rand_name_root + "-subnet" - subnet = self._create_subnet(subnet_name, tenant_id, - network['id']) - if not self.network_resources or self.network_resources['router']: - router_name = rand_name_root + "-router" - router = self._create_router(router_name, tenant_id) - self._add_router_interface(router['id'], subnet['id']) - except Exception: - try: - if router: - self._clear_isolated_router(router['id'], router['name']) - if subnet: - self._clear_isolated_subnet(subnet['id'], subnet['name']) - if network: - self._clear_isolated_network(network['id'], - network['name']) - except Exception as cleanup_exception: - msg = "There was an exception trying to setup network " \ - "resources for tenant %s, and this error happened " \ - "trying to clean them up: %s" - LOG.warning(msg, tenant_id, cleanup_exception) - raise - return network, subnet, router - - def _create_network(self, name, tenant_id): - resp_body = self.networks_admin_client.create_network( - name=name, tenant_id=tenant_id) - return resp_body['network'] - - def _create_subnet(self, subnet_name, tenant_id, network_id): - base_cidr = netaddr.IPNetwork(self.project_network_cidr) - mask_bits = self.project_network_mask_bits - for subnet_cidr in base_cidr.subnet(mask_bits): - try: - if self.network_resources: - resp_body = self.subnets_admin_client.\ - create_subnet( - network_id=network_id, cidr=str(subnet_cidr), - name=subnet_name, - tenant_id=tenant_id, - enable_dhcp=self.network_resources['dhcp'], - ip_version=(ipaddress.ip_network( - six.text_type(subnet_cidr)).version)) - else: - resp_body = self.subnets_admin_client.\ - create_subnet(network_id=network_id, - cidr=str(subnet_cidr), - name=subnet_name, - tenant_id=tenant_id, - ip_version=(ipaddress.ip_network( - six.text_type(subnet_cidr)).version)) - break - except lib_exc.BadRequest as e: - if 'overlaps with another subnet' not in str(e): - raise - else: - message = 'Available CIDR for subnet creation could not be found' - raise Exception(message) - return resp_body['subnet'] - - def _create_router(self, router_name, tenant_id): - kwargs = {'name': router_name, - 'tenant_id': tenant_id} - if self.public_network_id: - kwargs['external_gateway_info'] = dict( - network_id=self.public_network_id) - resp_body = self.routers_admin_client.create_router(**kwargs) - return resp_body['router'] - - def _add_router_interface(self, router_id, subnet_id): - self.routers_admin_client.add_router_interface(router_id, - subnet_id=subnet_id) - - def get_credentials(self, credential_type): - if self._creds.get(str(credential_type)): - credentials = self._creds[str(credential_type)] - else: - if credential_type in ['primary', 'alt', 'admin']: - is_admin = (credential_type == 'admin') - credentials = self._create_creds(admin=is_admin) - else: - credentials = self._create_creds(roles=credential_type) - self._creds[str(credential_type)] = credentials - # Maintained until tests are ported - LOG.info("Acquired dynamic creds:\n credentials: %s", credentials) - if (self.neutron_available and - self.create_networks): - network, subnet, router = self._create_network_resources( - credentials.tenant_id) - credentials.set_resources(network=network, subnet=subnet, - router=router) - LOG.info("Created isolated network resources for : \n" - + " credentials: %s", credentials) - return credentials - - def get_primary_creds(self): - return self.get_credentials('primary') - - def get_admin_creds(self): - return self.get_credentials('admin') - - def get_alt_creds(self): - return self.get_credentials('alt') - - def get_creds_by_roles(self, roles, force_new=False): - roles = list(set(roles)) - # The roles list as a str will become the index as the dict key for - # the created credentials set in the dynamic_creds dict. - exist_creds = self._creds.get(str(roles)) - # If force_new flag is True 2 cred sets with the same roles are needed - # handle this by creating a separate index for old one to store it - # separately for cleanup - if exist_creds and force_new: - new_index = str(roles) + '-' + str(len(self._creds)) - self._creds[new_index] = exist_creds - del self._creds[str(roles)] - return self.get_credentials(roles) - - def _clear_isolated_router(self, router_id, router_name): - client = self.routers_admin_client - try: - client.delete_router(router_id) - except lib_exc.NotFound: - LOG.warning('router with name: %s not found for delete', - router_name) - - def _clear_isolated_subnet(self, subnet_id, subnet_name): - client = self.subnets_admin_client - try: - client.delete_subnet(subnet_id) - except lib_exc.NotFound: - LOG.warning('subnet with name: %s not found for delete', - subnet_name) - - def _clear_isolated_network(self, network_id, network_name): - net_client = self.networks_admin_client - try: - net_client.delete_network(network_id) - except lib_exc.NotFound: - LOG.warning('network with name: %s not found for delete', - network_name) - - def _cleanup_default_secgroup(self, tenant): - nsg_client = self.security_groups_admin_client - resp_body = nsg_client.list_security_groups(tenant_id=tenant, - name="default") - secgroups_to_delete = resp_body['security_groups'] - for secgroup in secgroups_to_delete: - try: - nsg_client.delete_security_group(secgroup['id']) - except lib_exc.NotFound: - LOG.warning('Security group %s, id %s not found for clean-up', - secgroup['name'], secgroup['id']) - - def _clear_isolated_net_resources(self): - client = self.routers_admin_client - for cred in self._creds: - creds = self._creds.get(cred) - if (not creds or not any([creds.router, creds.network, - creds.subnet])): - continue - LOG.debug("Clearing network: %(network)s, " - "subnet: %(subnet)s, router: %(router)s", - {'network': creds.network, 'subnet': creds.subnet, - 'router': creds.router}) - if (not self.network_resources or - (self.network_resources.get('router') and creds.subnet)): - try: - client.remove_router_interface( - creds.router['id'], - subnet_id=creds.subnet['id']) - except lib_exc.NotFound: - LOG.warning('router with name: %s not found for delete', - creds.router['name']) - self._clear_isolated_router(creds.router['id'], - creds.router['name']) - if (not self.network_resources or - self.network_resources.get('subnet')): - self._clear_isolated_subnet(creds.subnet['id'], - creds.subnet['name']) - if (not self.network_resources or - self.network_resources.get('network')): - self._clear_isolated_network(creds.network['id'], - creds.network['name']) - - def clear_creds(self): - if not self._creds: - return - self._clear_isolated_net_resources() - for creds in six.itervalues(self._creds): - try: - self.creds_client.delete_user(creds.user_id) - except lib_exc.NotFound: - LOG.warning("user with name: %s not found for delete", - creds.username) - # NOTE(zhufl): Only when neutron's security_group ext is - # enabled, _cleanup_default_secgroup will not raise error. But - # here cannot use test.is_extension_enabled for it will cause - # "circular dependency". So here just use try...except to - # ensure tenant deletion without big changes. - try: - if self.neutron_available: - self._cleanup_default_secgroup(creds.tenant_id) - except lib_exc.NotFound: - LOG.warning("failed to cleanup tenant %s's secgroup", - creds.tenant_name) - try: - self.creds_client.delete_project(creds.tenant_id) - except lib_exc.NotFound: - LOG.warning("tenant with name: %s not found for delete", - creds.tenant_name) - self._creds = {} - - def is_multi_user(self): - return True - - def is_multi_tenant(self): - return True - - def is_role_available(self, role): - return True diff --git a/tempest/lib/common/fixed_network.py b/tempest/lib/common/fixed_network.py deleted file mode 100644 index e2054a4d1..000000000 --- a/tempest/lib/common/fixed_network.py +++ /dev/null @@ -1,127 +0,0 @@ -# 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 copy - -from oslo_log import log as logging - -from tempest.lib.common.utils import test_utils -from tempest.lib import exceptions - -LOG = logging.getLogger(__name__) - - -def get_network_from_name(name, compute_networks_client): - """Get a full network dict from just a network name - - :param str name: the name of the network to use - :param NetworksClient compute_networks_client: The network client - object to use for making the network lists api request - :return: The full dictionary for the network in question - :rtype: dict - :raises InvalidTestResource: If the name provided is invalid, the networks - list returns a 404, there are no found networks, or the found network - is invalid - """ - caller = test_utils.find_test_caller() - - if not name: - raise exceptions.InvalidTestResource(type='network', name=name) - - networks = compute_networks_client.list_networks()['networks'] - networks = [n for n in networks if n['label'] == name] - - # Check that a network exists, else raise an InvalidConfigurationException - if len(networks) == 1: - network = sorted(networks)[0] - elif len(networks) > 1: - msg = ("Network with name: %s had multiple matching networks in the " - "list response: %s\n Unable to specify a single network" % ( - name, networks)) - if caller: - msg = '(%s) %s' % (caller, msg) - LOG.warning(msg) - raise exceptions.InvalidTestResource(type='network', name=name) - else: - msg = "Network with name: %s not found" % name - if caller: - msg = '(%s) %s' % (caller, msg) - LOG.warning(msg) - raise exceptions.InvalidTestResource(type='network', name=name) - # To be consistent between neutron and nova network always use name even - # if label is used in the api response. If neither is present than then - # the returned network is invalid. - name = network.get('name') or network.get('label') - if not name: - msg = "Network found from list doesn't contain a valid name or label" - if caller: - msg = '(%s) %s' % (caller, msg) - LOG.warning(msg) - raise exceptions.InvalidTestResource(type='network', name=name) - network['name'] = name - return network - - -def get_tenant_network(creds_provider, compute_networks_client, - shared_network_name): - """Get a network usable by the primary tenant - - :param creds_provider: instance of credential provider - :param compute_networks_client: compute network client. We want to have the - compute network client so we can have use a common approach for both - neutron and nova-network cases. If this is not an admin network - client, set_network_kwargs might fail in case fixed_network_name - is the network to be used, and it's not visible to the tenant - :param shared_network_name: name of the shared network to be used if no - tenant network is available in the creds provider - :returns: a dict with 'id' and 'name' of the network - """ - caller = test_utils.find_test_caller() - net_creds = creds_provider.get_primary_creds() - network = getattr(net_creds, 'network', None) - if not network or not network.get('name'): - if shared_network_name: - msg = ('No valid network provided or created, defaulting to ' - 'fixed_network_name') - if caller: - msg = '(%s) %s' % (caller, msg) - LOG.debug(msg) - try: - network = get_network_from_name(shared_network_name, - compute_networks_client) - except exceptions.InvalidTestResource: - network = {} - msg = ('Found network %s available for tenant' % network) - if caller: - msg = '(%s) %s' % (caller, msg) - LOG.info(msg) - return network - - -def set_networks_kwarg(network, kwargs=None): - """Set 'networks' kwargs for a server create if missing - - :param network: dict of network to be used with 'id' and 'name' - :param kwargs: server create kwargs to be enhanced - :return: new dict of kwargs updated to include networks - """ - params = copy.copy(kwargs) or {} - if kwargs and 'networks' in kwargs: - return params - - if network: - if 'id' in network.keys(): - params.update({"networks": [{'uuid': network['id']}]}) - else: - LOG.warning('The provided network dict: %s was invalid and did ' - 'not contain an id', network) - return params diff --git a/tempest/lib/common/http.py b/tempest/lib/common/http.py deleted file mode 100644 index 8a47d4436..000000000 --- a/tempest/lib/common/http.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# 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 six -import urllib3 - - -class ClosingHttp(urllib3.poolmanager.PoolManager): - def __init__(self, disable_ssl_certificate_validation=False, - ca_certs=None, timeout=None): - kwargs = {} - - if disable_ssl_certificate_validation: - urllib3.disable_warnings() - kwargs['cert_reqs'] = 'CERT_NONE' - - if ca_certs: - kwargs['cert_reqs'] = 'CERT_REQUIRED' - kwargs['ca_certs'] = ca_certs - - if timeout: - kwargs['timeout'] = timeout - - super(ClosingHttp, self).__init__(**kwargs) - - def request(self, url, method, *args, **kwargs): - - class Response(dict): - def __init__(self, info): - for key, value in info.getheaders().items(): - # We assume HTTP header name to be string, not random - # bytes, thus ensure we have string keys. - self[six.u(key).lower()] = value - self.status = info.status - self['status'] = str(self.status) - self.reason = info.reason - self.version = info.version - self['content-location'] = url - - original_headers = kwargs.get('headers', {}) - new_headers = dict(original_headers, connection='close') - new_kwargs = dict(kwargs, headers=new_headers) - - # Follow up to 5 redirections. Don't raise an exception if - # it's exceeded but return the HTTP 3XX response instead. - retry = urllib3.util.Retry(raise_on_redirect=False, redirect=5) - r = super(ClosingHttp, self).request(method, url, retries=retry, - *args, **new_kwargs) - return Response(r), r.data diff --git a/tempest/lib/common/jsonschema_validator.py b/tempest/lib/common/jsonschema_validator.py deleted file mode 100644 index bbdf38255..000000000 --- a/tempest/lib/common/jsonschema_validator.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2016 NEC Corporation. -# 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 jsonschema -from oslo_utils import timeutils - -# JSON Schema validator and format checker used for JSON Schema validation -JSONSCHEMA_VALIDATOR = jsonschema.Draft4Validator -FORMAT_CHECKER = jsonschema.draft4_format_checker - - -# NOTE(gmann): Add customized format checker for 'date-time' format because: -# 1. jsonschema needs strict_rfc3339 or isodate module to be installed -# for proper date-time checking as per rfc3339. -# 2. Nova or other OpenStack components handle the date time format as -# ISO 8601 which is defined in oslo_utils.timeutils -# so this checker will validate the date-time as defined in -# oslo_utils.timeutils -@FORMAT_CHECKER.checks('iso8601-date-time') -def _validate_datetime_format(instance): - try: - if isinstance(instance, jsonschema.compat.str_types): - timeutils.parse_isotime(instance) - except ValueError: - return False - else: - return True diff --git a/tempest/lib/common/preprov_creds.py b/tempest/lib/common/preprov_creds.py deleted file mode 100644 index cd3a10e4d..000000000 --- a/tempest/lib/common/preprov_creds.py +++ /dev/null @@ -1,374 +0,0 @@ -# Copyright (c) 2014 Hewlett-Packard Development Company, L.P. -# -# 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 hashlib -import os - -from oslo_concurrency import lockutils -from oslo_log import log as logging -import six -import yaml - -from tempest.lib import auth -from tempest.lib.common import cred_provider -from tempest.lib.common import fixed_network -from tempest.lib import exceptions as lib_exc -from tempest.lib.services import clients - -LOG = logging.getLogger(__name__) - - -def read_accounts_yaml(path): - try: - with open(path, 'r') as yaml_file: - accounts = yaml.safe_load(yaml_file) - except IOError: - raise lib_exc.InvalidConfiguration( - 'The path for the test accounts file: %s ' - 'could not be found' % path) - return accounts - - -class PreProvisionedCredentialProvider(cred_provider.CredentialProvider): - - # Exclude from the hash fields specific to v2 or v3 identity API - # i.e. only include user*, project*, tenant* and password - HASH_CRED_FIELDS = (set(auth.KeystoneV2Credentials.ATTRIBUTES) & - set(auth.KeystoneV3Credentials.ATTRIBUTES)) - - def __init__(self, identity_version, test_accounts_file, - accounts_lock_dir, name=None, credentials_domain=None, - admin_role=None, object_storage_operator_role=None, - object_storage_reseller_admin_role=None, identity_uri=None): - """Credentials provider using pre-provisioned accounts - - This credentials provider loads the details of pre-provisioned - accounts from a YAML file, in the format specified by - `etc/accounts.yaml.sample`. It locks accounts while in use, using the - external locking mechanism, allowing for multiple python processes - to share a single account file, and thus running tests in parallel. - - The accounts_lock_dir must be generated using `lockutils.get_lock_path` - from the oslo.concurrency library. For instance: - - accounts_lock_dir = os.path.join(lockutils.get_lock_path(CONF), - 'test_accounts') - - Role names for object storage are optional as long as the - `operator` and `reseller_admin` credential types are not used in the - accounts file. - - :param identity_version: identity version of the credentials - :param admin_role: name of the admin role - :param test_accounts_file: path to the accounts YAML file - :param accounts_lock_dir: the directory for external locking - :param name: name of the hash file (optional) - :param credentials_domain: name of the domain credentials belong to - (if no domain is configured) - :param object_storage_operator_role: name of the role - :param object_storage_reseller_admin_role: name of the role - :param identity_uri: Identity URI of the target cloud - """ - super(PreProvisionedCredentialProvider, self).__init__( - identity_version=identity_version, name=name, - admin_role=admin_role, credentials_domain=credentials_domain, - identity_uri=identity_uri) - self.test_accounts_file = test_accounts_file - if test_accounts_file: - accounts = read_accounts_yaml(self.test_accounts_file) - else: - raise lib_exc.InvalidCredentials("No accounts file specified") - self.hash_dict = self.get_hash_dict( - accounts, admin_role, object_storage_operator_role, - object_storage_reseller_admin_role) - self.accounts_dir = accounts_lock_dir - self._creds = {} - - @classmethod - def _append_role(cls, role, account_hash, hash_dict): - if role in hash_dict['roles']: - hash_dict['roles'][role].append(account_hash) - else: - hash_dict['roles'][role] = [account_hash] - return hash_dict - - @classmethod - def get_hash_dict(cls, accounts, admin_role, - object_storage_operator_role=None, - object_storage_reseller_admin_role=None): - hash_dict = {'roles': {}, 'creds': {}, 'networks': {}} - - # Loop over the accounts read from the yaml file - for account in accounts: - roles = [] - types = [] - resources = [] - if 'roles' in account: - roles = account.pop('roles') - if 'types' in account: - types = account.pop('types') - if 'resources' in account: - resources = account.pop('resources') - temp_hash = hashlib.md5() - account_for_hash = dict((k, v) for (k, v) in account.items() - if k in cls.HASH_CRED_FIELDS) - temp_hash.update(six.text_type(account_for_hash).encode('utf-8')) - temp_hash_key = temp_hash.hexdigest() - hash_dict['creds'][temp_hash_key] = account - for role in roles: - hash_dict = cls._append_role(role, temp_hash_key, - hash_dict) - # If types are set for the account append the matching role - # subdict with the hash - for type in types: - if type == 'admin': - hash_dict = cls._append_role(admin_role, temp_hash_key, - hash_dict) - elif type == 'operator': - if object_storage_operator_role: - hash_dict = cls._append_role( - object_storage_operator_role, temp_hash_key, - hash_dict) - else: - msg = ("Type 'operator' configured, but no " - "object_storage_operator_role specified") - raise lib_exc.InvalidCredentials(msg) - elif type == 'reseller_admin': - if object_storage_reseller_admin_role: - hash_dict = cls._append_role( - object_storage_reseller_admin_role, - temp_hash_key, - hash_dict) - else: - msg = ("Type 'reseller_admin' configured, but no " - "object_storage_reseller_admin_role specified") - raise lib_exc.InvalidCredentials(msg) - # Populate the network subdict - for resource in resources: - if resource == 'network': - hash_dict['networks'][temp_hash_key] = resources[resource] - else: - LOG.warning( - 'Unknown resource type %s, ignoring this field', - resource - ) - return hash_dict - - def is_multi_user(self): - return len(self.hash_dict['creds']) > 1 - - def is_multi_tenant(self): - return self.is_multi_user() - - def _create_hash_file(self, hash_string): - path = os.path.join(os.path.join(self.accounts_dir, hash_string)) - if not os.path.isfile(path): - with open(path, 'w') as fd: - fd.write(self.name) - return True - return False - - @lockutils.synchronized('test_accounts_io', external=True) - def _get_free_hash(self, hashes): - # Cast as a list because in some edge cases a set will be passed in - hashes = list(hashes) - if not os.path.isdir(self.accounts_dir): - os.mkdir(self.accounts_dir) - # Create File from first hash (since none are in use) - self._create_hash_file(hashes[0]) - return hashes[0] - names = [] - for _hash in hashes: - res = self._create_hash_file(_hash) - if res: - return _hash - else: - path = os.path.join(os.path.join(self.accounts_dir, - _hash)) - with open(path, 'r') as fd: - names.append(fd.read()) - msg = ('Insufficient number of users provided. %s have allocated all ' - 'the credentials for this allocation request' % ','.join(names)) - raise lib_exc.InvalidCredentials(msg) - - def _get_match_hash_list(self, roles=None): - hashes = [] - if roles: - # Loop over all the creds for each role in the subdict and generate - # a list of cred lists for each role - for role in roles: - temp_hashes = self.hash_dict['roles'].get(role, None) - if not temp_hashes: - raise lib_exc.InvalidCredentials( - "No credentials with role: %s specified in the " - "accounts ""file" % role) - hashes.append(temp_hashes) - # Take the list of lists and do a boolean and between each list to - # find the creds which fall under all the specified roles - temp_list = set(hashes[0]) - for hash_list in hashes[1:]: - temp_list = temp_list & set(hash_list) - hashes = temp_list - else: - hashes = self.hash_dict['creds'].keys() - # NOTE(mtreinish): admin is a special case because of the increased - # privilege set which could potentially cause issues on tests where - # that is not expected. So unless the admin role isn't specified do - # not allocate admin. - admin_hashes = self.hash_dict['roles'].get(self.admin_role, - None) - if ((not roles or self.admin_role not in roles) and - admin_hashes): - useable_hashes = [x for x in hashes if x not in admin_hashes] - else: - useable_hashes = hashes - return useable_hashes - - def _sanitize_creds(self, creds): - temp_creds = creds.copy() - temp_creds.pop('password') - return temp_creds - - def _get_creds(self, roles=None): - useable_hashes = self._get_match_hash_list(roles) - if not useable_hashes: - msg = 'No users configured for type/roles %s' % roles - raise lib_exc.InvalidCredentials(msg) - free_hash = self._get_free_hash(useable_hashes) - clean_creds = self._sanitize_creds( - self.hash_dict['creds'][free_hash]) - LOG.info('%s allocated creds:\n%s', self.name, clean_creds) - return self._wrap_creds_with_network(free_hash) - - @lockutils.synchronized('test_accounts_io', external=True) - def remove_hash(self, hash_string): - hash_path = os.path.join(self.accounts_dir, hash_string) - if not os.path.isfile(hash_path): - LOG.warning('Expected an account lock file %s to remove, but ' - 'one did not exist', hash_path) - else: - os.remove(hash_path) - if not os.listdir(self.accounts_dir): - os.rmdir(self.accounts_dir) - - def get_hash(self, creds): - for _hash in self.hash_dict['creds']: - # Comparing on the attributes that are expected in the YAML - init_attributes = creds.get_init_attributes() - # Only use the attributes initially used to calculate the hash - init_attributes = [x for x in init_attributes if - x in self.HASH_CRED_FIELDS] - hash_attributes = self.hash_dict['creds'][_hash].copy() - # NOTE(andreaf) Not all fields may be available on all credentials - # so defaulting to None for that case. - if all([getattr(creds, k, None) == hash_attributes.get(k, None) for - k in init_attributes]): - return _hash - raise AttributeError('Invalid credentials %s' % creds) - - def remove_credentials(self, creds): - _hash = self.get_hash(creds) - clean_creds = self._sanitize_creds(self.hash_dict['creds'][_hash]) - self.remove_hash(_hash) - LOG.info("%s returned allocated creds:\n%s", self.name, clean_creds) - - def get_primary_creds(self): - if self._creds.get('primary'): - return self._creds.get('primary') - net_creds = self._get_creds() - self._creds['primary'] = net_creds - return net_creds - - def get_alt_creds(self): - if self._creds.get('alt'): - return self._creds.get('alt') - net_creds = self._get_creds() - self._creds['alt'] = net_creds - return net_creds - - def get_creds_by_roles(self, roles, force_new=False): - roles = list(set(roles)) - exist_creds = self._creds.get(six.text_type(roles).encode( - 'utf-8'), None) - # The force kwarg is used to allocate an additional set of creds with - # the same role list. The index used for the previously allocation - # in the _creds dict will be moved. - if exist_creds and not force_new: - return exist_creds - elif exist_creds and force_new: - # NOTE(andreaf) In py3.x encode returns bytes, and b'' is bytes - # In py2.7 encode returns strings, and b'' is still string - new_index = six.text_type(roles).encode('utf-8') + b'-' + \ - six.text_type(len(self._creds)).encode('utf-8') - self._creds[new_index] = exist_creds - net_creds = self._get_creds(roles=roles) - self._creds[six.text_type(roles).encode('utf-8')] = net_creds - return net_creds - - def clear_creds(self): - for creds in self._creds.values(): - self.remove_credentials(creds) - - def get_admin_creds(self): - return self.get_creds_by_roles([self.admin_role]) - - def is_role_available(self, role): - if self.hash_dict['roles'].get(role): - return True - return False - - def admin_available(self): - return self.is_role_available(self.admin_role) - - def _wrap_creds_with_network(self, hash): - creds_dict = self.hash_dict['creds'][hash] - # Make sure a domain scope if defined for users in case of V3 - # Make sure a tenant is available in case of V2 - creds_dict = self._extend_credentials(creds_dict) - # This just builds a Credentials object, it does not validate - # nor fill with missing fields. - credential = auth.get_credentials( - auth_url=None, fill_in=False, - identity_version=self.identity_version, **creds_dict) - net_creds = cred_provider.TestResources(credential) - net_clients = clients.ServiceClients(credentials=credential, - identity_uri=self.identity_uri) - compute_network_client = net_clients.compute.NetworksClient() - net_name = self.hash_dict['networks'].get(hash, None) - try: - network = fixed_network.get_network_from_name( - net_name, compute_network_client) - except lib_exc.InvalidTestResource: - network = {} - net_creds.set_resources(network=network) - return net_creds - - def _extend_credentials(self, creds_dict): - # Add or remove credential domain fields to fit the identity version - domain_fields = set(x for x in auth.KeystoneV3Credentials.ATTRIBUTES - if 'domain' in x) - msg = 'Assuming they are valid in the default domain.' - if self.identity_version == 'v3': - if not domain_fields.intersection(set(creds_dict.keys())): - msg = 'Using credentials %s for v3 API calls. ' + msg - LOG.warning(msg, self._sanitize_creds(creds_dict)) - creds_dict['domain_name'] = self.credentials_domain - if self.identity_version == 'v2': - if domain_fields.intersection(set(creds_dict.keys())): - msg = 'Using credentials %s for v2 API calls. ' + msg - LOG.warning(msg, self._sanitize_creds(creds_dict)) - # Remove all valid domain attributes - for attr in domain_fields.intersection(set(creds_dict.keys())): - creds_dict.pop(attr) - return creds_dict diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py deleted file mode 100644 index f58d7372d..000000000 --- a/tempest/lib/common/rest_client.py +++ /dev/null @@ -1,976 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# Copyright 2013 IBM 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 collections -import email.utils -import re -import time - -import jsonschema -from oslo_log import log as logging -from oslo_serialization import jsonutils as json -import six -from six.moves import urllib - -from tempest.lib.common import http -from tempest.lib.common import jsonschema_validator -from tempest.lib.common.utils import test_utils -from tempest.lib import exceptions - -# redrive rate limited calls at most twice -MAX_RECURSION_DEPTH = 2 - -# All the successful HTTP status codes from RFC 7231 & 4918 -HTTP_SUCCESS = (200, 201, 202, 203, 204, 205, 206, 207) - -# All the redirection HTTP status codes from RFC 7231 & 4918 -HTTP_REDIRECTION = (300, 301, 302, 303, 304, 305, 306, 307) - -# JSON Schema validator and format checker used for JSON Schema validation -JSONSCHEMA_VALIDATOR = jsonschema_validator.JSONSCHEMA_VALIDATOR -FORMAT_CHECKER = jsonschema_validator.FORMAT_CHECKER - - -class RestClient(object): - """Unified OpenStack RestClient class - - This class is used for building openstack api clients on top of. It is - intended to provide a base layer for wrapping outgoing http requests in - keystone auth as well as providing response code checking and error - handling. - - :param auth_provider: an auth provider object used to wrap requests in auth - :param str service: The service name to use for the catalog lookup - :param str region: The region to use for the catalog lookup - :param str name: The endpoint name to use for the catalog lookup; this - returns only if the service exists - :param str endpoint_type: The endpoint type to use for the catalog lookup - :param int build_interval: Time in seconds between to status checks in - wait loops - :param int build_timeout: Timeout in seconds to wait for a wait operation. - :param bool disable_ssl_certificate_validation: Set to true to disable ssl - certificate validation - :param str ca_certs: File containing the CA Bundle to use in verifying a - TLS server cert - :param str trace_requests: Regex to use for specifying logging the entirety - of the request and response payload - :param str http_timeout: Timeout in seconds to wait for the http request to - return - """ - - # The version of the API this client implements - api_version = None - - LOG = logging.getLogger(__name__) - - def __init__(self, auth_provider, service, region, - endpoint_type='publicURL', - build_interval=1, build_timeout=60, - disable_ssl_certificate_validation=False, ca_certs=None, - trace_requests='', name=None, http_timeout=None): - self.auth_provider = auth_provider - self.service = service - self.region = region - self.name = name - self.endpoint_type = endpoint_type - self.build_interval = build_interval - self.build_timeout = build_timeout - self.trace_requests = trace_requests - - self._skip_path = False - self.general_header_lc = set(('cache-control', 'connection', - 'date', 'pragma', 'trailer', - 'transfer-encoding', 'via', - 'warning')) - self.response_header_lc = set(('accept-ranges', 'age', 'etag', - 'location', 'proxy-authenticate', - 'retry-after', 'server', - 'vary', 'www-authenticate')) - dscv = disable_ssl_certificate_validation - self.http_obj = http.ClosingHttp( - disable_ssl_certificate_validation=dscv, ca_certs=ca_certs, - timeout=http_timeout) - - def get_headers(self, accept_type=None, send_type=None): - """Return the default headers which will be used with outgoing requests - - :param str accept_type: The media type to use for the Accept header, if - one isn't provided the object var TYPE will be - used - :param str send_type: The media-type to use for the Content-Type - header, if one isn't provided the object var - TYPE will be used - :rtype: dict - :return: The dictionary of headers which can be used in the headers - dict for outgoing request - """ - if accept_type is None: - accept_type = 'json' - if send_type is None: - send_type = 'json' - return {'Content-Type': 'application/%s' % send_type, - 'Accept': 'application/%s' % accept_type} - - def __str__(self): - STRING_LIMIT = 80 - str_format = ("service:%s, base_url:%s, " - "filters: %s, build_interval:%s, build_timeout:%s" - "\ntoken:%s..., \nheaders:%s...") - return str_format % (self.service, self.base_url, - self.filters, self.build_interval, - self.build_timeout, - str(self.token)[0:STRING_LIMIT], - str(self.get_headers())[0:STRING_LIMIT]) - - @property - def user(self): - """The username used for requests - - :rtype: string - :return: The username being used for requests - """ - - return self.auth_provider.credentials.username - - @property - def user_id(self): - """The user_id used for requests - - :rtype: string - :return: The user id being used for requests - """ - return self.auth_provider.credentials.user_id - - @property - def tenant_name(self): - """The tenant/project being used for requests - - :rtype: string - :return: The tenant/project name being used for requests - """ - return self.auth_provider.credentials.tenant_name - - @property - def tenant_id(self): - """The tenant/project id being used for requests - - :rtype: string - :return: The tenant/project id being used for requests - """ - return self.auth_provider.credentials.tenant_id - - @property - def password(self): - """The password being used for requests - - :rtype: string - :return: The password being used for requests - """ - return self.auth_provider.credentials.password - - @property - def base_url(self): - return self.auth_provider.base_url(filters=self.filters) - - @property - def token(self): - return self.auth_provider.get_token() - - @property - def filters(self): - _filters = dict( - service=self.service, - endpoint_type=self.endpoint_type, - region=self.region, - name=self.name - ) - if self.api_version is not None: - _filters['api_version'] = self.api_version - if self._skip_path: - _filters['skip_path'] = self._skip_path - return _filters - - def skip_path(self): - """When set, ignore the path part of the base URL from the catalog""" - self._skip_path = True - - def reset_path(self): - """When reset, use the base URL from the catalog as-is""" - self._skip_path = False - - @classmethod - def expected_success(cls, expected_code, read_code): - """Check expected success response code against the http response - - :param int expected_code: The response code that is expected. - Optionally a list of integers can be used - to specify multiple valid success codes - :param int read_code: The response code which was returned in the - response - :raises AssertionError: if the expected_code isn't a valid http success - response code - :raises exceptions.InvalidHttpSuccessCode: if the read code isn't an - expected http success code - """ - if not isinstance(read_code, int): - raise TypeError("'read_code' must be an int instead of (%s)" - % type(read_code)) - - assert_msg = ("This function only allowed to use for HTTP status " - "codes which explicitly defined in the RFC 7231 & 4918. " - "{0} is not a defined Success Code!" - ).format(expected_code) - if isinstance(expected_code, list): - for code in expected_code: - assert code in HTTP_SUCCESS + HTTP_REDIRECTION, assert_msg - else: - assert expected_code in HTTP_SUCCESS + HTTP_REDIRECTION, assert_msg - - # NOTE(afazekas): the http status code above 400 is processed by - # the _error_checker method - if read_code < 400: - pattern = ("Unexpected http success status code {0}, " - "The expected status code is {1}") - if ((not isinstance(expected_code, list) and - (read_code != expected_code)) or - (isinstance(expected_code, list) and - (read_code not in expected_code))): - details = pattern.format(read_code, expected_code) - raise exceptions.InvalidHttpSuccessCode(details) - - def post(self, url, body, headers=None, extra_headers=False, - chunked=False): - """Send a HTTP POST request using keystone auth - - :param str url: the relative url to send the post request to - :param dict body: the request body - :param dict headers: The headers to use for the request - :param bool extra_headers: Boolean value than indicates if the headers - returned by the get_headers() method are to - be used but additional headers are needed in - the request pass them in as a dict. - :param bool chunked: sends the body with chunked encoding - :return: a tuple with the first entry containing the response headers - and the second the response body - :rtype: tuple - """ - return self.request('POST', url, extra_headers, headers, body, chunked) - - def get(self, url, headers=None, extra_headers=False): - """Send a HTTP GET request using keystone service catalog and auth - - :param str url: the relative url to send the post request to - :param dict headers: The headers to use for the request - :param bool extra_headers: Boolean value than indicates if the headers - returned by the get_headers() method are to - be used but additional headers are needed in - the request pass them in as a dict. - :return: a tuple with the first entry containing the response headers - and the second the response body - :rtype: tuple - """ - return self.request('GET', url, extra_headers, headers) - - def delete(self, url, headers=None, body=None, extra_headers=False): - """Send a HTTP DELETE request using keystone service catalog and auth - - :param str url: the relative url to send the post request to - :param dict headers: The headers to use for the request - :param dict body: the request body - :param bool extra_headers: Boolean value than indicates if the headers - returned by the get_headers() method are to - be used but additional headers are needed in - the request pass them in as a dict. - :return: a tuple with the first entry containing the response headers - and the second the response body - :rtype: tuple - """ - return self.request('DELETE', url, extra_headers, headers, body) - - def patch(self, url, body, headers=None, extra_headers=False): - """Send a HTTP PATCH request using keystone service catalog and auth - - :param str url: the relative url to send the post request to - :param dict body: the request body - :param dict headers: The headers to use for the request - :param bool extra_headers: Boolean value than indicates if the headers - returned by the get_headers() method are to - be used but additional headers are needed in - the request pass them in as a dict. - :return: a tuple with the first entry containing the response headers - and the second the response body - :rtype: tuple - """ - return self.request('PATCH', url, extra_headers, headers, body) - - def put(self, url, body, headers=None, extra_headers=False, chunked=False): - """Send a HTTP PUT request using keystone service catalog and auth - - :param str url: the relative url to send the post request to - :param dict body: the request body - :param dict headers: The headers to use for the request - :param bool extra_headers: Boolean value than indicates if the headers - returned by the get_headers() method are to - be used but additional headers are needed in - the request pass them in as a dict. - :param bool chunked: sends the body with chunked encoding - :return: a tuple with the first entry containing the response headers - and the second the response body - :rtype: tuple - """ - return self.request('PUT', url, extra_headers, headers, body, chunked) - - def head(self, url, headers=None, extra_headers=False): - """Send a HTTP HEAD request using keystone service catalog and auth - - :param str url: the relative url to send the post request to - :param dict headers: The headers to use for the request - :param bool extra_headers: Boolean value than indicates if the headers - returned by the get_headers() method are to - be used but additional headers are needed in - the request pass them in as a dict. - :return: a tuple with the first entry containing the response headers - and the second the response body - :rtype: tuple - """ - return self.request('HEAD', url, extra_headers, headers) - - def copy(self, url, headers=None, extra_headers=False): - """Send a HTTP COPY request using keystone service catalog and auth - - :param str url: the relative url to send the post request to - :param dict headers: The headers to use for the request - :param bool extra_headers: Boolean value than indicates if the headers - returned by the get_headers() method are to - be used but additional headers are needed in - the request pass them in as a dict. - :return: a tuple with the first entry containing the response headers - and the second the response body - :rtype: tuple - """ - return self.request('COPY', url, extra_headers, headers) - - def get_versions(self): - """Get the versions on a endpoint from the keystone catalog - - This method will make a GET request on the baseurl from the keystone - catalog to return a list of API versions. It is expected that a GET - on the endpoint in the catalog will return a list of supported API - versions. - - :return: tuple with response headers and list of version numbers - :rtype: tuple - """ - resp, body = self.get('') - body = self._parse_resp(body) - versions = map(lambda x: x['id'], body) - return resp, versions - - def _get_request_id(self, resp): - for i in ('x-openstack-request-id', 'x-compute-request-id'): - if i in resp: - return resp[i] - return "" - - def _safe_body(self, body, maxlen=4096): - # convert a structure into a string safely - try: - text = six.text_type(body) - except UnicodeDecodeError: - # if this isn't actually text, return marker that - return "" - if len(text) > maxlen: - return text[:maxlen] - else: - return text - - def _log_request_start(self, method, req_url): - caller_name = test_utils.find_test_caller() - if self.trace_requests and re.search(self.trace_requests, caller_name): - self.LOG.debug('Starting Request (%s): %s %s', caller_name, - method, req_url) - - def _log_request_full(self, resp, req_headers=None, req_body=None, - resp_body=None, extra=None): - if 'X-Auth-Token' in req_headers: - req_headers['X-Auth-Token'] = '' - # A shallow copy is sufficient - resp_log = resp.copy() - if 'x-subject-token' in resp_log: - resp_log['x-subject-token'] = '' - log_fmt = """Request - Headers: %s - Body: %s - Response - Headers: %s - Body: %s""" - - self.LOG.debug( - log_fmt, - str(req_headers), - self._safe_body(req_body), - str(resp_log), - self._safe_body(resp_body), - extra=extra) - - def _log_request(self, method, req_url, resp, - secs="", req_headers=None, - req_body=None, resp_body=None): - if req_headers is None: - req_headers = {} - # if we have the request id, put it in the right part of the log - extra = dict(request_id=self._get_request_id(resp)) - # NOTE(sdague): while we still have 6 callers to this function - # we're going to just provide work around on who is actually - # providing timings by gracefully adding no content if they don't. - # Once we're down to 1 caller, clean this up. - caller_name = test_utils.find_test_caller() - if secs: - secs = " %.3fs" % secs - self.LOG.info( - 'Request (%s): %s %s %s%s', - caller_name, - resp['status'], - method, - req_url, - secs, - extra=extra) - - # Also look everything at DEBUG if you want to filter this - # out, don't run at debug. - if self.LOG.isEnabledFor(logging.DEBUG): - self._log_request_full(resp, req_headers, req_body, - resp_body, extra) - - def _parse_resp(self, body): - try: - body = json.loads(body) - except ValueError: - return body - - # We assume, that if the first value of the deserialized body's - # item set is a dict or a list, that we just return the first value - # of deserialized body. - # Essentially "cutting out" the first placeholder element in a body - # that looks like this: - # - # { - # "users": [ - # ... - # ] - # } - try: - # Ensure there are not more than one top-level keys - # NOTE(freerunner): Ensure, that JSON is not nullable to - # to prevent StopIteration Exception - if not hasattr(body, "keys") or len(body.keys()) != 1: - return body - # Just return the "wrapped" element - first_key, first_item = six.next(six.iteritems(body)) - if isinstance(first_item, (dict, list)): - return first_item - except (ValueError, IndexError): - pass - return body - - def response_checker(self, method, resp, resp_body): - """A sanity check on the response from a HTTP request - - This method does a sanity check on whether the response from an HTTP - request conforms the HTTP RFC. - - :param str method: The HTTP verb of the request associated with the - response being passed in. - :param resp: The response headers - :param resp_body: The body of the response - :raises ResponseWithNonEmptyBody: If the response with the status code - is not supposed to have a body - :raises ResponseWithEntity: If the response code is 205 but has an - entity - """ - if (resp.status in set((204, 205, 304)) or resp.status < 200 or - method.upper() == 'HEAD') and resp_body: - raise exceptions.ResponseWithNonEmptyBody(status=resp.status) - # NOTE(afazekas): - # If the HTTP Status Code is 205 - # 'The response MUST NOT include an entity.' - # A HTTP entity has an entity-body and an 'entity-header'. - # In the HTTP response specification (Section 6) the 'entity-header' - # 'generic-header' and 'response-header' are in OR relation. - # All headers not in the above two group are considered as entity - # header in every interpretation. - - if (resp.status == 205 and - 0 != len(set(resp.keys()) - set(('status',)) - - self.response_header_lc - self.general_header_lc)): - raise exceptions.ResponseWithEntity() - # NOTE(afazekas) - # Now the swift sometimes (delete not empty container) - # returns with non json error response, we can create new rest class - # for swift. - # Usually RFC2616 says error responses SHOULD contain an explanation. - # The warning is normal for SHOULD/SHOULD NOT case - - # Likely it will cause an error - if method != 'HEAD' and not resp_body and resp.status >= 400: - self.LOG.warning("status >= 400 response with empty body") - - def _request(self, method, url, headers=None, body=None, chunked=False): - """A simple HTTP request interface.""" - # Authenticate the request with the auth provider - req_url, req_headers, req_body = self.auth_provider.auth_request( - method, url, headers, body, self.filters) - - # Do the actual request, and time it - start = time.time() - self._log_request_start(method, req_url) - resp, resp_body = self.raw_request( - req_url, method, headers=req_headers, body=req_body, - chunked=chunked - ) - end = time.time() - self._log_request(method, req_url, resp, secs=(end - start), - req_headers=req_headers, req_body=req_body, - resp_body=resp_body) - - # Verify HTTP response codes - self.response_checker(method, resp, resp_body) - - return resp, resp_body - - def raw_request(self, url, method, headers=None, body=None, chunked=False): - """Send a raw HTTP request without the keystone catalog or auth - - This method sends a HTTP request in the same manner as the request() - method, however it does so without using keystone auth or the catalog - to determine the base url. Additionally no response handling is done - the results from the request are just returned. - - :param str url: Full url to send the request - :param str method: The HTTP verb to use for the request - :param str headers: Headers to use for the request if none are specifed - the headers - :param str body: Body to send with the request - :param bool chunked: sends the body with chunked encoding - :rtype: tuple - :return: a tuple with the first entry containing the response headers - and the second the response body - """ - if headers is None: - headers = self.get_headers() - return self.http_obj.request(url, method, headers=headers, - body=body, chunked=chunked) - - def request(self, method, url, extra_headers=False, headers=None, - body=None, chunked=False): - """Send a HTTP request with keystone auth and using the catalog - - This method will send an HTTP request using keystone auth in the - headers and the catalog to determine the endpoint to use for the - baseurl to send the request to. Additionally - - When a response is received it will check it to see if an error - response was received. If it was an exception will be raised to enable - it to be handled quickly. - - This method will also handle rate-limiting, if a 413 response code is - received it will retry the request after waiting the 'retry-after' - duration from the header. - - :param str method: The HTTP verb to use for the request - :param str url: Relative url to send the request to - :param bool extra_headers: Boolean value than indicates if the headers - returned by the get_headers() method are to - be used but additional headers are needed in - the request pass them in as a dict. - :param dict headers: Headers to use for the request if none are - specifed the headers returned from the - get_headers() method are used. If the request - explicitly requires no headers use an empty dict. - :param str body: Body to send with the request - :param bool chunked: sends the body with chunked encoding - :rtype: tuple - :return: a tuple with the first entry containing the response headers - and the second the response body - :raises UnexpectedContentType: If the content-type of the response - isn't an expect type - :raises Unauthorized: If a 401 response code is received - :raises Forbidden: If a 403 response code is received - :raises NotFound: If a 404 response code is received - :raises BadRequest: If a 400 response code is received - :raises Gone: If a 410 response code is received - :raises Conflict: If a 409 response code is received - :raises PreconditionFailed: If a 412 response code is received - :raises OverLimit: If a 413 response code is received and over_limit is - not in the response body - :raises RateLimitExceeded: If a 413 response code is received and - over_limit is in the response body - :raises InvalidContentType: If a 415 response code is received - :raises UnprocessableEntity: If a 422 response code is received - :raises InvalidHTTPResponseBody: The response body wasn't valid JSON - and couldn't be parsed - :raises NotImplemented: If a 501 response code is received - :raises ServerFault: If a 500 response code is received - :raises UnexpectedResponseCode: If a response code above 400 is - received and it doesn't fall into any - of the handled checks - """ - # if extra_headers is True - # default headers would be added to headers - retry = 0 - - if headers is None: - # NOTE(vponomaryov): if some client do not need headers, - # it should explicitly pass empty dict - headers = self.get_headers() - elif extra_headers: - try: - headers.update(self.get_headers()) - except (ValueError, TypeError): - headers = self.get_headers() - - resp, resp_body = self._request(method, url, headers=headers, - body=body, chunked=chunked) - - while (resp.status == 413 and - 'retry-after' in resp and - not self.is_absolute_limit( - resp, self._parse_resp(resp_body)) and - retry < MAX_RECURSION_DEPTH): - retry += 1 - delay = self._get_retry_after_delay(resp) - self.LOG.debug( - "Sleeping %s seconds based on retry-after header", delay - ) - time.sleep(delay) - resp, resp_body = self._request(method, url, - headers=headers, body=body) - self._error_checker(resp, resp_body) - return resp, resp_body - - def _get_retry_after_delay(self, resp): - """Extract the delay from the retry-after header. - - This supports both integer and HTTP date formatted retry-after headers - per RFC 2616. - - :param resp: The response containing the retry-after headers - :rtype: int - :return: The delay in seconds, clamped to be at least 1 second - :raises ValueError: On failing to parse the delay - """ - delay = None - try: - delay = int(resp['retry-after']) - except (ValueError, KeyError): - pass - - try: - retry_timestamp = self._parse_http_date(resp['retry-after']) - date_timestamp = self._parse_http_date(resp['date']) - delay = int(retry_timestamp - date_timestamp) - except (ValueError, OverflowError, KeyError): - pass - - if delay is None: - raise ValueError( - "Failed to parse retry-after header %r as either int or " - "HTTP-date." % resp.get('retry-after') - ) - - # Retry-after headers do not have sub-second precision. Clients may - # receive a delay of 0. After sleeping 0 seconds, we would (likely) hit - # another 413. To avoid this, always sleep at least 1 second. - return max(1, delay) - - def _parse_http_date(self, val): - """Parse an HTTP date, like 'Fri, 31 Dec 1999 23:59:59 GMT'. - - Return an epoch timestamp (float), as returned by time.mktime(). - """ - parts = email.utils.parsedate(val) - if not parts: - raise ValueError("Failed to parse date %s" % val) - return time.mktime(parts) - - def _error_checker(self, resp, resp_body): - - # NOTE(mtreinish): Check for httplib response from glance_http. The - # object can't be used here because importing httplib breaks httplib2. - # If another object from a class not imported were passed here as - # resp this could possibly fail - if str(type(resp)) == "": - ctype = resp.getheader('content-type') - else: - try: - ctype = resp['content-type'] - # NOTE(mtreinish): Keystone delete user responses doesn't have a - # content-type header. (They don't have a body) So just pretend it - # is set. - except KeyError: - ctype = 'application/json' - - # It is not an error response - if resp.status < 400: - return - - # NOTE(zhipengh): There is a purposefully duplicate of content-type - # with the only difference is with or without spaces, as specified - # in RFC7231. - JSON_ENC = ['application/json', 'application/json; charset=utf-8', - 'application/json;charset=utf-8'] - - # NOTE(mtreinish): This is for compatibility with Glance and swift - # APIs. These are the return content types that Glance api v1 - # (and occasionally swift) are using. - # NOTE(zhipengh): There is a purposefully duplicate of content-type - # with the only difference is with or without spaces, as specified - # in RFC7231. - TXT_ENC = ['text/plain', 'text/html', 'text/html; charset=utf-8', - 'text/plain; charset=utf-8', 'text/html;charset=utf-8', - 'text/plain;charset=utf-8'] - - if ctype.lower() in JSON_ENC: - parse_resp = True - elif ctype.lower() in TXT_ENC: - parse_resp = False - else: - raise exceptions.UnexpectedContentType(str(resp.status), - resp=resp) - - if resp.status == 401: - if parse_resp: - resp_body = self._parse_resp(resp_body) - raise exceptions.Unauthorized(resp_body, resp=resp) - - if resp.status == 403: - if parse_resp: - resp_body = self._parse_resp(resp_body) - raise exceptions.Forbidden(resp_body, resp=resp) - - if resp.status == 404: - if parse_resp: - resp_body = self._parse_resp(resp_body) - raise exceptions.NotFound(resp_body, resp=resp) - - if resp.status == 400: - if parse_resp: - resp_body = self._parse_resp(resp_body) - raise exceptions.BadRequest(resp_body, resp=resp) - - if resp.status == 410: - if parse_resp: - resp_body = self._parse_resp(resp_body) - raise exceptions.Gone(resp_body, resp=resp) - - if resp.status == 409: - if parse_resp: - resp_body = self._parse_resp(resp_body) - raise exceptions.Conflict(resp_body, resp=resp) - - if resp.status == 412: - if parse_resp: - resp_body = self._parse_resp(resp_body) - raise exceptions.PreconditionFailed(resp_body, resp=resp) - - if resp.status == 413: - if parse_resp: - resp_body = self._parse_resp(resp_body) - if self.is_absolute_limit(resp, resp_body): - raise exceptions.OverLimit(resp_body, resp=resp) - else: - raise exceptions.RateLimitExceeded(resp_body, resp=resp) - - if resp.status == 415: - if parse_resp: - resp_body = self._parse_resp(resp_body) - raise exceptions.InvalidContentType(resp_body, resp=resp) - - if resp.status == 422: - if parse_resp: - resp_body = self._parse_resp(resp_body) - raise exceptions.UnprocessableEntity(resp_body, resp=resp) - - if resp.status in (500, 501): - message = resp_body - if parse_resp: - try: - resp_body = self._parse_resp(resp_body) - except ValueError: - # If response body is a non-json string message. - # Use resp_body as is and raise InvalidResponseBody - # exception. - raise exceptions.InvalidHTTPResponseBody(message) - else: - if isinstance(resp_body, dict): - # I'm seeing both computeFault - # and cloudServersFault come back. - # Will file a bug to fix, but leave as is for now. - if 'cloudServersFault' in resp_body: - message = resp_body['cloudServersFault']['message'] - elif 'computeFault' in resp_body: - message = resp_body['computeFault']['message'] - elif 'error' in resp_body: - message = resp_body['error']['message'] - elif 'message' in resp_body: - message = resp_body['message'] - else: - message = resp_body - - if resp.status == 501: - raise exceptions.NotImplemented(resp_body, resp=resp, - message=message) - else: - raise exceptions.ServerFault(resp_body, resp=resp, - message=message) - - if resp.status >= 400: - raise exceptions.UnexpectedResponseCode(str(resp.status), - resp=resp) - - def is_absolute_limit(self, resp, resp_body): - if (not isinstance(resp_body, collections.Mapping) or - 'retry-after' not in resp): - return True - return 'exceed' in resp_body.get('message', 'blabla') - - def wait_for_resource_deletion(self, id): - """Waits for a resource to be deleted - - This method will loop over is_resource_deleted until either - is_resource_deleted returns True or the build timeout is reached. This - depends on is_resource_deleted being implemented - - :param str id: The id of the resource to check - :raises TimeoutException: If the build_timeout has elapsed and the - resource still hasn't been deleted - """ - start_time = int(time.time()) - while True: - if self.is_resource_deleted(id): - return - if int(time.time()) - start_time >= self.build_timeout: - message = ('Failed to delete %(resource_type)s %(id)s within ' - 'the required time (%(timeout)s s).' % - {'resource_type': self.resource_type, 'id': id, - 'timeout': self.build_timeout}) - caller = test_utils.find_test_caller() - if caller: - message = '(%s) %s' % (caller, message) - raise exceptions.TimeoutException(message) - time.sleep(self.build_interval) - - def is_resource_deleted(self, id): - """Subclasses override with specific deletion detection.""" - message = ('"%s" does not implement is_resource_deleted' - % self.__class__.__name__) - raise NotImplementedError(message) - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'resource' - - @classmethod - def validate_response(cls, schema, resp, body): - # Only check the response if the status code is a success code - # TODO(cyeoh): Eventually we should be able to verify that a failure - # code if it exists is something that we expect. This is explicitly - # declared in the V3 API and so we should be able to export this in - # the response schema. For now we'll ignore it. - if resp.status in HTTP_SUCCESS + HTTP_REDIRECTION: - cls.expected_success(schema['status_code'], resp.status) - - # Check the body of a response - body_schema = schema.get('response_body') - if body_schema: - try: - jsonschema.validate(body, body_schema, - cls=JSONSCHEMA_VALIDATOR, - format_checker=FORMAT_CHECKER) - except jsonschema.ValidationError as ex: - msg = ("HTTP response body is invalid (%s)" % ex) - raise exceptions.InvalidHTTPResponseBody(msg) - else: - if body: - msg = ("HTTP response body should not exist (%s)" % body) - raise exceptions.InvalidHTTPResponseBody(msg) - - # Check the header of a response - header_schema = schema.get('response_header') - if header_schema: - try: - jsonschema.validate(resp, header_schema, - cls=JSONSCHEMA_VALIDATOR, - format_checker=FORMAT_CHECKER) - except jsonschema.ValidationError as ex: - msg = ("HTTP response header is invalid (%s)" % ex) - raise exceptions.InvalidHTTPResponseHeader(msg) - - def _get_base_version_url(self): - # TODO(oomichi): This method can be used for auth's replace_version(). - # So it is nice to have common logic for the maintenance. - endpoint = self.base_url - url = urllib.parse.urlsplit(endpoint) - new_path = re.split(r'(^|/)+v\d+(\.\d+)?', url.path)[0] - url = list(url) - url[2] = new_path + '/' - return urllib.parse.urlunsplit(url) - - -class ResponseBody(dict): - """Class that wraps an http response and dict body into a single value. - - Callers that receive this object will normally use it as a dict but - can extract the response if needed. - """ - - def __init__(self, response, body=None): - body_data = body or {} - self.update(body_data) - self.response = response - - def __str__(self): - body = super(ResponseBody, self).__str__() - return "response: %s\nBody: %s" % (self.response, body) - - -class ResponseBodyData(object): - """Class that wraps an http response and string data into a single value. - - """ - - def __init__(self, response, data): - self.response = response - self.data = data - - def __str__(self): - return "response: %s\nBody: %s" % (self.response, self.data) - - -class ResponseBodyList(list): - """Class that wraps an http response and list body into a single value. - - Callers that receive this object will normally use it as a list but - can extract the response if needed. - """ - - def __init__(self, response, body=None): - body_data = body or [] - self.extend(body_data) - self.response = response - - def __str__(self): - body = super(ResponseBodyList, self).__str__() - return "response: %s\nBody: %s" % (self.response, body) diff --git a/tempest/lib/common/ssh.py b/tempest/lib/common/ssh.py deleted file mode 100644 index d4ec6ad59..000000000 --- a/tempest/lib/common/ssh.py +++ /dev/null @@ -1,219 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 select -import socket -import time -import warnings - -from oslo_log import log as logging -import six - -from tempest.lib import exceptions - - -with warnings.catch_warnings(): - warnings.simplefilter("ignore") - import paramiko - - -LOG = logging.getLogger(__name__) - - -class Client(object): - - def __init__(self, host, username, password=None, timeout=300, pkey=None, - channel_timeout=10, look_for_keys=False, key_filename=None, - port=22, proxy_client=None): - """SSH client. - - Many of parameters are just passed to the underlying implementation - as it is. See the paramiko documentation for more details. - http://docs.paramiko.org/en/2.1/api/client.html#paramiko.client.SSHClient.connect - - :param host: Host to login. - :param username: SSH username. - :param password: SSH password, or a password to unlock private key. - :param timeout: Timeout in seconds, including retries. - Default is 300 seconds. - :param pkey: Private key. - :param channel_timeout: Channel timeout in seconds, passed to the - paramiko. Default is 10 seconds. - :param look_for_keys: Whether or not to search for private keys - in ``~/.ssh``. Default is False. - :param key_filename: Filename for private key to use. - :param port: SSH port number. - :param proxy_client: Another SSH client to provide a transport - for ssh-over-ssh. The default is None, which means - not to use ssh-over-ssh. - :type proxy_client: ``tempest.lib.common.ssh.Client`` object - """ - self.host = host - self.username = username - self.port = port - self.password = password - if isinstance(pkey, six.string_types): - pkey = paramiko.RSAKey.from_private_key( - six.StringIO(str(pkey))) - self.pkey = pkey - self.look_for_keys = look_for_keys - self.key_filename = key_filename - self.timeout = int(timeout) - self.channel_timeout = float(channel_timeout) - self.buf_size = 1024 - self.proxy_client = proxy_client - self._proxy_conn = None - - def _get_ssh_connection(self, sleep=1.5, backoff=1): - """Returns an ssh connection to the specified host.""" - bsleep = sleep - ssh = paramiko.SSHClient() - ssh.set_missing_host_key_policy( - paramiko.AutoAddPolicy()) - _start_time = time.time() - if self.pkey is not None: - LOG.info("Creating ssh connection to '%s:%d' as '%s'" - " with public key authentication", - self.host, self.port, self.username) - else: - LOG.info("Creating ssh connection to '%s:%d' as '%s'" - " with password %s", - self.host, self.port, self.username, str(self.password)) - attempts = 0 - while True: - if self.proxy_client is not None: - proxy_chan = self._get_proxy_channel() - else: - proxy_chan = None - try: - ssh.connect(self.host, port=self.port, username=self.username, - password=self.password, - look_for_keys=self.look_for_keys, - key_filename=self.key_filename, - timeout=self.channel_timeout, pkey=self.pkey, - sock=proxy_chan) - LOG.info("ssh connection to %s@%s successfully created", - self.username, self.host) - return ssh - except (EOFError, - socket.error, socket.timeout, - paramiko.SSHException) as e: - ssh.close() - if self._is_timed_out(_start_time): - LOG.exception("Failed to establish authenticated ssh" - " connection to %s@%s after %d attempts", - self.username, self.host, attempts) - raise exceptions.SSHTimeout(host=self.host, - user=self.username, - password=self.password) - bsleep += backoff - attempts += 1 - LOG.warning("Failed to establish authenticated ssh" - " connection to %s@%s (%s). Number attempts: %s." - " Retry after %d seconds.", - self.username, self.host, e, attempts, bsleep) - time.sleep(bsleep) - - def _is_timed_out(self, start_time): - return (time.time() - self.timeout) > start_time - - @staticmethod - def _can_system_poll(): - return hasattr(select, 'poll') - - def exec_command(self, cmd, encoding="utf-8"): - """Execute the specified command on the server - - Note that this method is reading whole command outputs to memory, thus - shouldn't be used for large outputs. - - :param str cmd: Command to run at remote server. - :param str encoding: Encoding for result from paramiko. - Result will not be decoded if None. - :returns: data read from standard output of the command. - :raises: SSHExecCommandFailed if command returns nonzero - status. The exception contains command status stderr content. - :raises: TimeoutException if cmd doesn't end when timeout expires. - """ - ssh = self._get_ssh_connection() - transport = ssh.get_transport() - with transport.open_session() as channel: - channel.fileno() # Register event pipe - channel.exec_command(cmd) - channel.shutdown_write() - - # If the executing host is linux-based, poll the channel - if self._can_system_poll(): - out_data_chunks = [] - err_data_chunks = [] - poll = select.poll() - poll.register(channel, select.POLLIN) - start_time = time.time() - - while True: - ready = poll.poll(self.channel_timeout) - if not any(ready): - if not self._is_timed_out(start_time): - continue - raise exceptions.TimeoutException( - "Command: '{0}' executed on host '{1}'.".format( - cmd, self.host)) - if not ready[0]: # If there is nothing to read. - continue - out_chunk = err_chunk = None - if channel.recv_ready(): - out_chunk = channel.recv(self.buf_size) - out_data_chunks += out_chunk, - if channel.recv_stderr_ready(): - err_chunk = channel.recv_stderr(self.buf_size) - err_data_chunks += err_chunk, - if not err_chunk and not out_chunk: - break - out_data = b''.join(out_data_chunks) - err_data = b''.join(err_data_chunks) - # Just read from the channels - else: - out_file = channel.makefile('rb', self.buf_size) - err_file = channel.makefile_stderr('rb', self.buf_size) - out_data = out_file.read() - err_data = err_file.read() - if encoding: - out_data = out_data.decode(encoding) - err_data = err_data.decode(encoding) - - exit_status = channel.recv_exit_status() - - if 0 != exit_status: - raise exceptions.SSHExecCommandFailed( - command=cmd, exit_status=exit_status, - stderr=err_data, stdout=out_data) - return out_data - - def test_connection_auth(self): - """Raises an exception when we can not connect to server via ssh.""" - connection = self._get_ssh_connection() - connection.close() - - def _get_proxy_channel(self): - conn = self.proxy_client._get_ssh_connection() - # Keep a reference to avoid g/c - # https://github.com/paramiko/paramiko/issues/440 - self._proxy_conn = conn - transport = conn.get_transport() - chan = transport.open_session() - cmd = 'nc %s %s' % (self.host, self.port) - chan.exec_command(cmd) - return chan diff --git a/tempest/lib/common/utils/__init__.py b/tempest/lib/common/utils/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/common/utils/data_utils.py b/tempest/lib/common/utils/data_utils.py deleted file mode 100644 index a0941ef50..000000000 --- a/tempest/lib/common/utils/data_utils.py +++ /dev/null @@ -1,214 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 itertools -import random -import string -import uuid - -from debtcollector import removals -import netaddr -from oslo_utils import netutils -from oslo_utils import uuidutils -import six.moves - - -def rand_uuid(): - """Generate a random UUID string - - :return: a random UUID (e.g. '1dc12c7d-60eb-4b61-a7a2-17cf210155b6') - :rtype: string - """ - return uuidutils.generate_uuid() - - -def rand_uuid_hex(): - """Generate a random UUID hex string - - :return: a random UUID (e.g. '0b98cf96d90447bda4b46f31aeb1508c') - :rtype: string - """ - return uuid.uuid4().hex - - -def rand_name(name='', prefix='tempest'): - """Generate a random name that includes a random number - - :param str name: The name that you want to include - :param str prefix: The prefix that you want to include - :return: a random name. The format is - '--'. - (e.g. 'prefixfoo-namebar-154876201') - :rtype: string - """ - randbits = str(random.randint(1, 0x7fffffff)) - rand_name = randbits - if name: - rand_name = name + '-' + rand_name - if prefix: - rand_name = prefix + '-' + rand_name - return rand_name - - -def rand_password(length=15): - """Generate a random password - - :param int length: The length of password that you expect to set - (If it's smaller than 3, it's same as 3.) - :return: a random password. The format is - '-- - -' - (e.g. 'G2*ac8&lKFFgh%2') - :rtype: string - """ - upper = random.choice(string.ascii_uppercase) - ascii_char = string.ascii_letters - digits = string.digits - digit = random.choice(string.digits) - puncs = '~!@#%^&*_=+' - punc = random.choice(puncs) - seed = ascii_char + digits + puncs - pre = upper + digit + punc - password = pre + ''.join(random.choice(seed) for x in range(length - 3)) - return password - - -def rand_url(): - """Generate a random url that includes a random number - - :return: a random url. The format is 'https://url-.com'. - (e.g. 'https://url-154876201.com') - :rtype: string - """ - randbits = str(random.randint(1, 0x7fffffff)) - return 'https://url-' + randbits + '.com' - - -def rand_int_id(start=0, end=0x7fffffff): - """Generate a random integer value - - :param int start: The value that you expect to start here - :param int end: The value that you expect to end here - :return: a random integer value - :rtype: int - """ - return random.randint(start, end) - - -def rand_mac_address(): - """Generate an Ethernet MAC address - - :return: an random Ethernet MAC address - :rtype: string - """ - # NOTE(vish): We would prefer to use 0xfe here to ensure that linux - # bridge mac addresses don't change, but it appears to - # conflict with libvirt, so we use the next highest octet - # that has the unicast and locally administered bits set - # properly: 0xfa. - # Discussion: https://bugs.launchpad.net/nova/+bug/921838 - mac = [0xfa, 0x16, 0x3e, - random.randint(0x00, 0xff), - random.randint(0x00, 0xff), - random.randint(0x00, 0xff)] - return ':'.join(["%02x" % x for x in mac]) - - -def rand_infiniband_guid_address(): - """Generate an Infiniband GUID address - - :return: an random Infiniband GUID address - :rtype: string - """ - guid = [] - for i in range(8): - guid.append("%02x" % random.randint(0x00, 0xff)) - return ':'.join(guid) - - -def parse_image_id(image_ref): - """Return the image id from a given image ref - - This function just returns the last word of the given image ref string - splitting with '/'. - :param str image_ref: a string that includes the image id - :return: the image id string - :rtype: string - """ - return image_ref.rsplit('/')[-1] - - -def arbitrary_string(size=4, base_text=None): - """Return size characters from base_text - - This generates a string with an arbitrary number of characters, generated - by looping the base_text string. If the size is smaller than the size of - base_text, returning string is shrunk to the size. - :param int size: a returning characters size - :param str base_text: a string you want to repeat - :return: size string - :rtype: string - """ - if not base_text: - base_text = 'test' - return ''.join(itertools.islice(itertools.cycle(base_text), size)) - - -def random_bytes(size=1024): - """Return size randomly selected bytes as a string - - :param int size: a returning bytes size - :return: size randomly bytes - :rtype: string - """ - return b''.join([six.int2byte(random.randint(0, 255)) - for i in range(size)]) - - -@removals.remove( - message="use get_ipv6_addr_by_EUI64 from oslo_utils.netutils", - version="Newton", - removal_version="Ocata") -def get_ipv6_addr_by_EUI64(cidr, mac): - """Generate a IPv6 addr by EUI-64 with CIDR and MAC - - :param str cidr: a IPv6 CIDR - :param str mac: a MAC address - :return: an IPv6 Address - :rtype: netaddr.IPAddress - """ - # Check if the prefix is IPv4 address - is_ipv4 = netutils.is_valid_ipv4(cidr) - if is_ipv4: - msg = "Unable to generate IP address by EUI64 for IPv4 prefix" - raise TypeError(msg) - try: - eui64 = int(netaddr.EUI(mac).eui64()) - prefix = netaddr.IPNetwork(cidr) - return netaddr.IPAddress(prefix.first + eui64 ^ (1 << 57)) - except (ValueError, netaddr.AddrFormatError): - raise TypeError('Bad prefix or mac format for generating IPv6 ' - 'address by EUI-64: %(prefix)s, %(mac)s:' - % {'prefix': cidr, 'mac': mac}) - except TypeError: - raise TypeError('Bad prefix type for generate IPv6 address by ' - 'EUI-64: %s' % cidr) - - -# Courtesy of http://stackoverflow.com/a/312464 -def chunkify(sequence, chunksize): - """Yield successive chunks from `sequence`.""" - for i in range(0, len(sequence), chunksize): - yield sequence[i:i + chunksize] diff --git a/tempest/lib/common/utils/linux/__init__.py b/tempest/lib/common/utils/linux/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/common/utils/linux/remote_client.py b/tempest/lib/common/utils/linux/remote_client.py deleted file mode 100644 index aef2ff35b..000000000 --- a/tempest/lib/common/utils/linux/remote_client.py +++ /dev/null @@ -1,126 +0,0 @@ -# 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 sys - -import netaddr -from oslo_log import log as logging -import six - -from tempest.lib.common import ssh -from tempest.lib.common.utils import test_utils -import tempest.lib.exceptions - -LOG = logging.getLogger(__name__) - - -def debug_ssh(function): - """Decorator to generate extra debug info in case off SSH failure""" - def wrapper(self, *args, **kwargs): - try: - return function(self, *args, **kwargs) - except Exception as e: - caller = test_utils.find_test_caller() or "not found" - if not isinstance(e, tempest.lib.exceptions.SSHTimeout): - message = ('Initializing SSH connection to %(ip)s failed. ' - 'Error: %(error)s' % {'ip': self.ip_address, - 'error': e}) - message = '(%s) %s' % (caller, message) - LOG.error(message) - raise - else: - try: - original_exception = sys.exc_info() - if self.server: - msg = 'Caller: %s. Timeout trying to ssh to server %s' - LOG.debug(msg, caller, self.server) - if self.console_output_enabled and self.servers_client: - try: - msg = 'Console log for server %s: %s' - console_log = ( - self.servers_client.get_console_output( - self.server['id'])['output']) - LOG.debug(msg, self.server['id'], console_log) - except Exception: - msg = 'Could not get console_log for server %s' - LOG.debug(msg, self.server['id']) - # re-raise the original ssh timeout exception - six.reraise(*original_exception) - finally: - # Delete the traceback to avoid circular references - _, _, trace = original_exception - del trace - return wrapper - - -class RemoteClient(object): - - def __init__(self, ip_address, username, password=None, pkey=None, - server=None, servers_client=None, ssh_timeout=300, - connect_timeout=60, console_output_enabled=True, - ssh_shell_prologue="set -eu -o pipefail; PATH=$$PATH:/sbin;", - ping_count=1, ping_size=56): - """Executes commands in a VM over ssh - - :param ip_address: IP address to ssh to - :param username: Ssh username - :param password: Ssh password - :param pkey: Ssh public key - :param server: Server dict, used for debugging purposes - :param servers_client: Servers client, used for debugging purposes - :param ssh_timeout: Timeout in seconds to wait for the ssh banner - :param connect_timeout: Timeout in seconds to wait for TCP connection - :param console_output_enabled: Support serial console output? - :param ssh_shell_prologue: Shell fragments to use before command - :param ping_count: Number of ping packets - :param ping_size: Packet size for ping packets - """ - self.server = server - self.servers_client = servers_client - self.ip_address = ip_address - self.console_output_enabled = console_output_enabled - self.ssh_shell_prologue = ssh_shell_prologue - self.ping_count = ping_count - self.ping_size = ping_size - - self.ssh_client = ssh.Client(ip_address, username, password, - ssh_timeout, pkey=pkey, - channel_timeout=connect_timeout) - - @debug_ssh - def exec_command(self, cmd): - # Shell options below add more clearness on failures, - # path is extended for some non-cirros guest oses (centos7) - cmd = self.ssh_shell_prologue + " " + cmd - LOG.debug("Remote command: %s", cmd) - return self.ssh_client.exec_command(cmd) - - @debug_ssh - def validate_authentication(self): - """Validate ssh connection and authentication - - This method raises an Exception when the validation fails. - """ - self.ssh_client.test_connection_auth() - - def ping_host(self, host, count=None, size=None, nic=None): - if count is None: - count = self.ping_count - if size is None: - size = self.ping_size - - addr = netaddr.IPAddress(host) - cmd = 'ping6' if addr.version == 6 else 'ping' - if nic: - cmd = 'sudo {cmd} -I {nic}'.format(cmd=cmd, nic=nic) - cmd += ' -c{0} -w{0} -s{1} {2}'.format(count, size, host) - return self.exec_command(cmd) diff --git a/tempest/lib/common/utils/misc.py b/tempest/lib/common/utils/misc.py deleted file mode 100644 index f13b4c882..000000000 --- a/tempest/lib/common/utils/misc.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_log import log as logging - -from tempest.lib.common.utils import test_utils - -LOG = logging.getLogger(__name__) - - -def singleton(cls): - """Simple wrapper for classes that should only have a single instance.""" - instances = {} - - def getinstance(): - if cls not in instances: - instances[cls] = cls() - return instances[cls] - return getinstance - - -def find_test_caller(*args, **kwargs): - LOG.warning("tempest.lib.common.utils.misc.find_test_caller is deprecated " - "in favor of tempest.lib.common.utils.test_utils." - "find_test_caller") - test_utils.find_test_caller(*args, **kwargs) diff --git a/tempest/lib/common/utils/test_utils.py b/tempest/lib/common/utils/test_utils.py deleted file mode 100644 index bd0db7c81..000000000 --- a/tempest/lib/common/utils/test_utils.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# 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 inspect -import re -import time - -from oslo_log import log as logging - -from tempest.lib import exceptions - -LOG = logging.getLogger(__name__) - - -def find_test_caller(): - """Find the caller class and test name. - - Because we know that the interesting things that call us are - test_* methods, and various kinds of setUp / tearDown, we - can look through the call stack to find appropriate methods, - and the class we were in when those were called. - """ - caller_name = None - names = [] - frame = inspect.currentframe() - is_cleanup = False - # Start climbing the ladder until we hit a good method - while True: - try: - frame = frame.f_back - name = frame.f_code.co_name - names.append(name) - if re.search("^(test_|setUp|tearDown)", name): - cname = "" - if 'self' in frame.f_locals: - cname = frame.f_locals['self'].__class__.__name__ - if 'cls' in frame.f_locals: - cname = frame.f_locals['cls'].__name__ - caller_name = cname + ":" + name - break - elif re.search("^_run_cleanup", name): - is_cleanup = True - elif name == 'main': - caller_name = 'main' - break - else: - cname = "" - if 'self' in frame.f_locals: - cname = frame.f_locals['self'].__class__.__name__ - if 'cls' in frame.f_locals: - cname = frame.f_locals['cls'].__name__ - - # the fact that we are running cleanups is indicated pretty - # deep in the stack, so if we see that we want to just - # start looking for a real class name, and declare victory - # once we do. - if is_cleanup and cname: - if not re.search("^RunTest", cname): - caller_name = cname + ":_run_cleanups" - break - except Exception: - break - # prevents frame leaks - del frame - if caller_name is None: - LOG.debug("Sane call name not found in %s", names) - return caller_name - - -def call_and_ignore_notfound_exc(func, *args, **kwargs): - """Call the given function and pass if a `NotFound` exception is raised.""" - try: - return func(*args, **kwargs) - except exceptions.NotFound: - pass - - -def call_until_true(func, duration, sleep_for): - """Call the given function until it returns True (and return True) - - or until the specified duration (in seconds) elapses (and return False). - - :param func: A zero argument callable that returns True on success. - :param duration: The number of seconds for which to attempt a - successful call of the function. - :param sleep_for: The number of seconds to sleep after an unsuccessful - invocation of the function. - """ - now = time.time() - timeout = now + duration - while now < timeout: - if func(): - return True - time.sleep(sleep_for) - now = time.time() - return False diff --git a/tempest/lib/decorators.py b/tempest/lib/decorators.py deleted file mode 100644 index f82f707af..000000000 --- a/tempest/lib/decorators.py +++ /dev/null @@ -1,124 +0,0 @@ -# Copyright 2015 Hewlett-Packard Development Company, L.P. -# -# 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 functools -import uuid - -import debtcollector.removals -from oslo_log import log as logging -import six -import testtools - -LOG = logging.getLogger(__name__) - - -def skip_because(*args, **kwargs): - """A decorator useful to skip tests hitting known bugs - - @param bug: bug number causing the test to skip - @param condition: optional condition to be True for the skip to have place - """ - def decorator(f): - @functools.wraps(f) - def wrapper(self, *func_args, **func_kwargs): - skip = False - if "condition" in kwargs: - if kwargs["condition"] is True: - skip = True - else: - skip = True - if "bug" in kwargs and skip is True: - if not kwargs['bug'].isdigit(): - raise ValueError('bug must be a valid bug number') - msg = "Skipped until Bug: %s is resolved." % kwargs["bug"] - raise testtools.TestCase.skipException(msg) - return f(self, *func_args, **func_kwargs) - return wrapper - return decorator - - -def related_bug(bug, status_code=None): - """A decorator useful to know solutions from launchpad bug reports - - @param bug: The launchpad bug number causing the test - @param status_code: The status code related to the bug report - """ - def decorator(f): - @functools.wraps(f) - def wrapper(self, *func_args, **func_kwargs): - try: - return f(self, *func_args, **func_kwargs) - except Exception as exc: - exc_status_code = getattr(exc, 'status_code', None) - if status_code is None or status_code == exc_status_code: - LOG.error('Hints: This test was made for the bug %s. ' - 'The failure could be related to ' - 'https://launchpad.net/bugs/%s', bug, bug) - raise exc - return wrapper - return decorator - - -def idempotent_id(id): - """Stub for metadata decorator""" - if not isinstance(id, six.string_types): - raise TypeError('Test idempotent_id must be string not %s' - '' % type(id).__name__) - uuid.UUID(id) - - def decorator(f): - f = testtools.testcase.attr('id-%s' % id)(f) - if f.__doc__: - f.__doc__ = 'Test idempotent id: %s\n%s' % (id, f.__doc__) - else: - f.__doc__ = 'Test idempotent id: %s' % id - return f - return decorator - - -@debtcollector.removals.remove(removal_version='Queen') -class skip_unless_attr(object): - """Decorator to skip tests if a specified attr does not exists or False""" - def __init__(self, attr, msg=None): - self.attr = attr - self.message = msg or ("Test case attribute %s not found " - "or False") % attr - - def __call__(self, func): - @functools.wraps(func) - def _skipper(*args, **kw): - """Wrapped skipper function.""" - testobj = args[0] - if not getattr(testobj, self.attr, False): - raise testtools.TestCase.skipException(self.message) - func(*args, **kw) - return _skipper - - -def attr(**kwargs): - """A decorator which applies the testtools attr decorator - - This decorator applies the testtools.testcase.attr if it is in the list of - attributes to testtools we want to apply. - """ - - def decorator(f): - if 'type' in kwargs and isinstance(kwargs['type'], str): - f = testtools.testcase.attr(kwargs['type'])(f) - elif 'type' in kwargs and isinstance(kwargs['type'], list): - for attr in kwargs['type']: - f = testtools.testcase.attr(attr)(f) - return f - - return decorator diff --git a/tempest/lib/exceptions.py b/tempest/lib/exceptions.py deleted file mode 100644 index cdb8be9d0..000000000 --- a/tempest/lib/exceptions.py +++ /dev/null @@ -1,275 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 testtools - - -class TempestException(Exception): - """Base Tempest Exception - - To correctly use this class, inherit from it and define - a 'message' property. That message will get printf'd - with the keyword arguments provided to the constructor. - """ - message = "An unknown exception occurred" - - def __init__(self, *args, **kwargs): - super(TempestException, self).__init__() - try: - self._error_string = self.message % kwargs - except Exception: - # at least get the core message out if something happened - self._error_string = self.message - if args: - # If there is a non-kwarg parameter, assume it's the error - # message or reason description and tack it on to the end - # of the exception message - # Convert all arguments into their string representations... - args = ["%s" % arg for arg in args] - self._error_string = (self._error_string + - "\nDetails: %s" % '\n'.join(args)) - - def __str__(self): - return self._error_string - - -class RestClientException(TempestException, - testtools.TestCase.failureException): - def __init__(self, resp_body=None, *args, **kwargs): - if 'resp' in kwargs: - self.resp = kwargs.get('resp') - self.resp_body = resp_body - message = kwargs.get("message", resp_body) - super(RestClientException, self).__init__(message, *args, **kwargs) - - -class OtherRestClientException(RestClientException): - pass - - -class ServerRestClientException(RestClientException): - pass - - -class ClientRestClientException(RestClientException): - pass - - -class InvalidHttpSuccessCode(OtherRestClientException): - message = "The success code is different than the expected one" - - -class BadRequest(ClientRestClientException): - status_code = 400 - message = "Bad request" - - -class Unauthorized(ClientRestClientException): - status_code = 401 - message = 'Unauthorized' - - -class Forbidden(ClientRestClientException): - status_code = 403 - message = "Forbidden" - - -class NotFound(ClientRestClientException): - status_code = 404 - message = "Object not found" - - -class Conflict(ClientRestClientException): - status_code = 409 - message = "An object with that identifier already exists" - - -class Gone(ClientRestClientException): - status_code = 410 - message = "The requested resource is no longer available" - - -class PreconditionFailed(ClientRestClientException): - status_code = 412 - message = "Precondition Failed" - - -class RateLimitExceeded(ClientRestClientException): - status_code = 413 - message = "Rate limit exceeded" - - -class OverLimit(ClientRestClientException): - status_code = 413 - message = "Request entity is too large" - - -class InvalidContentType(ClientRestClientException): - status_code = 415 - message = "Invalid content type provided" - - -class UnprocessableEntity(ClientRestClientException): - status_code = 422 - message = "Unprocessable entity" - - -class ServerFault(ServerRestClientException): - status_code = 500 - message = "Got server fault" - - -class NotImplemented(ServerRestClientException): - status_code = 501 - message = "Got NotImplemented error" - - -class TimeoutException(OtherRestClientException): - message = "Request timed out" - - -class ResponseWithNonEmptyBody(OtherRestClientException): - message = ("RFC Violation! Response with %(status)d HTTP Status Code " - "MUST NOT have a body") - - -class ResponseWithEntity(OtherRestClientException): - message = ("RFC Violation! Response with 205 HTTP Status Code " - "MUST NOT have an entity") - - -class InvalidHTTPResponseBody(OtherRestClientException): - message = "HTTP response body is invalid json or xml" - - -class InvalidHTTPResponseHeader(OtherRestClientException): - message = "HTTP response header is invalid" - - -class UnexpectedContentType(OtherRestClientException): - message = "Unexpected content type provided" - - -class UnexpectedResponseCode(OtherRestClientException): - message = "Unexpected response code received" - - -class InvalidConfiguration(TempestException): - message = "Invalid Configuration" - - -class InvalidIdentityVersion(TempestException): - message = "Invalid version %(identity_version)s of the identity service" - - -class InvalidStructure(TempestException): - message = "Invalid structure of table with details" - - -class InvalidAPIVersionString(TempestException): - message = ("API Version String %(version)s is of invalid format. Must " - "be of format MajorNum.MinorNum or string 'latest'.") - - -class JSONSchemaNotFound(TempestException): - message = ("JSON Schema for %(version)s is not found in\n" - " %(schema_versions_info)s") - - -class InvalidAPIVersionRange(TempestException): - message = ("The API version range is invalid.") - - -class BadAltAuth(TempestException): - """Used when trying and failing to change to alt creds. - - If alt creds end up the same as primary creds, use this - exception. This is often going to be the case when you assume - project_id is in the url, but it's not. - - """ - message = "The alt auth looks the same as primary auth for %(part)s" - - -class CommandFailed(Exception): - def __init__(self, returncode, cmd, output, stderr): - super(CommandFailed, self).__init__() - self.returncode = returncode - self.cmd = cmd - self.stdout = output - self.stderr = stderr - - def __str__(self): - return ("Command '%s' returned non-zero exit status %d.\n" - "stdout:\n%s\n" - "stderr:\n%s" % (self.cmd, - self.returncode, - self.stdout, - self.stderr)) - - -class IdentityError(TempestException): - message = "Got identity error" - - -class EndpointNotFound(TempestException): - message = "Endpoint not found" - - -class InvalidCredentials(TempestException): - message = "Invalid Credentials" - - -class InvalidScope(TempestException): - message = "Invalid Scope %(scope)s for %(auth_provider)s" - - -class SSHTimeout(TempestException): - message = ("Connection to the %(host)s via SSH timed out.\n" - "User: %(user)s, Password: %(password)s") - - -class SSHExecCommandFailed(TempestException): - """Raised when remotely executed command returns nonzero status.""" - message = ("Command '%(command)s', exit status: %(exit_status)d, " - "stderr:\n%(stderr)s\n" - "stdout:\n%(stdout)s") - - -class UnknownServiceClient(TempestException): - message = "Service clients named %(services)s are not known" - - -class ServiceClientRegistrationException(TempestException): - message = ("Error registering module %(name)s in path %(module_path)s, " - "with service %(service_version)s and clients " - "%(client_names)s: %(detailed_error)s") - - -class PluginRegistrationException(TempestException): - message = "Error registering plugin %(name)s: %(detailed_error)s" - - -class VolumeBackupException(TempestException): - message = "Volume backup %(backup_id)s failed and is in ERROR status" - - -class DeleteErrorException(TempestException): - message = ("Resource %(resource_id)s failed to delete " - "and is in ERROR status") - - -class InvalidTestResource(TempestException): - message = "%(name)s is not a valid %(type)s, or the name is ambiguous" diff --git a/tempest/lib/services/__init__.py b/tempest/lib/services/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/lib/services/clients.py b/tempest/lib/services/clients.py deleted file mode 100644 index 5f230b7b4..000000000 --- a/tempest/lib/services/clients.py +++ /dev/null @@ -1,466 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# 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 copy -import importlib -import inspect -import warnings - -from debtcollector import removals -from oslo_log import log as logging - -from tempest.lib import auth -from tempest.lib.common.utils import misc -from tempest.lib import exceptions -from tempest.lib.services import compute -from tempest.lib.services import identity -from tempest.lib.services import image -from tempest.lib.services import network -from tempest.lib.services import volume - -warnings.simplefilter("once") -LOG = logging.getLogger(__name__) - - -def tempest_modules(): - """Dict of service client modules available in Tempest. - - Provides a dict of stable service modules available in Tempest, with - ``service_version`` as key, and the module object as value. - """ - return { - 'compute': compute, - 'identity.v2': identity.v2, - 'identity.v3': identity.v3, - 'image.v1': image.v1, - 'image.v2': image.v2, - 'network': network, - 'volume.v1': volume.v1, - 'volume.v2': volume.v2, - 'volume.v3': volume.v3 - } - - -def _tempest_internal_modules(): - # Set of unstable service clients available in Tempest - # NOTE(andreaf) This list will exists only as long the remain clients - # are migrated to tempest.lib, and it will then be deleted without - # deprecation or advance notice - return set(['object-storage']) - - -def available_modules(): - """Set of service client modules available in Tempest and plugins - - Set of stable service clients from Tempest and service clients exposed - by plugins. This set of available modules can be used for automatic - configuration. - - :raise PluginRegistrationException: if a plugin exposes a service_version - already defined by Tempest or another plugin. - - Examples:: - - from tempest import config - params = {} - for service_version in available_modules(): - service = service_version.split('.')[0] - params[service] = config.service_client_config(service) - service_clients = ServiceClients(creds, identity_uri, - client_parameters=params) - """ - extra_service_versions = set([]) - _tempest_modules = set(tempest_modules()) - plugin_services = ClientsRegistry().get_service_clients() - for plugin_name in plugin_services: - plug_service_versions = set([x['service_version'] for x in - plugin_services[plugin_name]]) - # If a plugin exposes a duplicate service_version raise an exception - if plug_service_versions: - if not plug_service_versions.isdisjoint(extra_service_versions): - detailed_error = ( - 'Plugin %s is trying to register a service %s already ' - 'claimed by another one' % (plugin_name, - extra_service_versions & - plug_service_versions)) - raise exceptions.PluginRegistrationException( - name=plugin_name, detailed_error=detailed_error) - # NOTE(andreaf) Once all tempest clients are stable, the following - # if will have to be removed. - if not plug_service_versions.isdisjoint( - _tempest_internal_modules()): - detailed_error = ( - 'Plugin %s is trying to register a service %s already ' - 'claimed by a Tempest one' % (plugin_name, - _tempest_internal_modules() & - plug_service_versions)) - raise exceptions.PluginRegistrationException( - name=plugin_name, detailed_error=detailed_error) - extra_service_versions |= plug_service_versions - return _tempest_modules | extra_service_versions - - -@misc.singleton -class ClientsRegistry(object): - """Registry of all service clients available from plugins""" - - def __init__(self): - self._service_clients = {} - - def register_service_client(self, plugin_name, service_client_data): - if plugin_name in self._service_clients: - detailed_error = 'Clients for plugin %s already registered' - raise exceptions.PluginRegistrationException( - name=plugin_name, - detailed_error=detailed_error % plugin_name) - self._service_clients[plugin_name] = service_client_data - LOG.debug("Successfully registered plugin %s in the service client " - "registry with configuration: %s", plugin_name, - service_client_data) - - def get_service_clients(self): - return self._service_clients - - -class ClientsFactory(object): - """Builds service clients for a service client module - - This class implements the logic of feeding service client parameters - to service clients from a specific module. It allows setting the - parameters once and obtaining new instances of the clients without the - need of passing any parameter. - - ClientsFactory can be used directly, or consumed via the `ServiceClients` - class, which manages the authorization part. - """ - - def __init__(self, module_path, client_names, auth_provider, **kwargs): - """Initialises the client factory - - :param module_path: Path to module that includes all service clients. - All service client classes must be exposed by a single module. - If they are separated in different modules, defining __all__ - in the root module can help, similar to what is done by service - clients in tempest. - :param client_names: List or set of names of the service client - classes. - :param auth_provider: The auth provider used to initialise client. - :param kwargs: Parameters to be passed to all clients. Parameters - values can be overwritten when clients are initialised, but - parameters cannot be deleted. - :raise ImportError: if the specified module_path cannot be imported - - Example:: - - # Get credentials and an auth_provider - clients = ClientsFactory( - module_path='my_service.my_service_clients', - client_names=['ServiceClient1', 'ServiceClient2'], - auth_provider=auth_provider, - service='my_service', - region='region1') - my_api_client = clients.MyApiClient() - my_api_client_region2 = clients.MyApiClient(region='region2') - - """ - # Import the module. If it's not importable, the raised exception - # provides good enough information about what happened - _module = importlib.import_module(module_path) - # If any of the classes is not in the module we fail - for class_name in client_names: - # TODO(andreaf) This always passes all parameters to all clients. - # In future to allow clients to specify the list of parameters - # that they accept based out of a list of standard ones. - - # Obtain the class - klass = self._get_class(_module, class_name) - final_kwargs = copy.copy(kwargs) - - # Set the function as an attribute of the factory - setattr(self, class_name, self._get_partial_class( - klass, auth_provider, final_kwargs)) - - def _get_partial_class(self, klass, auth_provider, kwargs): - - # Define a function that returns a new class instance by - # combining default kwargs with extra ones - def partial_class(alias=None, **later_kwargs): - """Returns a callable the initialises a service client - - Builds a callable that accepts kwargs, which are passed through - to the __init__ of the service client, along with a set of defaults - set in factory at factory __init__ time. - Original args in the service client can only be passed as kwargs. - - It accepts one extra parameter 'alias' compared to the original - service client. When alias is provided, the returned callable will - also set an attribute called with a name defined in 'alias', which - contains the instance of the service client. - - :param alias: str Name of the attribute set on the factory once - the callable is invoked which contains the initialised - service client. If None, no attribute is set. - :param later_kwargs: kwargs passed through to the service client - __init__ on top of defaults set at factory level. - """ - kwargs.update(later_kwargs) - _client = klass(auth_provider=auth_provider, **kwargs) - if alias: - setattr(self, alias, _client) - return _client - - return partial_class - - @classmethod - def _get_class(cls, module, class_name): - klass = getattr(module, class_name, None) - if not klass: - msg = 'Invalid class name, %s is not found in %s' - raise AttributeError(msg % (class_name, module)) - if not inspect.isclass(klass): - msg = 'Expected a class, got %s of type %s instead' - raise TypeError(msg % (klass, type(klass))) - return klass - - -class ServiceClients(object): - """Service client provider class - - The ServiceClients object provides a useful means for tests to access - service clients configured for a specified set of credentials. - It hides some of the complexity from the authorization and configuration - layers. - - Examples:: - - # johndoe is a tempest.lib.auth.Credentials type instance - johndoe_clients = clients.ServiceClients(johndoe, identity_uri) - - # List servers in default region - johndoe_servers_client = johndoe_clients.compute.ServersClient() - johndoe_servers = johndoe_servers_client.list_servers() - - # List servers in Region B - johndoe_servers_client_B = johndoe_clients.compute.ServersClient( - region='B') - johndoe_servers = johndoe_servers_client_B.list_servers() - - """ - # NOTE(andreaf) This class does not depend on tempest configuration - # and its meant for direct consumption by external clients such as tempest - # plugins. Tempest provides a wrapper class, `clients.Manager`, that - # initialises this class using values from tempest CONF object. The wrapper - # class should only be used by tests hosted in Tempest. - - @removals.removed_kwarg('client_parameters') - def __init__(self, credentials, identity_uri, region=None, scope='project', - disable_ssl_certificate_validation=True, ca_certs=None, - trace_requests='', client_parameters=None): - """Service Clients provider - - Instantiate a `ServiceClients` object, from a set of credentials and an - identity URI. The identity version is inferred from the credentials - object. Optionally auth scope can be provided. - - A few parameters can be given a value which is applied as default - for all service clients: region, dscv, ca_certs, trace_requests. - - Parameters dscv, ca_certs and trace_requests all apply to the auth - provider as well as any service clients provided by this manager. - - Any other client parameter should be set via ClientsRegistry. - - Client parameter used to be set via client_parameters, but this is - deprecated, and it is actually already not honoured - anymore: https://launchpad.net/bugs/1680915. - - The list of available parameters is defined in the service clients - interfaces. For reference, most clients will accept 'region', - 'service', 'endpoint_type', 'build_timeout' and 'build_interval', which - are all inherited from RestClient. - - The `config` module in Tempest exposes an helper function - `service_client_config` that can be used to extract from configuration - a dictionary ready to be injected in kwargs. - - Exceptions are: - - Token clients for 'identity' must be given an 'auth_url' parameter - - Volume client for 'volume' accepts 'default_volume_size' - - Servers client from 'compute' accepts 'enable_instance_password' - - If Tempest configuration is used, parameters will be loaded in the - Registry automatically for all service client (Tempest stable ones - and plugins). - - Examples:: - - identity_params = config.service_client_config('identity') - params = { - 'identity': identity_params, - 'compute': {'region': 'region2'}} - manager = lib_manager.Manager( - my_creds, identity_uri, client_parameters=params) - - :param credentials: An instance of `auth.Credentials` - :param identity_uri: URI of the identity API. This should be a - mandatory parameter, and it will so soon. - :param region: Default value of region for service clients. - :param scope: default scope for tokens produced by the auth provider - :param disable_ssl_certificate_validation: Applies to auth and to all - service clients. - :param ca_certs: Applies to auth and to all service clients. - :param trace_requests: Applies to auth and to all service clients. - :param client_parameters: Dictionary with parameters for service - clients. Keys of the dictionary are the service client service - name, as declared in `service_clients.available_modules()` except - for the version. Values are dictionaries of parameters that are - going to be passed to all clients in the service client module. - """ - self._registered_services = set([]) - self.credentials = credentials - self.identity_uri = identity_uri - if not identity_uri: - raise exceptions.InvalidCredentials( - 'ServiceClients requires a non-empty identity_uri.') - self.region = region - # Check if passed or default credentials are valid - if not self.credentials.is_valid(): - raise exceptions.InvalidCredentials() - # Get the identity classes matching the provided credentials - # TODO(andreaf) Define a new interface in Credentials to get - # the API version from an instance - identity = [(k, auth.IDENTITY_VERSION[k][1]) for k in - auth.IDENTITY_VERSION.keys() if - isinstance(self.credentials, auth.IDENTITY_VERSION[k][0])] - # Zero matches or more than one are both not valid. - if len(identity) != 1: - raise exceptions.InvalidCredentials() - self.auth_version, auth_provider_class = identity[0] - self.dscv = disable_ssl_certificate_validation - self.ca_certs = ca_certs - self.trace_requests = trace_requests - # Creates an auth provider for the credentials - self.auth_provider = auth_provider_class( - self.credentials, self.identity_uri, scope=scope, - disable_ssl_certificate_validation=self.dscv, - ca_certs=self.ca_certs, trace_requests=self.trace_requests) - # Setup some defaults for client parameters of registered services - client_parameters = client_parameters or {} - self.parameters = {} - # Parameters are provided for unversioned services - all_modules = available_modules() | _tempest_internal_modules() - unversioned_services = set( - [x.split('.')[0] for x in all_modules]) - for service in unversioned_services: - self.parameters[service] = self._setup_parameters( - client_parameters.pop(service, {})) - # Check that no client parameters was supplied for unregistered clients - if client_parameters: - raise exceptions.UnknownServiceClient( - services=list(client_parameters.keys())) - - # Register service clients from the registry (__tempest__ and plugins) - clients_registry = ClientsRegistry() - plugin_service_clients = clients_registry.get_service_clients() - for plugin in plugin_service_clients: - service_clients = plugin_service_clients[plugin] - # Each plugin returns a list of service client parameters - for service_client in service_clients: - # NOTE(andreaf) If a plugin cannot register, stop the - # registration process, log some details to help - # troubleshooting, and re-raise - try: - self.register_service_client_module(**service_client) - except Exception: - LOG.exception( - 'Failed to register service client from plugin %s ' - 'with parameters %s', plugin, service_client) - raise - - def register_service_client_module(self, name, service_version, - module_path, client_names, **kwargs): - """Register a service client module - - Initiates a client factory for the specified module, using this - class auth_provider, and accessible via a `name` attribute in the - service client. - - :param name: Name used to access the client - :param service_version: Name of the service complete with version. - Used to track registered services. When a plugin implements it, - it can be used by other plugins to obtain their configuration. - :param module_path: Path to module that includes all service clients. - All service client classes must be exposed by a single module. - If they are separated in different modules, defining __all__ - in the root module can help, similar to what is done by service - clients in tempest. - :param client_names: List or set of names of service client classes. - :param kwargs: Extra optional parameters to be passed to all clients. - ServiceClient provides defaults for region, dscv, ca_certs and - trace_requests. - :raise ServiceClientRegistrationException: if the provided name is - already in use or if service_version is already registered. - :raise ImportError: if module_path cannot be imported. - """ - if hasattr(self, name): - using_name = getattr(self, name) - detailed_error = 'Module name already in use: %s' % using_name - raise exceptions.ServiceClientRegistrationException( - name=name, service_version=service_version, - module_path=module_path, client_names=client_names, - detailed_error=detailed_error) - if service_version in self.registered_services: - detailed_error = 'Service %s already registered.' % service_version - raise exceptions.ServiceClientRegistrationException( - name=name, service_version=service_version, - module_path=module_path, client_names=client_names, - detailed_error=detailed_error) - params = dict(region=self.region, - disable_ssl_certificate_validation=self.dscv, - ca_certs=self.ca_certs, - trace_requests=self.trace_requests) - params.update(kwargs) - # Instantiate the client factory - _factory = ClientsFactory(module_path=module_path, - client_names=client_names, - auth_provider=self.auth_provider, - **params) - # Adds the client factory to the service_client - setattr(self, name, _factory) - # Add the name of the new service in self.SERVICES for discovery - self._registered_services.add(service_version) - - @property - def registered_services(self): - # NOTE(andreaf) Once all tempest modules are stable this needs to - # be updated to remove _tempest_internal_modules - return self._registered_services | _tempest_internal_modules() - - def _setup_parameters(self, parameters): - """Setup default values for client parameters - - Region by default is the region passed as an __init__ parameter. - Checks that no parameter for an unknown service is provided. - """ - _parameters = {} - # Use region from __init__ - if self.region: - _parameters['region'] = self.region - # Update defaults with specified parameters - _parameters.update(parameters) - # If any parameter is left, parameters for an unknown service were - # provided as input. Fail rather than ignore silently. - return _parameters diff --git a/tempest/lib/services/compute/__init__.py b/tempest/lib/services/compute/__init__.py deleted file mode 100644 index 91e896af0..000000000 --- a/tempest/lib/services/compute/__init__.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# 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 tempest.lib.services.compute.agents_client import AgentsClient -from tempest.lib.services.compute.aggregates_client import AggregatesClient -from tempest.lib.services.compute.availability_zone_client import \ - AvailabilityZoneClient -from tempest.lib.services.compute.baremetal_nodes_client import \ - BaremetalNodesClient -from tempest.lib.services.compute.certificates_client import \ - CertificatesClient -from tempest.lib.services.compute.extensions_client import \ - ExtensionsClient -from tempest.lib.services.compute.fixed_ips_client import FixedIPsClient -from tempest.lib.services.compute.flavors_client import FlavorsClient -from tempest.lib.services.compute.floating_ip_pools_client import \ - FloatingIPPoolsClient -from tempest.lib.services.compute.floating_ips_bulk_client import \ - FloatingIPsBulkClient -from tempest.lib.services.compute.floating_ips_client import \ - FloatingIPsClient -from tempest.lib.services.compute.hosts_client import HostsClient -from tempest.lib.services.compute.hypervisor_client import \ - HypervisorClient -from tempest.lib.services.compute.images_client import ImagesClient -from tempest.lib.services.compute.instance_usage_audit_log_client import \ - InstanceUsagesAuditLogClient -from tempest.lib.services.compute.interfaces_client import InterfacesClient -from tempest.lib.services.compute.keypairs_client import KeyPairsClient -from tempest.lib.services.compute.limits_client import LimitsClient -from tempest.lib.services.compute.migrations_client import MigrationsClient -from tempest.lib.services.compute.networks_client import NetworksClient -from tempest.lib.services.compute.quota_classes_client import \ - QuotaClassesClient -from tempest.lib.services.compute.quotas_client import QuotasClient -from tempest.lib.services.compute.security_group_default_rules_client import \ - SecurityGroupDefaultRulesClient -from tempest.lib.services.compute.security_group_rules_client import \ - SecurityGroupRulesClient -from tempest.lib.services.compute.security_groups_client import \ - SecurityGroupsClient -from tempest.lib.services.compute.server_groups_client import \ - ServerGroupsClient -from tempest.lib.services.compute.servers_client import ServersClient -from tempest.lib.services.compute.services_client import ServicesClient -from tempest.lib.services.compute.snapshots_client import SnapshotsClient -from tempest.lib.services.compute.tenant_networks_client import \ - TenantNetworksClient -from tempest.lib.services.compute.tenant_usages_client import \ - TenantUsagesClient -from tempest.lib.services.compute.versions_client import VersionsClient -from tempest.lib.services.compute.volumes_client import \ - VolumesClient - -__all__ = ['AgentsClient', 'AggregatesClient', 'AvailabilityZoneClient', - 'BaremetalNodesClient', 'CertificatesClient', 'ExtensionsClient', - 'FixedIPsClient', 'FlavorsClient', 'FloatingIPPoolsClient', - 'FloatingIPsBulkClient', 'FloatingIPsClient', 'HostsClient', - 'HypervisorClient', 'ImagesClient', 'InstanceUsagesAuditLogClient', - 'InterfacesClient', 'KeyPairsClient', 'LimitsClient', - 'MigrationsClient', 'NetworksClient', 'QuotaClassesClient', - 'QuotasClient', 'SecurityGroupDefaultRulesClient', - 'SecurityGroupRulesClient', 'SecurityGroupsClient', - 'ServerGroupsClient', 'ServersClient', 'ServicesClient', - 'SnapshotsClient', 'TenantNetworksClient', 'TenantUsagesClient', - 'VersionsClient', 'VolumesClient'] diff --git a/tempest/lib/services/compute/agents_client.py b/tempest/lib/services/compute/agents_client.py deleted file mode 100644 index 408f75dc2..000000000 --- a/tempest/lib/services/compute/agents_client.py +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright 2014 NEC Corporation. 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import agents as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class AgentsClient(base_compute_client.BaseComputeClient): - """Tests Agents API""" - - def list_agents(self, **params): - """List all agent builds. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-agent-builds - """ - url = 'os-agents' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.list_agents, resp, body) - return rest_client.ResponseBody(resp, body) - - def create_agent(self, **kwargs): - """Create an agent build. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-agent-build - """ - post_body = json.dumps({'agent': kwargs}) - resp, body = self.post('os-agents', post_body) - body = json.loads(body) - self.validate_response(schema.create_agent, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_agent(self, agent_id): - """Delete an existing agent build. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#delete-agent-build - """ - resp, body = self.delete("os-agents/%s" % agent_id) - self.validate_response(schema.delete_agent, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_agent(self, agent_id, **kwargs): - """Update an agent build. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#update-agent-build - """ - put_body = json.dumps({'para': kwargs}) - resp, body = self.put('os-agents/%s' % agent_id, put_body) - body = json.loads(body) - self.validate_response(schema.update_agent, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/aggregates_client.py b/tempest/lib/services/compute/aggregates_client.py deleted file mode 100644 index 713d7a30b..000000000 --- a/tempest/lib/services/compute/aggregates_client.py +++ /dev/null @@ -1,126 +0,0 @@ -# Copyright 2013 NEC Corporation. -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import aggregates as schema -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.compute import base_compute_client - - -class AggregatesClient(base_compute_client.BaseComputeClient): - - def list_aggregates(self): - """Get aggregate list.""" - resp, body = self.get("os-aggregates") - body = json.loads(body) - self.validate_response(schema.list_aggregates, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_aggregate(self, aggregate_id): - """Get details of the given aggregate.""" - resp, body = self.get("os-aggregates/%s" % aggregate_id) - body = json.loads(body) - self.validate_response(schema.get_aggregate, resp, body) - return rest_client.ResponseBody(resp, body) - - def create_aggregate(self, **kwargs): - """Create a new aggregate. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-aggregate - """ - post_body = json.dumps({'aggregate': kwargs}) - resp, body = self.post('os-aggregates', post_body) - - body = json.loads(body) - self.validate_response(schema.create_aggregate, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_aggregate(self, aggregate_id, **kwargs): - """Update an aggregate. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#update-aggregate - """ - put_body = json.dumps({'aggregate': kwargs}) - resp, body = self.put('os-aggregates/%s' % aggregate_id, put_body) - - body = json.loads(body) - self.validate_response(schema.update_aggregate, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_aggregate(self, aggregate_id): - """Delete the given aggregate.""" - resp, body = self.delete("os-aggregates/%s" % aggregate_id) - self.validate_response(schema.delete_aggregate, resp, body) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_aggregate(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Return the primary type of resource this client works with.""" - return 'aggregate' - - def add_host(self, aggregate_id, **kwargs): - """Add a host to the given aggregate. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#add-host - """ - post_body = json.dumps({'add_host': kwargs}) - resp, body = self.post('os-aggregates/%s/action' % aggregate_id, - post_body) - body = json.loads(body) - self.validate_response(schema.aggregate_add_remove_host, resp, body) - return rest_client.ResponseBody(resp, body) - - def remove_host(self, aggregate_id, **kwargs): - """Remove a host from the given aggregate. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#remove-host - """ - post_body = json.dumps({'remove_host': kwargs}) - resp, body = self.post('os-aggregates/%s/action' % aggregate_id, - post_body) - body = json.loads(body) - self.validate_response(schema.aggregate_add_remove_host, resp, body) - return rest_client.ResponseBody(resp, body) - - def set_metadata(self, aggregate_id, **kwargs): - """Replace the aggregate's existing metadata with new metadata. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-or-update-aggregate-metadata - """ - post_body = json.dumps({'set_metadata': kwargs}) - resp, body = self.post('os-aggregates/%s/action' % aggregate_id, - post_body) - body = json.loads(body) - self.validate_response(schema.aggregate_set_metadata, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/availability_zone_client.py b/tempest/lib/services/compute/availability_zone_client.py deleted file mode 100644 index a91119161..000000000 --- a/tempest/lib/services/compute/availability_zone_client.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright 2013 NEC Corporation. -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import availability_zone \ - as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class AvailabilityZoneClient(base_compute_client.BaseComputeClient): - - def list_availability_zones(self, detail=False): - url = 'os-availability-zone' - schema_list = schema.list_availability_zone_list - if detail: - url += '/detail' - schema_list = schema.list_availability_zone_list_detail - - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema_list, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/baremetal_nodes_client.py b/tempest/lib/services/compute/baremetal_nodes_client.py deleted file mode 100644 index e44c19558..000000000 --- a/tempest/lib/services/compute/baremetal_nodes_client.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import baremetal_nodes \ - as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class BaremetalNodesClient(base_compute_client.BaseComputeClient): - """Tests Baremetal API""" - - def list_baremetal_nodes(self, **params): - """List all baremetal nodes. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-bare-metal-nodes - """ - url = 'os-baremetal-nodes' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.list_baremetal_nodes, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_baremetal_node(self, baremetal_node_id): - """Show the details of a single baremetal node. - - For more information, please refer to the official API reference: - https://developer.openstack.org/api-ref/compute/#show-bare-metal-node-details - """ - url = 'os-baremetal-nodes/%s' % baremetal_node_id - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.get_baremetal_node, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/base_compute_client.py b/tempest/lib/services/compute/base_compute_client.py deleted file mode 100644 index a706a79ac..000000000 --- a/tempest/lib/services/compute/base_compute_client.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 tempest.lib.common import api_version_request -from tempest.lib.common import api_version_utils -from tempest.lib.common import rest_client -from tempest.lib import exceptions - -COMPUTE_MICROVERSION = None - - -class BaseComputeClient(rest_client.RestClient): - """Base compute service clients class to support microversion. - - This class adds microversion to API request header if that is set - and provides interface to select appropriate JSON schema file for - response validation. - - :param auth_provider: An auth provider object used to wrap requests in - auth - :param str service: The service name to use for the catalog lookup - :param str region: The region to use for the catalog lookup - :param kwargs: kwargs required by rest_client.RestClient - """ - - api_microversion_header_name = 'X-OpenStack-Nova-API-Version' - - def get_headers(self): - headers = super(BaseComputeClient, self).get_headers() - if COMPUTE_MICROVERSION: - headers[self.api_microversion_header_name] = COMPUTE_MICROVERSION - return headers - - def request(self, method, url, extra_headers=False, headers=None, - body=None, chunked=False): - resp, resp_body = super(BaseComputeClient, self).request( - method, url, extra_headers, headers, body, chunked) - if (COMPUTE_MICROVERSION and - COMPUTE_MICROVERSION != api_version_utils.LATEST_MICROVERSION): - api_version_utils.assert_version_header_matches_request( - self.api_microversion_header_name, - COMPUTE_MICROVERSION, - resp) - return resp, resp_body - - def get_schema(self, schema_versions_info): - """Get JSON schema - - This method provides the matching schema for requested - microversion. - - :param schema_versions_info: List of dict which provides schema - information with range of valid versions. - - Example:: - - schema_versions_info = [ - {'min': None, 'max': '2.1', 'schema': schemav21}, - {'min': '2.2', 'max': '2.9', 'schema': schemav22}, - {'min': '2.10', 'max': None, 'schema': schemav210}] - """ - schema = None - version = api_version_request.APIVersionRequest(COMPUTE_MICROVERSION) - for items in schema_versions_info: - min_version = api_version_request.APIVersionRequest(items['min']) - max_version = api_version_request.APIVersionRequest(items['max']) - # This is case where COMPUTE_MICROVERSION is None, which means - # request without microversion So select base v2.1 schema. - if version.is_null() and items['min'] is None: - schema = items['schema'] - break - # else select appropriate schema as per COMPUTE_MICROVERSION - elif version.matches(min_version, max_version): - schema = items['schema'] - break - if schema is None: - raise exceptions.JSONSchemaNotFound( - version=version.get_string(), - schema_versions_info=schema_versions_info) - return schema diff --git a/tempest/lib/services/compute/certificates_client.py b/tempest/lib/services/compute/certificates_client.py deleted file mode 100644 index 822756c78..000000000 --- a/tempest/lib/services/compute/certificates_client.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2013 IBM 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 oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import certificates as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class CertificatesClient(base_compute_client.BaseComputeClient): - - def show_certificate(self, certificate_id): - url = "os-certificates/%s" % certificate_id - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.get_certificate, resp, body) - return rest_client.ResponseBody(resp, body) - - def create_certificate(self): - """Create a certificate.""" - url = "os-certificates" - resp, body = self.post(url, None) - body = json.loads(body) - self.validate_response(schema.create_certificate, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/extensions_client.py b/tempest/lib/services/compute/extensions_client.py deleted file mode 100644 index afaf28286..000000000 --- a/tempest/lib/services/compute/extensions_client.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import extensions as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class ExtensionsClient(base_compute_client.BaseComputeClient): - - def list_extensions(self): - url = 'extensions' - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.list_extensions, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_extension(self, extension_alias): - resp, body = self.get('extensions/%s' % extension_alias) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/fixed_ips_client.py b/tempest/lib/services/compute/fixed_ips_client.py deleted file mode 100644 index 968646c00..000000000 --- a/tempest/lib/services/compute/fixed_ips_client.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright 2013 IBM 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 oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import fixed_ips as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class FixedIPsClient(base_compute_client.BaseComputeClient): - - def show_fixed_ip(self, fixed_ip): - url = "os-fixed-ips/%s" % fixed_ip - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.get_fixed_ip, resp, body) - return rest_client.ResponseBody(resp, body) - - def reserve_fixed_ip(self, fixed_ip, **kwargs): - """Reserve/Unreserve a fixed IP. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#reserve-or-release-a-fixed-ip - """ - url = "os-fixed-ips/%s/action" % fixed_ip - resp, body = self.post(url, json.dumps(kwargs)) - self.validate_response(schema.reserve_unreserve_fixed_ip, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/flavors_client.py b/tempest/lib/services/compute/flavors_client.py deleted file mode 100644 index 0fb199151..000000000 --- a/tempest/lib/services/compute/flavors_client.py +++ /dev/null @@ -1,230 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import flavors as schema -from tempest.lib.api_schema.response.compute.v2_1 import flavors_access \ - as schema_access -from tempest.lib.api_schema.response.compute.v2_1 import flavors_extra_specs \ - as schema_extra_specs -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class FlavorsClient(base_compute_client.BaseComputeClient): - - def list_flavors(self, detail=False, **params): - """Lists flavors. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-flavors - https://developer.openstack.org/api-ref/compute/#list-flavors-with-details - """ - url = 'flavors' - _schema = schema.list_flavors - - if detail: - url += '/detail' - _schema = schema.list_flavors_details - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(_schema, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_flavor(self, flavor_id): - """Shows details for a flavor. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#show-flavor-details - """ - resp, body = self.get("flavors/%s" % flavor_id) - body = json.loads(body) - self.validate_response(schema.create_get_flavor_details, resp, body) - return rest_client.ResponseBody(resp, body) - - def create_flavor(self, **kwargs): - """Create a new flavor or instance type. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-flavor - """ - if 'ephemeral' in kwargs: - kwargs['OS-FLV-EXT-DATA:ephemeral'] = kwargs.pop('ephemeral') - if 'is_public' in kwargs: - kwargs['os-flavor-access:is_public'] = kwargs.pop('is_public') - - post_body = json.dumps({'flavor': kwargs}) - resp, body = self.post('flavors', post_body) - - body = json.loads(body) - self.validate_response(schema.create_get_flavor_details, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_flavor(self, flavor_id): - """Delete the given flavor. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#delete-flavor - """ - resp, body = self.delete("flavors/{0}".format(flavor_id)) - self.validate_response(schema.delete_flavor, resp, body) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - # Did not use show_flavor(id) for verification as it gives - # 200 ok even for deleted id. LP #981263 - # we can remove the loop here and use get by ID when bug gets sortedout - flavors = self.list_flavors(detail=True)['flavors'] - for flavor in flavors: - if flavor['id'] == id: - return False - return True - - @property - def resource_type(self): - """Return the primary type of resource this client works with.""" - return 'flavor' - - def set_flavor_extra_spec(self, flavor_id, **kwargs): - """Set extra Specs to the mentioned flavor. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-extra-specs-for-a-flavor - """ - post_body = json.dumps({'extra_specs': kwargs}) - resp, body = self.post('flavors/%s/os-extra_specs' % flavor_id, - post_body) - body = json.loads(body) - self.validate_response(schema_extra_specs.set_get_flavor_extra_specs, - resp, body) - return rest_client.ResponseBody(resp, body) - - def list_flavor_extra_specs(self, flavor_id): - """Get extra Specs details of the mentioned flavor. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-extra-specs-for-a-flavor - """ - resp, body = self.get('flavors/%s/os-extra_specs' % flavor_id) - body = json.loads(body) - self.validate_response(schema_extra_specs.set_get_flavor_extra_specs, - resp, body) - return rest_client.ResponseBody(resp, body) - - def show_flavor_extra_spec(self, flavor_id, key): - """Get extra Specs key-value of the mentioned flavor and key. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#show-an-extra-spec-for-a-flavor - """ - resp, body = self.get('flavors/%s/os-extra_specs/%s' % (flavor_id, - key)) - body = json.loads(body) - self.validate_response( - schema_extra_specs.set_get_flavor_extra_specs_key, - resp, body) - return rest_client.ResponseBody(resp, body) - - def update_flavor_extra_spec(self, flavor_id, key, **kwargs): - """Update specified extra Specs of the mentioned flavor and key. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#update-an-extra-spec-for-a-flavor - """ - resp, body = self.put('flavors/%s/os-extra_specs/%s' % - (flavor_id, key), json.dumps(kwargs)) - body = json.loads(body) - self.validate_response( - schema_extra_specs.set_get_flavor_extra_specs_key, - resp, body) - return rest_client.ResponseBody(resp, body) - - def unset_flavor_extra_spec(self, flavor_id, key): # noqa - # NOTE: This noqa is for passing T111 check and we cannot rename - # to keep backwards compatibility. - """Unset extra Specs from the mentioned flavor. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#delete-an-extra-spec-for-a-flavor - """ - resp, body = self.delete('flavors/%s/os-extra_specs/%s' % - (flavor_id, key)) - self.validate_response(schema.unset_flavor_extra_specs, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_flavor_access(self, flavor_id): - """Get flavor access information given the flavor id. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-flavor-access-information-for-given-flavor - """ - resp, body = self.get('flavors/%s/os-flavor-access' % flavor_id) - body = json.loads(body) - self.validate_response(schema_access.add_remove_list_flavor_access, - resp, body) - return rest_client.ResponseBody(resp, body) - - def add_flavor_access(self, flavor_id, tenant_id): - """Add flavor access for the specified tenant. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#add-flavor-access-to-tenant-addtenantaccess-action - """ - post_body = { - 'addTenantAccess': { - 'tenant': tenant_id - } - } - post_body = json.dumps(post_body) - resp, body = self.post('flavors/%s/action' % flavor_id, post_body) - body = json.loads(body) - self.validate_response(schema_access.add_remove_list_flavor_access, - resp, body) - return rest_client.ResponseBody(resp, body) - - def remove_flavor_access(self, flavor_id, tenant_id): - """Remove flavor access from the specified tenant. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#remove-flavor-access-from-tenant-removetenantaccess-action - """ - post_body = { - 'removeTenantAccess': { - 'tenant': tenant_id - } - } - post_body = json.dumps(post_body) - resp, body = self.post('flavors/%s/action' % flavor_id, post_body) - body = json.loads(body) - self.validate_response(schema_access.add_remove_list_flavor_access, - resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/floating_ip_pools_client.py b/tempest/lib/services/compute/floating_ip_pools_client.py deleted file mode 100644 index d3af050be..000000000 --- a/tempest/lib/services/compute/floating_ip_pools_client.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import floating_ips as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class FloatingIPPoolsClient(base_compute_client.BaseComputeClient): - - def list_floating_ip_pools(self, params=None): - """Gets all floating IP Pools list.""" - url = 'os-floating-ip-pools' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.list_floating_ip_pools, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/floating_ips_bulk_client.py b/tempest/lib/services/compute/floating_ips_bulk_client.py deleted file mode 100644 index 5f06009d6..000000000 --- a/tempest/lib/services/compute/floating_ips_bulk_client.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import floating_ips as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class FloatingIPsBulkClient(base_compute_client.BaseComputeClient): - - def create_floating_ips_bulk(self, ip_range, pool, interface): - """Allocate floating IPs in bulk.""" - post_body = { - 'ip_range': ip_range, - 'pool': pool, - 'interface': interface - } - post_body = json.dumps({'floating_ips_bulk_create': post_body}) - resp, body = self.post('os-floating-ips-bulk', post_body) - body = json.loads(body) - self.validate_response(schema.create_floating_ips_bulk, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_floating_ips_bulk(self): - """Gets all floating IPs in bulk.""" - resp, body = self.get('os-floating-ips-bulk') - body = json.loads(body) - self.validate_response(schema.list_floating_ips_bulk, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_floating_ips_bulk(self, ip_range): - """Deletes the provided floating IPs in bulk.""" - post_body = json.dumps({'ip_range': ip_range}) - resp, body = self.put('os-floating-ips-bulk/delete', post_body) - body = json.loads(body) - self.validate_response(schema.delete_floating_ips_bulk, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/floating_ips_client.py b/tempest/lib/services/compute/floating_ips_client.py deleted file mode 100644 index 5364d971f..000000000 --- a/tempest/lib/services/compute/floating_ips_client.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import floating_ips as schema -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.compute import base_compute_client - - -class FloatingIPsClient(base_compute_client.BaseComputeClient): - - def list_floating_ips(self, **params): - """Returns a list of all floating IPs filtered by any parameters. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-floating-ip-addresses - """ - url = 'os-floating-ips' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.list_floating_ips, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_floating_ip(self, floating_ip_id): - """Get the details of a floating IP. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#show-floating-ip-address-details - """ - url = "os-floating-ips/%s" % floating_ip_id - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.create_get_floating_ip, resp, body) - return rest_client.ResponseBody(resp, body) - - def create_floating_ip(self, **kwargs): - """Allocate a floating IP to the project. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-allocate-floating-ip-address - """ - url = 'os-floating-ips' - post_body = json.dumps(kwargs) - resp, body = self.post(url, post_body) - body = json.loads(body) - self.validate_response(schema.create_get_floating_ip, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_floating_ip(self, floating_ip_id): - """Deletes the provided floating IP from the project. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#delete-deallocate-floating-ip-address - """ - url = "os-floating-ips/%s" % floating_ip_id - resp, body = self.delete(url) - self.validate_response(schema.add_remove_floating_ip, resp, body) - return rest_client.ResponseBody(resp, body) - - def associate_floating_ip_to_server(self, floating_ip, server_id): - """Associate the provided floating IP to a specific server.""" - url = "servers/%s/action" % server_id - post_body = { - 'addFloatingIp': { - 'address': floating_ip, - } - } - - post_body = json.dumps(post_body) - resp, body = self.post(url, post_body) - self.validate_response(schema.add_remove_floating_ip, resp, body) - return rest_client.ResponseBody(resp, body) - - def disassociate_floating_ip_from_server(self, floating_ip, server_id): - """Disassociate the provided floating IP from a specific server.""" - url = "servers/%s/action" % server_id - post_body = { - 'removeFloatingIp': { - 'address': floating_ip, - } - } - - post_body = json.dumps(post_body) - resp, body = self.post(url, post_body) - self.validate_response(schema.add_remove_floating_ip, resp, body) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_floating_ip(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'floating_ip' diff --git a/tempest/lib/services/compute/hosts_client.py b/tempest/lib/services/compute/hosts_client.py deleted file mode 100644 index 1fdd9075c..000000000 --- a/tempest/lib/services/compute/hosts_client.py +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import hosts as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class HostsClient(base_compute_client.BaseComputeClient): - - def list_hosts(self, **params): - """List all hosts. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-hosts - """ - - url = 'os-hosts' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.list_hosts, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_host(self, hostname): - """Show detail information for the host.""" - - resp, body = self.get("os-hosts/%s" % hostname) - body = json.loads(body) - self.validate_response(schema.get_host_detail, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_host(self, hostname, **kwargs): - """Update a host. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#update-host-status - """ - - request_body = { - 'status': None, - 'maintenance_mode': None, - } - request_body.update(**kwargs) - request_body = json.dumps(request_body) - - resp, body = self.put("os-hosts/%s" % hostname, request_body) - body = json.loads(body) - self.validate_response(schema.update_host, resp, body) - return rest_client.ResponseBody(resp, body) - - def startup_host(self, hostname): # noqa - # NOTE: This noqa is for passing T110 check and we cannot rename - # to keep backwards compatibility. Actually, the root problem - # of this is a wrong API design. GET operation should not change - # resource status, but current API does that. - """Startup a host.""" - - resp, body = self.get("os-hosts/%s/startup" % hostname) - body = json.loads(body) - self.validate_response(schema.startup_host, resp, body) - return rest_client.ResponseBody(resp, body) - - def shutdown_host(self, hostname): # noqa - # NOTE: This noqa is for passing T110 check and we cannot rename - # to keep backwards compatibility. Actually, the root problem - # of this is a wrong API design. GET operation should not change - # resource status, but current API does that. - """Shutdown a host.""" - - resp, body = self.get("os-hosts/%s/shutdown" % hostname) - body = json.loads(body) - self.validate_response(schema.shutdown_host, resp, body) - return rest_client.ResponseBody(resp, body) - - def reboot_host(self, hostname): # noqa - # NOTE: This noqa is for passing T110 check and we cannot rename - # to keep backwards compatibility. Actually, the root problem - # of this is a wrong API design. GET operation should not change - # resource status, but current API does that. - """Reboot a host.""" - - resp, body = self.get("os-hosts/%s/reboot" % hostname) - body = json.loads(body) - self.validate_response(schema.reboot_host, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/hypervisor_client.py b/tempest/lib/services/compute/hypervisor_client.py deleted file mode 100644 index 23c304e83..000000000 --- a/tempest/lib/services/compute/hypervisor_client.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2013 IBM Corporation. -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import hypervisors as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class HypervisorClient(base_compute_client.BaseComputeClient): - - def list_hypervisors(self, detail=False): - """List hypervisors information.""" - url = 'os-hypervisors' - _schema = schema.list_search_hypervisors - if detail: - url += '/detail' - _schema = schema.list_hypervisors_detail - - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(_schema, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_hypervisor(self, hypervisor_id): - """Display the details of the specified hypervisor.""" - resp, body = self.get('os-hypervisors/%s' % hypervisor_id) - body = json.loads(body) - self.validate_response(schema.get_hypervisor, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_servers_on_hypervisor(self, hypervisor_name): - """List instances belonging to the specified hypervisor.""" - resp, body = self.get('os-hypervisors/%s/servers' % hypervisor_name) - body = json.loads(body) - self.validate_response(schema.get_hypervisors_servers, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_hypervisor_statistics(self): - """Get hypervisor statistics over all compute nodes.""" - resp, body = self.get('os-hypervisors/statistics') - body = json.loads(body) - self.validate_response(schema.get_hypervisor_statistics, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_hypervisor_uptime(self, hypervisor_id): - """Display the uptime of the specified hypervisor.""" - resp, body = self.get('os-hypervisors/%s/uptime' % hypervisor_id) - body = json.loads(body) - self.validate_response(schema.get_hypervisor_uptime, resp, body) - return rest_client.ResponseBody(resp, body) - - def search_hypervisor(self, hypervisor_name): # noqa - # NOTE: This noqa is for passing T110 check and we cannot rename - # to keep backwards compatibility. - """Search specified hypervisor.""" - resp, body = self.get('os-hypervisors/%s/search' % hypervisor_name) - body = json.loads(body) - self.validate_response(schema.list_search_hypervisors, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/images_client.py b/tempest/lib/services/compute/images_client.py deleted file mode 100644 index 86bea9e7f..000000000 --- a/tempest/lib/services/compute/images_client.py +++ /dev/null @@ -1,150 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import images as schema -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.compute import base_compute_client - - -class ImagesClient(base_compute_client.BaseComputeClient): - - def create_image(self, server_id, **kwargs): - """Create an image of the original server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-image-createimage-action - """ - - post_body = {'createImage': kwargs} - post_body = json.dumps(post_body) - resp, body = self.post('servers/%s/action' % server_id, - post_body) - self.validate_response(schema.create_image, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_images(self, detail=False, **params): - """Return a list of all images filtered by any parameter. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-images - https://developer.openstack.org/api-ref/compute/#list-images-with-details - """ - url = 'images' - _schema = schema.list_images - if detail: - url += '/detail' - _schema = schema.list_images_details - - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(_schema, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_image(self, image_id): - """Return the details of a single image.""" - resp, body = self.get("images/%s" % image_id) - body = json.loads(body) - self.validate_response(schema.get_image, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_image(self, image_id): - """Delete the provided image.""" - resp, body = self.delete("images/%s" % image_id) - self.validate_response(schema.delete, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_image_metadata(self, image_id): - """List all metadata items for an image.""" - resp, body = self.get("images/%s/metadata" % image_id) - body = json.loads(body) - self.validate_response(schema.image_metadata, resp, body) - return rest_client.ResponseBody(resp, body) - - def set_image_metadata(self, image_id, meta): - """Set the metadata for an image. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#update-image-metadata - """ - post_body = json.dumps({'metadata': meta}) - resp, body = self.put('images/%s/metadata' % image_id, post_body) - body = json.loads(body) - self.validate_response(schema.image_metadata, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_image_metadata(self, image_id, meta): - """Update the metadata for an image. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-image-metadata - """ - post_body = json.dumps({'metadata': meta}) - resp, body = self.post('images/%s/metadata' % image_id, post_body) - body = json.loads(body) - self.validate_response(schema.image_metadata, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_image_metadata_item(self, image_id, key): - """Return the value for a specific image metadata key.""" - resp, body = self.get("images/%s/metadata/%s" % (image_id, key)) - body = json.loads(body) - self.validate_response(schema.image_meta_item, resp, body) - return rest_client.ResponseBody(resp, body) - - def set_image_metadata_item(self, image_id, key, meta): - """Set the value for a specific image metadata key. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-or-update-image-metadata-item - """ - post_body = json.dumps({'meta': meta}) - resp, body = self.put('images/%s/metadata/%s' % (image_id, key), - post_body) - body = json.loads(body) - self.validate_response(schema.image_meta_item, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_image_metadata_item(self, image_id, key): - """Delete a single image metadata key/value pair.""" - resp, body = self.delete("images/%s/metadata/%s" % - (image_id, key)) - self.validate_response(schema.delete, resp, body) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - # Added status check for user with admin role - try: - if self.show_image(id)['image']['status'] == 'DELETED': - return True - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Return the primary type of resource this client works with.""" - return 'image' diff --git a/tempest/lib/services/compute/instance_usage_audit_log_client.py b/tempest/lib/services/compute/instance_usage_audit_log_client.py deleted file mode 100644 index 1b9430683..000000000 --- a/tempest/lib/services/compute/instance_usage_audit_log_client.py +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2013 IBM Corporation -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import \ - instance_usage_audit_logs as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class InstanceUsagesAuditLogClient(base_compute_client.BaseComputeClient): - - def list_instance_usage_audit_logs(self): - url = 'os-instance_usage_audit_log' - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.list_instance_usage_audit_log, - resp, body) - return rest_client.ResponseBody(resp, body) - - def show_instance_usage_audit_log(self, time_before): - url = 'os-instance_usage_audit_log/%s' % time_before - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.get_instance_usage_audit_log, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/interfaces_client.py b/tempest/lib/services/compute/interfaces_client.py deleted file mode 100644 index d7c3107d2..000000000 --- a/tempest/lib/services/compute/interfaces_client.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2013 IBM 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 oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import interfaces as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class InterfacesClient(base_compute_client.BaseComputeClient): - - def list_interfaces(self, server_id): - resp, body = self.get('servers/%s/os-interface' % server_id) - body = json.loads(body) - self.validate_response(schema.list_interfaces, resp, body) - return rest_client.ResponseBody(resp, body) - - def create_interface(self, server_id, **kwargs): - """Create an interface. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-interface - """ - post_body = {'interfaceAttachment': kwargs} - post_body = json.dumps(post_body) - resp, body = self.post('servers/%s/os-interface' % server_id, - body=post_body) - body = json.loads(body) - self.validate_response(schema.get_create_interfaces, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_interface(self, server_id, port_id): - resp, body = self.get('servers/%s/os-interface/%s' % (server_id, - port_id)) - body = json.loads(body) - self.validate_response(schema.get_create_interfaces, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_interface(self, server_id, port_id): - resp, body = self.delete('servers/%s/os-interface/%s' % (server_id, - port_id)) - self.validate_response(schema.delete_interface, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/keypairs_client.py b/tempest/lib/services/compute/keypairs_client.py deleted file mode 100644 index 5215fcadc..000000000 --- a/tempest/lib/services/compute/keypairs_client.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import keypairs as schemav21 -from tempest.lib.api_schema.response.compute.v2_2 import keypairs as schemav22 -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class KeyPairsClient(base_compute_client.BaseComputeClient): - - schema_versions_info = [{'min': None, 'max': '2.1', 'schema': schemav21}, - {'min': '2.2', 'max': None, 'schema': schemav22}] - - def list_keypairs(self, **params): - """Lists keypairs that are associated with the account. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-keypairs - """ - url = 'os-keypairs' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.list_keypairs, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_keypair(self, keypair_name, **params): - """Shows details for a keypair that is associated with the account. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#show-keypair-details - """ - url = "os-keypairs/%s" % keypair_name - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.get_keypair, resp, body) - return rest_client.ResponseBody(resp, body) - - def create_keypair(self, **kwargs): - """Create a keypair. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-or-import-keypair - """ - post_body = json.dumps({'keypair': kwargs}) - resp, body = self.post("os-keypairs", body=post_body) - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.create_keypair, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_keypair(self, keypair_name, **params): - """Deletes a keypair. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#delete-keypair - """ - url = "os-keypairs/%s" % keypair_name - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.delete(url) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.delete_keypair, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/limits_client.py b/tempest/lib/services/compute/limits_client.py deleted file mode 100644 index efe98897e..000000000 --- a/tempest/lib/services/compute/limits_client.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import limits as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class LimitsClient(base_compute_client.BaseComputeClient): - - def show_limits(self): - resp, body = self.get("limits") - body = json.loads(body) - self.validate_response(schema.get_limit, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/migrations_client.py b/tempest/lib/services/compute/migrations_client.py deleted file mode 100644 index 68c8f3f4d..000000000 --- a/tempest/lib/services/compute/migrations_client.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2014 NEC Corporation. -# -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import migrations as schema -from tempest.lib.api_schema.response.compute.v2_23 import migrations \ - as schemav223 -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class MigrationsClient(base_compute_client.BaseComputeClient): - schema_versions_info = [ - {'min': None, 'max': '2.22', 'schema': schema}, - {'min': '2.23', 'max': None, 'schema': schemav223}] - - def list_migrations(self, **params): - """List all migrations. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-migrations - """ - - url = 'os-migrations' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.list_migrations, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/networks_client.py b/tempest/lib/services/compute/networks_client.py deleted file mode 100644 index 6c8c943e4..000000000 --- a/tempest/lib/services/compute/networks_client.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class NetworksClient(base_compute_client.BaseComputeClient): - - def list_networks(self): - resp, body = self.get("os-networks") - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_network(self, network_id): - resp, body = self.get("os-networks/%s" % network_id) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/quota_classes_client.py b/tempest/lib/services/compute/quota_classes_client.py deleted file mode 100644 index 0fe9868f3..000000000 --- a/tempest/lib/services/compute/quota_classes_client.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2012 NTT Data -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1\ - import quota_classes as classes_schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class QuotaClassesClient(base_compute_client.BaseComputeClient): - - def show_quota_class_set(self, quota_class_id): - """List the quota class set for a quota class.""" - - url = 'os-quota-class-sets/%s' % quota_class_id - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(classes_schema.get_quota_class_set, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_quota_class_set(self, quota_class_id, **kwargs): - """Update the quota class's limits for one or more resources. - - # NOTE: Current api-site doesn't contain this API description. - # LP: https://bugs.launchpad.net/nova/+bug/1602400 - """ - post_body = json.dumps({'quota_class_set': kwargs}) - - resp, body = self.put('os-quota-class-sets/%s' % quota_class_id, - post_body) - - body = json.loads(body) - self.validate_response(classes_schema.update_quota_class_set, - resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/quotas_client.py b/tempest/lib/services/compute/quotas_client.py deleted file mode 100644 index daf4bc09c..000000000 --- a/tempest/lib/services/compute/quotas_client.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright 2012 NTT Data -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import quotas as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class QuotasClient(base_compute_client.BaseComputeClient): - - def show_quota_set(self, tenant_id, user_id=None, detail=False): - """List the quota set for a tenant. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref-compute-v2.1.html/#show-a-quota - http://developer.openstack.org/api-ref-compute-v2.1.html/#show-the-detail-of-quota - """ - - params = {} - url = 'os-quota-sets/%s' % tenant_id - if detail: - url += '/detail' - if user_id: - params.update({'user_id': user_id}) - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - body = json.loads(body) - if detail: - self.validate_response(schema.get_quota_set_details, resp, body) - else: - self.validate_response(schema.get_quota_set, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_default_quota_set(self, tenant_id): - """List the default quota set for a tenant.""" - - url = 'os-quota-sets/%s/defaults' % tenant_id - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.get_quota_set, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_quota_set(self, tenant_id, user_id=None, **kwargs): - """Updates the tenant's quota limits for one or more resources. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#update-quotas - """ - - post_body = json.dumps({'quota_set': kwargs}) - - if user_id: - resp, body = self.put('os-quota-sets/%s?user_id=%s' % - (tenant_id, user_id), post_body) - else: - resp, body = self.put('os-quota-sets/%s' % tenant_id, - post_body) - - body = json.loads(body) - self.validate_response(schema.update_quota_set, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_quota_set(self, tenant_id): - """Delete the tenant's quota set.""" - resp, body = self.delete('os-quota-sets/%s' % tenant_id) - self.validate_response(schema.delete_quota, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/security_group_default_rules_client.py b/tempest/lib/services/compute/security_group_default_rules_client.py deleted file mode 100644 index 70cab88e6..000000000 --- a/tempest/lib/services/compute/security_group_default_rules_client.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2014 NEC Corporation. -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import \ - security_group_default_rule as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class SecurityGroupDefaultRulesClient(base_compute_client.BaseComputeClient): - - def create_security_default_group_rule(self, **kwargs): - """Create security group default rule. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-default-security-group-rule - """ - post_body = json.dumps({'security_group_default_rule': kwargs}) - url = 'os-security-group-default-rules' - resp, body = self.post(url, post_body) - body = json.loads(body) - self.validate_response(schema.create_get_security_group_default_rule, - resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_security_group_default_rule(self, - security_group_default_rule_id): - """Delete the provided Security Group default rule.""" - resp, body = self.delete('os-security-group-default-rules/%s' % ( - security_group_default_rule_id)) - self.validate_response(schema.delete_security_group_default_rule, - resp, body) - return rest_client.ResponseBody(resp, body) - - def list_security_group_default_rules(self): - """List all Security Group default rules.""" - resp, body = self.get('os-security-group-default-rules') - body = json.loads(body) - self.validate_response(schema.list_security_group_default_rules, - resp, body) - return rest_client.ResponseBody(resp, body) - - def show_security_group_default_rule(self, security_group_default_rule_id): - """Return the details of provided Security Group default rule.""" - resp, body = self.get('os-security-group-default-rules/%s' % - security_group_default_rule_id) - body = json.loads(body) - self.validate_response(schema.create_get_security_group_default_rule, - resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/security_group_rules_client.py b/tempest/lib/services/compute/security_group_rules_client.py deleted file mode 100644 index 710bfab4e..000000000 --- a/tempest/lib/services/compute/security_group_rules_client.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import \ - security_groups as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class SecurityGroupRulesClient(base_compute_client.BaseComputeClient): - - def create_security_group_rule(self, **kwargs): - """Create a new security group rule. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-security-group-rule - """ - post_body = json.dumps({'security_group_rule': kwargs}) - url = 'os-security-group-rules' - resp, body = self.post(url, post_body) - body = json.loads(body) - self.validate_response(schema.create_security_group_rule, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_security_group_rule(self, group_rule_id): - """Deletes the provided Security Group rule.""" - resp, body = self.delete('os-security-group-rules/%s' % - group_rule_id) - self.validate_response(schema.delete_security_group_rule, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/security_groups_client.py b/tempest/lib/services/compute/security_groups_client.py deleted file mode 100644 index b525f6861..000000000 --- a/tempest/lib/services/compute/security_groups_client.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import \ - security_groups as schema -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.compute import base_compute_client - - -class SecurityGroupsClient(base_compute_client.BaseComputeClient): - - def list_security_groups(self, **params): - """List all security groups for a user. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-security-groups - """ - - url = 'os-security-groups' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.list_security_groups, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_security_group(self, security_group_id): - """Get the details of a Security Group. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#show-security-group-details - """ - url = "os-security-groups/%s" % security_group_id - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.get_security_group, resp, body) - return rest_client.ResponseBody(resp, body) - - def create_security_group(self, **kwargs): - """Create a new security group. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-security-group - """ - post_body = json.dumps({'security_group': kwargs}) - resp, body = self.post('os-security-groups', post_body) - body = json.loads(body) - self.validate_response(schema.get_security_group, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_security_group(self, security_group_id, **kwargs): - """Update a security group. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#update-security-group - """ - post_body = json.dumps({'security_group': kwargs}) - resp, body = self.put('os-security-groups/%s' % security_group_id, - post_body) - body = json.loads(body) - self.validate_response(schema.update_security_group, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_security_group(self, security_group_id): - """Delete the provided Security Group. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#delete-security-group - """ - resp, body = self.delete( - 'os-security-groups/%s' % security_group_id) - self.validate_response(schema.delete_security_group, resp, body) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_security_group(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Return the primary type of resource this client works with.""" - return 'security_group' diff --git a/tempest/lib/services/compute/server_groups_client.py b/tempest/lib/services/compute/server_groups_client.py deleted file mode 100644 index 03cd645cd..000000000 --- a/tempest/lib/services/compute/server_groups_client.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# Copyright 2013 Hewlett-Packard Development Company, L.P. -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import servers as schema -from tempest.lib.api_schema.response.compute.v2_13 import servers as schemav213 -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class ServerGroupsClient(base_compute_client.BaseComputeClient): - - schema_versions_info = [ - {'min': None, 'max': '2.12', 'schema': schema}, - {'min': '2.13', 'max': None, 'schema': schemav213}] - - def create_server_group(self, **kwargs): - """Create the server group. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-server-group - """ - post_body = json.dumps({'server_group': kwargs}) - resp, body = self.post('os-server-groups', post_body) - - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.create_show_server_group, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_server_group(self, server_group_id): - """Delete the given server-group.""" - resp, body = self.delete("os-server-groups/%s" % server_group_id) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.delete_server_group, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_server_groups(self): - """List the server-groups.""" - resp, body = self.get("os-server-groups") - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.list_server_groups, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_server_group(self, server_group_id): - """Get the details of given server_group.""" - resp, body = self.get("os-server-groups/%s" % server_group_id) - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.create_show_server_group, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/servers_client.py b/tempest/lib/services/compute/servers_client.py deleted file mode 100644 index 598d5a63e..000000000 --- a/tempest/lib/services/compute/servers_client.py +++ /dev/null @@ -1,864 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# Copyright 2013 Hewlett-Packard Development Company, L.P. -# Copyright 2017 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 copy - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import \ - security_groups as security_groups_schema -from tempest.lib.api_schema.response.compute.v2_1 import servers as schema -from tempest.lib.api_schema.response.compute.v2_16 import servers as schemav216 -from tempest.lib.api_schema.response.compute.v2_19 import servers as schemav219 -from tempest.lib.api_schema.response.compute.v2_26 import servers as schemav226 -from tempest.lib.api_schema.response.compute.v2_3 import servers as schemav23 -from tempest.lib.api_schema.response.compute.v2_47 import servers as schemav247 -from tempest.lib.api_schema.response.compute.v2_48 import servers as schemav248 -from tempest.lib.api_schema.response.compute.v2_6 import servers as schemav26 -from tempest.lib.api_schema.response.compute.v2_9 import servers as schemav29 -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class ServersClient(base_compute_client.BaseComputeClient): - """Service client for the resource /servers""" - - schema_versions_info = [ - {'min': None, 'max': '2.2', 'schema': schema}, - {'min': '2.3', 'max': '2.5', 'schema': schemav23}, - {'min': '2.6', 'max': '2.8', 'schema': schemav26}, - {'min': '2.9', 'max': '2.15', 'schema': schemav29}, - {'min': '2.16', 'max': '2.18', 'schema': schemav216}, - {'min': '2.19', 'max': '2.25', 'schema': schemav219}, - {'min': '2.26', 'max': '2.46', 'schema': schemav226}, - {'min': '2.47', 'max': '2.47', 'schema': schemav247}, - {'min': '2.48', 'max': None, 'schema': schemav248}] - - def __init__(self, auth_provider, service, region, - enable_instance_password=True, **kwargs): - super(ServersClient, self).__init__( - auth_provider, service, region, **kwargs) - self.enable_instance_password = enable_instance_password - - def create_server(self, **kwargs): - """Create server. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/compute/#create-server - - :param name: Server name - :param imageRef: Image reference (UUID) - :param flavorRef: Flavor reference (UUID or full URL) - - Most parameters except the following are passed to the API without - any changes. - :param disk_config: The name is changed to OS-DCF:diskConfig - :param scheduler_hints: The name is changed to os:scheduler_hints and - the parameter is set in the same level as the parameter 'server'. - """ - body = copy.deepcopy(kwargs) - if body.get('disk_config'): - body['OS-DCF:diskConfig'] = body.pop('disk_config') - - hints = None - if body.get('scheduler_hints'): - hints = {'os:scheduler_hints': body.pop('scheduler_hints')} - - post_body = {'server': body} - - if hints: - post_body.update(hints) - - post_body = json.dumps(post_body) - resp, body = self.post('servers', post_body) - - body = json.loads(body) - # NOTE(maurosr): this deals with the case of multiple server create - # with return reservation id set True - if 'reservation_id' in body: - return rest_client.ResponseBody(resp, body) - if self.enable_instance_password: - create_schema = schema.create_server_with_admin_pass - else: - create_schema = schema.create_server - self.validate_response(create_schema, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_server(self, server_id, **kwargs): - """Update server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#update-server - - Most parameters except the following are passed to the API without - any changes. - :param disk_config: The name is changed to OS-DCF:diskConfig - """ - if 'disk_config' in kwargs: - kwargs['OS-DCF:diskConfig'] = kwargs.pop('disk_config') - - post_body = json.dumps({'server': kwargs}) - resp, body = self.put("servers/%s" % server_id, post_body) - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.update_server, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_server(self, server_id): - """Get server details. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref-compute-v2.1.html#showServer - """ - resp, body = self.get("servers/%s" % server_id) - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.get_server, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_server(self, server_id): - """Delete server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#delete-server - """ - resp, body = self.delete("servers/%s" % server_id) - self.validate_response(schema.delete_server, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_servers(self, detail=False, **params): - """List servers. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-servers - https://developer.openstack.org/api-ref/compute/#list-servers-detailed - """ - - url = 'servers' - schema = self.get_schema(self.schema_versions_info) - _schema = schema.list_servers - - if detail: - url += '/detail' - _schema = schema.list_servers_detail - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(_schema, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_addresses(self, server_id): - """Lists all addresses for a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-ips - """ - resp, body = self.get("servers/%s/ips" % server_id) - body = json.loads(body) - self.validate_response(schema.list_addresses, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_addresses_by_network(self, server_id, network_id): - """Lists all addresses of a specific network type for a server.""" - resp, body = self.get("servers/%s/ips/%s" % - (server_id, network_id)) - body = json.loads(body) - self.validate_response(schema.list_addresses_by_network, resp, body) - return rest_client.ResponseBody(resp, body) - - def action(self, server_id, action_name, - schema=schema.server_actions_common_schema, - **kwargs): - post_body = json.dumps({action_name: kwargs}) - resp, body = self.post('servers/%s/action' % server_id, - post_body) - if body: - body = json.loads(body) - self.validate_response(schema, resp, body) - return rest_client.ResponseBody(resp, body) - - def create_backup(self, server_id, **kwargs): - """Backup a server instance. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-server-back-up-createbackup-action - """ - return self.action(server_id, "createBackup", **kwargs) - - def change_password(self, server_id, **kwargs): - """Change the root password for the server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#change-administrative-password-changepassword-action - """ - return self.action(server_id, 'changePassword', **kwargs) - - def show_password(self, server_id): - resp, body = self.get("servers/%s/os-server-password" % - server_id) - body = json.loads(body) - self.validate_response(schema.show_password, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_password(self, server_id): - """Removes the encrypted server password from the metadata server - - Note that this does not actually change the instance server - password. - """ - resp, body = self.delete("servers/%s/os-server-password" % - server_id) - self.validate_response(schema.server_actions_delete_password, - resp, body) - return rest_client.ResponseBody(resp, body) - - def reboot_server(self, server_id, **kwargs): - """Reboot a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#reboot-server-reboot-action - """ - return self.action(server_id, 'reboot', **kwargs) - - def rebuild_server(self, server_id, image_ref, **kwargs): - """Rebuild a server with a new image. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#rebuild-server-rebuild-action - - Most parameters except the following are passed to the API without - any changes. - :param disk_config: The name is changed to OS-DCF:diskConfig - """ - kwargs['imageRef'] = image_ref - if 'disk_config' in kwargs: - kwargs['OS-DCF:diskConfig'] = kwargs.pop('disk_config') - schema = self.get_schema(self.schema_versions_info) - if self.enable_instance_password: - rebuild_schema = schema.rebuild_server_with_admin_pass - else: - rebuild_schema = schema.rebuild_server - return self.action(server_id, 'rebuild', - rebuild_schema, **kwargs) - - def resize_server(self, server_id, flavor_ref, **kwargs): - """Change the flavor of a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#resize-server-resize-action - - Most parameters except the following are passed to the API without - any changes. - :param disk_config: The name is changed to OS-DCF:diskConfig - """ - kwargs['flavorRef'] = flavor_ref - if 'disk_config' in kwargs: - kwargs['OS-DCF:diskConfig'] = kwargs.pop('disk_config') - return self.action(server_id, 'resize', **kwargs) - - def confirm_resize_server(self, server_id, **kwargs): - """Confirm the flavor change for a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#confirm-resized-server-confirmresize-action - """ - return self.action(server_id, 'confirmResize', - schema.server_actions_confirm_resize, - **kwargs) - - def revert_resize_server(self, server_id, **kwargs): - """Revert a server back to its original flavor. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#revert-resized-server-revertresize-action - """ - return self.action(server_id, 'revertResize', **kwargs) - - def list_server_metadata(self, server_id): - """Lists all metadata for a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-all-metadata - """ - resp, body = self.get("servers/%s/metadata" % server_id) - body = json.loads(body) - self.validate_response(schema.list_server_metadata, resp, body) - return rest_client.ResponseBody(resp, body) - - def set_server_metadata(self, server_id, meta, no_metadata_field=False): - """Sets one or more metadata items for a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-or-replace-metadata-items - """ - if no_metadata_field: - post_body = "" - else: - post_body = json.dumps({'metadata': meta}) - resp, body = self.put('servers/%s/metadata' % server_id, - post_body) - body = json.loads(body) - self.validate_response(schema.set_server_metadata, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_server_metadata(self, server_id, meta): - """Updates one or more metadata items for a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#update-metadata-items - """ - post_body = json.dumps({'metadata': meta}) - resp, body = self.post('servers/%s/metadata' % server_id, - post_body) - body = json.loads(body) - self.validate_response(schema.update_server_metadata, - resp, body) - return rest_client.ResponseBody(resp, body) - - def show_server_metadata_item(self, server_id, key): - """Shows details for a metadata item, by key, for a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#show-metadata-item-details - """ - resp, body = self.get("servers/%s/metadata/%s" % (server_id, key)) - body = json.loads(body) - self.validate_response(schema.set_show_server_metadata_item, - resp, body) - return rest_client.ResponseBody(resp, body) - - def set_server_metadata_item(self, server_id, key, meta): - """Sets a metadata item, by key, for a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-or-update-metadata-item - """ - post_body = json.dumps({'meta': meta}) - resp, body = self.put('servers/%s/metadata/%s' % (server_id, key), - post_body) - body = json.loads(body) - self.validate_response(schema.set_show_server_metadata_item, - resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_server_metadata_item(self, server_id, key): - """Deletes a metadata item, by key, from a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#delete-metadata-item - """ - resp, body = self.delete("servers/%s/metadata/%s" % - (server_id, key)) - self.validate_response(schema.delete_server_metadata_item, - resp, body) - return rest_client.ResponseBody(resp, body) - - def stop_server(self, server_id, **kwargs): - """Stops a running server and changes its status to SHUTOFF. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#stop-server-os-stop-action - """ - return self.action(server_id, 'os-stop', **kwargs) - - def start_server(self, server_id, **kwargs): - """Starts a stopped server and changes its status to ACTIVE. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#start-server-os-start-action - """ - return self.action(server_id, 'os-start', **kwargs) - - def attach_volume(self, server_id, **kwargs): - """Attaches a volume to a server instance. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#attach-a-volume-to-an-instance - """ - post_body = json.dumps({'volumeAttachment': kwargs}) - resp, body = self.post('servers/%s/os-volume_attachments' % server_id, - post_body) - body = json.loads(body) - self.validate_response(schema.attach_volume, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_attached_volume(self, server_id, attachment_id, **kwargs): - """Swaps a volume attached to an instance for another volume""" - post_body = json.dumps({'volumeAttachment': kwargs}) - resp, body = self.put('servers/%s/os-volume_attachments/%s' % - (server_id, attachment_id), - post_body) - self.validate_response(schema.update_attached_volume, resp, body) - return rest_client.ResponseBody(resp, body) - - def detach_volume(self, server_id, volume_id): # noqa - """Detaches a volume from a server instance. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#detach-a-volume-from-an-instance - """ - resp, body = self.delete('servers/%s/os-volume_attachments/%s' % - (server_id, volume_id)) - self.validate_response(schema.detach_volume, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_volume_attachment(self, server_id, volume_id): - """Return details about the given volume attachment. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#show-a-detail-of-a-volume-attachment - """ - resp, body = self.get('servers/%s/os-volume_attachments/%s' % ( - server_id, volume_id)) - body = json.loads(body) - self.validate_response(schema.show_volume_attachment, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_volume_attachments(self, server_id): - """Returns the list of volume attachments for a given instance. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-volume-attachments-for-an-instance - """ - resp, body = self.get('servers/%s/os-volume_attachments' % ( - server_id)) - body = json.loads(body) - self.validate_response(schema.list_volume_attachments, resp, body) - return rest_client.ResponseBody(resp, body) - - def add_security_group(self, server_id, **kwargs): - """Add a security group to the server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#add-security-group-to-a-server-addsecuritygroup-action - """ - return self.action(server_id, 'addSecurityGroup', **kwargs) - - def remove_security_group(self, server_id, **kwargs): - """Remove a security group from the server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#remove-security-group-from-a-server-removesecuritygroup-action - """ - return self.action(server_id, 'removeSecurityGroup', **kwargs) - - def live_migrate_server(self, server_id, **kwargs): - """This should be called with administrator privileges. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#live-migrate-server-os-migratelive-action - """ - return self.action(server_id, 'os-migrateLive', **kwargs) - - def migrate_server(self, server_id, **kwargs): - """Migrate a server to a new host. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#migrate-server-migrate-action - """ - return self.action(server_id, 'migrate', **kwargs) - - def lock_server(self, server_id, **kwargs): - """Lock the given server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#lock-server-lock-action - """ - return self.action(server_id, 'lock', **kwargs) - - def unlock_server(self, server_id, **kwargs): - """UNlock the given server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#unlock-server-unlock-action - """ - return self.action(server_id, 'unlock', **kwargs) - - def suspend_server(self, server_id, **kwargs): - """Suspend the provided server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#suspend-server-suspend-action - """ - return self.action(server_id, 'suspend', **kwargs) - - def resume_server(self, server_id, **kwargs): - """Un-suspend the provided server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#resume-suspended-server-resume-action - """ - return self.action(server_id, 'resume', **kwargs) - - def pause_server(self, server_id, **kwargs): - """Pause the provided server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#pause-server-pause-action - """ - return self.action(server_id, 'pause', **kwargs) - - def unpause_server(self, server_id, **kwargs): - """Un-pause the provided server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#unpause-server-unpause-action - """ - return self.action(server_id, 'unpause', **kwargs) - - def reset_state(self, server_id, **kwargs): - """Reset the state of a server to active/error. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#reset-server-state-os-resetstate-action - """ - return self.action(server_id, 'os-resetState', **kwargs) - - def shelve_server(self, server_id, **kwargs): - """Shelve the provided server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#shelve-server-shelve-action - """ - return self.action(server_id, 'shelve', **kwargs) - - def unshelve_server(self, server_id, **kwargs): - """Un-shelve the provided server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#unshelve-restore-shelved-server-unshelve-action - """ - return self.action(server_id, 'unshelve', **kwargs) - - def shelve_offload_server(self, server_id, **kwargs): - """Shelve-offload the provided server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#shelf-offload-remove-server-shelveoffload-action - """ - return self.action(server_id, 'shelveOffload', **kwargs) - - def get_console_output(self, server_id, **kwargs): - """Get console output. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#show-console-output-os-getconsoleoutput-action - """ - return self.action(server_id, 'os-getConsoleOutput', - schema.get_console_output, **kwargs) - - def get_remote_console(self, server_id, console_type, protocol, **kwargs): - """Get a remote console. - - For a full list of available parameters, please refer to the official - API reference: - TODO (markus_z) The api-ref for that isn't yet available, update this - here when the docs in Nova are updated. The old API is at - http://developer.openstack.org/api-ref/compute/#get-serial-console-os-getserialconsole-action - """ - param = { - 'remote_console': { - 'type': console_type, - 'protocol': protocol, - } - } - post_body = json.dumps(param) - resp, body = self.post("servers/%s/remote-consoles" % server_id, - post_body) - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.get_remote_consoles, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_virtual_interfaces(self, server_id): - """List the virtual interfaces used in an instance.""" - resp, body = self.get('/'.join(['servers', server_id, - 'os-virtual-interfaces'])) - body = json.loads(body) - self.validate_response(schema.list_virtual_interfaces, resp, body) - return rest_client.ResponseBody(resp, body) - - def rescue_server(self, server_id, **kwargs): - """Rescue the provided server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#rescue-server-rescue-action - """ - if self.enable_instance_password: - rescue_schema = schema.rescue_server_with_admin_pass - else: - rescue_schema = schema.rescue_server - return self.action(server_id, 'rescue', rescue_schema, **kwargs) - - def unrescue_server(self, server_id): - """Unrescue the provided server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#unrescue-server-unrescue-action - """ - return self.action(server_id, 'unrescue') - - def show_server_diagnostics(self, server_id): - """Get the usage data for a server.""" - resp, body = self.get("servers/%s/diagnostics" % server_id) - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.show_server_diagnostics, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_instance_actions(self, server_id): - """List the provided server action.""" - resp, body = self.get("servers/%s/os-instance-actions" % - server_id) - body = json.loads(body) - self.validate_response(schema.list_instance_actions, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_instance_action(self, server_id, request_id): - """Returns the action details of the provided server.""" - resp, body = self.get("servers/%s/os-instance-actions/%s" % - (server_id, request_id)) - body = json.loads(body) - self.validate_response(schema.show_instance_action, resp, body) - return rest_client.ResponseBody(resp, body) - - def force_delete_server(self, server_id, **kwargs): - """Force delete a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#force-delete-server-forcedelete-action - """ - return self.action(server_id, 'forceDelete', **kwargs) - - def restore_soft_deleted_server(self, server_id, **kwargs): - """Restore a soft-deleted server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#restore-soft-deleted-instance-restore-action - """ - return self.action(server_id, 'restore', **kwargs) - - def reset_network(self, server_id, **kwargs): - """Reset the Network of a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#reset-networking-on-a-server-resetnetwork-action - """ - return self.action(server_id, 'resetNetwork', **kwargs) - - def inject_network_info(self, server_id, **kwargs): - """Inject the Network Info into server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#inject-network-information-injectnetworkinfo-action - """ - return self.action(server_id, 'injectNetworkInfo', **kwargs) - - def get_vnc_console(self, server_id, **kwargs): - """Get URL of VNC console. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#get-vnc-console-os-getvncconsole-action - """ - return self.action(server_id, "os-getVNCConsole", - schema.get_vnc_console, **kwargs) - - def add_fixed_ip(self, server_id, **kwargs): - """Add a fixed IP to server instance. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#add-associate-fixed-ip-addfixedip-action - """ - return self.action(server_id, 'addFixedIp', **kwargs) - - def remove_fixed_ip(self, server_id, **kwargs): - """Remove input fixed IP from input server instance. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#remove-disassociate-fixed-ip-removefixedip-action - """ - return self.action(server_id, 'removeFixedIp', **kwargs) - - def list_security_groups_by_server(self, server_id): - """Lists security groups for a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-security-groups-by-server - """ - resp, body = self.get("servers/%s/os-security-groups" % server_id) - body = json.loads(body) - self.validate_response(security_groups_schema.list_security_groups, - resp, body) - return rest_client.ResponseBody(resp, body) - - def list_tags(self, server_id): - """Lists all tags for a server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-tags - """ - url = 'servers/%s/tags' % server_id - resp, body = self.get(url) - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.list_tags, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_all_tags(self, server_id, tags): - """Replaces all tags on specified server with the new set of tags. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#replace-tags - - :param tags: List of tags to replace current server tags with. - """ - url = 'servers/%s/tags' % server_id - put_body = {'tags': tags} - resp, body = self.put(url, json.dumps(put_body)) - body = json.loads(body) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.update_all_tags, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_all_tags(self, server_id): - """Deletes all tags from the specified server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#delete-all-tags - """ - url = 'servers/%s/tags' % server_id - resp, body = self.delete(url) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.delete_all_tags, resp, body) - return rest_client.ResponseBody(resp, body) - - def check_tag_existence(self, server_id, tag): - """Checks tag existence on the server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#check-tag-existence - - :param tag: Check for existence of tag on specified server. - """ - url = 'servers/%s/tags/%s' % (server_id, tag) - resp, body = self.get(url) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.check_tag_existence, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_tag(self, server_id, tag): - """Adds a single tag to the server if server has no specified tag. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#add-a-single-tag - - :param tag: Tag to be added to the specified server. - """ - url = 'servers/%s/tags/%s' % (server_id, tag) - resp, body = self.put(url, None) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.update_tag, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_tag(self, server_id, tag): - """Deletes a single tag from the specified server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#delete-a-single-tag - - :param tag: Tag to be removed from the specified server. - """ - url = 'servers/%s/tags/%s' % (server_id, tag) - resp, body = self.delete(url) - schema = self.get_schema(self.schema_versions_info) - self.validate_response(schema.delete_tag, resp, body) - return rest_client.ResponseBody(resp, body) - - def evacuate_server(self, server_id, **kwargs): - """Evacuate the given server. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#evacuate-server-evacuate-action - """ - if self.enable_instance_password: - evacuate_schema = schema.evacuate_server_with_admin_pass - else: - evacuate_schema = schema.evacuate_server - - return self.action(server_id, 'evacuate', - evacuate_schema, - **kwargs) diff --git a/tempest/lib/services/compute/services_client.py b/tempest/lib/services/compute/services_client.py deleted file mode 100644 index 857c435a6..000000000 --- a/tempest/lib/services/compute/services_client.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright 2013 NEC Corporation -# Copyright 2013 IBM 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import services as schema -from tempest.lib.api_schema.response.compute.v2_11 import services \ - as schemav211 -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class ServicesClient(base_compute_client.BaseComputeClient): - - schema_versions_info = [ - {'min': None, 'max': '2.10', 'schema': schema}, - {'min': '2.11', 'max': None, 'schema': schemav211}] - - def list_services(self, **params): - """Lists all running Compute services for a tenant. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-compute-services - """ - url = 'os-services' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - _schema = self.get_schema(self.schema_versions_info) - self.validate_response(_schema.list_services, resp, body) - return rest_client.ResponseBody(resp, body) - - def enable_service(self, **kwargs): - """Enable service on a host. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#enable-scheduling-for-a-compute-service - """ - post_body = json.dumps(kwargs) - resp, body = self.put('os-services/enable', post_body) - body = json.loads(body) - self.validate_response(schema.enable_disable_service, resp, body) - return rest_client.ResponseBody(resp, body) - - def disable_service(self, **kwargs): - """Disable service on a host. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#disable-scheduling-for-a-compute-service - """ - post_body = json.dumps(kwargs) - resp, body = self.put('os-services/disable', post_body) - body = json.loads(body) - self.validate_response(schema.enable_disable_service, resp, body) - return rest_client.ResponseBody(resp, body) - - def disable_log_reason(self, **kwargs): - """Disables scheduling for a Compute service and logs reason. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#log-disabled-compute-service-information - """ - post_body = json.dumps(kwargs) - resp, body = self.put('os-services/disable-log-reason', post_body) - body = json.loads(body) - self.validate_response(schema.disable_log_reason, resp, body) - return rest_client.ResponseBody(resp, body) - - def update_forced_down(self, **kwargs): - """Set or unset ``forced_down`` flag for the service. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#update-forced-down - """ - post_body = json.dumps(kwargs) - resp, body = self.put('os-services/force-down', post_body) - body = json.loads(body) - # NOTE: Use schemav211.update_forced_down directly because there is no - # update_forced_down schema for <2.11. - self.validate_response(schemav211.update_forced_down, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/snapshots_client.py b/tempest/lib/services/compute/snapshots_client.py deleted file mode 100644 index df8d6fbd3..000000000 --- a/tempest/lib/services/compute/snapshots_client.py +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright 2015 Fujitsu(fnst) Corporation -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import snapshots as schema -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.compute import base_compute_client - - -class SnapshotsClient(base_compute_client.BaseComputeClient): - - def create_snapshot(self, volume_id, **kwargs): - """Create a snapshot. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-snapshot - """ - post_body = { - 'volume_id': volume_id - } - post_body.update(kwargs) - post_body = json.dumps({'snapshot': post_body}) - resp, body = self.post('os-snapshots', post_body) - body = json.loads(body) - self.validate_response(schema.create_get_snapshot, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_snapshot(self, snapshot_id): - url = "os-snapshots/%s" % snapshot_id - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.create_get_snapshot, resp, body) - return rest_client.ResponseBody(resp, body) - - def list_snapshots(self, detail=False, params=None): - """List snapshots. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-snapshots - """ - url = 'os-snapshots' - - if detail: - url += '/detail' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.list_snapshots, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_snapshot(self, snapshot_id): - resp, body = self.delete("os-snapshots/%s" % snapshot_id) - self.validate_response(schema.delete_snapshot, resp, body) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_snapshot(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Return the primary type of resource this client works with.""" - return 'snapshot' diff --git a/tempest/lib/services/compute/tenant_networks_client.py b/tempest/lib/services/compute/tenant_networks_client.py deleted file mode 100644 index 04d8babae..000000000 --- a/tempest/lib/services/compute/tenant_networks_client.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import tenant_networks -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class TenantNetworksClient(base_compute_client.BaseComputeClient): - - def list_tenant_networks(self): - resp, body = self.get("os-tenant-networks") - body = json.loads(body) - self.validate_response(tenant_networks.list_tenant_networks, resp, - body) - return rest_client.ResponseBody(resp, body) - - def show_tenant_network(self, network_id): - resp, body = self.get("os-tenant-networks/%s" % network_id) - body = json.loads(body) - self.validate_response(tenant_networks.get_tenant_network, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/tenant_usages_client.py b/tempest/lib/services/compute/tenant_usages_client.py deleted file mode 100644 index ade60e541..000000000 --- a/tempest/lib/services/compute/tenant_usages_client.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright 2013 NEC Corporation -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import tenant_usages -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class TenantUsagesClient(base_compute_client.BaseComputeClient): - - def list_tenant_usages(self, **params): - """List Tenant Usage For All Tenants. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-tenant-usage-statistics-for-all-tenants - """ - url = 'os-simple-tenant-usage' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(tenant_usages.list_tenant_usage, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_tenant_usage(self, tenant_id, **params): - """Show Usage Details For Tenant. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#show-usage-statistics-for-tenant - """ - url = 'os-simple-tenant-usage/%s' % tenant_id - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(tenant_usages.get_tenant_usage, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/versions_client.py b/tempest/lib/services/compute/versions_client.py deleted file mode 100644 index 8fbb136fc..000000000 --- a/tempest/lib/services/compute/versions_client.py +++ /dev/null @@ -1,55 +0,0 @@ -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# -# 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 time - -from oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.compute.v2_1 import versions as schema -from tempest.lib.common import rest_client -from tempest.lib.services.compute import base_compute_client - - -class VersionsClient(base_compute_client.BaseComputeClient): - - def list_versions(self): - version_url = self._get_base_version_url() - - start = time.time() - resp, body = self.raw_request(version_url, 'GET') - end = time.time() - self._log_request('GET', version_url, resp, secs=(end - start), - resp_body=body) - - self._error_checker(resp, body) - body = json.loads(body) - self.validate_response(schema.list_versions, resp, body) - return rest_client.ResponseBody(resp, body) - - def get_version_by_url(self, version_url): - """Get the version document by url. - - This gets the version document for a url, useful in testing - the contents of things like /v2/ or /v2.1/ in Nova. That - controller needs authenticated access, so we have to get - ourselves a token before making the request. - - """ - # we need a token for this request - resp, body = self.raw_request(version_url, 'GET', - {'X-Auth-Token': self.token}) - self._error_checker(resp, body) - body = json.loads(body) - self.validate_response(schema.get_one_version, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/compute/volumes_client.py b/tempest/lib/services/compute/volumes_client.py deleted file mode 100644 index 95cdd5379..000000000 --- a/tempest/lib/services/compute/volumes_client.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.api_schema.response.compute.v2_1 import volumes as schema -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.compute import base_compute_client - - -class VolumesClient(base_compute_client.BaseComputeClient): - - def list_volumes(self, detail=False, **params): - """List all the volumes created. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#list-volumes - https://developer.openstack.org/api-ref/compute/#list-volumes-with-details - """ - url = 'os-volumes' - - if detail: - url += '/detail' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.list_volumes, resp, body) - return rest_client.ResponseBody(resp, body) - - def show_volume(self, volume_id): - """Return the details of a single volume. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#show-volume-details - """ - url = "os-volumes/%s" % volume_id - resp, body = self.get(url) - body = json.loads(body) - self.validate_response(schema.create_get_volume, resp, body) - return rest_client.ResponseBody(resp, body) - - def create_volume(self, **kwargs): - """Create a new Volume. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#create-volume - """ - post_body = json.dumps({'volume': kwargs}) - resp, body = self.post('os-volumes', post_body) - body = json.loads(body) - self.validate_response(schema.create_get_volume, resp, body) - return rest_client.ResponseBody(resp, body) - - def delete_volume(self, volume_id): - """Delete the Specified Volume. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/compute/#delete-volume - """ - resp, body = self.delete("os-volumes/%s" % volume_id) - self.validate_response(schema.delete_volume, resp, body) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_volume(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Return the primary type of resource this client works with.""" - return 'volume' diff --git a/tempest/lib/services/identity/__init__.py b/tempest/lib/services/identity/__init__.py deleted file mode 100644 index 941a10e7d..000000000 --- a/tempest/lib/services/identity/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# 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 tempest.lib.services.identity import v2 -from tempest.lib.services.identity import v3 - -__all__ = ['v2', 'v3'] diff --git a/tempest/lib/services/identity/v2/__init__.py b/tempest/lib/services/identity/v2/__init__.py deleted file mode 100644 index b7d3c7464..000000000 --- a/tempest/lib/services/identity/v2/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# 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 tempest.lib.services.identity.v2.endpoints_client import EndpointsClient -from tempest.lib.services.identity.v2.identity_client import IdentityClient -from tempest.lib.services.identity.v2.roles_client import RolesClient -from tempest.lib.services.identity.v2.services_client import ServicesClient -from tempest.lib.services.identity.v2.tenants_client import TenantsClient -from tempest.lib.services.identity.v2.token_client import TokenClient -from tempest.lib.services.identity.v2.users_client import UsersClient - -__all__ = ['EndpointsClient', 'IdentityClient', 'RolesClient', - 'ServicesClient', 'TenantsClient', 'TokenClient', 'UsersClient'] diff --git a/tempest/lib/services/identity/v2/endpoints_client.py b/tempest/lib/services/identity/v2/endpoints_client.py deleted file mode 100644 index db8d7cc60..000000000 --- a/tempest/lib/services/identity/v2/endpoints_client.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class EndpointsClient(rest_client.RestClient): - api_version = "v2.0" - - def create_endpoint(self, **kwargs): - """Create an endpoint for service. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v2-admin/index.html#create-endpoint-template - """ - - post_body = json.dumps({'endpoint': kwargs}) - resp, body = self.post('/endpoints', post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_endpoints(self): - """List Endpoints - Returns Endpoints.""" - resp, body = self.get('/endpoints') - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_endpoint(self, endpoint_id): - """Delete an endpoint.""" - url = '/endpoints/%s' % endpoint_id - resp, body = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v2/identity_client.py b/tempest/lib/services/identity/v2/identity_client.py deleted file mode 100644 index c610d65e1..000000000 --- a/tempest/lib/services/identity/v2/identity_client.py +++ /dev/null @@ -1,69 +0,0 @@ -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class IdentityClient(rest_client.RestClient): - api_version = "v2.0" - - def show_api_description(self): - """Retrieves info about the v2.0 Identity API""" - url = '' - resp, body = self.get(url) - self.expected_success([200, 203], resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_token(self, token_id): - """Get token details.""" - resp, body = self.get("tokens/%s" % token_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_token(self, token_id): - """Delete a token.""" - resp, body = self.delete("tokens/%s" % token_id) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_extensions(self): - """List all the extensions.""" - resp, body = self.get('/extensions') - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_endpoints_for_token(self, token_id): - """List endpoints for a token """ - resp, body = self.get("tokens/%s/endpoints" % token_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def check_token_existence(self, token_id, **params): - """Validates a token and confirms that it belongs to a tenant. - - For a full list of available parameters, please refer to the - official API reference: - https://developer.openstack.org/api-ref/identity/v2-admin/#validate-token - """ - url = "tokens/%s" % token_id - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.head(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v2/roles_client.py b/tempest/lib/services/identity/v2/roles_client.py deleted file mode 100644 index 9e841dd3a..000000000 --- a/tempest/lib/services/identity/v2/roles_client.py +++ /dev/null @@ -1,109 +0,0 @@ -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class RolesClient(rest_client.RestClient): - api_version = "v2.0" - - def create_role(self, **kwargs): - """Create a role. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v2-ext/index.html#create-a-role - """ - post_body = json.dumps({'role': kwargs}) - resp, body = self.post('OS-KSADM/roles', post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_role(self, role_id_or_name): - """Get a role by its id or name. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v2-ext/index.html#show-a-role - OR - https://developer.openstack.org/api-ref/identity/v2-ext/index.html#show-role-information-by-name - """ - resp, body = self.get('OS-KSADM/roles/%s' % role_id_or_name) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_roles(self, **params): - """Returns roles. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v2-ext/index.html#list-all-roles - """ - url = 'OS-KSADM/roles' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_role(self, role_id): - """Delete a role. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v2-ext/index.html#delete-a-role - """ - resp, body = self.delete('OS-KSADM/roles/%s' % role_id) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_user_role_on_project(self, tenant_id, user_id, role_id): - """Add roles to a user on a tenant. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v2-ext/index.html#grant-roles-to-user-on-tenant - """ - resp, body = self.put('/tenants/%s/users/%s/roles/OS-KSADM/%s' % - (tenant_id, user_id, role_id), "") - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_user_roles_on_project(self, tenant_id, user_id, **params): - """Returns a list of roles assigned to a user for a tenant.""" - # TODO(gmann): Need to write API-ref link, Bug# 1592711 - url = '/tenants/%s/users/%s/roles' % (tenant_id, user_id) - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_role_from_user_on_project(self, tenant_id, user_id, role_id): - """Removes a role assignment for a user on a tenant. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v2-ext/index.html#revoke-role-from-user-on-tenant - """ - resp, body = self.delete('/tenants/%s/users/%s/roles/OS-KSADM/%s' % - (tenant_id, user_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v2/services_client.py b/tempest/lib/services/identity/v2/services_client.py deleted file mode 100644 index 47398dbf7..000000000 --- a/tempest/lib/services/identity/v2/services_client.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2015 Red Hat, Inc. -# -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class ServicesClient(rest_client.RestClient): - api_version = "v2.0" - - def create_service(self, **kwargs): - """Create a service. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v2-ext/#create-service-admin-extension - """ - post_body = json.dumps({'OS-KSADM:service': kwargs}) - resp, body = self.post('/OS-KSADM/services', post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_service(self, service_id): - """Get Service.""" - url = '/OS-KSADM/services/%s' % service_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_services(self, **params): - """List Service - Returns Services. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v2-ext/#list-services-admin-extension - """ - url = '/OS-KSADM/services' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_service(self, service_id): - """Delete Service.""" - url = '/OS-KSADM/services/%s' % service_id - resp, body = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v2/tenants_client.py b/tempest/lib/services/identity/v2/tenants_client.py deleted file mode 100644 index 026db6420..000000000 --- a/tempest/lib/services/identity/v2/tenants_client.py +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright 2015 Red Hat, Inc. -# -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class TenantsClient(rest_client.RestClient): - api_version = "v2.0" - - def create_tenant(self, **kwargs): - """Create a tenant - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v2-admin/index.html#create-tenant - """ - post_body = json.dumps({'tenant': kwargs}) - resp, body = self.post('tenants', post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_tenant(self, tenant_id): - """Delete a tenant. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v2-admin/index.html#delete-tenant - """ - resp, body = self.delete('tenants/%s' % str(tenant_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_tenant(self, tenant_id): - """Get tenant details. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v2-admin/index.html#show-tenant-details-by-id - """ - resp, body = self.get('tenants/%s' % str(tenant_id)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_tenants(self, **params): - """Returns tenants. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v2-admin/index.html#list-tenants-admin-endpoint - """ - url = 'tenants' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_tenant(self, tenant_id, **kwargs): - """Updates a tenant. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v2-admin/index.html#update-tenant - """ - if 'id' not in kwargs: - kwargs['id'] = tenant_id - post_body = json.dumps({'tenant': kwargs}) - resp, body = self.post('tenants/%s' % tenant_id, post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_tenant_users(self, tenant_id, **params): - """List users for a Tenant. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v2-admin/index.html#list-users-on-a-tenant - """ - url = '/tenants/%s/users' % tenant_id - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v2/token_client.py b/tempest/lib/services/identity/v2/token_client.py deleted file mode 100644 index 458c862ad..000000000 --- a/tempest/lib/services/identity/v2/token_client.py +++ /dev/null @@ -1,140 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 oslo_log import log as logging -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client -from tempest.lib import exceptions - - -class TokenClient(rest_client.RestClient): - - def __init__(self, auth_url, disable_ssl_certificate_validation=None, - ca_certs=None, trace_requests=None, **kwargs): - """Initialises the Token client - - :param auth_url: URL to which the token request is sent - :param disable_ssl_certificate_validation: pass-through to rest client - :param ca_certs: pass-through to rest client - :param trace_requests: pass-through to rest client - :param kwargs: any extra parameter to pass through the rest client. - region, service and auth_provider will be ignored, if passed, - as they are not meaningful for token client - """ - dscv = disable_ssl_certificate_validation - # NOTE(andreaf) region, service and auth_provider are passed - # positionally with None. Having them in kwargs would raise a - # "multiple values for keyword arguments" error - for unwanted_kwargs in ['region', 'service', 'auth_provider']: - kwargs.pop(unwanted_kwargs, None) - super(TokenClient, self).__init__( - None, None, None, disable_ssl_certificate_validation=dscv, - ca_certs=ca_certs, trace_requests=trace_requests, **kwargs) - - if auth_url is None: - raise exceptions.IdentityError("Couldn't determine auth_url") - - # Normalize URI to ensure /tokens is in it. - if 'tokens' not in auth_url: - auth_url = auth_url.rstrip('/') + '/tokens' - - self.auth_url = auth_url - - def auth(self, user, password, tenant=None): - creds = { - 'auth': { - 'passwordCredentials': { - 'username': user, - 'password': password, - }, - } - } - - if tenant: - creds['auth']['tenantName'] = tenant - - body = json.dumps(creds, sort_keys=True) - resp, body = self.post(self.auth_url, body=body) - self.expected_success(200, resp.status) - - return rest_client.ResponseBody(resp, body['access']) - - def auth_token(self, token_id, tenant=None): - creds = { - 'auth': { - 'token': { - 'id': token_id, - }, - } - } - - if tenant: - creds['auth']['tenantName'] = tenant - - body = json.dumps(creds) - resp, body = self.post(self.auth_url, body=body) - self.expected_success(200, resp.status) - - return rest_client.ResponseBody(resp, body['access']) - - def request(self, method, url, extra_headers=False, headers=None, - body=None, chunked=False): - """A simple HTTP request interface. - - Note: this overloads the `request` method from the parent class and - thus must implement the same method signature. - """ - if headers is None: - headers = self.get_headers(accept_type="json") - elif extra_headers: - try: - headers.update(self.get_headers(accept_type="json")) - except (ValueError, TypeError): - headers = self.get_headers(accept_type="json") - - resp, resp_body = self.raw_request(url, method, - headers=headers, body=body) - self._log_request(method, url, resp, req_headers=headers, - req_body='', resp_body=resp_body) - - if resp.status in [401, 403]: - resp_body = json.loads(resp_body) - raise exceptions.Unauthorized(resp_body['error']['message']) - elif resp.status not in [200, 201]: - raise exceptions.IdentityError( - 'Unexpected status code {0}'.format(resp.status)) - - return resp, json.loads(resp_body) - - def get_token(self, user, password, tenant, auth_data=False): - """Returns (token id, token data) for supplied credentials.""" - body = self.auth(user, password, tenant) - - if auth_data: - return body['token']['id'], body - else: - return body['token']['id'] - - -class TokenClientJSON(TokenClient): - LOG = logging.getLogger(__name__) - - def _warn(self): - self.LOG.warning("%s class was deprecated and renamed to %s", - self.__class__.__name__, 'TokenClient') - - def __init__(self, *args, **kwargs): - self._warn() - super(TokenClientJSON, self).__init__(*args, **kwargs) diff --git a/tempest/lib/services/identity/v2/users_client.py b/tempest/lib/services/identity/v2/users_client.py deleted file mode 100644 index 44bb5fd69..000000000 --- a/tempest/lib/services/identity/v2/users_client.py +++ /dev/null @@ -1,158 +0,0 @@ -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class UsersClient(rest_client.RestClient): - api_version = "v2.0" - - def create_user(self, **kwargs): - """Create a user. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v2-admin/index.html#create-user-admin-endpoint - """ - post_body = json.dumps({'user': kwargs}) - resp, body = self.post('users', post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_user(self, user_id, **kwargs): - """Updates a user. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v2-admin/index.html#update-user-admin-endpoint - """ - put_body = json.dumps({'user': kwargs}) - resp, body = self.put('users/%s' % user_id, put_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_user(self, user_id): - """GET a user. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v2-admin/index.html#show-user-details-admin-endpoint - """ - resp, body = self.get("users/%s" % user_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_user(self, user_id): - """Delete a user. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v2-admin/index.html#delete-user-admin-endpoint - """ - resp, body = self.delete("users/%s" % user_id) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_users(self, **params): - """Get the list of users. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v2-admin/index.html#list-users-admin-endpoint - """ - url = "users" - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_user_enabled(self, user_id, **kwargs): - """Enables or disables a user. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v2-ext/index.html#enable-disable-user - """ - # NOTE: The URL (users//enabled) is different from the api-site - # one (users//OS-KSADM/enabled) , but they are the same API - # because of the fact that in keystone/contrib/admin_crud/core.py - # both api use same action='set_user_enabled' - put_body = json.dumps({'user': kwargs}) - resp, body = self.put('users/%s/enabled' % user_id, put_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_user_password(self, user_id, **kwargs): - """Update User Password.""" - # TODO(piyush): Current api-site doesn't contain this API description. - # After fixing the api-site, we need to fix here also for putting the - # link to api-site. - # LP: https://bugs.launchpad.net/openstack-api-site/+bug/1524147 - put_body = json.dumps({'user': kwargs}) - resp, body = self.put('users/%s/OS-KSADM/password' % user_id, put_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_user_own_password(self, user_id, **kwargs): - """User updates own password""" - # TODO(piyush): Current api-site doesn't contain this API description. - # After fixing the api-site, we need to fix here also for putting the - # link to api-site. - # LP: https://bugs.launchpad.net/openstack-api-site/+bug/1524153 - # NOTE: This API is used for updating user password by itself. - # Ref: http://lists.openstack.org/pipermail/openstack-dev/2015-December - # /081803.html - patch_body = json.dumps({'user': kwargs}) - resp, body = self.patch('OS-KSCRUD/users/%s' % user_id, patch_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_user_ec2_credential(self, user_id, **kwargs): - # TODO(piyush): Current api-site doesn't contain this API description. - # After fixing the api-site, we need to fix here also for putting the - # link to api-site. - post_body = json.dumps(kwargs) - resp, body = self.post('/users/%s/credentials/OS-EC2' % user_id, - post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_user_ec2_credential(self, user_id, access): - resp, body = self.delete('/users/%s/credentials/OS-EC2/%s' % - (user_id, access)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_user_ec2_credentials(self, user_id): - resp, body = self.get('/users/%s/credentials/OS-EC2' % user_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_user_ec2_credential(self, user_id, access): - resp, body = self.get('/users/%s/credentials/OS-EC2/%s' % - (user_id, access)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/__init__.py b/tempest/lib/services/identity/v3/__init__.py deleted file mode 100644 index a539d08c0..000000000 --- a/tempest/lib/services/identity/v3/__init__.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# 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 tempest.lib.services.identity.v3.catalog_client import \ - CatalogClient -from tempest.lib.services.identity.v3.credentials_client import \ - CredentialsClient -from tempest.lib.services.identity.v3.domain_configuration_client \ - import DomainConfigurationClient -from tempest.lib.services.identity.v3.domains_client import DomainsClient -from tempest.lib.services.identity.v3.endpoint_filter_client import \ - EndPointsFilterClient -from tempest.lib.services.identity.v3.endpoint_groups_client import \ - EndPointGroupsClient -from tempest.lib.services.identity.v3.endpoints_client import EndPointsClient -from tempest.lib.services.identity.v3.groups_client import GroupsClient -from tempest.lib.services.identity.v3.identity_client import IdentityClient -from tempest.lib.services.identity.v3.inherited_roles_client import \ - InheritedRolesClient -from tempest.lib.services.identity.v3.oauth_consumers_client import \ - OAUTHConsumerClient -from tempest.lib.services.identity.v3.oauth_token_client import \ - OAUTHTokenClient -from tempest.lib.services.identity.v3.policies_client import PoliciesClient -from tempest.lib.services.identity.v3.projects_client import ProjectsClient -from tempest.lib.services.identity.v3.regions_client import RegionsClient -from tempest.lib.services.identity.v3.role_assignments_client import \ - RoleAssignmentsClient -from tempest.lib.services.identity.v3.roles_client import RolesClient -from tempest.lib.services.identity.v3.services_client import ServicesClient -from tempest.lib.services.identity.v3.token_client import V3TokenClient -from tempest.lib.services.identity.v3.trusts_client import TrustsClient -from tempest.lib.services.identity.v3.users_client import UsersClient -from tempest.lib.services.identity.v3.versions_client import VersionsClient - -__all__ = ['CatalogClient', 'CredentialsClient', 'DomainsClient', - 'DomainConfigurationClient', 'EndPointGroupsClient', - 'EndPointsClient', 'EndPointsFilterClient', 'GroupsClient', - 'IdentityClient', 'InheritedRolesClient', 'OAUTHConsumerClient', - 'OAUTHTokenClient', 'PoliciesClient', 'ProjectsClient', - 'RegionsClient', 'RoleAssignmentsClient', 'RolesClient', - 'ServicesClient', 'V3TokenClient', 'TrustsClient', 'UsersClient', - 'VersionsClient'] diff --git a/tempest/lib/services/identity/v3/catalog_client.py b/tempest/lib/services/identity/v3/catalog_client.py deleted file mode 100644 index 0f9d48543..000000000 --- a/tempest/lib/services/identity/v3/catalog_client.py +++ /dev/null @@ -1,30 +0,0 @@ -# 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. - -""" -https://developer.openstack.org/api-ref/identity/v3/index.html#\ -get-service-catalog -""" - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class CatalogClient(rest_client.RestClient): - api_version = "v3" - - def show_catalog(self): - resp, body = self.get('auth/catalog') - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/credentials_client.py b/tempest/lib/services/identity/v3/credentials_client.py deleted file mode 100644 index 6e5fd3150..000000000 --- a/tempest/lib/services/identity/v3/credentials_client.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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. - -""" -http://developer.openstack.org/api-ref/identity/v3/index.html#credentials -""" - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class CredentialsClient(rest_client.RestClient): - api_version = "v3" - - def create_credential(self, **kwargs): - """Creates a credential. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#create-credential - """ - post_body = json.dumps({'credential': kwargs}) - resp, body = self.post('credentials', post_body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_credential(self, credential_id, **kwargs): - """Updates a credential. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#update-credential - """ - post_body = json.dumps({'credential': kwargs}) - resp, body = self.patch('credentials/%s' % credential_id, post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_credential(self, credential_id): - """To GET Details of a credential. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#show-credential-details - """ - resp, body = self.get('credentials/%s' % credential_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_credentials(self, **params): - """Lists out all the available credentials. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/#list-credentials - """ - url = 'credentials' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_credential(self, credential_id): - """Deletes a credential. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/#delete-credential - """ - resp, body = self.delete('credentials/%s' % credential_id) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/domain_configuration_client.py b/tempest/lib/services/identity/v3/domain_configuration_client.py deleted file mode 100644 index d57f2d478..000000000 --- a/tempest/lib/services/identity/v3/domain_configuration_client.py +++ /dev/null @@ -1,188 +0,0 @@ -# Copyright 2017 AT&T Corporation -# -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class DomainConfigurationClient(rest_client.RestClient): - api_version = "v3" - - def show_default_config_settings(self): - """Show default configuration settings. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#show-default-configuration-settings - """ - url = 'domains/config/default' - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_default_group_config(self, group): - """Show default configuration for a group. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#show-default-configuration-for-a-group - """ - url = 'domains/config/%s/default' % group - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_default_group_option(self, group, option): - """Show default option for a group. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#show-default-option-for-a-group - """ - url = 'domains/config/%s/%s/default' % (group, option) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_domain_group_option_config(self, domain_id, group, option): - """Show domain group option configuration. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#show-domain-group-option-configuration - """ - url = 'domains/%s/config/%s/%s' % (domain_id, group, option) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_domain_group_option_config(self, domain_id, group, option, - **kwargs): - """Update domain group option configuration. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#update-domain-group-option-configuration - """ - url = 'domains/%s/config/%s/%s' % (domain_id, group, option) - resp, body = self.patch(url, json.dumps({'config': kwargs})) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_domain_group_option_config(self, domain_id, group, option): - """Delete domain group option configuration. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#delete-domain-group-option-configuration - """ - url = 'domains/%s/config/%s/%s' % (domain_id, group, option) - resp, body = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_domain_group_config(self, domain_id, group): - """Shows details for a domain group configuration. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#show-domain-group-configuration - """ - url = 'domains/%s/config/%s' % (domain_id, group) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_domain_group_config(self, domain_id, group, **kwargs): - """Update domain group configuration. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#update-domain-group-configuration - """ - url = 'domains/%s/config/%s' % (domain_id, group) - resp, body = self.patch(url, json.dumps({'config': kwargs})) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_domain_group_config(self, domain_id, group): - """Delete domain group configuration. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#delete-domain-group-configuration - """ - url = 'domains/%s/config/%s' % (domain_id, group) - resp, body = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_domain_config(self, domain_id, **kwargs): - """Create domain configuration. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#create-domain-configuration - """ - url = 'domains/%s/config' % domain_id - resp, body = self.put(url, json.dumps({'config': kwargs})) - self.expected_success([200, 201], resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_domain_config(self, domain_id): - """Show domain configuration. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#show-domain-configuration - """ - url = 'domains/%s/config' % domain_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_domain_config(self, domain_id, **kwargs): - """Update domain configuration. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#update-domain-configuration - """ - url = 'domains/%s/config' % domain_id - resp, body = self.patch(url, json.dumps({'config': kwargs})) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_domain_config(self, domain_id): - """Delete domain configuration. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#delete-domain-configuration - """ - url = 'domains/%s/config' % domain_id - resp, body = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/domains_client.py b/tempest/lib/services/identity/v3/domains_client.py deleted file mode 100644 index 43cb62c73..000000000 --- a/tempest/lib/services/identity/v3/domains_client.py +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class DomainsClient(rest_client.RestClient): - api_version = "v3" - - def create_domain(self, **kwargs): - """Creates a domain. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#create-domain - """ - post_body = json.dumps({'domain': kwargs}) - resp, body = self.post('domains', post_body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_domain(self, domain_id): - """Deletes a domain. - - For APi details, please refer to the official API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#delete-domain - """ - resp, body = self.delete('domains/%s' % domain_id) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_domains(self, **params): - """List Domains. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#list-domains - """ - url = 'domains' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_domain(self, domain_id, **kwargs): - """Updates a domain. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#update-domain - """ - post_body = json.dumps({'domain': kwargs}) - resp, body = self.patch('domains/%s' % domain_id, post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_domain(self, domain_id): - """Get Domain details. - - For API details, please refer to the official API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#show-domain-details - """ - resp, body = self.get('domains/%s' % domain_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/endpoint_filter_client.py b/tempest/lib/services/identity/v3/endpoint_filter_client.py deleted file mode 100644 index a8cd7222e..000000000 --- a/tempest/lib/services/identity/v3/endpoint_filter_client.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2017 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. - -""" -https://developer.openstack.org/api-ref/identity/v3-ext/#os-ep-filter-api -""" - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class EndPointsFilterClient(rest_client.RestClient): - api_version = "v3" - ep_filter = "OS-EP-FILTER" - - def list_projects_for_endpoint(self, endpoint_id): - """List all projects that are associated with the endpoint.""" - resp, body = self.get(self.ep_filter + '/endpoints/%s/projects' % - endpoint_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def add_endpoint_to_project(self, project_id, endpoint_id): - """Add association between project and endpoint. """ - body = None - resp, body = self.put( - self.ep_filter + '/projects/%s/endpoints/%s' % - (project_id, endpoint_id), body) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def check_endpoint_in_project(self, project_id, endpoint_id): - """Check association of Project with Endpoint.""" - resp, body = self.head( - self.ep_filter + '/projects/%s/endpoints/%s' % - (project_id, endpoint_id), None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_endpoints_in_project(self, project_id): - """List Endpoints associated with Project.""" - resp, body = self.get(self.ep_filter + '/projects/%s/endpoints' - % project_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_endpoint_from_project(self, project_id, endpoint_id): - """Delete association between project and endpoint.""" - resp, body = self.delete( - self.ep_filter + '/projects/%s/endpoints/%s' - % (project_id, endpoint_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/endpoint_groups_client.py b/tempest/lib/services/identity/v3/endpoint_groups_client.py deleted file mode 100644 index ce9938953..000000000 --- a/tempest/lib/services/identity/v3/endpoint_groups_client.py +++ /dev/null @@ -1,78 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class EndPointGroupsClient(rest_client.RestClient): - api_version = "v3" - - def create_endpoint_group(self, **kwargs): - """Create endpoint group. - - For a full list of available parameters, please refer to the - official API reference: - https://developer.openstack.org/api-ref/identity/v3-ext/#create-endpoint-group - """ - post_body = json.dumps({'endpoint_group': kwargs}) - resp, body = self.post('OS-EP-FILTER/endpoint_groups', post_body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_endpoint_group(self, endpoint_group_id, **kwargs): - """Update endpoint group. - - For a full list of available parameters, please refer to the - official API reference: - https://developer.openstack.org/api-ref/identity/v3-ext/#update-endpoint-group - """ - post_body = json.dumps({'endpoint_group': kwargs}) - resp, body = self.patch( - 'OS-EP-FILTER/endpoint_groups/%s' % endpoint_group_id, post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_endpoint_group(self, endpoint_group_id): - """Delete endpoint group.""" - resp_header, resp_body = self.delete( - 'OS-EP-FILTER/endpoint_groups/%s' % endpoint_group_id) - self.expected_success(204, resp_header.status) - return rest_client.ResponseBody(resp_header, resp_body) - - def show_endpoint_group(self, endpoint_group_id): - """Get endpoint group.""" - resp_header, resp_body = self.get( - 'OS-EP-FILTER/endpoint_groups/%s' % endpoint_group_id) - self.expected_success(200, resp_header.status) - resp_body = json.loads(resp_body) - return rest_client.ResponseBody(resp_header, resp_body) - - def check_endpoint_group(self, endpoint_group_id): - """Check endpoint group.""" - resp_header, resp_body = self.head( - 'OS-EP-FILTER/endpoint_groups/%s' % endpoint_group_id) - self.expected_success(200, resp_header.status) - return rest_client.ResponseBody(resp_header, resp_body) - - def list_endpoint_groups(self): - """Get endpoint groups.""" - resp_header, resp_body = self.get('OS-EP-FILTER/endpoint_groups') - self.expected_success(200, resp_header.status) - resp_body = json.loads(resp_body) - return rest_client.ResponseBody(resp_header, resp_body) diff --git a/tempest/lib/services/identity/v3/endpoints_client.py b/tempest/lib/services/identity/v3/endpoints_client.py deleted file mode 100644 index e24dca7b6..000000000 --- a/tempest/lib/services/identity/v3/endpoints_client.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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. - -""" -https://developer.openstack.org/api-ref/identity/v3/index.html#service-catalog-and-endpoints -""" - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class EndPointsClient(rest_client.RestClient): - api_version = "v3" - - def list_endpoints(self, **params): - """List endpoints. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/#list-endpoints - """ - url = 'endpoints' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_endpoint(self, **kwargs): - """Create endpoint. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#create-endpoint - """ - post_body = json.dumps({'endpoint': kwargs}) - resp, body = self.post('endpoints', post_body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_endpoint(self, endpoint_id, **kwargs): - """Updates an endpoint with given parameters. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#update-endpoint - """ - post_body = json.dumps({'endpoint': kwargs}) - resp, body = self.patch('endpoints/%s' % endpoint_id, post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_endpoint(self, endpoint_id): - """Delete endpoint.""" - resp_header, resp_body = self.delete('endpoints/%s' % endpoint_id) - self.expected_success(204, resp_header.status) - return rest_client.ResponseBody(resp_header, resp_body) - - def show_endpoint(self, endpoint_id): - """Get endpoint.""" - resp_header, resp_body = self.get('endpoints/%s' % endpoint_id) - self.expected_success(200, resp_header.status) - resp_body = json.loads(resp_body) - return rest_client.ResponseBody(resp_header, resp_body) diff --git a/tempest/lib/services/identity/v3/groups_client.py b/tempest/lib/services/identity/v3/groups_client.py deleted file mode 100644 index bc6ead023..000000000 --- a/tempest/lib/services/identity/v3/groups_client.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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. - -""" -https://developer.openstack.org/api-ref/identity/v3/index.html#groups -""" - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class GroupsClient(rest_client.RestClient): - api_version = "v3" - - def create_group(self, **kwargs): - """Creates a group. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#create-group - """ - post_body = json.dumps({'group': kwargs}) - resp, body = self.post('groups', post_body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_group(self, group_id): - """Get group details.""" - resp, body = self.get('groups/%s' % group_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_groups(self, **params): - """Lists the groups. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/#list-groups - """ - url = 'groups' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_group(self, group_id, **kwargs): - """Updates a group. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#update-group - """ - post_body = json.dumps({'group': kwargs}) - resp, body = self.patch('groups/%s' % group_id, post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_group(self, group_id): - """Delete a group.""" - resp, body = self.delete('groups/%s' % group_id) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def add_group_user(self, group_id, user_id): - """Add user into group.""" - resp, body = self.put('groups/%s/users/%s' % (group_id, user_id), - None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_group_users(self, group_id, **params): - """List users in group. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/#list-users-in-group - """ - url = 'groups/%s/users' % group_id - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_group_user(self, group_id, user_id): - """Delete user in group.""" - resp, body = self.delete('groups/%s/users/%s' % (group_id, user_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def check_group_user_existence(self, group_id, user_id): - """Check user in group.""" - resp, body = self.head('groups/%s/users/%s' % (group_id, user_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) diff --git a/tempest/lib/services/identity/v3/identity_client.py b/tempest/lib/services/identity/v3/identity_client.py deleted file mode 100644 index 2512a3edc..000000000 --- a/tempest/lib/services/identity/v3/identity_client.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class IdentityClient(rest_client.RestClient): - api_version = "v3" - - def show_api_description(self): - """Retrieves info about the v3 Identity API""" - url = '' - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_token(self, resp_token): - """Get token details.""" - headers = {'X-Subject-Token': resp_token} - resp, body = self.get("auth/tokens", headers=headers) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_token(self, resp_token): - """Deletes token.""" - headers = {'X-Subject-Token': resp_token} - resp, body = self.delete("auth/tokens", headers=headers) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def check_token_existence(self, resp_token): - """Validates a token.""" - headers = {'X-Subject-Token': resp_token} - resp, body = self.head("auth/tokens", headers=headers) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_auth_projects(self): - """Get available project scopes.""" - resp, body = self.get("auth/projects") - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/inherited_roles_client.py b/tempest/lib/services/identity/v3/inherited_roles_client.py deleted file mode 100644 index 691c7fdc9..000000000 --- a/tempest/lib/services/identity/v3/inherited_roles_client.py +++ /dev/null @@ -1,151 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class InheritedRolesClient(rest_client.RestClient): - api_version = "v3" - - def create_inherited_role_on_domains_user( - self, domain_id, user_id, role_id): - """Assigns a role to a user on projects owned by a domain.""" - resp, body = self.put( - "OS-INHERIT/domains/%s/users/%s/roles/%s/inherited_to_projects" - % (domain_id, user_id, role_id), None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_inherited_role_from_user_on_domain( - self, domain_id, user_id, role_id): - """Revokes an inherited project role from a user on a domain.""" - resp, body = self.delete( - "OS-INHERIT/domains/%s/users/%s/roles/%s/inherited_to_projects" - % (domain_id, user_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_inherited_project_role_for_user_on_domain( - self, domain_id, user_id): - """Lists the inherited project roles on a domain for a user.""" - resp, body = self.get( - "OS-INHERIT/domains/%s/users/%s/roles/inherited_to_projects" - % (domain_id, user_id)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def check_user_inherited_project_role_on_domain( - self, domain_id, user_id, role_id): - """Checks whether a user has an inherited project role on a domain.""" - resp, body = self.head( - "OS-INHERIT/domains/%s/users/%s/roles/%s/inherited_to_projects" - % (domain_id, user_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def create_inherited_role_on_domains_group( - self, domain_id, group_id, role_id): - """Assigns a role to a group on projects owned by a domain.""" - resp, body = self.put( - "OS-INHERIT/domains/%s/groups/%s/roles/%s/inherited_to_projects" - % (domain_id, group_id, role_id), None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_inherited_role_from_group_on_domain( - self, domain_id, group_id, role_id): - """Revokes an inherited project role from a group on a domain.""" - resp, body = self.delete( - "OS-INHERIT/domains/%s/groups/%s/roles/%s/inherited_to_projects" - % (domain_id, group_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_inherited_project_role_for_group_on_domain( - self, domain_id, group_id): - """Lists the inherited project roles on a domain for a group.""" - resp, body = self.get( - "OS-INHERIT/domains/%s/groups/%s/roles/inherited_to_projects" - % (domain_id, group_id)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def check_group_inherited_project_role_on_domain( - self, domain_id, group_id, role_id): - """Checks whether a group has an inherited project role on a domain.""" - resp, body = self.head( - "OS-INHERIT/domains/%s/groups/%s/roles/%s/inherited_to_projects" - % (domain_id, group_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def create_inherited_role_on_projects_user( - self, project_id, user_id, role_id): - """Assigns a role to a user on projects in a subtree.""" - resp, body = self.put( - "OS-INHERIT/projects/%s/users/%s/roles/%s/inherited_to_projects" - % (project_id, user_id, role_id), None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_inherited_role_from_user_on_project( - self, project_id, user_id, role_id): - """Revokes an inherited role from a user on a project.""" - resp, body = self.delete( - "OS-INHERIT/projects/%s/users/%s/roles/%s/inherited_to_projects" - % (project_id, user_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def check_user_has_flag_on_inherited_to_project( - self, project_id, user_id, role_id): - """Checks whether a user has a role assignment""" - """with the inherited_to_projects flag on a project.""" - resp, body = self.head( - "OS-INHERIT/projects/%s/users/%s/roles/%s/inherited_to_projects" - % (project_id, user_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def create_inherited_role_on_projects_group( - self, project_id, group_id, role_id): - """Assigns a role to a group on projects in a subtree.""" - resp, body = self.put( - "OS-INHERIT/projects/%s/groups/%s/roles/%s/inherited_to_projects" - % (project_id, group_id, role_id), None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_inherited_role_from_group_on_project( - self, project_id, group_id, role_id): - """Revokes an inherited role from a group on a project.""" - resp, body = self.delete( - "OS-INHERIT/projects/%s/groups/%s/roles/%s/inherited_to_projects" - % (project_id, group_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def check_group_has_flag_on_inherited_to_project( - self, project_id, group_id, role_id): - """Checks whether a group has a role assignment""" - """with the inherited_to_projects flag on a project.""" - resp, body = self.head( - "OS-INHERIT/projects/%s/groups/%s/roles/%s/inherited_to_projects" - % (project_id, group_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) diff --git a/tempest/lib/services/identity/v3/oauth_consumers_client.py b/tempest/lib/services/identity/v3/oauth_consumers_client.py deleted file mode 100644 index 97fb14145..000000000 --- a/tempest/lib/services/identity/v3/oauth_consumers_client.py +++ /dev/null @@ -1,95 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class OAUTHConsumerClient(rest_client.RestClient): - api_version = "v3" - - def create_consumer(self, description=None): - """Creates a consumer. - - :param str description: Optional field to add notes about the consumer - - For more information, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/#create-consumer - """ - post_body = {"description": description} - post_body = json.dumps({'consumer': post_body}) - resp, body = self.post('OS-OAUTH1/consumers', post_body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_consumer(self, consumer_id): - """Deletes a consumer. - - :param str consumer_id: The ID of the consumer that will be deleted - - For more information, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/#delete-consumer - """ - resp, body = self.delete('OS-OAUTH1/consumers/%s' % consumer_id) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_consumer(self, consumer_id, description=None): - """Updates a consumer. - - :param str consumer_id: The ID of the consumer that will be updated - :param str description: Optional field to add notes about the consumer - - For more information, please refer to the official - API reference: - https://developer.openstack.org/api-ref/identity/v3-ext/#update-consumer - """ - post_body = {"description": description} - post_body = json.dumps({'consumer': post_body}) - resp, body = self.patch('OS-OAUTH1/consumers/%s' % consumer_id, - post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_consumer(self, consumer_id): - """Show consumer details. - - :param str consumer_id: The ID of the consumer that will be shown - - For more information, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/#show-consumer-details - """ - resp, body = self.get('OS-OAUTH1/consumers/%s' % consumer_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_consumers(self): - """List all consumers. - - For more information, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/#list-consumers - """ - resp, body = self.get('OS-OAUTH1/consumers') - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/oauth_token_client.py b/tempest/lib/services/identity/v3/oauth_token_client.py deleted file mode 100644 index b1d298b8f..000000000 --- a/tempest/lib/services/identity/v3/oauth_token_client.py +++ /dev/null @@ -1,236 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 binascii -import hashlib -import hmac -import random -import time - -import six -from six.moves.urllib import parse as urlparse - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class OAUTHTokenClient(rest_client.RestClient): - api_version = "v3" - - def _escape(self, s): - """Escape a unicode string in an OAuth-compatible fashion.""" - safe = b'~' - s = s.encode('utf-8') if isinstance(s, six.text_type) else s - s = urlparse.quote(s, safe) - if isinstance(s, six.binary_type): - s = s.decode('utf-8') - return s - - def _generate_params_with_signature(self, client_key, uri, - client_secret=None, - resource_owner_key=None, - resource_owner_secret=None, - callback_uri=None, - verifier=None, - http_method='GET'): - """Generate OAUTH params along with signature.""" - timestamp = six.text_type(int(time.time())) - nonce = six.text_type(random.getrandbits(64)) + timestamp - oauth_params = [ - ('oauth_nonce', nonce), - ('oauth_timestamp', timestamp), - ('oauth_version', '1.0'), - ('oauth_signature_method', 'HMAC-SHA1'), - ('oauth_consumer_key', client_key), - ] - if resource_owner_key: - oauth_params.append(('oauth_token', resource_owner_key)) - if callback_uri: - oauth_params.append(('oauth_callback', callback_uri)) - if verifier: - oauth_params.append(('oauth_verifier', verifier)) - - # normalize_params - key_values = [(self._escape(k), self._escape(v)) - for k, v in oauth_params] - key_values.sort() - parameter_parts = ['{0}={1}'.format(k, v) for k, v in key_values] - normalized_params = '&'.join(parameter_parts) - - # normalize_uri - scheme, netloc, path, params, query, fragment = urlparse.urlparse(uri) - scheme = scheme.lower() - netloc = netloc.lower() - normalized_uri = urlparse.urlunparse((scheme, netloc, path, - params, '', '')) - - # construct base string - base_string = self._escape(http_method.upper()) - base_string += '&' - base_string += self._escape(normalized_uri) - base_string += '&' - base_string += self._escape(normalized_params) - - # sign using hmac-sha1 - key = self._escape(client_secret or '') - key += '&' - key += self._escape(resource_owner_secret or '') - key_utf8 = key.encode('utf-8') - text_utf8 = base_string.encode('utf-8') - signature = hmac.new(key_utf8, text_utf8, hashlib.sha1) - sig = binascii.b2a_base64(signature.digest())[:-1].decode('utf-8') - - oauth_params.append(('oauth_signature', sig)) - return oauth_params - - def _generate_oauth_header(self, oauth_params): - authorization_header = {} - authorization_header_parameters_parts = [] - for oauth_parameter_name, value in oauth_params: - escaped_name = self._escape(oauth_parameter_name) - escaped_value = self._escape(value) - part = '{0}="{1}"'.format(escaped_name, escaped_value) - authorization_header_parameters_parts.append(part) - - authorization_header_parameters = ', '.join( - authorization_header_parameters_parts) - oauth_string = 'OAuth %s' % authorization_header_parameters - authorization_header['Authorization'] = oauth_string - - return authorization_header - - def create_request_token(self, consumer_key, consumer_secret, project_id): - """Create request token. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/#create-request-token - """ - endpoint = 'OS-OAUTH1/request_token' - headers = {'Requested-Project-Id': project_id} - oauth_params = self._generate_params_with_signature( - consumer_key, - self.base_url + '/' + endpoint, - client_secret=consumer_secret, - callback_uri='oob', - http_method='POST') - oauth_header = self._generate_oauth_header(oauth_params) - headers.update(oauth_header) - resp, body = self.post(endpoint, - body=None, - headers=headers) - self.expected_success(201, resp.status) - if not isinstance(body, str): - body = body.decode('utf-8') - body = dict(item.split("=") for item in body.split("&")) - return rest_client.ResponseBody(resp, body) - - def authorize_request_token(self, request_token_id, role_ids): - """Authorize request token. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/#authorize-request-token - """ - roles = [{'id': role_id} for role_id in role_ids] - body = {'roles': roles} - post_body = json.dumps(body) - resp, body = self.put("OS-OAUTH1/authorize/%s" % request_token_id, - post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_access_token(self, consumer_key, consumer_secret, request_key, - request_secret, oauth_verifier): - """Create access token. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/#create-access-token - """ - endpoint = 'OS-OAUTH1/access_token' - oauth_params = self._generate_params_with_signature( - consumer_key, - self.base_url + '/' + endpoint, - client_secret=consumer_secret, - resource_owner_key=request_key, - resource_owner_secret=request_secret, - verifier=oauth_verifier, - http_method='POST') - headers = self._generate_oauth_header(oauth_params) - resp, body = self.post(endpoint, body=None, headers=headers) - self.expected_success(201, resp.status) - if not isinstance(body, str): - body = body.decode('utf-8') - body = dict(item.split("=") for item in body.split("&")) - return rest_client.ResponseBody(resp, body) - - def get_access_token(self, user_id, access_token_id): - """Get access token. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/#get-access-token - """ - resp, body = self.get("users/%s/OS-OAUTH1/access_tokens/%s" - % (user_id, access_token_id)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def revoke_access_token(self, user_id, access_token_id): - """Revoke access token. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/#revoke-access-token - """ - resp, body = self.delete("users/%s/OS-OAUTH1/access_tokens/%s" - % (user_id, access_token_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_access_tokens(self, user_id): - """List access tokens. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/#list-access-tokens - """ - resp, body = self.get("users/%s/OS-OAUTH1/access_tokens" - % (user_id)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_access_token_roles(self, user_id, access_token_id): - """List roles for an access token. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/#list-roles-for-an-access-token - """ - resp, body = self.get("users/%s/OS-OAUTH1/access_tokens/%s/roles" - % (user_id, access_token_id)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def get_access_token_role(self, user_id, access_token_id, role_id): - """Show role details for an access token. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/#show-role-details-for-an-access-token - """ - resp, body = self.get("users/%s/OS-OAUTH1/access_tokens/%s/roles/%s" - % (user_id, access_token_id, role_id)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/policies_client.py b/tempest/lib/services/identity/v3/policies_client.py deleted file mode 100644 index d4560e2fd..000000000 --- a/tempest/lib/services/identity/v3/policies_client.py +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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. - -""" -https://developer.openstack.org/api-ref/identity/v3/index.html#policies -""" - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class PoliciesClient(rest_client.RestClient): - api_version = "v3" - - def create_policy(self, **kwargs): - """Creates a Policy. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#create-policy - """ - post_body = json.dumps({'policy': kwargs}) - resp, body = self.post('policies', post_body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_policies(self): - """Lists the policies.""" - resp, body = self.get('policies') - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_policy(self, policy_id): - """Lists out the given policy.""" - url = 'policies/%s' % policy_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_policy(self, policy_id, **kwargs): - """Updates a policy. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#update-policy - """ - post_body = json.dumps({'policy': kwargs}) - url = 'policies/%s' % policy_id - resp, body = self.patch(url, post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_policy(self, policy_id): - """Deletes the policy.""" - url = "policies/%s" % policy_id - resp, body = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/projects_client.py b/tempest/lib/services/identity/v3/projects_client.py deleted file mode 100644 index 20787da21..000000000 --- a/tempest/lib/services/identity/v3/projects_client.py +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class ProjectsClient(rest_client.RestClient): - api_version = "v3" - - def create_project(self, name, **kwargs): - """Create a Project. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#create-project - - """ - # Include the project name to the kwargs parameters - kwargs['name'] = name - post_body = json.dumps({'project': kwargs}) - resp, body = self.post('projects', post_body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_projects(self, params=None): - url = "projects" - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_project(self, project_id, **kwargs): - """Update a Project. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#update-project - - """ - post_body = json.dumps({'project': kwargs}) - resp, body = self.patch('projects/%s' % project_id, post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_project(self, project_id): - """GET a Project.""" - resp, body = self.get("projects/%s" % project_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_project(self, project_id): - """Delete a project.""" - resp, body = self.delete('projects/%s' % project_id) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/regions_client.py b/tempest/lib/services/identity/v3/regions_client.py deleted file mode 100644 index d7507cf70..000000000 --- a/tempest/lib/services/identity/v3/regions_client.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P -# 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. - -""" -https://developer.openstack.org/api-ref/identity/v3/index.html#regions -""" - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class RegionsClient(rest_client.RestClient): - api_version = "v3" - - def create_region(self, region_id=None, **kwargs): - """Create region. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#create-region - """ - if region_id is not None: - method = self.put - url = 'regions/%s' % region_id - else: - method = self.post - url = 'regions' - req_body = json.dumps({'region': kwargs}) - resp, body = method(url, req_body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_region(self, region_id, **kwargs): - """Updates a region. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#update-region - """ - post_body = json.dumps({'region': kwargs}) - resp, body = self.patch('regions/%s' % region_id, post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_region(self, region_id): - """Get region.""" - url = 'regions/%s' % region_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_regions(self, params=None): - """List regions.""" - url = 'regions' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_region(self, region_id): - """Delete region.""" - resp, body = self.delete('regions/%s' % region_id) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/role_assignments_client.py b/tempest/lib/services/identity/v3/role_assignments_client.py deleted file mode 100644 index a426e695d..000000000 --- a/tempest/lib/services/identity/v3/role_assignments_client.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class RoleAssignmentsClient(rest_client.RestClient): - api_version = "v3" - - def list_role_assignments(self, effective=False, **kwargs): - """List role assignments. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/#list-role-assignments - - :param effective: If True, returns the effective assignments, including - any assignments gained by virtue of group membership - or inherited roles. - """ - url = 'role_assignments' - if kwargs: - # NOTE(rodrigods): "effective" is a key-only query parameter and - # is treated below. - if 'effective' in kwargs: - del kwargs['effective'] - url += '?%s' % urllib.urlencode(kwargs) - if effective: - url += '&effective' - - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/roles_client.py b/tempest/lib/services/identity/v3/roles_client.py deleted file mode 100644 index 43e3c0187..000000000 --- a/tempest/lib/services/identity/v3/roles_client.py +++ /dev/null @@ -1,241 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class RolesClient(rest_client.RestClient): - api_version = "v3" - - def create_role(self, **kwargs): - """Create a Role. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#create-role - """ - post_body = json.dumps({'role': kwargs}) - resp, body = self.post('roles', post_body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_role(self, role_id): - """GET a Role.""" - resp, body = self.get('roles/%s' % role_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_roles(self, **params): - """Get the list of Roles.""" - - url = 'roles' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_role(self, role_id, **kwargs): - """Update a Role. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#update-role - """ - post_body = json.dumps({'role': kwargs}) - resp, body = self.patch('roles/%s' % role_id, post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_role(self, role_id): - """Delete a role.""" - resp, body = self.delete('roles/%s' % role_id) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_user_role_on_project(self, project_id, user_id, role_id): - """Add roles to a user on a project.""" - resp, body = self.put('projects/%s/users/%s/roles/%s' % - (project_id, user_id, role_id), None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_user_role_on_domain(self, domain_id, user_id, role_id): - """Add roles to a user on a domain.""" - resp, body = self.put('domains/%s/users/%s/roles/%s' % - (domain_id, user_id, role_id), None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_user_roles_on_project(self, project_id, user_id): - """list roles of a user on a project.""" - resp, body = self.get('projects/%s/users/%s/roles' % - (project_id, user_id)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_user_roles_on_domain(self, domain_id, user_id): - """list roles of a user on a domain.""" - resp, body = self.get('domains/%s/users/%s/roles' % - (domain_id, user_id)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_role_from_user_on_project(self, project_id, user_id, role_id): - """Delete role of a user on a project.""" - resp, body = self.delete('projects/%s/users/%s/roles/%s' % - (project_id, user_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_role_from_user_on_domain(self, domain_id, user_id, role_id): - """Delete role of a user on a domain.""" - resp, body = self.delete('domains/%s/users/%s/roles/%s' % - (domain_id, user_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def check_user_role_existence_on_project(self, project_id, - user_id, role_id): - """Check role of a user on a project.""" - resp, body = self.head('projects/%s/users/%s/roles/%s' % - (project_id, user_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def check_user_role_existence_on_domain(self, domain_id, - user_id, role_id): - """Check role of a user on a domain.""" - resp, body = self.head('domains/%s/users/%s/roles/%s' % - (domain_id, user_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def create_group_role_on_project(self, project_id, group_id, role_id): - """Add roles to a group on a project.""" - resp, body = self.put('projects/%s/groups/%s/roles/%s' % - (project_id, group_id, role_id), None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_group_role_on_domain(self, domain_id, group_id, role_id): - """Add roles to a group on a domain.""" - resp, body = self.put('domains/%s/groups/%s/roles/%s' % - (domain_id, group_id, role_id), None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_group_roles_on_project(self, project_id, group_id): - """list roles of a group on a project.""" - resp, body = self.get('projects/%s/groups/%s/roles' % - (project_id, group_id)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_group_roles_on_domain(self, domain_id, group_id): - """list roles of a group on a domain.""" - resp, body = self.get('domains/%s/groups/%s/roles' % - (domain_id, group_id)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_role_from_group_on_project(self, project_id, group_id, role_id): - """Delete role of a group on a project.""" - resp, body = self.delete('projects/%s/groups/%s/roles/%s' % - (project_id, group_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_role_from_group_on_domain(self, domain_id, group_id, role_id): - """Delete role of a group on a domain.""" - resp, body = self.delete('domains/%s/groups/%s/roles/%s' % - (domain_id, group_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def check_role_from_group_on_project_existence(self, project_id, - group_id, role_id): - """Check role of a group on a project.""" - resp, body = self.head('projects/%s/groups/%s/roles/%s' % - (project_id, group_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def check_role_from_group_on_domain_existence(self, domain_id, - group_id, role_id): - """Check role of a group on a domain.""" - resp, body = self.head('domains/%s/groups/%s/roles/%s' % - (domain_id, group_id, role_id)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def create_role_inference_rule(self, prior_role, implies_role): - """Create a role inference rule.""" - resp, body = self.put('roles/%s/implies/%s' % - (prior_role, implies_role), None) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_role_inference_rule(self, prior_role, implies_role): - """Get a role inference rule.""" - resp, body = self.get('roles/%s/implies/%s' % - (prior_role, implies_role)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_role_inferences_rules(self, prior_role): - """List the inferences rules from a role.""" - resp, body = self.get('roles/%s/implies' % prior_role) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_all_role_inference_rules(self): - """Lists all role inference rules. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#list-all-role-inference-rules - """ - resp, body = self.get('role_inferences') - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def check_role_inference_rule(self, prior_role, implies_role): - """Check a role inference rule.""" - resp, body = self.head('roles/%s/implies/%s' % - (prior_role, implies_role)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def delete_role_inference_rule(self, prior_role, implies_role): - """Delete a role inference rule.""" - resp, body = self.delete('roles/%s/implies/%s' % - (prior_role, implies_role)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) diff --git a/tempest/lib/services/identity/v3/services_client.py b/tempest/lib/services/identity/v3/services_client.py deleted file mode 100644 index 7bbe850b5..000000000 --- a/tempest/lib/services/identity/v3/services_client.py +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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. - -""" -https://developer.openstack.org/api-ref/identity/v3/index.html#service-catalog-and-endpoints -""" - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class ServicesClient(rest_client.RestClient): - api_version = "v3" - - def update_service(self, service_id, **kwargs): - """Updates a service. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#update-service - """ - patch_body = json.dumps({'service': kwargs}) - resp, body = self.patch('services/%s' % service_id, patch_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_service(self, service_id): - """Get Service.""" - url = 'services/%s' % service_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_service(self, **kwargs): - """Creates a service. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#create-service - """ - body = json.dumps({'service': kwargs}) - resp, body = self.post("services", body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_service(self, service_id): - url = "services/" + service_id - resp, body = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_services(self, **params): - """List services. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/#list-services - """ - url = 'services' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/token_client.py b/tempest/lib/services/identity/v3/token_client.py deleted file mode 100644 index 33f6f16fb..000000000 --- a/tempest/lib/services/identity/v3/token_client.py +++ /dev/null @@ -1,199 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 oslo_log import log as logging -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client -from tempest.lib import exceptions - - -class V3TokenClient(rest_client.RestClient): - - def __init__(self, auth_url, disable_ssl_certificate_validation=None, - ca_certs=None, trace_requests=None, **kwargs): - """Initialises the Token client - - :param auth_url: URL to which the token request is sent - :param disable_ssl_certificate_validation: pass-through to rest client - :param ca_certs: pass-through to rest client - :param trace_requests: pass-through to rest client - :param kwargs: any extra parameter to pass through the rest client. - Three kwargs are forbidden: region, service and auth_provider - as they are not meaningful for token client - """ - dscv = disable_ssl_certificate_validation - for unwanted_kwargs in ['region', 'service', 'auth_provider']: - kwargs.pop(unwanted_kwargs, None) - super(V3TokenClient, self).__init__( - None, None, None, disable_ssl_certificate_validation=dscv, - ca_certs=ca_certs, trace_requests=trace_requests, **kwargs) - - if auth_url is None: - raise exceptions.IdentityError("Couldn't determine auth_url") - - if 'auth/tokens' not in auth_url: - auth_url = auth_url.rstrip('/') + '/auth/tokens' - - self.auth_url = auth_url - - def auth(self, user_id=None, username=None, password=None, project_id=None, - project_name=None, user_domain_id=None, user_domain_name=None, - project_domain_id=None, project_domain_name=None, domain_id=None, - domain_name=None, token=None): - """Obtains a token from the authentication service - - :param user_id: user id - :param username: user name - :param user_domain_id: the user domain id - :param user_domain_name: the user domain name - :param project_domain_id: the project domain id - :param project_domain_name: the project domain name - :param domain_id: a domain id to scope to - :param domain_name: a domain name to scope to - :param project_id: a project id to scope to - :param project_name: a project name to scope to - :param token: a token to re-scope. - - Accepts different combinations of credentials. - Sample sample valid combinations: - - token - - token, project_name, project_domain_id - - user_id, password - - username, password, user_domain_id - - username, password, project_name, user_domain_id, project_domain_id - Validation is left to the server side. - """ - creds = { - 'auth': { - 'identity': { - 'methods': [], - } - } - } - id_obj = creds['auth']['identity'] - if token: - id_obj['methods'].append('token') - id_obj['token'] = { - 'id': token - } - - if (user_id or username) and password: - id_obj['methods'].append('password') - id_obj['password'] = { - 'user': { - 'password': password, - } - } - if user_id: - id_obj['password']['user']['id'] = user_id - else: - id_obj['password']['user']['name'] = username - - _domain = None - if user_domain_id is not None: - _domain = dict(id=user_domain_id) - elif user_domain_name is not None: - _domain = dict(name=user_domain_name) - if _domain: - id_obj['password']['user']['domain'] = _domain - - if (project_id or project_name): - _project = dict() - - if project_id: - _project['id'] = project_id - elif project_name: - _project['name'] = project_name - - if project_domain_id is not None: - _project['domain'] = {'id': project_domain_id} - elif project_domain_name is not None: - _project['domain'] = {'name': project_domain_name} - - creds['auth']['scope'] = dict(project=_project) - elif domain_id: - creds['auth']['scope'] = dict(domain={'id': domain_id}) - elif domain_name: - creds['auth']['scope'] = dict(domain={'name': domain_name}) - - body = json.dumps(creds, sort_keys=True) - resp, body = self.post(self.auth_url, body=body) - self.expected_success(201, resp.status) - return rest_client.ResponseBody(resp, body) - - def request(self, method, url, extra_headers=False, headers=None, - body=None, chunked=False): - """A simple HTTP request interface. - - Note: this overloads the `request` method from the parent class and - thus must implement the same method signature. - """ - if headers is None: - # Always accept 'json', for xml token client too. - # Because XML response is not easily - # converted to the corresponding JSON one - headers = self.get_headers(accept_type="json") - elif extra_headers: - try: - headers.update(self.get_headers(accept_type="json")) - except (ValueError, TypeError): - headers = self.get_headers(accept_type="json") - - resp, resp_body = self.raw_request(url, method, - headers=headers, body=body) - self._log_request(method, url, resp, req_headers=headers, - req_body='', resp_body=resp_body) - - if resp.status in [401, 403]: - resp_body = json.loads(resp_body) - raise exceptions.Unauthorized(resp_body['error']['message']) - elif resp.status not in [200, 201, 204]: - raise exceptions.IdentityError( - 'Unexpected status code {0}'.format(resp.status)) - - return resp, json.loads(resp_body) - - def get_token(self, **kwargs): - """Returns (token id, token data) for supplied credentials""" - - auth_data = kwargs.pop('auth_data', False) - - if not (kwargs.get('user_domain_id') or - kwargs.get('user_domain_name')): - kwargs['user_domain_name'] = 'Default' - - if not (kwargs.get('project_domain_id') or - kwargs.get('project_domain_name')): - kwargs['project_domain_name'] = 'Default' - - body = self.auth(**kwargs) - - token = body.response.get('x-subject-token') - if auth_data: - return token, body['token'] - else: - return token - - -class V3TokenClientJSON(V3TokenClient): - LOG = logging.getLogger(__name__) - - def _warn(self): - self.LOG.warning("%s class was deprecated and renamed to %s", - self.__class__.__name__, 'V3TokenClient') - - def __init__(self, *args, **kwargs): - self._warn() - super(V3TokenClientJSON, self).__init__(*args, **kwargs) diff --git a/tempest/lib/services/identity/v3/trusts_client.py b/tempest/lib/services/identity/v3/trusts_client.py deleted file mode 100644 index d113905d7..000000000 --- a/tempest/lib/services/identity/v3/trusts_client.py +++ /dev/null @@ -1,85 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class TrustsClient(rest_client.RestClient): - api_version = "v3" - - def create_trust(self, **kwargs): - """Creates a trust. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/index.html#create-trust - """ - post_body = json.dumps({'trust': kwargs}) - resp, body = self.post('OS-TRUST/trusts', post_body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_trust(self, trust_id): - """Deletes a trust.""" - resp, body = self.delete("OS-TRUST/trusts/%s" % trust_id) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_trusts(self, **params): - """Returns trusts - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3-ext/index.html#list-trusts - """ - url = "OS-TRUST/trusts/" - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_trust(self, trust_id): - """GET trust.""" - resp, body = self.get("OS-TRUST/trusts/%s" % trust_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_trust_roles(self, trust_id): - """GET roles delegated by a trust.""" - resp, body = self.get("OS-TRUST/trusts/%s/roles" % trust_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_trust_role(self, trust_id, role_id): - """GET role delegated by a trust.""" - resp, body = self.get("OS-TRUST/trusts/%s/roles/%s" - % (trust_id, role_id)) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def check_trust_role(self, trust_id, role_id): - """HEAD Check if role is delegated by a trust.""" - resp, body = self.head("OS-TRUST/trusts/%s/roles/%s" - % (trust_id, role_id)) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/users_client.py b/tempest/lib/services/identity/v3/users_client.py deleted file mode 100644 index e99a971aa..000000000 --- a/tempest/lib/services/identity/v3/users_client.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class UsersClient(rest_client.RestClient): - api_version = "v3" - - def create_user(self, **kwargs): - """Creates a user. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/#create-user - """ - post_body = json.dumps({'user': kwargs}) - resp, body = self.post('users', post_body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_user(self, user_id, **kwargs): - """Updates a user. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/#update-user - """ - if 'id' not in kwargs: - kwargs['id'] = user_id - post_body = json.dumps({'user': kwargs}) - resp, body = self.patch('users/%s' % user_id, post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_user_password(self, user_id, **kwargs): - """Update a user password - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/index.html#change-password-for-user - """ - update_user = json.dumps({'user': kwargs}) - resp, _ = self.post('users/%s/password' % user_id, update_user) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def list_user_projects(self, user_id, **params): - """Lists the projects on which a user has roles assigned. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/#list-projects-for-user - """ - url = 'users/%s/projects' % user_id - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_users(self, **params): - """Get the list of users. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/#list-users - """ - url = 'users' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_user(self, user_id): - """GET a user.""" - resp, body = self.get("users/%s" % user_id) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_user(self, user_id): - """Deletes a User.""" - resp, body = self.delete("users/%s" % user_id) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_user_groups(self, user_id, **params): - """Lists groups which a user belongs to. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/identity/v3/#list-groups-to-which-a-user-belongs - """ - url = 'users/%s/groups' % user_id - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/identity/v3/versions_client.py b/tempest/lib/services/identity/v3/versions_client.py deleted file mode 100644 index 441ee0dd8..000000000 --- a/tempest/lib/services/identity/v3/versions_client.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2017 NEC Corporation. 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 time - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class VersionsClient(rest_client.RestClient): - api_version = "v3" - - def list_versions(self): - """List API versions""" - version_url = self._get_base_version_url() - - start = time.time() - resp, body = self.raw_request(version_url, 'GET') - end = time.time() - self._log_request('GET', version_url, resp, secs=(end - start), - resp_body=body) - self._error_checker(resp, body) - - self.expected_success(300, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/image/__init__.py b/tempest/lib/services/image/__init__.py deleted file mode 100644 index 4b01663ea..000000000 --- a/tempest/lib/services/image/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# 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 tempest.lib.services.image import v1 -from tempest.lib.services.image import v2 - -__all__ = ['v1', 'v2'] diff --git a/tempest/lib/services/image/v1/__init__.py b/tempest/lib/services/image/v1/__init__.py deleted file mode 100644 index 9bd8262a8..000000000 --- a/tempest/lib/services/image/v1/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# 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 tempest.lib.services.image.v1.image_members_client import \ - ImageMembersClient -from tempest.lib.services.image.v1.images_client import ImagesClient - -__all__ = ['ImageMembersClient', 'ImagesClient'] diff --git a/tempest/lib/services/image/v1/image_members_client.py b/tempest/lib/services/image/v1/image_members_client.py deleted file mode 100644 index 231808722..000000000 --- a/tempest/lib/services/image/v1/image_members_client.py +++ /dev/null @@ -1,66 +0,0 @@ -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class ImageMembersClient(rest_client.RestClient): - api_version = "v1" - - def list_image_members(self, image_id): - """List all members of an image.""" - url = 'images/%s/members' % image_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_shared_images(self, tenant_id): - """List image memberships for the given tenant. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v1/#list-shared-images - """ - - url = 'shared-images/%s' % tenant_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_image_member(self, image_id, member_id, **kwargs): - """Add a member to an image. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v1/#add-member-to-image - """ - url = 'images/%s/members/%s' % (image_id, member_id) - body = json.dumps({'member': kwargs}) - resp, __ = self.put(url, body) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def delete_image_member(self, image_id, member_id): - """Removes a membership from the image. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v1/#remove-member - """ - url = 'images/%s/members/%s' % (image_id, member_id) - resp, __ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) diff --git a/tempest/lib/services/image/v1/images_client.py b/tempest/lib/services/image/v1/images_client.py deleted file mode 100644 index 42f8cf212..000000000 --- a/tempest/lib/services/image/v1/images_client.py +++ /dev/null @@ -1,155 +0,0 @@ -# Copyright 2013 IBM 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 functools - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - -CHUNKSIZE = 1024 * 64 # 64kB - - -class ImagesClient(rest_client.RestClient): - api_version = "v1" - - def _create_with_data(self, headers, data): - # We are going to do chunked transfert, so split the input data - # info fixed-sized chunks. - headers['Content-Type'] = 'application/octet-stream' - data = iter(functools.partial(data.read, CHUNKSIZE), b'') - resp, body = self.request('POST', 'images', - headers=headers, body=data, chunked=True) - self._error_checker(resp, body) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def _update_with_data(self, image_id, headers, data): - # We are going to do chunked transfert, so split the input data - # info fixed-sized chunks. - headers['Content-Type'] = 'application/octet-stream' - data = iter(functools.partial(data.read, CHUNKSIZE), b'') - url = 'images/%s' % image_id - resp, body = self.request('PUT', url, headers=headers, - body=data, chunked=True) - self._error_checker(resp, body) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - @property - def http(self): - if self._http is None: - self._http = self._get_http() - return self._http - - def create_image(self, data=None, headers=None): - """Create an image. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/image/v1/index.html#create-image - """ - if headers is None: - headers = {} - - if data is not None: - return self._create_with_data(headers, data) - - resp, body = self.post('images', None, headers) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_image(self, image_id, data=None, headers=None): - """Update an image. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/image/v1/index.html#update-image - """ - if headers is None: - headers = {} - - if data is not None: - return self._update_with_data(image_id, headers, data) - - url = 'images/%s' % image_id - resp, body = self.put(url, None, headers) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_image(self, image_id): - url = 'images/%s' % image_id - resp, body = self.delete(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_images(self, detail=False, **kwargs): - """Return a list of all images filtered by input parameters. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v1/#list-images - - Most parameters except the following are passed to the API without - any changes. - :param changes_since: The name is changed to changes-since - """ - url = 'images' - - if detail: - url += '/detail' - - if 'changes_since' in kwargs: - kwargs['changes-since'] = kwargs.pop('changes_since') - - if kwargs: - url += '?%s' % urllib.urlencode(kwargs) - - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def check_image(self, image_id): - """Check image metadata.""" - url = 'images/%s' % image_id - resp, body = self.head(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_image(self, image_id): - """Get image details plus the image itself.""" - url = 'images/%s' % image_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBodyData(resp, body) - - def is_resource_deleted(self, id): - try: - resp = self.check_image(id) - if resp.response["x-image-meta-status"] == 'deleted': - return True - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'image_meta' diff --git a/tempest/lib/services/image/v2/__init__.py b/tempest/lib/services/image/v2/__init__.py deleted file mode 100644 index 99a5321b9..000000000 --- a/tempest/lib/services/image/v2/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# 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 tempest.lib.services.image.v2.image_members_client import \ - ImageMembersClient -from tempest.lib.services.image.v2.images_client import ImagesClient -from tempest.lib.services.image.v2.namespace_objects_client import \ - NamespaceObjectsClient -from tempest.lib.services.image.v2.namespace_properties_client import \ - NamespacePropertiesClient -from tempest.lib.services.image.v2.namespace_tags_client import \ - NamespaceTagsClient -from tempest.lib.services.image.v2.namespaces_client import NamespacesClient -from tempest.lib.services.image.v2.resource_types_client import \ - ResourceTypesClient -from tempest.lib.services.image.v2.schemas_client import SchemasClient -from tempest.lib.services.image.v2.versions_client import VersionsClient - -__all__ = ['ImageMembersClient', 'ImagesClient', 'NamespaceObjectsClient', - 'NamespacePropertiesClient', 'NamespaceTagsClient', - 'NamespacesClient', 'ResourceTypesClient', 'SchemasClient', - 'VersionsClient'] diff --git a/tempest/lib/services/image/v2/image_members_client.py b/tempest/lib/services/image/v2/image_members_client.py deleted file mode 100644 index e5118a813..000000000 --- a/tempest/lib/services/image/v2/image_members_client.py +++ /dev/null @@ -1,84 +0,0 @@ -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class ImageMembersClient(rest_client.RestClient): - api_version = "v2" - - def list_image_members(self, image_id): - """List image members. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#list-image-members - """ - url = 'images/%s/members' % image_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_image_member(self, image_id, **kwargs): - """Create an image member. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#create-image-member - """ - url = 'images/%s/members' % image_id - data = json.dumps(kwargs) - resp, body = self.post(url, data) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_image_member(self, image_id, member_id, **kwargs): - """Update an image member. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#update-image-member - """ - url = 'images/%s/members/%s' % (image_id, member_id) - data = json.dumps(kwargs) - resp, body = self.put(url, data) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_image_member(self, image_id, member_id): - """Show an image member. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#show-image-member-details - """ - url = 'images/%s/members/%s' % (image_id, member_id) - resp, body = self.get(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, json.loads(body)) - - def delete_image_member(self, image_id, member_id): - """Delete an image member. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#delete-image-member - """ - url = 'images/%s/members/%s' % (image_id, member_id) - resp, _ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) diff --git a/tempest/lib/services/image/v2/images_client.py b/tempest/lib/services/image/v2/images_client.py deleted file mode 100644 index bcdae4454..000000000 --- a/tempest/lib/services/image/v2/images_client.py +++ /dev/null @@ -1,189 +0,0 @@ -# Copyright 2013 IBM 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 functools - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - -CHUNKSIZE = 1024 * 64 # 64kB - - -class ImagesClient(rest_client.RestClient): - api_version = "v2" - - def update_image(self, image_id, patch): - """Update an image. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/index.html#update-an-image - """ - data = json.dumps(patch) - headers = {"Content-Type": "application/openstack-images-v2.0" - "-json-patch"} - resp, body = self.patch('images/%s' % image_id, data, headers) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_image(self, **kwargs): - """Create an image. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/index.html#create-an-image - """ - data = json.dumps(kwargs) - resp, body = self.post('images', data) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def deactivate_image(self, image_id): - """Deactivate image. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#deactivate-image - """ - url = 'images/%s/actions/deactivate' % image_id - resp, body = self.post(url, None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def reactivate_image(self, image_id): - """Reactivate image. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#reactivate-image - """ - url = 'images/%s/actions/reactivate' % image_id - resp, body = self.post(url, None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_image(self, image_id): - """Delete image. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#delete-an-image - """ - url = 'images/%s' % image_id - resp, _ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def list_images(self, params=None): - """List images. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#show-images - """ - url = 'images' - - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_image(self, image_id): - """Show image details. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#show-image-details - """ - url = 'images/%s' % image_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_image(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'image' - - def store_image_file(self, image_id, data): - """Upload binary image data. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#upload-binary-image-data - """ - url = 'images/%s/file' % image_id - - # We are going to do chunked transfert, so split the input data - # info fixed-sized chunks. - headers = {'Content-Type': 'application/octet-stream'} - data = iter(functools.partial(data.read, CHUNKSIZE), b'') - - resp, body = self.request('PUT', url, headers=headers, - body=data, chunked=True) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_image_file(self, image_id): - """Download binary image data. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#download-binary-image-data - """ - url = 'images/%s/file' % image_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBodyData(resp, body) - - def add_image_tag(self, image_id, tag): - """Add an image tag. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#add-image-tag - """ - url = 'images/%s/tags/%s' % (image_id, tag) - resp, body = self.put(url, body=None) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_image_tag(self, image_id, tag): - """Delete an image tag. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/#delete-image-tag - """ - url = 'images/%s/tags/%s' % (image_id, tag) - resp, _ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) diff --git a/tempest/lib/services/image/v2/namespace_objects_client.py b/tempest/lib/services/image/v2/namespace_objects_client.py deleted file mode 100644 index ac2e63e98..000000000 --- a/tempest/lib/services/image/v2/namespace_objects_client.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2016 EasyStack. -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class NamespaceObjectsClient(rest_client.RestClient): - api_version = "v2" - - def list_namespace_objects(self, namespace, **kwargs): - """Lists all namespace objects. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#list-objects - """ - url = 'metadefs/namespaces/%s/objects' % namespace - if kwargs: - url += '?%s' % urllib.urlencode(kwargs) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_namespace_object(self, namespace, **kwargs): - """Create a namespace object - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#create-object - """ - url = 'metadefs/namespaces/%s/objects' % namespace - data = json.dumps(kwargs) - resp, body = self.post(url, data) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_namespace_object(self, namespace, object_name, **kwargs): - """Update a namespace object - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#update-object - """ - url = 'metadefs/namespaces/%s/objects/%s' % (namespace, object_name) - data = json.dumps(kwargs) - resp, body = self.put(url, data) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_namespace_object(self, namespace, object_name): - """Show a namespace object - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#show-object - """ - url = 'metadefs/namespaces/%s/objects/%s' % (namespace, object_name) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_namespace_object(self, namespace, object_name): - """Delete a namespace object - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#delete-object - """ - url = 'metadefs/namespaces/%s/objects/%s' % (namespace, object_name) - resp, _ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) diff --git a/tempest/lib/services/image/v2/namespace_properties_client.py b/tempest/lib/services/image/v2/namespace_properties_client.py deleted file mode 100644 index 1236b2b9c..000000000 --- a/tempest/lib/services/image/v2/namespace_properties_client.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2016 EasyStack. -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class NamespacePropertiesClient(rest_client.RestClient): - api_version = "v2" - - def list_namespace_properties(self, namespace): - """Lists property definitions in a namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#list-properties - """ - url = 'metadefs/namespaces/%s/properties' % namespace - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_namespace_property(self, namespace, **kwargs): - """Creates a property definition in a namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#create-property - """ - url = 'metadefs/namespaces/%s/properties' % namespace - data = json.dumps(kwargs) - resp, body = self.post(url, data) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_namespace_properties(self, namespace, property_name): - """Shows the definition for a property. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#show-property-definition - """ - url = 'metadefs/namespaces/%s/properties/%s' % (namespace, - property_name) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_namespace_properties(self, namespace, property_name, **kwargs): - """Updates a property definition. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#update-property-definition - """ - url = 'metadefs/namespaces/%s/properties/%s' % (namespace, - property_name) - data = json.dumps(kwargs) - resp, body = self.put(url, data) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_namespace_property(self, namespace, property_name): - """Removes a property definition from a namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#remove-property-definition - """ - url = 'metadefs/namespaces/%s/properties/%s' % (namespace, - property_name) - resp, _ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) diff --git a/tempest/lib/services/image/v2/namespace_tags_client.py b/tempest/lib/services/image/v2/namespace_tags_client.py deleted file mode 100644 index 61cc33ddc..000000000 --- a/tempest/lib/services/image/v2/namespace_tags_client.py +++ /dev/null @@ -1,125 +0,0 @@ -# Copyright 2016 EasyStack. -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class NamespaceTagsClient(rest_client.RestClient): - api_version = "v2" - - def create_namespace_tag(self, namespace, tag_name): - """Adds a tag to the list of namespace tag definitions. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#create-tag-definition - """ - url = 'metadefs/namespaces/%s/tags/%s' % (namespace, - tag_name) - resp, body = self.post(url, None) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_namespace_tag(self, namespace, tag_name): - """Gets a definition for a tag. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/image/v2/metadefs-index.html#get-tag-definition - """ - url = 'metadefs/namespaces/%s/tags/%s' % (namespace, - tag_name) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_namespace_tag(self, namespace, tag_name, **kwargs): - """Renames a tag definition. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#update-tag-definition - """ - url = 'metadefs/namespaces/%s/tags/%s' % (namespace, - tag_name) - data = json.dumps(kwargs) - resp, body = self.put(url, data) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_namespace_tag(self, namespace, tag_name): - """Deletes a tag definition within a namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#delete-tag-definition - """ - url = 'metadefs/namespaces/%s/tags/%s' % (namespace, tag_name) - resp, _ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def create_namespace_tags(self, namespace, **kwargs): - """Creates one or more tag definitions in a namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#create-tags - """ - url = 'metadefs/namespaces/%s/tags' % namespace - data = json.dumps(kwargs) - resp, body = self.post(url, data) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_namespace_tags(self, namespace, **params): - """Lists the tag definitions within a namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#list-tags - """ - url = 'metadefs/namespaces/%s/tags' % namespace - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_namespace_tags(self, namespace): - """Deletes all tag definitions within a namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#delete-all-tag-definitions - """ - url = 'metadefs/namespaces/%s/tags' % namespace - resp, _ = self.delete(url) - - # NOTE(rosmaita): Bug 1656183 fixed the success response code for - # this call to make it consistent with the other metadefs delete - # calls. Accept both codes in case tempest is being run against - # an old Glance. - self.expected_success([200, 204], resp.status) - - return rest_client.ResponseBody(resp) diff --git a/tempest/lib/services/image/v2/namespaces_client.py b/tempest/lib/services/image/v2/namespaces_client.py deleted file mode 100644 index b00de89f4..000000000 --- a/tempest/lib/services/image/v2/namespaces_client.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2013 IBM 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class NamespacesClient(rest_client.RestClient): - api_version = "v2" - - def create_namespace(self, **kwargs): - """Create a namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#create-namespace - """ - data = json.dumps(kwargs) - resp, body = self.post('metadefs/namespaces', data) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_namespaces(self): - """List namespaces - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#list-namespaces - """ - url = 'metadefs/namespaces' - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_namespace(self, namespace): - """Show namespace details. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#get-namespace-details - """ - url = 'metadefs/namespaces/%s' % namespace - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_namespace(self, namespace, **kwargs): - """Update a namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#update-namespace - """ - # NOTE: On Glance API, we need to pass namespace on both URI - # and a request body. - params = {'namespace': namespace} - params.update(kwargs) - data = json.dumps(params) - url = 'metadefs/namespaces/%s' % namespace - resp, body = self.put(url, body=data) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_namespace(self, namespace): - """Delete a namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#delete-namespace - """ - url = 'metadefs/namespaces/%s' % namespace - resp, _ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) diff --git a/tempest/lib/services/image/v2/resource_types_client.py b/tempest/lib/services/image/v2/resource_types_client.py deleted file mode 100644 index 13259d1c7..000000000 --- a/tempest/lib/services/image/v2/resource_types_client.py +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright 2013 IBM 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class ResourceTypesClient(rest_client.RestClient): - api_version = "v2" - - def list_resource_types(self): - """Lists all resource types. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#list-resource-types - """ - url = 'metadefs/resource_types' - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_resource_type_association(self, namespace_id, **kwargs): - """Creates a resource type association in given namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#create-resource-type-association - """ - url = 'metadefs/namespaces/%s/resource_types' % namespace_id - data = json.dumps(kwargs) - resp, body = self.post(url, data) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_resource_type_association(self, namespace_id): - """Lists resource type associations in given namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#list-resource-type-associations - """ - url = 'metadefs/namespaces/%s/resource_types' % namespace_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_resource_type_association(self, namespace_id, resource_name): - """Removes resource type association in given namespace. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/image/v2/metadefs-index.html#remove-resource-type-association - """ - url = 'metadefs/namespaces/%s/resource_types/%s' % (namespace_id, - resource_name) - resp, _ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) diff --git a/tempest/lib/services/image/v2/schemas_client.py b/tempest/lib/services/image/v2/schemas_client.py deleted file mode 100644 index 0c9db401c..000000000 --- a/tempest/lib/services/image/v2/schemas_client.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2013 IBM 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class SchemasClient(rest_client.RestClient): - api_version = "v2" - - def show_schema(self, schema): - url = 'schemas/%s' % schema - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/image/v2/versions_client.py b/tempest/lib/services/image/v2/versions_client.py deleted file mode 100644 index 1adc46694..000000000 --- a/tempest/lib/services/image/v2/versions_client.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2017 NEC Corporation. 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 time - -from oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class VersionsClient(rest_client.RestClient): - api_version = "v2" - - def list_versions(self): - """List API versions""" - version_url = self._get_base_version_url() - - start = time.time() - resp, body = self.raw_request(version_url, 'GET') - end = time.time() - self._log_request('GET', version_url, resp, secs=(end - start), - resp_body=body) - self._error_checker(resp, body) - - self.expected_success(300, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/network/__init__.py b/tempest/lib/services/network/__init__.py deleted file mode 100644 index 419e59393..000000000 --- a/tempest/lib/services/network/__init__.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# 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 tempest.lib.services.network.agents_client import AgentsClient -from tempest.lib.services.network.extensions_client import ExtensionsClient -from tempest.lib.services.network.floating_ips_client import FloatingIPsClient -from tempest.lib.services.network.metering_label_rules_client import \ - MeteringLabelRulesClient -from tempest.lib.services.network.metering_labels_client import \ - MeteringLabelsClient -from tempest.lib.services.network.networks_client import NetworksClient -from tempest.lib.services.network.ports_client import PortsClient -from tempest.lib.services.network.quotas_client import QuotasClient -from tempest.lib.services.network.routers_client import RoutersClient -from tempest.lib.services.network.security_group_rules_client import \ - SecurityGroupRulesClient -from tempest.lib.services.network.security_groups_client import \ - SecurityGroupsClient -from tempest.lib.services.network.service_providers_client import \ - ServiceProvidersClient -from tempest.lib.services.network.subnetpools_client import SubnetpoolsClient -from tempest.lib.services.network.subnets_client import SubnetsClient -from tempest.lib.services.network.tags_client import TagsClient -from tempest.lib.services.network.versions_client import NetworkVersionsClient - -__all__ = ['AgentsClient', 'ExtensionsClient', 'FloatingIPsClient', - 'MeteringLabelRulesClient', 'MeteringLabelsClient', - 'NetworksClient', 'NetworkVersionsClient', 'PortsClient', - 'QuotasClient', 'RoutersClient', 'SecurityGroupRulesClient', - 'SecurityGroupsClient', 'ServiceProvidersClient', - 'SubnetpoolsClient', 'SubnetsClient', 'TagsClient'] diff --git a/tempest/lib/services/network/agents_client.py b/tempest/lib/services/network/agents_client.py deleted file mode 100644 index 9bdf090b0..000000000 --- a/tempest/lib/services/network/agents_client.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 tempest.lib.services.network import base - - -class AgentsClient(base.BaseNetworkClient): - - def update_agent(self, agent_id, **kwargs): - """Update agent.""" - # TODO(piyush): Current api-site doesn't contain this API description. - # After fixing the api-site, we need to fix here also for putting the - # link to api-site. - # LP: https://bugs.launchpad.net/openstack-api-site/+bug/1526673 - uri = '/agents/%s' % agent_id - return self.update_resource(uri, kwargs) - - def show_agent(self, agent_id, **fields): - uri = '/agents/%s' % agent_id - return self.show_resource(uri, **fields) - - def list_agents(self, **filters): - uri = '/agents' - return self.list_resources(uri, **filters) - - def list_routers_on_l3_agent(self, agent_id): - uri = '/agents/%s/l3-routers' % agent_id - return self.list_resources(uri) - - def create_router_on_l3_agent(self, agent_id, **kwargs): - # TODO(piyush): Current api-site doesn't contain this API description. - # After fixing the api-site, we need to fix here also for putting the - # link to api-site. - # LP: https://bugs.launchpad.net/openstack-api-site/+bug/1526670 - uri = '/agents/%s/l3-routers' % agent_id - return self.create_resource(uri, kwargs, expect_empty_body=True) - - def delete_router_from_l3_agent(self, agent_id, router_id): - uri = '/agents/%s/l3-routers/%s' % (agent_id, router_id) - return self.delete_resource(uri) - - def list_networks_hosted_by_one_dhcp_agent(self, agent_id): - uri = '/agents/%s/dhcp-networks' % agent_id - return self.list_resources(uri) - - def delete_network_from_dhcp_agent(self, agent_id, network_id): - uri = '/agents/%s/dhcp-networks/%s' % (agent_id, - network_id) - return self.delete_resource(uri) - - def add_dhcp_agent_to_network(self, agent_id, **kwargs): - # TODO(piyush): Current api-site doesn't contain this API description. - # After fixing the api-site, we need to fix here also for putting the - # link to api-site. - # LP: https://bugs.launchpad.net/openstack-api-site/+bug/1526212 - uri = '/agents/%s/dhcp-networks' % agent_id - return self.create_resource(uri, kwargs, expect_empty_body=True) diff --git a/tempest/lib/services/network/base.py b/tempest/lib/services/network/base.py deleted file mode 100644 index fe8b244ea..000000000 --- a/tempest/lib/services/network/base.py +++ /dev/null @@ -1,85 +0,0 @@ -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class BaseNetworkClient(rest_client.RestClient): - - """Base class for Tempest REST clients for Neutron. - - Child classes use v2 of the Neutron API, since the V1 API has been - removed from the code base. - """ - - version = '2.0' - uri_prefix = "v2.0" - - def list_resources(self, uri, **filters): - req_uri = self.uri_prefix + uri - if filters: - req_uri += '?' + urllib.urlencode(filters, doseq=1) - resp, body = self.get(req_uri) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_resource(self, uri): - req_uri = self.uri_prefix + uri - resp, body = self.delete(req_uri) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_resource(self, uri, **fields): - # fields is a dict which key is 'fields' and value is a - # list of field's name. An example: - # {'fields': ['id', 'name']} - req_uri = self.uri_prefix + uri - if fields: - req_uri += '?' + urllib.urlencode(fields, doseq=1) - resp, body = self.get(req_uri) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_resource(self, uri, post_data, expect_empty_body=False, - expect_response_code=201): - req_uri = self.uri_prefix + uri - req_post_data = json.dumps(post_data) - resp, body = self.post(req_uri, req_post_data) - # NOTE: RFC allows both a valid non-empty body and an empty body for - # response of POST API. If a body is expected not empty, we decode the - # body. Otherwise we returns the body as it is. - if not expect_empty_body: - body = json.loads(body) - else: - body = None - self.expected_success(expect_response_code, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_resource(self, uri, post_data, expect_empty_body=False, - expect_response_code=200): - req_uri = self.uri_prefix + uri - req_post_data = json.dumps(post_data) - resp, body = self.put(req_uri, req_post_data) - # NOTE: RFC allows both a valid non-empty body and an empty body for - # response of PUT API. If a body is expected not empty, we decode the - # body. Otherwise we returns the body as it is. - if not expect_empty_body: - body = json.loads(body) - else: - body = None - self.expected_success(expect_response_code, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/network/extensions_client.py b/tempest/lib/services/network/extensions_client.py deleted file mode 100644 index 3910c849c..000000000 --- a/tempest/lib/services/network/extensions_client.py +++ /dev/null @@ -1,24 +0,0 @@ -# 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 tempest.lib.services.network import base - - -class ExtensionsClient(base.BaseNetworkClient): - - def show_extension(self, ext_alias, **fields): - uri = '/extensions/%s' % ext_alias - return self.show_resource(uri, **fields) - - def list_extensions(self, **filters): - uri = '/extensions' - return self.list_resources(uri, **filters) diff --git a/tempest/lib/services/network/floating_ips_client.py b/tempest/lib/services/network/floating_ips_client.py deleted file mode 100644 index 2bb18e03f..000000000 --- a/tempest/lib/services/network/floating_ips_client.py +++ /dev/null @@ -1,65 +0,0 @@ -# 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 tempest.lib.services.network import base - - -class FloatingIPsClient(base.BaseNetworkClient): - - def create_floatingip(self, **kwargs): - """Creates a floating IP. - - If you specify port information, associates the floating IP with an - internal port. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#create-floating-ip - """ - uri = '/floatingips' - post_data = {'floatingip': kwargs} - return self.create_resource(uri, post_data) - - def update_floatingip(self, floatingip_id, **kwargs): - """Updates a floating IP and its association with an internal port. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#update-floating-ip - """ - uri = '/floatingips/%s' % floatingip_id - post_data = {'floatingip': kwargs} - return self.update_resource(uri, post_data) - - def show_floatingip(self, floatingip_id, **fields): - """Shows details for a floating IP. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#show-floating-ip-details - """ - uri = '/floatingips/%s' % floatingip_id - return self.show_resource(uri, **fields) - - def delete_floatingip(self, floatingip_id): - uri = '/floatingips/%s' % floatingip_id - return self.delete_resource(uri) - - def list_floatingips(self, **filters): - """Lists floating IPs. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#list-floating-ips - """ - uri = '/floatingips' - return self.list_resources(uri, **filters) diff --git a/tempest/lib/services/network/metering_label_rules_client.py b/tempest/lib/services/network/metering_label_rules_client.py deleted file mode 100644 index 36cf8e30a..000000000 --- a/tempest/lib/services/network/metering_label_rules_client.py +++ /dev/null @@ -1,33 +0,0 @@ -# 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 tempest.lib.services.network import base - - -class MeteringLabelRulesClient(base.BaseNetworkClient): - - def create_metering_label_rule(self, **kwargs): - uri = '/metering/metering-label-rules' - post_data = {'metering_label_rule': kwargs} - return self.create_resource(uri, post_data) - - def show_metering_label_rule(self, metering_label_rule_id, **fields): - uri = '/metering/metering-label-rules/%s' % metering_label_rule_id - return self.show_resource(uri, **fields) - - def delete_metering_label_rule(self, metering_label_rule_id): - uri = '/metering/metering-label-rules/%s' % metering_label_rule_id - return self.delete_resource(uri) - - def list_metering_label_rules(self, **filters): - uri = '/metering/metering-label-rules' - return self.list_resources(uri, **filters) diff --git a/tempest/lib/services/network/metering_labels_client.py b/tempest/lib/services/network/metering_labels_client.py deleted file mode 100644 index 411da1f47..000000000 --- a/tempest/lib/services/network/metering_labels_client.py +++ /dev/null @@ -1,57 +0,0 @@ -# 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 tempest.lib.services.network import base - - -class MeteringLabelsClient(base.BaseNetworkClient): - - def create_metering_label(self, **kwargs): - """Creates an L3 metering label. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#create-metering-label - """ - uri = '/metering/metering-labels' - post_data = {'metering_label': kwargs} - return self.create_resource(uri, post_data) - - def show_metering_label(self, metering_label_id, **fields): - """Shows details for a metering label. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#show-metering-label-details - """ - uri = '/metering/metering-labels/%s' % metering_label_id - return self.show_resource(uri, **fields) - - def delete_metering_label(self, metering_label_id): - """Deletes an L3 metering label. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#delete-metering-label - """ - uri = '/metering/metering-labels/%s' % metering_label_id - return self.delete_resource(uri) - - def list_metering_labels(self, **filters): - """Lists all L3 metering labels that belong to the tenant. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#list-metering-labels - """ - uri = '/metering/metering-labels' - return self.list_resources(uri, **filters) diff --git a/tempest/lib/services/network/networks_client.py b/tempest/lib/services/network/networks_client.py deleted file mode 100644 index 77d482331..000000000 --- a/tempest/lib/services/network/networks_client.py +++ /dev/null @@ -1,76 +0,0 @@ -# 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 tempest.lib.services.network import base - - -class NetworksClient(base.BaseNetworkClient): - - def create_network(self, **kwargs): - """Creates a network. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#create-network - """ - uri = '/networks' - post_data = {'network': kwargs} - return self.create_resource(uri, post_data) - - def update_network(self, network_id, **kwargs): - """Updates a network. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#update-network - """ - uri = '/networks/%s' % network_id - post_data = {'network': kwargs} - return self.update_resource(uri, post_data) - - def show_network(self, network_id, **fields): - """Shows details for a network. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#show-network-details - """ - uri = '/networks/%s' % network_id - return self.show_resource(uri, **fields) - - def delete_network(self, network_id): - uri = '/networks/%s' % network_id - return self.delete_resource(uri) - - def list_networks(self, **filters): - """Lists networks to which the tenant has access. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#list-networks - """ - uri = '/networks' - return self.list_resources(uri, **filters) - - def create_bulk_networks(self, **kwargs): - """Create multiple networks in a single request. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#bulk-create-networks - """ - uri = '/networks' - return self.create_resource(uri, kwargs) - - def list_dhcp_agents_on_hosting_network(self, network_id): - uri = '/networks/%s/dhcp-agents' % network_id - return self.list_resources(uri) diff --git a/tempest/lib/services/network/ports_client.py b/tempest/lib/services/network/ports_client.py deleted file mode 100644 index daa15d759..000000000 --- a/tempest/lib/services/network/ports_client.py +++ /dev/null @@ -1,86 +0,0 @@ -# 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 tempest.lib import exceptions as lib_exc -from tempest.lib.services.network import base - - -class PortsClient(base.BaseNetworkClient): - - def create_port(self, **kwargs): - """Creates a port on a network. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#create-port - """ - uri = '/ports' - post_data = {'port': kwargs} - return self.create_resource(uri, post_data) - - def update_port(self, port_id, **kwargs): - """Updates a port. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#update-port - """ - uri = '/ports/%s' % port_id - post_data = {'port': kwargs} - return self.update_resource(uri, post_data) - - def show_port(self, port_id, **fields): - """Shows details for a port. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#show-port-details - """ - uri = '/ports/%s' % port_id - return self.show_resource(uri, **fields) - - def delete_port(self, port_id): - """Deletes a port. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#delete-port - """ - uri = '/ports/%s' % port_id - return self.delete_resource(uri) - - def list_ports(self, **filters): - """Lists ports to which the tenant has access. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#list-ports - """ - uri = '/ports' - return self.list_resources(uri, **filters) - - def create_bulk_ports(self, **kwargs): - """Create multiple ports in a single request. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#bulk-create-ports - """ - uri = '/ports' - return self.create_resource(uri, kwargs) - - def is_resource_deleted(self, id): - try: - self.show_port(id) - except lib_exc.NotFound: - return True - return False diff --git a/tempest/lib/services/network/quotas_client.py b/tempest/lib/services/network/quotas_client.py deleted file mode 100644 index 752b253f4..000000000 --- a/tempest/lib/services/network/quotas_client.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 tempest.lib.services.network import base - - -class QuotasClient(base.BaseNetworkClient): - - def update_quotas(self, tenant_id, **kwargs): - put_body = {'quota': kwargs} - uri = '/quotas/%s' % tenant_id - return self.update_resource(uri, put_body) - - def reset_quotas(self, tenant_id): # noqa - # NOTE: This noqa is for passing T111 check and we cannot rename - # to keep backwards compatibility. - uri = '/quotas/%s' % tenant_id - return self.delete_resource(uri) - - def show_quotas(self, tenant_id, **fields): - uri = '/quotas/%s' % tenant_id - return self.show_resource(uri, **fields) - - def list_quotas(self, **filters): - uri = '/quotas' - return self.list_resources(uri, **filters) diff --git a/tempest/lib/services/network/routers_client.py b/tempest/lib/services/network/routers_client.py deleted file mode 100644 index 19b7627df..000000000 --- a/tempest/lib/services/network/routers_client.py +++ /dev/null @@ -1,86 +0,0 @@ -# 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 tempest.lib.services.network import base - - -class RoutersClient(base.BaseNetworkClient): - - def create_router(self, **kwargs): - """Create a router. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#create-router - """ - post_body = {'router': kwargs} - uri = '/routers' - return self.create_resource(uri, post_body) - - def update_router(self, router_id, **kwargs): - """Updates a logical router. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#update-router - """ - uri = '/routers/%s' % router_id - update_body = {'router': kwargs} - return self.update_resource(uri, update_body) - - def show_router(self, router_id, **fields): - """Shows details for a router. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#show-router-details - """ - uri = '/routers/%s' % router_id - return self.show_resource(uri, **fields) - - def delete_router(self, router_id): - uri = '/routers/%s' % router_id - return self.delete_resource(uri) - - def list_routers(self, **filters): - """Lists logical routers. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#list-routers - """ - uri = '/routers' - return self.list_resources(uri, **filters) - - def add_router_interface(self, router_id, **kwargs): - """Add router interface. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#add-interface-to-router - """ - uri = '/routers/%s/add_router_interface' % router_id - return self.update_resource(uri, kwargs) - - def remove_router_interface(self, router_id, **kwargs): - """Remove router interface. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#remove-interface-from-router - """ - uri = '/routers/%s/remove_router_interface' % router_id - return self.update_resource(uri, kwargs) - - def list_l3_agents_hosting_router(self, router_id): - uri = '/routers/%s/l3-agents' % router_id - return self.list_resources(uri) diff --git a/tempest/lib/services/network/security_group_rules_client.py b/tempest/lib/services/network/security_group_rules_client.py deleted file mode 100644 index d2bc4a9c5..000000000 --- a/tempest/lib/services/network/security_group_rules_client.py +++ /dev/null @@ -1,51 +0,0 @@ -# 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 tempest.lib.services.network import base - - -class SecurityGroupRulesClient(base.BaseNetworkClient): - - def create_security_group_rule(self, **kwargs): - """Creates an OpenStack Networking security group rule. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#create-security-group-rule - """ - uri = '/security-group-rules' - post_data = {'security_group_rule': kwargs} - return self.create_resource(uri, post_data) - - def show_security_group_rule(self, security_group_rule_id, **fields): - """Shows detailed information for a security group rule. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#show-security-group-rule - """ - uri = '/security-group-rules/%s' % security_group_rule_id - return self.show_resource(uri, **fields) - - def delete_security_group_rule(self, security_group_rule_id): - uri = '/security-group-rules/%s' % security_group_rule_id - return self.delete_resource(uri) - - def list_security_group_rules(self, **filters): - """Lists a summary of all OpenStack Networking security group rules. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#list-security-group-rules - """ - uri = '/security-group-rules' - return self.list_resources(uri, **filters) diff --git a/tempest/lib/services/network/security_groups_client.py b/tempest/lib/services/network/security_groups_client.py deleted file mode 100644 index 1f30216f7..000000000 --- a/tempest/lib/services/network/security_groups_client.py +++ /dev/null @@ -1,68 +0,0 @@ -# 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 tempest.lib.services.network import base - - -class SecurityGroupsClient(base.BaseNetworkClient): - - def create_security_group(self, **kwargs): - """Creates an OpenStack Networking security group. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#create-security-group - """ - uri = '/security-groups' - post_data = {'security_group': kwargs} - return self.create_resource(uri, post_data) - - def update_security_group(self, security_group_id, **kwargs): - """Updates a security group. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#update-security-group - """ - uri = '/security-groups/%s' % security_group_id - post_data = {'security_group': kwargs} - return self.update_resource(uri, post_data) - - def show_security_group(self, security_group_id, **fields): - """Shows details for a security group. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#show-security-group - """ - uri = '/security-groups/%s' % security_group_id - return self.show_resource(uri, **fields) - - def delete_security_group(self, security_group_id): - """Deletes an OpenStack Networking security group. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#delete-security-group - """ - uri = '/security-groups/%s' % security_group_id - return self.delete_resource(uri) - - def list_security_groups(self, **filters): - """Lists OpenStack Networking security groups. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#list-security-groups - """ - uri = '/security-groups' - return self.list_resources(uri, **filters) diff --git a/tempest/lib/services/network/service_providers_client.py b/tempest/lib/services/network/service_providers_client.py deleted file mode 100644 index 0ee9bc32a..000000000 --- a/tempest/lib/services/network/service_providers_client.py +++ /dev/null @@ -1,21 +0,0 @@ -# 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 tempest.lib.services.network import base - - -class ServiceProvidersClient(base.BaseNetworkClient): - - def list_service_providers(self, **filters): - """Lists service providers.""" - uri = '/service-providers' - return self.list_resources(uri, **filters) diff --git a/tempest/lib/services/network/subnetpools_client.py b/tempest/lib/services/network/subnetpools_client.py deleted file mode 100644 index 7e77e3026..000000000 --- a/tempest/lib/services/network/subnetpools_client.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 tempest.lib.services.network import base - - -class SubnetpoolsClient(base.BaseNetworkClient): - - def list_subnetpools(self, **filters): - """Lists subnet pools to which the tenant has access. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#list-subnet-pools - """ - uri = '/subnetpools' - return self.list_resources(uri, **filters) - - def create_subnetpool(self, **kwargs): - """Creates a subnet pool. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#create-subnet-pool - """ - uri = '/subnetpools' - post_data = {'subnetpool': kwargs} - return self.create_resource(uri, post_data) - - def show_subnetpool(self, subnetpool_id, **fields): - """Shows information for a subnet pool. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#show-subnet-pool - """ - uri = '/subnetpools/%s' % subnetpool_id - return self.show_resource(uri, **fields) - - def update_subnetpool(self, subnetpool_id, **kwargs): - """Updates a subnet pool. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#update-subnet-pool - """ - uri = '/subnetpools/%s' % subnetpool_id - post_data = {'subnetpool': kwargs} - return self.update_resource(uri, post_data) - - def delete_subnetpool(self, subnetpool_id): - uri = '/subnetpools/%s' % subnetpool_id - return self.delete_resource(uri) diff --git a/tempest/lib/services/network/subnets_client.py b/tempest/lib/services/network/subnets_client.py deleted file mode 100644 index b843f840a..000000000 --- a/tempest/lib/services/network/subnets_client.py +++ /dev/null @@ -1,72 +0,0 @@ -# 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 tempest.lib.services.network import base - - -class SubnetsClient(base.BaseNetworkClient): - - def create_subnet(self, **kwargs): - """Creates a subnet on a network. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#create-subnet - """ - uri = '/subnets' - post_data = {'subnet': kwargs} - return self.create_resource(uri, post_data) - - def update_subnet(self, subnet_id, **kwargs): - """Updates a subnet. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#update-subnet - """ - uri = '/subnets/%s' % subnet_id - post_data = {'subnet': kwargs} - return self.update_resource(uri, post_data) - - def show_subnet(self, subnet_id, **fields): - """Shows details for a subnet. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#show-subnet-details - """ - uri = '/subnets/%s' % subnet_id - return self.show_resource(uri, **fields) - - def delete_subnet(self, subnet_id): - uri = '/subnets/%s' % subnet_id - return self.delete_resource(uri) - - def list_subnets(self, **filters): - """Lists subnets to which the tenant has access. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#list-subnets - """ - uri = '/subnets' - return self.list_resources(uri, **filters) - - def create_bulk_subnets(self, **kwargs): - """Create multiple subnets in a single request. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#bulk-create-subnet - """ - uri = '/subnets' - return self.create_resource(uri, kwargs) diff --git a/tempest/lib/services/network/tags_client.py b/tempest/lib/services/network/tags_client.py deleted file mode 100644 index 5d49a79c2..000000000 --- a/tempest/lib/services/network/tags_client.py +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client -from tempest.lib.services.network import base - - -class TagsClient(base.BaseNetworkClient): - - def create_tag(self, resource_type, resource_id, tag): - """Adds a tag on the resource. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#add-a-tag - """ - uri = '/%s/%s/tags/%s' % (resource_type, resource_id, tag) - return self.update_resource( - uri, json.dumps({}), expect_response_code=201, - expect_empty_body=True) - - def check_tag_existence(self, resource_type, resource_id, tag): - """Confirm that a given tag is set on the resource. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#confirm-a-tag - """ - # TODO(felipemonteiro): Use the "check_resource" method in - # ``BaseNetworkClient`` once it has been implemented. - uri = '%s/%s/%s/tags/%s' % ( - self.uri_prefix, resource_type, resource_id, tag) - resp, _ = self.get(uri) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def update_all_tags(self, resource_type, resource_id, tags): - """Replace all tags on the resource. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#replace-all-tags - """ - uri = '/%s/%s/tags' % (resource_type, resource_id) - put_body = {"tags": tags} - return self.update_resource(uri, put_body) - - def delete_tag(self, resource_type, resource_id, tag): - """Removes a tag on the resource. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#remove-a-tag - """ - uri = '/%s/%s/tags/%s' % (resource_type, resource_id, tag) - return self.delete_resource(uri) - - def delete_all_tags(self, resource_type, resource_id): - """Removes all tags on the resource. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#remove-all-tags - """ - uri = '/%s/%s/tags' % (resource_type, resource_id) - return self.delete_resource(uri) - - def list_tags(self, resource_type, resource_id): - """Retrieves the tags for a resource. - - For more information, please refer to the official API reference: - http://developer.openstack.org/api-ref/networking/v2/index.html#obtain-tag-list - """ - uri = '/%s/%s/tags' % (resource_type, resource_id) - return self.list_resources(uri) diff --git a/tempest/lib/services/network/versions_client.py b/tempest/lib/services/network/versions_client.py deleted file mode 100644 index a9c3bbfb8..000000000 --- a/tempest/lib/services/network/versions_client.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2016 VMware, Inc. 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 time - -from oslo_serialization import jsonutils as json -from six.moves import urllib - -from tempest.lib.services.network import base - - -class NetworkVersionsClient(base.BaseNetworkClient): - - def list_versions(self): - """Do a GET / to fetch available API version information.""" - - endpoint = self.base_url - url = urllib.parse.urlparse(endpoint) - version_url = '%s://%s/' % (url.scheme, url.netloc) - - # Note: we do a raw_request here because we want to use - # an unversioned URL, not "v2/$project_id/". - # Since raw_request doesn't log anything, we do that too. - start = time.time() - self._log_request_start('GET', version_url) - response, body = self.raw_request(version_url, 'GET') - self._error_checker(response, body) - end = time.time() - self._log_request('GET', version_url, response, - secs=(end - start), resp_body=body) - - self.response_checker('GET', response, body) - self.expected_success(200, response.status) - body = json.loads(body) - return body diff --git a/tempest/lib/services/volume/__init__.py b/tempest/lib/services/volume/__init__.py deleted file mode 100644 index 6855d8ee8..000000000 --- a/tempest/lib/services/volume/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# 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 tempest.lib.services.volume import v1 -from tempest.lib.services.volume import v2 -from tempest.lib.services.volume import v3 - -__all__ = ['v1', 'v2', 'v3'] diff --git a/tempest/lib/services/volume/base_client.py b/tempest/lib/services/volume/base_client.py deleted file mode 100644 index c7fb21a97..000000000 --- a/tempest/lib/services/volume/base_client.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2016 Andrew Kerr -# 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 tempest.lib.common import api_version_utils -from tempest.lib.common import rest_client - -VOLUME_MICROVERSION = None - - -class BaseClient(rest_client.RestClient): - """Base volume service clients class to support microversion.""" - api_microversion_header_name = 'Openstack-Api-Version' - - def get_headers(self, accept_type=None, send_type=None): - headers = super(BaseClient, self).get_headers( - accept_type=accept_type, send_type=send_type) - if VOLUME_MICROVERSION: - headers[self.api_microversion_header_name] = ('volume %s' % - VOLUME_MICROVERSION) - return headers - - def request(self, method, url, extra_headers=False, headers=None, - body=None, chunked=False): - - resp, resp_body = super(BaseClient, self).request( - method, url, extra_headers, headers, body, chunked) - if (VOLUME_MICROVERSION and - VOLUME_MICROVERSION != api_version_utils.LATEST_MICROVERSION): - api_version_utils.assert_version_header_matches_request( - self.api_microversion_header_name, - 'volume %s' % VOLUME_MICROVERSION, - resp) - return resp, resp_body diff --git a/tempest/lib/services/volume/v1/__init__.py b/tempest/lib/services/volume/v1/__init__.py deleted file mode 100644 index 7b5991f73..000000000 --- a/tempest/lib/services/volume/v1/__init__.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# 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 tempest.lib.services.volume.v1.availability_zone_client \ - import AvailabilityZoneClient -from tempest.lib.services.volume.v1.backups_client import BackupsClient -from tempest.lib.services.volume.v1.encryption_types_client import \ - EncryptionTypesClient -from tempest.lib.services.volume.v1.extensions_client import ExtensionsClient -from tempest.lib.services.volume.v1.hosts_client import HostsClient -from tempest.lib.services.volume.v1.limits_client import LimitsClient -from tempest.lib.services.volume.v1.qos_client import QosSpecsClient -from tempest.lib.services.volume.v1.quotas_client import QuotasClient -from tempest.lib.services.volume.v1.services_client import ServicesClient -from tempest.lib.services.volume.v1.snapshots_client import SnapshotsClient -from tempest.lib.services.volume.v1.types_client import TypesClient -from tempest.lib.services.volume.v1.volumes_client import VolumesClient - -__all__ = ['AvailabilityZoneClient', 'BackupsClient', 'EncryptionTypesClient', - 'ExtensionsClient', 'HostsClient', 'QosSpecsClient', 'QuotasClient', - 'ServicesClient', 'SnapshotsClient', 'TypesClient', 'VolumesClient', - 'LimitsClient'] diff --git a/tempest/lib/services/volume/v1/availability_zone_client.py b/tempest/lib/services/volume/v1/availability_zone_client.py deleted file mode 100644 index be4f53928..000000000 --- a/tempest/lib/services/volume/v1/availability_zone_client.py +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2014 NEC Corporation. -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class AvailabilityZoneClient(rest_client.RestClient): - """Volume V1 availability zone client.""" - - def list_availability_zones(self): - resp, body = self.get('os-availability-zone') - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v1/backups_client.py b/tempest/lib/services/volume/v1/backups_client.py deleted file mode 100644 index 867791374..000000000 --- a/tempest/lib/services/volume/v1/backups_client.py +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - - -class BackupsClient(rest_client.RestClient): - """Volume V1 Backups client""" - api_version = "v1" - - def create_backup(self, **kwargs): - """Creates a backup of volume. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#create-backup - """ - post_body = json.dumps({'backup': kwargs}) - resp, body = self.post('backups', post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def restore_backup(self, backup_id, **kwargs): - """Restore volume from backup. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#restore-backup - """ - post_body = json.dumps({'restore': kwargs}) - resp, body = self.post('backups/%s/restore' % (backup_id), post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_backup(self, backup_id): - """Delete a backup of volume.""" - resp, body = self.delete('backups/%s' % backup_id) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_backup(self, backup_id): - """Returns the details of a single backup.""" - url = "backups/%s" % backup_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_backups(self, detail=False): - """Information for all the tenant's backups.""" - url = "backups" - if detail: - url += "/detail" - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def export_backup(self, backup_id): - """Export backup metadata record.""" - url = "backups/%s/export_record" % backup_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def import_backup(self, **kwargs): - """Import backup metadata record.""" - post_body = json.dumps({'backup-record': kwargs}) - resp, body = self.post("backups/import_record", post_body) - body = json.loads(body) - self.expected_success(201, resp.status) - return rest_client.ResponseBody(resp, body) - - def reset_backup_status(self, backup_id, status): - """Reset the specified backup's status.""" - post_body = json.dumps({'os-reset_status': {"status": status}}) - resp, body = self.post('backups/%s/action' % backup_id, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_backup(id) - except lib_exc.NotFound: - return True - return False diff --git a/tempest/lib/services/volume/v1/encryption_types_client.py b/tempest/lib/services/volume/v1/encryption_types_client.py deleted file mode 100755 index 067b4e823..000000000 --- a/tempest/lib/services/volume/v1/encryption_types_client.py +++ /dev/null @@ -1,68 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - - -class EncryptionTypesClient(rest_client.RestClient): - - def is_resource_deleted(self, id): - try: - body = self.show_encryption_type(id) - if not body: - return True - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'encryption-type' - - def show_encryption_type(self, volume_type_id): - """Get the volume encryption type for the specified volume type. - - volume_type_id: Id of volume_type. - """ - url = "/types/%s/encryption" % volume_type_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_encryption_type(self, volume_type_id, **kwargs): - """Create encryption type. - - TODO: Current api-site doesn't contain this API description. - After fixing the api-site, we need to fix here also for putting - the link to api-site. - """ - url = "/types/%s/encryption" % volume_type_id - post_body = json.dumps({'encryption': kwargs}) - resp, body = self.post(url, post_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_encryption_type(self, volume_type_id): - """Delete the encryption type for the specified volume-type.""" - resp, body = self.delete( - "/types/%s/encryption/provider" % volume_type_id) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v1/extensions_client.py b/tempest/lib/services/volume/v1/extensions_client.py deleted file mode 100644 index 7b849a83d..000000000 --- a/tempest/lib/services/volume/v1/extensions_client.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class ExtensionsClient(rest_client.RestClient): - """Volume V1 extensions client.""" - - def list_extensions(self): - url = 'extensions' - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v1/hosts_client.py b/tempest/lib/services/volume/v1/hosts_client.py deleted file mode 100644 index 56ba12c5b..000000000 --- a/tempest/lib/services/volume/v1/hosts_client.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2013 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class HostsClient(rest_client.RestClient): - """Client class to send CRUD Volume Host API V1 requests""" - - def list_hosts(self, **params): - """Lists all hosts.""" - - url = 'os-hosts' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v1/limits_client.py b/tempest/lib/services/volume/v1/limits_client.py deleted file mode 100644 index e14b2dc92..000000000 --- a/tempest/lib/services/volume/v1/limits_client.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class LimitsClient(rest_client.RestClient): - """Volume V1 limits client.""" - - api_version = "v1" - - def show_limits(self): - """Returns the details of a volume absolute limits.""" - url = "limits" - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v1/qos_client.py b/tempest/lib/services/volume/v1/qos_client.py deleted file mode 100644 index e247b7b7c..000000000 --- a/tempest/lib/services/volume/v1/qos_client.py +++ /dev/null @@ -1,131 +0,0 @@ -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - - -class QosSpecsClient(rest_client.RestClient): - """Volume V1 QoS client. - - Client class to send CRUD QoS API requests - """ - - api_version = "v1" - - def is_resource_deleted(self, qos_id): - try: - self.show_qos(qos_id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'qos' - - def create_qos(self, **kwargs): - """Create a QoS Specification. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#create-qos-specification - """ - post_body = json.dumps({'qos_specs': kwargs}) - resp, body = self.post('qos-specs', post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_qos(self, qos_id, force=False): - """Delete the specified QoS specification.""" - resp, body = self.delete( - "qos-specs/%s?force=%s" % (qos_id, force)) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_qos(self): - """List all the QoS specifications created.""" - url = 'qos-specs' - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_qos(self, qos_id): - """Get the specified QoS specification.""" - url = "qos-specs/%s" % qos_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def set_qos_key(self, qos_id, **kwargs): - """Set the specified keys/values of QoS specification. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#set-keys-in-qos-specification - """ - put_body = json.dumps({"qos_specs": kwargs}) - resp, body = self.put('qos-specs/%s' % qos_id, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def unset_qos_key(self, qos_id, keys): - """Unset the specified keys of QoS specification. - - :param keys: keys to delete from the QoS specification. - - TODO(jordanP): Add a link once LP #1524877 is fixed. - """ - put_body = json.dumps({'keys': keys}) - resp, body = self.put('qos-specs/%s/delete_keys' % qos_id, put_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def associate_qos(self, qos_id, vol_type_id): - """Associate the specified QoS with specified volume-type.""" - url = "qos-specs/%s/associate" % qos_id - url += "?vol_type_id=%s" % vol_type_id - resp, body = self.get(url) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_association_qos(self, qos_id): - """Get the association of the specified QoS specification.""" - url = "qos-specs/%s/associations" % qos_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def disassociate_qos(self, qos_id, vol_type_id): - """Disassociate the specified QoS with specified volume-type.""" - url = "qos-specs/%s/disassociate" % qos_id - url += "?vol_type_id=%s" % vol_type_id - resp, body = self.get(url) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def disassociate_all_qos(self, qos_id): - """Disassociate the specified QoS with all associations.""" - url = "qos-specs/%s/disassociate_all" % qos_id - resp, body = self.get(url) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v1/quotas_client.py b/tempest/lib/services/volume/v1/quotas_client.py deleted file mode 100644 index 678fd8234..000000000 --- a/tempest/lib/services/volume/v1/quotas_client.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright (C) 2014 eNovance SAS -# -# 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 oslo_serialization import jsonutils -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class QuotasClient(rest_client.RestClient): - """Client class to send CRUD Volume Quotas API V1 requests""" - - def show_default_quota_set(self, tenant_id): - """List the default volume quota set for a tenant.""" - - url = 'os-quota-sets/%s/defaults' % tenant_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = jsonutils.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_quota_set(self, tenant_id, params=None): - """List the quota set for a tenant.""" - - url = 'os-quota-sets/%s' % tenant_id - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = jsonutils.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_quota_set(self, tenant_id, **kwargs): - """Updates quota set - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref-blockstorage-v1.html#updateQuota - """ - put_body = jsonutils.dumps({'quota_set': kwargs}) - resp, body = self.put('os-quota-sets/%s' % tenant_id, put_body) - self.expected_success(200, resp.status) - body = jsonutils.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_quota_set(self, tenant_id): - """Delete the tenant's quota set.""" - resp, body = self.delete('os-quota-sets/%s' % tenant_id) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v1/services_client.py b/tempest/lib/services/volume/v1/services_client.py deleted file mode 100644 index d438a34ec..000000000 --- a/tempest/lib/services/volume/v1/services_client.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2014 NEC Corporation -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class ServicesClient(rest_client.RestClient): - """Volume V1 volume services client""" - - def list_services(self, **params): - url = 'os-services' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v1/snapshots_client.py b/tempest/lib/services/volume/v1/snapshots_client.py deleted file mode 100644 index 3433e6811..000000000 --- a/tempest/lib/services/volume/v1/snapshots_client.py +++ /dev/null @@ -1,186 +0,0 @@ -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - - -class SnapshotsClient(rest_client.RestClient): - """Client class to send CRUD Volume V1 API requests.""" - - create_resp = 200 - - def list_snapshots(self, detail=False, **params): - """List all the snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#list-snapshots-with-details-v1 - """ - url = 'snapshots' - if detail: - url += '/detail' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_snapshot(self, snapshot_id): - """Returns the details of a single snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#show-snapshot-details-v1 - """ - url = "snapshots/%s" % snapshot_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_snapshot(self, **kwargs): - """Creates a new snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#create-snapshot-v1 - """ - post_body = json.dumps({'snapshot': kwargs}) - resp, body = self.post('snapshots', post_body) - body = json.loads(body) - self.expected_success(self.create_resp, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_snapshot(self, snapshot_id): - """Delete Snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#delete-snapshot-v1 - """ - resp, body = self.delete("snapshots/%s" % snapshot_id) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_snapshot(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'volume-snapshot' - - def reset_snapshot_status(self, snapshot_id, status): - """Reset the specified snapshot's status.""" - post_body = json.dumps({'os-reset_status': {"status": status}}) - resp, body = self.post('snapshots/%s/action' % snapshot_id, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_snapshot_status(self, snapshot_id, **kwargs): - """Update the specified snapshot's status.""" - # TODO(gmann): api-site doesn't contain doc ref - # for this API. After fixing the api-site, we need to - # add the link here. - # Bug https://bugs.launchpad.net/openstack-api-site/+bug/1532645 - - post_body = json.dumps({'os-update_snapshot_status': kwargs}) - url = 'snapshots/%s/action' % snapshot_id - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_snapshot_metadata(self, snapshot_id, metadata): - """Create metadata for the snapshot.""" - put_body = json.dumps({'metadata': metadata}) - url = "snapshots/%s/metadata" % snapshot_id - resp, body = self.post(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_snapshot(self, snapshot_id, **kwargs): - """Updates a snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#update-snapshot-v1 - """ - put_body = json.dumps({'snapshot': kwargs}) - resp, body = self.put('snapshots/%s' % snapshot_id, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_snapshot_metadata(self, snapshot_id): - """Get metadata of the snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#show-snapshot-metadata-v1 - """ - url = "snapshots/%s/metadata" % snapshot_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_snapshot_metadata(self, snapshot_id, **kwargs): - """Update metadata for the snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#update-snapshot-metadata-v1 - """ - put_body = json.dumps(kwargs) - url = "snapshots/%s/metadata" % snapshot_id - resp, body = self.put(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_snapshot_metadata_item(self, snapshot_id, id, **kwargs): - """Update metadata item for the snapshot.""" - # TODO(piyush): Current api-site doesn't contain this API description. - # After fixing the api-site, we need to fix here also for putting the - # link to api-site. - # LP: https://bugs.launchpad.net/openstack-api-site/+bug/1529064 - put_body = json.dumps(kwargs) - url = "snapshots/%s/metadata/%s" % (snapshot_id, id) - resp, body = self.put(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_snapshot_metadata_item(self, snapshot_id, id): - """Delete metadata item for the snapshot.""" - url = "snapshots/%s/metadata/%s" % (snapshot_id, id) - resp, body = self.delete(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def force_delete_snapshot(self, snapshot_id): - """Force Delete Snapshot.""" - post_body = json.dumps({'os-force_delete': {}}) - resp, body = self.post('snapshots/%s/action' % snapshot_id, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v1/types_client.py b/tempest/lib/services/volume/v1/types_client.py deleted file mode 100644 index 4ae99357d..000000000 --- a/tempest/lib/services/volume/v1/types_client.py +++ /dev/null @@ -1,165 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - - -class TypesClient(rest_client.RestClient): - """Client class to send CRUD Volume Types API requests""" - - def is_resource_deleted(self, id): - try: - self.show_volume_type(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'volume-type' - - def list_volume_types(self, **params): - """List all the volume_types created. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#list-volume-types-v1 - """ - url = 'types' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_volume_type(self, volume_type_id): - """Returns the details of a single volume_type. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#show-volume-type-v1 - """ - url = "types/%s" % volume_type_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_volume_type(self, **kwargs): - """Create volume type. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#create-volume-type-v1 - """ - post_body = json.dumps({'volume_type': kwargs}) - resp, body = self.post('types', post_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_volume_type(self, volume_type_id): - """Deletes the Specified Volume_type. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#delete-volume-type-v1 - """ - resp, body = self.delete("types/%s" % volume_type_id) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_volume_types_extra_specs(self, volume_type_id, **params): - """List all the volume_types extra specs created. - - TODO: Current api-site doesn't contain this API description. - After fixing the api-site, we need to fix here also for putting - the link to api-site. - """ - url = 'types/%s/extra_specs' % volume_type_id - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_volume_type_extra_specs(self, volume_type_id, extra_specs_name): - """Returns the details of a single volume_type extra spec.""" - url = "types/%s/extra_specs/%s" % (volume_type_id, extra_specs_name) - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_volume_type_extra_specs(self, volume_type_id, extra_specs): - """Creates a new Volume_type extra spec. - - volume_type_id: Id of volume_type. - extra_specs: A dictionary of values to be used as extra_specs. - """ - url = "types/%s/extra_specs" % volume_type_id - post_body = json.dumps({'extra_specs': extra_specs}) - resp, body = self.post(url, post_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_volume_type_extra_specs(self, volume_type_id, extra_spec_name): - """Deletes the Specified Volume_type extra spec.""" - resp, body = self.delete("types/%s/extra_specs/%s" % ( - volume_type_id, extra_spec_name)) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume_type(self, volume_type_id, **kwargs): - """Updates volume type name, description, and/or is_public. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#update-volume-type-v1 - """ - put_body = json.dumps({'volume_type': kwargs}) - resp, body = self.put('types/%s' % volume_type_id, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume_type_extra_specs(self, volume_type_id, extra_spec_name, - extra_specs): - """Update a volume_type extra spec. - - volume_type_id: Id of volume_type. - extra_spec_name: Name of the extra spec to be updated. - extra_spec: A dictionary of with key as extra_spec_name and the - updated value. - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#update-extra-specs-for-a-volume-type-v1 - """ - url = "types/%s/extra_specs/%s" % (volume_type_id, extra_spec_name) - put_body = json.dumps(extra_specs) - resp, body = self.put(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v1/volumes_client.py b/tempest/lib/services/volume/v1/volumes_client.py deleted file mode 100644 index 7a256979f..000000000 --- a/tempest/lib/services/volume/v1/volumes_client.py +++ /dev/null @@ -1,301 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json -import six -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - - -class VolumesClient(rest_client.RestClient): - """Client class to send CRUD Volume V1 API requests""" - - def _prepare_params(self, params): - """Prepares params for use in get or _ext_get methods. - - If params is a string it will be left as it is, but if it's not it will - be urlencoded. - """ - if isinstance(params, six.string_types): - return params - return urllib.urlencode(params) - - def list_volumes(self, detail=False, params=None): - """List all the volumes created. - - Params can be a string (must be urlencoded) or a dictionary. - """ - url = 'volumes' - if detail: - url += '/detail' - if params: - url += '?%s' % self._prepare_params(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_volume(self, volume_id): - """Returns the details of a single volume.""" - url = "volumes/%s" % volume_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_volume(self, **kwargs): - """Creates a new Volume. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#create-volume - """ - post_body = json.dumps({'volume': kwargs}) - resp, body = self.post('volumes', post_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume(self, volume_id, **kwargs): - """Updates the Specified Volume. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#update-volume - """ - put_body = json.dumps({'volume': kwargs}) - resp, body = self.put('volumes/%s' % volume_id, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_volume(self, volume_id): - """Deletes the Specified Volume.""" - resp, body = self.delete("volumes/%s" % volume_id) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def upload_volume(self, volume_id, **kwargs): - """Uploads a volume in Glance.""" - post_body = json.dumps({'os-volume_upload_image': kwargs}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def attach_volume(self, volume_id, **kwargs): - """Attaches a volume to a given instance on a given mountpoint. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#attach-volume - """ - post_body = json.dumps({'os-attach': kwargs}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def set_bootable_volume(self, volume_id, **kwargs): - """set a bootable flag for a volume - true or false.""" - post_body = json.dumps({'os-set_bootable': kwargs}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def detach_volume(self, volume_id): - """Detaches a volume from an instance.""" - post_body = json.dumps({'os-detach': {}}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def reserve_volume(self, volume_id): - """Reserves a volume.""" - post_body = json.dumps({'os-reserve': {}}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def unreserve_volume(self, volume_id): - """Restore a reserved volume .""" - post_body = json.dumps({'os-unreserve': {}}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_volume(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'volume' - - def extend_volume(self, volume_id, **kwargs): - """Extend a volume. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#extend-volume - """ - post_body = json.dumps({'os-extend': kwargs}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def reset_volume_status(self, volume_id, **kwargs): - """Reset the Specified Volume's Status. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#reset-volume-status - """ - post_body = json.dumps({'os-reset_status': kwargs}) - resp, body = self.post('volumes/%s/action' % volume_id, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_volume_transfer(self, **kwargs): - """Create a volume transfer. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#create-volume-transfer - """ - post_body = json.dumps({'transfer': kwargs}) - resp, body = self.post('os-volume-transfer', post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_volume_transfer(self, transfer_id): - """Returns the details of a volume transfer.""" - url = "os-volume-transfer/%s" % transfer_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_volume_transfers(self, **params): - """List all the volume transfers created. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#list-volume-transfers - """ - url = 'os-volume-transfer' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_volume_transfer(self, transfer_id): - """Delete a volume transfer.""" - resp, body = self.delete("os-volume-transfer/%s" % transfer_id) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def accept_volume_transfer(self, transfer_id, **kwargs): - """Accept a volume transfer. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v1/#accept-volume-transfer - """ - url = 'os-volume-transfer/%s/accept' % transfer_id - post_body = json.dumps({'accept': kwargs}) - resp, body = self.post(url, post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume_readonly(self, volume_id, **kwargs): - """Update the Specified Volume readonly.""" - post_body = json.dumps({'os-update_readonly_flag': kwargs}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def force_delete_volume(self, volume_id): - """Force Delete Volume.""" - post_body = json.dumps({'os-force_delete': {}}) - resp, body = self.post('volumes/%s/action' % volume_id, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_volume_metadata(self, volume_id, metadata): - """Create metadata for the volume.""" - put_body = json.dumps({'metadata': metadata}) - url = "volumes/%s/metadata" % volume_id - resp, body = self.post(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_volume_metadata(self, volume_id): - """Get metadata of the volume.""" - url = "volumes/%s/metadata" % volume_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume_metadata(self, volume_id, metadata): - """Update metadata for the volume.""" - put_body = json.dumps({'metadata': metadata}) - url = "volumes/%s/metadata" % volume_id - resp, body = self.put(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume_metadata_item(self, volume_id, id, meta_item): - """Update metadata item for the volume.""" - put_body = json.dumps({'meta': meta_item}) - url = "volumes/%s/metadata/%s" % (volume_id, id) - resp, body = self.put(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_volume_metadata_item(self, volume_id, id): - """Delete metadata item for the volume.""" - url = "volumes/%s/metadata/%s" % (volume_id, id) - resp, body = self.delete(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def retype_volume(self, volume_id, **kwargs): - """Updates volume with new volume type.""" - post_body = json.dumps({'os-retype': kwargs}) - resp, body = self.post('volumes/%s/action' % volume_id, post_body) - self.expected_success(202, resp.status) diff --git a/tempest/lib/services/volume/v2/__init__.py b/tempest/lib/services/volume/v2/__init__.py deleted file mode 100644 index 68982d99e..000000000 --- a/tempest/lib/services/volume/v2/__init__.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# 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 tempest.lib.services.volume.v2.availability_zone_client \ - import AvailabilityZoneClient -from tempest.lib.services.volume.v2.backups_client import BackupsClient -from tempest.lib.services.volume.v2.capabilities_client import \ - CapabilitiesClient -from tempest.lib.services.volume.v2.encryption_types_client import \ - EncryptionTypesClient -from tempest.lib.services.volume.v2.extensions_client import ExtensionsClient -from tempest.lib.services.volume.v2.hosts_client import HostsClient -from tempest.lib.services.volume.v2.limits_client import LimitsClient -from tempest.lib.services.volume.v2.qos_client import QosSpecsClient -from tempest.lib.services.volume.v2.quota_classes_client import \ - QuotaClassesClient -from tempest.lib.services.volume.v2.quotas_client import QuotasClient -from tempest.lib.services.volume.v2.scheduler_stats_client import \ - SchedulerStatsClient -from tempest.lib.services.volume.v2.services_client import ServicesClient -from tempest.lib.services.volume.v2.snapshot_manage_client import \ - SnapshotManageClient -from tempest.lib.services.volume.v2.snapshots_client import SnapshotsClient -from tempest.lib.services.volume.v2.transfers_client import TransfersClient -from tempest.lib.services.volume.v2.types_client import TypesClient -from tempest.lib.services.volume.v2.volume_manage_client import \ - VolumeManageClient -from tempest.lib.services.volume.v2.volumes_client import VolumesClient - -__all__ = ['AvailabilityZoneClient', 'BackupsClient', 'EncryptionTypesClient', - 'ExtensionsClient', 'HostsClient', 'QosSpecsClient', 'QuotasClient', - 'ServicesClient', 'SnapshotsClient', 'TypesClient', 'VolumesClient', - 'LimitsClient', 'CapabilitiesClient', 'SchedulerStatsClient', - 'SnapshotManageClient', 'VolumeManageClient', 'TransfersClient', - 'QuotaClassesClient'] diff --git a/tempest/lib/services/volume/v2/availability_zone_client.py b/tempest/lib/services/volume/v2/availability_zone_client.py deleted file mode 100644 index bb4a357f4..000000000 --- a/tempest/lib/services/volume/v2/availability_zone_client.py +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2014 IBM 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class AvailabilityZoneClient(rest_client.RestClient): - api_version = "v2" - - def list_availability_zones(self): - resp, body = self.get('os-availability-zone') - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/backups_client.py b/tempest/lib/services/volume/v2/backups_client.py deleted file mode 100644 index 830fb82fe..000000000 --- a/tempest/lib/services/volume/v2/backups_client.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.volume import base_client - - -class BackupsClient(base_client.BaseClient): - """Volume V2 Backups client""" - api_version = "v2" - - def create_backup(self, **kwargs): - """Creates a backup of volume. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/index.html#create-backup - """ - post_body = json.dumps({'backup': kwargs}) - resp, body = self.post('backups', post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def restore_backup(self, backup_id, **kwargs): - """Restore volume from backup. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/index.html#restore-backup - """ - post_body = json.dumps({'restore': kwargs}) - resp, body = self.post('backups/%s/restore' % (backup_id), post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_backup(self, backup_id): - """Delete a backup of volume.""" - resp, body = self.delete('backups/%s' % backup_id) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_backup(self, backup_id): - """Returns the details of a single backup.""" - url = "backups/%s" % backup_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_backups(self, detail=False, **params): - """List all the tenant's backups. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#list-backups - http://developer.openstack.org/api-ref/block-storage/v2/#list-backups-with-details - """ - url = "backups" - if detail: - url += "/detail" - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def export_backup(self, backup_id): - """Export backup metadata record.""" - url = "backups/%s/export_record" % backup_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def import_backup(self, **kwargs): - """Import backup metadata record.""" - post_body = json.dumps({'backup-record': kwargs}) - resp, body = self.post("backups/import_record", post_body) - body = json.loads(body) - self.expected_success(201, resp.status) - return rest_client.ResponseBody(resp, body) - - def reset_backup_status(self, backup_id, status): - """Reset the specified backup's status.""" - post_body = json.dumps({'os-reset_status': {"status": status}}) - resp, body = self.post('backups/%s/action' % backup_id, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_backup(id) - except lib_exc.NotFound: - return True - return False diff --git a/tempest/lib/services/volume/v2/capabilities_client.py b/tempest/lib/services/volume/v2/capabilities_client.py deleted file mode 100644 index 240be135d..000000000 --- a/tempest/lib/services/volume/v2/capabilities_client.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class CapabilitiesClient(rest_client.RestClient): - api_version = "v2" - - def show_backend_capabilities(self, host): - """Shows capabilities for a storage back end. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/index.html#show-back-end-capabilities - """ - url = 'capabilities/%s' % host - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/encryption_types_client.py b/tempest/lib/services/volume/v2/encryption_types_client.py deleted file mode 100755 index 20f3356b4..000000000 --- a/tempest/lib/services/volume/v2/encryption_types_client.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - - -class EncryptionTypesClient(rest_client.RestClient): - api_version = "v2" - - def is_resource_deleted(self, id): - try: - body = self.show_encryption_type(id) - if not body: - return True - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'encryption-type' - - def show_encryption_type(self, volume_type_id): - """Get the volume encryption type for the specified volume type. - - volume_type_id: Id of volume_type. - """ - url = "/types/%s/encryption" % volume_type_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_encryption_type(self, volume_type_id, **kwargs): - """Create encryption type. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#create-an-encryption-type-for-v2 - """ - url = "/types/%s/encryption" % volume_type_id - post_body = json.dumps({'encryption': kwargs}) - resp, body = self.post(url, post_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_encryption_type(self, volume_type_id): - """Delete the encryption type for the specified volume-type.""" - resp, body = self.delete( - "/types/%s/encryption/provider" % volume_type_id) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_encryption_type(self, volume_type_id, **kwargs): - """Update an encryption type for an existing volume type. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#update-an-encryption-type-for-v2 - """ - url = "/types/%s/encryption/provider" % volume_type_id - put_body = json.dumps({'encryption': kwargs}) - resp, body = self.put(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/extensions_client.py b/tempest/lib/services/volume/v2/extensions_client.py deleted file mode 100644 index 09279d578..000000000 --- a/tempest/lib/services/volume/v2/extensions_client.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright 2014 IBM 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class ExtensionsClient(rest_client.RestClient): - """Volume V2 extensions client.""" - api_version = "v2" - - def list_extensions(self): - url = 'extensions' - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/hosts_client.py b/tempest/lib/services/volume/v2/hosts_client.py deleted file mode 100644 index f44bda391..000000000 --- a/tempest/lib/services/volume/v2/hosts_client.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class HostsClient(rest_client.RestClient): - """Client class to send CRUD Volume V2 API requests""" - api_version = "v2" - - def list_hosts(self, **params): - """Lists all hosts. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#list-all-hosts - """ - url = 'os-hosts' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_host(self, host_name): - """Show host details.""" - url = 'os-hosts/%s' % host_name - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/limits_client.py b/tempest/lib/services/volume/v2/limits_client.py deleted file mode 100644 index ce9fba9b9..000000000 --- a/tempest/lib/services/volume/v2/limits_client.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class LimitsClient(rest_client.RestClient): - """Volume V2 limits client.""" - - api_version = "v2" - - def show_limits(self): - """Returns the details of a volume absolute limits.""" - url = "limits" - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/qos_client.py b/tempest/lib/services/volume/v2/qos_client.py deleted file mode 100644 index 47d3914cb..000000000 --- a/tempest/lib/services/volume/v2/qos_client.py +++ /dev/null @@ -1,133 +0,0 @@ -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - - -class QosSpecsClient(rest_client.RestClient): - """Volume V2 QoS client. - - Client class to send CRUD QoS API requests - """ - - api_version = "v2" - - def is_resource_deleted(self, qos_id): - try: - self.show_qos(qos_id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'qos' - - def create_qos(self, **kwargs): - """Create a QoS Specification. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#create-qos-specification - """ - post_body = json.dumps({'qos_specs': kwargs}) - resp, body = self.post('qos-specs', post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_qos(self, qos_id, force=False): - """Delete the specified QoS specification.""" - resp, body = self.delete( - "qos-specs/%s?force=%s" % (qos_id, force)) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_qos(self): - """List all the QoS specifications created.""" - url = 'qos-specs' - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_qos(self, qos_id): - """Get the specified QoS specification.""" - url = "qos-specs/%s" % qos_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def set_qos_key(self, qos_id, **kwargs): - """Set the specified keys/values of QoS specification. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#set-keys-in-qos-specification - """ - put_body = json.dumps({"qos_specs": kwargs}) - resp, body = self.put('qos-specs/%s' % qos_id, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def unset_qos_key(self, qos_id, keys): - """Unset the specified keys of QoS specification. - - :param keys: keys to delete from the QoS specification. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#unset-keys-in-qos-specification - """ - put_body = json.dumps({'keys': keys}) - resp, body = self.put('qos-specs/%s/delete_keys' % qos_id, put_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def associate_qos(self, qos_id, vol_type_id): - """Associate the specified QoS with specified volume-type.""" - url = "qos-specs/%s/associate" % qos_id - url += "?vol_type_id=%s" % vol_type_id - resp, body = self.get(url) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_association_qos(self, qos_id): - """Get the association of the specified QoS specification.""" - url = "qos-specs/%s/associations" % qos_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def disassociate_qos(self, qos_id, vol_type_id): - """Disassociate the specified QoS with specified volume-type.""" - url = "qos-specs/%s/disassociate" % qos_id - url += "?vol_type_id=%s" % vol_type_id - resp, body = self.get(url) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def disassociate_all_qos(self, qos_id): - """Disassociate the specified QoS with all associations.""" - url = "qos-specs/%s/disassociate_all" % qos_id - resp, body = self.get(url) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/quota_classes_client.py b/tempest/lib/services/volume/v2/quota_classes_client.py deleted file mode 100644 index d40d2d9c7..000000000 --- a/tempest/lib/services/volume/v2/quota_classes_client.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class QuotaClassesClient(rest_client.RestClient): - """Volume quota class V2 client.""" - - api_version = "v2" - - def show_quota_class_set(self, quota_class_id): - """List quotas for a quota class. - - TODO: Current api-site doesn't contain this API description. - LP: https://bugs.launchpad.net/nova/+bug/1602400 - """ - url = 'os-quota-class-sets/%s' % quota_class_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_quota_class_set(self, quota_class_id, **kwargs): - """Update quotas for a quota class. - - TODO: Current api-site doesn't contain this API description. - LP: https://bugs.launchpad.net/nova/+bug/1602400 - """ - url = 'os-quota-class-sets/%s' % quota_class_id - put_body = json.dumps({'quota_class_set': kwargs}) - resp, body = self.put(url, put_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/quotas_client.py b/tempest/lib/services/volume/v2/quotas_client.py deleted file mode 100644 index e4b289509..000000000 --- a/tempest/lib/services/volume/v2/quotas_client.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# 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 oslo_serialization import jsonutils -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class QuotasClient(rest_client.RestClient): - """Client class to send CRUD Volume Quotas API V2 requests""" - api_version = "v2" - - def show_default_quota_set(self, tenant_id): - """List the default volume quota set for a tenant.""" - - url = 'os-quota-sets/%s/defaults' % tenant_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = jsonutils.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_quota_set(self, tenant_id, params=None): - """List the quota set for a tenant.""" - - url = 'os-quota-sets/%s' % tenant_id - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = jsonutils.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_quota_set(self, tenant_id, **kwargs): - """Updates quota set - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/index.html#update-quotas - """ - put_body = jsonutils.dumps({'quota_set': kwargs}) - resp, body = self.put('os-quota-sets/%s' % tenant_id, put_body) - self.expected_success(200, resp.status) - body = jsonutils.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_quota_set(self, tenant_id): - """Delete the tenant's quota set.""" - resp, body = self.delete('os-quota-sets/%s' % tenant_id) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/scheduler_stats_client.py b/tempest/lib/services/volume/v2/scheduler_stats_client.py deleted file mode 100644 index 0d04f85d2..000000000 --- a/tempest/lib/services/volume/v2/scheduler_stats_client.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class SchedulerStatsClient(rest_client.RestClient): - api_version = "v2" - - def list_pools(self, detail=False): - """List all the volumes pools (hosts). - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/index.html#list-back-end-storage-pools - """ - url = 'scheduler-stats/get_pools' - if detail: - url += '?detail=True' - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/services_client.py b/tempest/lib/services/volume/v2/services_client.py deleted file mode 100644 index bc554696d..000000000 --- a/tempest/lib/services/volume/v2/services_client.py +++ /dev/null @@ -1,34 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class ServicesClient(rest_client.RestClient): - """Client class to send CRUD Volume V2 API requests""" - api_version = "v2" - - def list_services(self, **params): - url = 'os-services' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/snapshot_manage_client.py b/tempest/lib/services/volume/v2/snapshot_manage_client.py deleted file mode 100644 index aecd30b1d..000000000 --- a/tempest/lib/services/volume/v2/snapshot_manage_client.py +++ /dev/null @@ -1,33 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class SnapshotManageClient(rest_client.RestClient): - """Snapshot manage V2 client.""" - - api_version = "v2" - - def manage_snapshot(self, **kwargs): - """Manage a snapshot.""" - post_body = json.dumps({'snapshot': kwargs}) - url = 'os-snapshot-manage' - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/snapshots_client.py b/tempest/lib/services/volume/v2/snapshots_client.py deleted file mode 100644 index 4bc2842a6..000000000 --- a/tempest/lib/services/volume/v2/snapshots_client.py +++ /dev/null @@ -1,208 +0,0 @@ -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - - -class SnapshotsClient(rest_client.RestClient): - """Client class to send CRUD Volume V2 API requests.""" - api_version = "v2" - create_resp = 202 - - def list_snapshots(self, detail=False, **params): - """List all the snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#list-snapshots-with-details - http://developer.openstack.org/api-ref/block-storage/v2/#list-snapshots - """ - url = 'snapshots' - if detail: - url += '/detail' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_snapshot(self, snapshot_id): - """Returns the details of a single snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#show-snapshot-details - """ - url = "snapshots/%s" % snapshot_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_snapshot(self, **kwargs): - """Creates a new snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#create-snapshot - """ - post_body = json.dumps({'snapshot': kwargs}) - resp, body = self.post('snapshots', post_body) - body = json.loads(body) - self.expected_success(self.create_resp, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_snapshot(self, snapshot_id, **kwargs): - """Updates a snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#update-snapshot - """ - put_body = json.dumps({'snapshot': kwargs}) - resp, body = self.put('snapshots/%s' % snapshot_id, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_snapshot(self, snapshot_id): - """Delete Snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#delete-snapshot - """ - resp, body = self.delete("snapshots/%s" % snapshot_id) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_snapshot(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'volume-snapshot' - - def reset_snapshot_status(self, snapshot_id, status): - """Reset the specified snapshot's status.""" - post_body = json.dumps({'os-reset_status': {"status": status}}) - resp, body = self.post('snapshots/%s/action' % snapshot_id, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_snapshot_status(self, snapshot_id, **kwargs): - """Update the specified snapshot's status.""" - # TODO(gmann): api-site doesn't contain doc ref - # for this API. After fixing the api-site, we need to - # add the link here. - # Bug https://bugs.launchpad.net/openstack-api-site/+bug/1532645 - - post_body = json.dumps({'os-update_snapshot_status': kwargs}) - url = 'snapshots/%s/action' % snapshot_id - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_snapshot_metadata(self, snapshot_id, metadata): - """Create metadata for the snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#create-snapshot-metadata - """ - put_body = json.dumps({'metadata': metadata}) - url = "snapshots/%s/metadata" % snapshot_id - resp, body = self.post(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_snapshot_metadata(self, snapshot_id): - """Get metadata of the snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#show-snapshot-metadata - """ - url = "snapshots/%s/metadata" % snapshot_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_snapshot_metadata(self, snapshot_id, **kwargs): - """Update metadata for the snapshot. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#update-snapshot-metadata - """ - put_body = json.dumps(kwargs) - url = "snapshots/%s/metadata" % snapshot_id - resp, body = self.put(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_snapshot_metadata_item(self, snapshot_id, id): - """Show metadata item for the snapshot.""" - url = "snapshots/%s/metadata/%s" % (snapshot_id, id) - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_snapshot_metadata_item(self, snapshot_id, id, **kwargs): - """Update metadata item for the snapshot.""" - # TODO(piyush): Current api-site doesn't contain this API description. - # After fixing the api-site, we need to fix here also for putting the - # link to api-site. - # LP: https://bugs.launchpad.net/openstack-api-site/+bug/1529064 - put_body = json.dumps(kwargs) - url = "snapshots/%s/metadata/%s" % (snapshot_id, id) - resp, body = self.put(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_snapshot_metadata_item(self, snapshot_id, id): - """Delete metadata item for the snapshot.""" - url = "snapshots/%s/metadata/%s" % (snapshot_id, id) - resp, body = self.delete(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def force_delete_snapshot(self, snapshot_id): - """Force Delete Snapshot.""" - post_body = json.dumps({'os-force_delete': {}}) - resp, body = self.post('snapshots/%s/action' % snapshot_id, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def unmanage_snapshot(self, snapshot_id): - """Unmanage a snapshot.""" - post_body = json.dumps({'os-unmanage': {}}) - url = 'snapshots/%s/action' % (snapshot_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/transfers_client.py b/tempest/lib/services/volume/v2/transfers_client.py deleted file mode 100644 index 2dfbe7bb1..000000000 --- a/tempest/lib/services/volume/v2/transfers_client.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class TransfersClient(rest_client.RestClient): - """Client class to send CRUD Volume Transfer V2 API requests""" - api_version = "v2" - - def create_volume_transfer(self, **kwargs): - """Create a volume transfer. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#create-volume-transfer - """ - post_body = json.dumps({'transfer': kwargs}) - resp, body = self.post('os-volume-transfer', post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_volume_transfer(self, transfer_id): - """Returns the details of a volume transfer.""" - url = "os-volume-transfer/%s" % transfer_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_volume_transfers(self, detail=False, **params): - """List all the volume transfers created. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#list-volume-transfers - https://developer.openstack.org/api-ref/block-storage/v2/#list-volume-transfers-with-details - """ - url = 'os-volume-transfer' - if detail: - url += '/detail' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_volume_transfer(self, transfer_id): - """Delete a volume transfer.""" - resp, body = self.delete("os-volume-transfer/%s" % transfer_id) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def accept_volume_transfer(self, transfer_id, **kwargs): - """Accept a volume transfer. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#accept-volume-transfer - """ - url = 'os-volume-transfer/%s/accept' % transfer_id - post_body = json.dumps({'accept': kwargs}) - resp, body = self.post(url, post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/types_client.py b/tempest/lib/services/volume/v2/types_client.py deleted file mode 100644 index af4fd8cd6..000000000 --- a/tempest/lib/services/volume/v2/types_client.py +++ /dev/null @@ -1,205 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - - -class TypesClient(rest_client.RestClient): - """Client class to send CRUD Volume V2 API requests""" - api_version = "v2" - - def is_resource_deleted(self, id): - try: - self.show_volume_type(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'volume-type' - - def list_volume_types(self, **params): - """List all the volume_types created. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#list-all-volume-types-for-v2 - """ - url = 'types' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_volume_type(self, volume_type_id): - """Returns the details of a single volume_type. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#show-volume-type-details-for-v2 - """ - url = "types/%s" % volume_type_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_volume_type(self, **kwargs): - """Create volume type. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#create-volume-type-for-v2 - """ - post_body = json.dumps({'volume_type': kwargs}) - resp, body = self.post('types', post_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_volume_type(self, volume_type_id): - """Deletes the Specified Volume_type. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#delete-volume-type - """ - resp, body = self.delete("types/%s" % volume_type_id) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_volume_types_extra_specs(self, volume_type_id, **params): - """List all the volume_types extra specs created. - - TODO: Current api-site doesn't contain this API description. - After fixing the api-site, we need to fix here also for putting - the link to api-site. - """ - url = 'types/%s/extra_specs' % volume_type_id - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_volume_type_extra_specs(self, volume_type_id, extra_specs_name): - """Returns the details of a single volume_type extra spec.""" - url = "types/%s/extra_specs/%s" % (volume_type_id, extra_specs_name) - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_volume_type_extra_specs(self, volume_type_id, extra_specs): - """Creates a new Volume_type extra spec. - - volume_type_id: Id of volume_type. - extra_specs: A dictionary of values to be used as extra_specs. - """ - url = "types/%s/extra_specs" % volume_type_id - post_body = json.dumps({'extra_specs': extra_specs}) - resp, body = self.post(url, post_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_volume_type_extra_specs(self, volume_type_id, extra_spec_name): - """Deletes the Specified Volume_type extra spec.""" - resp, body = self.delete("types/%s/extra_specs/%s" % ( - volume_type_id, extra_spec_name)) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume_type(self, volume_type_id, **kwargs): - """Updates volume type name, description, and/or is_public. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#update-volume-type - """ - put_body = json.dumps({'volume_type': kwargs}) - resp, body = self.put('types/%s' % volume_type_id, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume_type_extra_specs(self, volume_type_id, extra_spec_name, - extra_specs): - """Update a volume_type extra spec. - - volume_type_id: Id of volume_type. - extra_spec_name: Name of the extra spec to be updated. - extra_spec: A dictionary of with key as extra_spec_name and the - updated value. - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#update-extra-specs-for-a-volume-type - """ - url = "types/%s/extra_specs/%s" % (volume_type_id, extra_spec_name) - put_body = json.dumps(extra_specs) - resp, body = self.put(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def add_type_access(self, volume_type_id, **kwargs): - """Adds volume type access for the given project. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#add-private-volume-type-access - """ - post_body = json.dumps({'addProjectAccess': kwargs}) - url = 'types/%s/action' % volume_type_id - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def remove_type_access(self, volume_type_id, **kwargs): - """Removes volume type access for the given project. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#remove-private-volume-type-access - """ - post_body = json.dumps({'removeProjectAccess': kwargs}) - url = 'types/%s/action' % volume_type_id - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_type_access(self, volume_type_id): - """Print access information about the given volume type. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#list-private-volume-type-access-details - """ - url = 'types/%s/os-volume-type-access' % volume_type_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/volume_manage_client.py b/tempest/lib/services/volume/v2/volume_manage_client.py deleted file mode 100644 index 12f4240a5..000000000 --- a/tempest/lib/services/volume/v2/volume_manage_client.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class VolumeManageClient(rest_client.RestClient): - """Volume manage V2 client.""" - - api_version = "v2" - - def manage_volume(self, **kwargs): - """Manage existing volume. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#manage-existing-volume - """ - post_body = json.dumps({'volume': kwargs}) - resp, body = self.post('os-volume-manage', post_body) - self.expected_success(202, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v2/volumes_client.py b/tempest/lib/services/volume/v2/volumes_client.py deleted file mode 100644 index 62b9992dd..000000000 --- a/tempest/lib/services/volume/v2/volumes_client.py +++ /dev/null @@ -1,396 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 debtcollector import moves -from debtcollector import removals -from oslo_serialization import jsonutils as json -import six -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.volume import base_client -from tempest.lib.services.volume.v2 import transfers_client - - -class VolumesClient(base_client.BaseClient): - """Client class to send CRUD Volume V2 API requests""" - api_version = "v2" - - create_volume_transfer = moves.moved_function( - transfers_client.TransfersClient.create_volume_transfer, - 'VolumesClient.create_volume_transfer', __name__, - message='Use create_volume_transfer from new location.', - version='Pike', removal_version='Queens') - - show_volume_transfer = moves.moved_function( - transfers_client.TransfersClient.show_volume_transfer, - 'VolumesClient.show_volume_transfer', __name__, - message='Use show_volume_transfer from new location.', - version='Pike', removal_version='Queens') - - list_volume_transfers = moves.moved_function( - transfers_client.TransfersClient.list_volume_transfers, - 'VolumesClient.list_volume_transfers', __name__, - message='Use list_volume_transfer from new location.', - version='Pike', removal_version='Queens') - - delete_volume_transfer = moves.moved_function( - transfers_client.TransfersClient.delete_volume_transfer, - 'VolumesClient.delete_volume_transfer', __name__, - message='Use delete_volume_transfer from new location.', - version='Pike', removal_version='Queens') - - accept_volume_transfer = moves.moved_function( - transfers_client.TransfersClient.accept_volume_transfer, - 'VolumesClient.accept_volume_transfer', __name__, - message='Use accept_volume_transfer from new location.', - version='Pike', removal_version='Queens') - - def _prepare_params(self, params): - """Prepares params for use in get or _ext_get methods. - - If params is a string it will be left as it is, but if it's not it will - be urlencoded. - """ - if isinstance(params, six.string_types): - return params - return urllib.urlencode(params) - - def list_volumes(self, detail=False, params=None): - """List all the volumes created. - - Params can be a string (must be urlencoded) or a dictionary. - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#list-volumes-with-details - http://developer.openstack.org/api-ref/block-storage/v2/#list-volumes - """ - url = 'volumes' - if detail: - url += '/detail' - if params: - url += '?%s' % self._prepare_params(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_volume(self, volume_id): - """Returns the details of a single volume.""" - url = "volumes/%s" % volume_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_volume(self, **kwargs): - """Creates a new Volume. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#create-volume - """ - post_body = json.dumps({'volume': kwargs}) - resp, body = self.post('volumes', post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume(self, volume_id, **kwargs): - """Updates the Specified Volume. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#update-volume - """ - put_body = json.dumps({'volume': kwargs}) - resp, body = self.put('volumes/%s' % volume_id, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_volume(self, volume_id, **params): - """Deletes the Specified Volume. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#delete-volume - """ - url = 'volumes/%s' % volume_id - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.delete(url) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def upload_volume(self, volume_id, **kwargs): - """Uploads a volume in Glance.""" - post_body = json.dumps({'os-volume_upload_image': kwargs}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def attach_volume(self, volume_id, **kwargs): - """Attaches a volume to a given instance on a given mountpoint. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#attach-volume-to-server - """ - post_body = json.dumps({'os-attach': kwargs}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def set_bootable_volume(self, volume_id, **kwargs): - """Set a bootable flag for a volume - true or false. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#update-volume-bootable-status - """ - post_body = json.dumps({'os-set_bootable': kwargs}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def detach_volume(self, volume_id): - """Detaches a volume from an instance.""" - post_body = json.dumps({'os-detach': {}}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def reserve_volume(self, volume_id): - """Reserves a volume.""" - post_body = json.dumps({'os-reserve': {}}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def unreserve_volume(self, volume_id): - """Restore a reserved volume .""" - post_body = json.dumps({'os-unreserve': {}}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_volume(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'volume' - - def extend_volume(self, volume_id, **kwargs): - """Extend a volume. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#extend-volume-size - """ - post_body = json.dumps({'os-extend': kwargs}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def reset_volume_status(self, volume_id, **kwargs): - """Reset the Specified Volume's Status. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#reset-volume-statuses - """ - post_body = json.dumps({'os-reset_status': kwargs}) - resp, body = self.post('volumes/%s/action' % volume_id, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume_readonly(self, volume_id, **kwargs): - """Update the Specified Volume readonly.""" - post_body = json.dumps({'os-update_readonly_flag': kwargs}) - url = 'volumes/%s/action' % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def force_delete_volume(self, volume_id): - """Force Delete Volume.""" - post_body = json.dumps({'os-force_delete': {}}) - resp, body = self.post('volumes/%s/action' % volume_id, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def create_volume_metadata(self, volume_id, metadata): - """Create metadata for the volume. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#create-volume-metadata - """ - put_body = json.dumps({'metadata': metadata}) - url = "volumes/%s/metadata" % volume_id - resp, body = self.post(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_volume_metadata(self, volume_id): - """Get metadata of the volume.""" - url = "volumes/%s/metadata" % volume_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume_metadata(self, volume_id, metadata): - """Update metadata for the volume. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#update-volume-metadata - """ - put_body = json.dumps({'metadata': metadata}) - url = "volumes/%s/metadata" % volume_id - resp, body = self.put(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_volume_metadata_item(self, volume_id, id): - """Show metadata item for the volume.""" - url = "volumes/%s/metadata/%s" % (volume_id, id) - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume_metadata_item(self, volume_id, id, meta_item): - """Update metadata item for the volume.""" - put_body = json.dumps({'meta': meta_item}) - url = "volumes/%s/metadata/%s" % (volume_id, id) - resp, body = self.put(url, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_volume_metadata_item(self, volume_id, id): - """Delete metadata item for the volume.""" - url = "volumes/%s/metadata/%s" % (volume_id, id) - resp, body = self.delete(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def retype_volume(self, volume_id, **kwargs): - """Updates volume with new volume type. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#retype-volume - """ - post_body = json.dumps({'os-retype': kwargs}) - resp, body = self.post('volumes/%s/action' % volume_id, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def force_detach_volume(self, volume_id, **kwargs): - """Force detach a volume. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#force-detach-volume - """ - post_body = json.dumps({'os-force_detach': kwargs}) - url = 'volumes/%s/action' % volume_id - resp, body = self.post(url, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def update_volume_image_metadata(self, volume_id, **kwargs): - """Update image metadata for the volume. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#set-image-metadata-for-volume - """ - post_body = json.dumps({'os-set_image_metadata': {'metadata': kwargs}}) - url = "volumes/%s/action" % (volume_id) - resp, body = self.post(url, post_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_volume_image_metadata(self, volume_id, key_name): - """Delete image metadata item for the volume.""" - post_body = json.dumps({'os-unset_image_metadata': {'key': key_name}}) - url = "volumes/%s/action" % (volume_id) - resp, body = self.post(url, post_body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - @removals.remove(message="use list_pools from tempest.lib.services." - "volume.v2.scheduler_stats_client") - def show_pools(self, detail=False): - # List all the volumes pools (hosts) - url = 'scheduler-stats/get_pools' - if detail: - url += '?detail=True' - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - @removals.remove(message="use show_backend_capabilities from tempest.lib." - "services.volume.v2.capabilities_client") - def show_backend_capabilities(self, host): - """Shows capabilities for a storage back end. - - For a full list of available parameters, please refer to the official - API reference: - http://developer.openstack.org/api-ref/block-storage/v2/#show-back-end-capabilities - """ - url = 'capabilities/%s' % host - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def unmanage_volume(self, volume_id): - """Unmanage volume. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v2/#unmanage-volume - """ - post_body = json.dumps({'os-unmanage': {}}) - resp, body = self.post('volumes/%s/action' % volume_id, post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v3/__init__.py b/tempest/lib/services/volume/v3/__init__.py deleted file mode 100644 index ff58fc2e4..000000000 --- a/tempest/lib/services/volume/v3/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# 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 tempest.lib.services.volume.v3.backups_client import BackupsClient -from tempest.lib.services.volume.v3.base_client import BaseClient -from tempest.lib.services.volume.v3.group_types_client import GroupTypesClient -from tempest.lib.services.volume.v3.groups_client import GroupsClient -from tempest.lib.services.volume.v3.messages_client import MessagesClient -from tempest.lib.services.volume.v3.versions_client import VersionsClient -from tempest.lib.services.volume.v3.volumes_client import VolumesClient - -__all__ = ['BackupsClient', 'BaseClient', 'GroupsClient', 'GroupTypesClient', - 'MessagesClient', 'VersionsClient', 'VolumesClient'] diff --git a/tempest/lib/services/volume/v3/backups_client.py b/tempest/lib/services/volume/v3/backups_client.py deleted file mode 100644 index e742e3901..000000000 --- a/tempest/lib/services/volume/v3/backups_client.py +++ /dev/null @@ -1,37 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client -from tempest.lib.services.volume.v2 import backups_client - - -class BackupsClient(backups_client.BackupsClient): - """Volume V3 Backups client""" - api_version = "v3" - - def update_backup(self, backup_id, **kwargs): - """Updates the specified volume backup. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v3/#update-a-backup - """ - put_body = json.dumps({'backup': kwargs}) - resp, body = self.put('backups/%s' % backup_id, put_body) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v3/base_client.py b/tempest/lib/services/volume/v3/base_client.py deleted file mode 100644 index e78380bb7..000000000 --- a/tempest/lib/services/volume/v3/base_client.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2016 Andrew Kerr -# 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 debtcollector import moves - -from tempest.lib.services.volume import base_client - - -BaseClient = moves.moved_class(base_client.BaseClient, 'BaseClient', __name__, - version="Pike", removal_version='?') -BaseClient.api_version = 'v3' diff --git a/tempest/lib/services/volume/v3/group_types_client.py b/tempest/lib/services/volume/v3/group_types_client.py deleted file mode 100644 index 97bac4847..000000000 --- a/tempest/lib/services/volume/v3/group_types_client.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright (C) 2017 Dell Inc. or its subsidiaries. -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib.services.volume import base_client - - -class GroupTypesClient(base_client.BaseClient): - """Client class to send CRUD Volume V3 Group Types API requests""" - api_version = 'v3' - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'group-type' - - def create_group_type(self, **kwargs): - """Create group_type. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v3/#create-group-type - """ - post_body = json.dumps({'group_type': kwargs}) - resp, body = self.post('group_types', post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_group_type(self, group_type_id): - """Deletes the specified group_type.""" - resp, body = self.delete("group_types/%s" % group_type_id) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_group_types(self, **params): - """List all the group_types created. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v3/#list-group-types - """ - url = 'group_types' - if params: - url += '?%s' % urllib.urlencode(params) - - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_group_type(self, group_type_id): - """Returns the details of a single group_type. - - For more information, please refer to the official API reference: - https://developer.openstack.org/api-ref/block-storage/v3/#show-group-type-details - """ - url = "group_types/%s" % group_type_id - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v3/groups_client.py b/tempest/lib/services/volume/v3/groups_client.py deleted file mode 100644 index 9b53bb7da..000000000 --- a/tempest/lib/services/volume/v3/groups_client.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright (C) 2017 Dell Inc. or its subsidiaries. -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.volume import base_client - - -class GroupsClient(base_client.BaseClient): - """Client class to send CRUD Volume Group API requests""" - api_version = 'v3' - - def create_group(self, **kwargs): - """Creates a group. - - group_type and volume_types are required parameters in kwargs. - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v3/#create-group - """ - post_body = json.dumps({'group': kwargs}) - resp, body = self.post('groups', post_body) - body = json.loads(body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_group(self, group_id, delete_volumes=True): - """Deletes a group. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v3/#delete-group - """ - post_body = {'delete-volumes': delete_volumes} - post_body = json.dumps({'delete': post_body}) - resp, body = self.post('groups/%s/action' % group_id, - post_body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def show_group(self, group_id): - """Returns the details of a single group. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v3/#show-group-details - """ - url = "groups/%s" % str(group_id) - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_groups(self, detail=False, **params): - """Lists information for all the tenant's groups. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v3/#list-groups - https://developer.openstack.org/api-ref/block-storage/v3/#list-groups-with-details - """ - url = "groups" - if detail: - url += "/detail" - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_group(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'group' diff --git a/tempest/lib/services/volume/v3/messages_client.py b/tempest/lib/services/volume/v3/messages_client.py deleted file mode 100644 index 012727137..000000000 --- a/tempest/lib/services/volume/v3/messages_client.py +++ /dev/null @@ -1,60 +0,0 @@ -# Copyright 2016 Andrew Kerr -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.volume import base_client - - -class MessagesClient(base_client.BaseClient): - """Client class to send user messages API requests.""" - api_version = 'v3' - - def show_message(self, message_id): - """Show details for a single message.""" - url = 'messages/%s' % str(message_id) - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def list_messages(self): - """List all messages.""" - url = 'messages' - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) - - def delete_message(self, message_id): - """Delete a single message.""" - url = 'messages/%s' % str(message_id) - resp, body = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp, body) - - def is_resource_deleted(self, id): - try: - self.show_message(id) - except lib_exc.NotFound: - return True - return False - - @property - def resource_type(self): - """Returns the primary type of resource this client works with.""" - return 'message' diff --git a/tempest/lib/services/volume/v3/versions_client.py b/tempest/lib/services/volume/v3/versions_client.py deleted file mode 100644 index 5702f9521..000000000 --- a/tempest/lib/services/volume/v3/versions_client.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2017 NEC Corporation. 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 time - -from oslo_serialization import jsonutils as json - -from tempest.lib.api_schema.response.volume import versions as schema -from tempest.lib.common import rest_client -from tempest.lib.services.volume import base_client - - -class VersionsClient(base_client.BaseClient): - api_version = 'v3' - - def list_versions(self): - """List API versions - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v3/#list-all-api-versions - """ - version_url = self._get_base_version_url() - - start = time.time() - resp, body = self.raw_request(version_url, 'GET') - end = time.time() - # NOTE: We need a raw_request() here instead of request() call because - # "list API versions" API doesn't require an authentication and we can - # skip it with raw_request() call. - self._log_request('GET', version_url, resp, secs=(end - start), - resp_body=body) - self._error_checker(resp, body) - - body = json.loads(body) - self.validate_response(schema.list_versions, resp, body) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/lib/services/volume/v3/volumes_client.py b/tempest/lib/services/volume/v3/volumes_client.py deleted file mode 100644 index 5f4b278e8..000000000 --- a/tempest/lib/services/volume/v3/volumes_client.py +++ /dev/null @@ -1,40 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# 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 oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client -from tempest.lib.services.volume.v2 import volumes_client - - -class VolumesClient(volumes_client.VolumesClient): - """Client class to send CRUD Volume V3 API requests""" - api_version = "v3" - - def show_volume_summary(self, **params): - """Get volumes summary. - - For a full list of available parameters, please refer to the official - API reference: - https://developer.openstack.org/api-ref/block-storage/v3/#get-volumes-summary - """ - url = 'volumes/summary' - if params: - url += '?%s' % urllib.urlencode(params) - resp, body = self.get(url) - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/manager.py b/tempest/manager.py deleted file mode 100644 index e3174d448..000000000 --- a/tempest/manager.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_log import log as logging - -from tempest import clients as tempest_clients -from tempest import config -from tempest.lib.services import clients - -CONF = config.CONF -LOG = logging.getLogger(__name__) - - -class Manager(clients.ServiceClients): - """Service client manager class for backward compatibility - - The former manager.Manager is not a stable interface in Tempest, - nonetheless it is consumed by a number of plugins already. This class - exists to provide some grace time for the move to tempest.lib. - """ - - def __init__(self, credentials, scope='project'): - msg = ("tempest.manager.Manager is not a stable interface and as such " - "it should not imported directly. It will be removed as " - "soon as the client manager becomes available in tempest.lib.") - LOG.warning(msg) - dscv = CONF.identity.disable_ssl_certificate_validation - _, uri = tempest_clients.get_auth_provider_class(credentials) - super(Manager, self).__init__( - credentials=credentials, scope=scope, - identity_uri=uri, - disable_ssl_certificate_validation=dscv, - ca_certs=CONF.identity.ca_certificates_file, - trace_requests=CONF.debug.trace_requests) - - -def get_auth_provider(credentials, pre_auth=False, scope='project'): - """Shim to get_auth_provider in clients.py - - get_auth_provider used to be hosted in this module, but it has been - moved to clients.py now as a more permanent location. - This module will be removed eventually, and this shim is only - maintained for the benefit of plugins already consuming this interface. - """ - msg = ("tempest.manager.get_auth_provider is not a stable interface and " - "as such it should not imported directly. It will be removed as " - "the client manager becomes available in tempest.lib.") - LOG.warning(msg) - return tempest_clients.get_auth_provider(credentials=credentials, - pre_auth=pre_auth, scope=scope) diff --git a/tempest/releasenotes/notes/add-return-value-to-retype-volume-a401aa619aaa2457.yaml b/tempest/releasenotes/notes/add-return-value-to-retype-volume-a401aa619aaa2457.yaml deleted file mode 100644 index 4abfe9ed8..000000000 --- a/tempest/releasenotes/notes/add-return-value-to-retype-volume-a401aa619aaa2457.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -fixes: - Add a missing return statement to the retype_volume API in the v2 volumes_client library. - This changes the response body from None to an empty dictionary. - diff --git a/tempest/scenario/README.rst b/tempest/scenario/README.rst deleted file mode 100644 index c1dcccc0b..000000000 --- a/tempest/scenario/README.rst +++ /dev/null @@ -1,49 +0,0 @@ -.. _scenario_field_guide: - -Tempest Field Guide to Scenario tests -===================================== - - -What are these tests? ---------------------- - -Scenario tests are "through path" tests of OpenStack -function. Complicated setups where one part might depend on completion -of a previous part. They ideally involve the integration between -multiple OpenStack services to exercise the touch points between them. - -Any scenario test should have a real-life use case. An example would be: - - - "As operator I want to start with a blank environment": - 1. upload a glance image - 2. deploy a vm from it - 3. ssh to the guest - 4. create a snapshot of the vm - - -Why are these tests in Tempest? -------------------------------- -This is one of Tempest's core purposes, testing the integration between -projects. - - -Scope of these tests --------------------- -Scenario tests should always use the Tempest implementation of the -OpenStack API, as we want to ensure that bugs aren't hidden by the -official clients. - -Tests should be tagged with which services they exercise, as -determined by which client libraries are used directly by the test. - - -Example of a good test ----------------------- -While we are looking for interaction of 2 or more services, be -specific in your interactions. A giant "this is my data center" smoke -test is hard to debug when it goes wrong. - -A flow of interactions between Glance and Nova, like in the -introduction, is a good example. Especially if it involves a repeated -interaction when a resource is setup, modified, detached, and then -reused later again. diff --git a/tempest/scenario/__init__.py b/tempest/scenario/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py deleted file mode 100644 index 9b8c7a01f..000000000 --- a/tempest/scenario/manager.py +++ /dev/null @@ -1,1375 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# Copyright 2013 IBM 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 subprocess - -import netaddr -from oslo_log import log -from oslo_serialization import jsonutils as json -from oslo_utils import netutils - -from tempest.common import compute -from tempest.common import image as common_image -from tempest.common.utils.linux import remote_client -from tempest.common.utils import net_utils -from tempest.common import waiters -from tempest import config -from tempest import exceptions -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import exceptions as lib_exc -import tempest.test - -CONF = config.CONF - -LOG = log.getLogger(__name__) - - -class ScenarioTest(tempest.test.BaseTestCase): - """Base class for scenario tests. Uses tempest own clients. """ - - credentials = ['primary'] - - @classmethod - def setup_clients(cls): - super(ScenarioTest, cls).setup_clients() - # Clients (in alphabetical order) - cls.flavors_client = cls.os_primary.flavors_client - cls.compute_floating_ips_client = ( - cls.os_primary.compute_floating_ips_client) - if CONF.service_available.glance: - # Check if glance v1 is available to determine which client to use. - if CONF.image_feature_enabled.api_v1: - cls.image_client = cls.os_primary.image_client - elif CONF.image_feature_enabled.api_v2: - cls.image_client = cls.os_primary.image_client_v2 - else: - raise lib_exc.InvalidConfiguration( - 'Either api_v1 or api_v2 must be True in ' - '[image-feature-enabled].') - # Compute image client - cls.compute_images_client = cls.os_primary.compute_images_client - cls.keypairs_client = cls.os_primary.keypairs_client - # Nova security groups client - cls.compute_security_groups_client = ( - cls.os_primary.compute_security_groups_client) - cls.compute_security_group_rules_client = ( - cls.os_primary.compute_security_group_rules_client) - cls.servers_client = cls.os_primary.servers_client - cls.interface_client = cls.os_primary.interfaces_client - # Neutron network client - cls.networks_client = cls.os_primary.networks_client - cls.ports_client = cls.os_primary.ports_client - cls.routers_client = cls.os_primary.routers_client - cls.subnets_client = cls.os_primary.subnets_client - cls.floating_ips_client = cls.os_primary.floating_ips_client - cls.security_groups_client = cls.os_primary.security_groups_client - cls.security_group_rules_client = ( - cls.os_primary.security_group_rules_client) - cls.volumes_client = cls.os_primary.volumes_v2_client - cls.snapshots_client = cls.os_primary.snapshots_v2_client - - # ## Test functions library - # - # The create_[resource] functions only return body and discard the - # resp part which is not used in scenario tests - - def _create_port(self, network_id, client=None, namestart='port-quotatest', - **kwargs): - if not client: - client = self.ports_client - name = data_utils.rand_name(namestart) - result = client.create_port( - name=name, - network_id=network_id, - **kwargs) - self.assertIsNotNone(result, 'Unable to allocate port') - port = result['port'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - client.delete_port, port['id']) - return port - - def create_keypair(self, client=None): - if not client: - client = self.keypairs_client - name = data_utils.rand_name(self.__class__.__name__) - # We don't need to create a keypair by pubkey in scenario - body = client.create_keypair(name=name) - self.addCleanup(client.delete_keypair, name) - return body['keypair'] - - def create_server(self, name=None, image_id=None, flavor=None, - validatable=False, wait_until='ACTIVE', - clients=None, **kwargs): - """Wrapper utility that returns a test server. - - This wrapper utility calls the common create test server and - returns a test server. The purpose of this wrapper is to minimize - the impact on the code of the tests already using this - function. - """ - - # NOTE(jlanoux): As a first step, ssh checks in the scenario - # tests need to be run regardless of the run_validation and - # validatable parameters and thus until the ssh validation job - # becomes voting in CI. The test resources management and IP - # association are taken care of in the scenario tests. - # Therefore, the validatable parameter is set to false in all - # those tests. In this way create_server just return a standard - # server and the scenario tests always perform ssh checks. - - # Needed for the cross_tenant_traffic test: - if clients is None: - clients = self.os_primary - - if name is None: - name = data_utils.rand_name(self.__class__.__name__ + "-server") - - vnic_type = CONF.network.port_vnic_type - - # If vnic_type is configured create port for - # every network - if vnic_type: - ports = [] - - create_port_body = {'binding:vnic_type': vnic_type, - 'namestart': 'port-smoke'} - if kwargs: - # Convert security group names to security group ids - # to pass to create_port - if 'security_groups' in kwargs: - security_groups = \ - clients.security_groups_client.list_security_groups( - ).get('security_groups') - sec_dict = dict([(s['name'], s['id']) - for s in security_groups]) - - sec_groups_names = [s['name'] for s in kwargs.pop( - 'security_groups')] - security_groups_ids = [sec_dict[s] - for s in sec_groups_names] - - if security_groups_ids: - create_port_body[ - 'security_groups'] = security_groups_ids - networks = kwargs.pop('networks', []) - else: - networks = [] - - # If there are no networks passed to us we look up - # for the project's private networks and create a port. - # The same behaviour as we would expect when passing - # the call to the clients with no networks - if not networks: - networks = clients.networks_client.list_networks( - **{'router:external': False, 'fields': 'id'})['networks'] - - # It's net['uuid'] if networks come from kwargs - # and net['id'] if they come from - # clients.networks_client.list_networks - for net in networks: - net_id = net.get('uuid', net.get('id')) - if 'port' not in net: - port = self._create_port(network_id=net_id, - client=clients.ports_client, - **create_port_body) - ports.append({'port': port['id']}) - else: - ports.append({'port': net['port']}) - if ports: - kwargs['networks'] = ports - self.ports = ports - - tenant_network = self.get_tenant_network() - - body, _ = compute.create_test_server( - clients, - tenant_network=tenant_network, - wait_until=wait_until, - name=name, flavor=flavor, - image_id=image_id, **kwargs) - - self.addCleanup(waiters.wait_for_server_termination, - clients.servers_client, body['id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - clients.servers_client.delete_server, body['id']) - server = clients.servers_client.show_server(body['id'])['server'] - return server - - def create_volume(self, size=None, name=None, snapshot_id=None, - imageRef=None, volume_type=None): - if size is None: - size = CONF.volume.volume_size - if imageRef: - image = self.compute_images_client.show_image(imageRef)['image'] - min_disk = image.get('minDisk') - size = max(size, min_disk) - if name is None: - name = data_utils.rand_name(self.__class__.__name__ + "-volume") - kwargs = {'display_name': name, - 'snapshot_id': snapshot_id, - 'imageRef': imageRef, - 'volume_type': volume_type, - 'size': size} - volume = self.volumes_client.create_volume(**kwargs)['volume'] - - self.addCleanup(self.volumes_client.wait_for_resource_deletion, - volume['id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.volumes_client.delete_volume, volume['id']) - self.assertEqual(name, volume['name']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') - # The volume retrieved on creation has a non-up-to-date status. - # Retrieval after it becomes active ensures correct details. - volume = self.volumes_client.show_volume(volume['id'])['volume'] - return volume - - def create_volume_snapshot(self, volume_id, name=None, description=None, - metadata=None, force=False): - name = name or data_utils.rand_name( - self.__class__.__name__ + '-snapshot') - snapshot = self.snapshots_client.create_snapshot( - volume_id=volume_id, - force=force, - display_name=name, - description=description, - metadata=metadata)['snapshot'] - self.addCleanup(self.snapshots_client.wait_for_resource_deletion, - snapshot['id']) - self.addCleanup(self.snapshots_client.delete_snapshot, snapshot['id']) - waiters.wait_for_volume_resource_status(self.snapshots_client, - snapshot['id'], 'available') - return snapshot - - def create_volume_type(self, client=None, name=None, backend_name=None): - if not client: - client = self.os_admin.volume_types_v2_client - if not name: - class_name = self.__class__.__name__ - name = data_utils.rand_name(class_name + '-volume-type') - randomized_name = data_utils.rand_name('scenario-type-' + name) - - LOG.debug("Creating a volume type: %s on backend %s", - randomized_name, backend_name) - extra_specs = {} - if backend_name: - extra_specs = {"volume_backend_name": backend_name} - - body = client.create_volume_type(name=randomized_name, - extra_specs=extra_specs) - volume_type = body['volume_type'] - self.assertIn('id', volume_type) - self.addCleanup(client.delete_volume_type, volume_type['id']) - return volume_type - - def _create_loginable_secgroup_rule(self, secgroup_id=None): - _client = self.compute_security_groups_client - _client_rules = self.compute_security_group_rules_client - if secgroup_id is None: - sgs = _client.list_security_groups()['security_groups'] - for sg in sgs: - if sg['name'] == 'default': - secgroup_id = sg['id'] - - # These rules are intended to permit inbound ssh and icmp - # traffic from all sources, so no group_id is provided. - # Setting a group_id would only permit traffic from ports - # belonging to the same security group. - rulesets = [ - { - # ssh - 'ip_protocol': 'tcp', - 'from_port': 22, - 'to_port': 22, - 'cidr': '0.0.0.0/0', - }, - { - # ping - 'ip_protocol': 'icmp', - 'from_port': -1, - 'to_port': -1, - 'cidr': '0.0.0.0/0', - } - ] - rules = list() - for ruleset in rulesets: - sg_rule = _client_rules.create_security_group_rule( - parent_group_id=secgroup_id, **ruleset)['security_group_rule'] - rules.append(sg_rule) - return rules - - def _create_security_group(self): - # Create security group - sg_name = data_utils.rand_name(self.__class__.__name__) - sg_desc = sg_name + " description" - secgroup = self.compute_security_groups_client.create_security_group( - name=sg_name, description=sg_desc)['security_group'] - self.assertEqual(secgroup['name'], sg_name) - self.assertEqual(secgroup['description'], sg_desc) - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.compute_security_groups_client.delete_security_group, - secgroup['id']) - - # Add rules to the security group - self._create_loginable_secgroup_rule(secgroup['id']) - - return secgroup - - def get_remote_client(self, ip_address, username=None, private_key=None, - server=None): - """Get a SSH client to a remote server - - @param ip_address the server floating or fixed IP address to use - for ssh validation - @param username name of the Linux account on the remote server - @param private_key the SSH private key to use - @param server: server dict, used for debugging purposes - @return a RemoteClient object - """ - - if username is None: - username = CONF.validation.image_ssh_user - # Set this with 'keypair' or others to log in with keypair or - # username/password. - if CONF.validation.auth_method == 'keypair': - password = None - if private_key is None: - private_key = self.keypair['private_key'] - else: - password = CONF.validation.image_ssh_password - private_key = None - linux_client = remote_client.RemoteClient( - ip_address, username, pkey=private_key, password=password, - server=server, servers_client=self.servers_client) - linux_client.validate_authentication() - return linux_client - - def _image_create(self, name, fmt, path, - disk_format=None, properties=None): - if properties is None: - properties = {} - name = data_utils.rand_name('%s-' % name) - params = { - 'name': name, - 'container_format': fmt, - 'disk_format': disk_format or fmt, - } - if CONF.image_feature_enabled.api_v1: - params['is_public'] = 'False' - params['properties'] = properties - params = {'headers': common_image.image_meta_to_headers(**params)} - else: - params['visibility'] = 'private' - # Additional properties are flattened out in the v2 API. - params.update(properties) - body = self.image_client.create_image(**params) - image = body['image'] if 'image' in body else body - self.addCleanup(self.image_client.delete_image, image['id']) - self.assertEqual("queued", image['status']) - with open(path, 'rb') as image_file: - if CONF.image_feature_enabled.api_v1: - self.image_client.update_image(image['id'], data=image_file) - else: - self.image_client.store_image_file(image['id'], image_file) - return image['id'] - - def glance_image_create(self): - img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file - aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file - ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file - ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file - img_container_format = CONF.scenario.img_container_format - img_disk_format = CONF.scenario.img_disk_format - img_properties = CONF.scenario.img_properties - LOG.debug("paths: img: %s, container_format: %s, disk_format: %s, " - "properties: %s, ami: %s, ari: %s, aki: %s", - img_path, img_container_format, img_disk_format, - img_properties, ami_img_path, ari_img_path, aki_img_path) - try: - image = self._image_create('scenario-img', - img_container_format, - img_path, - disk_format=img_disk_format, - properties=img_properties) - except IOError: - LOG.debug("A qcow2 image was not found. Try to get a uec image.") - kernel = self._image_create('scenario-aki', 'aki', aki_img_path) - ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path) - properties = {'kernel_id': kernel, 'ramdisk_id': ramdisk} - image = self._image_create('scenario-ami', 'ami', - path=ami_img_path, - properties=properties) - LOG.debug("image:%s", image) - - return image - - def _log_console_output(self, servers=None, client=None): - if not CONF.compute_feature_enabled.console_output: - LOG.debug('Console output not supported, cannot log') - return - client = client or self.servers_client - if not servers: - servers = client.list_servers() - servers = servers['servers'] - for server in servers: - try: - console_output = client.get_console_output( - server['id'])['output'] - LOG.debug('Console output for %s\nbody=\n%s', - server['id'], console_output) - except lib_exc.NotFound: - LOG.debug("Server %s disappeared(deleted) while looking " - "for the console log", server['id']) - - def _log_net_info(self, exc): - # network debug is called as part of ssh init - if not isinstance(exc, lib_exc.SSHTimeout): - LOG.debug('Network information on a devstack host') - - def create_server_snapshot(self, server, name=None): - # Glance client - _image_client = self.image_client - # Compute client - _images_client = self.compute_images_client - if name is None: - name = data_utils.rand_name(self.__class__.__name__ + 'snapshot') - LOG.debug("Creating a snapshot image for server: %s", server['name']) - image = _images_client.create_image(server['id'], name=name) - image_id = image.response['location'].split('images/')[1] - waiters.wait_for_image_status(_image_client, image_id, 'active') - - self.addCleanup(_image_client.wait_for_resource_deletion, - image_id) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - _image_client.delete_image, image_id) - - if CONF.image_feature_enabled.api_v1: - # In glance v1 the additional properties are stored in the headers. - resp = _image_client.check_image(image_id) - snapshot_image = common_image.get_image_meta_from_headers(resp) - image_props = snapshot_image.get('properties', {}) - else: - # In glance v2 the additional properties are flattened. - snapshot_image = _image_client.show_image(image_id) - image_props = snapshot_image - - bdm = image_props.get('block_device_mapping') - if bdm: - bdm = json.loads(bdm) - if bdm and 'snapshot_id' in bdm[0]: - snapshot_id = bdm[0]['snapshot_id'] - self.addCleanup( - self.snapshots_client.wait_for_resource_deletion, - snapshot_id) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.snapshots_client.delete_snapshot, - snapshot_id) - waiters.wait_for_volume_resource_status(self.snapshots_client, - snapshot_id, - 'available') - image_name = snapshot_image['name'] - self.assertEqual(name, image_name) - LOG.debug("Created snapshot image %s for server %s", - image_name, server['name']) - return snapshot_image - - def nova_volume_attach(self, server, volume_to_attach): - volume = self.servers_client.attach_volume( - server['id'], volumeId=volume_to_attach['id'], device='/dev/%s' - % CONF.compute.volume_device_name)['volumeAttachment'] - self.assertEqual(volume_to_attach['id'], volume['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'in-use') - - # Return the updated volume after the attachment - return self.volumes_client.show_volume(volume['id'])['volume'] - - def nova_volume_detach(self, server, volume): - self.servers_client.detach_volume(server['id'], volume['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') - - volume = self.volumes_client.show_volume(volume['id'])['volume'] - self.assertEqual('available', volume['status']) - - def rebuild_server(self, server_id, image=None, - preserve_ephemeral=False, wait=True, - rebuild_kwargs=None): - if image is None: - image = CONF.compute.image_ref - - rebuild_kwargs = rebuild_kwargs or {} - - LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)", - server_id, image, preserve_ephemeral) - self.servers_client.rebuild_server( - server_id=server_id, image_ref=image, - preserve_ephemeral=preserve_ephemeral, - **rebuild_kwargs) - if wait: - waiters.wait_for_server_status(self.servers_client, - server_id, 'ACTIVE') - - def ping_ip_address(self, ip_address, should_succeed=True, - ping_timeout=None, mtu=None): - timeout = ping_timeout or CONF.validation.ping_timeout - cmd = ['ping', '-c1', '-w1'] - - if mtu: - cmd += [ - # don't fragment - '-M', 'do', - # ping receives just the size of ICMP payload - '-s', str(net_utils.get_ping_payload_size(mtu, 4)) - ] - cmd.append(ip_address) - - def ping(): - proc = subprocess.Popen(cmd, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - proc.communicate() - - return (proc.returncode == 0) == should_succeed - - caller = test_utils.find_test_caller() - LOG.debug('%(caller)s begins to ping %(ip)s in %(timeout)s sec and the' - ' expected result is %(should_succeed)s', { - 'caller': caller, 'ip': ip_address, 'timeout': timeout, - 'should_succeed': - 'reachable' if should_succeed else 'unreachable' - }) - result = test_utils.call_until_true(ping, timeout, 1) - LOG.debug('%(caller)s finishes ping %(ip)s in %(timeout)s sec and the ' - 'ping result is %(result)s', { - 'caller': caller, 'ip': ip_address, 'timeout': timeout, - 'result': 'expected' if result else 'unexpected' - }) - return result - - def check_vm_connectivity(self, ip_address, - username=None, - private_key=None, - should_connect=True, - mtu=None): - """Check server connectivity - - :param ip_address: server to test against - :param username: server's ssh username - :param private_key: server's ssh private key to be used - :param should_connect: True/False indicates positive/negative test - positive - attempt ping and ssh - negative - attempt ping and fail if succeed - :param mtu: network MTU to use for connectivity validation - - :raises: AssertError if the result of the connectivity check does - not match the value of the should_connect param - """ - if should_connect: - msg = "Timed out waiting for %s to become reachable" % ip_address - else: - msg = "ip address %s is reachable" % ip_address - self.assertTrue(self.ping_ip_address(ip_address, - should_succeed=should_connect, - mtu=mtu), - msg=msg) - if should_connect: - # no need to check ssh for negative connectivity - self.get_remote_client(ip_address, username, private_key) - - def check_public_network_connectivity(self, ip_address, username, - private_key, should_connect=True, - msg=None, servers=None, mtu=None): - # The target login is assumed to have been configured for - # key-based authentication by cloud-init. - LOG.debug('checking network connections to IP %s with user: %s', - ip_address, username) - try: - self.check_vm_connectivity(ip_address, - username, - private_key, - should_connect=should_connect, - mtu=mtu) - except Exception: - ex_msg = 'Public network connectivity check failed' - if msg: - ex_msg += ": " + msg - LOG.exception(ex_msg) - self._log_console_output(servers) - raise - - def create_floating_ip(self, thing, pool_name=None): - """Create a floating IP and associates to a server on Nova""" - - if not pool_name: - pool_name = CONF.network.floating_network_name - floating_ip = (self.compute_floating_ips_client. - create_floating_ip(pool=pool_name)['floating_ip']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.compute_floating_ips_client.delete_floating_ip, - floating_ip['id']) - self.compute_floating_ips_client.associate_floating_ip_to_server( - floating_ip['ip'], thing['id']) - return floating_ip - - def create_timestamp(self, ip_address, dev_name=None, mount_path='/mnt', - private_key=None): - ssh_client = self.get_remote_client(ip_address, - private_key=private_key) - if dev_name is not None: - ssh_client.make_fs(dev_name) - ssh_client.exec_command('sudo mount /dev/%s %s' % (dev_name, - mount_path)) - cmd_timestamp = 'sudo sh -c "date > %s/timestamp; sync"' % mount_path - ssh_client.exec_command(cmd_timestamp) - timestamp = ssh_client.exec_command('sudo cat %s/timestamp' - % mount_path) - if dev_name is not None: - ssh_client.exec_command('sudo umount %s' % mount_path) - return timestamp - - def get_timestamp(self, ip_address, dev_name=None, mount_path='/mnt', - private_key=None): - ssh_client = self.get_remote_client(ip_address, - private_key=private_key) - if dev_name is not None: - ssh_client.mount(dev_name, mount_path) - timestamp = ssh_client.exec_command('sudo cat %s/timestamp' - % mount_path) - if dev_name is not None: - ssh_client.exec_command('sudo umount %s' % mount_path) - return timestamp - - def get_server_ip(self, server): - """Get the server fixed or floating IP. - - Based on the configuration we're in, return a correct ip - address for validating that a guest is up. - """ - if CONF.validation.connect_method == 'floating': - # The tests calling this method don't have a floating IP - # and can't make use of the validation resources. So the - # method is creating the floating IP there. - return self.create_floating_ip(server)['ip'] - elif CONF.validation.connect_method == 'fixed': - # Determine the network name to look for based on config or creds - # provider network resources. - if CONF.validation.network_for_ssh: - addresses = server['addresses'][ - CONF.validation.network_for_ssh] - else: - creds_provider = self._get_credentials_provider() - net_creds = creds_provider.get_primary_creds() - network = getattr(net_creds, 'network', None) - addresses = (server['addresses'][network['name']] - if network else []) - for address in addresses: - if (address['version'] == CONF.validation.ip_version_for_ssh - and address['OS-EXT-IPS:type'] == 'fixed'): - return address['addr'] - raise exceptions.ServerUnreachable(server_id=server['id']) - else: - raise lib_exc.InvalidConfiguration() - - -class NetworkScenarioTest(ScenarioTest): - """Base class for network scenario tests. - - This class provide helpers for network scenario tests, using the neutron - API. Helpers from ancestor which use the nova network API are overridden - with the neutron API. - - This Class also enforces using Neutron instead of novanetwork. - Subclassed tests will be skipped if Neutron is not enabled - - """ - - credentials = ['primary', 'admin'] - - @classmethod - def skip_checks(cls): - super(NetworkScenarioTest, cls).skip_checks() - if not CONF.service_available.neutron: - raise cls.skipException('Neutron not available') - - def _create_network(self, networks_client=None, - tenant_id=None, - namestart='network-smoke-', - port_security_enabled=True): - if not networks_client: - networks_client = self.networks_client - if not tenant_id: - tenant_id = networks_client.tenant_id - name = data_utils.rand_name(namestart) - network_kwargs = dict(name=name, tenant_id=tenant_id) - # Neutron disables port security by default so we have to check the - # config before trying to create the network with port_security_enabled - if CONF.network_feature_enabled.port_security: - network_kwargs['port_security_enabled'] = port_security_enabled - result = networks_client.create_network(**network_kwargs) - network = result['network'] - - self.assertEqual(network['name'], name) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - networks_client.delete_network, - network['id']) - return network - - def _create_subnet(self, network, subnets_client=None, - routers_client=None, namestart='subnet-smoke', - **kwargs): - """Create a subnet for the given network - - within the cidr block configured for tenant networks. - """ - if not subnets_client: - subnets_client = self.subnets_client - if not routers_client: - routers_client = self.routers_client - - def cidr_in_use(cidr, tenant_id): - """Check cidr existence - - :returns: True if subnet with cidr already exist in tenant - False else - """ - cidr_in_use = self.os_admin.subnets_client.list_subnets( - tenant_id=tenant_id, cidr=cidr)['subnets'] - return len(cidr_in_use) != 0 - - ip_version = kwargs.pop('ip_version', 4) - - if ip_version == 6: - tenant_cidr = netaddr.IPNetwork( - CONF.network.project_network_v6_cidr) - num_bits = CONF.network.project_network_v6_mask_bits - else: - tenant_cidr = netaddr.IPNetwork(CONF.network.project_network_cidr) - num_bits = CONF.network.project_network_mask_bits - - result = None - str_cidr = None - # Repeatedly attempt subnet creation with sequential cidr - # blocks until an unallocated block is found. - for subnet_cidr in tenant_cidr.subnet(num_bits): - str_cidr = str(subnet_cidr) - if cidr_in_use(str_cidr, tenant_id=network['tenant_id']): - continue - - subnet = dict( - name=data_utils.rand_name(namestart), - network_id=network['id'], - tenant_id=network['tenant_id'], - cidr=str_cidr, - ip_version=ip_version, - **kwargs - ) - try: - result = subnets_client.create_subnet(**subnet) - break - except lib_exc.Conflict as e: - is_overlapping_cidr = 'overlaps with another subnet' in str(e) - if not is_overlapping_cidr: - raise - self.assertIsNotNone(result, 'Unable to allocate tenant network') - - subnet = result['subnet'] - self.assertEqual(subnet['cidr'], str_cidr) - - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - subnets_client.delete_subnet, subnet['id']) - - return subnet - - def _get_server_port_id_and_ip4(self, server, ip_addr=None): - ports = self.os_admin.ports_client.list_ports( - device_id=server['id'], fixed_ip=ip_addr)['ports'] - # A port can have more than one IP address in some cases. - # If the network is dual-stack (IPv4 + IPv6), this port is associated - # with 2 subnets - p_status = ['ACTIVE'] - # NOTE(vsaienko) With Ironic, instances live on separate hardware - # servers. Neutron does not bind ports for Ironic instances, as a - # result the port remains in the DOWN state. - # TODO(vsaienko) remove once bug: #1599836 is resolved. - if getattr(CONF.service_available, 'ironic', False): - p_status.append('DOWN') - port_map = [(p["id"], fxip["ip_address"]) - for p in ports - for fxip in p["fixed_ips"] - if netutils.is_valid_ipv4(fxip["ip_address"]) - and p['status'] in p_status] - inactive = [p for p in ports if p['status'] != 'ACTIVE'] - if inactive: - LOG.warning("Instance has ports that are not ACTIVE: %s", inactive) - - self.assertNotEmpty(port_map, - "No IPv4 addresses found in: %s" % ports) - self.assertEqual(len(port_map), 1, - "Found multiple IPv4 addresses: %s. " - "Unable to determine which port to target." - % port_map) - return port_map[0] - - def _get_network_by_name(self, network_name): - net = self.os_admin.networks_client.list_networks( - name=network_name)['networks'] - self.assertNotEmpty(net, - "Unable to get network by name: %s" % network_name) - return net[0] - - def create_floating_ip(self, thing, external_network_id=None, - port_id=None, client=None): - """Create a floating IP and associates to a resource/port on Neutron""" - if not external_network_id: - external_network_id = CONF.network.public_network_id - if not client: - client = self.floating_ips_client - if not port_id: - port_id, ip4 = self._get_server_port_id_and_ip4(thing) - else: - ip4 = None - result = client.create_floatingip( - floating_network_id=external_network_id, - port_id=port_id, - tenant_id=thing['tenant_id'], - fixed_ip_address=ip4 - ) - floating_ip = result['floatingip'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - client.delete_floatingip, - floating_ip['id']) - return floating_ip - - def _associate_floating_ip(self, floating_ip, server): - port_id, _ = self._get_server_port_id_and_ip4(server) - kwargs = dict(port_id=port_id) - floating_ip = self.floating_ips_client.update_floatingip( - floating_ip['id'], **kwargs)['floatingip'] - self.assertEqual(port_id, floating_ip['port_id']) - return floating_ip - - def _disassociate_floating_ip(self, floating_ip): - """:param floating_ip: floating_ips_client.create_floatingip""" - kwargs = dict(port_id=None) - floating_ip = self.floating_ips_client.update_floatingip( - floating_ip['id'], **kwargs)['floatingip'] - self.assertIsNone(floating_ip['port_id']) - return floating_ip - - def check_floating_ip_status(self, floating_ip, status): - """Verifies floatingip reaches the given status - - :param dict floating_ip: floating IP dict to check status - :param status: target status - :raises: AssertionError if status doesn't match - """ - floatingip_id = floating_ip['id'] - - def refresh(): - result = (self.floating_ips_client. - show_floatingip(floatingip_id)['floatingip']) - return status == result['status'] - - if not test_utils.call_until_true(refresh, - CONF.network.build_timeout, - CONF.network.build_interval): - floating_ip = self.floating_ips_client.show_floatingip( - floatingip_id)['floatingip'] - self.assertEqual(status, floating_ip['status'], - message="FloatingIP: {fp} is at status: {cst}. " - "failed to reach status: {st}" - .format(fp=floating_ip, cst=floating_ip['status'], - st=status)) - LOG.info("FloatingIP: {fp} is at status: {st}" - .format(fp=floating_ip, st=status)) - - def _check_tenant_network_connectivity(self, server, - username, - private_key, - should_connect=True, - servers_for_debug=None): - if not CONF.network.project_networks_reachable: - msg = 'Tenant networks not configured to be reachable.' - LOG.info(msg) - return - # The target login is assumed to have been configured for - # key-based authentication by cloud-init. - try: - for ip_addresses in server['addresses'].values(): - for ip_address in ip_addresses: - self.check_vm_connectivity(ip_address['addr'], - username, - private_key, - should_connect=should_connect) - except Exception as e: - LOG.exception('Tenant network connectivity check failed') - self._log_console_output(servers_for_debug) - self._log_net_info(e) - raise - - def _check_remote_connectivity(self, source, dest, should_succeed=True, - nic=None): - """assert ping server via source ssh connection - - Note: This is an internal method. Use check_remote_connectivity - instead. - - :param source: RemoteClient: an ssh connection from which to ping - :param dest: and IP to ping against - :param should_succeed: boolean should ping succeed or not - :param nic: specific network interface to ping from - """ - def ping_remote(): - try: - source.ping_host(dest, nic=nic) - except lib_exc.SSHExecCommandFailed: - LOG.warning('Failed to ping IP: %s via a ssh connection ' - 'from: %s.', dest, source.ssh_client.host) - return not should_succeed - return should_succeed - - return test_utils.call_until_true(ping_remote, - CONF.validation.ping_timeout, - 1) - - def check_remote_connectivity(self, source, dest, should_succeed=True, - nic=None): - """assert ping server via source ssh connection - - :param source: RemoteClient: an ssh connection from which to ping - :param dest: and IP to ping against - :param should_succeed: boolean should ping succeed or not - :param nic: specific network interface to ping from - """ - result = self._check_remote_connectivity(source, dest, should_succeed, - nic) - source_host = source.ssh_client.host - if should_succeed: - msg = "Timed out waiting for %s to become reachable from %s" \ - % (dest, source_host) - else: - msg = "%s is reachable from %s" % (dest, source_host) - self.assertTrue(result, msg) - - def _create_security_group(self, security_group_rules_client=None, - tenant_id=None, - namestart='secgroup-smoke', - security_groups_client=None): - if security_group_rules_client is None: - security_group_rules_client = self.security_group_rules_client - if security_groups_client is None: - security_groups_client = self.security_groups_client - if tenant_id is None: - tenant_id = security_groups_client.tenant_id - secgroup = self._create_empty_security_group( - namestart=namestart, client=security_groups_client, - tenant_id=tenant_id) - - # Add rules to the security group - rules = self._create_loginable_secgroup_rule( - security_group_rules_client=security_group_rules_client, - secgroup=secgroup, - security_groups_client=security_groups_client) - for rule in rules: - self.assertEqual(tenant_id, rule['tenant_id']) - self.assertEqual(secgroup['id'], rule['security_group_id']) - return secgroup - - def _create_empty_security_group(self, client=None, tenant_id=None, - namestart='secgroup-smoke'): - """Create a security group without rules. - - Default rules will be created: - - IPv4 egress to any - - IPv6 egress to any - - :param tenant_id: secgroup will be created in this tenant - :returns: the created security group - """ - if client is None: - client = self.security_groups_client - if not tenant_id: - tenant_id = client.tenant_id - sg_name = data_utils.rand_name(namestart) - sg_desc = sg_name + " description" - sg_dict = dict(name=sg_name, - description=sg_desc) - sg_dict['tenant_id'] = tenant_id - result = client.create_security_group(**sg_dict) - - secgroup = result['security_group'] - self.assertEqual(secgroup['name'], sg_name) - self.assertEqual(tenant_id, secgroup['tenant_id']) - self.assertEqual(secgroup['description'], sg_desc) - - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - client.delete_security_group, secgroup['id']) - return secgroup - - def _default_security_group(self, client=None, tenant_id=None): - """Get default secgroup for given tenant_id. - - :returns: default secgroup for given tenant - """ - if client is None: - client = self.security_groups_client - if not tenant_id: - tenant_id = client.tenant_id - sgs = [ - sg for sg in list(client.list_security_groups().values())[0] - if sg['tenant_id'] == tenant_id and sg['name'] == 'default' - ] - msg = "No default security group for tenant %s." % (tenant_id) - self.assertNotEmpty(sgs, msg) - return sgs[0] - - def _create_security_group_rule(self, secgroup=None, - sec_group_rules_client=None, - tenant_id=None, - security_groups_client=None, **kwargs): - """Create a rule from a dictionary of rule parameters. - - Create a rule in a secgroup. if secgroup not defined will search for - default secgroup in tenant_id. - - :param secgroup: the security group. - :param tenant_id: if secgroup not passed -- the tenant in which to - search for default secgroup - :param kwargs: a dictionary containing rule parameters: - for example, to allow incoming ssh: - rule = { - direction: 'ingress' - protocol:'tcp', - port_range_min: 22, - port_range_max: 22 - } - """ - if sec_group_rules_client is None: - sec_group_rules_client = self.security_group_rules_client - if security_groups_client is None: - security_groups_client = self.security_groups_client - if not tenant_id: - tenant_id = security_groups_client.tenant_id - if secgroup is None: - secgroup = self._default_security_group( - client=security_groups_client, tenant_id=tenant_id) - - ruleset = dict(security_group_id=secgroup['id'], - tenant_id=secgroup['tenant_id']) - ruleset.update(kwargs) - - sg_rule = sec_group_rules_client.create_security_group_rule(**ruleset) - sg_rule = sg_rule['security_group_rule'] - - self.assertEqual(secgroup['tenant_id'], sg_rule['tenant_id']) - self.assertEqual(secgroup['id'], sg_rule['security_group_id']) - - return sg_rule - - def _create_loginable_secgroup_rule(self, security_group_rules_client=None, - secgroup=None, - security_groups_client=None): - """Create loginable security group rule - - This function will create: - 1. egress and ingress tcp port 22 allow rule in order to allow ssh - access for ipv4. - 2. egress and ingress ipv6 icmp allow rule, in order to allow icmpv6. - 3. egress and ingress ipv4 icmp allow rule, in order to allow icmpv4. - """ - - if security_group_rules_client is None: - security_group_rules_client = self.security_group_rules_client - if security_groups_client is None: - security_groups_client = self.security_groups_client - rules = [] - rulesets = [ - dict( - # ssh - protocol='tcp', - port_range_min=22, - port_range_max=22, - ), - dict( - # ping - protocol='icmp', - ), - dict( - # ipv6-icmp for ping6 - protocol='icmp', - ethertype='IPv6', - ) - ] - sec_group_rules_client = security_group_rules_client - for ruleset in rulesets: - for r_direction in ['ingress', 'egress']: - ruleset['direction'] = r_direction - try: - sg_rule = self._create_security_group_rule( - sec_group_rules_client=sec_group_rules_client, - secgroup=secgroup, - security_groups_client=security_groups_client, - **ruleset) - except lib_exc.Conflict as ex: - # if rule already exist - skip rule and continue - msg = 'Security group rule already exists' - if msg not in ex._error_string: - raise ex - else: - self.assertEqual(r_direction, sg_rule['direction']) - rules.append(sg_rule) - - return rules - - def _get_router(self, client=None, tenant_id=None): - """Retrieve a router for the given tenant id. - - If a public router has been configured, it will be returned. - - If a public router has not been configured, but a public - network has, a tenant router will be created and returned that - routes traffic to the public network. - """ - if not client: - client = self.routers_client - if not tenant_id: - tenant_id = client.tenant_id - router_id = CONF.network.public_router_id - network_id = CONF.network.public_network_id - if router_id: - body = client.show_router(router_id) - return body['router'] - elif network_id: - router = self._create_router(client, tenant_id) - kwargs = {'external_gateway_info': dict(network_id=network_id)} - router = client.update_router(router['id'], **kwargs)['router'] - return router - else: - raise Exception("Neither of 'public_router_id' or " - "'public_network_id' has been defined.") - - def _create_router(self, client=None, tenant_id=None, - namestart='router-smoke'): - if not client: - client = self.routers_client - if not tenant_id: - tenant_id = client.tenant_id - name = data_utils.rand_name(namestart) - result = client.create_router(name=name, - admin_state_up=True, - tenant_id=tenant_id) - router = result['router'] - self.assertEqual(router['name'], name) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - client.delete_router, - router['id']) - return router - - def _update_router_admin_state(self, router, admin_state_up): - kwargs = dict(admin_state_up=admin_state_up) - router = self.routers_client.update_router( - router['id'], **kwargs)['router'] - self.assertEqual(admin_state_up, router['admin_state_up']) - - def create_networks(self, networks_client=None, - routers_client=None, subnets_client=None, - tenant_id=None, dns_nameservers=None, - port_security_enabled=True): - """Create a network with a subnet connected to a router. - - The baremetal driver is a special case since all nodes are - on the same shared network. - - :param tenant_id: id of tenant to create resources in. - :param dns_nameservers: list of dns servers to send to subnet. - :returns: network, subnet, router - """ - if CONF.network.shared_physical_network: - # NOTE(Shrews): This exception is for environments where tenant - # credential isolation is available, but network separation is - # not (the current baremetal case). Likely can be removed when - # test account mgmt is reworked: - # https://blueprints.launchpad.net/tempest/+spec/test-accounts - if not CONF.compute.fixed_network_name: - m = 'fixed_network_name must be specified in config' - raise lib_exc.InvalidConfiguration(m) - network = self._get_network_by_name( - CONF.compute.fixed_network_name) - router = None - subnet = None - else: - network = self._create_network( - networks_client=networks_client, - tenant_id=tenant_id, - port_security_enabled=port_security_enabled) - router = self._get_router(client=routers_client, - tenant_id=tenant_id) - subnet_kwargs = dict(network=network, - subnets_client=subnets_client, - routers_client=routers_client) - # use explicit check because empty list is a valid option - if dns_nameservers is not None: - subnet_kwargs['dns_nameservers'] = dns_nameservers - subnet = self._create_subnet(**subnet_kwargs) - if not routers_client: - routers_client = self.routers_client - router_id = router['id'] - routers_client.add_router_interface(router_id, - subnet_id=subnet['id']) - - # save a cleanup job to remove this association between - # router and subnet - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - routers_client.remove_router_interface, router_id, - subnet_id=subnet['id']) - return network, subnet, router - - -class EncryptionScenarioTest(ScenarioTest): - """Base class for encryption scenario tests""" - - credentials = ['primary', 'admin'] - - @classmethod - def setup_clients(cls): - super(EncryptionScenarioTest, cls).setup_clients() - cls.admin_volume_types_client = cls.os_admin.volume_types_v2_client - cls.admin_encryption_types_client =\ - cls.os_admin.encryption_types_v2_client - - def create_encryption_type(self, client=None, type_id=None, provider=None, - key_size=None, cipher=None, - control_location=None): - if not client: - client = self.admin_encryption_types_client - if not type_id: - volume_type = self.create_volume_type() - type_id = volume_type['id'] - LOG.debug("Creating an encryption type for volume type: %s", type_id) - client.create_encryption_type( - type_id, provider=provider, key_size=key_size, cipher=cipher, - control_location=control_location)['encryption'] - - def create_encrypted_volume(self, encryption_provider, volume_type, - key_size=256, cipher='aes-xts-plain64', - control_location='front-end'): - volume_type = self.create_volume_type(name=volume_type) - self.create_encryption_type(type_id=volume_type['id'], - provider=encryption_provider, - key_size=key_size, - cipher=cipher, - control_location=control_location) - return self.create_volume(volume_type=volume_type['name']) - - -class ObjectStorageScenarioTest(ScenarioTest): - """Provide harness to do Object Storage scenario tests. - - Subclasses implement the tests that use the methods provided by this - class. - """ - - @classmethod - def skip_checks(cls): - super(ObjectStorageScenarioTest, cls).skip_checks() - if not CONF.service_available.swift: - skip_msg = ("%s skipped as swift is not available" % - cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_credentials(cls): - cls.set_network_resources() - super(ObjectStorageScenarioTest, cls).setup_credentials() - operator_role = CONF.object_storage.operator_role - cls.os_operator = cls.get_client_manager(roles=[operator_role]) - - @classmethod - def setup_clients(cls): - super(ObjectStorageScenarioTest, cls).setup_clients() - # Clients for Swift - cls.account_client = cls.os_operator.account_client - cls.container_client = cls.os_operator.container_client - cls.object_client = cls.os_operator.object_client - - def get_swift_stat(self): - """get swift status for our user account.""" - self.account_client.list_account_containers() - LOG.debug('Swift status information obtained successfully') - - def create_container(self, container_name=None): - name = container_name or data_utils.rand_name( - 'swift-scenario-container') - self.container_client.create_container(name) - # look for the container to assure it is created - self.list_and_check_container_objects(name) - LOG.debug('Container %s created', name) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.container_client.delete_container, - name) - return name - - def delete_container(self, container_name): - self.container_client.delete_container(container_name) - LOG.debug('Container %s deleted', container_name) - - def upload_object_to_container(self, container_name, obj_name=None): - obj_name = obj_name or data_utils.rand_name('swift-scenario-object') - obj_data = data_utils.random_bytes() - self.object_client.create_object(container_name, obj_name, obj_data) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.object_client.delete_object, - container_name, - obj_name) - return obj_name, obj_data - - def delete_object(self, container_name, filename): - self.object_client.delete_object(container_name, filename) - self.list_and_check_container_objects(container_name, - not_present_obj=[filename]) - - def list_and_check_container_objects(self, container_name, - present_obj=None, - not_present_obj=None): - # List objects for a given container and assert which are present and - # which are not. - if present_obj is None: - present_obj = [] - if not_present_obj is None: - not_present_obj = [] - _, object_list = self.container_client.list_container_contents( - container_name) - if present_obj: - for obj in present_obj: - self.assertIn(obj, object_list) - if not_present_obj: - for obj in not_present_obj: - self.assertNotIn(obj, object_list) - - def change_container_acl(self, container_name, acl): - metadata_param = {'metadata_prefix': 'x-container-', - 'metadata': {'read': acl}} - self.container_client.update_container_metadata(container_name, - **metadata_param) - resp, _ = self.container_client.list_container_metadata(container_name) - self.assertEqual(resp['x-container-read'], acl) - - def download_and_verify(self, container_name, obj_name, expected_data): - _, obj = self.object_client.get_object(container_name, obj_name) - self.assertEqual(obj, expected_data) diff --git a/tempest/scenario/test_aggregates_basic_ops.py b/tempest/scenario/test_aggregates_basic_ops.py deleted file mode 100644 index 25227be74..000000000 --- a/tempest/scenario/test_aggregates_basic_ops.py +++ /dev/null @@ -1,125 +0,0 @@ -# Copyright 2013 IBM 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 tempest.common import tempest_fixtures as fixtures -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.scenario import manager -from tempest import test - - -class TestAggregatesBasicOps(manager.ScenarioTest): - """Creates an aggregate within an availability zone - - Adds a host to the aggregate - Checks aggregate details - Updates aggregate's name - Removes host from aggregate - Deletes aggregate - """ - - credentials = ['primary', 'admin'] - - @classmethod - def setup_clients(cls): - super(TestAggregatesBasicOps, cls).setup_clients() - # Use admin client by default - cls.aggregates_client = cls.os_admin.aggregates_client - cls.hosts_client = cls.os_admin.hosts_client - - def _create_aggregate(self, **kwargs): - aggregate = (self.aggregates_client.create_aggregate(**kwargs) - ['aggregate']) - self.addCleanup(self.aggregates_client.delete_aggregate, - aggregate['id']) - aggregate_name = kwargs['name'] - availability_zone = kwargs['availability_zone'] - self.assertEqual(aggregate['name'], aggregate_name) - self.assertEqual(aggregate['availability_zone'], availability_zone) - return aggregate - - def _get_host_name(self): - hosts = self.hosts_client.list_hosts()['hosts'] - self.assertNotEmpty(hosts) - computes = [x for x in hosts if x['service'] == 'compute'] - return computes[0]['host_name'] - - def _add_host(self, aggregate_id, host): - aggregate = (self.aggregates_client.add_host(aggregate_id, host=host) - ['aggregate']) - self.addCleanup(self._remove_host, aggregate['id'], host) - self.assertIn(host, aggregate['hosts']) - - def _remove_host(self, aggregate_id, host): - aggregate = self.aggregates_client.remove_host(aggregate_id, host=host) - self.assertNotIn(host, aggregate['aggregate']['hosts']) - - def _check_aggregate_details(self, aggregate, aggregate_name, azone, - hosts, metadata): - aggregate = (self.aggregates_client.show_aggregate(aggregate['id']) - ['aggregate']) - self.assertEqual(aggregate_name, aggregate['name']) - self.assertEqual(azone, aggregate['availability_zone']) - self.assertEqual(hosts, aggregate['hosts']) - for meta_key in metadata: - self.assertIn(meta_key, aggregate['metadata']) - self.assertEqual(metadata[meta_key], - aggregate['metadata'][meta_key]) - - def _set_aggregate_metadata(self, aggregate, meta): - aggregate = self.aggregates_client.set_metadata(aggregate['id'], - metadata=meta) - - for key in meta.keys(): - self.assertEqual(meta[key], - aggregate['aggregate']['metadata'][key]) - - def _update_aggregate(self, aggregate, aggregate_name, - availability_zone): - aggregate = self.aggregates_client.update_aggregate( - aggregate['id'], name=aggregate_name, - availability_zone=availability_zone)['aggregate'] - self.assertEqual(aggregate['name'], aggregate_name) - self.assertEqual(aggregate['availability_zone'], availability_zone) - return aggregate - - @decorators.idempotent_id('cb2b4c4f-0c7c-4164-bdde-6285b302a081') - @decorators.attr(type='slow') - @test.services('compute') - def test_aggregate_basic_ops(self): - self.useFixture(fixtures.LockFixture('availability_zone')) - az = 'foo_zone' - aggregate_name = data_utils.rand_name('aggregate-scenario') - aggregate = self._create_aggregate(name=aggregate_name, - availability_zone=az) - - metadata = {'meta_key': 'meta_value'} - self._set_aggregate_metadata(aggregate, metadata) - - host = self._get_host_name() - self._add_host(aggregate['id'], host) - self._check_aggregate_details(aggregate, aggregate_name, az, [host], - metadata) - - aggregate_name = data_utils.rand_name('renamed-aggregate-scenario') - # Updating the name alone. The az must be specified again otherwise - # the tempest client would send None in the put body - aggregate = self._update_aggregate(aggregate, aggregate_name, az) - - new_metadata = {'foo': 'bar'} - self._set_aggregate_metadata(aggregate, new_metadata) - - self._check_aggregate_details(aggregate, aggregate['name'], az, - [host], new_metadata) diff --git a/tempest/scenario/test_encrypted_cinder_volumes.py b/tempest/scenario/test_encrypted_cinder_volumes.py deleted file mode 100644 index cbdf30766..000000000 --- a/tempest/scenario/test_encrypted_cinder_volumes.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright (c) 2014 The Johns Hopkins University/Applied Physics Laboratory -# 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 tempest import config -from tempest.lib import decorators -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF - - -class TestEncryptedCinderVolumes(manager.EncryptionScenarioTest): - - """The test suite for encrypted cinder volumes - - This test is for verifying the functionality of encrypted cinder volumes. - - For both LUKS and cryptsetup encryption types, this test performs - the following: - * Creates an image in Glance - * Boots an instance from the image - * Creates an encryption type (as admin) - * Creates a volume of that encryption type (as a regular user) - * Attaches and detaches the encrypted volume to the instance - """ - - @classmethod - def skip_checks(cls): - super(TestEncryptedCinderVolumes, cls).skip_checks() - if not CONF.compute_feature_enabled.attach_encrypted_volume: - raise cls.skipException('Encrypted volume attach is not supported') - - def launch_instance(self): - image = self.glance_image_create() - keypair = self.create_keypair() - - return self.create_server(image_id=image, key_name=keypair['name']) - - def attach_detach_volume(self, server, volume): - attached_volume = self.nova_volume_attach(server, volume) - self.nova_volume_detach(server, attached_volume) - - @decorators.idempotent_id('79165fb4-5534-4b9d-8429-97ccffb8f86e') - @decorators.attr(type='slow') - @test.services('compute', 'volume', 'image') - def test_encrypted_cinder_volumes_luks(self): - server = self.launch_instance() - volume = self.create_encrypted_volume('nova.volume.encryptors.' - 'luks.LuksEncryptor', - volume_type='luks') - self.attach_detach_volume(server, volume) - - @decorators.idempotent_id('cbc752ed-b716-4717-910f-956cce965722') - @decorators.attr(type='slow') - @test.services('compute', 'volume', 'image') - def test_encrypted_cinder_volumes_cryptsetup(self): - server = self.launch_instance() - volume = self.create_encrypted_volume('nova.volume.encryptors.' - 'cryptsetup.CryptsetupEncryptor', - volume_type='cryptsetup') - self.attach_detach_volume(server, volume) diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py deleted file mode 100644 index 26a834b94..000000000 --- a/tempest/scenario/test_minimum_basic.py +++ /dev/null @@ -1,173 +0,0 @@ -# Copyright 2013 NEC Corporation -# 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 testtools - -from tempest.common import custom_matchers -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF - - -class TestMinimumBasicScenario(manager.ScenarioTest): - - """This is a basic minimum scenario test. - - This test below: - * across the multiple components - * as a regular user - * with and without optional parameters - * check command outputs - - Steps: - 1. Create image - 2. Create keypair - 3. Boot instance with keypair and get list of instances - 4. Create volume and show list of volumes - 5. Attach volume to instance and getlist of volumes - 6. Add IP to instance - 7. Create and add security group to instance - 8. Check SSH connection to instance - 9. Reboot instance - 10. Check SSH connection to instance after reboot - - """ - def nova_show(self, server): - got_server = (self.servers_client.show_server(server['id']) - ['server']) - excluded_keys = ['OS-EXT-AZ:availability_zone'] - # Exclude these keys because of LP:#1486475 - excluded_keys.extend(['OS-EXT-STS:power_state', 'updated']) - self.assertThat( - server, custom_matchers.MatchesDictExceptForKeys( - got_server, excluded_keys=excluded_keys)) - - def cinder_show(self, volume): - got_volume = self.volumes_client.show_volume(volume['id'])['volume'] - self.assertEqual(volume, got_volume) - - def nova_reboot(self, server): - self.servers_client.reboot_server(server['id'], type='SOFT') - waiters.wait_for_server_status(self.servers_client, - server['id'], 'ACTIVE') - - def check_disks(self): - # NOTE(andreaf) The device name may be different on different guest OS - disks = self.linux_client.get_disks() - self.assertEqual(1, disks.count(CONF.compute.volume_device_name)) - - def create_and_add_security_group_to_server(self, server): - secgroup = self._create_security_group() - self.servers_client.add_security_group(server['id'], - name=secgroup['name']) - self.addCleanup(self.servers_client.remove_security_group, - server['id'], name=secgroup['name']) - - def wait_for_secgroup_add(): - body = (self.servers_client.show_server(server['id']) - ['server']) - return {'name': secgroup['name']} in body['security_groups'] - - if not test_utils.call_until_true(wait_for_secgroup_add, - CONF.compute.build_timeout, - CONF.compute.build_interval): - msg = ('Timed out waiting for adding security group %s to server ' - '%s' % (secgroup['id'], server['id'])) - raise exceptions.TimeoutException(msg) - - def _get_floating_ip_in_server_addresses(self, floating_ip, server): - for addresses in server['addresses'].values(): - for address in addresses: - if (address['OS-EXT-IPS:type'] == 'floating' and - address['addr'] == floating_ip['ip']): - return address - - @decorators.idempotent_id('bdbb5441-9204-419d-a225-b4fdbfb1a1a8') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - @testtools.skipUnless(CONF.network_feature_enabled.floating_ips, - 'Floating ips are not available') - @test.services('compute', 'volume', 'image', 'network') - def test_minimum_basic_scenario(self): - image = self.glance_image_create() - keypair = self.create_keypair() - - server = self.create_server(image_id=image, key_name=keypair['name']) - servers = self.servers_client.list_servers()['servers'] - self.assertIn(server['id'], [x['id'] for x in servers]) - - self.nova_show(server) - - volume = self.create_volume() - volumes = self.volumes_client.list_volumes()['volumes'] - self.assertIn(volume['id'], [x['id'] for x in volumes]) - - self.cinder_show(volume) - - volume = self.nova_volume_attach(server, volume) - self.addCleanup(self.nova_volume_detach, server, volume) - self.cinder_show(volume) - - floating_ip = self.create_floating_ip(server) - # fetch the server again to make sure the addresses were refreshed - # after associating the floating IP - server = self.servers_client.show_server(server['id'])['server'] - address = self._get_floating_ip_in_server_addresses( - floating_ip, server) - self.assertIsNotNone( - address, - "Failed to find floating IP '%s' in server addresses: %s" % - (floating_ip['ip'], server['addresses'])) - - self.create_and_add_security_group_to_server(server) - - # check that we can SSH to the server before reboot - self.linux_client = self.get_remote_client( - floating_ip['ip'], private_key=keypair['private_key'], - server=server) - - self.nova_reboot(server) - - # check that we can SSH to the server after reboot - # (both connections are part of the scenario) - self.linux_client = self.get_remote_client( - floating_ip['ip'], private_key=keypair['private_key'], - server=server) - - self.check_disks() - - # delete the floating IP, this should refresh the server addresses - self.compute_floating_ips_client.delete_floating_ip(floating_ip['id']) - - def is_floating_ip_detached_from_server(): - server_info = self.servers_client.show_server( - server['id'])['server'] - address = self._get_floating_ip_in_server_addresses( - floating_ip, server_info) - return (not address) - - if not test_utils.call_until_true( - is_floating_ip_detached_from_server, - CONF.compute.build_timeout, - CONF.compute.build_interval): - msg = ("Floating IP '%s' should not be in server addresses: %s" % - (floating_ip['ip'], server['addresses'])) - raise exceptions.TimeoutException(msg) diff --git a/tempest/scenario/test_network_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py deleted file mode 100644 index c8add8b61..000000000 --- a/tempest/scenario/test_network_advanced_server_ops.py +++ /dev/null @@ -1,251 +0,0 @@ -# Copyright 2014 IBM 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 testtools - -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF - - -class TestNetworkAdvancedServerOps(manager.NetworkScenarioTest): - """Check VM connectivity after some advanced instance operations executed: - - * Stop/Start an instance - * Reboot an instance - * Rebuild an instance - * Pause/Unpause an instance - * Suspend/Resume an instance - * Resize an instance - """ - - @classmethod - def setup_clients(cls): - super(TestNetworkAdvancedServerOps, cls).setup_clients() - cls.admin_servers_client = cls.os_admin.servers_client - - @classmethod - def skip_checks(cls): - super(TestNetworkAdvancedServerOps, cls).skip_checks() - if not (CONF.network.project_networks_reachable - or CONF.network.public_network_id): - msg = ('Either project_networks_reachable must be "true", or ' - 'public_network_id must be defined.') - raise cls.skipException(msg) - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - @classmethod - def setup_credentials(cls): - # Create no network resources for these tests. - cls.set_network_resources() - super(TestNetworkAdvancedServerOps, cls).setup_credentials() - - def _setup_server(self, keypair): - security_groups = [] - if test.is_extension_enabled('security-group', 'network'): - security_group = self._create_security_group() - security_groups = [{'name': security_group['name']}] - network, _, _ = self.create_networks() - server = self.create_server( - networks=[{'uuid': network['id']}], - key_name=keypair['name'], - security_groups=security_groups) - return server - - def _setup_network(self, server, keypair): - public_network_id = CONF.network.public_network_id - floating_ip = self.create_floating_ip(server, public_network_id) - # Verify that we can indeed connect to the server before we mess with - # it's state - self._wait_server_status_and_check_network_connectivity( - server, keypair, floating_ip) - - return floating_ip - - def _check_network_connectivity(self, server, keypair, floating_ip, - should_connect=True): - username = CONF.validation.image_ssh_user - private_key = keypair['private_key'] - self._check_tenant_network_connectivity( - server, username, private_key, - should_connect=should_connect, - servers_for_debug=[server]) - floating_ip_addr = floating_ip['floating_ip_address'] - # Check FloatingIP status before checking the connectivity - self.check_floating_ip_status(floating_ip, 'ACTIVE') - self.check_public_network_connectivity(floating_ip_addr, username, - private_key, should_connect, - servers=[server]) - - def _wait_server_status_and_check_network_connectivity(self, server, - keypair, - floating_ip): - waiters.wait_for_server_status(self.servers_client, server['id'], - 'ACTIVE') - self._check_network_connectivity(server, keypair, floating_ip) - - def _get_host_for_server(self, server_id): - body = self.admin_servers_client.show_server(server_id)['server'] - return body['OS-EXT-SRV-ATTR:host'] - - @decorators.idempotent_id('61f1aa9a-1573-410e-9054-afa557cab021') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_server_connectivity_stop_start(self): - keypair = self.create_keypair() - server = self._setup_server(keypair) - floating_ip = self._setup_network(server, keypair) - self.servers_client.stop_server(server['id']) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'SHUTOFF') - self._check_network_connectivity(server, keypair, floating_ip, - should_connect=False) - self.servers_client.start_server(server['id']) - self._wait_server_status_and_check_network_connectivity( - server, keypair, floating_ip) - - @decorators.idempotent_id('7b6860c2-afa3-4846-9522-adeb38dfbe08') - @test.services('compute', 'network') - def test_server_connectivity_reboot(self): - keypair = self.create_keypair() - server = self._setup_server(keypair) - floating_ip = self._setup_network(server, keypair) - self.servers_client.reboot_server(server['id'], type='SOFT') - self._wait_server_status_and_check_network_connectivity( - server, keypair, floating_ip) - - @decorators.idempotent_id('88a529c2-1daa-4c85-9aec-d541ba3eb699') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_server_connectivity_rebuild(self): - keypair = self.create_keypair() - server = self._setup_server(keypair) - floating_ip = self._setup_network(server, keypair) - image_ref_alt = CONF.compute.image_ref_alt - self.servers_client.rebuild_server(server['id'], - image_ref=image_ref_alt) - self._wait_server_status_and_check_network_connectivity( - server, keypair, floating_ip) - - @decorators.idempotent_id('2b2642db-6568-4b35-b812-eceed3fa20ce') - @testtools.skipUnless(CONF.compute_feature_enabled.pause, - 'Pause is not available.') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_server_connectivity_pause_unpause(self): - keypair = self.create_keypair() - server = self._setup_server(keypair) - floating_ip = self._setup_network(server, keypair) - self.servers_client.pause_server(server['id']) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'PAUSED') - self._check_network_connectivity(server, keypair, floating_ip, - should_connect=False) - self.servers_client.unpause_server(server['id']) - self._wait_server_status_and_check_network_connectivity( - server, keypair, floating_ip) - - @decorators.idempotent_id('5cdf9499-541d-4923-804e-b9a60620a7f0') - @testtools.skipUnless(CONF.compute_feature_enabled.suspend, - 'Suspend is not available.') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_server_connectivity_suspend_resume(self): - keypair = self.create_keypair() - server = self._setup_server(keypair) - floating_ip = self._setup_network(server, keypair) - self.servers_client.suspend_server(server['id']) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'SUSPENDED') - self._check_network_connectivity(server, keypair, floating_ip, - should_connect=False) - self.servers_client.resume_server(server['id']) - self._wait_server_status_and_check_network_connectivity( - server, keypair, floating_ip) - - @decorators.idempotent_id('719eb59d-2f42-4b66-b8b1-bb1254473967') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize is not available.') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_server_connectivity_resize(self): - resize_flavor = CONF.compute.flavor_ref_alt - keypair = self.create_keypair() - server = self._setup_server(keypair) - floating_ip = self._setup_network(server, keypair) - self.servers_client.resize_server(server['id'], - flavor_ref=resize_flavor) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'VERIFY_RESIZE') - self.servers_client.confirm_resize_server(server['id']) - self._wait_server_status_and_check_network_connectivity( - server, keypair, floating_ip) - - @decorators.idempotent_id('a4858f6c-401e-4155-9a49-d5cd053d1a2f') - @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration, - 'Cold migration is not available.') - @testtools.skipUnless(CONF.compute.min_compute_nodes > 1, - 'Less than 2 compute nodes, skipping multinode ' - 'tests.') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_server_connectivity_cold_migration(self): - keypair = self.create_keypair() - server = self._setup_server(keypair) - floating_ip = self._setup_network(server, keypair) - src_host = self._get_host_for_server(server['id']) - self._wait_server_status_and_check_network_connectivity( - server, keypair, floating_ip) - - self.admin_servers_client.migrate_server(server['id']) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'VERIFY_RESIZE') - self.servers_client.confirm_resize_server(server['id']) - self._wait_server_status_and_check_network_connectivity( - server, keypair, floating_ip) - dst_host = self._get_host_for_server(server['id']) - - self.assertNotEqual(src_host, dst_host) - - @decorators.idempotent_id('25b188d7-0183-4b1e-a11d-15840c8e2fd6') - @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration, - 'Cold migration is not available.') - @testtools.skipUnless(CONF.compute.min_compute_nodes > 1, - 'Less than 2 compute nodes, skipping multinode ' - 'tests.') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_server_connectivity_cold_migration_revert(self): - keypair = self.create_keypair() - server = self._setup_server(keypair) - floating_ip = self._setup_network(server, keypair) - src_host = self._get_host_for_server(server['id']) - self._wait_server_status_and_check_network_connectivity( - server, keypair, floating_ip) - - self.admin_servers_client.migrate_server(server['id']) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'VERIFY_RESIZE') - self.servers_client.revert_resize_server(server['id']) - self._wait_server_status_and_check_network_connectivity( - server, keypair, floating_ip) - dst_host = self._get_host_for_server(server['id']) - - self.assertEqual(src_host, dst_host) diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py deleted file mode 100644 index 48ddac684..000000000 --- a/tempest/scenario/test_network_basic_ops.py +++ /dev/null @@ -1,857 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# Copyright 2013 Hewlett-Packard Development Company, L.P. -# 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 collections -import re - -from oslo_log import log as logging -import testtools - -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF -LOG = logging.getLogger(__name__) - -Floating_IP_tuple = collections.namedtuple('Floating_IP_tuple', - ['floating_ip', 'server']) - - -class TestNetworkBasicOps(manager.NetworkScenarioTest): - - """The test suite of network basic operations - - This smoke test suite assumes that Nova has been configured to - boot VM's with Neutron-managed networking, and attempts to - verify network connectivity as follows: - - There are presumed to be two types of networks: tenant and - public. A tenant network may or may not be reachable from the - Tempest host. A public network is assumed to be reachable from - the Tempest host, and it should be possible to associate a public - ('floating') IP address with a tenant ('fixed') IP address to - facilitate external connectivity to a potentially unroutable - tenant IP address. - - This test suite can be configured to test network connectivity to - a VM via a tenant network, a public network, or both. If both - networking types are to be evaluated, tests that need to be - executed remotely on the VM (via ssh) will only be run against - one of the networks (to minimize test execution time). - - Determine which types of networks to test as follows: - - * Configure tenant network checks (via the - 'project_networks_reachable' key) if the Tempest host should - have direct connectivity to tenant networks. This is likely to - be the case if Tempest is running on the same host as a - single-node devstack installation with IP namespaces disabled. - - * Configure checks for a public network if a public network has - been configured prior to the test suite being run and if the - Tempest host should have connectivity to that public network. - Checking connectivity for a public network requires that a - value be provided for 'public_network_id'. A value can - optionally be provided for 'public_router_id' if tenants will - use a shared router to access a public network (as is likely to - be the case when IP namespaces are not enabled). If a value is - not provided for 'public_router_id', a router will be created - for each tenant and use the network identified by - 'public_network_id' as its gateway. - - """ - - @classmethod - def skip_checks(cls): - super(TestNetworkBasicOps, cls).skip_checks() - if not (CONF.network.project_networks_reachable - or CONF.network.public_network_id): - msg = ('Either project_networks_reachable must be "true", or ' - 'public_network_id must be defined.') - raise cls.skipException(msg) - for ext in ['router', 'security-group']: - if not test.is_extension_enabled(ext, 'network'): - msg = "%s extension not enabled." % ext - raise cls.skipException(msg) - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - @classmethod - def setup_credentials(cls): - # Create no network resources for these tests. - cls.set_network_resources() - super(TestNetworkBasicOps, cls).setup_credentials() - - def setUp(self): - super(TestNetworkBasicOps, self).setUp() - self.keypairs = {} - self.servers = [] - - def _setup_network_and_servers(self, **kwargs): - boot_with_port = kwargs.pop('boot_with_port', False) - self.network, self.subnet, self.router = self.create_networks(**kwargs) - self.check_networks() - - self.ports = [] - port_id = None - if boot_with_port: - # create a port on the network and boot with that - port_id = self._create_port(self.network['id'])['id'] - self.ports.append({'port': port_id}) - - server = self._create_server(self.network, port_id) - self._check_tenant_network_connectivity() - - floating_ip = self.create_floating_ip(server) - self.floating_ip_tuple = Floating_IP_tuple(floating_ip, server) - - def check_networks(self): - """Checks that we see the newly created network/subnet/router - - via checking the result of list_[networks,routers,subnets] - """ - - seen_nets = self.os_admin.networks_client.list_networks() - seen_names = [n['name'] for n in seen_nets['networks']] - seen_ids = [n['id'] for n in seen_nets['networks']] - self.assertIn(self.network['name'], seen_names) - self.assertIn(self.network['id'], seen_ids) - - if self.subnet: - seen_subnets = self.os_admin.subnets_client.list_subnets() - seen_net_ids = [n['network_id'] for n in seen_subnets['subnets']] - seen_subnet_ids = [n['id'] for n in seen_subnets['subnets']] - self.assertIn(self.network['id'], seen_net_ids) - self.assertIn(self.subnet['id'], seen_subnet_ids) - - if self.router: - seen_routers = self.os_admin.routers_client.list_routers() - seen_router_ids = [n['id'] for n in seen_routers['routers']] - seen_router_names = [n['name'] for n in seen_routers['routers']] - self.assertIn(self.router['name'], - seen_router_names) - self.assertIn(self.router['id'], - seen_router_ids) - - def _create_server(self, network, port_id=None): - keypair = self.create_keypair() - self.keypairs[keypair['name']] = keypair - security_groups = [ - {'name': self._create_security_group()['name']} - ] - network = {'uuid': network['id']} - if port_id is not None: - network['port'] = port_id - - server = self.create_server( - networks=[network], - key_name=keypair['name'], - security_groups=security_groups) - self.servers.append(server) - return server - - def _get_server_key(self, server): - return self.keypairs[server['key_name']]['private_key'] - - def _check_tenant_network_connectivity(self): - ssh_login = CONF.validation.image_ssh_user - for server in self.servers: - # call the common method in the parent class - super(TestNetworkBasicOps, self).\ - _check_tenant_network_connectivity( - server, ssh_login, self._get_server_key(server), - servers_for_debug=self.servers) - - def check_public_network_connectivity( - self, should_connect=True, msg=None, - should_check_floating_ip_status=True, mtu=None): - """Verifies connectivty to a VM via public network and floating IP - - and verifies floating IP has resource status is correct. - - :param should_connect: bool. determines if connectivity check is - negative or positive. - :param msg: Failure message to add to Error message. Should describe - the place in the test scenario where the method was called, - to indicate the context of the failure - :param should_check_floating_ip_status: bool. should status of - floating_ip be checked or not - :param mtu: int. MTU network to use for connectivity validation - """ - ssh_login = CONF.validation.image_ssh_user - floating_ip, server = self.floating_ip_tuple - ip_address = floating_ip['floating_ip_address'] - private_key = None - floatingip_status = 'DOWN' - if should_connect: - private_key = self._get_server_key(server) - floatingip_status = 'ACTIVE' - # Check FloatingIP Status before initiating a connection - if should_check_floating_ip_status: - self.check_floating_ip_status(floating_ip, floatingip_status) - # call the common method in the parent class - super(TestNetworkBasicOps, self).check_public_network_connectivity( - ip_address, ssh_login, private_key, should_connect, msg, - self.servers, mtu=mtu) - - def _disassociate_floating_ips(self): - floating_ip, _ = self.floating_ip_tuple - self._disassociate_floating_ip(floating_ip) - self.floating_ip_tuple = Floating_IP_tuple( - floating_ip, None) - - def _reassociate_floating_ips(self): - floating_ip, server = self.floating_ip_tuple - # create a new server for the floating ip - server = self._create_server(self.network) - self._associate_floating_ip(floating_ip, server) - self.floating_ip_tuple = Floating_IP_tuple( - floating_ip, server) - - def _create_new_network(self, create_gateway=False): - self.new_net = self._create_network() - if create_gateway: - self.new_subnet = self._create_subnet( - network=self.new_net) - else: - self.new_subnet = self._create_subnet( - network=self.new_net, - gateway_ip=None) - - def _hotplug_server(self): - old_floating_ip, server = self.floating_ip_tuple - ip_address = old_floating_ip['floating_ip_address'] - private_key = self._get_server_key(server) - ssh_client = self.get_remote_client( - ip_address, private_key=private_key, server=server) - old_nic_list = self._get_server_nics(ssh_client) - # get a port from a list of one item - port_list = self.os_admin.ports_client.list_ports( - device_id=server['id'])['ports'] - self.assertEqual(1, len(port_list)) - old_port = port_list[0] - interface = self.interface_client.create_interface( - server_id=server['id'], - net_id=self.new_net['id'])['interfaceAttachment'] - self.addCleanup(self.ports_client.wait_for_resource_deletion, - interface['port_id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.interface_client.delete_interface, - server['id'], interface['port_id']) - - def check_ports(): - self.new_port_list = [ - port for port in - self.os_admin.ports_client.list_ports( - device_id=server['id'])['ports'] - if port['id'] != old_port['id'] - ] - return len(self.new_port_list) == 1 - - if not test_utils.call_until_true( - check_ports, CONF.network.build_timeout, - CONF.network.build_interval): - raise exceptions.TimeoutException( - "No new port attached to the server in time (%s sec)! " - "Old port: %s. Number of new ports: %d" % ( - CONF.network.build_timeout, old_port, - len(self.new_port_list))) - new_port = self.new_port_list[0] - - def check_new_nic(): - new_nic_list = self._get_server_nics(ssh_client) - self.diff_list = [n for n in new_nic_list if n not in old_nic_list] - return len(self.diff_list) == 1 - - if not test_utils.call_until_true( - check_new_nic, CONF.network.build_timeout, - CONF.network.build_interval): - raise exceptions.TimeoutException("Interface not visible on the " - "guest after %s sec" - % CONF.network.build_timeout) - - _, new_nic = self.diff_list[0] - ssh_client.exec_command("sudo ip addr add %s/%s dev %s" % ( - new_port['fixed_ips'][0]['ip_address'], - CONF.network.project_network_mask_bits, - new_nic)) - ssh_client.exec_command("sudo ip link set %s up" % new_nic) - - def _get_server_nics(self, ssh_client): - reg = re.compile(r'(?P\d+): (?P\w+)[@]?.*:') - ipatxt = ssh_client.exec_command("ip address") - return reg.findall(ipatxt) - - def _check_network_internal_connectivity(self, network, - should_connect=True): - """via ssh check VM internal connectivity: - - - ping internal gateway and DHCP port, implying in-tenant connectivity - pinging both, because L3 and DHCP agents might be on different nodes - """ - floating_ip, server = self.floating_ip_tuple - # get internal ports' ips: - # get all network ports in the new network - internal_ips = ( - p['fixed_ips'][0]['ip_address'] for p in - self.os_admin.ports_client.list_ports( - tenant_id=server['tenant_id'], - network_id=network['id'])['ports'] - if p['device_owner'].startswith('network') - ) - - self._check_server_connectivity(floating_ip, - internal_ips, - should_connect) - - def _check_network_external_connectivity(self): - """ping default gateway to imply external connectivity""" - if not CONF.network.public_network_id: - msg = 'public network not defined.' - LOG.info(msg) - return - - # We ping the external IP from the instance using its floating IP - # which is always IPv4, so we must only test connectivity to - # external IPv4 IPs if the external network is dualstack. - v4_subnets = [ - s for s in self.os_admin.subnets_client.list_subnets( - network_id=CONF.network.public_network_id)['subnets'] - if s['ip_version'] == 4 - ] - self.assertEqual(1, len(v4_subnets), - "Found %d IPv4 subnets" % len(v4_subnets)) - - external_ips = [v4_subnets[0]['gateway_ip']] - self._check_server_connectivity(self.floating_ip_tuple.floating_ip, - external_ips) - - def _check_server_connectivity(self, floating_ip, address_list, - should_connect=True): - ip_address = floating_ip['floating_ip_address'] - private_key = self._get_server_key(self.floating_ip_tuple.server) - ssh_source = self.get_remote_client( - ip_address, private_key=private_key, - server=self.floating_ip_tuple.server) - - for remote_ip in address_list: - self.check_remote_connectivity(ssh_source, remote_ip, - should_connect) - - @decorators.attr(type='smoke') - @decorators.idempotent_id('f323b3ba-82f8-4db7-8ea6-6a895869ec49') - @test.services('compute', 'network') - def test_network_basic_ops(self): - """Basic network operation test - - For a freshly-booted VM with an IP address ("port") on a given - network: - - - the Tempest host can ping the IP address. This implies, but - does not guarantee (see the ssh check that follows), that the - VM has been assigned the correct IP address and has - connectivity to the Tempest host. - - - the Tempest host can perform key-based authentication to an - ssh server hosted at the IP address. This check guarantees - that the IP address is associated with the target VM. - - - the Tempest host can ssh into the VM via the IP address and - successfully execute the following: - - - ping an external IP address, implying external connectivity. - - - ping an external hostname, implying that dns is correctly - configured. - - - ping an internal IP address, implying connectivity to another - VM on the same network. - - - detach the floating-ip from the VM and verify that it becomes - unreachable - - - associate detached floating ip to a new VM and verify connectivity. - VMs are created with unique keypair so connectivity also asserts that - floating IP is associated with the new VM instead of the old one - - Verifies that floating IP status is updated correctly after each change - - - """ - self._setup_network_and_servers() - self.check_public_network_connectivity(should_connect=True) - self._check_network_internal_connectivity(network=self.network) - self._check_network_external_connectivity() - self._disassociate_floating_ips() - self.check_public_network_connectivity(should_connect=False, - msg="after disassociate " - "floating ip") - self._reassociate_floating_ips() - self.check_public_network_connectivity(should_connect=True, - msg="after re-associate " - "floating ip") - - @decorators.idempotent_id('b158ea55-472e-4086-8fa9-c64ac0c6c1d0') - @testtools.skipUnless(test.is_extension_enabled('net-mtu', 'network'), - 'No way to calculate MTU for networks') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_mtu_sized_frames(self): - """Validate that network MTU sized frames fit through.""" - self._setup_network_and_servers() - self.check_public_network_connectivity( - should_connect=True, mtu=self.network['mtu']) - - @decorators.idempotent_id('1546850e-fbaa-42f5-8b5f-03d8a6a95f15') - @testtools.skipIf(CONF.network.shared_physical_network, - 'Connectivity can only be tested when in a ' - 'multitenant network environment') - @decorators.skip_because(bug="1610994") - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_connectivity_between_vms_on_different_networks(self): - """Test connectivity between VMs on different networks - - For a freshly-booted VM with an IP address ("port") on a given - network: - - - the Tempest host can ping the IP address. - - - the Tempest host can ssh into the VM via the IP address and - successfully execute the following: - - - ping an external IP address, implying external connectivity. - - - ping an external hostname, implying that dns is correctly - configured. - - - ping an internal IP address, implying connectivity to another - VM on the same network. - - - Create another network on the same tenant with subnet, create - an VM on the new network. - - - Ping the new VM from previous VM failed since the new network - was not attached to router yet. - - - Attach the new network to the router, Ping the new VM from - previous VM succeed. - - """ - self._setup_network_and_servers() - self.check_public_network_connectivity(should_connect=True) - self._check_network_internal_connectivity(network=self.network) - self._check_network_external_connectivity() - self._create_new_network(create_gateway=True) - self._create_server(self.new_net) - self._check_network_internal_connectivity(network=self.new_net, - should_connect=False) - router_id = self.router['id'] - self.routers_client.add_router_interface( - router_id, subnet_id=self.new_subnet['id']) - - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.routers_client.remove_router_interface, - router_id, subnet_id=self.new_subnet['id']) - self._check_network_internal_connectivity(network=self.new_net, - should_connect=True) - - @decorators.idempotent_id('c5adff73-e961-41f1-b4a9-343614f18cfa') - @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach, - 'NIC hotplug not available') - @testtools.skipIf(CONF.network.port_vnic_type in ['direct', 'macvtap'], - 'NIC hotplug not supported for ' - 'vnic_type direct or macvtap') - @test.services('compute', 'network') - def test_hotplug_nic(self): - """Test hotplug network interface - - 1. Create a network and a VM. - 2. Check connectivity to the VM via a public network. - 3. Create a new network, with no gateway. - 4. Bring up a new interface - 5. check the VM reach the new network - - """ - self._setup_network_and_servers() - self.check_public_network_connectivity(should_connect=True) - self._create_new_network() - self._hotplug_server() - self._check_network_internal_connectivity(network=self.new_net) - - @decorators.idempotent_id('04b9fe4e-85e8-4aea-b937-ea93885ac59f') - @testtools.skipIf(CONF.network.shared_physical_network, - 'Router state can be altered only with multitenant ' - 'networks capabilities') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_update_router_admin_state(self): - """Test to update admin state up of router - - 1. Check public connectivity before updating - admin_state_up attribute of router to False - 2. Check public connectivity after updating - admin_state_up attribute of router to False - 3. Check public connectivity after updating - admin_state_up attribute of router to True - """ - self._setup_network_and_servers() - self.check_public_network_connectivity( - should_connect=True, msg="before updating " - "admin_state_up of router to False") - self._update_router_admin_state(self.router, False) - # TODO(alokmaurya): Remove should_check_floating_ip_status=False check - # once bug 1396310 is fixed - - self.check_public_network_connectivity( - should_connect=False, msg="after updating " - "admin_state_up of router to False", - should_check_floating_ip_status=False) - self._update_router_admin_state(self.router, True) - self.check_public_network_connectivity( - should_connect=True, msg="after updating " - "admin_state_up of router to True") - - @decorators.idempotent_id('d8bb918e-e2df-48b2-97cd-b73c95450980') - @testtools.skipIf(CONF.network.shared_physical_network, - 'network isolation not available') - @testtools.skipUnless(CONF.scenario.dhcp_client, - "DHCP client is not available.") - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_subnet_details(self): - """Tests that subnet's extra configuration details are affecting VMs. - - This test relies on non-shared, isolated tenant networks. - - NOTE: Neutron subnets push data to servers via dhcp-agent, so any - update in subnet requires server to actively renew its DHCP lease. - - 1. Configure subnet with dns nameserver - 2. retrieve the VM's configured dns and verify it matches the one - configured for the subnet. - 3. update subnet's dns - 4. retrieve the VM's configured dns and verify it matches the new one - configured for the subnet. - - TODO(yfried): add host_routes - - any resolution check would be testing either: - * l3 forwarding (tested in test_network_basic_ops) - * Name resolution of an external DNS nameserver - out of scope for - Tempest - """ - # this test check only updates (no actual resolution) so using - # arbitrary ip addresses as nameservers, instead of parsing CONF - initial_dns_server = '1.2.3.4' - alt_dns_server = '9.8.7.6' - - # renewal should be immediate. - # Timeouts are suggested by salvatore-orlando in - # https://bugs.launchpad.net/neutron/+bug/1412325/comments/3 - renew_delay = CONF.network.build_interval - renew_timeout = CONF.network.build_timeout - - self._setup_network_and_servers(dns_nameservers=[initial_dns_server]) - self.check_public_network_connectivity(should_connect=True) - - floating_ip, server = self.floating_ip_tuple - ip_address = floating_ip['floating_ip_address'] - private_key = self._get_server_key(server) - ssh_client = self.get_remote_client( - ip_address, private_key=private_key, server=server) - - dns_servers = [initial_dns_server] - servers = ssh_client.get_dns_servers() - self.assertEqual(set(dns_servers), set(servers), - 'Looking for servers: {trgt_serv}. ' - 'Retrieved DNS nameservers: {act_serv} ' - 'From host: {host}.' - .format(host=ssh_client.ssh_client.host, - act_serv=servers, - trgt_serv=dns_servers)) - - self.subnet = self.subnets_client.update_subnet( - self.subnet['id'], dns_nameservers=[alt_dns_server])['subnet'] - - # asserts that Neutron DB has updated the nameservers - self.assertEqual([alt_dns_server], self.subnet['dns_nameservers'], - "Failed to update subnet's nameservers") - - def check_new_dns_server(): - # NOTE: Server needs to renew its dhcp lease in order to get new - # definitions from subnet - # NOTE(amuller): we are renewing the lease as part of the retry - # because Neutron updates dnsmasq asynchronously after the - # subnet-update API call returns. - ssh_client.renew_lease(fixed_ip=floating_ip['fixed_ip_address'], - dhcp_client=CONF.scenario.dhcp_client) - if ssh_client.get_dns_servers() != [alt_dns_server]: - LOG.debug("Failed to update DNS nameservers") - return False - return True - - self.assertTrue(test_utils.call_until_true(check_new_dns_server, - renew_timeout, - renew_delay), - msg="DHCP renewal failed to fetch " - "new DNS nameservers") - - @decorators.idempotent_id('f5dfcc22-45fd-409f-954c-5bd500d7890b') - @testtools.skipUnless(CONF.network_feature_enabled.port_admin_state_change, - "Changing a port's admin state is not supported " - "by the test environment") - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_update_instance_port_admin_state(self): - """Test to update admin_state_up attribute of instance port - - 1. Check public and project connectivity before updating - admin_state_up attribute of instance port to False - 2. Check public and project connectivity after updating - admin_state_up attribute of instance port to False - 3. Check public and project connectivity after updating - admin_state_up attribute of instance port to True - """ - self._setup_network_and_servers() - _, server = self.floating_ip_tuple - server_id = server['id'] - port_id = self.os_admin.ports_client.list_ports( - device_id=server_id)['ports'][0]['id'] - server_pip = server['addresses'][self.network['name']][0]['addr'] - - server2 = self._create_server(self.network) - server2_fip = self.create_floating_ip(server2) - - private_key = self._get_server_key(server2) - ssh_client = self.get_remote_client(server2_fip['floating_ip_address'], - private_key=private_key, - server=server2) - - self.check_public_network_connectivity( - should_connect=True, msg="before updating " - "admin_state_up of instance port to False") - self.check_remote_connectivity(ssh_client, dest=server_pip, - should_succeed=True) - self.ports_client.update_port(port_id, admin_state_up=False) - self.check_public_network_connectivity( - should_connect=False, msg="after updating " - "admin_state_up of instance port to False", - should_check_floating_ip_status=False) - self.check_remote_connectivity(ssh_client, dest=server_pip, - should_succeed=False) - self.ports_client.update_port(port_id, admin_state_up=True) - self.check_public_network_connectivity( - should_connect=True, msg="after updating " - "admin_state_up of instance port to True") - self.check_remote_connectivity(ssh_client, dest=server_pip, - should_succeed=True) - - @decorators.idempotent_id('759462e1-8535-46b0-ab3a-33aa45c55aaa') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_preserve_preexisting_port(self): - """Test preserve pre-existing port - - Tests that a pre-existing port provided on server boot is not deleted - if the server is deleted. - - Nova should unbind the port from the instance on delete if the port was - not created by Nova as part of the boot request. - - We should also be able to boot another server with the same port. - """ - # Setup the network, create a port and boot the server from that port. - self._setup_network_and_servers(boot_with_port=True) - _, server = self.floating_ip_tuple - self.assertEqual(1, len(self.ports), - 'There should only be one port created for ' - 'server %s.' % server['id']) - port_id = self.ports[0]['port'] - self.assertIsNotNone(port_id, - 'Server should have been created from a ' - 'pre-existing port.') - # Assert the port is bound to the server. - port_list = self.os_admin.ports_client.list_ports( - device_id=server['id'], network_id=self.network['id'])['ports'] - self.assertEqual(1, len(port_list), - 'There should only be one port created for ' - 'server %s.' % server['id']) - self.assertEqual(port_id, port_list[0]['id']) - # Delete the server. - self.servers_client.delete_server(server['id']) - waiters.wait_for_server_termination(self.servers_client, server['id']) - # Assert the port still exists on the network but is unbound from - # the deleted server. - port = self.ports_client.show_port(port_id)['port'] - self.assertEqual(self.network['id'], port['network_id']) - self.assertEqual('', port['device_id']) - self.assertEqual('', port['device_owner']) - - # Boot another server with the same port to make sure nothing was - # left around that could cause issues. - server = self._create_server(self.network, port['id']) - port_list = self.os_admin.ports_client.list_ports( - device_id=server['id'], network_id=self.network['id'])['ports'] - self.assertEqual(1, len(port_list), - 'There should only be one port created for ' - 'server %s.' % server['id']) - self.assertEqual(port['id'], port_list[0]['id']) - - @test.requires_ext(service='network', extension='l3_agent_scheduler') - @decorators.idempotent_id('2e788c46-fb3f-4ac9-8f82-0561555bea73') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_router_rescheduling(self): - """Tests that router can be removed from agent and add to a new agent. - - 1. Verify connectivity - 2. Remove router from all l3-agents - 3. Verify connectivity is down - 4. Assign router to new l3-agent (or old one if no new agent is - available) - 5. Verify connectivity - """ - - # TODO(yfried): refactor this test to be used for other agents (dhcp) - # as well - - list_hosts = (self.os_admin.routers_client. - list_l3_agents_hosting_router) - schedule_router = (self.os_admin.network_agents_client. - create_router_on_l3_agent) - unschedule_router = (self.os_admin.network_agents_client. - delete_router_from_l3_agent) - - agent_list_alive = set( - a["id"] for a in - self.os_admin.network_agents_client.list_agents( - agent_type="L3 agent")['agents'] if a["alive"] is True - ) - self._setup_network_and_servers() - - # NOTE(kevinbenton): we have to use the admin credentials to check - # for the distributed flag because self.router only has a project view. - admin = self.os_admin.routers_client.show_router( - self.router['id']) - if admin['router'].get('distributed', False): - msg = "Rescheduling test does not apply to distributed routers." - raise self.skipException(msg) - - self.check_public_network_connectivity(should_connect=True) - - # remove resource from agents - hosting_agents = set(a["id"] for a in - list_hosts(self.router['id'])['agents']) - no_migration = agent_list_alive == hosting_agents - LOG.info("Router will be assigned to {mig} hosting agent". - format(mig="the same" if no_migration else "a new")) - - for hosting_agent in hosting_agents: - unschedule_router(hosting_agent, self.router['id']) - self.assertNotIn(hosting_agent, - [a["id"] for a in - list_hosts(self.router['id'])['agents']], - 'unscheduling router failed') - - # verify resource is un-functional - self.check_public_network_connectivity( - should_connect=False, - msg='after router unscheduling', - ) - - # schedule resource to new agent - target_agent = list(hosting_agents if no_migration else - agent_list_alive - hosting_agents)[0] - schedule_router(target_agent, - router_id=self.router['id']) - self.assertEqual( - target_agent, - list_hosts(self.router['id'])['agents'][0]['id'], - "Router failed to reschedule. Hosting agent doesn't match " - "target agent") - - # verify resource is functional - self.check_public_network_connectivity( - should_connect=True, - msg='After router rescheduling') - - @test.requires_ext(service='network', extension='port-security') - @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach, - 'NIC hotplug not available') - @decorators.idempotent_id('7c0bb1a2-d053-49a4-98f9-ca1a1d849f63') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_port_security_macspoofing_port(self): - """Tests port_security extension enforces mac spoofing - - Neutron security groups always apply anti-spoof rules on the VMs. This - allows traffic to originate and terminate at the VM as expected, but - prevents traffic to pass through the VM. Anti-spoof rules are not - required in cases where the VM routes traffic through it. - - The test steps are : - 1. Create a new network. - 2. Connect (hotplug) the VM to a new network. - 3. Check the VM can ping a server on the new network ("peer") - 4. Spoof the mac address of the new VM interface. - 5. Check the Security Group enforces mac spoofing and blocks pings via - spoofed interface (VM cannot ping the peer). - 6. Disable port-security of the spoofed port- set the flag to false. - 7. Retest 3rd step and check that the Security Group allows pings via - the spoofed interface. - """ - - spoof_mac = "00:00:00:00:00:01" - - # Create server - self._setup_network_and_servers() - self.check_public_network_connectivity(should_connect=True) - self._create_new_network() - self._hotplug_server() - fip, server = self.floating_ip_tuple - new_ports = self.os_admin.ports_client.list_ports( - device_id=server["id"], network_id=self.new_net["id"])['ports'] - spoof_port = new_ports[0] - private_key = self._get_server_key(server) - ssh_client = self.get_remote_client(fip['floating_ip_address'], - private_key=private_key, - server=server) - spoof_nic = ssh_client.get_nic_name_by_mac(spoof_port["mac_address"]) - peer = self._create_server(self.new_net) - peer_address = peer['addresses'][self.new_net['name']][0]['addr'] - self.check_remote_connectivity(ssh_client, dest=peer_address, - nic=spoof_nic, should_succeed=True) - # Set a mac address by making nic down temporary - cmd = ("sudo ip link set {nic} down;" - "sudo ip link set dev {nic} address {mac};" - "sudo ip link set {nic} up").format(nic=spoof_nic, - mac=spoof_mac) - ssh_client.exec_command(cmd) - - new_mac = ssh_client.get_mac_address(nic=spoof_nic) - self.assertEqual(spoof_mac, new_mac) - self.check_remote_connectivity(ssh_client, dest=peer_address, - nic=spoof_nic, should_succeed=False) - self.ports_client.update_port(spoof_port["id"], - port_security_enabled=False, - security_groups=[]) - self.check_remote_connectivity(ssh_client, dest=peer_address, - nic=spoof_nic, should_succeed=True) diff --git a/tempest/scenario/test_network_v6.py b/tempest/scenario/test_network_v6.py deleted file mode 100644 index bf26c2ef8..000000000 --- a/tempest/scenario/test_network_v6.py +++ /dev/null @@ -1,258 +0,0 @@ -# Copyright 2014 Cisco Systems, Inc. -# 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 functools - -from tempest import config -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF - - -class TestGettingAddress(manager.NetworkScenarioTest): - """Test Summary: - - 1. Create network with subnets: - 1.1. one IPv4 and - 1.2. one or more IPv6 in a given address mode - 2. Boot 2 VMs on this network - 3. Allocate and assign 2 FIP4 - 4. Check that vNICs of all VMs gets all addresses actually assigned - 5. Each VM will ping the other's v4 private address - 6. If ping6 available in VM, each VM will ping all of the other's v6 - addresses as well as the router's - """ - - @classmethod - def skip_checks(cls): - super(TestGettingAddress, cls).skip_checks() - if not (CONF.network_feature_enabled.ipv6 - and CONF.network_feature_enabled.ipv6_subnet_attributes): - raise cls.skipException('IPv6 or its attributes not supported') - if not (CONF.network.project_networks_reachable - or CONF.network.public_network_id): - msg = ('Either project_networks_reachable must be "true", or ' - 'public_network_id must be defined.') - raise cls.skipException(msg) - if CONF.network.shared_physical_network: - msg = 'Deployment uses a shared physical network' - raise cls.skipException(msg) - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - @classmethod - def setup_credentials(cls): - # Create no network resources for these tests. - cls.set_network_resources() - super(TestGettingAddress, cls).setup_credentials() - - def setUp(self): - super(TestGettingAddress, self).setUp() - self.keypair = self.create_keypair() - self.sec_grp = self._create_security_group() - - def prepare_network(self, address6_mode, n_subnets6=1, dualnet=False): - """Prepare network - - Creates network with given number of IPv6 subnets in the given mode and - one IPv4 subnet. - Creates router with ports on all subnets. - if dualnet - create IPv6 subnets on a different network - :return: list of created networks - """ - network = self._create_network() - if dualnet: - network_v6 = self._create_network() - - sub4 = self._create_subnet(network=network, - namestart='sub4', - ip_version=4) - - router = self._get_router() - self.routers_client.add_router_interface(router['id'], - subnet_id=sub4['id']) - - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.routers_client.remove_router_interface, - router['id'], subnet_id=sub4['id']) - - self.subnets_v6 = [] - for _ in range(n_subnets6): - net6 = network_v6 if dualnet else network - sub6 = self._create_subnet(network=net6, - namestart='sub6', - ip_version=6, - ipv6_ra_mode=address6_mode, - ipv6_address_mode=address6_mode) - - self.routers_client.add_router_interface(router['id'], - subnet_id=sub6['id']) - - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.routers_client.remove_router_interface, - router['id'], subnet_id=sub6['id']) - - self.subnets_v6.append(sub6) - return [network, network_v6] if dualnet else [network] - - @staticmethod - def define_server_ips(srv): - ips = {'4': None, '6': []} - for nics in srv['addresses'].values(): - for nic in nics: - if nic['version'] == 6: - ips['6'].append(nic['addr']) - else: - ips['4'] = nic['addr'] - return ips - - def prepare_server(self, networks=None): - username = CONF.validation.image_ssh_user - - srv = self.create_server( - key_name=self.keypair['name'], - security_groups=[{'name': self.sec_grp['name']}], - networks=[{'uuid': n['id']} for n in networks]) - fip = self.create_floating_ip(thing=srv) - ips = self.define_server_ips(srv=srv) - ssh = self.get_remote_client( - ip_address=fip['floating_ip_address'], - username=username, server=srv) - return ssh, ips, srv["id"] - - def turn_nic6_on(self, ssh, sid, network_id): - """Turns the IPv6 vNIC on - - Required because guest images usually set only the first vNIC on boot. - Searches for the IPv6 vNIC's MAC and brings it up. - - @param ssh: RemoteClient ssh instance to server - @param sid: server uuid - @param network_id: the network id the NIC is connected to - """ - ports = [ - p["mac_address"] for p in - self.os_admin.ports_client.list_ports( - device_id=sid, network_id=network_id)['ports'] - ] - - self.assertEqual(1, len(ports), - message=("Multiple IPv6 ports found on network %s. " - "ports: %s") - % (network_id, ports)) - mac6 = ports[0] - nic = ssh.get_nic_name_by_mac(mac6) - ssh.exec_command("sudo ip link set %s up" % nic) - - def _prepare_and_test(self, address6_mode, n_subnets6=1, dualnet=False): - net_list = self.prepare_network(address6_mode=address6_mode, - n_subnets6=n_subnets6, - dualnet=dualnet) - - sshv4_1, ips_from_api_1, sid1 = self.prepare_server(networks=net_list) - sshv4_2, ips_from_api_2, sid2 = self.prepare_server(networks=net_list) - - def guest_has_address(ssh, addr): - return addr in ssh.exec_command("ip address") - - # Turn on 2nd NIC for Cirros when dualnet - if dualnet: - _, network_v6 = net_list - self.turn_nic6_on(sshv4_1, sid1, network_v6['id']) - self.turn_nic6_on(sshv4_2, sid2, network_v6['id']) - - # get addresses assigned to vNIC as reported by 'ip address' utility - ips_from_ip_1 = sshv4_1.exec_command("ip address") - ips_from_ip_2 = sshv4_2.exec_command("ip address") - self.assertIn(ips_from_api_1['4'], ips_from_ip_1) - self.assertIn(ips_from_api_2['4'], ips_from_ip_2) - for i in range(n_subnets6): - # v6 should be configured since the image supports it - # It can take time for ipv6 automatic address to get assigned - srv1_v6_addr_assigned = functools.partial( - guest_has_address, sshv4_1, ips_from_api_1['6'][i]) - - srv2_v6_addr_assigned = functools.partial( - guest_has_address, sshv4_2, ips_from_api_2['6'][i]) - - self.assertTrue(test_utils.call_until_true(srv1_v6_addr_assigned, - CONF.validation.ping_timeout, 1)) - - self.assertTrue(test_utils.call_until_true(srv2_v6_addr_assigned, - CONF.validation.ping_timeout, 1)) - - self.check_remote_connectivity(sshv4_1, ips_from_api_2['4']) - self.check_remote_connectivity(sshv4_2, ips_from_api_1['4']) - - for i in range(n_subnets6): - self.check_remote_connectivity(sshv4_1, - ips_from_api_2['6'][i]) - self.check_remote_connectivity(sshv4_1, - self.subnets_v6[i]['gateway_ip']) - self.check_remote_connectivity(sshv4_2, - ips_from_api_1['6'][i]) - self.check_remote_connectivity(sshv4_2, - self.subnets_v6[i]['gateway_ip']) - - @decorators.attr(type='slow') - @decorators.idempotent_id('2c92df61-29f0-4eaa-bee3-7c65bef62a43') - @test.services('compute', 'network') - def test_slaac_from_os(self): - self._prepare_and_test(address6_mode='slaac') - - @decorators.attr(type='slow') - @decorators.idempotent_id('d7e1f858-187c-45a6-89c9-bdafde619a9f') - @test.services('compute', 'network') - def test_dhcp6_stateless_from_os(self): - self._prepare_and_test(address6_mode='dhcpv6-stateless') - - @decorators.attr(type='slow') - @decorators.idempotent_id('7ab23f41-833b-4a16-a7c9-5b42fe6d4123') - @test.services('compute', 'network') - def test_multi_prefix_dhcpv6_stateless(self): - self._prepare_and_test(address6_mode='dhcpv6-stateless', n_subnets6=2) - - @decorators.attr(type='slow') - @decorators.idempotent_id('dec222b1-180c-4098-b8c5-cc1b8342d611') - @test.services('compute', 'network') - def test_multi_prefix_slaac(self): - self._prepare_and_test(address6_mode='slaac', n_subnets6=2) - - @decorators.attr(type='slow') - @decorators.idempotent_id('b6399d76-4438-4658-bcf5-0d6c8584fde2') - @test.services('compute', 'network') - def test_dualnet_slaac_from_os(self): - self._prepare_and_test(address6_mode='slaac', dualnet=True) - - @decorators.attr(type='slow') - @decorators.idempotent_id('76f26acd-9688-42b4-bc3e-cd134c4cb09e') - @test.services('compute', 'network') - def test_dualnet_dhcp6_stateless_from_os(self): - self._prepare_and_test(address6_mode='dhcpv6-stateless', dualnet=True) - - @decorators.attr(type='slow') - @decorators.idempotent_id('cf1c4425-766b-45b8-be35-e2959728eb00') - @test.services('compute', 'network') - def test_dualnet_multi_prefix_dhcpv6_stateless(self): - self._prepare_and_test(address6_mode='dhcpv6-stateless', n_subnets6=2, - dualnet=True) - - @decorators.idempotent_id('9178ad42-10e4-47e9-8987-e02b170cc5cd') - @test.services('compute', 'network') - def test_dualnet_multi_prefix_slaac(self): - self._prepare_and_test(address6_mode='slaac', n_subnets6=2, - dualnet=True) diff --git a/tempest/scenario/test_object_storage_basic_ops.py b/tempest/scenario/test_object_storage_basic_ops.py deleted file mode 100644 index 25e9f5c56..000000000 --- a/tempest/scenario/test_object_storage_basic_ops.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright 2013 IBM 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 tempest.lib import decorators -from tempest.scenario import manager -from tempest import test - - -class TestObjectStorageBasicOps(manager.ObjectStorageScenarioTest): - @decorators.idempotent_id('b920faf1-7b8a-4657-b9fe-9c4512bfb381') - @test.services('object_storage') - def test_swift_basic_ops(self): - """Test swift basic ops. - - * get swift stat. - * create container. - * upload a file to the created container. - * list container's objects and assure that the uploaded file is - present. - * download the object and check the content - * delete object from container. - * list container's objects and assure that the deleted file is gone. - * delete a container. - """ - self.get_swift_stat() - container_name = self.create_container() - obj_name, obj_data = self.upload_object_to_container(container_name) - self.list_and_check_container_objects(container_name, - present_obj=[obj_name]) - self.download_and_verify(container_name, obj_name, obj_data) - self.delete_object(container_name, obj_name) - self.list_and_check_container_objects(container_name, - not_present_obj=[obj_name]) - self.delete_container(container_name) - - @decorators.idempotent_id('916c7111-cb1f-44b2-816d-8f760e4ea910') - @decorators.attr(type='slow') - @test.services('object_storage') - def test_swift_acl_anonymous_download(self): - """This test will cover below steps: - - 1. Create container - 2. Upload object to the new container - 3. Change the ACL of the container - 4. Check if the object can be download by anonymous user - 5. Delete the object and container - """ - container_name = self.create_container() - obj_name, _ = self.upload_object_to_container(container_name) - obj_url = '%s/%s/%s' % (self.object_client.base_url, - container_name, obj_name) - resp, _ = self.object_client.raw_request(obj_url, 'GET') - self.assertEqual(resp.status, 401) - - self.change_container_acl(container_name, '.r:*') - resp, _ = self.object_client.raw_request(obj_url, 'GET') - self.assertEqual(resp.status, 200) diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py deleted file mode 100644 index 41c60f1e3..000000000 --- a/tempest/scenario/test_security_groups_basic_ops.py +++ /dev/null @@ -1,658 +0,0 @@ -# Copyright 2013 Red Hat, Inc. -# 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 oslo_log import log -import testtools - -from tempest.common.utils import net_info -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF -LOG = log.getLogger(__name__) - - -class TestSecurityGroupsBasicOps(manager.NetworkScenarioTest): - - """The test suite for security groups - - This test suite assumes that Nova has been configured to - boot VM's with Neutron-managed networking, and attempts to - verify cross tenant connectivity as follows - - ssh: - in order to overcome "ip namespace", each tenant has an "access point" - VM with floating-ip open to incoming ssh connection allowing network - commands (ping/ssh) to be executed from within the - tenant-network-namespace - Tempest host performs key-based authentication to the ssh server via - floating IP address - - connectivity test is done by pinging destination server via source server - ssh connection. - success - ping returns - failure - ping_timeout reached - - multi-node: - Multi-Node mode is enabled when CONF.compute.min_compute_nodes > 1. - Tests connectivity between servers on different compute nodes. - When enabled, test will boot each new server to different - compute nodes. - - setup: - for primary tenant: - 1. create a network&subnet - 2. create a router (if public router isn't configured) - 3. connect tenant network to public network via router - 4. create an access point: - a. a security group open to incoming ssh connection - b. a VM with a floating ip - 5. create a general empty security group (same as "default", but - without rules allowing in-tenant traffic) - - tests: - 1. _verify_network_details - 2. _verify_mac_addr: for each access point verify that - (subnet, fix_ip, mac address) are as defined in the port list - 3. _test_in_tenant_block: test that in-tenant traffic is disabled - without rules allowing it - 4. _test_in_tenant_allow: test that in-tenant traffic is enabled - once an appropriate rule has been created - 5. _test_cross_tenant_block: test that cross-tenant traffic is disabled - without a rule allowing it on destination tenant - 6. _test_cross_tenant_allow: - * test that cross-tenant traffic is enabled once an appropriate - rule has been created on destination tenant. - * test that reverse traffic is still blocked - * test than reverse traffic is enabled once an appropriate rule has - been created on source tenant - 7._test_port_update_new_security_group: - * test that traffic is blocked with default security group - * test that traffic is enabled after updating port with new security - group having appropriate rule - 8. _test_multiple_security_groups: test multiple security groups can be - associated with the vm - - assumptions: - 1. alt_tenant/user existed and is different from primary_tenant/user - 2. Public network is defined and reachable from the Tempest host - 3. Public router can either be: - * defined, in which case all tenants networks can connect directly - to it, and cross tenant check will be done on the private IP of the - destination tenant - or - * not defined (empty string), in which case each tenant will have - its own router connected to the public network - """ - - credentials = ['primary', 'alt', 'admin'] - - class TenantProperties(object): - """helper class to save tenant details - - id - credentials - network - subnet - security groups - servers - access point - """ - - def __init__(self, clients): - # Credentials from manager are filled with both names and IDs - self.manager = clients - self.creds = self.manager.credentials - self.network = None - self.subnet = None - self.router = None - self.security_groups = {} - self.servers = list() - self.access_point = None - - def set_network(self, network, subnet, router): - self.network = network - self.subnet = subnet - self.router = router - - @classmethod - def skip_checks(cls): - super(TestSecurityGroupsBasicOps, cls).skip_checks() - if CONF.network.port_vnic_type in ['direct', 'macvtap']: - msg = ('Not currently supported when using vnic_type' - ' direct or macvtap') - raise cls.skipException(msg) - if not (CONF.network.project_networks_reachable or - CONF.network.public_network_id): - msg = ('Either project_networks_reachable must be "true", or ' - 'public_network_id must be defined.') - raise cls.skipException(msg) - if not test.is_extension_enabled('security-group', 'network'): - msg = "security-group extension not enabled." - raise cls.skipException(msg) - if CONF.network.shared_physical_network: - msg = ('Deployment uses a shared physical network, security ' - 'groups not supported') - raise cls.skipException(msg) - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - @classmethod - def setup_credentials(cls): - # Create no network resources for these tests. - cls.set_network_resources() - super(TestSecurityGroupsBasicOps, cls).setup_credentials() - - @classmethod - def resource_setup(cls): - super(TestSecurityGroupsBasicOps, cls).resource_setup() - - cls.multi_node = CONF.compute.min_compute_nodes > 1 and \ - test.is_scheduler_filter_enabled("DifferentHostFilter") - if cls.multi_node: - LOG.info("Working in Multi Node mode") - else: - LOG.info("Working in Single Node mode") - - cls.floating_ips = {} - cls.tenants = {} - cls.primary_tenant = cls.TenantProperties(cls.os_primary) - cls.alt_tenant = cls.TenantProperties(cls.os_alt) - for tenant in [cls.primary_tenant, cls.alt_tenant]: - cls.tenants[tenant.creds.tenant_id] = tenant - - cls.floating_ip_access = not CONF.network.public_router_id - - def setUp(self): - """Set up a single tenant with an accessible server. - - If multi-host is enabled, save created server uuids. - """ - self.servers = [] - - super(TestSecurityGroupsBasicOps, self).setUp() - self._deploy_tenant(self.primary_tenant) - self._verify_network_details(self.primary_tenant) - self._verify_mac_addr(self.primary_tenant) - - def _create_tenant_keypairs(self, tenant): - keypair = self.create_keypair(tenant.manager.keypairs_client) - tenant.keypair = keypair - - def _create_tenant_security_groups(self, tenant): - access_sg = self._create_empty_security_group( - namestart='secgroup_access-', - tenant_id=tenant.creds.tenant_id, - client=tenant.manager.security_groups_client - ) - - # don't use default secgroup since it allows in-project traffic - def_sg = self._create_empty_security_group( - namestart='secgroup_general-', - tenant_id=tenant.creds.tenant_id, - client=tenant.manager.security_groups_client - ) - tenant.security_groups.update(access=access_sg, default=def_sg) - ssh_rule = dict( - protocol='tcp', - port_range_min=22, - port_range_max=22, - direction='ingress', - ) - sec_group_rules_client = tenant.manager.security_group_rules_client - self._create_security_group_rule( - secgroup=access_sg, - sec_group_rules_client=sec_group_rules_client, - **ssh_rule) - - def _verify_network_details(self, tenant): - # Checks that we see the newly created network/subnet/router via - # checking the result of list_[networks,routers,subnets] - # Check that (router, subnet) couple exist in port_list - seen_nets = self.os_admin.networks_client.list_networks() - seen_names = [n['name'] for n in seen_nets['networks']] - seen_ids = [n['id'] for n in seen_nets['networks']] - - self.assertIn(tenant.network['name'], seen_names) - self.assertIn(tenant.network['id'], seen_ids) - - seen_subnets = [ - (n['id'], n['cidr'], n['network_id']) for n in - self.os_admin.subnets_client.list_subnets()['subnets'] - ] - mysubnet = (tenant.subnet['id'], tenant.subnet['cidr'], - tenant.network['id']) - self.assertIn(mysubnet, seen_subnets) - - seen_routers = self.os_admin.routers_client.list_routers() - seen_router_ids = [n['id'] for n in seen_routers['routers']] - seen_router_names = [n['name'] for n in seen_routers['routers']] - - self.assertIn(tenant.router['name'], seen_router_names) - self.assertIn(tenant.router['id'], seen_router_ids) - - myport = (tenant.router['id'], tenant.subnet['id']) - router_ports = [ - (i['device_id'], f['subnet_id']) - for i in self.os_admin.ports_client.list_ports( - device_id=tenant.router['id'])['ports'] - if net_info.is_router_interface_port(i) - for f in i['fixed_ips'] - ] - - self.assertIn(myport, router_ports) - - def _create_server(self, name, tenant, security_groups, **kwargs): - """Creates a server and assigns it to security group. - - If multi-host is enabled, Ensures servers are created on different - compute nodes, by storing created servers' ids and uses different_host - as scheduler_hints on creation. - Validates servers are created as requested, using admin client. - """ - security_groups_names = [{'name': s['name']} for s in security_groups] - if self.multi_node: - kwargs["scheduler_hints"] = {'different_host': self.servers} - server = self.create_server( - name=name, - networks=[{'uuid': tenant.network["id"]}], - key_name=tenant.keypair['name'], - security_groups=security_groups_names, - clients=tenant.manager, - **kwargs) - if 'security_groups' in server: - self.assertEqual( - sorted([s['name'] for s in security_groups]), - sorted([s['name'] for s in server['security_groups']])) - - # Verify servers are on different compute nodes - if self.multi_node: - adm_get_server = self.os_admin.servers_client.show_server - new_host = adm_get_server(server["id"])["server"][ - "OS-EXT-SRV-ATTR:host"] - host_list = [adm_get_server(s)["server"]["OS-EXT-SRV-ATTR:host"] - for s in self.servers] - self.assertNotIn(new_host, host_list, - message="Failed to boot servers on different " - "Compute nodes.") - - self.servers.append(server["id"]) - - return server - - def _create_tenant_servers(self, tenant, num=1): - for i in range(num): - name = 'server-{tenant}-gen-{num}'.format( - tenant=tenant.creds.tenant_name, - num=i - ) - name = data_utils.rand_name(name) - server = self._create_server(name, tenant, - [tenant.security_groups['default']]) - tenant.servers.append(server) - - def _set_access_point(self, tenant): - # creates a server in a secgroup with rule allowing external ssh - # in order to access project internal network - # workaround ip namespace - secgroups = tenant.security_groups.values() - name = 'server-{tenant}-access_point'.format( - tenant=tenant.creds.tenant_name) - name = data_utils.rand_name(name) - server = self._create_server(name, tenant, - security_groups=secgroups) - tenant.access_point = server - self._assign_floating_ips(tenant, server) - - def _assign_floating_ips(self, tenant, server): - public_network_id = CONF.network.public_network_id - floating_ip = self.create_floating_ip( - server, public_network_id, - client=tenant.manager.floating_ips_client) - self.floating_ips.setdefault(server['id'], floating_ip) - - def _create_tenant_network(self, tenant, port_security_enabled=True): - network, subnet, router = self.create_networks( - networks_client=tenant.manager.networks_client, - routers_client=tenant.manager.routers_client, - subnets_client=tenant.manager.subnets_client, - port_security_enabled=port_security_enabled) - tenant.set_network(network, subnet, router) - - def _deploy_tenant(self, tenant_or_id): - """creates: - - network - subnet - router (if public not defined) - access security group - access-point server - """ - if not isinstance(tenant_or_id, self.TenantProperties): - tenant = self.tenants[tenant_or_id] - else: - tenant = tenant_or_id - self._create_tenant_keypairs(tenant) - self._create_tenant_network(tenant) - self._create_tenant_security_groups(tenant) - self._set_access_point(tenant) - - def _get_server_ip(self, server, floating=False): - """returns the ip (floating/internal) of a server""" - if floating: - server_ip = self.floating_ips[server['id']]['floating_ip_address'] - else: - server_ip = None - network_name = self.tenants[server['tenant_id']].network['name'] - if network_name in server['addresses']: - server_ip = server['addresses'][network_name][0]['addr'] - return server_ip - - def _connect_to_access_point(self, tenant): - """create ssh connection to tenant access point""" - access_point_ssh = \ - self.floating_ips[tenant.access_point['id']]['floating_ip_address'] - private_key = tenant.keypair['private_key'] - access_point_ssh = self.get_remote_client( - access_point_ssh, private_key=private_key) - return access_point_ssh - - def _test_in_tenant_block(self, tenant): - access_point_ssh = self._connect_to_access_point(tenant) - for server in tenant.servers: - self.check_remote_connectivity(source=access_point_ssh, - dest=self._get_server_ip(server), - should_succeed=False) - - def _test_in_tenant_allow(self, tenant): - ruleset = dict( - protocol='icmp', - remote_group_id=tenant.security_groups['default']['id'], - direction='ingress' - ) - self._create_security_group_rule( - secgroup=tenant.security_groups['default'], - security_groups_client=tenant.manager.security_groups_client, - **ruleset - ) - access_point_ssh = self._connect_to_access_point(tenant) - for server in tenant.servers: - self.check_remote_connectivity(source=access_point_ssh, - dest=self._get_server_ip(server)) - - def _test_cross_tenant_block(self, source_tenant, dest_tenant): - # if public router isn't defined, then dest_tenant access is via - # floating-ip - access_point_ssh = self._connect_to_access_point(source_tenant) - ip = self._get_server_ip(dest_tenant.access_point, - floating=self.floating_ip_access) - self.check_remote_connectivity(source=access_point_ssh, dest=ip, - should_succeed=False) - - def _test_cross_tenant_allow(self, source_tenant, dest_tenant): - """check for each direction: - - creating rule for tenant incoming traffic enables only 1way traffic - """ - ruleset = dict( - protocol='icmp', - direction='ingress' - ) - sec_group_rules_client = ( - dest_tenant.manager.security_group_rules_client) - self._create_security_group_rule( - secgroup=dest_tenant.security_groups['default'], - sec_group_rules_client=sec_group_rules_client, - **ruleset - ) - access_point_ssh = self._connect_to_access_point(source_tenant) - ip = self._get_server_ip(dest_tenant.access_point, - floating=self.floating_ip_access) - self.check_remote_connectivity(access_point_ssh, ip) - - # test that reverse traffic is still blocked - self._test_cross_tenant_block(dest_tenant, source_tenant) - - # allow reverse traffic and check - sec_group_rules_client = ( - source_tenant.manager.security_group_rules_client) - self._create_security_group_rule( - secgroup=source_tenant.security_groups['default'], - sec_group_rules_client=sec_group_rules_client, - **ruleset - ) - - access_point_ssh_2 = self._connect_to_access_point(dest_tenant) - ip = self._get_server_ip(source_tenant.access_point, - floating=self.floating_ip_access) - self.check_remote_connectivity(access_point_ssh_2, ip) - - def _verify_mac_addr(self, tenant): - """Verify that VM has the same ip, mac as listed in port""" - - access_point_ssh = self._connect_to_access_point(tenant) - mac_addr = access_point_ssh.get_mac_address() - mac_addr = mac_addr.strip().lower() - # Get the fixed_ips and mac_address fields of all ports. Select - # only those two columns to reduce the size of the response. - port_list = self.os_admin.ports_client.list_ports( - fields=['fixed_ips', 'mac_address'])['ports'] - port_detail_list = [ - (port['fixed_ips'][0]['subnet_id'], - port['fixed_ips'][0]['ip_address'], - port['mac_address'].lower()) - for port in port_list if port['fixed_ips'] - ] - server_ip = self._get_server_ip(tenant.access_point) - subnet_id = tenant.subnet['id'] - self.assertIn((subnet_id, server_ip, mac_addr), port_detail_list) - - def _log_console_output_for_all_tenants(self): - for tenant in self.tenants.values(): - client = tenant.manager.servers_client - self._log_console_output(servers=tenant.servers, client=client) - if tenant.access_point is not None: - self._log_console_output( - servers=[tenant.access_point], client=client) - - @decorators.idempotent_id('e79f879e-debb-440c-a7e4-efeda05b6848') - @test.services('compute', 'network') - def test_cross_tenant_traffic(self): - if not self.credentials_provider.is_multi_tenant(): - raise self.skipException("No secondary tenant defined") - try: - # deploy new project - self._deploy_tenant(self.alt_tenant) - self._verify_network_details(self.alt_tenant) - self._verify_mac_addr(self.alt_tenant) - - # cross tenant check - source_tenant = self.primary_tenant - dest_tenant = self.alt_tenant - self._test_cross_tenant_block(source_tenant, dest_tenant) - self._test_cross_tenant_allow(source_tenant, dest_tenant) - except Exception: - self._log_console_output_for_all_tenants() - raise - - @decorators.idempotent_id('63163892-bbf6-4249-aa12-d5ea1f8f421b') - @test.services('compute', 'network') - def test_in_tenant_traffic(self): - try: - self._create_tenant_servers(self.primary_tenant, num=1) - - # in-tenant check - self._test_in_tenant_block(self.primary_tenant) - self._test_in_tenant_allow(self.primary_tenant) - except Exception: - self._log_console_output_for_all_tenants() - raise - - @decorators.idempotent_id('f4d556d7-1526-42ad-bafb-6bebf48568f6') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_port_update_new_security_group(self): - """Verifies the traffic after updating the vm port - - With new security group having appropriate rule. - """ - new_tenant = self.primary_tenant - - # Create empty security group and add icmp rule in it - new_sg = self._create_empty_security_group( - namestart='secgroup_new-', - tenant_id=new_tenant.creds.tenant_id, - client=new_tenant.manager.security_groups_client) - icmp_rule = dict( - protocol='icmp', - direction='ingress', - ) - sec_group_rules_client = new_tenant.manager.security_group_rules_client - self._create_security_group_rule( - secgroup=new_sg, - sec_group_rules_client=sec_group_rules_client, - **icmp_rule) - new_tenant.security_groups.update(new_sg=new_sg) - - # Create server with default security group - name = 'server-{tenant}-gen-1'.format( - tenant=new_tenant.creds.tenant_name - ) - name = data_utils.rand_name(name) - server = self._create_server(name, new_tenant, - [new_tenant.security_groups['default']]) - - # Check connectivity failure with default security group - try: - access_point_ssh = self._connect_to_access_point(new_tenant) - self.check_remote_connectivity(source=access_point_ssh, - dest=self._get_server_ip(server), - should_succeed=False) - server_id = server['id'] - port_id = self.os_admin.ports_client.list_ports( - device_id=server_id)['ports'][0]['id'] - - # update port with new security group and check connectivity - self.ports_client.update_port(port_id, security_groups=[ - new_tenant.security_groups['new_sg']['id']]) - self.check_remote_connectivity( - source=access_point_ssh, - dest=self._get_server_ip(server)) - except Exception: - self._log_console_output_for_all_tenants() - raise - - @decorators.idempotent_id('d2f77418-fcc4-439d-b935-72eca704e293') - @decorators.attr(type='slow') - @test.services('compute', 'network') - def test_multiple_security_groups(self): - """Verify multiple security groups and checks that rules - - provided in the both the groups is applied onto VM - """ - tenant = self.primary_tenant - ip = self._get_server_ip(tenant.access_point, - floating=self.floating_ip_access) - ssh_login = CONF.validation.image_ssh_user - private_key = tenant.keypair['private_key'] - self.check_vm_connectivity(ip, - should_connect=False) - ruleset = dict( - protocol='icmp', - direction='ingress' - ) - self._create_security_group_rule( - secgroup=tenant.security_groups['default'], - **ruleset - ) - # NOTE: Vm now has 2 security groups one with ssh rule( - # already added in setUp() method),and other with icmp rule - # (added in the above step).The check_vm_connectivity tests - # -that vm ping test is successful - # -ssh to vm is successful - self.check_vm_connectivity(ip, - username=ssh_login, - private_key=private_key, - should_connect=True) - - @decorators.attr(type='slow') - @test.requires_ext(service='network', extension='port-security') - @decorators.idempotent_id('7c811dcc-263b-49a3-92d2-1b4d8405f50c') - @test.services('compute', 'network') - def test_port_security_disable_security_group(self): - """Verify the default security group rules is disabled.""" - new_tenant = self.primary_tenant - - # Create server - name = 'server-{tenant}-gen-1'.format( - tenant=new_tenant.creds.tenant_name - ) - name = data_utils.rand_name(name) - server = self._create_server(name, new_tenant, - [new_tenant.security_groups['default']]) - - access_point_ssh = self._connect_to_access_point(new_tenant) - server_id = server['id'] - port_id = self.os_admin.ports_client.list_ports( - device_id=server_id)['ports'][0]['id'] - - # Flip the port's port security and check connectivity - try: - self.ports_client.update_port(port_id, - port_security_enabled=True, - security_groups=[]) - self.check_remote_connectivity(source=access_point_ssh, - dest=self._get_server_ip(server), - should_succeed=False) - - self.ports_client.update_port(port_id, - port_security_enabled=False, - security_groups=[]) - self.check_remote_connectivity( - source=access_point_ssh, - dest=self._get_server_ip(server)) - except Exception: - self._log_console_output_for_all_tenants() - raise - - @decorators.attr(type='slow') - @test.requires_ext(service='network', extension='port-security') - @decorators.idempotent_id('13ccf253-e5ad-424b-9c4a-97b88a026699') - # TODO(mriedem): We shouldn't actually need to check this since neutron - # disables the port_security extension by default, but the problem is nova - # assumes port_security_enabled=True if it's not set on the network - # resource, which will mean nova may attempt to apply a security group on - # a port on that network which would fail. This is really a bug in nova. - @testtools.skipUnless( - CONF.network_feature_enabled.port_security, - 'Port security must be enabled.') - @test.services('compute', 'network') - def test_boot_into_disabled_port_security_network_without_secgroup(self): - tenant = self.primary_tenant - self._create_tenant_network(tenant, port_security_enabled=False) - self.assertFalse(tenant.network['port_security_enabled']) - name = data_utils.rand_name('server-smoke') - sec_groups = [] - server = self._create_server(name, tenant, sec_groups) - server_id = server['id'] - ports = self.os_admin.ports_client.list_ports( - device_id=server_id)['ports'] - self.assertEqual(1, len(ports)) - for port in ports: - self.assertEmpty(port['security_groups'], - "Neutron shouldn't even use it's default sec " - "group.") diff --git a/tempest/scenario/test_server_advanced_ops.py b/tempest/scenario/test_server_advanced_ops.py deleted file mode 100644 index 6d6318caa..000000000 --- a/tempest/scenario/test_server_advanced_ops.py +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_log import log as logging -import testtools - -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF - -LOG = logging.getLogger(__name__) - - -class TestServerAdvancedOps(manager.ScenarioTest): - - """The test suite for server advanced operations - - This test case stresses some advanced server instance operations: - * Resizing a volume-backed instance - * Sequence suspend resume - """ - - @classmethod - def setup_credentials(cls): - cls.set_network_resources() - super(TestServerAdvancedOps, cls).setup_credentials() - - @decorators.attr(type='slow') - @decorators.idempotent_id('e6c28180-7454-4b59-b188-0257af08a63b') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize is not available.') - @test.services('compute', 'volume') - def test_resize_volume_backed_server_confirm(self): - # We create an instance for use in this test - instance = self.create_server(volume_backed=True) - instance_id = instance['id'] - resize_flavor = CONF.compute.flavor_ref_alt - LOG.debug("Resizing instance %s from flavor %s to flavor %s", - instance['id'], instance['flavor']['id'], resize_flavor) - self.servers_client.resize_server(instance_id, resize_flavor) - waiters.wait_for_server_status(self.servers_client, instance_id, - 'VERIFY_RESIZE') - - LOG.debug("Confirming resize of instance %s", instance_id) - self.servers_client.confirm_resize_server(instance_id) - - waiters.wait_for_server_status(self.servers_client, instance_id, - 'ACTIVE') - - @decorators.attr(type='slow') - @decorators.idempotent_id('949da7d5-72c8-4808-8802-e3d70df98e2c') - @testtools.skipUnless(CONF.compute_feature_enabled.suspend, - 'Suspend is not available.') - @test.services('compute') - def test_server_sequence_suspend_resume(self): - # We create an instance for use in this test - instance_id = self.create_server()['id'] - - for _ in range(2): - LOG.debug("Suspending instance %s", instance_id) - self.servers_client.suspend_server(instance_id) - waiters.wait_for_server_status(self.servers_client, instance_id, - 'SUSPENDED') - - LOG.debug("Resuming instance %s", instance_id) - self.servers_client.resume_server(instance_id) - waiters.wait_for_server_status(self.servers_client, instance_id, - 'ACTIVE') diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py deleted file mode 100644 index 0c441ab41..000000000 --- a/tempest/scenario/test_server_basic_ops.py +++ /dev/null @@ -1,151 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 json -import re - -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF - - -class TestServerBasicOps(manager.ScenarioTest): - - """The test suite for server basic operations - - This smoke test case follows this basic set of operations: - * Create a keypair for use in launching an instance - * Create a security group to control network access in instance - * Add simple permissive rules to the security group - * Launch an instance - * Perform ssh to instance - * Verify metadata service - * Verify metadata on config_drive - * Terminate the instance - """ - - @classmethod - def skip_checks(cls): - super(TestServerBasicOps, cls).skip_checks() - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - def setUp(self): - super(TestServerBasicOps, self).setUp() - self.run_ssh = CONF.validation.run_validation - self.ssh_user = CONF.validation.image_ssh_user - - def verify_ssh(self, keypair): - if self.run_ssh: - # Obtain a floating IP - self.fip = self.create_floating_ip(self.instance)['ip'] - # Check ssh - self.ssh_client = self.get_remote_client( - ip_address=self.fip, - username=self.ssh_user, - private_key=keypair['private_key'], - server=self.instance) - - def verify_metadata(self): - if self.run_ssh and CONF.compute_feature_enabled.metadata_service: - # Verify metadata service - md_url = 'http://169.254.169.254/latest/meta-data/public-ipv4' - - def exec_cmd_and_verify_output(): - cmd = 'curl ' + md_url - result = self.ssh_client.exec_command(cmd) - if result: - msg = ('Failed while verifying metadata on server. Result ' - 'of command "%s" is NOT "%s".' % (cmd, self.fip)) - self.assertEqual(self.fip, result, msg) - return 'Verification is successful!' - - if not test_utils.call_until_true(exec_cmd_and_verify_output, - CONF.compute.build_timeout, - CONF.compute.build_interval): - raise exceptions.TimeoutException('Timed out while waiting to ' - 'verify metadata on server. ' - '%s is empty.' % md_url) - - # Also, test a POST - md_url = 'http://169.254.169.254/openstack/2013-10-17/password' - data = data_utils.arbitrary_string(100) - cmd = 'curl -X POST -d ' + data + ' ' + md_url - self.ssh_client.exec_command(cmd) - result = self.servers_client.show_password(self.instance['id']) - self.assertEqual(data, result['password']) - - def _mount_config_drive(self): - cmd_blkid = 'blkid | grep -i config-2' - result = self.ssh_client.exec_command(cmd_blkid) - dev_name = re.match('([^:]+)', result).group() - self.ssh_client.exec_command('sudo mount %s /mnt' % dev_name) - - def _unmount_config_drive(self): - self.ssh_client.exec_command('sudo umount /mnt') - - def verify_metadata_on_config_drive(self): - if self.run_ssh and CONF.compute_feature_enabled.config_drive: - # Verify metadata on config_drive - self._mount_config_drive() - cmd_md = 'sudo cat /mnt/openstack/latest/meta_data.json' - result = self.ssh_client.exec_command(cmd_md) - self._unmount_config_drive() - result = json.loads(result) - self.assertIn('meta', result) - msg = ('Failed while verifying metadata on config_drive on server.' - ' Result of command "%s" is NOT "%s".' % (cmd_md, self.md)) - self.assertEqual(self.md, result['meta'], msg) - - def verify_networkdata_on_config_drive(self): - if self.run_ssh and CONF.compute_feature_enabled.config_drive: - # Verify network data on config_drive - self._mount_config_drive() - cmd_md = 'sudo cat /mnt/openstack/latest/network_data.json' - result = self.ssh_client.exec_command(cmd_md) - self._unmount_config_drive() - result = json.loads(result) - self.assertIn('services', result) - self.assertIn('links', result) - self.assertIn('networks', result) - # TODO(clarkb) construct network_data from known network - # instance info and do direct comparison. - - @decorators.idempotent_id('7fff3fb3-91d8-4fd0-bd7d-0204f1f180ba') - @decorators.attr(type='smoke') - @test.services('compute', 'network') - def test_server_basic_ops(self): - keypair = self.create_keypair() - security_group = self._create_security_group() - self.md = {'meta1': 'data1', 'meta2': 'data2', 'metaN': 'dataN'} - self.instance = self.create_server( - key_name=keypair['name'], - security_groups=[{'name': security_group['name']}], - config_drive=CONF.compute_feature_enabled.config_drive, - metadata=self.md) - self.verify_ssh(keypair) - self.verify_metadata() - self.verify_metadata_on_config_drive() - self.verify_networkdata_on_config_drive() - self.servers_client.delete_server(self.instance['id']) - waiters.wait_for_server_termination( - self.servers_client, self.instance['id'], ignore_error=False) diff --git a/tempest/scenario/test_server_multinode.py b/tempest/scenario/test_server_multinode.py deleted file mode 100644 index 552ab27c0..000000000 --- a/tempest/scenario/test_server_multinode.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF - - -class TestServerMultinode(manager.ScenarioTest): - """This is a set of tests specific to multinode testing.""" - credentials = ['primary', 'admin'] - - @classmethod - def skip_checks(cls): - super(TestServerMultinode, cls).skip_checks() - - if CONF.compute.min_compute_nodes < 2: - raise cls.skipException( - "Less than 2 compute nodes, skipping multinode tests.") - - @decorators.idempotent_id('9cecbe35-b9d4-48da-a37e-7ce70aa43d30') - @decorators.attr(type='smoke') - @test.services('compute', 'network') - def test_schedule_to_all_nodes(self): - available_zone = \ - self.os_admin.availability_zone_client.list_availability_zones( - detail=True)['availabilityZoneInfo'] - hosts = [] - for zone in available_zone: - if zone['zoneState']['available']: - for host in zone['hosts']: - if 'nova-compute' in zone['hosts'][host] and \ - zone['hosts'][host]['nova-compute']['available']: - hosts.append({'zone': zone['zoneName'], - 'host_name': host}) - - # ensure we have at least as many compute hosts as we expect - if len(hosts) < CONF.compute.min_compute_nodes: - raise exceptions.InvalidConfiguration( - "Host list %s is shorter than min_compute_nodes. " - "Did a compute worker not boot correctly?" % hosts) - - # create 1 compute for each node, up to the min_compute_nodes - # threshold (so that things don't get crazy if you have 1000 - # compute nodes but set min to 3). - servers = [] - - for host in hosts[:CONF.compute.min_compute_nodes]: - # by getting to active state here, this means this has - # landed on the host in question. - # in order to use the availability_zone:host scheduler hint, - # admin client is need here. - inst = self.create_server( - clients=self.os_admin, - availability_zone='%(zone)s:%(host_name)s' % host) - server = self.os_admin.servers_client.show_server( - inst['id'])['server'] - # ensure server is located on the requested host - self.assertEqual(host['host_name'], server['OS-EXT-SRV-ATTR:host']) - servers.append(server) - - # make sure we really have the number of servers we think we should - self.assertEqual( - len(servers), CONF.compute.min_compute_nodes, - "Incorrect number of servers built %s" % servers) - - # ensure that every server ended up on a different host - host_ids = [x['hostId'] for x in servers] - self.assertEqual( - len(set(host_ids)), len(servers), - "Incorrect number of distinct host_ids scheduled to %s" % servers) diff --git a/tempest/scenario/test_shelve_instance.py b/tempest/scenario/test_shelve_instance.py deleted file mode 100644 index fc04b449a..000000000 --- a/tempest/scenario/test_shelve_instance.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2014 Scality -# 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 testtools - -from tempest.common import compute -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF - - -class TestShelveInstance(manager.ScenarioTest): - """This test shelves then unshelves a Nova instance - - The following is the scenario outline: - * boot an instance and create a timestamp file in it - * shelve the instance - * unshelve the instance - * check the existence of the timestamp file in the unshelved instance - - """ - - @classmethod - def skip_checks(cls): - super(TestShelveInstance, cls).skip_checks() - if not CONF.compute_feature_enabled.shelve: - raise cls.skipException("Shelve is not available.") - - def _shelve_then_unshelve_server(self, server): - compute.shelve_server(self.servers_client, server['id'], - force_shelve_offload=True) - - self.servers_client.unshelve_server(server['id']) - waiters.wait_for_server_status(self.servers_client, server['id'], - 'ACTIVE') - - def _create_server_then_shelve_and_unshelve(self, boot_from_volume=False): - keypair = self.create_keypair() - - security_group = self._create_security_group() - security_groups = [{'name': security_group['name']}] - - server = self.create_server( - key_name=keypair['name'], - security_groups=security_groups, - volume_backed=boot_from_volume) - - instance_ip = self.get_server_ip(server) - timestamp = self.create_timestamp(instance_ip, - private_key=keypair['private_key']) - - # Prevent bug #1257594 from coming back - # Unshelve used to boot the instance with the original image, not - # with the instance snapshot - self._shelve_then_unshelve_server(server) - - timestamp2 = self.get_timestamp(instance_ip, - private_key=keypair['private_key']) - self.assertEqual(timestamp, timestamp2) - - @decorators.attr(type='slow') - @decorators.idempotent_id('1164e700-0af0-4a4c-8792-35909a88743c') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - @test.services('compute', 'network', 'image') - def test_shelve_instance(self): - self._create_server_then_shelve_and_unshelve() - - @decorators.attr(type='slow') - @decorators.idempotent_id('c1b6318c-b9da-490b-9c67-9339b627271f') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - @test.services('compute', 'volume', 'network', 'image') - def test_shelve_volume_backed_instance(self): - self._create_server_then_shelve_and_unshelve(boot_from_volume=True) diff --git a/tempest/scenario/test_snapshot_pattern.py b/tempest/scenario/test_snapshot_pattern.py deleted file mode 100644 index 52767dc34..000000000 --- a/tempest/scenario/test_snapshot_pattern.py +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright 2013 NEC Corporation -# 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 testtools - -from tempest import config -from tempest.lib import decorators -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF - - -class TestSnapshotPattern(manager.ScenarioTest): - """This test is for snapshotting an instance and booting with it. - - The following is the scenario outline: - * boot an instance and create a timestamp file in it - * snapshot the instance - * boot a second instance from the snapshot - * check the existence of the timestamp file in the second instance - - """ - - @classmethod - def skip_checks(cls): - super(TestSnapshotPattern, cls).skip_checks() - if not CONF.compute_feature_enabled.snapshot: - raise cls.skipException("Snapshotting is not available.") - - @decorators.idempotent_id('608e604b-1d63-4a82-8e3e-91bc665c90b4') - @decorators.attr(type='slow') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - @test.services('compute', 'network', 'image') - def test_snapshot_pattern(self): - # prepare for booting an instance - keypair = self.create_keypair() - security_group = self._create_security_group() - - # boot an instance and create a timestamp file in it - server = self.create_server( - key_name=keypair['name'], - security_groups=[{'name': security_group['name']}]) - - instance_ip = self.get_server_ip(server) - timestamp = self.create_timestamp(instance_ip, - private_key=keypair['private_key']) - - # snapshot the instance - snapshot_image = self.create_server_snapshot(server=server) - - # boot a second instance from the snapshot - server_from_snapshot = self.create_server( - image_id=snapshot_image['id'], - key_name=keypair['name'], - security_groups=[{'name': security_group['name']}]) - - # check the existence of the timestamp file in the second instance - server_from_snapshot_ip = self.get_server_ip(server_from_snapshot) - timestamp2 = self.get_timestamp(server_from_snapshot_ip, - private_key=keypair['private_key']) - self.assertEqual(timestamp, timestamp2) diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py deleted file mode 100644 index 363264859..000000000 --- a/tempest/scenario/test_stamp_pattern.py +++ /dev/null @@ -1,130 +0,0 @@ -# Copyright 2013 NEC Corporation -# 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 oslo_log import log as logging -import testtools - -from tempest import config -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF -LOG = logging.getLogger(__name__) - - -class TestStampPattern(manager.ScenarioTest): - """The test suite for both snapshoting and attaching of volume - - This test is for snapshotting an instance/volume and attaching the volume - created from snapshot to the instance booted from snapshot. - The following is the scenario outline: - 1. Boot an instance "instance1" - 2. Create a volume "volume1" - 3. Attach volume1 to instance1 - 4. Create a filesystem on volume1 - 5. Mount volume1 - 6. Create a file which timestamp is written in volume1 - 7. Unmount volume1 - 8. Detach volume1 from instance1 - 9. Get a snapshot "snapshot_from_volume" of volume1 - 10. Get a snapshot "snapshot_from_instance" of instance1 - 11. Boot an instance "instance2" from snapshot_from_instance - 12. Create a volume "volume2" from snapshot_from_volume - 13. Attach volume2 to instance2 - 14. Check the existence of a file which created at 6. in volume2 - """ - - @classmethod - def skip_checks(cls): - super(TestStampPattern, cls).skip_checks() - if not CONF.volume_feature_enabled.snapshot: - raise cls.skipException("Cinder volume snapshots are disabled") - - def _wait_for_volume_available_on_the_system(self, ip_address, - private_key): - ssh = self.get_remote_client(ip_address, private_key=private_key) - - def _func(): - disks = ssh.get_disks() - LOG.debug("Disks: %s", disks) - return CONF.compute.volume_device_name in disks - - if not test_utils.call_until_true(_func, - CONF.compute.build_timeout, - CONF.compute.build_interval): - raise lib_exc.TimeoutException - - @decorators.attr(type='slow') - @decorators.skip_because(bug="1664793") - @decorators.idempotent_id('10fd234a-515c-41e5-b092-8323060598c5') - @testtools.skipUnless(CONF.compute_feature_enabled.snapshot, - 'Snapshotting is not available.') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - @test.services('compute', 'network', 'volume', 'image') - def test_stamp_pattern(self): - # prepare for booting an instance - keypair = self.create_keypair() - security_group = self._create_security_group() - - # boot an instance and create a timestamp file in it - volume = self.create_volume() - server = self.create_server( - key_name=keypair['name'], - security_groups=[{'name': security_group['name']}]) - - # create and add floating IP to server1 - ip_for_server = self.get_server_ip(server) - - self.nova_volume_attach(server, volume) - self._wait_for_volume_available_on_the_system(ip_for_server, - keypair['private_key']) - timestamp = self.create_timestamp(ip_for_server, - CONF.compute.volume_device_name, - private_key=keypair['private_key']) - self.nova_volume_detach(server, volume) - - # snapshot the volume - volume_snapshot = self.create_volume_snapshot(volume['id']) - - # snapshot the instance - snapshot_image = self.create_server_snapshot(server=server) - - # create second volume from the snapshot(volume2) - volume_from_snapshot = self.create_volume( - snapshot_id=volume_snapshot['id']) - - # boot second instance from the snapshot(instance2) - server_from_snapshot = self.create_server( - image_id=snapshot_image['id'], - key_name=keypair['name'], - security_groups=[{'name': security_group['name']}]) - - # create and add floating IP to server_from_snapshot - ip_for_snapshot = self.get_server_ip(server_from_snapshot) - - # attach volume2 to instance2 - self.nova_volume_attach(server_from_snapshot, volume_from_snapshot) - self._wait_for_volume_available_on_the_system(ip_for_snapshot, - keypair['private_key']) - - # check the existence of the timestamp file in the volume2 - timestamp2 = self.get_timestamp(ip_for_snapshot, - CONF.compute.volume_device_name, - private_key=keypair['private_key']) - self.assertEqual(timestamp, timestamp2) diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py deleted file mode 100644 index b6f3b38cf..000000000 --- a/tempest/scenario/test_volume_boot_pattern.py +++ /dev/null @@ -1,236 +0,0 @@ -# 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 oslo_log import log as logging -import testtools - -from tempest.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF -LOG = logging.getLogger(__name__) - - -class TestVolumeBootPattern(manager.EncryptionScenarioTest): - - # Boot from volume scenario is quite slow, and needs extra - # breathing room to get through deletes in the time allotted. - TIMEOUT_SCALING_FACTOR = 2 - - @classmethod - def skip_checks(cls): - super(TestVolumeBootPattern, cls).skip_checks() - if not CONF.volume_feature_enabled.snapshot: - raise cls.skipException("Cinder volume snapshots are disabled") - - def _create_volume_from_image(self): - img_uuid = CONF.compute.image_ref - vol_name = data_utils.rand_name( - self.__class__.__name__ + '-volume-origin') - return self.create_volume(name=vol_name, imageRef=img_uuid) - - def _get_bdm(self, source_id, source_type, delete_on_termination=False): - bd_map_v2 = [{ - 'uuid': source_id, - 'source_type': source_type, - 'destination_type': 'volume', - 'boot_index': 0, - 'delete_on_termination': delete_on_termination}] - return {'block_device_mapping_v2': bd_map_v2} - - def _boot_instance_from_resource(self, source_id, - source_type, - keypair=None, - security_group=None, - delete_on_termination=False): - create_kwargs = dict() - if keypair: - create_kwargs['key_name'] = keypair['name'] - if security_group: - create_kwargs['security_groups'] = [ - {'name': security_group['name']}] - create_kwargs.update(self._get_bdm( - source_id, - source_type, - delete_on_termination=delete_on_termination)) - - return self.create_server(image_id='', **create_kwargs) - - def _delete_server(self, server): - self.servers_client.delete_server(server['id']) - waiters.wait_for_server_termination(self.servers_client, server['id']) - - @decorators.idempotent_id('557cd2c2-4eb8-4dce-98be-f86765ff311b') - @testtools.skipUnless(CONF.network.public_network_id, - 'The public_network_id option must be specified.') - @test.services('compute', 'volume', 'image') - def test_volume_boot_pattern(self): - - """This test case attempts to reproduce the following steps: - - * Create in Cinder some bootable volume importing a Glance image - * Boot an instance from the bootable volume - * Write content to the volume - * Delete an instance and Boot a new instance from the volume - * Check written content in the instance - * Create a volume snapshot while the instance is running - * Boot an additional instance from the new snapshot based volume - * Check written content in the instance booted from snapshot - """ - - LOG.info("Creating keypair and security group") - keypair = self.create_keypair() - security_group = self._create_security_group() - - # create an instance from volume - LOG.info("Booting instance 1 from volume") - volume_origin = self._create_volume_from_image() - instance_1st = self._boot_instance_from_resource( - source_id=volume_origin['id'], - source_type='volume', - keypair=keypair, - security_group=security_group) - LOG.info("Booted first instance: %s", instance_1st) - - # write content to volume on instance - LOG.info("Setting timestamp in instance %s", instance_1st) - ip_instance_1st = self.get_server_ip(instance_1st) - timestamp = self.create_timestamp(ip_instance_1st, - private_key=keypair['private_key']) - - # delete instance - LOG.info("Deleting first instance: %s", instance_1st) - self._delete_server(instance_1st) - - # create a 2nd instance from volume - instance_2nd = self._boot_instance_from_resource( - source_id=volume_origin['id'], - source_type='volume', - keypair=keypair, - security_group=security_group) - LOG.info("Booted second instance %s", instance_2nd) - - # check the content of written file - LOG.info("Getting timestamp in instance %s", instance_2nd) - ip_instance_2nd = self.get_server_ip(instance_2nd) - timestamp2 = self.get_timestamp(ip_instance_2nd, - private_key=keypair['private_key']) - self.assertEqual(timestamp, timestamp2) - - # snapshot a volume - LOG.info("Creating snapshot from volume: %s", volume_origin['id']) - snapshot = self.create_volume_snapshot(volume_origin['id'], force=True) - - # create a 3rd instance from snapshot - LOG.info("Creating third instance from snapshot: %s", snapshot['id']) - volume = self.create_volume(snapshot_id=snapshot['id'], - size=snapshot['size']) - LOG.info("Booting third instance from snapshot") - server_from_snapshot = ( - self._boot_instance_from_resource(source_id=volume['id'], - source_type='volume', - keypair=keypair, - security_group=security_group)) - LOG.info("Booted third instance %s", server_from_snapshot) - - # check the content of written file - LOG.info("Logging into third instance to get timestamp: %s", - server_from_snapshot) - server_from_snapshot_ip = self.get_server_ip(server_from_snapshot) - timestamp3 = self.get_timestamp(server_from_snapshot_ip, - private_key=keypair['private_key']) - self.assertEqual(timestamp, timestamp3) - - @decorators.idempotent_id('05795fb2-b2a7-4c9f-8fac-ff25aedb1489') - @decorators.attr(type='slow') - @test.services('compute', 'image', 'volume') - def test_create_server_from_volume_snapshot(self): - # Create a volume from an image - boot_volume = self._create_volume_from_image() - - # Create a snapshot - boot_snapshot = self.create_volume_snapshot(boot_volume['id']) - - # Create a server from a volume snapshot - server = self._boot_instance_from_resource( - source_id=boot_snapshot['id'], - source_type='snapshot', - delete_on_termination=True) - - server_info = self.servers_client.show_server(server['id'])['server'] - - # The created volume when creating a server from a snapshot - created_volume = server_info['os-extended-volumes:volumes_attached'] - - self.assertNotEmpty(created_volume, "No volume attachment found.") - - created_volume_info = self.volumes_client.show_volume( - created_volume[0]['id'])['volume'] - - # Verify the server was created from the snapshot - self.assertEqual( - boot_volume['volume_image_metadata']['image_id'], - created_volume_info['volume_image_metadata']['image_id']) - self.assertEqual(boot_snapshot['id'], - created_volume_info['snapshot_id']) - self.assertEqual(server['id'], - created_volume_info['attachments'][0]['server_id']) - self.assertEqual(created_volume[0]['id'], - created_volume_info['attachments'][0]['volume_id']) - - @decorators.idempotent_id('36c34c67-7b54-4b59-b188-02a2f458a63b') - @test.services('compute', 'volume', 'image') - def test_create_ebs_image_and_check_boot(self): - # create an instance from volume - volume_origin = self._create_volume_from_image() - instance = self._boot_instance_from_resource( - source_id=volume_origin['id'], - source_type='volume', - delete_on_termination=True) - # create EBS image - image = self.create_server_snapshot(instance) - - # delete instance - self._delete_server(instance) - - # boot instance from EBS image - instance = self.create_server(image_id=image['id']) - # just ensure that instance booted - - # delete instance - self._delete_server(instance) - - @decorators.idempotent_id('cb78919a-e553-4bab-b73b-10cf4d2eb125') - @testtools.skipUnless(CONF.compute_feature_enabled.attach_encrypted_volume, - 'Encrypted volume attach is not supported') - @test.services('compute', 'volume') - def test_boot_server_from_encrypted_volume_luks(self): - # Create an encrypted volume - volume = self.create_encrypted_volume('nova.volume.encryptors.' - 'luks.LuksEncryptor', - volume_type='luks') - - self.volumes_client.set_bootable_volume(volume['id'], bootable=True) - - # Boot a server from the encrypted volume - server = self._boot_instance_from_resource( - source_id=volume['id'], - source_type='volume', - delete_on_termination=False) - - server_info = self.servers_client.show_server(server['id'])['server'] - created_volume = server_info['os-extended-volumes:volumes_attached'] - self.assertEqual(volume['id'], created_volume[0]['id']) diff --git a/tempest/scenario/test_volume_migrate_attached.py b/tempest/scenario/test_volume_migrate_attached.py deleted file mode 100644 index 5667fbb74..000000000 --- a/tempest/scenario/test_volume_migrate_attached.py +++ /dev/null @@ -1,127 +0,0 @@ -# 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 oslo_log import log as logging - -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators -from tempest.scenario import manager -from tempest import test - -CONF = config.CONF -LOG = logging.getLogger(__name__) - - -class TestVolumeMigrateRetypeAttached(manager.ScenarioTest): - - """This test case attempts to reproduce the following steps: - - * Create 2 volume types representing 2 different backends - * Create in Cinder some bootable volume importing a Glance image using - * volume_type_1 - * Boot an instance from the bootable volume - * Write to the volume - * Perform a cinder retype --on-demand of the volume to type of backend #2 - * Check written content of migrated volume - """ - - credentials = ['primary', 'admin'] - - @classmethod - def setup_clients(cls): - super(TestVolumeMigrateRetypeAttached, cls).setup_clients() - cls.admin_volumes_client = cls.os_admin.volumes_v2_client - - @classmethod - def skip_checks(cls): - super(TestVolumeMigrateRetypeAttached, cls).skip_checks() - if not CONF.volume_feature_enabled.multi_backend: - raise cls.skipException("Cinder multi-backend feature disabled") - - if len(set(CONF.volume.backend_names)) < 2: - raise cls.skipException("Requires at least two different " - "backend names") - - def _boot_instance_from_volume(self, vol_id, keypair, security_group): - - key_name = keypair['name'] - security_groups = [{'name': security_group['name']}] - block_device_mapping = [{'device_name': 'vda', 'volume_id': vol_id, - 'delete_on_termination': False}] - - return self.create_server(image_id='', - key_name=key_name, - security_groups=security_groups, - block_device_mapping=block_device_mapping) - - def _create_volume_types(self): - backend_names = CONF.volume.backend_names - - backend_source = backend_names[0] - backend_dest = backend_names[1] - - source_body = self.create_volume_type(backend_name=backend_source) - dest_body = self.create_volume_type(backend_name=backend_dest) - - LOG.info("Created Volume types: %(src)s -> %(src_backend)s, %(dst)s " - "-> %(dst_backend)s", {'src': source_body['name'], - 'src_backend': backend_source, - 'dst': dest_body['name'], - 'dst_backend': backend_dest}) - return source_body['name'], dest_body['name'] - - def _volume_retype_with_migration(self, volume_id, new_volume_type): - migration_policy = 'on-demand' - self.admin_volumes_client.retype_volume( - volume_id, new_type=new_volume_type, - migration_policy=migration_policy) - waiters.wait_for_volume_retype(self.volumes_client, - volume_id, new_volume_type) - - @decorators.attr(type='slow') - @decorators.idempotent_id('deadd2c2-beef-4dce-98be-f86765ff311b') - @test.services('compute', 'volume') - def test_volume_migrate_attached(self): - LOG.info("Creating keypair and security group") - keypair = self.create_keypair() - security_group = self._create_security_group() - - # create volume types - LOG.info("Creating Volume types") - source_type, dest_type = self._create_volume_types() - - # create an instance from volume - LOG.info("Booting instance from volume") - volume_origin = self.create_volume(imageRef=CONF.compute.image_ref, - volume_type=source_type) - - instance = self._boot_instance_from_volume(volume_origin['id'], - keypair, security_group) - - # write content to volume on instance - LOG.info("Setting timestamp in instance %s", instance['id']) - ip_instance = self.get_server_ip(instance) - timestamp = self.create_timestamp(ip_instance, - private_key=keypair['private_key']) - - # retype volume with migration from backend #1 to backend #2 - LOG.info("Retyping Volume %s to new type %s", volume_origin['id'], - dest_type) - self._volume_retype_with_migration(volume_origin['id'], dest_type) - - # check the content of written file - LOG.info("Getting timestamp in postmigrated instance %s", - instance['id']) - timestamp2 = self.get_timestamp(ip_instance, - private_key=keypair['private_key']) - self.assertEqual(timestamp, timestamp2) diff --git a/tempest/services/__init__.py b/tempest/services/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/services/object_storage/__init__.py b/tempest/services/object_storage/__init__.py deleted file mode 100644 index 17385664b..000000000 --- a/tempest/services/object_storage/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# 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 tempest.services.object_storage.account_client import AccountClient -from tempest.services.object_storage.bulk_middleware_client import \ - BulkMiddlewareClient -from tempest.services.object_storage.capabilities_client import \ - CapabilitiesClient -from tempest.services.object_storage.container_client import ContainerClient -from tempest.services.object_storage.object_client import ObjectClient - -__all__ = ['AccountClient', 'BulkMiddlewareClient', 'CapabilitiesClient', - 'ContainerClient', 'ObjectClient'] diff --git a/tempest/services/object_storage/account_client.py b/tempest/services/object_storage/account_client.py deleted file mode 100644 index 5a1737e6a..000000000 --- a/tempest/services/object_storage/account_client.py +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 xml.etree import ElementTree as etree - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class AccountClient(rest_client.RestClient): - - def create_update_or_delete_account_metadata( - self, - create_update_metadata=None, - delete_metadata=None, - create_update_metadata_prefix='X-Account-Meta-', - delete_metadata_prefix='X-Remove-Account-Meta-'): - """Creates, Updates or deletes an account metadata entry. - - Account Metadata can be created, updated or deleted based on - metadata header or value. For detailed info, please refer to the - official API reference: - http://developer.openstack.org/api-ref/object-storage/?expanded=create-update-or-delete-account-metadata-detail - """ - headers = {} - if create_update_metadata: - for key in create_update_metadata: - metadata_header_name = create_update_metadata_prefix + key - headers[metadata_header_name] = create_update_metadata[key] - if delete_metadata: - for key in delete_metadata: - headers[delete_metadata_prefix + key] = delete_metadata[key] - - resp, body = self.post('', headers=headers, body=None) - self.expected_success([200, 204], resp.status) - return resp, body - - def list_account_metadata(self): - """HEAD on the storage URL - - Returns all account metadata headers - """ - resp, body = self.head('') - self.expected_success(204, resp.status) - return resp, body - - def list_account_containers(self, params=None): - """GET on the (base) storage URL - - Given valid X-Auth-Token, returns a list of all containers for the - account. - - Optional Arguments: - limit=[integer value N] - Limits the number of results to at most N values - DEFAULT: 10,000 - - marker=[string value X] - Given string value X, return object names greater in value - than the specified marker. - DEFAULT: No Marker - - prefix=[string value Y] - Given string value Y, return object names starting with that prefix - - reverse=[boolean value Z] - Reverse the result order based on the boolean value Z - DEFAULT: False - - format=[string value, either 'json' or 'xml'] - Specify either json or xml to return the respective serialized - response. - DEFAULT: Python-List returned in response body - """ - url = '?%s' % urllib.urlencode(params) if params else '' - - resp, body = self.get(url, headers={}) - if params and params.get('format') == 'json': - body = json.loads(body) - elif params and params.get('format') == 'xml': - body = etree.fromstring(body) - else: - body = body.strip().splitlines() - self.expected_success([200, 204], resp.status) - return resp, body diff --git a/tempest/services/object_storage/bulk_middleware_client.py b/tempest/services/object_storage/bulk_middleware_client.py deleted file mode 100644 index c11a105b8..000000000 --- a/tempest/services/object_storage/bulk_middleware_client.py +++ /dev/null @@ -1,62 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 tempest.lib.common import rest_client - - -class BulkMiddlewareClient(rest_client.RestClient): - - def upload_archive(self, upload_path, data, - archive_file_format='tar', headers=None): - """Expand tar files into a Swift cluster. - - To extract containers and objects on Swift cluster from - uploaded archived file. For More information please check: - https://docs.openstack.org/swift/latest/middleware.html#module-swift.common.middleware.bulk - """ - url = '%s?extract-archive=%s' % (upload_path, archive_file_format) - if headers is None: - headers = {} - resp, body = self.put(url, data, headers) - self.expected_success(200, resp.status) - return rest_client.ResponseBodyData(resp, body) - - def delete_bulk_data(self, data=None, headers=None): - """Delete multiple objects or containers from their account. - - For More information please check: - https://docs.openstack.org/swift/latest/middleware.html#module-swift.common.middleware.bulk - """ - url = '?bulk-delete' - - if headers is None: - headers = {} - resp, body = self.delete(url, headers, data) - self.expected_success(200, resp.status) - return rest_client.ResponseBodyData(resp, body) - - def delete_bulk_data_with_post(self, data=None, headers=None): - """Delete multiple objects or containers with POST request. - - For More information please check: - https://docs.openstack.org/swift/latest/middleware.html#module-swift.common.middleware.bulk - """ - url = '?bulk-delete' - - if headers is None: - headers = {} - resp, body = self.post(url, data, headers) - self.expected_success([200, 204], resp.status) - return rest_client.ResponseBodyData(resp, body) diff --git a/tempest/services/object_storage/capabilities_client.py b/tempest/services/object_storage/capabilities_client.py deleted file mode 100644 index d31bbc299..000000000 --- a/tempest/services/object_storage/capabilities_client.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 oslo_serialization import jsonutils as json - -from tempest.lib.common import rest_client - - -class CapabilitiesClient(rest_client.RestClient): - - def list_capabilities(self): - self.skip_path() - try: - resp, body = self.get('info') - finally: - self.reset_path() - body = json.loads(body) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, body) diff --git a/tempest/services/object_storage/container_client.py b/tempest/services/object_storage/container_client.py deleted file mode 100644 index afedd3669..000000000 --- a/tempest/services/object_storage/container_client.py +++ /dev/null @@ -1,150 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 xml.etree import ElementTree as etree - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest.lib.common import rest_client - - -class ContainerClient(rest_client.RestClient): - - def create_container( - self, container_name, - metadata=None, - remove_metadata=None, - metadata_prefix='X-Container-Meta-', - remove_metadata_prefix='X-Remove-Container-Meta-'): - """Creates a container - - with optional metadata passed in as a dictionary - """ - url = str(container_name) - headers = {} - - if metadata is not None: - for key in metadata: - headers[metadata_prefix + key] = metadata[key] - if remove_metadata is not None: - for key in remove_metadata: - headers[remove_metadata_prefix + key] = remove_metadata[key] - - resp, body = self.put(url, body=None, headers=headers) - self.expected_success([201, 202], resp.status) - return resp, body - - def delete_container(self, container_name): - """Deletes the container (if it's empty).""" - url = str(container_name) - resp, body = self.delete(url) - self.expected_success(204, resp.status) - return resp, body - - def update_container_metadata( - self, container_name, - metadata=None, - remove_metadata=None, - metadata_prefix='X-Container-Meta-', - remove_metadata_prefix='X-Remove-Container-Meta-'): - """Updates arbitrary metadata on container.""" - url = str(container_name) - headers = {} - - if metadata is not None: - for key in metadata: - headers[metadata_prefix + key] = metadata[key] - if remove_metadata is not None: - for key in remove_metadata: - headers[remove_metadata_prefix + key] = remove_metadata[key] - - resp, body = self.post(url, body=None, headers=headers) - self.expected_success(204, resp.status) - return resp, body - - def delete_container_metadata(self, container_name, metadata, - metadata_prefix='X-Remove-Container-Meta-'): - """Deletes arbitrary metadata on container.""" - url = str(container_name) - headers = {} - - if metadata is not None: - for item in metadata: - headers[metadata_prefix + item] = metadata[item] - - resp, body = self.post(url, body=None, headers=headers) - self.expected_success(204, resp.status) - return resp, body - - def list_container_metadata(self, container_name): - """Retrieves container metadata headers""" - url = str(container_name) - resp, body = self.head(url) - self.expected_success(204, resp.status) - return resp, body - - def list_container_contents(self, container, params=None): - """List the objects in a container, given the container name - - Returns the container object listing as a plain text list, or as - xml or json if that option is specified via the 'format' argument. - - Optional Arguments: - limit = integer - For an integer value n, limits the number of results to at most - n values. - - marker = 'string' - Given a string value x, return object names greater in value - than the specified marker. - - prefix = 'string' - For a string value x, causes the results to be limited to names - beginning with the substring x. - - format = 'json' or 'xml' - Specify either json or xml to return the respective serialized - response. - If json, returns a list of json objects - if xml, returns a string of xml - - path = 'string' - For a string value x, return the object names nested in the - pseudo path (assuming preconditions are met - see below). - - delimiter = 'character' - For a character c, return all the object names nested in the - container (without the need for the directory marker objects). - """ - - url = str(container) - if params: - url += '?' - url += '&%s' % urllib.urlencode(params) - - resp, body = self.get(url, headers={}) - if params and params.get('format') == 'json': - body = json.loads(body) - elif params and params.get('format') == 'xml': - body = etree.fromstring(body) - # Else the content-type is plain/text - else: - body = [ - obj_name for obj_name in body.decode().split('\n') if obj_name - ] - - self.expected_success([200, 204], resp.status) - return resp, body diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py deleted file mode 100644 index 6d656ec57..000000000 --- a/tempest/services/object_storage/object_client.py +++ /dev/null @@ -1,231 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 six.moves import http_client as httplib -from six.moves.urllib import parse as urlparse - -from tempest.lib.common import rest_client -from tempest.lib import exceptions - - -class ObjectClient(rest_client.RestClient): - - def create_object(self, container, object_name, data, - params=None, metadata=None, headers=None): - """Create storage object.""" - - if headers is None: - headers = self.get_headers() - if not data: - headers['content-length'] = '0' - if metadata: - for key in metadata: - headers[str(key)] = metadata[key] - url = "%s/%s" % (str(container), str(object_name)) - if params: - url += '?%s' % urlparse.urlencode(params) - - resp, body = self.put(url, data, headers) - self.expected_success(201, resp.status) - return resp, body - - def delete_object(self, container, object_name, params=None): - """Delete storage object.""" - url = "%s/%s" % (str(container), str(object_name)) - if params: - url += '?%s' % urlparse.urlencode(params) - resp, body = self.delete(url, headers={}) - self.expected_success([200, 204], resp.status) - return resp, body - - def update_object_metadata(self, container, object_name, metadata, - metadata_prefix='X-Object-Meta-'): - """Add, remove, or change X-Object-Meta metadata for storage object.""" - - headers = {} - for key in metadata: - headers["%s%s" % (str(metadata_prefix), str(key))] = metadata[key] - - url = "%s/%s" % (str(container), str(object_name)) - resp, body = self.post(url, None, headers=headers) - self.expected_success(202, resp.status) - return resp, body - - def list_object_metadata(self, container, object_name): - """List all storage object X-Object-Meta- metadata.""" - - url = "%s/%s" % (str(container), str(object_name)) - resp, body = self.head(url) - self.expected_success(200, resp.status) - return resp, body - - def get_object(self, container, object_name, metadata=None): - """Retrieve object's data.""" - - headers = {} - if metadata: - for key in metadata: - headers[str(key)] = metadata[key] - - url = "{0}/{1}".format(container, object_name) - resp, body = self.get(url, headers=headers) - self.expected_success([200, 206], resp.status) - return resp, body - - def copy_object_in_same_container(self, container, src_object_name, - dest_object_name, metadata=None): - """Copy storage object's data to the new object using PUT.""" - - url = "{0}/{1}".format(container, dest_object_name) - headers = {} - headers['X-Copy-From'] = "%s/%s" % (str(container), - str(src_object_name)) - headers['content-length'] = '0' - if metadata: - for key in metadata: - headers[str(key)] = metadata[key] - - resp, body = self.put(url, None, headers=headers) - self.expected_success(201, resp.status) - return resp, body - - def copy_object_across_containers(self, src_container, src_object_name, - dst_container, dst_object_name, - metadata=None): - """Copy storage object's data to the new object using PUT.""" - - url = "{0}/{1}".format(dst_container, dst_object_name) - headers = {} - headers['X-Copy-From'] = "%s/%s" % (str(src_container), - str(src_object_name)) - headers['content-length'] = '0' - if metadata: - for key in metadata: - headers[str(key)] = metadata[key] - - resp, body = self.put(url, None, headers=headers) - self.expected_success(201, resp.status) - return resp, body - - def copy_object_2d_way(self, container, src_object_name, dest_object_name, - metadata=None): - """Copy storage object's data to the new object using COPY.""" - - url = "{0}/{1}".format(container, src_object_name) - headers = {} - headers['Destination'] = "%s/%s" % (str(container), - str(dest_object_name)) - if metadata: - for key in metadata: - headers[str(key)] = metadata[key] - - resp, body = self.copy(url, headers=headers) - self.expected_success(201, resp.status) - return resp, body - - def create_object_segments(self, container, object_name, segment, data): - """Creates object segments.""" - url = "{0}/{1}/{2}".format(container, object_name, segment) - resp, body = self.put(url, data) - self.expected_success(201, resp.status) - return resp, body - - def put_object_with_chunk(self, container, name, contents): - """Put an object with Transfer-Encoding header - - :param container: name of the container - :type container: string - :param name: name of the object - :type name: string - :param contents: object data - :type contents: iterable - """ - headers = {'Transfer-Encoding': 'chunked'} - if self.token: - headers['X-Auth-Token'] = self.token - - url = "%s/%s" % (container, name) - resp, body = self.put( - url, headers=headers, - body=contents, - chunked=True - ) - - self._error_checker(resp, body) - self.expected_success(201, resp.status) - return resp.status, resp.reason, resp - - def create_object_continue(self, container, object_name, - data, metadata=None): - """Put an object using Expect:100-continue""" - headers = {} - if metadata: - for key in metadata: - headers[str(key)] = metadata[key] - - headers['X-Auth-Token'] = self.token - headers['content-length'] = 0 if data is None else len(data) - headers['Expect'] = '100-continue' - - parsed = urlparse.urlparse(self.base_url) - path = str(parsed.path) + "/" - path += "%s/%s" % (str(container), str(object_name)) - - conn = create_connection(parsed) - - # Send the PUT request and the headers including the "Expect" header - conn.putrequest('PUT', path) - - for header, value in headers.items(): - conn.putheader(header, value) - conn.endheaders() - - # Read the 100 status prior to sending the data - response = conn.response_class(conn.sock, - method=conn._method) - _, status, _ = response._read_status() - - # toss the CRLF at the end of the response - response._safe_read(2) - - # Expecting a 100 here, if not close and throw an exception - if status != 100: - conn.close() - pattern = "%s %s" % ( - """Unexpected http success status code {0}.""", - """The expected status code is {1}""") - details = pattern.format(status, 100) - raise exceptions.UnexpectedResponseCode(details) - - # If a continue was received go ahead and send the data - # and get the final response - conn.send(data) - - resp = conn.getresponse() - - return resp.status, resp.reason - - -def create_connection(parsed_url): - """Helper function to create connection with httplib - - :param parsed_url: parsed url of the remote location - """ - if parsed_url.scheme == 'https': - conn = httplib.HTTPSConnection(parsed_url.netloc) - else: - conn = httplib.HTTPConnection(parsed_url.netloc) - - return conn diff --git a/tempest/services/orchestration/__init__.py b/tempest/services/orchestration/__init__.py deleted file mode 100644 index 5a1ffcc30..000000000 --- a/tempest/services/orchestration/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# 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 tempest.services.orchestration.json.orchestration_client import \ - OrchestrationClient - -__all__ = ['OrchestrationClient'] diff --git a/tempest/services/orchestration/json/__init__.py b/tempest/services/orchestration/json/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/services/orchestration/json/orchestration_client.py b/tempest/services/orchestration/json/orchestration_client.py deleted file mode 100644 index 9fec5482b..000000000 --- a/tempest/services/orchestration/json/orchestration_client.py +++ /dev/null @@ -1,413 +0,0 @@ -# Copyright 2013 IBM 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 re -import time - -from oslo_serialization import jsonutils as json -from six.moves.urllib import parse as urllib - -from tempest import exceptions -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc - - -class OrchestrationClient(rest_client.RestClient): - - def list_stacks(self, params=None): - """Lists all stacks for a user.""" - - uri = 'stacks' - if params: - uri += '?%s' % urllib.urlencode(params) - - resp, body = self.get(uri) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def create_stack(self, name, disable_rollback=True, parameters=None, - timeout_mins=60, template=None, template_url=None, - environment=None, files=None): - if parameters is None: - parameters = {} - headers, body = self._prepare_update_create( - name, - disable_rollback, - parameters, - timeout_mins, - template, - template_url, - environment, - files) - uri = 'stacks' - resp, body = self.post(uri, headers=headers, body=body) - self.expected_success(201, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_stack(self, stack_identifier, name, disable_rollback=True, - parameters=None, timeout_mins=60, template=None, - template_url=None, environment=None, files=None): - if parameters is None: - parameters = {} - headers, body = self._prepare_update_create( - name, - disable_rollback, - parameters, - timeout_mins, - template, - template_url, - environment) - - uri = "stacks/%s" % stack_identifier - resp, body = self.put(uri, headers=headers, body=body) - self.expected_success(202, resp.status) - return rest_client.ResponseBody(resp, body) - - def _prepare_update_create(self, name, disable_rollback=True, - parameters=None, timeout_mins=60, - template=None, template_url=None, - environment=None, files=None): - if parameters is None: - parameters = {} - post_body = { - "stack_name": name, - "disable_rollback": disable_rollback, - "parameters": parameters, - "timeout_mins": timeout_mins, - "template": "HeatTemplateFormatVersion: '2012-12-12'\n", - "environment": environment, - "files": files - } - if template: - post_body['template'] = template - if template_url: - post_body['template_url'] = template_url - body = json.dumps(post_body) - - # Password must be provided on stack create so that heat - # can perform future operations on behalf of the user - headers = self.get_headers() - headers['X-Auth-Key'] = self.password - headers['X-Auth-User'] = self.user - return headers, body - - def show_stack(self, stack_identifier): - """Returns the details of a single stack.""" - url = "stacks/%s" % stack_identifier - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def suspend_stack(self, stack_identifier): - """Suspend a stack.""" - url = 'stacks/%s/actions' % stack_identifier - body = {'suspend': None} - resp, body = self.post(url, json.dumps(body)) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp) - - def resume_stack(self, stack_identifier): - """Resume a stack.""" - url = 'stacks/%s/actions' % stack_identifier - body = {'resume': None} - resp, body = self.post(url, json.dumps(body)) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp) - - def list_resources(self, stack_identifier): - """Returns the details of a single resource.""" - url = "stacks/%s/resources" % stack_identifier - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_resource(self, stack_identifier, resource_name): - """Returns the details of a single resource.""" - url = "stacks/%s/resources/%s" % (stack_identifier, resource_name) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_stack(self, stack_identifier): - """Deletes the specified Stack.""" - resp, _ = self.delete("stacks/%s" % str(stack_identifier)) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def wait_for_stack_status(self, stack_identifier, status, - failure_pattern='^.*_FAILED$'): - """Waits for a Stack to reach a given status.""" - start = int(time.time()) - fail_regexp = re.compile(failure_pattern) - - while True: - try: - body = self.show_stack(stack_identifier)['stack'] - except lib_exc.NotFound: - if status == 'DELETE_COMPLETE': - return - stack_name = body['stack_name'] - stack_status = body['stack_status'] - if stack_status == status: - return body - if fail_regexp.search(stack_status): - raise exceptions.StackBuildErrorException( - stack_identifier=stack_identifier, - stack_status=stack_status, - stack_status_reason=body['stack_status_reason']) - - if int(time.time()) - start >= self.build_timeout: - message = ('Stack %s failed to reach %s status (current: %s) ' - 'within the required time (%s s).' % - (stack_name, status, stack_status, - self.build_timeout)) - raise lib_exc.TimeoutException(message) - time.sleep(self.build_interval) - - def show_resource_metadata(self, stack_identifier, resource_name): - """Returns the resource's metadata.""" - url = ('stacks/{stack_identifier}/resources/{resource_name}' - '/metadata'.format(**locals())) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_events(self, stack_identifier): - """Returns list of all events for a stack.""" - url = 'stacks/{stack_identifier}/events'.format(**locals()) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_resource_events(self, stack_identifier, resource_name): - """Returns list of all events for a resource from stack.""" - url = ('stacks/{stack_identifier}/resources/{resource_name}' - '/events'.format(**locals())) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_event(self, stack_identifier, resource_name, event_id): - """Returns the details of a single stack's event.""" - url = ('stacks/{stack_identifier}/resources/{resource_name}/events' - '/{event_id}'.format(**locals())) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_template(self, stack_identifier): - """Returns the template for the stack.""" - url = ('stacks/{stack_identifier}/template'.format(**locals())) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def _validate_template(self, post_body): - """Returns the validation request result.""" - post_body = json.dumps(post_body) - resp, body = self.post('validate', post_body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def validate_template(self, template, parameters=None): - """Returns the validation result for a template with parameters.""" - if parameters is None: - parameters = {} - post_body = { - 'template': template, - 'parameters': parameters, - } - return self._validate_template(post_body) - - def validate_template_url(self, template_url, parameters=None): - """Returns the validation result for a template with parameters.""" - if parameters is None: - parameters = {} - post_body = { - 'template_url': template_url, - 'parameters': parameters, - } - return self._validate_template(post_body) - - def list_resource_types(self): - """List resource types.""" - resp, body = self.get('resource_types') - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_resource_type(self, resource_type_name): - """Return the schema of a resource type.""" - url = 'resource_types/%s' % resource_type_name - resp, body = self.get(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, json.loads(body)) - - def show_resource_type_template(self, resource_type_name): - """Return the template of a resource type.""" - url = 'resource_types/%s/template' % resource_type_name - resp, body = self.get(url) - self.expected_success(200, resp.status) - return rest_client.ResponseBody(resp, json.loads(body)) - - def create_software_config(self, name=None, config=None, group=None, - inputs=None, outputs=None, options=None): - headers, body = self._prep_software_config_create( - name, config, group, inputs, outputs, options) - - url = 'software_configs' - resp, body = self.post(url, headers=headers, body=body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_software_config(self, conf_id): - """Returns a software configuration resource.""" - url = 'software_configs/%s' % str(conf_id) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_software_config(self, conf_id): - """Deletes a specific software configuration.""" - url = 'software_configs/%s' % str(conf_id) - resp, _ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def create_software_deploy(self, server_id=None, config_id=None, - action=None, status=None, - input_values=None, output_values=None, - status_reason=None, signal_transport=None): - """Creates or updates a software deployment.""" - headers, body = self._prep_software_deploy_update( - None, server_id, config_id, action, status, input_values, - output_values, status_reason, signal_transport) - - url = 'software_deployments' - resp, body = self.post(url, headers=headers, body=body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def update_software_deploy(self, deploy_id=None, server_id=None, - config_id=None, action=None, status=None, - input_values=None, output_values=None, - status_reason=None, signal_transport=None): - """Creates or updates a software deployment.""" - headers, body = self._prep_software_deploy_update( - deploy_id, server_id, config_id, action, status, input_values, - output_values, status_reason, signal_transport) - - url = 'software_deployments/%s' % str(deploy_id) - resp, body = self.put(url, headers=headers, body=body) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def list_software_deployments(self): - """Returns a list of all deployments.""" - url = 'software_deployments' - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_software_deployment(self, deploy_id): - """Returns a specific software deployment.""" - url = 'software_deployments/%s' % str(deploy_id) - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def show_software_deployment_metadata(self, server_id): - """Return a config metadata for a specific server.""" - url = 'software_deployments/metadata/%s' % server_id - resp, body = self.get(url) - self.expected_success(200, resp.status) - body = json.loads(body) - return rest_client.ResponseBody(resp, body) - - def delete_software_deploy(self, deploy_id): - """Deletes a specific software deployment.""" - url = 'software_deployments/%s' % str(deploy_id) - resp, _ = self.delete(url) - self.expected_success(204, resp.status) - return rest_client.ResponseBody(resp) - - def _prep_software_config_create(self, name=None, conf=None, group=None, - inputs=None, outputs=None, options=None): - """Prepares a software configuration body.""" - post_body = {} - if name is not None: - post_body["name"] = name - if conf is not None: - post_body["config"] = conf - if group is not None: - post_body["group"] = group - if inputs is not None: - post_body["inputs"] = inputs - if outputs is not None: - post_body["outputs"] = outputs - if options is not None: - post_body["options"] = options - body = json.dumps(post_body) - - headers = self.get_headers() - return headers, body - - def _prep_software_deploy_update(self, deploy_id=None, server_id=None, - config_id=None, action=None, status=None, - input_values=None, output_values=None, - status_reason=None, - signal_transport=None): - """Prepares a deployment create or update (if an id was given).""" - post_body = {} - - if deploy_id is not None: - post_body["id"] = deploy_id - if server_id is not None: - post_body["server_id"] = server_id - if config_id is not None: - post_body["config_id"] = config_id - if action is not None: - post_body["action"] = action - if status is not None: - post_body["status"] = status - if input_values is not None: - post_body["input_values"] = input_values - if output_values is not None: - post_body["output_values"] = output_values - if status_reason is not None: - post_body["status_reason"] = status_reason - if signal_transport is not None: - post_body["signal_transport"] = signal_transport - body = json.dumps(post_body) - - headers = self.get_headers() - return headers, body diff --git a/tempest/test.py b/tempest/test.py deleted file mode 100644 index 317c0a74d..000000000 --- a/tempest/test.py +++ /dev/null @@ -1,680 +0,0 @@ -# Copyright 2012 OpenStack Foundation -# 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 atexit -import functools -import os -import sys - -import debtcollector.moves -import fixtures -from oslo_log import log as logging -import six -import testtools - -from tempest import clients -from tempest.common import credentials_factory as credentials -import tempest.common.validation_resources as vresources -from tempest import config -from tempest.lib.common import cred_client -from tempest.lib.common import fixed_network -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -LOG = logging.getLogger(__name__) - -CONF = config.CONF - -# TODO(oomichi): This test.idempotent_id should be removed after all projects -# switch to use decorators.idempotent_id. -idempotent_id = debtcollector.moves.moved_function( - decorators.idempotent_id, 'idempotent_id', __name__, - version='Mitaka', removal_version='?') - - -related_bug = debtcollector.moves.moved_function( - decorators.related_bug, 'related_bug', __name__, - version='Pike', removal_version='?') - - -attr = debtcollector.moves.moved_function( - decorators.attr, 'attr', __name__, - version='Pike', removal_version='?') - - -class InvalidServiceTag(lib_exc.TempestException): - message = "Invalid service tag" - - -def get_service_list(): - service_list = { - 'compute': CONF.service_available.nova, - 'image': CONF.service_available.glance, - 'volume': CONF.service_available.cinder, - # NOTE(masayukig): We have two network services which are neutron and - # nova-network. And we have no way to know whether nova-network is - # available or not. After the pending removal of nova-network from - # nova, we can treat the network/neutron case in the same manner as - # the other services. - 'network': True, - # NOTE(masayukig): Tempest tests always require the identity service. - # So we should set this True here. - 'identity': True, - 'object_storage': CONF.service_available.swift, - } - return service_list - - -def services(*args): - """A decorator used to set an attr for each service used in a test case - - This decorator applies a testtools attr for each service that gets - exercised by a test case. - """ - def decorator(f): - known_services = get_service_list() - - for service in args: - if service not in known_services: - raise InvalidServiceTag('%s is not a valid service' % service) - decorators.attr(type=list(args))(f) - - @functools.wraps(f) - def wrapper(self, *func_args, **func_kwargs): - service_list = get_service_list() - - for service in args: - if not service_list[service]: - msg = 'Skipped because the %s service is not available' % ( - service) - raise testtools.TestCase.skipException(msg) - return f(self, *func_args, **func_kwargs) - return wrapper - return decorator - - -def requires_ext(**kwargs): - """A decorator to skip tests if an extension is not enabled - - @param extension - @param service - """ - def decorator(func): - @functools.wraps(func) - def wrapper(*func_args, **func_kwargs): - if not is_extension_enabled(kwargs['extension'], - kwargs['service']): - msg = "Skipped because %s extension: %s is not enabled" % ( - kwargs['service'], kwargs['extension']) - raise testtools.TestCase.skipException(msg) - return func(*func_args, **func_kwargs) - return wrapper - return decorator - - -def is_extension_enabled(extension_name, service): - """A function that will check the list of enabled extensions from config - - """ - config_dict = { - 'compute': CONF.compute_feature_enabled.api_extensions, - 'volume': CONF.volume_feature_enabled.api_extensions, - 'network': CONF.network_feature_enabled.api_extensions, - 'object': CONF.object_storage_feature_enabled.discoverable_apis, - 'identity': CONF.identity_feature_enabled.api_extensions - } - if not config_dict[service]: - return False - if config_dict[service][0] == 'all': - return True - if extension_name in config_dict[service]: - return True - return False - - -def is_scheduler_filter_enabled(filter_name): - """Check the list of enabled compute scheduler filters from config. - - This function checks whether the given compute scheduler filter is - available and configured in the config file. If the - scheduler_available_filters option is set to 'all' (Default value. which - means default filters are configured in nova) in tempest.conf then, this - function returns True with assumption that requested filter 'filter_name' - is one of available filter in nova ("nova.scheduler.filters.all_filters"). - """ - - filters = CONF.compute_feature_enabled.scheduler_available_filters - if not filters: - return False - if 'all' in filters: - return True - if filter_name in filters: - return True - return False - - -at_exit_set = set() - - -def validate_tearDownClass(): - if at_exit_set: - LOG.error( - "tearDownClass does not call the super's " - "tearDownClass in these classes: \n" - + str(at_exit_set)) - - -atexit.register(validate_tearDownClass) - - -class BaseTestCase(testtools.testcase.WithAttributes, - testtools.TestCase): - """The test base class defines Tempest framework for class level fixtures. - - `setUpClass` and `tearDownClass` are defined here and cannot be overwritten - by subclasses (enforced via hacking rule T105). - - Set-up is split in a series of steps (setup stages), which can be - overwritten by test classes. Set-up stages are: - - skip_checks - - setup_credentials - - setup_clients - - resource_setup - - Tear-down is also split in a series of steps (teardown stages), which are - stacked for execution only if the corresponding setup stage had been - reached during the setup phase. Tear-down stages are: - - clear_credentials (defined in the base test class) - - resource_cleanup - """ - - setUpClassCalled = False - - # NOTE(andreaf) credentials holds a list of the credentials to be allocated - # at class setup time. Credential types can be 'primary', 'alt', 'admin' or - # a list of roles - the first element of the list being a label, and the - # rest the actual roles - credentials = [] - # Resources required to validate a server using ssh - validation_resources = {} - network_resources = {} - - # NOTE(sdague): log_format is defined inline here instead of using the oslo - # default because going through the config path recouples config to the - # stress tests too early, and depending on testr order will fail unit tests - log_format = ('%(asctime)s %(process)d %(levelname)-8s ' - '[%(name)s] %(message)s') - - # Client manager class to use in this test case. - client_manager = clients.Manager - - # A way to adjust slow test classes - TIMEOUT_SCALING_FACTOR = 1 - - @classmethod - def setUpClass(cls): - # It should never be overridden by descendants - if hasattr(super(BaseTestCase, cls), 'setUpClass'): - super(BaseTestCase, cls).setUpClass() - cls.setUpClassCalled = True - # Stack of (name, callable) to be invoked in reverse order at teardown - cls.teardowns = [] - # All the configuration checks that may generate a skip - cls.skip_checks() - try: - # Allocation of all required credentials and client managers - cls.teardowns.append(('credentials', cls.clear_credentials)) - cls.setup_credentials() - # Shortcuts to clients - cls.setup_clients() - # Additional class-wide test resources - cls.teardowns.append(('resources', cls.resource_cleanup)) - cls.resource_setup() - except Exception: - etype, value, trace = sys.exc_info() - LOG.info("%s raised in %s.setUpClass. Invoking tearDownClass.", - etype, cls.__name__) - cls.tearDownClass() - try: - six.reraise(etype, value, trace) - finally: - del trace # to avoid circular refs - - @classmethod - def tearDownClass(cls): - # insert pdb breakpoint when pause_teardown is enabled - if CONF.pause_teardown: - cls.insert_pdb_breakpoint() - at_exit_set.discard(cls) - # It should never be overridden by descendants - if hasattr(super(BaseTestCase, cls), 'tearDownClass'): - super(BaseTestCase, cls).tearDownClass() - # Save any existing exception, we always want to re-raise the original - # exception only - etype, value, trace = sys.exc_info() - # If there was no exception during setup we shall re-raise the first - # exception in teardown - re_raise = (etype is None) - while cls.teardowns: - name, teardown = cls.teardowns.pop() - # Catch any exception in tearDown so we can re-raise the original - # exception at the end - try: - teardown() - except Exception as te: - sys_exec_info = sys.exc_info() - tetype = sys_exec_info[0] - # TODO(andreaf): Till we have the ability to cleanup only - # resources that were successfully setup in resource_cleanup, - # log AttributeError as info instead of exception. - if tetype is AttributeError and name == 'resources': - LOG.info("tearDownClass of %s failed: %s", name, te) - else: - LOG.exception("teardown of %s failed: %s", name, te) - if not etype: - etype, value, trace = sys_exec_info - # If exceptions were raised during teardown, and not before, re-raise - # the first one - if re_raise and etype is not None: - try: - six.reraise(etype, value, trace) - finally: - del trace # to avoid circular refs - - def tearDown(self): - super(BaseTestCase, self).tearDown() - # insert pdb breakpoint when pause_teardown is enabled - if CONF.pause_teardown: - BaseTestCase.insert_pdb_breakpoint() - - @classmethod - def insert_pdb_breakpoint(cls): - """Add pdb breakpoint. - - This can help in debugging process, cleaning of resources is - paused, so they can be examined. - """ - import pdb - pdb.set_trace() - - @classmethod - def skip_checks(cls): - """Class level skip checks. - - Subclasses verify in here all conditions that might prevent the - execution of the entire test class. - Checks implemented here may not make use API calls, and should rely on - configuration alone. - In general skip checks that require an API call are discouraged. - If one is really needed it may be implemented either in the - resource_setup or at test level. - """ - identity_version = cls.get_identity_version() - if 'admin' in cls.credentials and not credentials.is_admin_available( - identity_version=identity_version): - msg = "Missing Identity Admin API credentials in configuration." - raise cls.skipException(msg) - if 'alt' in cls.credentials and not credentials.is_alt_available( - identity_version=identity_version): - msg = "Missing a 2nd set of API credentials in configuration." - raise cls.skipException(msg) - if hasattr(cls, 'identity_version'): - if cls.identity_version == 'v2': - if not CONF.identity_feature_enabled.api_v2: - raise cls.skipException("Identity api v2 is not enabled") - elif cls.identity_version == 'v3': - if not CONF.identity_feature_enabled.api_v3: - raise cls.skipException("Identity api v3 is not enabled") - - @classmethod - def setup_credentials(cls): - """Allocate credentials and create the client managers from them. - - For every element of credentials param function creates tenant/user, - Then it creates client manager for that credential. - - Network related tests must override this function with - set_network_resources() method, otherwise it will create - network resources(network resources are created in a later step). - """ - for credentials_type in cls.credentials: - # This may raise an exception in case credentials are not available - # In that case we want to let the exception through and the test - # fail accordingly - if isinstance(credentials_type, six.string_types): - manager = cls.get_client_manager( - credential_type=credentials_type) - setattr(cls, 'os_%s' % credentials_type, manager) - # NOTE(jordanP): Tempest should use os_primary, os_admin - # and os_alt throughout its code base but we keep the aliases - # around for a while for Tempest plugins. Aliases should be - # removed eventually. - # Setup some common aliases - if credentials_type == 'primary': - cls.os = debtcollector.moves.moved_read_only_property( - 'os', 'os_primary', version='Pike', - removal_version='Queens') - cls.manager =\ - debtcollector.moves.moved_read_only_property( - 'manager', 'os_primary', version='Pike', - removal_version='Queens') - if credentials_type == 'admin': - cls.os_adm = debtcollector.moves.moved_read_only_property( - 'os_adm', 'os_admin', version='Pike', - removal_version='Queens') - cls.admin_manager =\ - debtcollector.moves.moved_read_only_property( - 'admin_manager', 'os_admin', version='Pike', - removal_version='Queens') - if credentials_type == 'alt': - cls.alt_manager =\ - debtcollector.moves.moved_read_only_property( - 'alt_manager', 'os_alt', version='Pike', - removal_version='Queens') - elif isinstance(credentials_type, list): - manager = cls.get_client_manager(roles=credentials_type[1:], - force_new=True) - setattr(cls, 'os_roles_%s' % credentials_type[0], manager) - - @classmethod - def setup_clients(cls): - """Create links to the clients into the test object.""" - # TODO(andreaf) There is a fair amount of code that could me moved from - # base / test classes in here. Ideally tests should be able to only - # specify which client is `client` and nothing else. - pass - - @classmethod - def resource_setup(cls): - """Class level resource setup for test cases.""" - if hasattr(cls, "os_primary"): - cls.validation_resources = vresources.create_validation_resources( - cls.os_primary, cls.validation_resources) - else: - LOG.warning("Client manager not found, validation resources not" - " created") - - @classmethod - def resource_cleanup(cls): - """Class level resource cleanup for test cases. - - Resource cleanup must be able to handle the case of partially setup - resources, in case a failure during `resource_setup` should happen. - """ - if cls.validation_resources: - if hasattr(cls, "os_primary"): - vresources.clear_validation_resources(cls.os_primary, - cls.validation_resources) - cls.validation_resources = {} - else: - LOG.warning("Client manager not found, validation resources " - "not deleted") - - def setUp(self): - super(BaseTestCase, self).setUp() - if not self.setUpClassCalled: - raise RuntimeError("setUpClass does not calls the super's" - "setUpClass in the " - + self.__class__.__name__) - at_exit_set.add(self.__class__) - test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0) - try: - test_timeout = int(test_timeout) * self.TIMEOUT_SCALING_FACTOR - except ValueError: - test_timeout = 0 - if test_timeout > 0: - self.useFixture(fixtures.Timeout(test_timeout, gentle=True)) - - if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or - os.environ.get('OS_STDOUT_CAPTURE') == '1'): - stdout = self.useFixture(fixtures.StringStream('stdout')).stream - self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout)) - if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or - os.environ.get('OS_STDERR_CAPTURE') == '1'): - stderr = self.useFixture(fixtures.StringStream('stderr')).stream - self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr)) - if (os.environ.get('OS_LOG_CAPTURE') != 'False' and - os.environ.get('OS_LOG_CAPTURE') != '0'): - self.useFixture(fixtures.LoggerFixture(nuke_handlers=False, - format=self.log_format, - level=None)) - - @property - def credentials_provider(self): - return self._get_credentials_provider() - - @property - def identity_utils(self): - """A client that abstracts v2 and v3 identity operations. - - This can be used for creating and tearing down projects in tests. It - should not be used for testing identity features. - """ - if CONF.identity.auth_version == 'v2': - client = self.os_admin.identity_client - users_client = self.os_admin.users_client - project_client = self.os_admin.tenants_client - roles_client = self.os_admin.roles_client - domains_client = None - else: - client = self.os_admin.identity_v3_client - users_client = self.os_admin.users_v3_client - project_client = self.os_admin.projects_client - roles_client = self.os_admin.roles_v3_client - domains_client = self.os_admin.domains_client - - try: - domain = client.auth_provider.credentials.project_domain_name - except AttributeError: - domain = 'Default' - - return cred_client.get_creds_client(client, project_client, - users_client, - roles_client, - domains_client, - project_domain_name=domain) - - @classmethod - def get_identity_version(cls): - """Returns the identity version used by the test class""" - identity_version = getattr(cls, 'identity_version', None) - return identity_version or CONF.identity.auth_version - - @classmethod - def _get_credentials_provider(cls): - """Returns a credentials provider - - If no credential provider exists yet creates one. - It always use the configuration value from identity.auth_version, - since we always want to provision accounts with the current version - of the identity API. - """ - if (not hasattr(cls, '_creds_provider') or not cls._creds_provider or - not cls._creds_provider.name == cls.__name__): - force_tenant_isolation = getattr(cls, 'force_tenant_isolation', - False) - - cls._creds_provider = credentials.get_credentials_provider( - name=cls.__name__, network_resources=cls.network_resources, - force_tenant_isolation=force_tenant_isolation) - return cls._creds_provider - - @classmethod - def get_client_manager(cls, credential_type=None, roles=None, - force_new=None): - """Returns an OpenStack client manager - - Returns an OpenStack client manager based on either credential_type - or a list of roles. If neither is specified, it defaults to - credential_type 'primary' - :param credential_type: string - primary, alt or admin - :param roles: list of roles - - :returns: the created client manager - :raises skipException: if the requested credentials are not available - """ - if all([roles, credential_type]): - msg = "Cannot get credentials by type and roles at the same time" - raise ValueError(msg) - if not any([roles, credential_type]): - credential_type = 'primary' - cred_provider = cls._get_credentials_provider() - if roles: - for role in roles: - if not cred_provider.is_role_available(role): - skip_msg = ( - "%s skipped because the configured credential provider" - " is not able to provide credentials with the %s role " - "assigned." % (cls.__name__, role)) - raise cls.skipException(skip_msg) - params = dict(roles=roles) - if force_new is not None: - params.update(force_new=force_new) - creds = cred_provider.get_creds_by_roles(**params) - else: - credentials_method = 'get_%s_creds' % credential_type - if hasattr(cred_provider, credentials_method): - creds = getattr(cred_provider, credentials_method)() - else: - raise lib_exc.InvalidCredentials( - "Invalid credentials type %s" % credential_type) - manager = cls.client_manager(credentials=creds.credentials) - # NOTE(andreaf) Ensure credentials have user and project id fields. - # It may not be the case when using pre-provisioned credentials. - manager.auth_provider.set_auth() - return manager - - @classmethod - def clear_credentials(cls): - """Clears creds if set""" - if hasattr(cls, '_creds_provider'): - cls._creds_provider.clear_creds() - - @classmethod - def set_validation_resources(cls, keypair=None, floating_ip=None, - security_group=None, - security_group_rules=None): - """Specify which ssh server validation resources should be created. - - Each of the argument must be set to either None, True or False, with - None - use default from config (security groups and security group - rules get created when set to None) - False - Do not create the validation resource - True - create the validation resource - - @param keypair - @param security_group - @param security_group_rules - @param floating_ip - """ - if not CONF.validation.run_validation: - return - - if keypair is None: - keypair = (CONF.validation.auth_method.lower() == "keypair") - - if floating_ip is None: - floating_ip = (CONF.validation.connect_method.lower() == - "floating") - - if security_group is None: - security_group = CONF.validation.security_group - - if security_group_rules is None: - security_group_rules = CONF.validation.security_group_rules - - if not cls.validation_resources: - cls.validation_resources = { - 'keypair': keypair, - 'security_group': security_group, - 'security_group_rules': security_group_rules, - 'floating_ip': floating_ip} - - @classmethod - def set_network_resources(cls, network=False, router=False, subnet=False, - dhcp=False): - """Specify which network resources should be created - - @param network - @param router - @param subnet - @param dhcp - """ - # network resources should be set only once from callers - # in order to ensure that even if it's called multiple times in - # a chain of overloaded methods, the attribute is set only - # in the leaf class - if not cls.network_resources: - cls.network_resources = { - 'network': network, - 'router': router, - 'subnet': subnet, - 'dhcp': dhcp} - - @classmethod - def get_tenant_network(cls, credentials_type='primary'): - """Get the network to be used in testing - - :param credentials_type: The type of credentials for which to get the - tenant network - - :return: network dict including 'id' and 'name' - """ - # Get a manager for the given credentials_type, but at least - # always fall back on getting the manager for primary credentials - if isinstance(credentials_type, six.string_types): - manager = cls.get_client_manager(credential_type=credentials_type) - elif isinstance(credentials_type, list): - manager = cls.get_client_manager(roles=credentials_type[1:]) - else: - manager = cls.get_client_manager() - - # Make sure cred_provider exists and get a network client - networks_client = manager.compute_networks_client - cred_provider = cls._get_credentials_provider() - # In case of nova network, isolated tenants are not able to list the - # network configured in fixed_network_name, even if they can use it - # for their servers, so using an admin network client to validate - # the network name - if (not CONF.service_available.neutron and - credentials.is_admin_available( - identity_version=cls.get_identity_version())): - admin_creds = cred_provider.get_admin_creds() - admin_manager = clients.Manager(admin_creds.credentials) - networks_client = admin_manager.compute_networks_client - return fixed_network.get_tenant_network( - cred_provider, networks_client, CONF.compute.fixed_network_name) - - def assertEmpty(self, items, msg=None): - """Asserts whether a sequence or collection is empty - - :param items: sequence or collection to be tested - :param msg: message to be passed to the AssertionError - :raises AssertionError: when items is not empty - """ - if msg is None: - msg = "sequence or collection is not empty: %s" % items - self.assertFalse(items, msg) - - def assertNotEmpty(self, items, msg=None): - """Asserts whether a sequence or collection is not empty - - :param items: sequence or collection to be tested - :param msg: message to be passed to the AssertionError - :raises AssertionError: when items is empty - """ - if msg is None: - msg = "sequence or collection is empty." - self.assertTrue(items, msg) diff --git a/tempest/test_discover/__init__.py b/tempest/test_discover/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/test_discover/plugins.py b/tempest/test_discover/plugins.py deleted file mode 100644 index 1206e3fee..000000000 --- a/tempest/test_discover/plugins.py +++ /dev/null @@ -1,225 +0,0 @@ -# Copyright (c) 2015 Hewlett-Packard Development Company, L.P. -# -# 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 abc - -from oslo_log import log as logging -import six -import stevedore - -from tempest.lib.common.utils import misc -from tempest.lib.services import clients - -LOG = logging.getLogger(__name__) - - -@six.add_metaclass(abc.ABCMeta) -class TempestPlugin(object): - """Provide basic hooks for an external plugin - - To provide tempest the necessary information to run the plugin. - """ - - @abc.abstractmethod - def load_tests(self): - """Return the information necessary to load the tests in the plugin. - - :return: a tuple with the first value being the test_dir and the second - being the top_level - :rtype: tuple - """ - return - - @abc.abstractmethod - def register_opts(self, conf): - """Add additional configuration options to tempest. - - This method will be run for the plugin during the register_opts() - function in tempest.config. - - :param ConfigOpts conf: The conf object that can be used to register - additional options on. - - Example:: - - # Config options are defined in a config.py module - service_option = cfg.BoolOpt( - "my_service", - default=True, - help="Whether or not my service is available") - - # Note: as long as the group is listed in get_opt_lists, - # it will be possible to access its optins in the plugin code - # via ("-" in the group name are replaces with "_"): - # CONF.my_service. - my_service_group = cfg.OptGroup(name="my-service", - title="My service options") - - MyServiceGroup = [] - # (...) More groups and options... - - # Plugin is implemented in a plugin.py module - from my_plugin import config as my_config - - def register_opts(self, conf): - conf.register_opt(my_config.service_option, - group='service_available') - conf.register_group(my_config.my_service_group) - conf.register_opts(my_config.MyService + - my_config.my_service_group) - - conf.register_group(my_config.my_service_feature_group) - conf.register_opts(my_config.MyServiceFeaturesGroup, - my_config.my_service_feature_group) - """ - return - - @abc.abstractmethod - def get_opt_lists(self): - """Get a list of options for sample config generation - - :return option_list: A list of tuples with the group name and options - in that group. - :rtype: list - - Example:: - - # Config options are defined in a config.py module - service_option = cfg.BoolOpt( - "my_service", default=True, - help="Whether or not my service is available") - - my_service_group = cfg.OptGroup(name="my-service", - title="My service options") - my_service_features_group = cfg.OptGroup( - name="my-service-features", - title="My service available features") - - MyServiceGroup = [] - MyServiceFeaturesGroup = [] - - # Plugin is implemented in a plugin.py module - from my_plugin import config as my_config - - def get_opt_lists(self, conf): - return [ - (my_service_group.name, MyServiceGroup), - (my_service_features_group.name, MyServiceFeaturesGroup) - ] - """ - return [] - - def get_service_clients(self): - """Get a list of the service clients for registration - - If the plugin implements service clients for one or more APIs, it - may return their details by this method for automatic registration - in any ServiceClients object instantiated by tests. - The default implementation returns an empty list. - - :returns: Each element of the list represents the service client for an - API. Each dict must define all parameters required for the invocation - of `service_clients.ServiceClients.register_service_client_module`. - :rtype: list of dictionaries - - Example implementation with one service client:: - - def get_service_clients(self): - # Example implementation with one service client - myservice_config = config.service_client_config('myservice') - params = { - 'name': 'myservice', - 'service_version': 'myservice', - 'module_path': 'myservice_tempest_tests.services', - 'client_names': ['API1Client', 'API2Client'], - } - params.update(myservice_config) - return [params] - - Example implementation with two service clients:: - - def get_service_clients(self): - # Example implementation with two service clients - foo1_config = config.service_client_config('foo') - params_foo1 = { - 'name': 'foo_v1', - 'service_version': 'foo.v1', - 'module_path': 'bar_tempest_tests.services.foo.v1', - 'client_names': ['API1Client', 'API2Client'], - } - params_foo1.update(foo_config) - foo2_config = config.service_client_config('foo') - params_foo2 = { - 'name': 'foo_v2', - 'service_version': 'foo.v2', - 'module_path': 'bar_tempest_tests.services.foo.v2', - 'client_names': ['API1Client', 'API2Client'], - } - params_foo2.update(foo2_config) - return [params_foo1, params_foo2] - """ - return [] - - -@misc.singleton -class TempestTestPluginManager(object): - """Tempest test plugin manager class - - This class is used to manage the lifecycle of external tempest test - plugins. It provides functions for getting set - """ - def __init__(self): - self.ext_plugins = stevedore.ExtensionManager( - 'tempest.test_plugins', invoke_on_load=True, - propagate_map_exceptions=True, - on_load_failure_callback=self.failure_hook) - - @staticmethod - def failure_hook(_, ep, err): - LOG.error('Could not load %r: %s', ep.name, err) - raise err - - def get_plugin_load_tests_tuple(self): - load_tests_dict = {} - for plug in self.ext_plugins: - load_tests_dict[plug.name] = plug.obj.load_tests() - return load_tests_dict - - def register_plugin_opts(self, conf): - for plug in self.ext_plugins: - try: - plug.obj.register_opts(conf) - except Exception: - LOG.exception('Plugin %s raised an exception trying to run ' - 'register_opts', plug.name) - - def get_plugin_options_list(self): - plugin_options = [] - for plug in self.ext_plugins: - opt_list = plug.obj.get_opt_lists() - if opt_list: - plugin_options.extend(opt_list) - return plugin_options - - def _register_service_clients(self): - registry = clients.ClientsRegistry() - for plug in self.ext_plugins: - try: - service_clients = plug.obj.get_service_clients() - if service_clients: - registry.register_service_client( - plug.name, service_clients) - except Exception: - LOG.exception('Plugin %s raised an exception trying to run ' - 'get_service_clients', plug.name) diff --git a/tempest/test_discover/test_discover.py b/tempest/test_discover/test_discover.py deleted file mode 100644 index 330f370f7..000000000 --- a/tempest/test_discover/test_discover.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# 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 os -import sys - -from tempest.test_discover import plugins - -if sys.version_info >= (2, 7): - import unittest -else: - import unittest2 as unittest - - -def load_tests(loader, tests, pattern): - ext_plugins = plugins.TempestTestPluginManager() - - suite = unittest.TestSuite() - base_path = os.path.split(os.path.dirname(os.path.abspath(__file__)))[0] - base_path = os.path.split(base_path)[0] - # Load local tempest tests - for test_dir in ['tempest/api', 'tempest/scenario']: - full_test_dir = os.path.join(base_path, test_dir) - if not pattern: - suite.addTests(loader.discover(full_test_dir, - top_level_dir=base_path)) - else: - suite.addTests(loader.discover(full_test_dir, pattern=pattern, - top_level_dir=base_path)) - - plugin_load_tests = ext_plugins.get_plugin_load_tests_tuple() - if not plugin_load_tests: - return suite - - # Load any installed plugin tests - for plugin in plugin_load_tests: - test_dir, top_path = plugin_load_tests[plugin] - if not pattern: - suite.addTests(loader.discover(test_dir, top_level_dir=top_path)) - else: - suite.addTests(loader.discover(test_dir, pattern=pattern, - top_level_dir=top_path)) - return suite diff --git a/tempest/tests/README.rst b/tempest/tests/README.rst deleted file mode 100644 index 0587e7b88..000000000 --- a/tempest/tests/README.rst +++ /dev/null @@ -1,27 +0,0 @@ -.. _unit_tests_field_guide: - -Tempest Field Guide to Unit tests -================================= - -What are these tests? ---------------------- - -Unit tests are the self checks for Tempest. They provide functional -verification and regression checking for the internal components of Tempest. -They should be used to just verify that the individual pieces of Tempest are -working as expected. They should not require an external service to be running -and should be able to run solely from the Tempest tree. - -Why are these tests in Tempest? -------------------------------- -These tests exist to make sure that the mechanisms that we use inside of -Tempest are valid and remain functional. They are only here for self -validation of Tempest. - - -Scope of these tests --------------------- -Unit tests should not require an external service to be running or any extra -configuration to run. Any state that is required for a test should either be -mocked out or created in a temporary test directory. (see test_wrappers.py for -an example of using a temporary test directory) diff --git a/tempest/tests/__init__.py b/tempest/tests/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/api/__init__.py b/tempest/tests/api/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/api/compute/__init__.py b/tempest/tests/api/compute/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/api/compute/test_base.py b/tempest/tests/api/compute/test_base.py deleted file mode 100644 index 6345728ba..000000000 --- a/tempest/tests/api/compute/test_base.py +++ /dev/null @@ -1,173 +0,0 @@ -# Copyright 2017 IBM Corp. -# -# 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 mock - -from oslo_utils import uuidutils -import six - -from tempest.api.compute import base as compute_base -from tempest.common import waiters -from tempest import exceptions -from tempest.lib import exceptions as lib_exc -from tempest.tests import base - - -class TestBaseV2ComputeTest(base.TestCase): - """Unit tests for utility functions in BaseV2ComputeTest.""" - - @mock.patch.multiple(compute_base.BaseV2ComputeTest, - compute_images_client=mock.DEFAULT, - images=[], create=True) - def test_create_image_from_server_no_wait(self, compute_images_client): - """Tests create_image_from_server without the wait_until kwarg.""" - # setup mocks - image_id = uuidutils.generate_uuid() - fake_image = mock.Mock(response={'location': image_id}) - compute_images_client.create_image.return_value = fake_image - # call the utility method - image = compute_base.BaseV2ComputeTest.create_image_from_server( - mock.sentinel.server_id, name='fake-snapshot-name') - self.assertEqual(fake_image, image) - # make our assertions - compute_images_client.create_image.assert_called_once_with( - mock.sentinel.server_id, name='fake-snapshot-name') - self.assertEqual(1, len(compute_base.BaseV2ComputeTest.images)) - self.assertEqual(image_id, compute_base.BaseV2ComputeTest.images[0]) - - @mock.patch.multiple(compute_base.BaseV2ComputeTest, - compute_images_client=mock.DEFAULT, - servers_client=mock.DEFAULT, - images=[], create=True) - @mock.patch.object(waiters, 'wait_for_image_status') - @mock.patch.object(waiters, 'wait_for_server_status') - def test_create_image_from_server_wait_until_active(self, - wait_for_server_status, - wait_for_image_status, - servers_client, - compute_images_client): - """Tests create_image_from_server with wait_until='ACTIVE' kwarg.""" - # setup mocks - image_id = uuidutils.generate_uuid() - fake_image = mock.Mock(response={'location': image_id}) - compute_images_client.create_image.return_value = fake_image - compute_images_client.show_image.return_value = ( - {'image': fake_image}) - # call the utility method - image = compute_base.BaseV2ComputeTest.create_image_from_server( - mock.sentinel.server_id, wait_until='ACTIVE') - self.assertEqual(fake_image, image) - # make our assertions - wait_for_image_status.assert_called_once_with( - compute_images_client, image_id, 'ACTIVE') - wait_for_server_status.assert_called_once_with( - servers_client, mock.sentinel.server_id, 'ACTIVE') - compute_images_client.show_image.assert_called_once_with(image_id) - - @mock.patch.multiple(compute_base.BaseV2ComputeTest, - compute_images_client=mock.DEFAULT, - servers_client=mock.DEFAULT, - images=[], create=True) - @mock.patch.object(waiters, 'wait_for_image_status') - @mock.patch.object(waiters, 'wait_for_server_status') - def test_create_image_from_server_wait_until_active_no_server_wait( - self, wait_for_server_status, wait_for_image_status, - servers_client, compute_images_client): - """Tests create_image_from_server with wait_until='ACTIVE' kwarg.""" - # setup mocks - image_id = uuidutils.generate_uuid() - fake_image = mock.Mock(response={'location': image_id}) - compute_images_client.create_image.return_value = fake_image - compute_images_client.show_image.return_value = ( - {'image': fake_image}) - # call the utility method - image = compute_base.BaseV2ComputeTest.create_image_from_server( - mock.sentinel.server_id, wait_until='ACTIVE', - wait_for_server=False) - self.assertEqual(fake_image, image) - # make our assertions - wait_for_image_status.assert_called_once_with( - compute_images_client, image_id, 'ACTIVE') - self.assertEqual(0, wait_for_server_status.call_count) - compute_images_client.show_image.assert_called_once_with(image_id) - - @mock.patch.multiple(compute_base.BaseV2ComputeTest, - compute_images_client=mock.DEFAULT, - servers_client=mock.DEFAULT, - images=[], create=True) - @mock.patch.object(waiters, 'wait_for_image_status', - side_effect=lib_exc.NotFound) - def _test_create_image_from_server_wait_until_active_not_found( - self, wait_for_image_status, compute_images_client, - servers_client, fault=None): - # setup mocks - image_id = uuidutils.generate_uuid() - fake_image = mock.Mock(response={'location': image_id}) - compute_images_client.create_image.return_value = fake_image - fake_server = {'id': mock.sentinel.server_id} - if fault: - fake_server['fault'] = fault - servers_client.show_server.return_value = {'server': fake_server} - # call the utility method - ex = self.assertRaises( - exceptions.SnapshotNotFoundException, - compute_base.BaseV2ComputeTest.create_image_from_server, - mock.sentinel.server_id, wait_until='active') - # make our assertions - if fault: - self.assertIn(fault, six.text_type(ex)) - else: - self.assertNotIn(fault, six.text_type(ex)) - wait_for_image_status.assert_called_once_with( - compute_images_client, image_id, 'active') - servers_client.show_server.assert_called_once_with( - mock.sentinel.server_id) - - def test_create_image_from_server_wait_until_active_not_found_no_fault( - self): - # Tests create_image_from_server with wait_until='active' kwarg and - # the a 404 is raised while waiting for the image status to change. In - # this test the server does not have a fault associated with it. - self._test_create_image_from_server_wait_until_active_not_found() - - def test_create_image_from_server_wait_until_active_not_found_with_fault( - self): - # Tests create_image_from_server with wait_until='active' kwarg and - # the a 404 is raised while waiting for the image status to change. In - # this test the server has a fault associated with it. - self._test_create_image_from_server_wait_until_active_not_found( - fault='Lost connection to hypervisor!') - - @mock.patch.multiple(compute_base.BaseV2ComputeTest, - compute_images_client=mock.DEFAULT, - images=[], create=True) - @mock.patch.object(waiters, 'wait_for_image_status', - side_effect=lib_exc.NotFound) - def test_create_image_from_server_wait_until_saving_not_found( - self, wait_for_image_status, compute_images_client): - # Tests create_image_from_server with wait_until='SAVING' kwarg and - # the a 404 is raised while waiting for the image status to change. In - # this case we do not get the server details and just re-raise the 404. - # setup mocks - image_id = uuidutils.generate_uuid() - fake_image = mock.Mock(response={'location': image_id}) - compute_images_client.create_image.return_value = fake_image - # call the utility method - self.assertRaises( - lib_exc.NotFound, - compute_base.BaseV2ComputeTest.create_image_from_server, - mock.sentinel.server_id, wait_until='SAVING') - # make our assertions - wait_for_image_status.assert_called_once_with( - compute_images_client, image_id, 'SAVING') diff --git a/tempest/tests/base.py b/tempest/tests/base.py deleted file mode 100644 index ca81d4d60..000000000 --- a/tempest/tests/base.py +++ /dev/null @@ -1,49 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# 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 mock -from oslotest import base - - -class TestCase(base.BaseTestCase): - - def patch(self, target, **kwargs): - """Returns a started `mock.patch` object for the supplied target. - - The caller may then call the returned patcher to create a mock object. - - The caller does not need to call stop() on the returned - patcher object, as this method automatically adds a cleanup - to the test class to stop the patcher. - - :param target: String module.class or module.object expression to patch - :param **kwargs: Passed as-is to `mock.patch`. See mock documentation - for details. - """ - p = mock.patch(target, **kwargs) - m = p.start() - self.addCleanup(p.stop) - return m - - def patchobject(self, target, attribute, new=mock.DEFAULT): - """Convenient wrapper around `mock.patch.object` - - Returns a started mock that will be automatically stopped after the - test ran. - """ - - p = mock.patch.object(target, attribute, new) - m = p.start() - self.addCleanup(p.stop) - return m diff --git a/tempest/tests/cmd/__init__.py b/tempest/tests/cmd/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/cmd/sample_streams/calls.subunit b/tempest/tests/cmd/sample_streams/calls.subunit deleted file mode 100644 index d5b479036..000000000 Binary files a/tempest/tests/cmd/sample_streams/calls.subunit and /dev/null differ diff --git a/tempest/tests/cmd/test_account_generator.py b/tempest/tests/cmd/test_account_generator.py deleted file mode 100644 index f907bd081..000000000 --- a/tempest/tests/cmd/test_account_generator.py +++ /dev/null @@ -1,332 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# 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 fixtures -import mock -from oslo_config import cfg - -from tempest.cmd import account_generator -from tempest import config -from tempest.tests import base -from tempest.tests import fake_config - - -class FakeOpts(object): - - def __init__(self, version=3): - self.os_username = 'fake_user' - self.os_password = 'fake_password' - self.os_project_name = 'fake_project_name' - self.os_tenant_name = None - self.os_domain_name = 'fake_domain' - self.tag = 'fake' - self.concurrency = 2 - self.with_admin = True - self.identity_version = version - self.accounts = 'fake_accounts.yml' - - -class MockHelpersMixin(object): - - def mock_config_and_opts(self, identity_version): - self.useFixture(fake_config.ConfigFixture()) - self.patchobject(config, 'TempestConfigPrivate', - fake_config.FakePrivate) - self.opts = FakeOpts(version=identity_version) - - def mock_resource_creation(self): - fake_resource = dict(id='id', name='name') - self.user_create_fixture = self.useFixture(fixtures.MockPatch( - self.cred_client + '.create_user', return_value=fake_resource)) - self.useFixture(fixtures.MockPatch( - self.cred_client + '.create_project', - return_value=fake_resource)) - self.useFixture(fixtures.MockPatch( - self.cred_client + '.assign_user_role')) - self.useFixture(fixtures.MockPatch( - self.cred_client + '._check_role_exists', - return_value=fake_resource)) - self.useFixture(fixtures.MockPatch( - self.dynamic_creds + '._create_network', - return_value=fake_resource)) - self.useFixture(fixtures.MockPatch( - self.dynamic_creds + '._create_subnet', - return_value=fake_resource)) - self.useFixture(fixtures.MockPatch( - self.dynamic_creds + '._create_router', - return_value=fake_resource)) - self.useFixture(fixtures.MockPatch( - self.dynamic_creds + '._add_router_interface', - return_value=fake_resource)) - - def mock_domains(self): - fake_domain_list = {'domains': [{'id': 'fake_domain', - 'name': 'Fake_Domain'}]} - self.useFixture(fixtures.MockPatch(''.join([ - 'tempest.lib.services.identity.v3.domains_client.' - 'DomainsClient.list_domains']), - return_value=fake_domain_list)) - self.useFixture(fixtures.MockPatch( - self.cred_client + '.assign_user_role_on_domain')) - - -class TestAccountGeneratorV2(base.TestCase, MockHelpersMixin): - - identity_version = 2 - - def setUp(self): - super(TestAccountGeneratorV2, self).setUp() - self.mock_config_and_opts(self.identity_version) - - def test_get_credential_provider(self): - cp = account_generator.get_credential_provider(self.opts) - admin_creds = cp.default_admin_creds - self.assertEqual(self.opts.tag, cp.name) - self.assertIn(str(self.opts.identity_version), cp.identity_version) - self.assertEqual(self.opts.os_username, admin_creds.username) - self.assertEqual(self.opts.os_project_name, admin_creds.tenant_name) - self.assertEqual(self.opts.os_password, admin_creds.password) - self.assertFalse(hasattr(admin_creds, 'domain_name')) - - def test_get_credential_provider_with_tenant(self): - self.opts.os_project_name = None - self.opts.os_tenant_name = 'fake_tenant' - cp = account_generator.get_credential_provider(self.opts) - admin_creds = cp.default_admin_creds - self.assertEqual(self.opts.os_tenant_name, admin_creds.tenant_name) - - -class TestAccountGeneratorV3(TestAccountGeneratorV2): - - identity_version = 3 - - def setUp(self): - super(TestAccountGeneratorV3, self).setUp() - fake_domain_list = {'domains': [{'id': 'fake_domain'}]} - self.useFixture(fixtures.MockPatch(''.join([ - 'tempest.lib.services.identity.v3.domains_client.' - 'DomainsClient.list_domains']), - return_value=fake_domain_list)) - - def test_get_credential_provider(self): - cp = account_generator.get_credential_provider(self.opts) - admin_creds = cp.default_admin_creds - self.assertEqual(self.opts.tag, cp.name) - self.assertIn(str(self.opts.identity_version), cp.identity_version) - self.assertEqual(self.opts.os_username, admin_creds.username) - self.assertEqual(self.opts.os_project_name, admin_creds.tenant_name) - self.assertEqual(self.opts.os_password, admin_creds.password) - self.assertEqual(self.opts.os_domain_name, admin_creds.domain_name) - - def test_get_credential_provider_without_domain(self): - self.opts.os_domain_name = None - cp = account_generator.get_credential_provider(self.opts) - admin_creds = cp.default_admin_creds - self.assertIsNotNone(admin_creds.domain_name) - - -class TestGenerateResourcesV2(base.TestCase, MockHelpersMixin): - - identity_version = 2 - cred_client = 'tempest.lib.common.cred_client.V2CredsClient' - dynamic_creds = ('tempest.lib.common.dynamic_creds.' - 'DynamicCredentialProvider') - - def setUp(self): - super(TestGenerateResourcesV2, self).setUp() - self.mock_config_and_opts(self.identity_version) - self.cred_provider = account_generator.get_credential_provider( - self.opts) - self.mock_resource_creation() - - def test_generate_resources_no_admin(self): - cfg.CONF.set_default('swift', False, group='service_available') - cfg.CONF.set_default('heat', False, group='service_available') - cfg.CONF.set_default('operator_role', 'fake_operator', - group='object-storage') - cfg.CONF.set_default('reseller_admin_role', 'fake_reseller', - group='object-storage') - cfg.CONF.set_default('stack_owner_role', 'fake_owner', - group='orchestration') - resources = account_generator.generate_resources( - self.cred_provider, admin=False) - resource_types = [k for k, _ in resources] - # No admin, no heat, no swift, expect two credentials only - self.assertEqual(2, len(resources)) - # Ensure create_user was invoked twice (two distinct users) - self.assertEqual(2, self.user_create_fixture.mock.call_count) - self.assertIn('primary', resource_types) - self.assertIn('alt', resource_types) - self.assertNotIn('admin', resource_types) - self.assertNotIn(['fake_operator'], resource_types) - self.assertNotIn(['fake_reseller'], resource_types) - self.assertNotIn(['fake_owner'], resource_types) - for resource in resources: - self.assertIsNotNone(resource[1].network) - self.assertIsNotNone(resource[1].router) - self.assertIsNotNone(resource[1].subnet) - - def test_generate_resources_admin(self): - cfg.CONF.set_default('swift', False, group='service_available') - cfg.CONF.set_default('heat', False, group='service_available') - cfg.CONF.set_default('operator_role', 'fake_operator', - group='object-storage') - cfg.CONF.set_default('reseller_admin_role', 'fake_reseller', - group='object-storage') - cfg.CONF.set_default('stack_owner_role', 'fake_owner', - group='orchestration') - resources = account_generator.generate_resources( - self.cred_provider, admin=True) - resource_types = [k for k, _ in resources] - # Admin, no heat, no swift, expect three credentials only - self.assertEqual(3, len(resources)) - # Ensure create_user was invoked 3 times (3 distinct users) - self.assertEqual(3, self.user_create_fixture.mock.call_count) - self.assertIn('primary', resource_types) - self.assertIn('alt', resource_types) - self.assertIn('admin', resource_types) - self.assertNotIn(['fake_operator'], resource_types) - self.assertNotIn(['fake_reseller'], resource_types) - self.assertNotIn(['fake_owner'], resource_types) - for resource in resources: - self.assertIsNotNone(resource[1].network) - self.assertIsNotNone(resource[1].router) - self.assertIsNotNone(resource[1].subnet) - - def test_generate_resources_swift_heat_admin(self): - cfg.CONF.set_default('swift', True, group='service_available') - cfg.CONF.set_default('heat', True, group='service_available') - cfg.CONF.set_default('operator_role', 'fake_operator', - group='object-storage') - cfg.CONF.set_default('reseller_admin_role', 'fake_reseller', - group='object-storage') - cfg.CONF.set_default('stack_owner_role', 'fake_owner', - group='orchestration') - resources = account_generator.generate_resources( - self.cred_provider, admin=True) - resource_types = [k for k, _ in resources] - # all options on, expect six credentials - self.assertEqual(6, len(resources)) - # Ensure create_user was invoked 6 times (6 distinct users) - self.assertEqual(6, self.user_create_fixture.mock.call_count) - self.assertIn('primary', resource_types) - self.assertIn('alt', resource_types) - self.assertIn('admin', resource_types) - self.assertIn(['fake_operator'], resource_types) - self.assertIn(['fake_reseller'], resource_types) - self.assertIn(['fake_owner', 'fake_operator'], resource_types) - for resource in resources: - self.assertIsNotNone(resource[1].network) - self.assertIsNotNone(resource[1].router) - self.assertIsNotNone(resource[1].subnet) - - -class TestGenerateResourcesV3(TestGenerateResourcesV2): - - identity_version = 3 - cred_client = 'tempest.lib.common.cred_client.V3CredsClient' - - def setUp(self): - self.mock_domains() - super(TestGenerateResourcesV3, self).setUp() - - -class TestDumpAccountsV2(base.TestCase, MockHelpersMixin): - - identity_version = 2 - cred_client = 'tempest.lib.common.cred_client.V2CredsClient' - dynamic_creds = ('tempest.lib.common.dynamic_creds.' - 'DynamicCredentialProvider') - domain_is_in = False - - def setUp(self): - super(TestDumpAccountsV2, self).setUp() - self.mock_config_and_opts(self.identity_version) - self.cred_provider = account_generator.get_credential_provider( - self.opts) - self.mock_resource_creation() - cfg.CONF.set_default('swift', True, group='service_available') - cfg.CONF.set_default('heat', True, group='service_available') - self.resources = account_generator.generate_resources( - self.cred_provider, admin=True) - - def test_dump_accounts(self): - self.useFixture(fixtures.MockPatch('os.path.exists', - return_value=False)) - mocked_open = mock.mock_open() - with mock.patch('{}.open'.format(account_generator.__name__), - mocked_open, create=True): - with mock.patch('yaml.safe_dump') as yaml_dump_mock: - account_generator.setup_logging() - account_generator.dump_accounts(self.resources, - self.opts.identity_version, - self.opts.accounts) - mocked_open.assert_called_once_with(self.opts.accounts, 'w') - handle = mocked_open() - # Ordered args in [0], keyword args in [1] - accounts, f = yaml_dump_mock.call_args[0] - self.assertEqual(handle, f) - self.assertEqual(6, len(accounts)) - if self.domain_is_in: - self.assertIn('domain_name', accounts[0].keys()) - else: - self.assertNotIn('domain_name', accounts[0].keys()) - self.assertEqual(1, len([x for x in accounts if - x.get('types') == ['admin']])) - self.assertEqual(3, len([x for x in accounts if 'roles' in x])) - for account in accounts: - self.assertIn('resources', account) - self.assertIn('network', account.get('resources')) - - def test_dump_accounts_existing_file(self): - self.useFixture(fixtures.MockPatch('os.path.exists', - return_value=True)) - rename_mock = self.useFixture(fixtures.MockPatch('os.rename')).mock - backup_file = '.'.join((self.opts.accounts, 'bak')) - mocked_open = mock.mock_open() - with mock.patch('{}.open'.format(account_generator.__name__), - mocked_open, create=True): - with mock.patch('yaml.safe_dump') as yaml_dump_mock: - account_generator.setup_logging() - account_generator.dump_accounts(self.resources, - self.opts.identity_version, - self.opts.accounts) - rename_mock.assert_called_once_with(self.opts.accounts, backup_file) - mocked_open.assert_called_once_with(self.opts.accounts, 'w') - handle = mocked_open() - # Ordered args in [0], keyword args in [1] - accounts, f = yaml_dump_mock.call_args[0] - self.assertEqual(handle, f) - self.assertEqual(6, len(accounts)) - if self.domain_is_in: - self.assertIn('domain_name', accounts[0].keys()) - else: - self.assertNotIn('domain_name', accounts[0].keys()) - self.assertEqual(1, len([x for x in accounts if - x.get('types') == ['admin']])) - self.assertEqual(3, len([x for x in accounts if 'roles' in x])) - for account in accounts: - self.assertIn('resources', account) - self.assertIn('network', account.get('resources')) - - -class TestDumpAccountsV3(TestDumpAccountsV2): - - identity_version = 3 - cred_client = 'tempest.lib.common.cred_client.V3CredsClient' - domain_is_in = True - - def setUp(self): - self.mock_domains() - super(TestDumpAccountsV3, self).setUp() diff --git a/tempest/tests/cmd/test_list_plugins.py b/tempest/tests/cmd/test_list_plugins.py deleted file mode 100644 index 17ddb1828..000000000 --- a/tempest/tests/cmd/test_list_plugins.py +++ /dev/null @@ -1,24 +0,0 @@ -# Copyright 2015 Hewlett-Packard Development Company, L.P. -# -# 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 subprocess - -from tempest.tests import base - - -class TestTempestListPlugins(base.TestCase): - def test_run_list_plugins(self): - return_code = subprocess.call( - ['tempest', 'list-plugins'], stdout=subprocess.PIPE) - self.assertEqual(return_code, 0) diff --git a/tempest/tests/cmd/test_run.py b/tempest/tests/cmd/test_run.py deleted file mode 100644 index 7ac347dea..000000000 --- a/tempest/tests/cmd/test_run.py +++ /dev/null @@ -1,154 +0,0 @@ -# Copyright 2015 Hewlett-Packard Development Company, L.P. -# -# 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 argparse -import os -import shutil -import subprocess -import tempfile - -import fixtures -import mock - -from tempest.cmd import run -from tempest.tests import base - -DEVNULL = open(os.devnull, 'wb') - - -class TestTempestRun(base.TestCase): - - def setUp(self): - super(TestTempestRun, self).setUp() - self.run_cmd = run.TempestRun(None, None) - - def test_build_options(self): - args = mock.Mock(spec=argparse.Namespace) - setattr(args, "subunit", True) - setattr(args, "parallel", False) - setattr(args, "concurrency", 10) - options = self.run_cmd._build_options(args) - self.assertEqual(['--subunit', - '--concurrency=10'], - options) - - def test__build_regex_default(self): - args = mock.Mock(spec=argparse.Namespace) - setattr(args, 'smoke', False) - setattr(args, 'regex', '') - setattr(args, 'whitelist_file', None) - setattr(args, 'blacklist_file', None) - self.assertEqual('', self.run_cmd._build_regex(args)) - - def test__build_regex_smoke(self): - args = mock.Mock(spec=argparse.Namespace) - setattr(args, "smoke", True) - setattr(args, 'regex', '') - setattr(args, 'whitelist_file', None) - setattr(args, 'blacklist_file', None) - self.assertEqual('smoke', self.run_cmd._build_regex(args)) - - def test__build_regex_regex(self): - args = mock.Mock(spec=argparse.Namespace) - setattr(args, 'smoke', False) - setattr(args, "regex", 'i_am_a_fun_little_regex') - setattr(args, 'whitelist_file', None) - setattr(args, 'blacklist_file', None) - self.assertEqual('i_am_a_fun_little_regex', - self.run_cmd._build_regex(args)) - - -class TestRunReturnCode(base.TestCase): - def setUp(self): - super(TestRunReturnCode, self).setUp() - # Setup test dirs - self.directory = tempfile.mkdtemp(prefix='tempest-unit') - self.addCleanup(shutil.rmtree, self.directory) - self.test_dir = os.path.join(self.directory, 'tests') - os.mkdir(self.test_dir) - # Setup Test files - self.testr_conf_file = os.path.join(self.directory, '.testr.conf') - self.setup_cfg_file = os.path.join(self.directory, 'setup.cfg') - self.passing_file = os.path.join(self.test_dir, 'test_passing.py') - self.failing_file = os.path.join(self.test_dir, 'test_failing.py') - self.init_file = os.path.join(self.test_dir, '__init__.py') - self.setup_py = os.path.join(self.directory, 'setup.py') - shutil.copy('tempest/tests/files/testr-conf', self.testr_conf_file) - shutil.copy('tempest/tests/files/passing-tests', self.passing_file) - shutil.copy('tempest/tests/files/failing-tests', self.failing_file) - shutil.copy('setup.py', self.setup_py) - shutil.copy('tempest/tests/files/setup.cfg', self.setup_cfg_file) - shutil.copy('tempest/tests/files/__init__.py', self.init_file) - # Change directory, run wrapper and check result - self.addCleanup(os.chdir, os.path.abspath(os.curdir)) - os.chdir(self.directory) - - def assertRunExit(self, cmd, expected): - p = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - out, err = p.communicate() - msg = ("Running %s got an unexpected returncode\n" - "Stdout: %s\nStderr: %s" % (' '.join(cmd), out, err)) - self.assertEqual(p.returncode, expected, msg) - - def test_tempest_run_passes(self): - # Git init is required for the pbr testr command. pbr requires a git - # version or an sdist to work. so make the test directory a git repo - # too. - subprocess.call(['git', 'init'], stderr=DEVNULL) - self.assertRunExit(['tempest', 'run', '--regex', 'passing'], 0) - - def test_tempest_run_passes_with_testrepository(self): - # Git init is required for the pbr testr command. pbr requires a git - # version or an sdist to work. so make the test directory a git repo - # too. - subprocess.call(['git', 'init'], stderr=DEVNULL) - subprocess.call(['testr', 'init']) - self.assertRunExit(['tempest', 'run', '--regex', 'passing'], 0) - - def test_tempest_run_fails(self): - # Git init is required for the pbr testr command. pbr requires a git - # version or an sdist to work. so make the test directory a git repo - # too. - subprocess.call(['git', 'init'], stderr=DEVNULL) - self.assertRunExit(['tempest', 'run'], 1) - - -class TestTakeAction(base.TestCase): - def test_workspace_not_registered(self): - class Exception_(Exception): - pass - - m_exit = self.useFixture(fixtures.MockPatch('sys.exit')).mock - # sys.exit must not continue (or exit) - m_exit.side_effect = Exception_ - - workspace = self.getUniqueString() - - tempest_run = run.TempestRun(app=mock.Mock(), app_args=mock.Mock()) - parsed_args = mock.Mock() - parsed_args.config_file = [] - - # Override $HOME so that empty workspace gets created in temp dir. - self.useFixture(fixtures.TempHomeDir()) - - # Force use of the temporary home directory. - parsed_args.workspace_path = None - - # Simulate --workspace argument. - parsed_args.workspace = workspace - - self.assertRaises(Exception_, tempest_run.take_action, parsed_args) - exit_msg = m_exit.call_args[0][0] - self.assertIn(workspace, exit_msg) diff --git a/tempest/tests/cmd/test_subunit_describe_calls.py b/tempest/tests/cmd/test_subunit_describe_calls.py deleted file mode 100644 index 5f3d77085..000000000 --- a/tempest/tests/cmd/test_subunit_describe_calls.py +++ /dev/null @@ -1,206 +0,0 @@ -# Copyright 2016 Rackspace -# -# 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 os -import subprocess -import tempfile - -from tempest.cmd import subunit_describe_calls -from tempest.tests import base - - -class TestSubunitDescribeCalls(base.TestCase): - def test_return_code(self): - subunit_file = os.path.join( - os.path.dirname(os.path.abspath(__file__)), - 'sample_streams/calls.subunit') - p = subprocess.Popen([ - 'subunit-describe-calls', '-s', subunit_file, - '-o', tempfile.mkstemp()[1]], stdin=subprocess.PIPE) - p.communicate() - self.assertEqual(0, p.returncode) - - def test_return_code_no_output(self): - subunit_file = os.path.join( - os.path.dirname(os.path.abspath(__file__)), - 'sample_streams/calls.subunit') - p = subprocess.Popen([ - 'subunit-describe-calls', '-s', subunit_file], - stdin=subprocess.PIPE) - p.communicate() - self.assertEqual(0, p.returncode) - - def test_parse(self): - subunit_file = os.path.join( - os.path.dirname(os.path.abspath(__file__)), - 'sample_streams/calls.subunit') - parser = subunit_describe_calls.parse( - open(subunit_file), "pythonlogging", None) - expected_result = { - 'bar': [{ - 'name': 'AgentsAdminTestJSON:setUp', - 'request_body': '{"agent": {"url": "xxx://xxxx/xxx/xxx", ' - '"hypervisor": "common", "md5hash": ' - '"add6bb58e139be103324d04d82d8f545", "version": "7.0", ' - '"architecture": "tempest-x86_64-424013832", "os": "linux"}}', - 'request_headers': "{'Content-Type': 'application/json', " - "'Accept': 'application/json', 'X-Auth-Token': ''}", - 'response_body': '{"agent": {"url": "xxx://xxxx/xxx/xxx", ' - '"hypervisor": "common", "md5hash": ' - '"add6bb58e139be103324d04d82d8f545", "version": "7.0", ' - '"architecture": "tempest-x86_64-424013832", "os": "linux", ' - '"agent_id": 1}}', - 'response_headers': "{'status': '200', 'content-length': " - "'203', 'x-compute-request-id': " - "'req-25ddaae2-0ef1-40d1-8228-59bd64a7e75b', 'vary': " - "'X-OpenStack-Nova-API-Version', 'connection': 'close', " - "'x-openstack-nova-api-version': '2.1', 'date': " - "'Tue, 02 Feb 2016 03:27:00 GMT', 'content-type': " - "'application/json'}", - 'service': 'Nova', - 'status_code': '200', - 'url': 'v2.1//os-agents', - 'verb': 'POST'}, { - 'name': 'AgentsAdminTestJSON:test_create_agent', - 'request_body': '{"agent": {"url": "xxx://xxxx/xxx/xxx", ' - '"hypervisor": "kvm", "md5hash": ' - '"add6bb58e139be103324d04d82d8f545", "version": "7.0", ' - '"architecture": "tempest-x86-252246646", "os": "win"}}', - 'request_headers': "{'Content-Type': 'application/json', " - "'Accept': 'application/json', 'X-Auth-Token': ''}", - 'response_body': '{"agent": {"url": "xxx://xxxx/xxx/xxx", ' - '"hypervisor": "kvm", "md5hash": ' - '"add6bb58e139be103324d04d82d8f545", "version": "7.0", ' - '"architecture": "tempest-x86-252246646", "os": "win", ' - '"agent_id": 2}}', - 'response_headers': "{'status': '200', 'content-length': " - "'195', 'x-compute-request-id': " - "'req-b4136f06-c015-4e7e-995f-c43831e3ecce', 'vary': " - "'X-OpenStack-Nova-API-Version', 'connection': 'close', " - "'x-openstack-nova-api-version': '2.1', 'date': " - "'Tue, 02 Feb 2016 03:27:00 GMT', 'content-type': " - "'application/json'}", - 'service': 'Nova', - 'status_code': '200', - 'url': 'v2.1//os-agents', - 'verb': 'POST'}, { - 'name': 'AgentsAdminTestJSON:tearDown', - 'request_body': 'None', - 'request_headers': "{'Content-Type': 'application/json', " - "'Accept': 'application/json', 'X-Auth-Token': ''}", - 'response_body': '', - 'response_headers': "{'status': '200', 'content-length': " - "'0', 'x-compute-request-id': " - "'req-ee905fd6-a5b5-4da4-8c37-5363cb25bd9d', 'vary': " - "'X-OpenStack-Nova-API-Version', 'connection': 'close', " - "'x-openstack-nova-api-version': '2.1', 'date': " - "'Tue, 02 Feb 2016 03:27:00 GMT', 'content-type': " - "'application/json'}", - 'service': 'Nova', - 'status_code': '200', - 'url': 'v2.1//os-agents/1', - 'verb': 'DELETE'}, { - 'name': 'AgentsAdminTestJSON:_run_cleanups', - 'request_body': 'None', - 'request_headers': "{'Content-Type': 'application/json', " - "'Accept': 'application/json', 'X-Auth-Token': ''}", - 'response_headers': "{'status': '200', 'content-length': " - "'0', 'x-compute-request-id': " - "'req-e912cac0-63e0-4679-a68a-b6d18ddca074', 'vary': " - "'X-OpenStack-Nova-API-Version', 'connection': 'close', " - "'x-openstack-nova-api-version': '2.1', 'date': " - "'Tue, 02 Feb 2016 03:27:00 GMT', 'content-type': " - "'application/json'}", - 'service': 'Nova', - 'status_code': '200', - 'url': 'v2.1//os-agents/2', - 'verb': 'DELETE'}], - 'foo': [{ - 'name': 'AgentsAdminTestJSON:setUp', - 'request_body': '{"agent": {"url": "xxx://xxxx/xxx/xxx", ' - '"hypervisor": "common", "md5hash": ' - '"add6bb58e139be103324d04d82d8f545", "version": "7.0", ' - '"architecture": "tempest-x86_64-948635295", "os": "linux"}}', - 'request_headers': "{'Content-Type': 'application/json', " - "'Accept': 'application/json', 'X-Auth-Token': ''}", - 'response_body': '{"agent": {"url": "xxx://xxxx/xxx/xxx", ' - '"hypervisor": "common", "md5hash": ' - '"add6bb58e139be103324d04d82d8f545", "version": "7.0", ' - '"architecture": "tempest-x86_64-948635295", "os": "linux", ' - '"agent_id": 3}}', - 'response_headers': "{'status': '200', 'content-length': " - "'203', 'x-compute-request-id': " - "'req-ccd2116d-04b1-4ffe-ae32-fb623f68bf1c', 'vary': " - "'X-OpenStack-Nova-API-Version', 'connection': 'close', " - "'x-openstack-nova-api-version': '2.1', 'date': " - "'Tue, 02 Feb 2016 03:27:01 GMT', 'content-type': " - "'application/json'}", - 'service': 'Nova', - 'status_code': '200', - 'url': 'v2.1//os-agents', - 'verb': 'POST'}, { - 'name': 'AgentsAdminTestJSON:test_delete_agent', - 'request_body': 'None', - 'request_headers': "{'Content-Type': 'application/json', " - "'Accept': 'application/json', 'X-Auth-Token': ''}", - 'response_body': '', - 'response_headers': "{'status': '200', 'content-length': " - "'0', 'x-compute-request-id': " - "'req-6e7fa28f-ae61-4388-9a78-947c58bc0588', 'vary': " - "'X-OpenStack-Nova-API-Version', 'connection': 'close', " - "'x-openstack-nova-api-version': '2.1', 'date': " - "'Tue, 02 Feb 2016 03:27:01 GMT', 'content-type': " - "'application/json'}", - 'service': 'Nova', - 'status_code': '200', - 'url': 'v2.1//os-agents/3', - 'verb': 'DELETE'}, { - 'name': 'AgentsAdminTestJSON:test_delete_agent', - 'request_body': 'None', - 'request_headers': "{'Content-Type': 'application/json', " - "'Accept': 'application/json', 'X-Auth-Token': ''}", - 'response_body': '{"agents": []}', - 'response_headers': "{'status': '200', 'content-length': " - "'14', 'content-location': " - "'http://23.253.76.97:8774/v2.1/" - "cf6b1933fe5b476fbbabb876f6d1b924/os-agents', " - "'x-compute-request-id': " - "'req-e41aa9b4-41a6-4138-ae04-220b768eb644', 'vary': " - "'X-OpenStack-Nova-API-Version', 'connection': 'close', " - "'x-openstack-nova-api-version': '2.1', 'date': " - "'Tue, 02 Feb 2016 03:27:01 GMT', 'content-type': " - "'application/json'}", - 'service': 'Nova', - 'status_code': '200', - 'url': 'v2.1//os-agents', - 'verb': 'GET'}, { - 'name': 'AgentsAdminTestJSON:tearDown', - 'request_body': 'None', - 'request_headers': "{'Content-Type': 'application/json', " - "'Accept': 'application/json', 'X-Auth-Token': ''}", - 'response_headers': "{'status': '404', 'content-length': " - "'82', 'x-compute-request-id': " - "'req-e297aeea-91cf-4f26-b49c-8f46b1b7a926', 'vary': " - "'X-OpenStack-Nova-API-Version', 'connection': 'close', " - "'x-openstack-nova-api-version': '2.1', 'date': " - "'Tue, 02 Feb 2016 03:27:02 GMT', 'content-type': " - "'application/json; charset=UTF-8'}", - 'service': 'Nova', - 'status_code': '404', - 'url': 'v2.1//os-agents/3', - 'verb': 'DELETE'}]} - - self.assertEqual(expected_result, parser.test_logs) diff --git a/tempest/tests/cmd/test_tempest_init.py b/tempest/tests/cmd/test_tempest_init.py deleted file mode 100644 index 79510be76..000000000 --- a/tempest/tests/cmd/test_tempest_init.py +++ /dev/null @@ -1,154 +0,0 @@ -# Copyright 2015 Hewlett-Packard Development Company, L.P. -# -# 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 os - -import fixtures - -from tempest.cmd import init -from tempest.tests import base - - -class TestTempestInit(base.TestCase): - - def test_generate_testr_conf(self): - # Create fake conf dir - conf_dir = self.useFixture(fixtures.TempDir()) - - init_cmd = init.TempestInit(None, None) - init_cmd.generate_testr_conf(conf_dir.path) - - # Generate expected file contents - top_level_path = os.path.dirname(os.path.dirname(init.__file__)) - discover_path = os.path.join(top_level_path, 'test_discover') - testr_conf_file = init.TESTR_CONF % (top_level_path, discover_path) - - conf_path = conf_dir.join('.testr.conf') - with open(conf_path, 'r') as conf_file: - self.assertEqual(conf_file.read(), testr_conf_file) - - def test_generate_sample_config(self): - local_dir = self.useFixture(fixtures.TempDir()) - etc_dir_path = os.path.join(local_dir.path, 'etc/') - os.mkdir(etc_dir_path) - init_cmd = init.TempestInit(None, None) - local_sample_conf_file = os.path.join(etc_dir_path, - 'tempest.conf.sample') - - # Verify no sample config file exist - self.assertFalse(os.path.isfile(local_sample_conf_file)) - init_cmd.generate_sample_config(local_dir.path) - - # Verify sample config file exist with some content - self.assertTrue(os.path.isfile(local_sample_conf_file)) - self.assertGreater(os.path.getsize(local_sample_conf_file), 0) - - def test_update_local_conf(self): - local_dir = self.useFixture(fixtures.TempDir()) - etc_dir_path = os.path.join(local_dir.path, 'etc/') - os.mkdir(etc_dir_path) - lock_dir = os.path.join(local_dir.path, 'tempest_lock') - config_path = os.path.join(etc_dir_path, 'tempest.conf') - log_dir = os.path.join(local_dir.path, 'logs') - - init_cmd = init.TempestInit(None, None) - - # Generate the config file - init_cmd.generate_sample_config(local_dir.path) - - # Create a conf file with populated values - config_parser_pre = init_cmd.get_configparser(config_path) - with open(config_path, 'w+') as conf_file: - # create the same section init will check for and add values to - config_parser_pre.add_section('oslo_concurrency') - config_parser_pre.set('oslo_concurrency', 'TEST', local_dir.path) - # create a new section - config_parser_pre.add_section('TEST') - config_parser_pre.set('TEST', 'foo', "bar") - config_parser_pre.write(conf_file) - - # Update the config file the same way tempest init does - init_cmd.update_local_conf(config_path, lock_dir, log_dir) - - # parse the new config file to verify it - config_parser_post = init_cmd.get_configparser(config_path) - - # check that our value in oslo_concurrency wasn't overwritten - self.assertTrue(config_parser_post.has_section('oslo_concurrency')) - self.assertEqual(config_parser_post.get('oslo_concurrency', 'TEST'), - local_dir.path) - # check that the lock directory was set correctly - self.assertEqual(config_parser_post.get('oslo_concurrency', - 'lock_path'), lock_dir) - - # check that our new section still exists and wasn't modified - self.assertTrue(config_parser_post.has_section('TEST')) - self.assertEqual(config_parser_post.get('TEST', 'foo'), 'bar') - - # check that the DEFAULT values are correct - # NOTE(auggy): has_section ignores DEFAULT - self.assertEqual(config_parser_post.get('DEFAULT', 'log_dir'), log_dir) - - def test_create_working_dir_with_existing_local_dir_non_empty(self): - fake_local_dir = self.useFixture(fixtures.TempDir()) - fake_local_conf_dir = self.useFixture(fixtures.TempDir()) - open("%s/foo" % fake_local_dir.path, 'w').close() - - _init = init.TempestInit(None, None) - self.assertRaises(OSError, - _init.create_working_dir, - fake_local_dir.path, - fake_local_conf_dir.path) - - def test_create_working_dir(self): - fake_local_dir = self.useFixture(fixtures.TempDir()) - fake_local_conf_dir = self.useFixture(fixtures.TempDir()) - os.rmdir(fake_local_dir.path) - # Create a fake conf file - fake_file = fake_local_conf_dir.join('conf_file.conf') - open(fake_file, 'w').close() - init_cmd = init.TempestInit(None, None) - init_cmd.create_working_dir(fake_local_dir.path, - fake_local_conf_dir.path) - # Assert directories are created - lock_path = os.path.join(fake_local_dir.path, 'tempest_lock') - etc_dir = os.path.join(fake_local_dir.path, 'etc') - log_dir = os.path.join(fake_local_dir.path, 'logs') - testr_dir = os.path.join(fake_local_dir.path, '.testrepository') - self.assertTrue(os.path.isdir(lock_path)) - self.assertTrue(os.path.isdir(etc_dir)) - self.assertTrue(os.path.isdir(log_dir)) - self.assertTrue(os.path.isdir(testr_dir)) - # Assert file creation - fake_file_moved = os.path.join(etc_dir, 'conf_file.conf') - local_conf_file = os.path.join(etc_dir, 'tempest.conf') - local_testr_conf = os.path.join(fake_local_dir.path, '.testr.conf') - self.assertTrue(os.path.isfile(fake_file_moved)) - self.assertTrue(os.path.isfile(local_conf_file)) - self.assertTrue(os.path.isfile(local_testr_conf)) - - def test_take_action_fails(self): - class ParsedArgs(object): - workspace_dir = self.useFixture(fixtures.TempDir()).path - workspace_path = os.path.join(workspace_dir, 'workspace.yaml') - name = 'test' - dir_base = self.useFixture(fixtures.TempDir()).path - dir = os.path.join(dir_base, 'foo', 'bar') - config_dir = self.useFixture(fixtures.TempDir()).path - show_global_dir = False - pa = ParsedArgs() - init_cmd = init.TempestInit(None, None) - self.assertRaises(OSError, init_cmd.take_action, pa) - # one more trying should be a same error not "workspace already exists" - self.assertRaises(OSError, init_cmd.take_action, pa) diff --git a/tempest/tests/cmd/test_verify_tempest_config.py b/tempest/tests/cmd/test_verify_tempest_config.py deleted file mode 100644 index 1415111cc..000000000 --- a/tempest/tests/cmd/test_verify_tempest_config.py +++ /dev/null @@ -1,431 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# 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 fixtures -import mock -from oslo_serialization import jsonutils as json - -from tempest.cmd import verify_tempest_config -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.tests import base -from tempest.tests import fake_config - - -class TestGetAPIVersions(base.TestCase): - - def test_remove_version_project(self): - f = verify_tempest_config._remove_version_project - self.assertEqual('/', f('/v2.1/%s/' % data_utils.rand_uuid_hex())) - self.assertEqual('', f('/v2.1/tenant_id')) - self.assertEqual('', f('/v3')) - self.assertEqual('/', f('/v3/')) - self.assertEqual('/something/', f('/something/v2.1/tenant_id/')) - self.assertEqual('/something', f('/something/v2.1/tenant_id')) - self.assertEqual('/something', f('/something/v3')) - self.assertEqual('/something/', f('/something/v3/')) - self.assertEqual('/', f('/')) # http://localhost/ - self.assertEqual('', f('')) # http://localhost - - def test_url_grab_versioned_nova_nossl(self): - base_url = 'http://127.0.0.1:8774/v2/' - endpoint = verify_tempest_config._get_unversioned_endpoint(base_url) - self.assertEqual('http://127.0.0.1:8774/', endpoint) - - def test_url_grab_versioned_nova_ssl(self): - base_url = 'https://127.0.0.1:8774/v3/' - endpoint = verify_tempest_config._get_unversioned_endpoint(base_url) - self.assertEqual('https://127.0.0.1:8774/', endpoint) - - def test_get_unversioned_endpoint_base(self): - base_url = 'https://127.0.0.1:5000/' - endpoint = verify_tempest_config._get_unversioned_endpoint(base_url) - self.assertEqual('https://127.0.0.1:5000/', endpoint) - - def test_get_unversioned_endpoint_subpath(self): - base_url = 'https://127.0.0.1/identity/v3' - endpoint = verify_tempest_config._get_unversioned_endpoint(base_url) - self.assertEqual('https://127.0.0.1/identity', endpoint) - - def test_get_unversioned_endpoint_subpath_trailing_solidus(self): - base_url = 'https://127.0.0.1/identity/v3/' - endpoint = verify_tempest_config._get_unversioned_endpoint(base_url) - self.assertEqual('https://127.0.0.1/identity/', endpoint) - - -class TestDiscovery(base.TestCase): - - def setUp(self): - super(TestDiscovery, self).setUp() - self.useFixture(fake_config.ConfigFixture()) - self.patchobject(config, 'TempestConfigPrivate', - fake_config.FakePrivate) - - def test_get_keystone_api_versions(self): - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, '_get_unversioned_endpoint', - return_value='http://fake_endpoint:5000')) - fake_resp = {'versions': {'values': [{'id': 'v2.0'}, {'id': 'v3.0'}]}} - fake_resp = json.dumps(fake_resp) - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.http.ClosingHttp.request', - return_value=(None, fake_resp))) - fake_os = mock.MagicMock() - versions = verify_tempest_config._get_api_versions(fake_os, 'keystone') - self.assertIn('v2.0', versions) - self.assertIn('v3.0', versions) - - def test_get_cinder_api_versions(self): - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, '_get_unversioned_endpoint', - return_value='http://fake_endpoint:5000')) - fake_resp = {'versions': [{'id': 'v1.0'}, {'id': 'v2.0'}]} - fake_resp = json.dumps(fake_resp) - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.http.ClosingHttp.request', - return_value=(None, fake_resp))) - fake_os = mock.MagicMock() - versions = verify_tempest_config._get_api_versions(fake_os, 'cinder') - self.assertIn('v1.0', versions) - self.assertIn('v2.0', versions) - - def test_get_nova_versions(self): - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, '_get_unversioned_endpoint', - return_value='http://fake_endpoint:5000')) - fake_resp = {'versions': [{'id': 'v2.0'}, {'id': 'v3.0'}]} - fake_resp = json.dumps(fake_resp) - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.http.ClosingHttp.request', - return_value=(None, fake_resp))) - fake_os = mock.MagicMock() - versions = verify_tempest_config._get_api_versions(fake_os, 'nova') - self.assertIn('v2.0', versions) - self.assertIn('v3.0', versions) - - def test_get_versions_invalid_response(self): - # When the response doesn't contain a JSON response, an error is - # logged. - mock_log_error = self.useFixture(fixtures.MockPatchObject( - verify_tempest_config.LOG, 'error')).mock - - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, '_get_unversioned_endpoint')) - - # Simulated response is not JSON. - sample_body = ( - 'Sample ResponseThis is the sample page ' - 'for the web server. Why are you requesting it?') - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.http.ClosingHttp.request', - return_value=(None, sample_body))) - - # service value doesn't matter, just needs to match what - # _get_api_versions puts in its client_dict. - self.assertRaises(ValueError, verify_tempest_config._get_api_versions, - os=mock.MagicMock(), service='keystone') - self.assertTrue(mock_log_error.called) - - def test_verify_api_versions(self): - api_services = ['cinder', 'glance', 'keystone'] - fake_os = mock.MagicMock() - for svc in api_services: - m = 'verify_%s_api_versions' % svc - with mock.patch.object(verify_tempest_config, m) as verify_mock: - verify_tempest_config.verify_api_versions(fake_os, svc, True) - verify_mock.assert_called_once_with(fake_os, True) - - def test_verify_api_versions_not_implemented(self): - api_services = ['cinder', 'glance', 'keystone'] - fake_os = mock.MagicMock() - for svc in api_services: - m = 'verify_%s_api_versions' % svc - with mock.patch.object(verify_tempest_config, m) as verify_mock: - verify_tempest_config.verify_api_versions(fake_os, 'foo', True) - self.assertFalse(verify_mock.called) - - @mock.patch('tempest.lib.common.http.ClosingHttp.request') - def test_verify_keystone_api_versions_no_v3(self, mock_request): - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, '_get_unversioned_endpoint', - return_value='http://fake_endpoint:5000')) - fake_resp = {'versions': {'values': [{'id': 'v2.0'}]}} - fake_resp = json.dumps(fake_resp) - mock_request.return_value = (None, fake_resp) - fake_os = mock.MagicMock() - with mock.patch.object(verify_tempest_config, - 'print_and_or_update') as print_mock: - verify_tempest_config.verify_keystone_api_versions(fake_os, True) - print_mock.assert_called_once_with('api_v3', - 'identity-feature-enabled', - False, True) - - @mock.patch('tempest.lib.common.http.ClosingHttp.request') - def test_verify_keystone_api_versions_no_v2(self, mock_request): - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, '_get_unversioned_endpoint', - return_value='http://fake_endpoint:5000')) - fake_resp = {'versions': {'values': [{'id': 'v3.0'}]}} - fake_resp = json.dumps(fake_resp) - mock_request.return_value = (None, fake_resp) - fake_os = mock.MagicMock() - with mock.patch.object(verify_tempest_config, - 'print_and_or_update') as print_mock: - verify_tempest_config.verify_keystone_api_versions(fake_os, True) - print_mock.assert_called_once_with('api_v2', - 'identity-feature-enabled', - False, True) - - @mock.patch('tempest.lib.common.http.ClosingHttp.request') - def test_verify_cinder_api_versions_no_v3(self, mock_request): - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, '_get_unversioned_endpoint', - return_value='http://fake_endpoint:5000')) - fake_resp = {'versions': [{'id': 'v2.0'}]} - fake_resp = json.dumps(fake_resp) - mock_request.return_value = (None, fake_resp) - fake_os = mock.MagicMock() - with mock.patch.object(verify_tempest_config, - 'print_and_or_update') as print_mock: - verify_tempest_config.verify_cinder_api_versions(fake_os, True) - print_mock.assert_any_call('api_v3', 'volume-feature-enabled', - False, True) - self.assertEqual(1, print_mock.call_count) - - @mock.patch('tempest.lib.common.http.ClosingHttp.request') - def test_verify_cinder_api_versions_no_v2(self, mock_request): - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, '_get_unversioned_endpoint', - return_value='http://fake_endpoint:5000')) - fake_resp = {'versions': [{'id': 'v3.0'}]} - fake_resp = json.dumps(fake_resp) - mock_request.return_value = (None, fake_resp) - fake_os = mock.MagicMock() - with mock.patch.object(verify_tempest_config, - 'print_and_or_update') as print_mock: - verify_tempest_config.verify_cinder_api_versions(fake_os, True) - print_mock.assert_any_call('api_v2', 'volume-feature-enabled', - False, True) - self.assertEqual(1, print_mock.call_count) - - @mock.patch('tempest.lib.common.http.ClosingHttp.request') - def test_verify_cinder_api_versions_no_v1(self, mock_request): - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, '_get_unversioned_endpoint', - return_value='http://fake_endpoint:5000')) - fake_resp = {'versions': [{'id': 'v2.0'}, {'id': 'v3.0'}]} - fake_resp = json.dumps(fake_resp) - mock_request.return_value = (None, fake_resp) - fake_os = mock.MagicMock() - with mock.patch.object(verify_tempest_config, - 'print_and_or_update') as print_mock: - verify_tempest_config.verify_cinder_api_versions(fake_os, True) - print_mock.assert_not_called() - - def test_verify_glance_version_no_v2_with_v1_1(self): - def fake_get_versions(): - return (None, ['v1.1']) - fake_os = mock.MagicMock() - fake_os.image_client.get_versions = fake_get_versions - with mock.patch.object(verify_tempest_config, - 'print_and_or_update') as print_mock: - verify_tempest_config.verify_glance_api_versions(fake_os, True) - print_mock.assert_called_once_with('api_v2', 'image-feature-enabled', - False, True) - - def test_verify_glance_version_no_v2_with_v1_0(self): - def fake_get_versions(): - return (None, ['v1.0']) - fake_os = mock.MagicMock() - fake_os.image_client.get_versions = fake_get_versions - with mock.patch.object(verify_tempest_config, - 'print_and_or_update') as print_mock: - verify_tempest_config.verify_glance_api_versions(fake_os, True) - print_mock.assert_called_once_with('api_v2', 'image-feature-enabled', - False, True) - - def test_verify_glance_version_no_v1(self): - def fake_get_versions(): - return (None, ['v2.0']) - fake_os = mock.MagicMock() - fake_os.image_client.get_versions = fake_get_versions - with mock.patch.object(verify_tempest_config, - 'print_and_or_update') as print_mock: - verify_tempest_config.verify_glance_api_versions(fake_os, True) - print_mock.assert_called_once_with('api_v1', 'image-feature-enabled', - False, True) - - def test_verify_extensions_neutron(self): - def fake_list_extensions(): - return {'extensions': [{'alias': 'fake1'}, - {'alias': 'fake2'}, - {'alias': 'not_fake'}]} - fake_os = mock.MagicMock() - fake_os.network_extensions_client.list_extensions = ( - fake_list_extensions) - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, 'get_enabled_extensions', - return_value=(['fake1', 'fake2', 'fake3']))) - results = verify_tempest_config.verify_extensions(fake_os, - 'neutron', {}) - self.assertIn('neutron', results) - self.assertIn('fake1', results['neutron']) - self.assertTrue(results['neutron']['fake1']) - self.assertIn('fake2', results['neutron']) - self.assertTrue(results['neutron']['fake2']) - self.assertIn('fake3', results['neutron']) - self.assertFalse(results['neutron']['fake3']) - self.assertIn('not_fake', results['neutron']) - self.assertFalse(results['neutron']['not_fake']) - - def test_verify_extensions_neutron_all(self): - def fake_list_extensions(): - return {'extensions': [{'alias': 'fake1'}, - {'alias': 'fake2'}, - {'alias': 'not_fake'}]} - fake_os = mock.MagicMock() - fake_os.network_extensions_client.list_extensions = ( - fake_list_extensions) - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, 'get_enabled_extensions', - return_value=(['all']))) - results = verify_tempest_config.verify_extensions(fake_os, - 'neutron', {}) - self.assertIn('neutron', results) - self.assertIn('extensions', results['neutron']) - self.assertEqual(sorted(['fake1', 'fake2', 'not_fake']), - sorted(results['neutron']['extensions'])) - - def test_verify_extensions_cinder(self): - def fake_list_extensions(): - return {'extensions': [{'alias': 'fake1'}, - {'alias': 'fake2'}, - {'alias': 'not_fake'}]} - fake_os = mock.MagicMock() - # NOTE (e0ne): mock both v1 and v2 APIs - fake_os.volumes_extension_client.list_extensions = fake_list_extensions - fake_os.volumes_v2_extension_client.list_extensions = ( - fake_list_extensions) - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, 'get_enabled_extensions', - return_value=(['fake1', 'fake2', 'fake3']))) - results = verify_tempest_config.verify_extensions(fake_os, - 'cinder', {}) - self.assertIn('cinder', results) - self.assertIn('fake1', results['cinder']) - self.assertTrue(results['cinder']['fake1']) - self.assertIn('fake2', results['cinder']) - self.assertTrue(results['cinder']['fake2']) - self.assertIn('fake3', results['cinder']) - self.assertFalse(results['cinder']['fake3']) - self.assertIn('not_fake', results['cinder']) - self.assertFalse(results['cinder']['not_fake']) - - def test_verify_extensions_cinder_all(self): - def fake_list_extensions(): - return {'extensions': [{'alias': 'fake1'}, - {'alias': 'fake2'}, - {'alias': 'not_fake'}]} - fake_os = mock.MagicMock() - # NOTE (e0ne): mock both v1 and v2 APIs - fake_os.volumes_extension_client.list_extensions = fake_list_extensions - fake_os.volumes_v2_extension_client.list_extensions = ( - fake_list_extensions) - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, 'get_enabled_extensions', - return_value=(['all']))) - results = verify_tempest_config.verify_extensions(fake_os, - 'cinder', {}) - self.assertIn('cinder', results) - self.assertIn('extensions', results['cinder']) - self.assertEqual(sorted(['fake1', 'fake2', 'not_fake']), - sorted(results['cinder']['extensions'])) - - def test_verify_extensions_nova(self): - def fake_list_extensions(): - return ([{'alias': 'fake1'}, {'alias': 'fake2'}, - {'alias': 'not_fake'}]) - fake_os = mock.MagicMock() - fake_os.extensions_client.list_extensions = fake_list_extensions - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, 'get_enabled_extensions', - return_value=(['fake1', 'fake2', 'fake3']))) - results = verify_tempest_config.verify_extensions(fake_os, - 'nova', {}) - self.assertIn('nova', results) - self.assertIn('fake1', results['nova']) - self.assertTrue(results['nova']['fake1']) - self.assertIn('fake2', results['nova']) - self.assertTrue(results['nova']['fake2']) - self.assertIn('fake3', results['nova']) - self.assertFalse(results['nova']['fake3']) - self.assertIn('not_fake', results['nova']) - self.assertFalse(results['nova']['not_fake']) - - def test_verify_extensions_nova_all(self): - def fake_list_extensions(): - return ({'extensions': [{'alias': 'fake1'}, - {'alias': 'fake2'}, - {'alias': 'not_fake'}]}) - fake_os = mock.MagicMock() - fake_os.extensions_client.list_extensions = fake_list_extensions - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, 'get_enabled_extensions', - return_value=(['all']))) - results = verify_tempest_config.verify_extensions(fake_os, - 'nova', {}) - self.assertIn('nova', results) - self.assertIn('extensions', results['nova']) - self.assertEqual(sorted(['fake1', 'fake2', 'not_fake']), - sorted(results['nova']['extensions'])) - - def test_verify_extensions_swift(self): - def fake_list_extensions(): - return {'fake1': 'metadata', - 'fake2': 'metadata', - 'not_fake': 'metadata', - 'swift': 'metadata'} - fake_os = mock.MagicMock() - fake_os.capabilities_client.list_capabilities = fake_list_extensions - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, 'get_enabled_extensions', - return_value=(['fake1', 'fake2', 'fake3']))) - results = verify_tempest_config.verify_extensions(fake_os, 'swift', {}) - self.assertIn('swift', results) - self.assertIn('fake1', results['swift']) - self.assertTrue(results['swift']['fake1']) - self.assertIn('fake2', results['swift']) - self.assertTrue(results['swift']['fake2']) - self.assertIn('fake3', results['swift']) - self.assertFalse(results['swift']['fake3']) - self.assertIn('not_fake', results['swift']) - self.assertFalse(results['swift']['not_fake']) - - def test_verify_extensions_swift_all(self): - def fake_list_extensions(): - return {'fake1': 'metadata', - 'fake2': 'metadata', - 'not_fake': 'metadata', - 'swift': 'metadata'} - fake_os = mock.MagicMock() - fake_os.capabilities_client.list_capabilities = fake_list_extensions - self.useFixture(fixtures.MockPatchObject( - verify_tempest_config, 'get_enabled_extensions', - return_value=(['all']))) - results = verify_tempest_config.verify_extensions(fake_os, - 'swift', {}) - self.assertIn('swift', results) - self.assertIn('extensions', results['swift']) - self.assertEqual(sorted(['not_fake', 'fake1', 'fake2']), - sorted(results['swift']['extensions'])) diff --git a/tempest/tests/cmd/test_workspace.py b/tempest/tests/cmd/test_workspace.py deleted file mode 100644 index a1c8c5333..000000000 --- a/tempest/tests/cmd/test_workspace.py +++ /dev/null @@ -1,142 +0,0 @@ -# Copyright 2016 Rackspace -# -# 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 os -import shutil -import subprocess -import tempfile - -from tempest.cmd import workspace -from tempest.lib.common.utils import data_utils -from tempest.tests import base - - -class TestTempestWorkspaceBase(base.TestCase): - def setUp(self): - super(TestTempestWorkspaceBase, self).setUp() - self.name = data_utils.rand_uuid() - self.path = tempfile.mkdtemp() - self.addCleanup(shutil.rmtree, self.path, ignore_errors=True) - store_dir = tempfile.mkdtemp() - self.addCleanup(shutil.rmtree, store_dir, ignore_errors=True) - self.store_file = os.path.join(store_dir, 'workspace.yaml') - self.workspace_manager = workspace.WorkspaceManager( - path=self.store_file) - self.workspace_manager.register_new_workspace(self.name, self.path) - - -class TestTempestWorkspace(TestTempestWorkspaceBase): - def _run_cmd_gets_return_code(self, cmd, expected): - process = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - stdout, stderr = process.communicate() - return_code = process.returncode - msg = ("%s failed with:\nstdout: %s\nstderr: %s" % (' '.join(cmd), - stdout, stderr)) - self.assertEqual(return_code, expected, msg) - - def test_run_workspace_list(self): - cmd = ['tempest', 'workspace', 'list', - '--workspace-path', self.store_file] - self._run_cmd_gets_return_code(cmd, 0) - - def test_run_workspace_register(self): - name = data_utils.rand_uuid() - path = tempfile.mkdtemp() - self.addCleanup(shutil.rmtree, path, ignore_errors=True) - cmd = ['tempest', 'workspace', 'register', - '--workspace-path', self.store_file, - '--name', name, '--path', path] - self._run_cmd_gets_return_code(cmd, 0) - self.assertIsNotNone(self.workspace_manager.get_workspace(name)) - - def test_run_workspace_rename(self): - new_name = data_utils.rand_uuid() - cmd = ['tempest', 'workspace', 'rename', - '--workspace-path', self.store_file, - '--old-name', self.name, '--new-name', new_name] - self._run_cmd_gets_return_code(cmd, 0) - self.assertIsNone(self.workspace_manager.get_workspace(self.name)) - self.assertIsNotNone(self.workspace_manager.get_workspace(new_name)) - - def test_run_workspace_move(self): - new_path = tempfile.mkdtemp() - self.addCleanup(shutil.rmtree, new_path, ignore_errors=True) - cmd = ['tempest', 'workspace', 'move', - '--workspace-path', self.store_file, - '--name', self.name, '--path', new_path] - self._run_cmd_gets_return_code(cmd, 0) - self.assertEqual( - self.workspace_manager.get_workspace(self.name), new_path) - - def test_run_workspace_remove_entry(self): - cmd = ['tempest', 'workspace', 'remove', - '--workspace-path', self.store_file, - '--name', self.name] - self._run_cmd_gets_return_code(cmd, 0) - self.assertIsNone(self.workspace_manager.get_workspace(self.name)) - - def test_run_workspace_remove_directory(self): - cmd = ['tempest', 'workspace', 'remove', - '--workspace-path', self.store_file, - '--name', self.name, '--rmdir'] - self._run_cmd_gets_return_code(cmd, 0) - self.assertIsNone(self.workspace_manager.get_workspace(self.name)) - - -class TestTempestWorkspaceManager(TestTempestWorkspaceBase): - def setUp(self): - super(TestTempestWorkspaceManager, self).setUp() - self.name = data_utils.rand_uuid() - self.path = tempfile.mkdtemp() - self.addCleanup(shutil.rmtree, self.path, ignore_errors=True) - store_dir = tempfile.mkdtemp() - self.addCleanup(shutil.rmtree, store_dir, ignore_errors=True) - self.store_file = os.path.join(store_dir, 'workspace.yaml') - self.workspace_manager = workspace.WorkspaceManager( - path=self.store_file) - self.workspace_manager.register_new_workspace(self.name, self.path) - - def test_workspace_manager_get(self): - self.assertIsNotNone(self.workspace_manager.get_workspace(self.name)) - - def test_workspace_manager_rename(self): - new_name = data_utils.rand_uuid() - self.workspace_manager.rename_workspace(self.name, new_name) - self.assertIsNone(self.workspace_manager.get_workspace(self.name)) - self.assertIsNotNone(self.workspace_manager.get_workspace(new_name)) - - def test_workspace_manager_move(self): - new_path = tempfile.mkdtemp() - self.addCleanup(shutil.rmtree, new_path, ignore_errors=True) - self.workspace_manager.move_workspace(self.name, new_path) - self.assertEqual( - self.workspace_manager.get_workspace(self.name), new_path) - - def test_workspace_manager_remove_entry(self): - self.workspace_manager.remove_workspace_entry(self.name) - self.assertIsNone(self.workspace_manager.get_workspace(self.name)) - - def test_workspace_manager_remove_directory(self): - path = self.workspace_manager.remove_workspace_entry(self.name) - self.workspace_manager.remove_workspace_directory(path) - self.assertIsNone(self.workspace_manager.get_workspace(self.name)) - - def test_path_expansion(self): - name = data_utils.rand_uuid() - path = os.path.join("~", name) - os.makedirs(os.path.expanduser(path)) - self.addCleanup(shutil.rmtree, path, ignore_errors=True) - self.workspace_manager.register_new_workspace(name, path) - self.assertIsNotNone(self.workspace_manager.get_workspace(name)) diff --git a/tempest/tests/common/__init__.py b/tempest/tests/common/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/common/test_admin_available.py b/tempest/tests/common/test_admin_available.py deleted file mode 100644 index 7b3b1b027..000000000 --- a/tempest/tests/common/test_admin_available.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright 2015 Red Hat, Inc. -# -# 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 fixtures -from oslo_config import cfg - -from tempest.common import credentials_factory as credentials -from tempest import config -from tempest.tests import base -from tempest.tests import fake_config - - -class TestAdminAvailable(base.TestCase): - - identity_version = 'v2' - - def setUp(self): - super(TestAdminAvailable, self).setUp() - self.useFixture(fake_config.ConfigFixture()) - self.patchobject(config, 'TempestConfigPrivate', - fake_config.FakePrivate) - - def run_test(self, dynamic_creds, use_accounts_file, admin_creds): - - cfg.CONF.set_default('use_dynamic_credentials', - dynamic_creds, group='auth') - if use_accounts_file: - accounts = [{'username': 'u1', - 'project_name': 't1', - 'password': 'p'}, - {'username': 'u2', - 'project_name': 't2', - 'password': 'p'}] - if admin_creds == 'role': - accounts.append({'username': 'admin', - 'project_name': 'admin', - 'password': 'p', - 'roles': ['admin']}) - elif admin_creds == 'type': - accounts.append({'username': 'admin', - 'project_name': 'admin', - 'password': 'p', - 'types': ['admin']}) - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.preprov_creds.read_accounts_yaml', - return_value=accounts)) - cfg.CONF.set_default('test_accounts_file', - use_accounts_file, group='auth') - self.useFixture(fixtures.MockPatch('os.path.isfile', - return_value=True)) - else: - self.useFixture(fixtures.MockPatch('os.path.isfile', - return_value=False)) - if admin_creds: - username = 'u' - project = 't' - password = 'p' - domain = 'd' - else: - username = None - project = None - password = None - domain = None - - cfg.CONF.set_default('admin_username', username, group='auth') - cfg.CONF.set_default('admin_project_name', project, group='auth') - cfg.CONF.set_default('admin_password', password, group='auth') - cfg.CONF.set_default('admin_domain_name', domain, group='auth') - - expected = admin_creds is not None or dynamic_creds - observed = credentials.is_admin_available( - identity_version=self.identity_version) - self.assertEqual(expected, observed) - - # Dynamic credentials implies admin so only one test case for True - def test__dynamic_creds__accounts_file__no_admin(self): - self.run_test(dynamic_creds=True, - use_accounts_file=True, - admin_creds=None) - - def test__no_dynamic_creds__accounts_file__no_admin(self): - self.run_test(dynamic_creds=False, - use_accounts_file=True, - admin_creds=None) - - def test__no_dynamic_creds__accounts_file__admin_role(self): - self.run_test(dynamic_creds=False, - use_accounts_file=True, - admin_creds='role') - - def test__no_dynamic_creds__accounts_file__admin_type(self): - self.run_test(dynamic_creds=False, - use_accounts_file=True, - admin_creds='type') - - def test__no_dynamic_creds__no_accounts_file__no_admin(self): - self.run_test(dynamic_creds=False, - use_accounts_file=False, - admin_creds=None) - - def test__no_dynamic_creds__no_accounts_file__admin(self): - self.run_test(dynamic_creds=False, - use_accounts_file=False, - admin_creds='role') - - -class TestAdminAvailableV3(TestAdminAvailable): - - identity_version = 'v3' diff --git a/tempest/tests/common/test_alt_available.py b/tempest/tests/common/test_alt_available.py deleted file mode 100644 index a425bb86d..000000000 --- a/tempest/tests/common/test_alt_available.py +++ /dev/null @@ -1,81 +0,0 @@ -# Copyright 2015 Red Hat, Inc. -# -# 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 fixtures -from oslo_config import cfg - -from tempest.common import credentials_factory as credentials -from tempest import config -from tempest.tests import base -from tempest.tests import fake_config - - -class TestAltAvailable(base.TestCase): - - identity_version = 'v2' - - def setUp(self): - super(TestAltAvailable, self).setUp() - self.useFixture(fake_config.ConfigFixture()) - self.patchobject(config, 'TempestConfigPrivate', - fake_config.FakePrivate) - - def run_test(self, dynamic_creds, use_accounts_file, creds): - - cfg.CONF.set_default('use_dynamic_credentials', - dynamic_creds, group='auth') - if use_accounts_file: - accounts = [dict(username="u%s" % ii, - project_name="t%s" % ii, - password="p") for ii in creds] - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.preprov_creds.read_accounts_yaml', - return_value=accounts)) - cfg.CONF.set_default('test_accounts_file', - use_accounts_file, group='auth') - self.useFixture(fixtures.MockPatch('os.path.isfile', - return_value=True)) - else: - self.useFixture(fixtures.MockPatch('os.path.isfile', - return_value=False)) - expected = len(set(creds)) > 1 or dynamic_creds - observed = credentials.is_alt_available( - identity_version=self.identity_version) - self.assertEqual(expected, observed) - - # Dynamic credentials implies alt so only one test case for True - def test__dynamic_creds__accounts_file__one_user(self): - self.run_test(dynamic_creds=True, - use_accounts_file=False, - creds=['1', '2']) - - def test__no_dynamic_creds__accounts_file__one_user(self): - self.run_test(dynamic_creds=False, - use_accounts_file=True, - creds=['1']) - - def test__no_dynamic_creds__accounts_file__two_users(self): - self.run_test(dynamic_creds=False, - use_accounts_file=True, - creds=['1', '2']) - - def test__no_dynamic_creds__accounts_file__two_users_identical(self): - self.run_test(dynamic_creds=False, - use_accounts_file=True, - creds=['1', '1']) - - -class TestAltAvailableV3(TestAltAvailable): - - identity_version = 'v3' diff --git a/tempest/tests/common/test_compute.py b/tempest/tests/common/test_compute.py deleted file mode 100644 index c108be981..000000000 --- a/tempest/tests/common/test_compute.py +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright 2017 Citrix Systems -# 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 six.moves.urllib import parse as urlparse - -import mock - -from tempest.common import compute -from tempest.tests import base - - -class TestCompute(base.TestCase): - def setUp(self): - super(TestCompute, self).setUp() - self.client_sock = mock.Mock() - self.url = urlparse.urlparse("http://www.fake.com:80") - - def test_rfp_frame_not_cached(self): - # rfp negotiation frame arrived separately after upgrade - # response, so it's not cached. - RFP_VERSION = b'RFB.003.003\x0a' - rfp_frame_header = b'\x82\x0c' - - self.client_sock.recv.side_effect = [ - b'fake response start\r\n', - b'fake response end\r\n\r\n', - rfp_frame_header, - RFP_VERSION] - expect_response = b'fake response start\r\nfake response end\r\n\r\n' - - webSocket = compute._WebSocket(self.client_sock, self.url) - - self.assertEqual(webSocket.response, expect_response) - # no cache - self.assertEqual(webSocket.cached_stream, b'') - self.client_sock.recv.assert_has_calls([mock.call(4096), - mock.call(4096)]) - - self.client_sock.recv.reset_mock() - recv_version = webSocket.receive_frame() - - self.assertEqual(recv_version, RFP_VERSION) - self.client_sock.recv.assert_has_calls([mock.call(2), - mock.call(12)]) - - def test_rfp_frame_fully_cached(self): - RFP_VERSION = b'RFB.003.003\x0a' - rfp_version_frame = b'\x82\x0c%s' % RFP_VERSION - - self.client_sock.recv.side_effect = [ - b'fake response start\r\n', - b'fake response end\r\n\r\n%s' % rfp_version_frame] - expect_response = b'fake response start\r\nfake response end\r\n\r\n' - webSocket = compute._WebSocket(self.client_sock, self.url) - - self.client_sock.recv.assert_has_calls([mock.call(4096), - mock.call(4096)]) - self.assertEqual(webSocket.response, expect_response) - self.assertEqual(webSocket.cached_stream, rfp_version_frame) - - self.client_sock.recv.reset_mock() - recv_version = webSocket.receive_frame() - - self.client_sock.recv.assert_not_called() - self.assertEqual(recv_version, RFP_VERSION) - # cached_stream should be empty in the end. - self.assertEqual(webSocket.cached_stream, b'') - - def test_rfp_frame_partially_cached(self): - RFP_VERSION = b'RFB.003.003\x0a' - rfp_version_frame = b'\x82\x0c%s' % RFP_VERSION - frame_part1 = rfp_version_frame[:6] - frame_part2 = rfp_version_frame[6:] - - self.client_sock.recv.side_effect = [ - b'fake response start\r\n', - b'fake response end\r\n\r\n%s' % frame_part1, - frame_part2] - expect_response = b'fake response start\r\nfake response end\r\n\r\n' - webSocket = compute._WebSocket(self.client_sock, self.url) - - self.client_sock.recv.assert_has_calls([mock.call(4096), - mock.call(4096)]) - self.assertEqual(webSocket.response, expect_response) - self.assertEqual(webSocket.cached_stream, frame_part1) - - self.client_sock.recv.reset_mock() - - recv_version = webSocket.receive_frame() - - self.client_sock.recv.assert_called_once_with(len(frame_part2)) - self.assertEqual(recv_version, RFP_VERSION) - # cached_stream should be empty in the end. - self.assertEqual(webSocket.cached_stream, b'') diff --git a/tempest/tests/common/test_custom_matchers.py b/tempest/tests/common/test_custom_matchers.py deleted file mode 100644 index 1053d861a..000000000 --- a/tempest/tests/common/test_custom_matchers.py +++ /dev/null @@ -1,102 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P. -# 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 tempest.common import custom_matchers -from tempest.tests import base - - -# Stolen from testtools/testtools/tests/matchers/helpers.py -class TestMatchersInterface(object): - - def test_matches_match(self): - matcher = self.matches_matcher - matches = self.matches_matches - mismatches = self.matches_mismatches - for candidate in matches: - self.assertIsNone(matcher.match(candidate)) - for candidate in mismatches: - mismatch = matcher.match(candidate) - self.assertIsNotNone(mismatch) - self.assertIsNotNone(getattr(mismatch, 'describe', None)) - - def test__str__(self): - # [(expected, object to __str__)]. - from testtools.matchers._doctest import DocTestMatches - examples = self.str_examples - for expected, matcher in examples: - self.assertThat(matcher, DocTestMatches(expected)) - - def test_describe_difference(self): - # [(expected, matchee, matcher), ...] - examples = self.describe_examples - for difference, matchee, matcher in examples: - mismatch = matcher.match(matchee) - self.assertEqual(difference, mismatch.describe()) - - def test_mismatch_details(self): - # The mismatch object must provide get_details, which must return a - # dictionary mapping names to Content objects. - examples = self.describe_examples - for difference, matchee, matcher in examples: - mismatch = matcher.match(matchee) - details = mismatch.get_details() - self.assertEqual(dict(details), details) - - -class TestMatchesDictExceptForKeys(base.TestCase, - TestMatchersInterface): - - matches_matcher = custom_matchers.MatchesDictExceptForKeys( - {'a': 1, 'b': 2, 'c': 3, 'd': 4}, ['c', 'd']) - matches_matches = [ - {'a': 1, 'b': 2, 'c': 3, 'd': 4}, - {'a': 1, 'b': 2, 'c': 5}, - {'a': 1, 'b': 2}, - ] - matches_mismatches = [ - {}, - {'foo': 1}, - {'a': 1, 'b': 3}, - {'a': 1, 'b': 2, 'foo': 1}, - {'a': 1, 'b': None, 'foo': 1}, - ] - - str_examples = [] - describe_examples = [ - ("Only in expected:\n" - " {'a': 1, 'b': 2}\n", - {}, - matches_matcher), - ("Only in expected:\n" - " {'a': 1, 'b': 2}\n" - "Only in actual:\n" - " {'foo': 1}\n", - {'foo': 1}, - matches_matcher), - ("Differences:\n" - " b: expected 2, actual 3\n", - {'a': 1, 'b': 3}, - matches_matcher), - ("Only in actual:\n" - " {'foo': 1}\n", - {'a': 1, 'b': 2, 'foo': 1}, - matches_matcher), - ("Only in actual:\n" - " {'foo': 1}\n" - "Differences:\n" - " b: expected 2, actual None\n", - {'a': 1, 'b': None, 'foo': 1}, - matches_matcher) - ] diff --git a/tempest/tests/common/test_image.py b/tempest/tests/common/test_image.py deleted file mode 100644 index 240df4d45..000000000 --- a/tempest/tests/common/test_image.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2016 NEC Corporation -# 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 tempest.common import image -from tempest.lib.common import rest_client -from tempest.tests import base - - -class TestImage(base.TestCase): - - def test_get_image_meta_from_headers(self): - resp = { - 'x-image-meta-id': 'ea30c926-0629-4400-bb6e-f8a8da6a4e56', - 'x-image-meta-owner': '8f421f9470e645b1b10f5d2db7804924', - 'x-image-meta-status': 'queued', - 'x-image-meta-name': 'New Http Image' - } - respbody = rest_client.ResponseBody(resp) - observed = image.get_image_meta_from_headers(respbody) - - expected = { - 'properties': {}, - 'id': 'ea30c926-0629-4400-bb6e-f8a8da6a4e56', - 'owner': '8f421f9470e645b1b10f5d2db7804924', - 'status': 'queued', - 'name': 'New Http Image' - } - self.assertEqual(expected, observed) - - def test_image_meta_to_headers(self): - observed = image.image_meta_to_headers( - name='test', - container_format='wrong', - disk_format='vhd', - copy_from='http://localhost/images/10', - properties={'foo': 'bar'}, - api={'abc': 'def'}, - purge_props=True) - - expected = { - 'x-image-meta-name': 'test', - 'x-image-meta-container_format': 'wrong', - 'x-image-meta-disk_format': 'vhd', - 'x-glance-api-copy-from': 'http://localhost/images/10', - 'x-image-meta-property-foo': 'bar', - 'x-glance-api-property-abc': 'def', - 'x-glance-registry-purge-props': True - } - self.assertEqual(expected, observed) diff --git a/tempest/tests/common/test_waiters.py b/tempest/tests/common/test_waiters.py deleted file mode 100644 index c2f622cab..000000000 --- a/tempest/tests/common/test_waiters.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# 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 time - -import mock - -from tempest.common import waiters -from tempest import exceptions -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.volume.v2 import volumes_client -from tempest.tests import base -import tempest.tests.utils as utils - - -class TestImageWaiters(base.TestCase): - def setUp(self): - super(TestImageWaiters, self).setUp() - self.client = mock.MagicMock() - self.client.build_timeout = 1 - self.client.build_interval = 1 - - def test_wait_for_image_status(self): - self.client.show_image.return_value = ({'status': 'active'}) - start_time = int(time.time()) - waiters.wait_for_image_status(self.client, 'fake_image_id', 'active') - end_time = int(time.time()) - # Ensure waiter returns before build_timeout - self.assertLess((end_time - start_time), 10) - - def test_wait_for_image_status_timeout(self): - time_mock = self.patch('time.time') - time_mock.side_effect = utils.generate_timeout_series(1) - - self.client.show_image.return_value = ({'status': 'saving'}) - self.assertRaises(lib_exc.TimeoutException, - waiters.wait_for_image_status, - self.client, 'fake_image_id', 'active') - - def test_wait_for_image_status_error_on_image_create(self): - self.client.show_image.return_value = ({'status': 'ERROR'}) - self.assertRaises(exceptions.AddImageException, - waiters.wait_for_image_status, - self.client, 'fake_image_id', 'active') - - @mock.patch.object(time, 'sleep') - def test_wait_for_volume_status_error_restoring(self, mock_sleep): - # Tests that the wait method raises VolumeRestoreErrorException if - # the volume status is 'error_restoring'. - client = mock.Mock(spec=volumes_client.VolumesClient, - build_interval=1) - volume1 = {'volume': {'status': 'restoring-backup'}} - volume2 = {'volume': {'status': 'error_restoring'}} - mock_show = mock.Mock(side_effect=(volume1, volume2)) - client.show_volume = mock_show - volume_id = '7532b91e-aa0a-4e06-b3e5-20c0c5ee1caa' - self.assertRaises(exceptions.VolumeRestoreErrorException, - waiters.wait_for_volume_resource_status, - client, volume_id, 'available') - mock_show.assert_has_calls([mock.call(volume_id), - mock.call(volume_id)]) - mock_sleep.assert_called_once_with(1) diff --git a/tempest/tests/common/utils/__init__.py b/tempest/tests/common/utils/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/common/utils/linux/__init__.py b/tempest/tests/common/utils/linux/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/common/utils/linux/test_remote_client.py b/tempest/tests/common/utils/linux/test_remote_client.py deleted file mode 100644 index 739357bab..000000000 --- a/tempest/tests/common/utils/linux/test_remote_client.py +++ /dev/null @@ -1,214 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# 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 time - -import fixtures -from oslo_config import cfg - -from tempest.common.utils.linux import remote_client -from tempest import config -from tempest.lib import exceptions as lib_exc -from tempest.tests import base -from tempest.tests import fake_config - - -SERVER = { - 'id': 'server_uuid', - 'name': 'fake_server', - 'status': 'ACTIVE' -} - -BROKEN_SERVER = { - 'id': 'broken_server_uuid', - 'name': 'broken_server', - 'status': 'ERROR' -} - - -class FakeServersClient(object): - - CONSOLE_OUTPUT = "Console output for %s" - - def get_console_output(self, server_id): - status = 'ERROR' - for s in SERVER, BROKEN_SERVER: - if s['id'] == server_id: - status = s['status'] - if status == 'ERROR': - raise lib_exc.BadRequest('Server in ERROR state') - else: - return dict(output=self.CONSOLE_OUTPUT % server_id) - - -class TestRemoteClient(base.TestCase): - def setUp(self): - super(TestRemoteClient, self).setUp() - self.useFixture(fake_config.ConfigFixture()) - self.patchobject(config, 'TempestConfigPrivate', - fake_config.FakePrivate) - cfg.CONF.set_default('ip_version_for_ssh', 4, group='validation') - cfg.CONF.set_default('network_for_ssh', 'public', group='validation') - cfg.CONF.set_default('connect_timeout', 1, group='validation') - - self.conn = remote_client.RemoteClient('127.0.0.1', 'user', 'pass') - self.ssh_mock = self.useFixture(fixtures.MockPatchObject(self.conn, - 'ssh_client')) - - def test_write_to_console_regular_str(self): - self.conn.write_to_console('test') - self._assert_exec_called_with( - 'sudo sh -c "echo \\"test\\" >/dev/console"') - - def _test_write_to_console_helper(self, message, expected_call): - self.conn.write_to_console(message) - self._assert_exec_called_with(expected_call) - - def test_write_to_console_special_chars(self): - self._test_write_to_console_helper( - '\`', - 'sudo sh -c "echo \\"\\\\\\`\\" >/dev/console"') - self.conn.write_to_console('$') - self._assert_exec_called_with( - 'sudo sh -c "echo \\"\\\\$\\" >/dev/console"') - - # NOTE(maurosr): The tests below end up closer to an output format - # assurance than a test since it's basically using comand_exec to format - # the information using gnu/linux tools. - - def _assert_exec_called_with(self, cmd): - cmd = "set -eu -o pipefail; PATH=$PATH:/sbin; " + cmd - self.ssh_mock.mock.exec_command.assert_called_with(cmd) - - def test_get_disks(self): - output_lsblk = """\ -NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT -sda 8:0 0 128035676160 0 disk -sdb 8:16 0 1000204886016 0 disk -sr0 11:0 1 1073741312 0 rom""" - result = """\ -NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT -sda 8:0 0 128035676160 0 disk -sdb 8:16 0 1000204886016 0 disk""" - - self.ssh_mock.mock.exec_command.return_value = output_lsblk - self.assertEqual(self.conn.get_disks(), result) - self._assert_exec_called_with('lsblk -lb --nodeps') - - def test_get_boot_time(self): - booted_at = 10000 - uptime_sec = 5000.02 - self.ssh_mock.mock.exec_command.return_value = uptime_sec - self.useFixture(fixtures.MockPatchObject( - time, 'time', return_value=booted_at + uptime_sec)) - self.assertEqual(self.conn.get_boot_time(), - time.localtime(booted_at)) - self._assert_exec_called_with('cut -f1 -d. /proc/uptime') - - def test_ping_host(self): - ping_response = """PING localhost (127.0.0.1) 70(98) bytes of data. -78 bytes from localhost (127.0.0.1): icmp_req=1 ttl=64 time=0.048 ms -78 bytes from localhost (127.0.0.1): icmp_req=2 ttl=64 time=0.048 ms - ---- localhost ping statistics --- -2 packets transmitted, 2 received, 0% packet loss, time 0ms -rtt min/avg/max/mdev = 0.048/0.048/0.048/0.000 ms""" - self.ssh_mock.mock.exec_command.return_value = ping_response - self.assertEqual(self.conn.ping_host('127.0.0.1', count=2, size=70), - ping_response) - self._assert_exec_called_with('ping -c2 -w2 -s70 127.0.0.1') - - def test_get_mac_address(self): - macs = """0a:0b:0c:0d:0e:0f -a0:b0:c0:d0:e0:f0""" - self.ssh_mock.mock.exec_command.return_value = macs - - self.assertEqual(self.conn.get_mac_address(), macs) - self._assert_exec_called_with( - "ip addr | awk '/ether/ {print $2}'") - - -class TestRemoteClientWithServer(base.TestCase): - - server = SERVER - - def setUp(self): - super(TestRemoteClientWithServer, self).setUp() - self.useFixture(fake_config.ConfigFixture()) - self.patchobject(config, 'TempestConfigPrivate', - fake_config.FakePrivate) - cfg.CONF.set_default('ip_version_for_ssh', 4, group='validation') - cfg.CONF.set_default('network_for_ssh', 'public', - group='validation') - cfg.CONF.set_default('connect_timeout', 1, group='validation') - cfg.CONF.set_default('console_output', True, - group='compute-feature-enabled') - - self.conn = remote_client.RemoteClient( - '127.0.0.1', 'user', 'pass', - server=self.server, servers_client=FakeServersClient()) - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.ssh.Client._get_ssh_connection', - side_effect=lib_exc.SSHTimeout(host='127.0.0.1', - user='user', - password='pass'))) - self.log = self.useFixture(fixtures.FakeLogger( - name='tempest.lib.common.utils.linux.remote_client', - level='DEBUG')) - - def test_validate_debug_ssh_console(self): - self.assertRaises(lib_exc.SSHTimeout, - self.conn.validate_authentication) - msg = 'Caller: %s. Timeout trying to ssh to server %s' % ( - 'TestRemoteClientWithServer:test_validate_debug_ssh_console', - self.server) - self.assertIn(msg, self.log.output) - self.assertIn('Console output for', self.log.output) - - def test_exec_command_debug_ssh_console(self): - self.assertRaises(lib_exc.SSHTimeout, - self.conn.exec_command, 'fake command') - self.assertIn('fake command', self.log.output) - msg = 'Caller: %s. Timeout trying to ssh to server %s' % ( - 'TestRemoteClientWithServer:test_exec_command_debug_ssh_console', - self.server) - self.assertIn(msg, self.log.output) - self.assertIn('Console output for', self.log.output) - - -class TestRemoteClientWithBrokenServer(TestRemoteClientWithServer): - - server = BROKEN_SERVER - - def test_validate_debug_ssh_console(self): - self.assertRaises(lib_exc.SSHTimeout, - self.conn.validate_authentication) - msg = 'Caller: %s. Timeout trying to ssh to server %s' % ( - 'TestRemoteClientWithBrokenServer:test_validate_debug_ssh_console', - self.server) - self.assertIn(msg, self.log.output) - msg = 'Could not get console_log for server %s' % self.server['id'] - self.assertIn(msg, self.log.output) - - def test_exec_command_debug_ssh_console(self): - self.assertRaises(lib_exc.SSHTimeout, - self.conn.exec_command, 'fake command') - self.assertIn('fake command', self.log.output) - caller = ":".join(['TestRemoteClientWithBrokenServer', - 'test_exec_command_debug_ssh_console']) - msg = 'Caller: %s. Timeout trying to ssh to server %s' % ( - caller, self.server) - self.assertIn(msg, self.log.output) - msg = 'Could not get console_log for server %s' % self.server['id'] - self.assertIn(msg, self.log.output) diff --git a/tempest/tests/common/utils/test_net_utils.py b/tempest/tests/common/utils/test_net_utils.py deleted file mode 100644 index 83c6bcc08..000000000 --- a/tempest/tests/common/utils/test_net_utils.py +++ /dev/null @@ -1,33 +0,0 @@ -# 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 mock - -from tempest.common.utils import net_utils -from tempest.lib import exceptions as lib_exc -from tempest.tests import base - - -class TestGetPingPayloadSize(base.TestCase): - - def test_ipv4(self): - self.assertEqual(1422, net_utils.get_ping_payload_size(1450, 4)) - - def test_ipv6(self): - self.assertEqual(1406, net_utils.get_ping_payload_size(1450, 6)) - - def test_too_low_mtu(self): - self.assertRaises( - lib_exc.BadRequest, net_utils.get_ping_payload_size, 10, 4) - - def test_None(self): - self.assertIsNone(net_utils.get_ping_payload_size(None, mock.Mock())) diff --git a/tempest/tests/fake_config.py b/tempest/tests/fake_config.py deleted file mode 100644 index ee6368441..000000000 --- a/tempest/tests/fake_config.py +++ /dev/null @@ -1,106 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# 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 os - -from oslo_concurrency import lockutils -from oslo_config import cfg -from oslo_config import fixture as conf_fixture - -from tempest import config - - -class ConfigFixture(conf_fixture.Config): - - def __init__(self): - cfg.CONF([], default_config_files=[]) - config.register_opts() - super(ConfigFixture, self).__init__() - - def setUp(self): - super(ConfigFixture, self).setUp() - self.conf.set_default('build_interval', 10, group='compute') - self.conf.set_default('build_timeout', 10, group='compute') - self.conf.set_default('disable_ssl_certificate_validation', True, - group='identity') - self.conf.set_default('uri', 'http://fake_uri.com/auth', - group='identity') - self.conf.set_default('uri_v3', 'http://fake_uri_v3.com/auth', - group='identity') - self.conf.set_default('neutron', True, group='service_available') - self.conf.set_default('heat', True, group='service_available') - if not os.path.exists(str(os.environ.get('OS_TEST_LOCK_PATH'))): - os.mkdir(str(os.environ.get('OS_TEST_LOCK_PATH'))) - lockutils.set_defaults( - lock_path=str(os.environ.get('OS_TEST_LOCK_PATH')), - ) - self.conf.set_default('auth_version', 'v2', group='identity') - for config_option in ['username', 'password', 'project_name']: - # Identity group items - self.conf.set_default('admin_' + config_option, - 'fake_' + config_option, - group='auth') - - -class FakePrivate(config.TempestConfigPrivate): - def __init__(self, parse_conf=True, config_path=None): - self._set_attrs() - self.lock_path = cfg.CONF.oslo_concurrency.lock_path - -fake_service1_group = cfg.OptGroup(name='fake-service1', title='Fake service1') - -FakeService1Group = [ - cfg.StrOpt('catalog_type', default='fake-service1'), - cfg.StrOpt('endpoint_type', default='faketype'), - cfg.StrOpt('region', default='fake_region'), - cfg.IntOpt('build_timeout', default=99), - cfg.IntOpt('build_interval', default=9)] - -fake_service2_group = cfg.OptGroup(name='fake-service2', title='Fake service2') - -FakeService2Group = [ - cfg.StrOpt('catalog_type', default='fake-service2'), - cfg.StrOpt('endpoint_type', default='faketype')] - - -class ServiceClientsConfigFixture(conf_fixture.Config): - - def __init__(self): - cfg.CONF([], default_config_files=[]) - config._opts.append((fake_service1_group, FakeService1Group)) - config._opts.append((fake_service2_group, FakeService2Group)) - config.register_opts() - super(ServiceClientsConfigFixture, self).__init__() - - def setUp(self): - super(ServiceClientsConfigFixture, self).setUp() - # Debug default values - self.conf.set_default('trace_requests', 'fake_module', 'debug') - # Identity default values - self.conf.set_default('disable_ssl_certificate_validation', True, - group='identity') - self.conf.set_default('ca_certificates_file', '/fake/certificates', - group='identity') - self.conf.set_default('region', 'fake_region', 'identity') - # Compute default values - self.conf.set_default('build_interval', 88, group='compute') - self.conf.set_default('build_timeout', 8, group='compute') - - -class ServiceClientsFakePrivate(config.TempestConfigPrivate): - def __init__(self, parse_conf=True, config_path=None): - self._set_attrs() - self.fake_service1 = cfg.CONF['fake-service1'] - self.fake_service2 = cfg.CONF['fake-service2'] - self.lock_path = cfg.CONF.oslo_concurrency.lock_path diff --git a/tempest/tests/fake_tempest_plugin.py b/tempest/tests/fake_tempest_plugin.py deleted file mode 100644 index 56aae1e97..000000000 --- a/tempest/tests/fake_tempest_plugin.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright (c) 2015 Deutsche Telekom AG -# 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 tempest.test_discover import plugins - - -class FakePlugin(plugins.TempestPlugin): - expected_load_test = ["my/test/path", "/home/dir"] - expected_service_clients = [{'foo': 'bar'}] - - def load_tests(self): - return self.expected_load_test - - def register_opts(self, conf): - return - - def get_opt_lists(self): - return [] - - def get_service_clients(self): - return self.expected_service_clients - - -class FakeStevedoreObj(object): - obj = FakePlugin() - - @property - def name(self): - return self._name - - def __init__(self, name='Test1'): - self._name = name - - -class FakePluginNoServiceClients(plugins.TempestPlugin): - - def load_tests(self): - return [] - - def register_opts(self, conf): - return - - def get_opt_lists(self): - return [] - - -class FakeStevedoreObjNoServiceClients(object): - obj = FakePluginNoServiceClients() - - @property - def name(self): - return self._name - - def __init__(self, name='Test2'): - self._name = name diff --git a/tempest/tests/files/__init__.py b/tempest/tests/files/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/files/failing-tests b/tempest/tests/files/failing-tests deleted file mode 100644 index 78efc9383..000000000 --- a/tempest/tests/files/failing-tests +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# 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 testtools - -class FakeTestClass(testtools.TestCase): - def test_pass(self): - self.assertTrue(False) - - def test_pass_list(self): - test_list = ['test', 'a', 'b'] - self.assertIn('fail', test_list) diff --git a/tempest/tests/files/passing-tests b/tempest/tests/files/passing-tests deleted file mode 100644 index a55cb1b5b..000000000 --- a/tempest/tests/files/passing-tests +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# 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 testtools - -class FakeTestClass(testtools.TestCase): - def test_pass(self): - self.assertTrue(True) - - def test_pass_list(self): - test_list = ['test', 'a', 'b'] - self.assertIn('test', test_list) diff --git a/tempest/tests/files/setup.cfg b/tempest/tests/files/setup.cfg deleted file mode 100644 index f6f9f7388..000000000 --- a/tempest/tests/files/setup.cfg +++ /dev/null @@ -1,20 +0,0 @@ -[metadata] -name = tempest_unit_tests -version = 1 -summary = Fake Project for testing wrapper scripts -author = OpenStack -author-email = openstack-dev@lists.openstack.org -home-page = http://www.openstack.org/ -classifier = - Intended Audience :: Information Technology - Intended Audience :: System Administrators - Intended Audience :: Developers - License :: OSI Approved :: Apache Software License - Operating System :: POSIX :: Linux - Programming Language :: Python - Programming Language :: Python :: 2 - Programming Language :: Python :: 2.7 - -[global] -setup-hooks = - pbr.hooks.setup_hook diff --git a/tempest/tests/files/testr-conf b/tempest/tests/files/testr-conf deleted file mode 100644 index d5ad08322..000000000 --- a/tempest/tests/files/testr-conf +++ /dev/null @@ -1,5 +0,0 @@ -[DEFAULT] -test_command=${PYTHON:-python} -m subunit.run discover -t ./ ./tests $LISTOPT $IDOPTION -test_id_option=--load-list $IDFILE -test_list_option=--list -group_regex=([^\.]*\.)* diff --git a/tempest/tests/lib/__init__.py b/tempest/tests/lib/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/cli/__init__.py b/tempest/tests/lib/cli/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/cli/test_command_failed.py b/tempest/tests/lib/cli/test_command_failed.py deleted file mode 100644 index 388028a9d..000000000 --- a/tempest/tests/lib/cli/test_command_failed.py +++ /dev/null @@ -1,30 +0,0 @@ -# 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 tempest.lib import exceptions -from tempest.tests import base - - -class TestOutputParser(base.TestCase): - - def test_command_failed_exception(self): - returncode = 1 - cmd = "foo" - stdout = "output" - stderr = "error" - try: - raise exceptions.CommandFailed(returncode, cmd, stdout, stderr) - except exceptions.CommandFailed as e: - self.assertIn(str(returncode), str(e)) - self.assertIn(cmd, str(e)) - self.assertIn(stdout, str(e)) - self.assertIn(stderr, str(e)) diff --git a/tempest/tests/lib/cli/test_execute.py b/tempest/tests/lib/cli/test_execute.py deleted file mode 100644 index 013045448..000000000 --- a/tempest/tests/lib/cli/test_execute.py +++ /dev/null @@ -1,93 +0,0 @@ -# -# 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 subprocess - -import mock - -from tempest.lib.cli import base as cli_base -from tempest.lib import exceptions -from tempest.tests import base - - -class TestExecute(base.TestCase): - - @mock.patch('subprocess.Popen', autospec=True) - def test_execute_success(self, mock_popen): - mock_popen.return_value.returncode = 0 - mock_popen.return_value.communicate.return_value = ( - "__init__.py", "") - result = cli_base.execute("/bin/ls", action="tempest", - flags="-l -a") - args, kwargs = mock_popen.call_args - # Check merge_stderr == False - self.assertEqual(subprocess.PIPE, kwargs['stderr']) - # Check action and flags are passed - args = args[0] - # We just tests that all pieces are passed through, we cannot make - # assumptions about the order - self.assertIn("/bin/ls", args) - self.assertIn("-l", args) - self.assertIn("-a", args) - self.assertIn("tempest", args) - # The result is mocked - checking that the mock was invoked correctly - self.assertIsInstance(result, str) - self.assertIn("__init__.py", result) - - @mock.patch('subprocess.Popen', autospec=True) - def test_execute_failure(self, mock_popen): - mock_popen.return_value.returncode = 1 - mock_popen.return_value.communicate.return_value = ( - "No such option --foobar", "") - result = cli_base.execute("/bin/ls", action="tempest.lib", - flags="--foobar", merge_stderr=True, - fail_ok=True) - args, kwargs = mock_popen.call_args - # Check the merge_stderr - self.assertEqual(subprocess.STDOUT, kwargs['stderr']) - # Check action and flags are passed - args = args[0] - # We just tests that all pieces are passed through, we cannot make - # assumptions about the order - self.assertIn("/bin/ls", args) - self.assertIn("--foobar", args) - self.assertIn("tempest.lib", args) - # The result is mocked - checking that the mock was invoked correctly - self.assertIsInstance(result, str) - self.assertIn("--foobar", result) - - @mock.patch('subprocess.Popen', autospec=True) - def test_execute_failure_raise_exception(self, mock_popen): - mock_popen.return_value.returncode = 1 - mock_popen.return_value.communicate.return_value = ( - "No such option --foobar", "") - self.assertRaises(exceptions.CommandFailed, cli_base.execute, - "/bin/ls", action="tempest", flags="--foobar", - merge_stderr=True) - - def test_execute_with_prefix(self): - result = cli_base.execute("env", action="", - prefix="env NEW_VAR=1") - self.assertIsInstance(result, str) - self.assertIn("NEW_VAR=1", result) - - -class TestCLIClient(base.TestCase): - - @mock.patch.object(cli_base, 'execute') - def test_execute_with_prefix(self, mock_execute): - cli = cli_base.CLIClient(prefix='env LAC_ALL=C') - cli.glance('action') - self.assertEqual(mock_execute.call_count, 1) - self.assertEqual(mock_execute.call_args[1], - {'prefix': 'env LAC_ALL=C'}) diff --git a/tempest/tests/lib/cli/test_output_parser.py b/tempest/tests/lib/cli/test_output_parser.py deleted file mode 100644 index d88dfc36d..000000000 --- a/tempest/tests/lib/cli/test_output_parser.py +++ /dev/null @@ -1,177 +0,0 @@ -# Copyright 2014 NEC Corporation. -# 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 tempest.lib.cli import output_parser -from tempest.lib import exceptions -from tempest.tests import base - - -class TestOutputParser(base.TestCase): - OUTPUT_LINES = """ -+----+------+---------+ -| ID | Name | Status | -+----+------+---------+ -| 11 | foo | BUILD | -| 21 | bar | ERROR | -| 31 | bee | None | -+----+------+---------+ -""" - OUTPUT_LINES2 = """ -+----+-------+---------+ -| ID | Name2 | Status2 | -+----+-------+---------+ -| 41 | aaa | SSSSS | -| 51 | bbb | TTTTT | -| 61 | ccc | AAAAA | -+----+-------+---------+ -""" - - EXPECTED_TABLE = {'headers': ['ID', 'Name', 'Status'], - 'values': [['11', 'foo', 'BUILD'], - ['21', 'bar', 'ERROR'], - ['31', 'bee', 'None']]} - EXPECTED_TABLE2 = {'headers': ['ID', 'Name2', 'Status2'], - 'values': [['41', 'aaa', 'SSSSS'], - ['51', 'bbb', 'TTTTT'], - ['61', 'ccc', 'AAAAA']]} - - def test_table_with_normal_values(self): - actual = output_parser.table(self.OUTPUT_LINES) - self.assertIsInstance(actual, dict) - self.assertEqual(self.EXPECTED_TABLE, actual) - - def test_table_with_list(self): - output_lines = self.OUTPUT_LINES.split('\n') - actual = output_parser.table(output_lines) - self.assertIsInstance(actual, dict) - self.assertEqual(self.EXPECTED_TABLE, actual) - - def test_table_with_invalid_line(self): - output_lines = self.OUTPUT_LINES + "aaaa" - actual = output_parser.table(output_lines) - self.assertIsInstance(actual, dict) - self.assertEqual(self.EXPECTED_TABLE, actual) - - def test_tables_with_normal_values(self): - output_lines = ('test' + self.OUTPUT_LINES + - 'test2' + self.OUTPUT_LINES2) - expected = [{'headers': self.EXPECTED_TABLE['headers'], - 'label': 'test', - 'values': self.EXPECTED_TABLE['values']}, - {'headers': self.EXPECTED_TABLE2['headers'], - 'label': 'test2', - 'values': self.EXPECTED_TABLE2['values']}] - actual = output_parser.tables(output_lines) - self.assertIsInstance(actual, list) - self.assertEqual(expected, actual) - - def test_tables_with_invalid_values(self): - output_lines = ('test' + self.OUTPUT_LINES + - 'test2' + self.OUTPUT_LINES2 + '\n') - expected = [{'headers': self.EXPECTED_TABLE['headers'], - 'label': 'test', - 'values': self.EXPECTED_TABLE['values']}, - {'headers': self.EXPECTED_TABLE2['headers'], - 'label': 'test2', - 'values': self.EXPECTED_TABLE2['values']}] - actual = output_parser.tables(output_lines) - self.assertIsInstance(actual, list) - self.assertEqual(expected, actual) - - def test_tables_with_invalid_line(self): - output_lines = ('test' + self.OUTPUT_LINES + - 'test2' + self.OUTPUT_LINES2 + - '+----+-------+---------+') - expected = [{'headers': self.EXPECTED_TABLE['headers'], - 'label': 'test', - 'values': self.EXPECTED_TABLE['values']}, - {'headers': self.EXPECTED_TABLE2['headers'], - 'label': 'test2', - 'values': self.EXPECTED_TABLE2['values']}] - - actual = output_parser.tables(output_lines) - self.assertIsInstance(actual, list) - self.assertEqual(expected, actual) - - LISTING_OUTPUT = """ -+----+ -| ID | -+----+ -| 11 | -| 21 | -| 31 | -+----+ -""" - - def test_listing(self): - expected = [{'ID': '11'}, {'ID': '21'}, {'ID': '31'}] - actual = output_parser.listing(self.LISTING_OUTPUT) - self.assertIsInstance(actual, list) - self.assertEqual(expected, actual) - - def test_details_multiple_with_invalid_line(self): - self.assertRaises(exceptions.InvalidStructure, - output_parser.details_multiple, - self.OUTPUT_LINES) - - DETAILS_LINES1 = """First Table -+----------+--------+ -| Property | Value | -+----------+--------+ -| foo | BUILD | -| bar | ERROR | -| bee | None | -+----------+--------+ -""" - DETAILS_LINES2 = """Second Table -+----------+--------+ -| Property | Value | -+----------+--------+ -| aaa | VVVVV | -| bbb | WWWWW | -| ccc | XXXXX | -+----------+--------+ -""" - - def test_details_with_normal_line_label_false(self): - expected = {'foo': 'BUILD', 'bar': 'ERROR', 'bee': 'None'} - actual = output_parser.details(self.DETAILS_LINES1) - self.assertEqual(expected, actual) - - def test_details_with_normal_line_label_true(self): - expected = {'__label': 'First Table', - 'foo': 'BUILD', 'bar': 'ERROR', 'bee': 'None'} - actual = output_parser.details(self.DETAILS_LINES1, with_label=True) - self.assertEqual(expected, actual) - - def test_details_multiple_with_normal_line_label_false(self): - expected = [{'foo': 'BUILD', 'bar': 'ERROR', 'bee': 'None'}, - {'aaa': 'VVVVV', 'bbb': 'WWWWW', 'ccc': 'XXXXX'}] - actual = output_parser.details_multiple(self.DETAILS_LINES1 + - self.DETAILS_LINES2) - self.assertIsInstance(actual, list) - self.assertEqual(expected, actual) - - def test_details_multiple_with_normal_line_label_true(self): - expected = [{'__label': 'First Table', - 'foo': 'BUILD', 'bar': 'ERROR', 'bee': 'None'}, - {'__label': 'Second Table', - 'aaa': 'VVVVV', 'bbb': 'WWWWW', 'ccc': 'XXXXX'}] - actual = output_parser.details_multiple(self.DETAILS_LINES1 + - self.DETAILS_LINES2, - with_label=True) - self.assertIsInstance(actual, list) - self.assertEqual(expected, actual) diff --git a/tempest/tests/lib/common/__init__.py b/tempest/tests/lib/common/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/common/test_api_version_request.py b/tempest/tests/lib/common/test_api_version_request.py deleted file mode 100644 index 58e7040bb..000000000 --- a/tempest/tests/lib/common/test_api_version_request.py +++ /dev/null @@ -1,146 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# 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 tempest.lib.common import api_version_request -from tempest.lib import exceptions -from tempest.tests import base - - -class APIVersionRequestTests(base.TestCase): - def test_valid_version_strings(self): - def _test_string(version, exp_major, exp_minor): - v = api_version_request.APIVersionRequest(version) - self.assertEqual(v.ver_major, exp_major) - self.assertEqual(v.ver_minor, exp_minor) - - _test_string("1.1", 1, 1) - _test_string("2.10", 2, 10) - _test_string("5.234", 5, 234) - _test_string("12.5", 12, 5) - _test_string("2.0", 2, 0) - _test_string("2.200", 2, 200) - - def test_null_version(self): - v = api_version_request.APIVersionRequest() - self.assertTrue(v.is_null()) - - def test_invalid_version_strings(self): - self.assertRaises(exceptions.InvalidAPIVersionString, - api_version_request.APIVersionRequest, "2") - - self.assertRaises(exceptions.InvalidAPIVersionString, - api_version_request.APIVersionRequest, "200") - - self.assertRaises(exceptions.InvalidAPIVersionString, - api_version_request.APIVersionRequest, "2.1.4") - - self.assertRaises(exceptions.InvalidAPIVersionString, - api_version_request.APIVersionRequest, "200.23.66.3") - - self.assertRaises(exceptions.InvalidAPIVersionString, - api_version_request.APIVersionRequest, "5 .3") - - self.assertRaises(exceptions.InvalidAPIVersionString, - api_version_request.APIVersionRequest, "5. 3") - - self.assertRaises(exceptions.InvalidAPIVersionString, - api_version_request.APIVersionRequest, "5.03") - - self.assertRaises(exceptions.InvalidAPIVersionString, - api_version_request.APIVersionRequest, "02.1") - - self.assertRaises(exceptions.InvalidAPIVersionString, - api_version_request.APIVersionRequest, "2.001") - - self.assertRaises(exceptions.InvalidAPIVersionString, - api_version_request.APIVersionRequest, "") - - self.assertRaises(exceptions.InvalidAPIVersionString, - api_version_request.APIVersionRequest, " 2.1") - - self.assertRaises(exceptions.InvalidAPIVersionString, - api_version_request.APIVersionRequest, "2.1 ") - - def test_version_comparisons(self): - vers2_0 = api_version_request.APIVersionRequest("2.0") - vers2_5 = api_version_request.APIVersionRequest("2.5") - vers5_23 = api_version_request.APIVersionRequest("5.23") - v_null = api_version_request.APIVersionRequest() - v_latest = api_version_request.APIVersionRequest('latest') - - self.assertTrue(v_null < vers2_5) - self.assertTrue(vers2_0 < vers2_5) - self.assertTrue(vers2_0 <= vers2_5) - self.assertTrue(vers2_0 <= vers2_0) - self.assertTrue(vers2_5 > v_null) - self.assertTrue(vers5_23 > vers2_5) - self.assertTrue(vers2_0 >= vers2_0) - self.assertTrue(vers5_23 >= vers2_5) - self.assertTrue(vers2_0 != vers2_5) - self.assertTrue(vers2_0 == vers2_0) - self.assertTrue(vers2_0 != v_null) - self.assertTrue(v_null == v_null) - self.assertTrue(vers2_0 <= v_latest) - self.assertTrue(vers2_0 != v_latest) - self.assertTrue(v_latest == v_latest) - self.assertRaises(TypeError, vers2_0.__lt__, "2.1") - - def test_version_matches(self): - vers2_0 = api_version_request.APIVersionRequest("2.0") - vers2_5 = api_version_request.APIVersionRequest("2.5") - vers2_45 = api_version_request.APIVersionRequest("2.45") - vers3_3 = api_version_request.APIVersionRequest("3.3") - vers3_23 = api_version_request.APIVersionRequest("3.23") - vers4_0 = api_version_request.APIVersionRequest("4.0") - v_null = api_version_request.APIVersionRequest() - v_latest = api_version_request.APIVersionRequest('latest') - - def _check_version_matches(version, version1, version2, check=True): - if check: - msg = "Version %s does not matches with [%s - %s] range" - self.assertTrue(version.matches(version1, version2), - msg % (version.get_string(), - version1.get_string(), - version2.get_string())) - else: - msg = "Version %s matches with [%s - %s] range" - self.assertFalse(version.matches(version1, version2), - msg % (version.get_string(), - version1.get_string(), - version2.get_string())) - - _check_version_matches(vers2_5, vers2_0, vers2_45) - _check_version_matches(vers2_5, vers2_0, v_null) - _check_version_matches(vers2_0, vers2_0, vers2_5) - _check_version_matches(vers3_3, vers2_5, vers3_3) - _check_version_matches(vers3_3, v_null, vers3_3) - _check_version_matches(vers3_3, v_null, vers4_0) - _check_version_matches(vers2_0, vers2_5, vers2_45, False) - _check_version_matches(vers3_23, vers2_5, vers3_3, False) - _check_version_matches(vers2_5, vers2_45, vers2_0, False) - _check_version_matches(vers2_5, vers2_0, v_latest) - _check_version_matches(v_latest, v_latest, v_latest) - _check_version_matches(vers2_5, v_latest, v_latest, False) - _check_version_matches(v_latest, vers2_0, vers4_0, False) - - self.assertRaises(ValueError, v_null.matches, vers2_0, vers2_45) - - def test_get_string(self): - vers_string = ["3.23", "latest"] - for ver in vers_string: - ver_obj = api_version_request.APIVersionRequest(ver) - self.assertEqual(ver, ver_obj.get_string()) - - self.assertIsNotNone( - api_version_request.APIVersionRequest().get_string) diff --git a/tempest/tests/lib/common/test_api_version_utils.py b/tempest/tests/lib/common/test_api_version_utils.py deleted file mode 100644 index 6206379d3..000000000 --- a/tempest/tests/lib/common/test_api_version_utils.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 testtools - -from tempest.lib.common import api_version_utils -from tempest.lib import exceptions -from tempest.tests import base - - -class TestVersionSkipLogic(base.TestCase): - - def _test_version(self, test_min_version, test_max_version, - cfg_min_version, cfg_max_version, expected_skip=False): - try: - api_version_utils.check_skip_with_microversion(test_min_version, - test_max_version, - cfg_min_version, - cfg_max_version) - except testtools.TestCase.skipException as e: - if not expected_skip: - raise testtools.TestCase.failureException(e.message) - - def test_version_min_in_range(self): - self._test_version('2.2', '2.10', '2.1', '2.7') - - def test_version_max_in_range(self): - self._test_version('2.1', '2.3', '2.2', '2.7') - - def test_version_cfg_in_range(self): - self._test_version('2.2', '2.9', '2.3', '2.7') - - def test_version_equal(self): - self._test_version('2.2', '2.2', '2.2', '2.2') - - def test_version_below_cfg_min(self): - self._test_version('2.2', '2.4', '2.5', '2.7', expected_skip=True) - - def test_version_above_cfg_max(self): - self._test_version('2.8', '2.9', '2.3', '2.7', expected_skip=True) - - def test_version_min_greater_than_max(self): - self.assertRaises(exceptions.InvalidAPIVersionRange, - self._test_version, '2.8', '2.7', '2.3', '2.7') - - def test_cfg_version_min_greater_than_max(self): - self.assertRaises(exceptions.InvalidAPIVersionRange, - self._test_version, '2.2', '2.7', '2.9', '2.7') - - -class TestSelectRequestMicroversion(base.TestCase): - - def _test_request_version(self, test_min_version, - cfg_min_version, expected_version): - selected_version = api_version_utils.select_request_microversion( - test_min_version, cfg_min_version) - self.assertEqual(expected_version, selected_version) - - def test_cfg_min_version_greater(self): - self._test_request_version('2.1', '2.3', expected_version='2.3') - - def test_class_min_version_greater(self): - self._test_request_version('2.5', '2.3', expected_version='2.5') - - def test_cfg_min_version_none(self): - self._test_request_version('2.5', None, expected_version='2.5') - - def test_class_min_version_none(self): - self._test_request_version(None, '2.3', expected_version='2.3') - - def test_both_min_version_none(self): - self._test_request_version(None, None, expected_version=None) - - def test_both_min_version_equal(self): - self._test_request_version('2.3', '2.3', expected_version='2.3') - - -class TestMicroversionHeaderMatches(base.TestCase): - - def test_header_matches(self): - microversion_header_name = 'x-openstack-xyz-api-version' - request_microversion = '2.1' - test_respose = {microversion_header_name: request_microversion} - api_version_utils.assert_version_header_matches_request( - microversion_header_name, request_microversion, test_respose) - - def test_header_does_not_match(self): - microversion_header_name = 'x-openstack-xyz-api-version' - request_microversion = '2.1' - test_respose = {microversion_header_name: '2.2'} - self.assertRaises( - exceptions.InvalidHTTPResponseHeader, - api_version_utils.assert_version_header_matches_request, - microversion_header_name, request_microversion, test_respose) - - def test_header_not_present(self): - microversion_header_name = 'x-openstack-xyz-api-version' - request_microversion = '2.1' - test_respose = {} - self.assertRaises( - exceptions.InvalidHTTPResponseHeader, - api_version_utils.assert_version_header_matches_request, - microversion_header_name, request_microversion, test_respose) diff --git a/tempest/tests/lib/common/test_cred_client.py b/tempest/tests/lib/common/test_cred_client.py deleted file mode 100644 index 3dff16fba..000000000 --- a/tempest/tests/lib/common/test_cred_client.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright 2016 Hewlett Packard Enterprise Development LP -# 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 mock - -from tempest.lib.common import cred_client -from tempest.tests import base - - -class TestCredClientV2(base.TestCase): - def setUp(self): - super(TestCredClientV2, self).setUp() - self.identity_client = mock.MagicMock() - self.projects_client = mock.MagicMock() - self.users_client = mock.MagicMock() - self.roles_client = mock.MagicMock() - self.creds_client = cred_client.V2CredsClient(self.identity_client, - self.projects_client, - self.users_client, - self.roles_client) - - def test_create_project(self): - self.projects_client.create_tenant.return_value = { - 'tenant': 'a_tenant' - } - res = self.creds_client.create_project('fake_name', 'desc') - self.assertEqual('a_tenant', res) - self.projects_client.create_tenant.assert_called_once_with( - name='fake_name', description='desc') - - def test_delete_project(self): - self.creds_client.delete_project('fake_id') - self.projects_client.delete_tenant.assert_called_once_with( - 'fake_id') - - -class TestCredClientV3(base.TestCase): - def setUp(self): - super(TestCredClientV3, self).setUp() - self.identity_client = mock.MagicMock() - self.projects_client = mock.MagicMock() - self.users_client = mock.MagicMock() - self.roles_client = mock.MagicMock() - self.domains_client = mock.MagicMock() - self.domains_client.list_domains.return_value = { - 'domains': [{'id': 'fake_domain_id'}] - } - self.creds_client = cred_client.V3CredsClient(self.identity_client, - self.projects_client, - self.users_client, - self.roles_client, - self.domains_client, - 'fake_domain') - - def test_create_project(self): - self.projects_client.create_project.return_value = { - 'project': 'a_tenant' - } - res = self.creds_client.create_project('fake_name', 'desc') - self.assertEqual('a_tenant', res) - self.projects_client.create_project.assert_called_once_with( - name='fake_name', description='desc', domain_id='fake_domain_id') - - def test_delete_project(self): - self.creds_client.delete_project('fake_id') - self.projects_client.delete_project.assert_called_once_with( - 'fake_id') diff --git a/tempest/tests/lib/common/test_dynamic_creds.py b/tempest/tests/lib/common/test_dynamic_creds.py deleted file mode 100644 index 6aa7a4270..000000000 --- a/tempest/tests/lib/common/test_dynamic_creds.py +++ /dev/null @@ -1,667 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# 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 fixtures -import mock -from oslo_config import cfg - -from tempest.common import credentials_factory as credentials -from tempest import config -from tempest.lib.common import dynamic_creds -from tempest.lib.common import rest_client -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.identity.v2 import identity_client as v2_iden_client -from tempest.lib.services.identity.v2 import roles_client as v2_roles_client -from tempest.lib.services.identity.v2 import tenants_client as \ - v2_tenants_client -from tempest.lib.services.identity.v2 import token_client as v2_token_client -from tempest.lib.services.identity.v2 import users_client as v2_users_client -from tempest.lib.services.identity.v3 import domains_client -from tempest.lib.services.identity.v3 import identity_client as v3_iden_client -from tempest.lib.services.identity.v3 import projects_client as \ - v3_projects_client -from tempest.lib.services.identity.v3 import roles_client as v3_roles_client -from tempest.lib.services.identity.v3 import token_client as v3_token_client -from tempest.lib.services.identity.v3 import users_client as \ - v3_users_client -from tempest.lib.services.network import routers_client -from tempest.tests import base -from tempest.tests import fake_config -from tempest.tests.lib import fake_http -from tempest.tests.lib import fake_identity - - -class TestDynamicCredentialProvider(base.TestCase): - - fixed_params = {'name': 'test class', - 'identity_version': 'v2', - 'admin_role': 'admin', - 'identity_uri': 'fake_uri'} - - token_client = v2_token_client - iden_client = v2_iden_client - roles_client = v2_roles_client - tenants_client = v2_tenants_client - users_client = v2_users_client - token_client_class = token_client.TokenClient - fake_response = fake_identity._fake_v2_response - tenants_client_class = tenants_client.TenantsClient - delete_tenant = 'delete_tenant' - - def setUp(self): - super(TestDynamicCredentialProvider, self).setUp() - self.useFixture(fake_config.ConfigFixture()) - self.patchobject(config, 'TempestConfigPrivate', - fake_config.FakePrivate) - self.patchobject(self.token_client_class, 'raw_request', - self.fake_response) - cfg.CONF.set_default('operator_role', 'FakeRole', - group='object-storage') - self._mock_list_ec2_credentials('fake_user_id', 'fake_tenant_id') - self.fixed_params.update( - admin_creds=self._get_fake_admin_creds()) - - def test_tempest_client(self): - creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params) - self.assertIsInstance(creds.identity_admin_client, - self.iden_client.IdentityClient) - - def _get_fake_admin_creds(self): - return credentials.get_credentials( - fill_in=False, - identity_version=self.fixed_params['identity_version'], - username='fake_username', password='fake_password', - tenant_name='fake_tenant') - - def _mock_user_create(self, id, name): - user_fix = self.useFixture(fixtures.MockPatchObject( - self.users_client.UsersClient, - 'create_user', - return_value=(rest_client.ResponseBody - (200, {'user': {'id': id, 'name': name}})))) - return user_fix - - def _mock_tenant_create(self, id, name): - tenant_fix = self.useFixture(fixtures.MockPatchObject( - self.tenants_client.TenantsClient, - 'create_tenant', - return_value=(rest_client.ResponseBody - (200, {'tenant': {'id': id, 'name': name}})))) - return tenant_fix - - def _mock_list_roles(self, id, name): - roles_fix = self.useFixture(fixtures.MockPatchObject( - self.roles_client.RolesClient, - 'list_roles', - return_value=(rest_client.ResponseBody - (200, - {'roles': [{'id': id, 'name': name}, - {'id': '1', 'name': 'FakeRole'}, - {'id': '2', 'name': 'Member'}]})))) - return roles_fix - - def _mock_list_2_roles(self): - roles_fix = self.useFixture(fixtures.MockPatchObject( - self.roles_client.RolesClient, - 'list_roles', - return_value=(rest_client.ResponseBody - (200, - {'roles': [{'id': '1234', 'name': 'role1'}, - {'id': '1', 'name': 'FakeRole'}, - {'id': '12345', 'name': 'role2'}]})))) - return roles_fix - - def _mock_assign_user_role(self): - tenant_fix = self.useFixture(fixtures.MockPatchObject( - self.roles_client.RolesClient, - 'create_user_role_on_project', - return_value=(rest_client.ResponseBody - (200, {})))) - return tenant_fix - - def _mock_list_role(self): - roles_fix = self.useFixture(fixtures.MockPatchObject( - self.roles_client.RolesClient, - 'list_roles', - return_value=(rest_client.ResponseBody - (200, {'roles': [ - {'id': '1', 'name': 'FakeRole'}, - {'id': '2', 'name': 'Member'}]})))) - return roles_fix - - def _mock_list_ec2_credentials(self, user_id, tenant_id): - ec2_creds_fix = self.useFixture(fixtures.MockPatchObject( - self.users_client.UsersClient, - 'list_user_ec2_credentials', - return_value=(rest_client.ResponseBody - (200, {'credentials': [{ - 'access': 'fake_access', - 'secret': 'fake_secret', - 'tenant_id': tenant_id, - 'user_id': user_id, - 'trust_id': None}]})))) - return ec2_creds_fix - - def _mock_network_create(self, iso_creds, id, name): - net_fix = self.useFixture(fixtures.MockPatchObject( - iso_creds.networks_admin_client, - 'create_network', - return_value={'network': {'id': id, 'name': name}})) - return net_fix - - def _mock_subnet_create(self, iso_creds, id, name): - subnet_fix = self.useFixture(fixtures.MockPatchObject( - iso_creds.subnets_admin_client, - 'create_subnet', - return_value={'subnet': {'id': id, 'name': name}})) - return subnet_fix - - def _mock_router_create(self, id, name): - router_fix = self.useFixture(fixtures.MockPatchObject( - routers_client.RoutersClient, - 'create_router', - return_value={'router': {'id': id, 'name': name}})) - return router_fix - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_primary_creds(self, MockRestClient): - creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params) - self._mock_assign_user_role() - self._mock_list_role() - self._mock_tenant_create('1234', 'fake_prim_tenant') - self._mock_user_create('1234', 'fake_prim_user') - primary_creds = creds.get_primary_creds() - self.assertEqual(primary_creds.username, 'fake_prim_user') - self.assertEqual(primary_creds.tenant_name, 'fake_prim_tenant') - # Verify IDs - self.assertEqual(primary_creds.tenant_id, '1234') - self.assertEqual(primary_creds.user_id, '1234') - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_admin_creds(self, MockRestClient): - creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params) - self._mock_list_roles('1234', 'admin') - self._mock_user_create('1234', 'fake_admin_user') - self._mock_tenant_create('1234', 'fake_admin_tenant') - - user_mock = mock.patch.object(self.roles_client.RolesClient, - 'create_user_role_on_project') - user_mock.start() - self.addCleanup(user_mock.stop) - with mock.patch.object(self.roles_client.RolesClient, - 'create_user_role_on_project') as user_mock: - admin_creds = creds.get_admin_creds() - user_mock.assert_has_calls([ - mock.call('1234', '1234', '1234')]) - self.assertEqual(admin_creds.username, 'fake_admin_user') - self.assertEqual(admin_creds.tenant_name, 'fake_admin_tenant') - # Verify IDs - self.assertEqual(admin_creds.tenant_id, '1234') - self.assertEqual(admin_creds.user_id, '1234') - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_role_creds(self, MockRestClient): - creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params) - self._mock_list_2_roles() - self._mock_user_create('1234', 'fake_role_user') - self._mock_tenant_create('1234', 'fake_role_tenant') - - user_mock = mock.patch.object(self.roles_client.RolesClient, - 'create_user_role_on_project') - user_mock.start() - self.addCleanup(user_mock.stop) - with mock.patch.object(self.roles_client.RolesClient, - 'create_user_role_on_project') as user_mock: - role_creds = creds.get_creds_by_roles( - roles=['role1', 'role2']) - calls = user_mock.mock_calls - # Assert that the role creation is called with the 2 specified roles - self.assertEqual(len(calls), 2) - args = map(lambda x: x[1], calls) - args = list(args) - self.assertIn(('1234', '1234', '1234'), args) - self.assertIn(('1234', '1234', '12345'), args) - self.assertEqual(role_creds.username, 'fake_role_user') - self.assertEqual(role_creds.tenant_name, 'fake_role_tenant') - # Verify IDs - self.assertEqual(role_creds.tenant_id, '1234') - self.assertEqual(role_creds.user_id, '1234') - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_all_cred_cleanup(self, MockRestClient): - creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params) - self._mock_assign_user_role() - self._mock_list_role() - self._mock_tenant_create('1234', 'fake_prim_tenant') - self._mock_user_create('1234', 'fake_prim_user') - creds.get_primary_creds() - self._mock_tenant_create('12345', 'fake_alt_tenant') - self._mock_user_create('12345', 'fake_alt_user') - creds.get_alt_creds() - self._mock_tenant_create('123456', 'fake_admin_tenant') - self._mock_user_create('123456', 'fake_admin_user') - self._mock_list_roles('123456', 'admin') - creds.get_admin_creds() - user_mock = self.patchobject(self.users_client.UsersClient, - 'delete_user') - tenant_mock = self.patchobject(self.tenants_client_class, - self.delete_tenant) - creds.clear_creds() - # Verify user delete calls - calls = user_mock.mock_calls - self.assertEqual(len(calls), 3) - args = map(lambda x: x[1][0], calls) - args = list(args) - self.assertIn('1234', args) - self.assertIn('12345', args) - self.assertIn('123456', args) - # Verify tenant delete calls - calls = tenant_mock.mock_calls - self.assertEqual(len(calls), 3) - args = map(lambda x: x[1][0], calls) - args = list(args) - self.assertIn('1234', args) - self.assertIn('12345', args) - self.assertIn('123456', args) - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_alt_creds(self, MockRestClient): - creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params) - self._mock_assign_user_role() - self._mock_list_role() - self._mock_user_create('1234', 'fake_alt_user') - self._mock_tenant_create('1234', 'fake_alt_tenant') - alt_creds = creds.get_alt_creds() - self.assertEqual(alt_creds.username, 'fake_alt_user') - self.assertEqual(alt_creds.tenant_name, 'fake_alt_tenant') - # Verify IDs - self.assertEqual(alt_creds.tenant_id, '1234') - self.assertEqual(alt_creds.user_id, '1234') - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_no_network_creation_with_config_set(self, MockRestClient): - creds = dynamic_creds.DynamicCredentialProvider( - neutron_available=True, create_networks=False, - project_network_cidr='10.100.0.0/16', project_network_mask_bits=28, - **self.fixed_params) - self._mock_assign_user_role() - self._mock_list_role() - self._mock_user_create('1234', 'fake_prim_user') - self._mock_tenant_create('1234', 'fake_prim_tenant') - net = mock.patch.object(creds.networks_admin_client, - 'delete_network') - net_mock = net.start() - subnet = mock.patch.object(creds.subnets_admin_client, - 'delete_subnet') - subnet_mock = subnet.start() - router = mock.patch.object(creds.routers_admin_client, - 'delete_router') - router_mock = router.start() - - primary_creds = creds.get_primary_creds() - self.assertEqual(net_mock.mock_calls, []) - self.assertEqual(subnet_mock.mock_calls, []) - self.assertEqual(router_mock.mock_calls, []) - network = primary_creds.network - subnet = primary_creds.subnet - router = primary_creds.router - self.assertIsNone(network) - self.assertIsNone(subnet) - self.assertIsNone(router) - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_network_creation(self, MockRestClient): - creds = dynamic_creds.DynamicCredentialProvider( - neutron_available=True, - project_network_cidr='10.100.0.0/16', project_network_mask_bits=28, - **self.fixed_params) - self._mock_assign_user_role() - self._mock_list_role() - self._mock_user_create('1234', 'fake_prim_user') - self._mock_tenant_create('1234', 'fake_prim_tenant') - self._mock_network_create(creds, '1234', 'fake_net') - self._mock_subnet_create(creds, '1234', 'fake_subnet') - self._mock_router_create('1234', 'fake_router') - router_interface_mock = self.patch( - 'tempest.lib.services.network.routers_client.RoutersClient.' - 'add_router_interface') - primary_creds = creds.get_primary_creds() - router_interface_mock.assert_called_once_with('1234', subnet_id='1234') - network = primary_creds.network - subnet = primary_creds.subnet - router = primary_creds.router - self.assertEqual(network['id'], '1234') - self.assertEqual(network['name'], 'fake_net') - self.assertEqual(subnet['id'], '1234') - self.assertEqual(subnet['name'], 'fake_subnet') - self.assertEqual(router['id'], '1234') - self.assertEqual(router['name'], 'fake_router') - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_network_cleanup(self, MockRestClient): - def side_effect(**args): - return {"security_groups": [{"tenant_id": args['tenant_id'], - "name": args['name'], - "description": args['name'], - "security_group_rules": [], - "id": "sg-%s" % args['tenant_id']}]} - creds = dynamic_creds.DynamicCredentialProvider( - neutron_available=True, - project_network_cidr='10.100.0.0/16', project_network_mask_bits=28, - **self.fixed_params) - # Create primary tenant and network - self._mock_assign_user_role() - self._mock_list_role() - self._mock_user_create('1234', 'fake_prim_user') - self._mock_tenant_create('1234', 'fake_prim_tenant') - self._mock_network_create(creds, '1234', 'fake_net') - self._mock_subnet_create(creds, '1234', 'fake_subnet') - self._mock_router_create('1234', 'fake_router') - router_interface_mock = self.patch( - 'tempest.lib.services.network.routers_client.RoutersClient.' - 'add_router_interface') - creds.get_primary_creds() - router_interface_mock.assert_called_once_with('1234', subnet_id='1234') - router_interface_mock.reset_mock() - # Create alternate tenant and network - self._mock_user_create('12345', 'fake_alt_user') - self._mock_tenant_create('12345', 'fake_alt_tenant') - self._mock_network_create(creds, '12345', 'fake_alt_net') - self._mock_subnet_create(creds, '12345', 'fake_alt_subnet') - self._mock_router_create('12345', 'fake_alt_router') - creds.get_alt_creds() - router_interface_mock.assert_called_once_with('12345', - subnet_id='12345') - router_interface_mock.reset_mock() - # Create admin tenant and networks - self._mock_user_create('123456', 'fake_admin_user') - self._mock_tenant_create('123456', 'fake_admin_tenant') - self._mock_network_create(creds, '123456', 'fake_admin_net') - self._mock_subnet_create(creds, '123456', 'fake_admin_subnet') - self._mock_router_create('123456', 'fake_admin_router') - self._mock_list_roles('123456', 'admin') - creds.get_admin_creds() - self.patchobject(self.users_client.UsersClient, 'delete_user') - self.patchobject(self.tenants_client_class, self.delete_tenant) - net = mock.patch.object(creds.networks_admin_client, 'delete_network') - net_mock = net.start() - subnet = mock.patch.object(creds.subnets_admin_client, 'delete_subnet') - subnet_mock = subnet.start() - router = mock.patch.object(creds.routers_admin_client, 'delete_router') - router_mock = router.start() - remove_router_interface_mock = self.patch( - 'tempest.lib.services.network.routers_client.RoutersClient.' - 'remove_router_interface') - return_values = ({'status': 200}, {'ports': []}) - port_list_mock = mock.patch.object(creds.ports_admin_client, - 'list_ports', - return_value=return_values) - - port_list_mock.start() - secgroup_list_mock = mock.patch.object( - creds.security_groups_admin_client, - 'list_security_groups', - side_effect=side_effect) - secgroup_list_mock.start() - - return_values = fake_http.fake_http_response({}, status=204), '' - remove_secgroup_mock = self.patch( - 'tempest.lib.services.network.security_groups_client.' - 'SecurityGroupsClient.delete', return_value=return_values) - creds.clear_creds() - # Verify default security group delete - calls = remove_secgroup_mock.mock_calls - self.assertEqual(len(calls), 3) - args = map(lambda x: x[1][0], calls) - args = list(args) - self.assertIn('v2.0/security-groups/sg-1234', args) - self.assertIn('v2.0/security-groups/sg-12345', args) - self.assertIn('v2.0/security-groups/sg-123456', args) - # Verify remove router interface calls - calls = remove_router_interface_mock.mock_calls - self.assertEqual(len(calls), 3) - args = map(lambda x: (x[1][0], x[2]), calls) - args = list(args) - self.assertIn(('1234', {'subnet_id': '1234'}), args) - self.assertIn(('12345', {'subnet_id': '12345'}), args) - self.assertIn(('123456', {'subnet_id': '123456'}), args) - # Verify network delete calls - calls = net_mock.mock_calls - self.assertEqual(len(calls), 3) - args = map(lambda x: x[1][0], calls) - args = list(args) - self.assertIn('1234', args) - self.assertIn('12345', args) - self.assertIn('123456', args) - # Verify subnet delete calls - calls = subnet_mock.mock_calls - self.assertEqual(len(calls), 3) - args = map(lambda x: x[1][0], calls) - args = list(args) - self.assertIn('1234', args) - self.assertIn('12345', args) - self.assertIn('123456', args) - # Verify router delete calls - calls = router_mock.mock_calls - self.assertEqual(len(calls), 3) - args = map(lambda x: x[1][0], calls) - args = list(args) - self.assertIn('1234', args) - self.assertIn('12345', args) - self.assertIn('123456', args) - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_network_alt_creation(self, MockRestClient): - creds = dynamic_creds.DynamicCredentialProvider( - neutron_available=True, - project_network_cidr='10.100.0.0/16', project_network_mask_bits=28, - **self.fixed_params) - self._mock_assign_user_role() - self._mock_list_role() - self._mock_user_create('1234', 'fake_alt_user') - self._mock_tenant_create('1234', 'fake_alt_tenant') - self._mock_network_create(creds, '1234', 'fake_alt_net') - self._mock_subnet_create(creds, '1234', 'fake_alt_subnet') - self._mock_router_create('1234', 'fake_alt_router') - router_interface_mock = self.patch( - 'tempest.lib.services.network.routers_client.RoutersClient.' - 'add_router_interface') - alt_creds = creds.get_alt_creds() - router_interface_mock.assert_called_once_with('1234', subnet_id='1234') - network = alt_creds.network - subnet = alt_creds.subnet - router = alt_creds.router - self.assertEqual(network['id'], '1234') - self.assertEqual(network['name'], 'fake_alt_net') - self.assertEqual(subnet['id'], '1234') - self.assertEqual(subnet['name'], 'fake_alt_subnet') - self.assertEqual(router['id'], '1234') - self.assertEqual(router['name'], 'fake_alt_router') - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_network_admin_creation(self, MockRestClient): - creds = dynamic_creds.DynamicCredentialProvider( - neutron_available=True, - project_network_cidr='10.100.0.0/16', project_network_mask_bits=28, - **self.fixed_params) - self._mock_assign_user_role() - self._mock_user_create('1234', 'fake_admin_user') - self._mock_tenant_create('1234', 'fake_admin_tenant') - self._mock_network_create(creds, '1234', 'fake_admin_net') - self._mock_subnet_create(creds, '1234', 'fake_admin_subnet') - self._mock_router_create('1234', 'fake_admin_router') - router_interface_mock = self.patch( - 'tempest.lib.services.network.routers_client.RoutersClient.' - 'add_router_interface') - self._mock_list_roles('123456', 'admin') - admin_creds = creds.get_admin_creds() - router_interface_mock.assert_called_once_with('1234', subnet_id='1234') - network = admin_creds.network - subnet = admin_creds.subnet - router = admin_creds.router - self.assertEqual(network['id'], '1234') - self.assertEqual(network['name'], 'fake_admin_net') - self.assertEqual(subnet['id'], '1234') - self.assertEqual(subnet['name'], 'fake_admin_subnet') - self.assertEqual(router['id'], '1234') - self.assertEqual(router['name'], 'fake_admin_router') - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_no_network_resources(self, MockRestClient): - net_dict = { - 'network': False, - 'router': False, - 'subnet': False, - 'dhcp': False, - } - creds = dynamic_creds.DynamicCredentialProvider( - neutron_available=True, - project_network_cidr='10.100.0.0/16', project_network_mask_bits=28, - network_resources=net_dict, - **self.fixed_params) - self._mock_assign_user_role() - self._mock_list_role() - self._mock_user_create('1234', 'fake_prim_user') - self._mock_tenant_create('1234', 'fake_prim_tenant') - net = mock.patch.object(creds.networks_admin_client, - 'delete_network') - net_mock = net.start() - subnet = mock.patch.object(creds.subnets_admin_client, - 'delete_subnet') - subnet_mock = subnet.start() - router = mock.patch.object(creds.routers_admin_client, - 'delete_router') - router_mock = router.start() - - primary_creds = creds.get_primary_creds() - self.assertEqual(net_mock.mock_calls, []) - self.assertEqual(subnet_mock.mock_calls, []) - self.assertEqual(router_mock.mock_calls, []) - network = primary_creds.network - subnet = primary_creds.subnet - router = primary_creds.router - self.assertIsNone(network) - self.assertIsNone(subnet) - self.assertIsNone(router) - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_router_without_network(self, MockRestClient): - net_dict = { - 'network': False, - 'router': True, - 'subnet': False, - 'dhcp': False, - } - creds = dynamic_creds.DynamicCredentialProvider( - neutron_available=True, - project_network_cidr='10.100.0.0/16', project_network_mask_bits=28, - network_resources=net_dict, - **self.fixed_params) - self._mock_assign_user_role() - self._mock_list_role() - self._mock_user_create('1234', 'fake_prim_user') - self._mock_tenant_create('1234', 'fake_prim_tenant') - self.assertRaises(lib_exc.InvalidConfiguration, - creds.get_primary_creds) - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_subnet_without_network(self, MockRestClient): - net_dict = { - 'network': False, - 'router': False, - 'subnet': True, - 'dhcp': False, - } - creds = dynamic_creds.DynamicCredentialProvider( - neutron_available=True, - project_network_cidr='10.100.0.0/16', project_network_mask_bits=28, - network_resources=net_dict, - **self.fixed_params) - self._mock_assign_user_role() - self._mock_list_role() - self._mock_user_create('1234', 'fake_prim_user') - self._mock_tenant_create('1234', 'fake_prim_tenant') - self.assertRaises(lib_exc.InvalidConfiguration, - creds.get_primary_creds) - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_dhcp_without_subnet(self, MockRestClient): - net_dict = { - 'network': False, - 'router': False, - 'subnet': False, - 'dhcp': True, - } - creds = dynamic_creds.DynamicCredentialProvider( - neutron_available=True, - project_network_cidr='10.100.0.0/16', project_network_mask_bits=28, - network_resources=net_dict, - **self.fixed_params) - self._mock_assign_user_role() - self._mock_list_role() - self._mock_user_create('1234', 'fake_prim_user') - self._mock_tenant_create('1234', 'fake_prim_tenant') - self.assertRaises(lib_exc.InvalidConfiguration, - creds.get_primary_creds) - - -class TestDynamicCredentialProviderV3(TestDynamicCredentialProvider): - - fixed_params = {'name': 'test class', - 'identity_version': 'v3', - 'admin_role': 'admin', - 'identity_uri': 'fake_uri'} - - token_client = v3_token_client - iden_client = v3_iden_client - roles_client = v3_roles_client - tenants_client = v3_projects_client - users_client = v3_users_client - token_client_class = token_client.V3TokenClient - fake_response = fake_identity._fake_v3_response - tenants_client_class = tenants_client.ProjectsClient - delete_tenant = 'delete_project' - - def setUp(self): - super(TestDynamicCredentialProviderV3, self).setUp() - self.useFixture(fake_config.ConfigFixture()) - self.useFixture(fixtures.MockPatchObject( - domains_client.DomainsClient, 'list_domains', - return_value=dict(domains=[dict(id='default', - name='Default')]))) - self.patchobject(self.roles_client.RolesClient, - 'create_user_role_on_domain') - - def _mock_list_ec2_credentials(self, user_id, tenant_id): - pass - - def _mock_tenant_create(self, id, name): - project_fix = self.useFixture(fixtures.MockPatchObject( - self.tenants_client.ProjectsClient, - 'create_project', - return_value=(rest_client.ResponseBody - (200, {'project': {'id': id, 'name': name}})))) - return project_fix - - @mock.patch('tempest.lib.common.rest_client.RestClient') - def test_member_role_creation_with_duplicate(self, rest_client_mock): - creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params) - creds.creds_client = mock.MagicMock() - creds.creds_client.create_user_role.side_effect = lib_exc.Conflict - with mock.patch('tempest.lib.common.dynamic_creds.LOG') as log_mock: - creds._create_creds() - log_mock.warning.assert_called_once_with( - "Member role already exists, ignoring conflict.") - creds.creds_client.assign_user_role.assert_called_once_with( - mock.ANY, mock.ANY, 'Member') diff --git a/tempest/tests/lib/common/test_jsonschema_validator.py b/tempest/tests/lib/common/test_jsonschema_validator.py deleted file mode 100644 index 8694f3d01..000000000 --- a/tempest/tests/lib/common/test_jsonschema_validator.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.lib.api_schema.response.compute.v2_1 import parameter_types -from tempest.lib.common import rest_client -from tempest.lib import exceptions -from tempest.tests import base -from tempest.tests.lib import fake_http - - -class TestJSONSchemaDateTimeFormat(base.TestCase): - date_time_schema = [ - { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'date-time': parameter_types.date_time - } - } - }, - { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'date-time': parameter_types.date_time_or_null - } - } - } - ] - - def test_valid_date_time_format(self): - valid_instances = ['2016-10-02T10:00:00-05:00', - '2016-10-02T10:00:00+09:00', - '2016-10-02T15:00:00Z', - '2016-10-02T15:00:00.05Z'] - resp = fake_http.fake_http_response('', status=200) - for instance in valid_instances: - body = {'date-time': instance} - for schema in self.date_time_schema: - rest_client.RestClient.validate_response(schema, resp, body) - - def test_invalid_date_time_format(self): - invalid_instances = ['2016-10-02 T10:00:00-05:00', - '2016-10-02T 15:00:00', - '2016-10-02T15:00:00.05 Z', - '2016-10-02:15:00:00.05Z', - 'T15:00:00.05Z', - '2016:10:02T15:00:00', - '2016-10-02T15-00-00', - '2016-10-02T15.05Z', - '09MAR2015 11:15', - '13 Oct 2015 05:55:36 GMT', - ''] - resp = fake_http.fake_http_response('', status=200) - for instance in invalid_instances: - body = {'date-time': instance} - for schema in self.date_time_schema: - self.assertRaises(exceptions.InvalidHTTPResponseBody, - rest_client.RestClient.validate_response, - schema, resp, body) - - def test_date_time_or_null_format(self): - instance = None - resp = fake_http.fake_http_response('', status=200) - body = {'date-time': instance} - rest_client.RestClient.validate_response(self.date_time_schema[1], - resp, body) - self.assertRaises(exceptions.InvalidHTTPResponseBody, - rest_client.RestClient.validate_response, - self.date_time_schema[0], resp, body) diff --git a/tempest/tests/lib/common/test_preprov_creds.py b/tempest/tests/lib/common/test_preprov_creds.py deleted file mode 100644 index 5402e470d..000000000 --- a/tempest/tests/lib/common/test_preprov_creds.py +++ /dev/null @@ -1,487 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P. -# -# 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 hashlib -import os -import shutil - -import mock -import six -import testtools - -import fixtures -from oslo_concurrency.fixture import lockutils as lockutils_fixtures -from oslo_config import cfg - -from tempest import config -from tempest.lib import auth -from tempest.lib.common import cred_provider -from tempest.lib.common import preprov_creds -from tempest.lib import exceptions as lib_exc -from tempest.tests import base -from tempest.tests import fake_config -from tempest.tests.lib import fake_identity - - -class TestPreProvisionedCredentials(base.TestCase): - - fixed_params = {'name': 'test class', - 'identity_version': 'v2', - 'identity_uri': 'fake_uri', - 'test_accounts_file': 'fake_accounts_file', - 'accounts_lock_dir': 'fake_locks_dir', - 'admin_role': 'admin', - 'object_storage_operator_role': 'operator', - 'object_storage_reseller_admin_role': 'reseller'} - - identity_response = fake_identity._fake_v2_response - token_client = ('tempest.lib.services.identity.v2.token_client' - '.TokenClient.raw_request') - - @classmethod - def _fake_accounts(cls, admin_role): - return [ - {'username': 'test_user1', 'tenant_name': 'test_tenant1', - 'password': 'p'}, - {'username': 'test_user2', 'project_name': 'test_tenant2', - 'password': 'p'}, - {'username': 'test_user3', 'tenant_name': 'test_tenant3', - 'password': 'p'}, - {'username': 'test_user4', 'project_name': 'test_tenant4', - 'password': 'p'}, - {'username': 'test_user5', 'tenant_name': 'test_tenant5', - 'password': 'p'}, - {'username': 'test_user6', 'project_name': 'test_tenant6', - 'password': 'p', 'roles': ['role1', 'role2']}, - {'username': 'test_user7', 'tenant_name': 'test_tenant7', - 'password': 'p', 'roles': ['role2', 'role3']}, - {'username': 'test_user8', 'project_name': 'test_tenant8', - 'password': 'p', 'roles': ['role4', 'role1']}, - {'username': 'test_user9', 'tenant_name': 'test_tenant9', - 'password': 'p', 'roles': ['role1', 'role2', 'role3', 'role4']}, - {'username': 'test_user10', 'project_name': 'test_tenant10', - 'password': 'p', 'roles': ['role1', 'role2', 'role3', 'role4']}, - {'username': 'test_admin1', 'tenant_name': 'test_tenant11', - 'password': 'p', 'roles': [admin_role]}, - {'username': 'test_admin2', 'project_name': 'test_tenant12', - 'password': 'p', 'roles': [admin_role]}, - {'username': 'test_admin3', 'project_name': 'test_tenant13', - 'password': 'p', 'types': ['admin']}] - - def setUp(self): - super(TestPreProvisionedCredentials, self).setUp() - self.useFixture(fake_config.ConfigFixture()) - self.patchobject(config, 'TempestConfigPrivate', - fake_config.FakePrivate) - self.patch(self.token_client, side_effect=self.identity_response) - self.useFixture(lockutils_fixtures.ExternalLockFixture()) - self.test_accounts = self._fake_accounts(cfg.CONF.identity.admin_role) - self.accounts_mock = self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.preprov_creds.read_accounts_yaml', - return_value=self.test_accounts)) - self.useFixture(fixtures.MockPatch( - 'os.path.isfile', return_value=True)) - # NOTE(andreaf) Ensure config is loaded so service clients are - # registered in the registry before tests - config.service_client_config() - - def tearDown(self): - super(TestPreProvisionedCredentials, self).tearDown() - shutil.rmtree(self.fixed_params['accounts_lock_dir'], - ignore_errors=True) - - def _get_hash_list(self, accounts_list): - hash_list = [] - hash_fields = ( - preprov_creds.PreProvisionedCredentialProvider.HASH_CRED_FIELDS) - for account in accounts_list: - hash = hashlib.md5() - account_for_hash = dict((k, v) for (k, v) in account.items() - if k in hash_fields) - hash.update(six.text_type(account_for_hash).encode('utf-8')) - temp_hash = hash.hexdigest() - hash_list.append(temp_hash) - return hash_list - - def test_get_hash(self): - # Test with all accounts to make sure we try all combinations - # and hide no race conditions - hash_index = 0 - for test_cred_dict in self.test_accounts: - test_account_class = ( - preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params)) - hash_list = self._get_hash_list(self.test_accounts) - test_creds = auth.get_credentials( - fake_identity.FAKE_AUTH_URL, - identity_version=self.fixed_params['identity_version'], - **test_cred_dict) - results = test_account_class.get_hash(test_creds) - self.assertEqual(hash_list[hash_index], results) - hash_index += 1 - - def test_get_hash_dict(self): - test_account_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - hash_dict = test_account_class.get_hash_dict( - self.test_accounts, self.fixed_params['admin_role']) - hash_list = self._get_hash_list(self.test_accounts) - for hash in hash_list: - self.assertIn(hash, hash_dict['creds'].keys()) - self.assertIn(hash_dict['creds'][hash], self.test_accounts) - - def test_create_hash_file_previous_file(self): - # Emulate the lock existing on the filesystem - self.useFixture(fixtures.MockPatch( - 'os.path.isfile', return_value=True)) - with mock.patch('six.moves.builtins.open', mock.mock_open(), - create=True): - test_account_class = ( - preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params)) - res = test_account_class._create_hash_file('12345') - self.assertFalse(res, "_create_hash_file should return False if the " - "pseudo-lock file already exists") - - def test_create_hash_file_no_previous_file(self): - # Emulate the lock not existing on the filesystem - self.useFixture(fixtures.MockPatch( - 'os.path.isfile', return_value=False)) - with mock.patch('six.moves.builtins.open', mock.mock_open(), - create=True): - test_account_class = ( - preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params)) - res = test_account_class._create_hash_file('12345') - self.assertTrue(res, "_create_hash_file should return True if the " - "pseudo-lock doesn't already exist") - - @mock.patch('oslo_concurrency.lockutils.lock') - def test_get_free_hash_no_previous_accounts(self, lock_mock): - # Emulate no pre-existing lock - self.useFixture(fixtures.MockPatch( - 'os.path.isdir', return_value=False)) - hash_list = self._get_hash_list(self.test_accounts) - mkdir_mock = self.useFixture(fixtures.MockPatch('os.mkdir')) - self.useFixture(fixtures.MockPatch( - 'os.path.isfile', return_value=False)) - test_account_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - with mock.patch('six.moves.builtins.open', mock.mock_open(), - create=True) as open_mock: - test_account_class._get_free_hash(hash_list) - lock_path = os.path.join(self.fixed_params['accounts_lock_dir'], - hash_list[0]) - open_mock.assert_called_once_with(lock_path, 'w') - mkdir_path = os.path.join(self.fixed_params['accounts_lock_dir']) - mkdir_mock.mock.assert_called_once_with(mkdir_path) - - @mock.patch('oslo_concurrency.lockutils.lock') - def test_get_free_hash_no_free_accounts(self, lock_mock): - hash_list = self._get_hash_list(self.test_accounts) - # Emulate pre-existing lock dir - self.useFixture(fixtures.MockPatch('os.path.isdir', return_value=True)) - # Emulate all locks in list are in use - self.useFixture(fixtures.MockPatch( - 'os.path.isfile', return_value=True)) - test_account_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - with mock.patch('six.moves.builtins.open', mock.mock_open(), - create=True): - self.assertRaises(lib_exc.InvalidCredentials, - test_account_class._get_free_hash, hash_list) - - @mock.patch('oslo_concurrency.lockutils.lock') - def test_get_free_hash_some_in_use_accounts(self, lock_mock): - # Emulate no pre-existing lock - self.useFixture(fixtures.MockPatch('os.path.isdir', return_value=True)) - hash_list = self._get_hash_list(self.test_accounts) - test_account_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - - def _fake_is_file(path): - # Fake isfile() to return that the path exists unless a specific - # hash is in the path - if hash_list[3] in path: - return False - return True - - self.patchobject(os.path, 'isfile', _fake_is_file) - with mock.patch('six.moves.builtins.open', mock.mock_open(), - create=True) as open_mock: - test_account_class._get_free_hash(hash_list) - lock_path = os.path.join(self.fixed_params['accounts_lock_dir'], - hash_list[3]) - open_mock.assert_has_calls([mock.call(lock_path, 'w')]) - - @mock.patch('oslo_concurrency.lockutils.lock') - def test_remove_hash_last_account(self, lock_mock): - hash_list = self._get_hash_list(self.test_accounts) - # Pretend the pseudo-lock is there - self.useFixture( - fixtures.MockPatch('os.path.isfile', return_value=True)) - # Pretend the lock dir is empty - self.useFixture(fixtures.MockPatch('os.listdir', return_value=[])) - test_account_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - remove_mock = self.useFixture(fixtures.MockPatch('os.remove')) - rmdir_mock = self.useFixture(fixtures.MockPatch('os.rmdir')) - test_account_class.remove_hash(hash_list[2]) - hash_path = os.path.join(self.fixed_params['accounts_lock_dir'], - hash_list[2]) - lock_path = self.fixed_params['accounts_lock_dir'] - remove_mock.mock.assert_called_once_with(hash_path) - rmdir_mock.mock.assert_called_once_with(lock_path) - - @mock.patch('oslo_concurrency.lockutils.lock') - def test_remove_hash_not_last_account(self, lock_mock): - hash_list = self._get_hash_list(self.test_accounts) - # Pretend the pseudo-lock is there - self.useFixture(fixtures.MockPatch( - 'os.path.isfile', return_value=True)) - # Pretend the lock dir is empty - self.useFixture(fixtures.MockPatch('os.listdir', return_value=[ - hash_list[1], hash_list[4]])) - test_account_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - remove_mock = self.useFixture(fixtures.MockPatch('os.remove')) - rmdir_mock = self.useFixture(fixtures.MockPatch('os.rmdir')) - test_account_class.remove_hash(hash_list[2]) - hash_path = os.path.join(self.fixed_params['accounts_lock_dir'], - hash_list[2]) - remove_mock.mock.assert_called_once_with(hash_path) - rmdir_mock.mock.assert_not_called() - - def test_is_multi_user(self): - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - self.assertTrue(test_accounts_class.is_multi_user()) - - def test_is_not_multi_user(self): - self.test_accounts = [self.test_accounts[0]] - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.preprov_creds.read_accounts_yaml', - return_value=self.test_accounts)) - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - self.assertFalse(test_accounts_class.is_multi_user()) - - def test__get_creds_by_roles_one_role(self): - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - hashes = test_accounts_class.hash_dict['roles']['role4'] - temp_hash = hashes[0] - get_free_hash_mock = self.useFixture(fixtures.MockPatchObject( - test_accounts_class, '_get_free_hash', return_value=temp_hash)) - # Test a single role returns all matching roles - test_accounts_class._get_creds(roles=['role4']) - calls = get_free_hash_mock.mock.mock_calls - self.assertEqual(len(calls), 1) - args = calls[0][1][0] - for i in hashes: - self.assertIn(i, args) - - def test__get_creds_by_roles_list_role(self): - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - hashes = test_accounts_class.hash_dict['roles']['role4'] - hashes2 = test_accounts_class.hash_dict['roles']['role2'] - hashes = list(set(hashes) & set(hashes2)) - temp_hash = hashes[0] - get_free_hash_mock = self.useFixture(fixtures.MockPatchObject( - test_accounts_class, '_get_free_hash', return_value=temp_hash)) - # Test an intersection of multiple roles - test_accounts_class._get_creds(roles=['role2', 'role4']) - calls = get_free_hash_mock.mock.mock_calls - self.assertEqual(len(calls), 1) - args = calls[0][1][0] - for i in hashes: - self.assertIn(i, args) - - def test__get_creds_by_roles_no_admin(self): - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - hashes = list(test_accounts_class.hash_dict['creds'].keys()) - admin_hashes = test_accounts_class.hash_dict['roles'][ - cfg.CONF.identity.admin_role] - temp_hash = hashes[0] - get_free_hash_mock = self.useFixture(fixtures.MockPatchObject( - test_accounts_class, '_get_free_hash', return_value=temp_hash)) - # Test an intersection of multiple roles - test_accounts_class._get_creds() - calls = get_free_hash_mock.mock.mock_calls - self.assertEqual(len(calls), 1) - args = calls[0][1][0] - self.assertEqual(len(args), 10) - for i in admin_hashes: - self.assertNotIn(i, args) - - def test_networks_returned_with_creds(self): - test_accounts = [ - {'username': 'test_user13', 'tenant_name': 'test_tenant13', - 'password': 'p', 'resources': {'network': 'network-1'}}, - {'username': 'test_user14', 'tenant_name': 'test_tenant14', - 'password': 'p', 'roles': ['role-7', 'role-11'], - 'resources': {'network': 'network-2'}}] - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.preprov_creds.read_accounts_yaml', - return_value=test_accounts)) - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - with mock.patch('tempest.lib.services.compute.networks_client.' - 'NetworksClient.list_networks', - return_value={'networks': [{'name': 'network-2', - 'id': 'fake-id', - 'label': 'network-2'}]}): - creds = test_accounts_class.get_creds_by_roles(['role-7']) - self.assertIsInstance(creds, cred_provider.TestResources) - network = creds.network - self.assertIsNotNone(network) - self.assertIn('name', network) - self.assertIn('id', network) - self.assertEqual('fake-id', network['id']) - self.assertEqual('network-2', network['name']) - - def test_get_primary_creds(self): - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - primary_creds = test_accounts_class.get_primary_creds() - self.assertNotIn('test_admin', primary_creds.username) - - def test_get_primary_creds_none_available(self): - admin_accounts = [x for x in self.test_accounts if 'test_admin' - in x['username']] - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.preprov_creds.read_accounts_yaml', - return_value=admin_accounts)) - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - with testtools.ExpectedException(lib_exc.InvalidCredentials): - # Get one more - test_accounts_class.get_primary_creds() - - def test_get_alt_creds(self): - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - alt_creds = test_accounts_class.get_alt_creds() - self.assertNotIn('test_admin', alt_creds.username) - - def test_get_alt_creds_none_available(self): - admin_accounts = [x for x in self.test_accounts if 'test_admin' - in x['username']] - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.preprov_creds.read_accounts_yaml', - return_value=admin_accounts)) - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - with testtools.ExpectedException(lib_exc.InvalidCredentials): - # Get one more - test_accounts_class.get_alt_creds() - - def test_get_admin_creds(self): - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - admin_creds = test_accounts_class.get_admin_creds() - self.assertIn('test_admin', admin_creds.username) - - def test_get_admin_creds_by_type(self): - test_accounts = [ - {'username': 'test_user10', 'project_name': 'test_tenant10', - 'password': 'p', 'roles': ['role1', 'role2', 'role3', 'role4']}, - {'username': 'test_admin1', 'tenant_name': 'test_tenant11', - 'password': 'p', 'types': ['admin']}] - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.preprov_creds.read_accounts_yaml', - return_value=test_accounts)) - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - admin_creds = test_accounts_class.get_admin_creds() - self.assertIn('test_admin', admin_creds.username) - - def test_get_admin_creds_by_role(self): - test_accounts = [ - {'username': 'test_user10', 'project_name': 'test_tenant10', - 'password': 'p', 'roles': ['role1', 'role2', 'role3', 'role4']}, - {'username': 'test_admin1', 'tenant_name': 'test_tenant11', - 'password': 'p', 'roles': [cfg.CONF.identity.admin_role]}] - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.preprov_creds.read_accounts_yaml', - return_value=test_accounts)) - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - admin_creds = test_accounts_class.get_admin_creds() - self.assertIn('test_admin', admin_creds.username) - - def test_get_admin_creds_none_available(self): - non_admin_accounts = [x for x in self.test_accounts if 'test_admin' - not in x['username']] - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.preprov_creds.read_accounts_yaml', - return_value=non_admin_accounts)) - test_accounts_class = preprov_creds.PreProvisionedCredentialProvider( - **self.fixed_params) - with testtools.ExpectedException(lib_exc.InvalidCredentials): - # Get one more - test_accounts_class.get_admin_creds() - - -class TestPreProvisionedCredentialsV3(TestPreProvisionedCredentials): - - fixed_params = {'name': 'test class', - 'identity_version': 'v3', - 'identity_uri': 'fake_uri', - 'test_accounts_file': 'fake_accounts_file', - 'accounts_lock_dir': 'fake_locks_dir_v3', - 'admin_role': 'admin', - 'object_storage_operator_role': 'operator', - 'object_storage_reseller_admin_role': 'reseller'} - - identity_response = fake_identity._fake_v3_response - token_client = ('tempest.lib.services.identity.v3.token_client' - '.V3TokenClient.raw_request') - - @classmethod - def _fake_accounts(cls, admin_role): - return [ - {'username': 'test_user1', 'project_name': 'test_project1', - 'domain_name': 'domain', 'password': 'p'}, - {'username': 'test_user2', 'project_name': 'test_project2', - 'domain_name': 'domain', 'password': 'p'}, - {'username': 'test_user3', 'project_name': 'test_project3', - 'domain_name': 'domain', 'password': 'p'}, - {'username': 'test_user4', 'project_name': 'test_project4', - 'domain_name': 'domain', 'password': 'p'}, - {'username': 'test_user5', 'project_name': 'test_project5', - 'domain_name': 'domain', 'password': 'p'}, - {'username': 'test_user6', 'project_name': 'test_project6', - 'domain_name': 'domain', 'password': 'p', - 'roles': ['role1', 'role2']}, - {'username': 'test_user7', 'project_name': 'test_project7', - 'domain_name': 'domain', 'password': 'p', - 'roles': ['role2', 'role3']}, - {'username': 'test_user8', 'project_name': 'test_project8', - 'domain_name': 'domain', 'password': 'p', - 'roles': ['role4', 'role1']}, - {'username': 'test_user9', 'project_name': 'test_project9', - 'domain_name': 'domain', 'password': 'p', - 'roles': ['role1', 'role2', 'role3', 'role4']}, - {'username': 'test_user10', 'project_name': 'test_project10', - 'domain_name': 'domain', 'password': 'p', - 'roles': ['role1', 'role2', 'role3', 'role4']}, - {'username': 'test_admin1', 'project_name': 'test_project11', - 'domain_name': 'domain', 'password': 'p', 'roles': [admin_role]}, - {'username': 'test_admin2', 'project_name': 'test_project12', - 'domain_name': 'domain', 'password': 'p', 'roles': [admin_role]}, - {'username': 'test_admin3', 'project_name': 'test_tenant13', - 'domain_name': 'domain', 'password': 'p', 'types': ['admin']}] diff --git a/tempest/tests/lib/common/test_rest_client.py b/tempest/tests/lib/common/test_rest_client.py deleted file mode 100644 index 4c0bb5705..000000000 --- a/tempest/tests/lib/common/test_rest_client.py +++ /dev/null @@ -1,1158 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# 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 copy -import json - -import fixtures -import jsonschema -import six - -from tempest.lib.common import http -from tempest.lib.common import rest_client -from tempest.lib import exceptions -from tempest.tests import base -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib import fake_http -import tempest.tests.utils as utils - - -class BaseRestClientTestClass(base.TestCase): - - url = 'fake_endpoint' - - def setUp(self): - super(BaseRestClientTestClass, self).setUp() - self.fake_auth_provider = fake_auth_provider.FakeAuthProvider() - self.rest_client = rest_client.RestClient( - self.fake_auth_provider, None, None) - self.patchobject(http.ClosingHttp, 'request', self.fake_http.request) - self.useFixture(fixtures.MockPatchObject(self.rest_client, - '_log_request')) - - -class TestRestClientHTTPMethods(BaseRestClientTestClass): - def setUp(self): - self.fake_http = fake_http.fake_httplib2() - super(TestRestClientHTTPMethods, self).setUp() - self.useFixture(fixtures.MockPatchObject(self.rest_client, - '_error_checker')) - - def test_post(self): - __, return_dict = self.rest_client.post(self.url, {}, {}) - self.assertEqual('POST', return_dict['method']) - - def test_get(self): - __, return_dict = self.rest_client.get(self.url) - self.assertEqual('GET', return_dict['method']) - - def test_delete(self): - __, return_dict = self.rest_client.delete(self.url) - self.assertEqual('DELETE', return_dict['method']) - - def test_patch(self): - __, return_dict = self.rest_client.patch(self.url, {}, {}) - self.assertEqual('PATCH', return_dict['method']) - - def test_put(self): - __, return_dict = self.rest_client.put(self.url, {}, {}) - self.assertEqual('PUT', return_dict['method']) - - def test_head(self): - self.useFixture(fixtures.MockPatchObject(self.rest_client, - 'response_checker')) - __, return_dict = self.rest_client.head(self.url) - self.assertEqual('HEAD', return_dict['method']) - - def test_copy(self): - __, return_dict = self.rest_client.copy(self.url) - self.assertEqual('COPY', return_dict['method']) - - -class TestRestClientNotFoundHandling(BaseRestClientTestClass): - def setUp(self): - self.fake_http = fake_http.fake_httplib2(404) - super(TestRestClientNotFoundHandling, self).setUp() - - def test_post(self): - self.assertRaises(exceptions.NotFound, self.rest_client.post, - self.url, {}, {}) - - -class TestRestClientHeadersJSON(TestRestClientHTTPMethods): - - def _verify_headers(self, resp): - resp = dict((k.lower(), v) for k, v in six.iteritems(resp)) - self.assertEqual(self.header_value, resp['accept']) - self.assertEqual(self.header_value, resp['content-type']) - - def setUp(self): - super(TestRestClientHeadersJSON, self).setUp() - self.header_value = 'application/json' - - def test_post(self): - resp, __ = self.rest_client.post(self.url, {}) - self._verify_headers(resp) - - def test_get(self): - resp, __ = self.rest_client.get(self.url) - self._verify_headers(resp) - - def test_delete(self): - resp, __ = self.rest_client.delete(self.url) - self._verify_headers(resp) - - def test_patch(self): - resp, __ = self.rest_client.patch(self.url, {}) - self._verify_headers(resp) - - def test_put(self): - resp, __ = self.rest_client.put(self.url, {}) - self._verify_headers(resp) - - def test_head(self): - self.useFixture(fixtures.MockPatchObject(self.rest_client, - 'response_checker')) - resp, __ = self.rest_client.head(self.url) - self._verify_headers(resp) - - def test_copy(self): - resp, __ = self.rest_client.copy(self.url) - self._verify_headers(resp) - - -class TestRestClientUpdateHeaders(BaseRestClientTestClass): - def setUp(self): - self.fake_http = fake_http.fake_httplib2() - super(TestRestClientUpdateHeaders, self).setUp() - self.useFixture(fixtures.MockPatchObject(self.rest_client, - '_error_checker')) - self.headers = {'X-Configuration-Session': 'session_id'} - - def test_post_update_headers(self): - __, return_dict = self.rest_client.post(self.url, {}, - extra_headers=True, - headers=self.headers) - - self.assertDictContainsSubset( - {'X-Configuration-Session': 'session_id', - 'Content-Type': 'application/json', - 'Accept': 'application/json'}, - return_dict['headers'] - ) - - def test_get_update_headers(self): - __, return_dict = self.rest_client.get(self.url, - extra_headers=True, - headers=self.headers) - - self.assertDictContainsSubset( - {'X-Configuration-Session': 'session_id', - 'Content-Type': 'application/json', - 'Accept': 'application/json'}, - return_dict['headers'] - ) - - def test_delete_update_headers(self): - __, return_dict = self.rest_client.delete(self.url, - extra_headers=True, - headers=self.headers) - - self.assertDictContainsSubset( - {'X-Configuration-Session': 'session_id', - 'Content-Type': 'application/json', - 'Accept': 'application/json'}, - return_dict['headers'] - ) - - def test_patch_update_headers(self): - __, return_dict = self.rest_client.patch(self.url, {}, - extra_headers=True, - headers=self.headers) - - self.assertDictContainsSubset( - {'X-Configuration-Session': 'session_id', - 'Content-Type': 'application/json', - 'Accept': 'application/json'}, - return_dict['headers'] - ) - - def test_put_update_headers(self): - __, return_dict = self.rest_client.put(self.url, {}, - extra_headers=True, - headers=self.headers) - - self.assertDictContainsSubset( - {'X-Configuration-Session': 'session_id', - 'Content-Type': 'application/json', - 'Accept': 'application/json'}, - return_dict['headers'] - ) - - def test_head_update_headers(self): - self.useFixture(fixtures.MockPatchObject(self.rest_client, - 'response_checker')) - - __, return_dict = self.rest_client.head(self.url, - extra_headers=True, - headers=self.headers) - - self.assertDictContainsSubset( - {'X-Configuration-Session': 'session_id', - 'Content-Type': 'application/json', - 'Accept': 'application/json'}, - return_dict['headers'] - ) - - def test_copy_update_headers(self): - __, return_dict = self.rest_client.copy(self.url, - extra_headers=True, - headers=self.headers) - - self.assertDictContainsSubset( - {'X-Configuration-Session': 'session_id', - 'Content-Type': 'application/json', - 'Accept': 'application/json'}, - return_dict['headers'] - ) - - -class TestRestClientParseRespJSON(BaseRestClientTestClass): - TYPE = "json" - - keys = ["fake_key1", "fake_key2"] - values = ["fake_value1", "fake_value2"] - item_expected = dict((key, value) for (key, value) in zip(keys, values)) - list_expected = {"body_list": [ - {keys[0]: values[0]}, - {keys[1]: values[1]}, - ]} - dict_expected = {"body_dict": { - keys[0]: values[0], - keys[1]: values[1], - }} - null_dict = {} - - def setUp(self): - self.fake_http = fake_http.fake_httplib2() - super(TestRestClientParseRespJSON, self).setUp() - self.rest_client.TYPE = self.TYPE - - def test_parse_resp_body_item(self): - body = self.rest_client._parse_resp(json.dumps(self.item_expected)) - self.assertEqual(self.item_expected, body) - - def test_parse_resp_body_list(self): - body = self.rest_client._parse_resp(json.dumps(self.list_expected)) - self.assertEqual(self.list_expected["body_list"], body) - - def test_parse_resp_body_dict(self): - body = self.rest_client._parse_resp(json.dumps(self.dict_expected)) - self.assertEqual(self.dict_expected["body_dict"], body) - - def test_parse_resp_two_top_keys(self): - dict_two_keys = self.dict_expected.copy() - dict_two_keys.update({"second_key": ""}) - body = self.rest_client._parse_resp(json.dumps(dict_two_keys)) - self.assertEqual(dict_two_keys, body) - - def test_parse_resp_one_top_key_without_list_or_dict(self): - data = {"one_top_key": "not_list_or_dict_value"} - body = self.rest_client._parse_resp(json.dumps(data)) - self.assertEqual(data, body) - - def test_parse_nullable_dict(self): - body = self.rest_client._parse_resp(json.dumps(self.null_dict)) - self.assertEqual(self.null_dict, body) - - def test_parse_empty_list(self): - empty_list = [] - body = self.rest_client._parse_resp(json.dumps(empty_list)) - self.assertEqual(empty_list, body) - - -class TestRestClientErrorCheckerJSON(base.TestCase): - c_type = "application/json" - - def set_data(self, r_code, enc=None, r_body=None, absolute_limit=True): - if enc is None: - enc = self.c_type - resp_dict = {'status': r_code, 'content-type': enc} - resp_body = {'resp_body': 'fake_resp_body'} - - if absolute_limit is False: - resp_dict.update({'retry-after': 120}) - resp_body.update({'overLimit': {'message': 'fake_message'}}) - resp = fake_http.fake_http_response(headers=resp_dict, - status=int(r_code), - body=json.dumps(resp_body)) - data = { - "resp": resp, - "resp_body": json.dumps(resp_body) - } - if r_body is not None: - data.update({"resp_body": r_body}) - return data - - def setUp(self): - super(TestRestClientErrorCheckerJSON, self).setUp() - self.rest_client = rest_client.RestClient( - fake_auth_provider.FakeAuthProvider(), None, None) - - def test_response_less_than_400(self): - self.rest_client._error_checker(**self.set_data("399")) - - def _test_error_checker(self, exception_type, data): - e = self.assertRaises(exception_type, - self.rest_client._error_checker, - **data) - self.assertEqual(e.resp, data['resp']) - self.assertTrue(hasattr(e, 'resp_body')) - return e - - def test_response_400(self): - self._test_error_checker(exceptions.BadRequest, self.set_data("400")) - - def test_response_401(self): - self._test_error_checker(exceptions.Unauthorized, self.set_data("401")) - - def test_response_403(self): - self._test_error_checker(exceptions.Forbidden, self.set_data("403")) - - def test_response_404(self): - self._test_error_checker(exceptions.NotFound, self.set_data("404")) - - def test_response_409(self): - self._test_error_checker(exceptions.Conflict, self.set_data("409")) - - def test_response_410(self): - self._test_error_checker(exceptions.Gone, self.set_data("410")) - - def test_response_412(self): - self._test_error_checker(exceptions.PreconditionFailed, - self.set_data("412")) - - def test_response_413(self): - self._test_error_checker(exceptions.OverLimit, self.set_data("413")) - - def test_response_413_without_absolute_limit(self): - self._test_error_checker(exceptions.RateLimitExceeded, - self.set_data("413", absolute_limit=False)) - - def test_response_415(self): - self._test_error_checker(exceptions.InvalidContentType, - self.set_data("415")) - - def test_response_422(self): - self._test_error_checker(exceptions.UnprocessableEntity, - self.set_data("422")) - - def test_response_500_with_text(self): - # _parse_resp is expected to return 'str' - self._test_error_checker(exceptions.ServerFault, self.set_data("500")) - - def test_response_501_with_text(self): - self._test_error_checker(exceptions.NotImplemented, - self.set_data("501")) - - def test_response_400_with_dict(self): - r_body = '{"resp_body": {"err": "fake_resp_body"}}' - e = self._test_error_checker(exceptions.BadRequest, - self.set_data("400", r_body=r_body)) - - if self.c_type == 'application/json': - expected = {"err": "fake_resp_body"} - else: - expected = r_body - self.assertEqual(expected, e.resp_body) - - def test_response_401_with_dict(self): - r_body = '{"resp_body": {"err": "fake_resp_body"}}' - e = self._test_error_checker(exceptions.Unauthorized, - self.set_data("401", r_body=r_body)) - - if self.c_type == 'application/json': - expected = {"err": "fake_resp_body"} - else: - expected = r_body - self.assertEqual(expected, e.resp_body) - - def test_response_403_with_dict(self): - r_body = '{"resp_body": {"err": "fake_resp_body"}}' - e = self._test_error_checker(exceptions.Forbidden, - self.set_data("403", r_body=r_body)) - - if self.c_type == 'application/json': - expected = {"err": "fake_resp_body"} - else: - expected = r_body - self.assertEqual(expected, e.resp_body) - - def test_response_404_with_dict(self): - r_body = '{"resp_body": {"err": "fake_resp_body"}}' - e = self._test_error_checker(exceptions.NotFound, - self.set_data("404", r_body=r_body)) - - if self.c_type == 'application/json': - expected = {"err": "fake_resp_body"} - else: - expected = r_body - self.assertEqual(expected, e.resp_body) - - def test_response_404_with_invalid_dict(self): - r_body = '{"foo": "bar"]' - e = self._test_error_checker(exceptions.NotFound, - self.set_data("404", r_body=r_body)) - - expected = r_body - self.assertEqual(expected, e.resp_body) - - def test_response_410_with_dict(self): - r_body = '{"resp_body": {"err": "fake_resp_body"}}' - e = self._test_error_checker(exceptions.Gone, - self.set_data("410", r_body=r_body)) - - if self.c_type == 'application/json': - expected = {"err": "fake_resp_body"} - else: - expected = r_body - self.assertEqual(expected, e.resp_body) - - def test_response_410_with_invalid_dict(self): - r_body = '{"foo": "bar"]' - e = self._test_error_checker(exceptions.Gone, - self.set_data("410", r_body=r_body)) - - expected = r_body - self.assertEqual(expected, e.resp_body) - - def test_response_409_with_dict(self): - r_body = '{"resp_body": {"err": "fake_resp_body"}}' - e = self._test_error_checker(exceptions.Conflict, - self.set_data("409", r_body=r_body)) - - if self.c_type == 'application/json': - expected = {"err": "fake_resp_body"} - else: - expected = r_body - self.assertEqual(expected, e.resp_body) - - def test_response_500_with_dict(self): - r_body = '{"resp_body": {"err": "fake_resp_body"}}' - e = self._test_error_checker(exceptions.ServerFault, - self.set_data("500", r_body=r_body)) - - if self.c_type == 'application/json': - expected = {"err": "fake_resp_body"} - else: - expected = r_body - self.assertEqual(expected, e.resp_body) - - def test_response_501_with_dict(self): - r_body = '{"resp_body": {"err": "fake_resp_body"}}' - self._test_error_checker(exceptions.NotImplemented, - self.set_data("501", r_body=r_body)) - - def test_response_bigger_than_400(self): - # Any response code, that bigger than 400, and not in - # (401, 403, 404, 409, 412, 413, 422, 500, 501) - self._test_error_checker(exceptions.UnexpectedResponseCode, - self.set_data("402")) - - -class TestRestClientErrorCheckerTEXT(TestRestClientErrorCheckerJSON): - c_type = "text/plain" - - def test_fake_content_type(self): - # This test is required only in one exemplar - # Any response code, that bigger than 400, and not in - # (401, 403, 404, 409, 413, 422, 500, 501) - self._test_error_checker(exceptions.UnexpectedContentType, - self.set_data("405", enc="fake_enc")) - - def test_response_413_without_absolute_limit(self): - # Skip this test because rest_client cannot get overLimit message - # from text body. - pass - - -class TestRestClientUtils(BaseRestClientTestClass): - - def _is_resource_deleted(self, resource_id): - if not isinstance(self.retry_pass, int): - return False - if self.retry_count >= self.retry_pass: - return True - self.retry_count = self.retry_count + 1 - return False - - def setUp(self): - self.fake_http = fake_http.fake_httplib2() - super(TestRestClientUtils, self).setUp() - self.retry_count = 0 - self.retry_pass = None - self.original_deleted_method = self.rest_client.is_resource_deleted - self.rest_client.is_resource_deleted = self._is_resource_deleted - - def test_wait_for_resource_deletion(self): - self.retry_pass = 2 - # Ensure timeout long enough for loop execution to hit retry count - self.rest_client.build_timeout = 500 - sleep_mock = self.patch('time.sleep') - self.rest_client.wait_for_resource_deletion('1234') - self.assertEqual(len(sleep_mock.mock_calls), 2) - - def test_wait_for_resource_deletion_not_deleted(self): - self.patch('time.sleep') - # Set timeout to be very quick to force exception faster - timeout = 1 - self.rest_client.build_timeout = timeout - - time_mock = self.patch('time.time') - time_mock.side_effect = utils.generate_timeout_series(timeout) - - self.assertRaises(exceptions.TimeoutException, - self.rest_client.wait_for_resource_deletion, - '1234') - - # time.time() should be called twice, first to start the timer - # and then to compute the timedelta - self.assertEqual(2, time_mock.call_count) - - def test_wait_for_deletion_with_unimplemented_deleted_method(self): - self.rest_client.is_resource_deleted = self.original_deleted_method - self.assertRaises(NotImplementedError, - self.rest_client.wait_for_resource_deletion, - '1234') - - def test_get_versions(self): - self.rest_client._parse_resp = lambda x: [{'id': 'v1'}, {'id': 'v2'}] - actual_resp, actual_versions = self.rest_client.get_versions() - self.assertEqual(['v1', 'v2'], list(actual_versions)) - - def test__str__(self): - def get_token(): - return "deadbeef" - - self.fake_auth_provider.get_token = get_token - self.assertIsNotNone(str(self.rest_client)) - - -class TestRateLimiting(BaseRestClientTestClass): - - def setUp(self): - self.fake_http = fake_http.fake_httplib2() - super(TestRateLimiting, self).setUp() - - def test__get_retry_after_delay_with_integer(self): - resp = {'retry-after': '123'} - self.assertEqual(123, self.rest_client._get_retry_after_delay(resp)) - - def test__get_retry_after_delay_with_http_date(self): - resp = { - 'date': 'Mon, 4 Apr 2016 21:56:23 GMT', - 'retry-after': 'Mon, 4 Apr 2016 21:58:26 GMT', - } - self.assertEqual(123, self.rest_client._get_retry_after_delay(resp)) - - def test__get_retry_after_delay_of_zero_with_integer(self): - resp = {'retry-after': '0'} - self.assertEqual(1, self.rest_client._get_retry_after_delay(resp)) - - def test__get_retry_after_delay_of_zero_with_http_date(self): - resp = { - 'date': 'Mon, 4 Apr 2016 21:56:23 GMT', - 'retry-after': 'Mon, 4 Apr 2016 21:56:23 GMT', - } - self.assertEqual(1, self.rest_client._get_retry_after_delay(resp)) - - def test__get_retry_after_delay_with_missing_date_header(self): - resp = { - 'retry-after': 'Mon, 4 Apr 2016 21:58:26 GMT', - } - self.assertRaises(ValueError, self.rest_client._get_retry_after_delay, - resp) - - def test__get_retry_after_delay_with_invalid_http_date(self): - resp = { - 'retry-after': 'Mon, 4 AAA 2016 21:58:26 GMT', - 'date': 'Mon, 4 Apr 2016 21:56:23 GMT', - } - self.assertRaises(ValueError, self.rest_client._get_retry_after_delay, - resp) - - def test__get_retry_after_delay_with_missing_retry_after_header(self): - self.assertRaises(ValueError, self.rest_client._get_retry_after_delay, - {}) - - def test_is_absolute_limit_gives_false_with_retry_after(self): - resp = {'retry-after': 123} - - # is_absolute_limit() requires the overLimit body to be unwrapped - resp_body = self.rest_client._parse_resp("""{ - "overLimit": { - "message": "" - } - }""") - self.assertFalse(self.rest_client.is_absolute_limit(resp, resp_body)) - - -class TestProperties(BaseRestClientTestClass): - - def setUp(self): - self.fake_http = fake_http.fake_httplib2() - super(TestProperties, self).setUp() - creds_dict = { - 'username': 'test-user', - 'user_id': 'test-user_id', - 'tenant_name': 'test-tenant_name', - 'tenant_id': 'test-tenant_id', - 'password': 'test-password' - } - self.rest_client = rest_client.RestClient( - fake_auth_provider.FakeAuthProvider(creds_dict=creds_dict), - None, None) - - def test_properties(self): - self.assertEqual('test-user', self.rest_client.user) - self.assertEqual('test-user_id', self.rest_client.user_id) - self.assertEqual('test-tenant_name', self.rest_client.tenant_name) - self.assertEqual('test-tenant_id', self.rest_client.tenant_id) - self.assertEqual('test-password', self.rest_client.password) - - self.rest_client.api_version = 'v1' - expected = {'api_version': 'v1', - 'endpoint_type': 'publicURL', - 'region': None, - 'name': None, - 'service': None, - 'skip_path': True} - self.rest_client.skip_path() - self.assertEqual(expected, self.rest_client.filters) - - self.rest_client.reset_path() - self.rest_client.api_version = 'v1' - expected = {'api_version': 'v1', - 'endpoint_type': 'publicURL', - 'region': None, - 'name': None, - 'service': None} - self.assertEqual(expected, self.rest_client.filters) - - -class TestExpectedSuccess(BaseRestClientTestClass): - - def setUp(self): - self.fake_http = fake_http.fake_httplib2() - super(TestExpectedSuccess, self).setUp() - - def test_expected_succes_int_match(self): - expected_code = 202 - read_code = 202 - resp = self.rest_client.expected_success(expected_code, read_code) - # Assert None resp on success - self.assertFalse(resp) - - def test_expected_succes_int_no_match(self): - expected_code = 204 - read_code = 202 - self.assertRaises(exceptions.InvalidHttpSuccessCode, - self.rest_client.expected_success, - expected_code, read_code) - - def test_expected_succes_list_match(self): - expected_code = [202, 204] - read_code = 202 - resp = self.rest_client.expected_success(expected_code, read_code) - # Assert None resp on success - self.assertFalse(resp) - - def test_expected_succes_list_no_match(self): - expected_code = [202, 204] - read_code = 200 - self.assertRaises(exceptions.InvalidHttpSuccessCode, - self.rest_client.expected_success, - expected_code, read_code) - - def test_non_success_expected_int(self): - expected_code = 404 - read_code = 202 - self.assertRaises(AssertionError, self.rest_client.expected_success, - expected_code, read_code) - - def test_non_success_expected_list(self): - expected_code = [404, 202] - read_code = 202 - self.assertRaises(AssertionError, self.rest_client.expected_success, - expected_code, read_code) - - def test_non_success_read_code_as_string(self): - expected_code = 202 - read_code = '202' - self.assertRaises(TypeError, self.rest_client.expected_success, - expected_code, read_code) - - def test_non_success_read_code_as_list(self): - expected_code = 202 - read_code = [202] - self.assertRaises(TypeError, self.rest_client.expected_success, - expected_code, read_code) - - def test_non_success_expected_code_as_non_int(self): - expected_code = ['201', 202] - read_code = 202 - self.assertRaises(AssertionError, self.rest_client.expected_success, - expected_code, read_code) - - -class TestResponseBody(base.TestCase): - - def test_str(self): - response = {'status': 200} - body = {'key1': 'value1'} - actual = rest_client.ResponseBody(response, body) - self.assertEqual("response: %s\nBody: %s" % (response, body), - str(actual)) - - -class TestResponseBodyData(base.TestCase): - - def test_str(self): - response = {'status': 200} - data = 'data1' - actual = rest_client.ResponseBodyData(response, data) - self.assertEqual("response: %s\nBody: %s" % (response, data), - str(actual)) - - -class TestResponseBodyList(base.TestCase): - - def test_str(self): - response = {'status': 200} - body = ['value1', 'value2', 'value3'] - actual = rest_client.ResponseBodyList(response, body) - self.assertEqual("response: %s\nBody: %s" % (response, body), - str(actual)) - - -class TestJSONSchemaValidationBase(base.TestCase): - - class Response(dict): - - def __getattr__(self, attr): - return self[attr] - - def __setattr__(self, attr, value): - self[attr] = value - - def setUp(self): - super(TestJSONSchemaValidationBase, self).setUp() - self.fake_auth_provider = fake_auth_provider.FakeAuthProvider() - self.rest_client = rest_client.RestClient( - self.fake_auth_provider, None, None) - - def _test_validate_pass(self, schema, resp_body, status=200): - resp = self.Response() - resp.status = status - self.rest_client.validate_response(schema, resp, resp_body) - - def _test_validate_fail(self, schema, resp_body, status=200, - error_msg="HTTP response body is invalid"): - resp = self.Response() - resp.status = status - ex = self.assertRaises(exceptions.InvalidHTTPResponseBody, - self.rest_client.validate_response, - schema, resp, resp_body) - self.assertIn(error_msg, ex._error_string) - - -class TestRestClientJSONSchemaValidation(TestJSONSchemaValidationBase): - - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': { - 'type': 'integer', - }, - }, - 'required': ['foo'] - } - } - - def test_validate_pass_with_http_success_code(self): - body = {'foo': 12} - self._test_validate_pass(self.schema, body, status=200) - - def test_validate_pass_with_http_redirect_code(self): - body = {'foo': 12} - schema = copy.deepcopy(self.schema) - schema['status_code'] = 300 - self._test_validate_pass(schema, body, status=300) - - def test_validate_not_http_success_code(self): - schema = { - 'status_code': [200] - } - body = {} - self._test_validate_pass(schema, body, status=400) - - def test_validate_multiple_allowed_type(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': { - 'type': ['integer', 'string'], - }, - }, - 'required': ['foo'] - } - } - body = {'foo': 12} - self._test_validate_pass(schema, body) - body = {'foo': '12'} - self._test_validate_pass(schema, body) - - def test_validate_enable_additional_property_pass(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': {'type': 'integer'} - }, - 'additionalProperties': True, - 'required': ['foo'] - } - } - body = {'foo': 12, 'foo2': 'foo2value'} - self._test_validate_pass(schema, body) - - def test_validate_disable_additional_property_pass(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': {'type': 'integer'} - }, - 'additionalProperties': False, - 'required': ['foo'] - } - } - body = {'foo': 12} - self._test_validate_pass(schema, body) - - def test_validate_disable_additional_property_fail(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': {'type': 'integer'} - }, - 'additionalProperties': False, - 'required': ['foo'] - } - } - body = {'foo': 12, 'foo2': 'foo2value'} - self._test_validate_fail(schema, body) - - def test_validate_wrong_status_code(self): - schema = { - 'status_code': [202] - } - body = {} - resp = self.Response() - resp.status = 200 - ex = self.assertRaises(exceptions.InvalidHttpSuccessCode, - self.rest_client.validate_response, - schema, resp, body) - self.assertIn("Unexpected http success status code", ex._error_string) - - def test_validate_wrong_attribute_type(self): - body = {'foo': 1.2} - self._test_validate_fail(self.schema, body) - - def test_validate_unexpected_response_body(self): - schema = { - 'status_code': [200], - } - body = {'foo': 12} - self._test_validate_fail( - schema, body, - error_msg="HTTP response body should not exist") - - def test_validate_missing_response_body(self): - body = {} - self._test_validate_fail(self.schema, body) - - def test_validate_missing_required_attribute(self): - body = {'notfoo': 12} - self._test_validate_fail(self.schema, body) - - def test_validate_response_body_not_list(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'list_items': { - 'type': 'array', - 'items': {'foo': {'type': 'integer'}} - } - }, - 'required': ['list_items'], - } - } - body = {'foo': 12} - self._test_validate_fail(schema, body) - - def test_validate_response_body_list_pass(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'list_items': { - 'type': 'array', - 'items': {'foo': {'type': 'integer'}} - } - }, - 'required': ['list_items'], - } - } - body = {'list_items': [{'foo': 12}, {'foo': 10}]} - self._test_validate_pass(schema, body) - - -class TestRestClientJSONHeaderSchemaValidation(TestJSONSchemaValidationBase): - - schema = { - 'status_code': [200], - 'response_header': { - 'type': 'object', - 'properties': { - 'foo': {'type': 'integer'} - }, - 'required': ['foo'] - } - } - - def test_validate_header_schema_pass(self): - resp_body = {} - resp = self.Response() - resp.status = 200 - resp.foo = 12 - self.rest_client.validate_response(self.schema, resp, resp_body) - - def test_validate_header_schema_fail(self): - resp_body = {} - resp = self.Response() - resp.status = 200 - resp.foo = 1.2 - ex = self.assertRaises(exceptions.InvalidHTTPResponseHeader, - self.rest_client.validate_response, - self.schema, resp, resp_body) - self.assertIn("HTTP response header is invalid", ex._error_string) - - -class TestRestClientJSONSchemaFormatValidation(TestJSONSchemaValidationBase): - - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': { - 'type': 'string', - 'format': 'email' - } - }, - 'required': ['foo'] - } - } - - def test_validate_format_pass(self): - body = {'foo': 'example@example.com'} - self._test_validate_pass(self.schema, body) - - def test_validate_format_fail(self): - body = {'foo': 'wrong_email'} - self._test_validate_fail(self.schema, body) - - def test_validate_formats_in_oneOf_pass(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': { - 'type': 'string', - 'oneOf': [ - {'format': 'ipv4'}, - {'format': 'ipv6'} - ] - } - }, - 'required': ['foo'] - } - } - body = {'foo': '10.0.0.0'} - self._test_validate_pass(schema, body) - body = {'foo': 'FE80:0000:0000:0000:0202:B3FF:FE1E:8329'} - self._test_validate_pass(schema, body) - - def test_validate_formats_in_oneOf_fail_both_match(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': { - 'type': 'string', - 'oneOf': [ - {'format': 'ipv4'}, - {'format': 'ipv4'} - ] - } - }, - 'required': ['foo'] - } - } - body = {'foo': '10.0.0.0'} - self._test_validate_fail(schema, body) - - def test_validate_formats_in_oneOf_fail_no_match(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': { - 'type': 'string', - 'oneOf': [ - {'format': 'ipv4'}, - {'format': 'ipv6'} - ] - } - }, - 'required': ['foo'] - } - } - body = {'foo': 'wrong_ip_format'} - self._test_validate_fail(schema, body) - - def test_validate_formats_in_anyOf_pass(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': { - 'type': 'string', - 'anyOf': [ - {'format': 'ipv4'}, - {'format': 'ipv6'} - ] - } - }, - 'required': ['foo'] - } - } - body = {'foo': '10.0.0.0'} - self._test_validate_pass(schema, body) - body = {'foo': 'FE80:0000:0000:0000:0202:B3FF:FE1E:8329'} - self._test_validate_pass(schema, body) - - def test_validate_formats_in_anyOf_pass_both_match(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': { - 'type': 'string', - 'anyOf': [ - {'format': 'ipv4'}, - {'format': 'ipv4'} - ] - } - }, - 'required': ['foo'] - } - } - body = {'foo': '10.0.0.0'} - self._test_validate_pass(schema, body) - - def test_validate_formats_in_anyOf_fail_no_match(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': { - 'type': 'string', - 'anyOf': [ - {'format': 'ipv4'}, - {'format': 'ipv6'} - ] - } - }, - 'required': ['foo'] - } - } - body = {'foo': 'wrong_ip_format'} - self._test_validate_fail(schema, body) - - def test_validate_formats_pass_for_unknow_format(self): - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': { - 'type': 'string', - 'format': 'UNKNOWN' - } - }, - 'required': ['foo'] - } - } - body = {'foo': 'example@example.com'} - self._test_validate_pass(schema, body) - - -class TestRestClientJSONSchemaValidatorVersion(TestJSONSchemaValidationBase): - - schema = { - 'status_code': [200], - 'response_body': { - 'type': 'object', - 'properties': { - 'foo': {'type': 'string'} - } - } - } - - def test_current_json_schema_validator_version(self): - with fixtures.MockPatchObject(jsonschema.Draft4Validator, - "check_schema") as chk_schema: - body = {'foo': 'test'} - self._test_validate_pass(self.schema, body) - chk_schema.mock.assert_called_once_with( - self.schema['response_body']) diff --git a/tempest/tests/lib/common/utils/__init__.py b/tempest/tests/lib/common/utils/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/common/utils/linux/__init__.py b/tempest/tests/lib/common/utils/linux/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/common/utils/linux/test_remote_client.py b/tempest/tests/lib/common/utils/linux/test_remote_client.py deleted file mode 100644 index cf312f4f2..000000000 --- a/tempest/tests/lib/common/utils/linux/test_remote_client.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright 2017 NEC Corporation. -# 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 mock - -from tempest.lib.common import ssh -from tempest.lib.common.utils.linux import remote_client -from tempest.lib import exceptions as lib_exc -from tempest.tests import base - - -class FakeServersClient(object): - - def get_console_output(self, server_id): - return {"output": "fake_output"} - - -class TestRemoteClient(base.TestCase): - - @mock.patch.object(ssh.Client, 'exec_command', return_value='success') - def test_exec_command(self, mock_ssh_exec_command): - client = remote_client.RemoteClient('192.168.1.10', 'username') - client.exec_command('ls') - mock_ssh_exec_command.assert_called_once_with( - 'set -eu -o pipefail; PATH=$$PATH:/sbin; ls') - - @mock.patch.object(ssh.Client, 'test_connection_auth') - def test_validate_authentication(self, mock_test_connection_auth): - client = remote_client.RemoteClient('192.168.1.10', 'username') - client.validate_authentication() - mock_test_connection_auth.assert_called_once_with() - - @mock.patch.object(remote_client.LOG, 'debug') - @mock.patch.object(ssh.Client, 'exec_command') - def test_debug_ssh_without_console(self, mock_exec_command, mock_debug): - mock_exec_command.side_effect = lib_exc.SSHTimeout - server = {'id': 'fake_id'} - client = remote_client.RemoteClient('192.168.1.10', 'username', - server=server) - self.assertRaises(lib_exc.SSHTimeout, client.exec_command, 'ls') - mock_debug.assert_called_with( - 'Caller: %s. Timeout trying to ssh to server %s', - 'TestRemoteClient:test_debug_ssh_without_console', server) - - @mock.patch.object(remote_client.LOG, 'debug') - @mock.patch.object(ssh.Client, 'exec_command') - def test_debug_ssh_with_console(self, mock_exec_command, mock_debug): - mock_exec_command.side_effect = lib_exc.SSHTimeout - server = {'id': 'fake_id'} - client = remote_client.RemoteClient('192.168.1.10', 'username', - server=server, - servers_client=FakeServersClient()) - self.assertRaises(lib_exc.SSHTimeout, client.exec_command, 'ls') - mock_debug.assert_called_with( - 'Console log for server %s: %s', server['id'], 'fake_output') diff --git a/tempest/tests/lib/common/utils/test_data_utils.py b/tempest/tests/lib/common/utils/test_data_utils.py deleted file mode 100644 index 8bdf70ec7..000000000 --- a/tempest/tests/lib/common/utils/test_data_utils.py +++ /dev/null @@ -1,182 +0,0 @@ -# Copyright 2014 NEC Corporation. -# 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 netaddr - -from tempest.lib.common.utils import data_utils -from tempest.tests import base - - -class TestDataUtils(base.TestCase): - - def test_rand_uuid(self): - actual = data_utils.rand_uuid() - self.assertIsInstance(actual, str) - self.assertRegex(actual, "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]" - "{4}-[0-9a-f]{4}-[0-9a-f]{12}$") - actual2 = data_utils.rand_uuid() - self.assertNotEqual(actual, actual2) - - def test_rand_uuid_hex(self): - actual = data_utils.rand_uuid_hex() - self.assertIsInstance(actual, str) - self.assertRegex(actual, "^[0-9a-f]{32}$") - - actual2 = data_utils.rand_uuid_hex() - self.assertNotEqual(actual, actual2) - - def test_rand_name_with_default_prefix(self): - actual = data_utils.rand_name('foo') - self.assertIsInstance(actual, str) - self.assertTrue(actual.startswith('tempest-foo')) - actual2 = data_utils.rand_name('foo') - self.assertTrue(actual2.startswith('tempest-foo')) - self.assertNotEqual(actual, actual2) - - def test_rand_name_with_none_prefix(self): - actual = data_utils.rand_name('foo', prefix=None) - self.assertIsInstance(actual, str) - self.assertTrue(actual.startswith('foo')) - actual2 = data_utils.rand_name('foo', prefix=None) - self.assertTrue(actual2.startswith('foo')) - self.assertNotEqual(actual, actual2) - - def test_rand_name_with_prefix(self): - actual = data_utils.rand_name(prefix='prefix-str') - self.assertIsInstance(actual, str) - self.assertRegex(actual, "^prefix-str-") - actual2 = data_utils.rand_name(prefix='prefix-str') - self.assertNotEqual(actual, actual2) - - def test_rand_password(self): - actual = data_utils.rand_password() - self.assertIsInstance(actual, str) - self.assertRegex(actual, "[A-Za-z0-9~!@#%^&*_=+]{15,}") - actual2 = data_utils.rand_password() - self.assertNotEqual(actual, actual2) - - def test_rand_password_with_len(self): - actual = data_utils.rand_password(8) - self.assertIsInstance(actual, str) - self.assertEqual(len(actual), 8) - self.assertRegex(actual, "[A-Za-z0-9~!@#%^&*_=+]{8}") - actual2 = data_utils.rand_password(8) - self.assertNotEqual(actual, actual2) - - def test_rand_password_with_len_2(self): - actual = data_utils.rand_password(2) - self.assertIsInstance(actual, str) - self.assertEqual(len(actual), 3) - self.assertRegex(actual, "[A-Za-z0-9~!@#%^&*_=+]{3}") - actual2 = data_utils.rand_password(2) - self.assertNotEqual(actual, actual2) - - def test_rand_url(self): - actual = data_utils.rand_url() - self.assertIsInstance(actual, str) - self.assertRegex(actual, "^https://url-[0-9]*\.com$") - actual2 = data_utils.rand_url() - self.assertNotEqual(actual, actual2) - - def test_rand_int(self): - actual = data_utils.rand_int_id() - self.assertIsInstance(actual, int) - - actual2 = data_utils.rand_int_id() - self.assertNotEqual(actual, actual2) - - def test_rand_infiniband_guid_address(self): - actual = data_utils.rand_infiniband_guid_address() - self.assertIsInstance(actual, str) - self.assertRegex(actual, "^([0-9a-f][0-9a-f]:){7}" - "[0-9a-f][0-9a-f]$") - - actual2 = data_utils.rand_infiniband_guid_address() - self.assertNotEqual(actual, actual2) - - def test_rand_mac_address(self): - actual = data_utils.rand_mac_address() - self.assertIsInstance(actual, str) - self.assertRegex(actual, "^([0-9a-f][0-9a-f]:){5}" - "[0-9a-f][0-9a-f]$") - - actual2 = data_utils.rand_mac_address() - self.assertNotEqual(actual, actual2) - - def test_parse_image_id(self): - actual = data_utils.parse_image_id("/foo/bar/deadbeaf") - self.assertEqual("deadbeaf", actual) - - def test_arbitrary_string(self): - actual = data_utils.arbitrary_string() - self.assertEqual(actual, "test") - actual = data_utils.arbitrary_string(size=30, base_text="abc") - self.assertEqual(actual, "abc" * int(30 / len("abc"))) - actual = data_utils.arbitrary_string(size=5, base_text="deadbeaf") - self.assertEqual(actual, "deadb") - - def test_random_bytes(self): - actual = data_utils.random_bytes() # default size=1024 - self.assertIsInstance(actual, bytes) - self.assertEqual(1024, len(actual)) - actual2 = data_utils.random_bytes() - self.assertNotEqual(actual, actual2) - - actual = data_utils.random_bytes(size=2048) - self.assertEqual(2048, len(actual)) - - def test_get_ipv6_addr_by_EUI64(self): - actual = data_utils.get_ipv6_addr_by_EUI64('2001:db8::', - '00:16:3e:33:44:55') - self.assertIsInstance(actual, netaddr.IPAddress) - self.assertEqual(actual, - netaddr.IPAddress('2001:db8::216:3eff:fe33:4455')) - - def test_get_ipv6_addr_by_EUI64_with_IPv4_prefix(self): - ipv4_prefix = '10.0.8' - mac = '00:16:3e:33:44:55' - self.assertRaises(TypeError, data_utils.get_ipv6_addr_by_EUI64, - ipv4_prefix, mac) - - def test_get_ipv6_addr_by_EUI64_bad_cidr_type(self): - bad_cidr = 123 - mac = '00:16:3e:33:44:55' - self.assertRaises(TypeError, data_utils.get_ipv6_addr_by_EUI64, - bad_cidr, mac) - - def test_get_ipv6_addr_by_EUI64_bad_cidr_value(self): - bad_cidr = 'bb' - mac = '00:16:3e:33:44:55' - self.assertRaises(TypeError, data_utils.get_ipv6_addr_by_EUI64, - bad_cidr, mac) - - def test_get_ipv6_addr_by_EUI64_bad_mac_value(self): - cidr = '2001:db8::' - bad_mac = '00:16:3e:33:44:5Z' - self.assertRaises(TypeError, data_utils.get_ipv6_addr_by_EUI64, - cidr, bad_mac) - - def test_get_ipv6_addr_by_EUI64_bad_mac_type(self): - cidr = '2001:db8::' - bad_mac = 99999999999999999999 - self.assertRaises(TypeError, data_utils.get_ipv6_addr_by_EUI64, - cidr, bad_mac) - - def test_chunkify(self): - data = "aaa" - chunks = data_utils.chunkify(data, 2) - self.assertEqual("aa", next(chunks)) - self.assertEqual("a", next(chunks)) - self.assertRaises(StopIteration, next, chunks) diff --git a/tempest/tests/lib/common/utils/test_misc.py b/tempest/tests/lib/common/utils/test_misc.py deleted file mode 100644 index 47e81d158..000000000 --- a/tempest/tests/lib/common/utils/test_misc.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2014 NEC Corporation. -# 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 tempest.lib.common.utils import misc -from tempest.tests import base - - -@misc.singleton -class TestFoo(object): - - count = 0 - - def increment(self): - self.count += 1 - return self.count - - -@misc.singleton -class TestBar(object): - - count = 0 - - def increment(self): - self.count += 1 - return self.count - - -class TestMisc(base.TestCase): - - def test_singleton(self): - test = TestFoo() - self.assertEqual(0, test.count) - self.assertEqual(1, test.increment()) - test2 = TestFoo() - self.assertEqual(1, test.count) - self.assertEqual(1, test2.count) - self.assertEqual(test, test2) - test3 = TestBar() - self.assertNotEqual(test, test3) diff --git a/tempest/tests/lib/common/utils/test_test_utils.py b/tempest/tests/lib/common/utils/test_test_utils.py deleted file mode 100644 index 29c56841e..000000000 --- a/tempest/tests/lib/common/utils/test_test_utils.py +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# 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 mock - -from tempest.lib.common.utils import test_utils -from tempest.lib import exceptions -from tempest.tests import base -from tempest.tests import utils - - -class TestTestUtils(base.TestCase): - - def test_find_test_caller_test_case(self): - # Calling it from here should give us the method we're in. - self.assertEqual('TestTestUtils:test_find_test_caller_test_case', - test_utils.find_test_caller()) - - def test_find_test_caller_setup_self(self): - def setUp(self): - return test_utils.find_test_caller() - self.assertEqual('TestTestUtils:setUp', setUp(self)) - - def test_find_test_caller_setup_no_self(self): - def setUp(): - return test_utils.find_test_caller() - self.assertEqual(':setUp', setUp()) - - def test_find_test_caller_setupclass_cls(self): - def setUpClass(cls): # noqa - return test_utils.find_test_caller() - self.assertEqual('TestTestUtils:setUpClass', - setUpClass(self.__class__)) - - def test_find_test_caller_teardown_self(self): - def tearDown(self): - return test_utils.find_test_caller() - self.assertEqual('TestTestUtils:tearDown', tearDown(self)) - - def test_find_test_caller_teardown_no_self(self): - def tearDown(): - return test_utils.find_test_caller() - self.assertEqual(':tearDown', tearDown()) - - def test_find_test_caller_teardown_class(self): - def tearDownClass(cls): # noqa - return test_utils.find_test_caller() - self.assertEqual('TestTestUtils:tearDownClass', - tearDownClass(self.__class__)) - - def test_call_and_ignore_notfound_exc_when_notfound_raised(self): - def raise_not_found(): - raise exceptions.NotFound() - self.assertIsNone( - test_utils.call_and_ignore_notfound_exc(raise_not_found)) - - def test_call_and_ignore_notfound_exc_when_value_error_raised(self): - def raise_value_error(): - raise ValueError() - self.assertRaises(ValueError, test_utils.call_and_ignore_notfound_exc, - raise_value_error) - - def test_call_and_ignore_notfound_exc(self): - m = mock.Mock(return_value=42) - args, kwargs = (1,), {'1': None} - self.assertEqual( - 42, test_utils.call_and_ignore_notfound_exc(m, *args, **kwargs)) - m.assert_called_once_with(*args, **kwargs) - - @mock.patch('time.sleep') - @mock.patch('time.time') - def test_call_until_true_when_f_never_returns_true(self, m_time, m_sleep): - timeout = 42 # The value doesn't matter as we mock time.time() - sleep = 60 # The value doesn't matter as we mock time.sleep() - m_time.side_effect = utils.generate_timeout_series(timeout) - self.assertEqual( - False, test_utils.call_until_true(lambda: False, timeout, sleep) - ) - m_sleep.call_args_list = [mock.call(sleep)] * 2 - m_time.call_args_list = [mock.call()] * 2 - - @mock.patch('time.sleep') - @mock.patch('time.time') - def test_call_until_true_when_f_returns_true(self, m_time, m_sleep): - timeout = 42 # The value doesn't matter as we mock time.time() - sleep = 60 # The value doesn't matter as we mock time.sleep() - m_time.return_value = 0 - self.assertEqual( - True, test_utils.call_until_true(lambda: True, timeout, sleep) - ) - self.assertEqual(0, m_sleep.call_count) - self.assertEqual(1, m_time.call_count) diff --git a/tempest/tests/lib/fake_auth_provider.py b/tempest/tests/lib/fake_auth_provider.py deleted file mode 100644 index e4582f81b..000000000 --- a/tempest/tests/lib/fake_auth_provider.py +++ /dev/null @@ -1,38 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P. -# 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. - - -class FakeAuthProvider(object): - - def __init__(self, creds_dict=None, fake_base_url=None): - creds_dict = creds_dict or {} - self.credentials = FakeCredentials(creds_dict) - self.fake_base_url = fake_base_url - - def auth_request(self, method, url, headers=None, body=None, filters=None): - return url, headers, body - - def base_url(self, filters, auth_data=None): - return self.fake_base_url or "https://example.com" - - def get_token(self): - return "faketoken" - - -class FakeCredentials(object): - - def __init__(self, creds_dict): - for key in creds_dict: - setattr(self, key, creds_dict[key]) diff --git a/tempest/tests/lib/fake_credentials.py b/tempest/tests/lib/fake_credentials.py deleted file mode 100644 index eac4ada39..000000000 --- a/tempest/tests/lib/fake_credentials.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P. -# 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 tempest.lib import auth - - -class FakeCredentials(auth.Credentials): - - def is_valid(self): - return True - - -class FakeKeystoneV2Credentials(auth.KeystoneV2Credentials): - - def __init__(self): - creds = dict( - username='fake_username', - password='fake_password', - tenant_name='fake_tenant_name' - ) - super(FakeKeystoneV2Credentials, self).__init__(**creds) - - -class FakeKeystoneV3Credentials(auth.KeystoneV3Credentials): - """Fake credentials suitable for the Keystone Identity V3 API""" - - def __init__(self): - creds = dict( - username='fake_username', - password='fake_password', - user_domain_name='fake_domain_name', - project_name='fake_tenant_name', - project_domain_name='fake_domain_name' - ) - super(FakeKeystoneV3Credentials, self).__init__(**creds) - - -class FakeKeystoneV3DomainCredentials(auth.KeystoneV3Credentials): - """Fake credentials for the Keystone Identity V3 API, with no scope""" - - def __init__(self): - creds = dict( - username='fake_username', - password='fake_password', - user_domain_name='fake_domain_name' - ) - super(FakeKeystoneV3DomainCredentials, self).__init__(**creds) - - -class FakeKeystoneV3AllCredentials(auth.KeystoneV3Credentials): - """Fake credentials for the Keystone Identity V3 API, with no scope""" - - def __init__(self): - creds = dict( - username='fake_username', - password='fake_password', - user_domain_name='fake_domain_name', - project_name='fake_tenant_name', - project_domain_name='fake_domain_name', - domain_name='fake_domain_name' - ) - super(FakeKeystoneV3AllCredentials, self).__init__(**creds) diff --git a/tempest/tests/lib/fake_http.py b/tempest/tests/lib/fake_http.py deleted file mode 100644 index cfa4b9368..000000000 --- a/tempest/tests/lib/fake_http.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# 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 copy - - -class fake_httplib2(object): - - def __init__(self, return_type=None, *args, **kwargs): - self.return_type = return_type - - def request(self, uri, method="GET", body=None, headers=None, - redirections=5, connection_type=None, chunked=False): - if not self.return_type: - fake_headers = fake_http_response(headers) - return_obj = { - 'uri': uri, - 'method': method, - 'body': body, - 'headers': headers - } - return (fake_headers, return_obj) - elif isinstance(self.return_type, int): - body = body or "fake_body" - header_info = { - 'content-type': 'text/plain', - 'content-length': len(body) - } - resp_header = fake_http_response(header_info, - status=self.return_type) - return (resp_header, body) - else: - msg = "unsupported return type %s" % self.return_type - raise TypeError(msg) - - -class fake_http_response(dict): - def __init__(self, headers, body=None, - version=1.0, status=200, reason="Ok"): - """Initialization of fake HTTP Response - - :param headers: dict representing HTTP response headers - :param body: file-like object - :param version: HTTP Version - :param status: Response status code - :param reason: Status code related message. - """ - self.body = body - self.status = status - self['status'] = str(self.status) - self.reason = reason - self.version = version - self.headers = headers - - if headers: - for key, value in headers.items(): - self[key.lower()] = value - - def getheaders(self): - return copy.deepcopy(self.headers).items() - - def getheader(self, key, default): - return self.headers.get(key, default) - - def read(self, amt): - return self.body.read(amt) diff --git a/tempest/tests/lib/fake_identity.py b/tempest/tests/lib/fake_identity.py deleted file mode 100644 index 8bae34f88..000000000 --- a/tempest/tests/lib/fake_identity.py +++ /dev/null @@ -1,240 +0,0 @@ -# Copyright 2014 IBM 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 oslo_serialization import jsonutils as json - -from tempest.tests.lib import fake_http - -FAKE_AUTH_URL = 'http://fake_uri.com/auth' - -TOKEN = "fake_token" -ALT_TOKEN = "alt_fake_token" - -# Fake Identity v2 constants -COMPUTE_ENDPOINTS_V2 = { - "endpoints": [ - { - "adminURL": "http://fake_url/v2/first_endpoint/admin", - "region": "NoMatchRegion", - "internalURL": "http://fake_url/v2/first_endpoint/internal", - "publicURL": "http://fake_url/v2/first_endpoint/public" - }, - { - "adminURL": "http://fake_url/v2/second_endpoint/admin", - "region": "FakeRegion", - "internalURL": "http://fake_url/v2/second_endpoint/internal", - "publicURL": "http://fake_url/v2/second_endpoint/public" - }, - ], - "type": "compute", - "name": "nova" -} - -CATALOG_V2 = [COMPUTE_ENDPOINTS_V2, ] - -ALT_IDENTITY_V2_RESPONSE = { - "access": { - "token": { - "expires": "2020-01-01T00:00:10Z", - "id": ALT_TOKEN, - "tenant": { - "id": "fake_alt_tenant_id" - }, - }, - "user": { - "id": "fake_alt_user_id", - "password_expires_at": None, - }, - "serviceCatalog": CATALOG_V2, - }, -} - -IDENTITY_V2_RESPONSE = { - "access": { - "token": { - "expires": "2020-01-01T00:00:10Z", - "id": TOKEN, - "tenant": { - "id": "fake_tenant_id" - }, - }, - "user": { - "id": "fake_user_id", - "password_expires_at": None, - }, - "serviceCatalog": CATALOG_V2, - }, -} - -# Fake Identity V3 constants -COMPUTE_ENDPOINTS_V3 = { - "endpoints": [ - { - "id": "first_compute_fake_service", - "interface": "public", - "region": "NoMatchRegion", - "region_id": "NoMatchRegion", - "url": "http://fake_url/v3/first_endpoint/api" - }, - { - "id": "second_fake_service", - "interface": "public", - "region": "FakeRegion", - "region_id": "FakeRegion", - "url": "http://fake_url/v3/second_endpoint/api" - }, - { - "id": "third_fake_service", - "interface": "admin", - "region": "MiddleEarthRegion", - "region_id": "MiddleEarthRegion", - "url": "http://fake_url/v3/third_endpoint/api" - } - - ], - "type": "compute", - "id": "fake_compute_endpoint", - "name": "nova" -} - -CATALOG_V3 = [COMPUTE_ENDPOINTS_V3, ] - -IDENTITY_V3_RESPONSE = { - "token": { - "audit_ids": ["ny5LA5YXToa_mAVO8Hnupw", "9NPTvsRDSkmsW61abP978Q"], - "methods": [ - "token", - "password" - ], - "expires_at": "2020-01-01T00:00:10.000123Z", - "project": { - "domain": { - "id": "fake_domain_id", - "name": "fake" - }, - "id": "project_id", - "name": "project_name" - }, - "user": { - "domain": { - "id": "fake_domain_id", - "name": "domain_name" - }, - "id": "fake_user_id", - "name": "username", - "password_expires_at": None, - }, - "issued_at": "2013-05-29T16:55:21.468960Z", - "catalog": CATALOG_V3 - } -} - -IDENTITY_V3_RESPONSE_DOMAIN_SCOPE = { - "token": { - "audit_ids": ["ny5LA5YXToa_mAVO8Hnupw", "9NPTvsRDSkmsW61abP978Q"], - "methods": [ - "token", - "password" - ], - "expires_at": "2020-01-01T00:00:10.000123Z", - "domain": { - "id": "fake_domain_id", - "name": "domain_name" - }, - "user": { - "domain": { - "id": "fake_domain_id", - "name": "domain_name" - }, - "id": "fake_user_id", - "name": "username", - "password_expires_at": None, - }, - "issued_at": "2013-05-29T16:55:21.468960Z", - "catalog": CATALOG_V3 - } -} - -IDENTITY_V3_RESPONSE_NO_SCOPE = { - "token": { - "audit_ids": ["ny5LA5YXToa_mAVO8Hnupw", "9NPTvsRDSkmsW61abP978Q"], - "methods": [ - "token", - "password" - ], - "expires_at": "2020-01-01T00:00:10.000123Z", - "user": { - "domain": { - "id": "fake_domain_id", - "name": "domain_name" - }, - "id": "fake_user_id", - "name": "username", - "password_expires_at": None, - }, - "issued_at": "2013-05-29T16:55:21.468960Z", - } -} - -ALT_IDENTITY_V3 = IDENTITY_V3_RESPONSE - - -def _fake_v3_response(self, uri, method="GET", body=None, headers=None, - redirections=5, connection_type=None): - fake_headers = { - "x-subject-token": TOKEN - } - return (fake_http.fake_http_response(fake_headers, status=201), - json.dumps(IDENTITY_V3_RESPONSE)) - - -def _fake_v3_response_domain_scope(self, uri, method="GET", body=None, - headers=None, redirections=5, - connection_type=None): - fake_headers = { - "status": "201", - "x-subject-token": TOKEN - } - return (fake_http.fake_http_response(fake_headers, status=201), - json.dumps(IDENTITY_V3_RESPONSE_DOMAIN_SCOPE)) - - -def _fake_v3_response_no_scope(self, uri, method="GET", body=None, - headers=None, redirections=5, - connection_type=None): - fake_headers = { - "status": "201", - "x-subject-token": TOKEN - } - return (fake_http.fake_http_response(fake_headers, status=201), - json.dumps(IDENTITY_V3_RESPONSE_NO_SCOPE)) - - -def _fake_v2_response(self, uri, method="GET", body=None, headers=None, - redirections=5, connection_type=None): - return (fake_http.fake_http_response({}, status=200), - json.dumps(IDENTITY_V2_RESPONSE)) - - -def _fake_auth_failure_response(): - # the response body isn't really used in this case, but lets send it anyway - # to have a safe check in some future change on the rest client. - body = { - "unauthorized": { - "message": "Unauthorized", - "code": "401" - } - } - return fake_http.fake_http_response({}, status=401), json.dumps(body) diff --git a/tempest/tests/lib/services/__init__.py b/tempest/tests/lib/services/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/base.py b/tempest/tests/lib/services/base.py deleted file mode 100644 index 924f9f206..000000000 --- a/tempest/tests/lib/services/base.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright 2015 Deutsche Telekom AG. 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 fixtures -from oslo_serialization import jsonutils as json - -from tempest.tests import base -from tempest.tests.lib import fake_http - - -class BaseServiceTest(base.TestCase): - def create_response(self, body, to_utf=False, status=200, headers=None): - json_body = {} - if body: - json_body = json.dumps(body) - if to_utf: - json_body = json_body.encode('utf-8') - resp = fake_http.fake_http_response(headers, status=status), json_body - return resp - - def check_service_client_function(self, function, function2mock, - body, to_utf=False, status=200, - headers=None, mock_args=None, - resp_as_string=False, - **kwargs): - """Mock a service client function for unit testing. - - :param function: The service client function to call. - :param function2mock: The REST call to mock inside the service client - function. - :param body: Expected response body returned by the service client - function. - :param to_utf: Whether to use UTF-8 encoding for response. - :param status: Expected response status returned by the service client - function. - :param headers: Expected headers returned by the service client - function. - :param mock_args: List/dict/value of expected args/kwargs called by - function2mock. For example: - * If mock_args=['foo'] then ``assert_called_once_with('foo')`` - is called. - * If mock_args={'foo': 'bar'} then - ``assert_called_once_with(foo='bar')`` is called. - * If mock_args='foo' then ``assert_called_once_with('foo')`` - is called. - :param resp_as_string: Whether response body is retruned as string. - This is for service client methods which return ResponseBodyData - object. - :param kwargs: kwargs that are passed to function. - """ - mocked_response = self.create_response(body, to_utf, status, headers) - fixture = self.useFixture(fixtures.MockPatch( - function2mock, return_value=mocked_response)) - if kwargs: - resp = function(**kwargs) - else: - resp = function() - if resp_as_string: - resp = resp.data - self.assertEqual(body, resp) - if isinstance(mock_args, list): - fixture.mock.assert_called_once_with(*mock_args) - elif isinstance(mock_args, dict): - fixture.mock.assert_called_once_with(**mock_args) - elif mock_args is not None: - fixture.mock.assert_called_once_with(mock_args) diff --git a/tempest/tests/lib/services/compute/__init__.py b/tempest/tests/lib/services/compute/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/compute/test_agents_client.py b/tempest/tests/lib/services/compute/test_agents_client.py deleted file mode 100644 index 880220e64..000000000 --- a/tempest/tests/lib/services/compute/test_agents_client.py +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 tempest.lib.services.compute import agents_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestAgentsClient(base.BaseServiceTest): - FAKE_CREATE_AGENT = { - "agent": { - "url": "http://foo.com", - "hypervisor": "kvm", - "md5hash": "md5", - "version": "2", - "architecture": "x86_64", - "os": "linux", - "agent_id": 1 - } - } - - FAKE_UPDATE_AGENT = { - "agent": { - "url": "http://foo.com", - "md5hash": "md5", - "version": "2", - "agent_id": 1 - } - } - - def setUp(self): - super(TestAgentsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = agents_client.AgentsClient(fake_auth, - 'compute', 'regionOne') - - def _test_list_agents(self, bytes_body=False): - self.check_service_client_function( - self.client.list_agents, - 'tempest.lib.common.rest_client.RestClient.get', - {"agents": []}, - bytes_body) - self.check_service_client_function( - self.client.list_agents, - 'tempest.lib.common.rest_client.RestClient.get', - {"agents": []}, - bytes_body, - hypervisor="kvm") - - def _test_create_agent(self, bytes_body=False): - self.check_service_client_function( - self.client.create_agent, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_AGENT, - bytes_body, - url="http://foo.com", hypervisor="kvm", md5hash="md5", - version="2", architecture="x86_64", os="linux") - - def _test_delete_agent(self): - self.check_service_client_function( - self.client.delete_agent, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, agent_id="1") - - def _test_update_agent(self, bytes_body=False): - self.check_service_client_function( - self.client.update_agent, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_AGENT, - bytes_body, - agent_id="1", url="http://foo.com", md5hash="md5", version="2") - - def test_list_agents_with_str_body(self): - self._test_list_agents() - - def test_list_agents_with_bytes_body(self): - self._test_list_agents(bytes_body=True) - - def test_create_agent_with_str_body(self): - self._test_create_agent() - - def test_create_agent_with_bytes_body(self): - self._test_create_agent(bytes_body=True) - - def test_delete_agent(self): - self._test_delete_agent() - - def test_update_agent_with_str_body(self): - self._test_update_agent() - - def test_update_agent_with_bytes_body(self): - self._test_update_agent(bytes_body=True) diff --git a/tempest/tests/lib/services/compute/test_aggregates_client.py b/tempest/tests/lib/services/compute/test_aggregates_client.py deleted file mode 100644 index 674d92a35..000000000 --- a/tempest/tests/lib/services/compute/test_aggregates_client.py +++ /dev/null @@ -1,192 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 tempest.lib.services.compute import aggregates_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestAggregatesClient(base.BaseServiceTest): - FAKE_SHOW_AGGREGATE = { - "aggregate": - { - "name": "hoge", - "availability_zone": None, - "deleted": False, - "created_at": - "2015-07-16T03:07:32.000000", - "updated_at": None, - "hosts": [], - "deleted_at": None, - "id": 1, - "metadata": {} - } - } - - FAKE_CREATE_AGGREGATE = { - "aggregate": - { - "name": u'\xf4', - "availability_zone": None, - "deleted": False, - "created_at": "2015-07-21T04:11:18.000000", - "updated_at": None, - "deleted_at": None, - "id": 1 - } - } - - FAKE_UPDATE_AGGREGATE = { - "aggregate": - { - "name": u'\xe9', - "availability_zone": None, - "deleted": False, - "created_at": "2015-07-16T03:07:32.000000", - "updated_at": "2015-07-23T05:16:29.000000", - "hosts": [], - "deleted_at": None, - "id": 1, - "metadata": {} - } - } - - FAKE_AGGREGATE = { - "availability_zone": "nova", - "created_at": "2013-08-18T12:17:56.297823", - "deleted": False, - "deleted_at": None, - "hosts": [ - "21549b2f665945baaa7101926a00143c" - ], - "id": 1, - "metadata": { - "availability_zone": "nova" - }, - "name": u'\xe9', - "updated_at": None - } - - FAKE_ADD_HOST = {'aggregate': FAKE_AGGREGATE} - FAKE_REMOVE_HOST = {'aggregate': FAKE_AGGREGATE} - FAKE_SET_METADATA = {'aggregate': FAKE_AGGREGATE} - - def setUp(self): - super(TestAggregatesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = aggregates_client.AggregatesClient( - fake_auth, 'compute', 'regionOne') - - def _test_list_aggregates(self, bytes_body=False): - self.check_service_client_function( - self.client.list_aggregates, - 'tempest.lib.common.rest_client.RestClient.get', - {"aggregates": []}, - bytes_body) - - def test_list_aggregates_with_str_body(self): - self._test_list_aggregates() - - def test_list_aggregates_with_bytes_body(self): - self._test_list_aggregates(bytes_body=True) - - def _test_show_aggregate(self, bytes_body=False): - self.check_service_client_function( - self.client.show_aggregate, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SHOW_AGGREGATE, - bytes_body, - aggregate_id=1) - - def test_show_aggregate_with_str_body(self): - self._test_show_aggregate() - - def test_show_aggregate_with_bytes_body(self): - self._test_show_aggregate(bytes_body=True) - - def _test_create_aggregate(self, bytes_body=False): - self.check_service_client_function( - self.client.create_aggregate, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_AGGREGATE, - bytes_body, - name='hoge') - - def test_create_aggregate_with_str_body(self): - self._test_create_aggregate() - - def test_create_aggregate_with_bytes_body(self): - self._test_create_aggregate(bytes_body=True) - - def test_delete_aggregate(self): - self.check_service_client_function( - self.client.delete_aggregate, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, aggregate_id="1") - - def _test_update_aggregate(self, bytes_body=False): - self.check_service_client_function( - self.client.update_aggregate, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_AGGREGATE, - bytes_body, - aggregate_id=1) - - def test_update_aggregate_with_str_body(self): - self._test_update_aggregate() - - def test_update_aggregate_with_bytes_body(self): - self._test_update_aggregate(bytes_body=True) - - def _test_add_host(self, bytes_body=False): - self.check_service_client_function( - self.client.add_host, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_ADD_HOST, - bytes_body, - aggregate_id=1) - - def test_add_host_with_str_body(self): - self._test_add_host() - - def test_add_host_with_bytes_body(self): - self._test_add_host(bytes_body=True) - - def _test_remove_host(self, bytes_body=False): - self.check_service_client_function( - self.client.remove_host, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_REMOVE_HOST, - bytes_body, - aggregate_id=1) - - def test_remove_host_with_str_body(self): - self._test_remove_host() - - def test_remove_host_with_bytes_body(self): - self._test_remove_host(bytes_body=True) - - def _test_set_metadata(self, bytes_body=False): - self.check_service_client_function( - self.client.set_metadata, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_SET_METADATA, - bytes_body, - aggregate_id=1) - - def test_set_metadata_with_str_body(self): - self._test_set_metadata() - - def test_set_metadata_with_bytes_body(self): - self._test_set_metadata(bytes_body=True) diff --git a/tempest/tests/lib/services/compute/test_availability_zone_client.py b/tempest/tests/lib/services/compute/test_availability_zone_client.py deleted file mode 100644 index 6608592da..000000000 --- a/tempest/tests/lib/services/compute/test_availability_zone_client.py +++ /dev/null @@ -1,51 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 tempest.lib.services.compute import availability_zone_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestAvailabilityZoneClient(base.BaseServiceTest): - - FAKE_AVAILABIRITY_ZONE_INFO = { - "availabilityZoneInfo": - [ - { - "zoneState": { - "available": True - }, - "hosts": None, - "zoneName": u'\xf4' - } - ] - } - - def setUp(self): - super(TestAvailabilityZoneClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = availability_zone_client.AvailabilityZoneClient( - fake_auth, 'compute', 'regionOne') - - def test_list_availability_zones_with_str_body(self): - self.check_service_client_function( - self.client.list_availability_zones, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_AVAILABIRITY_ZONE_INFO) - - def test_list_availability_zones_with_bytes_body(self): - self.check_service_client_function( - self.client.list_availability_zones, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_AVAILABIRITY_ZONE_INFO, to_utf=True) diff --git a/tempest/tests/lib/services/compute/test_baremetal_nodes_client.py b/tempest/tests/lib/services/compute/test_baremetal_nodes_client.py deleted file mode 100644 index 81c54b5da..000000000 --- a/tempest/tests/lib/services/compute/test_baremetal_nodes_client.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 copy - -from tempest.lib.services.compute import baremetal_nodes_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestBareMetalNodesClient(base.BaseServiceTest): - - FAKE_NODE_INFO = {'cpus': '8', - 'disk_gb': '64', - 'host': '10.0.2.15', - 'id': 'Identifier', - 'instance_uuid': "null", - 'interfaces': [ - { - "address": "20::01", - "datapath_id": "null", - "id": 1, - "port_no": None - } - ], - 'memory_mb': '8192', - 'task_state': None} - - def setUp(self): - super(TestBareMetalNodesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.baremetal_nodes_client = (baremetal_nodes_client. - BaremetalNodesClient - (fake_auth, 'compute', - 'regionOne')) - - def _test_bareMetal_nodes(self, operation='list', bytes_body=False): - if operation != 'list': - expected = {"node": self.FAKE_NODE_INFO} - function = self.baremetal_nodes_client.show_baremetal_node - else: - node_info = copy.deepcopy(self.FAKE_NODE_INFO) - del node_info['instance_uuid'] - expected = {"nodes": [node_info]} - function = self.baremetal_nodes_client.list_baremetal_nodes - - self.check_service_client_function( - function, - 'tempest.lib.common.rest_client.RestClient.get', - expected, bytes_body, 200, - baremetal_node_id='Identifier') - - def test_list_bareMetal_nodes_with_str_body(self): - self._test_bareMetal_nodes() - - def test_list_bareMetal_nodes_with_bytes_body(self): - self._test_bareMetal_nodes(bytes_body=True) - - def test_show_bareMetal_node_with_str_body(self): - self._test_bareMetal_nodes('show') - - def test_show_bareMetal_node_with_bytes_body(self): - self._test_bareMetal_nodes('show', True) diff --git a/tempest/tests/lib/services/compute/test_base_compute_client.py b/tempest/tests/lib/services/compute/test_base_compute_client.py deleted file mode 100644 index 69e8542c6..000000000 --- a/tempest/tests/lib/services/compute/test_base_compute_client.py +++ /dev/null @@ -1,206 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 mock - -from tempest.lib.common import rest_client -from tempest.lib import exceptions -from tempest.lib.services.compute import base_compute_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib import fake_http -from tempest.tests.lib.services import base - - -class TestMicroversionHeaderCheck(base.BaseServiceTest): - - def setUp(self): - super(TestMicroversionHeaderCheck, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = base_compute_client.BaseComputeClient( - fake_auth, 'compute', 'regionOne') - base_compute_client.COMPUTE_MICROVERSION = '2.2' - - def tearDown(self): - super(TestMicroversionHeaderCheck, self).tearDown() - base_compute_client.COMPUTE_MICROVERSION = None - - @mock.patch('tempest.lib.common.http.ClosingHttp.request') - def test_correct_microverion_in_response(self, mock_request): - response = fake_http.fake_http_response( - headers={self.client.api_microversion_header_name: '2.2'}, - ) - mock_request.return_value = response, '' - self.client.get('fake_url') - - @mock.patch('tempest.lib.common.http.ClosingHttp.request') - def test_incorrect_microverion_in_response(self, mock_request): - response = fake_http.fake_http_response( - headers={self.client.api_microversion_header_name: '2.3'}, - ) - mock_request.return_value = response, '' - self.assertRaises(exceptions.InvalidHTTPResponseHeader, - self.client.get, 'fake_url') - - @mock.patch('tempest.lib.common.http.ClosingHttp.request') - def test_no_microverion_header_in_response(self, mock_request): - response = fake_http.fake_http_response( - headers={}, - ) - mock_request.return_value = response, '' - self.assertRaises(exceptions.InvalidHTTPResponseHeader, - self.client.get, 'fake_url') - - -class DummyServiceClient1(base_compute_client.BaseComputeClient): - schema_versions_info = [ - {'min': None, 'max': '2.1', 'schema': 'schemav21'}, - {'min': '2.2', 'max': '2.9', 'schema': 'schemav22'}, - {'min': '2.10', 'max': None, 'schema': 'schemav210'}] - - def return_selected_schema(self): - return self.get_schema(self.schema_versions_info) - - -class TestSchemaVersionsNone(base.BaseServiceTest): - api_microversion = None - expected_schema = 'schemav21' - - def setUp(self): - super(TestSchemaVersionsNone, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = DummyServiceClient1(fake_auth, 'compute', 'regionOne') - base_compute_client.COMPUTE_MICROVERSION = self.api_microversion - - def tearDown(self): - super(TestSchemaVersionsNone, self).tearDown() - base_compute_client.COMPUTE_MICROVERSION = None - - def test_schema(self): - self.assertEqual(self.expected_schema, - self.client.return_selected_schema()) - - -class TestSchemaVersionsV21(TestSchemaVersionsNone): - api_microversion = '2.1' - expected_schema = 'schemav21' - - -class TestSchemaVersionsV22(TestSchemaVersionsNone): - api_microversion = '2.2' - expected_schema = 'schemav22' - - -class TestSchemaVersionsV25(TestSchemaVersionsNone): - api_microversion = '2.5' - expected_schema = 'schemav22' - - -class TestSchemaVersionsV29(TestSchemaVersionsNone): - api_microversion = '2.9' - expected_schema = 'schemav22' - - -class TestSchemaVersionsV210(TestSchemaVersionsNone): - api_microversion = '2.10' - expected_schema = 'schemav210' - - -class TestSchemaVersionsLatest(TestSchemaVersionsNone): - api_microversion = 'latest' - expected_schema = 'schemav210' - - -class DummyServiceClient2(base_compute_client.BaseComputeClient): - schema_versions_info = [ - {'min': None, 'max': '2.1', 'schema': 'schemav21'}, - {'min': '2.2', 'max': '2.9', 'schema': 'schemav22'}] - - def return_selected_schema(self): - return self.get_schema(self.schema_versions_info) - - -class TestSchemaVersionsNotFound(base.BaseServiceTest): - api_microversion = '2.10' - expected_schema = 'schemav210' - - def setUp(self): - super(TestSchemaVersionsNotFound, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = DummyServiceClient2(fake_auth, 'compute', 'regionOne') - base_compute_client.COMPUTE_MICROVERSION = self.api_microversion - - def tearDown(self): - super(TestSchemaVersionsNotFound, self).tearDown() - base_compute_client.COMPUTE_MICROVERSION = None - - def test_schema(self): - self.assertRaises(exceptions.JSONSchemaNotFound, - self.client.return_selected_schema) - - -class TestClientWithoutMicroversionHeader(base.BaseServiceTest): - - def setUp(self): - super(TestClientWithoutMicroversionHeader, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = base_compute_client.BaseComputeClient( - fake_auth, 'compute', 'regionOne') - - def test_no_microverion_header(self): - header = self.client.get_headers() - self.assertNotIn('X-OpenStack-Nova-API-Version', header) - - def test_no_microverion_header_in_raw_request(self): - def raw_request(*args, **kwargs): - self.assertNotIn('X-OpenStack-Nova-API-Version', kwargs['headers']) - return (fake_http.fake_http_response({}, status=200), '') - - with mock.patch.object(rest_client.RestClient, - 'raw_request') as mock_get: - mock_get.side_effect = raw_request - self.client.get('fake_url') - - -class TestClientWithMicroversionHeader(base.BaseServiceTest): - - def setUp(self): - super(TestClientWithMicroversionHeader, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = base_compute_client.BaseComputeClient( - fake_auth, 'compute', 'regionOne') - base_compute_client.COMPUTE_MICROVERSION = '2.2' - - def tearDown(self): - super(TestClientWithMicroversionHeader, self).tearDown() - base_compute_client.COMPUTE_MICROVERSION = None - - def test_microverion_header(self): - header = self.client.get_headers() - self.assertIn('X-OpenStack-Nova-API-Version', header) - self.assertEqual('2.2', - header['X-OpenStack-Nova-API-Version']) - - def test_microverion_header_in_raw_request(self): - def raw_request(*args, **kwargs): - self.assertIn('X-OpenStack-Nova-API-Version', kwargs['headers']) - self.assertEqual('2.2', - kwargs['headers']['X-OpenStack-Nova-API-Version']) - return (fake_http.fake_http_response( - headers={self.client.api_microversion_header_name: '2.2'}, - status=200), '') - - with mock.patch.object(rest_client.RestClient, - 'raw_request') as mock_get: - mock_get.side_effect = raw_request - self.client.get('fake_url') diff --git a/tempest/tests/lib/services/compute/test_certificates_client.py b/tempest/tests/lib/services/compute/test_certificates_client.py deleted file mode 100644 index 9faef6f47..000000000 --- a/tempest/tests/lib/services/compute/test_certificates_client.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 copy - -from tempest.lib.services.compute import certificates_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestCertificatesClient(base.BaseServiceTest): - - FAKE_CERTIFICATE = { - "certificate": { - "data": "-----BEGIN----MIICyzCCAjSgAwI----END CERTIFICATE-----\n", - "private_key": None - } - } - - def setUp(self): - super(TestCertificatesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = certificates_client.CertificatesClient( - fake_auth, 'compute', 'regionOne') - - def _test_show_certificate(self, bytes_body=False): - self.check_service_client_function( - self.client.show_certificate, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CERTIFICATE, - bytes_body, - certificate_id="fake-id") - - def test_show_certificate_with_str_body(self): - self._test_show_certificate() - - def test_show_certificate_with_bytes_body(self): - self._test_show_certificate(bytes_body=True) - - def _test_create_certificate(self, bytes_body=False): - cert = copy.deepcopy(self.FAKE_CERTIFICATE) - cert['certificate']['private_key'] = "my_private_key" - self.check_service_client_function( - self.client.create_certificate, - 'tempest.lib.common.rest_client.RestClient.post', - cert, - bytes_body) - - def test_create_certificate_with_str_body(self): - self._test_create_certificate() - - def test_create_certificate_with_bytes_body(self): - self._test_create_certificate(bytes_body=True) diff --git a/tempest/tests/lib/services/compute/test_extensions_client.py b/tempest/tests/lib/services/compute/test_extensions_client.py deleted file mode 100644 index d7e217e52..000000000 --- a/tempest/tests/lib/services/compute/test_extensions_client.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 tempest.lib.services.compute import extensions_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestExtensionsClient(base.BaseServiceTest): - - FAKE_SHOW_EXTENSION = { - "extension": { - "updated": "2011-06-09T00:00:00Z", - "name": "Multinic", - "links": [], - "namespace": - "http://docs.openstack.org/compute/ext/multinic/api/v1.1", - "alias": "NMN", - "description": u'\u2740(*\xb4\u25e1`*)\u2740' - } - } - - def setUp(self): - super(TestExtensionsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = extensions_client.ExtensionsClient( - fake_auth, 'compute', 'regionOne') - - def _test_list_extensions(self, bytes_body=False): - self.check_service_client_function( - self.client.list_extensions, - 'tempest.lib.common.rest_client.RestClient.get', - {"extensions": []}, - bytes_body) - - def test_list_extensions_with_str_body(self): - self._test_list_extensions() - - def test_list_extensions_with_bytes_body(self): - self._test_list_extensions(bytes_body=True) - - def _test_show_extension(self, bytes_body=False): - self.check_service_client_function( - self.client.show_extension, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SHOW_EXTENSION, - bytes_body, - extension_alias="NMN") - - def test_show_extension_with_str_body(self): - self._test_show_extension() - - def test_show_extension_with_bytes_body(self): - self._test_show_extension(bytes_body=True) diff --git a/tempest/tests/lib/services/compute/test_fixedIPs_client.py b/tempest/tests/lib/services/compute/test_fixedIPs_client.py deleted file mode 100644 index 65bda45b8..000000000 --- a/tempest/tests/lib/services/compute/test_fixedIPs_client.py +++ /dev/null @@ -1,58 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 tempest.lib.services.compute import fixed_ips_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestFixedIPsClient(base.BaseServiceTest): - FIXED_IP_INFO = {"fixed_ip": {"address": "10.0.0.1", - "cidr": "10.11.12.0/24", - "host": "localhost", - "hostname": "OpenStack"}} - - def setUp(self): - super(TestFixedIPsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.fixedIPsClient = (fixed_ips_client. - FixedIPsClient - (fake_auth, 'compute', - 'regionOne')) - - def _test_show_fixed_ip(self, bytes_body=False): - self.check_service_client_function( - self.fixedIPsClient.show_fixed_ip, - 'tempest.lib.common.rest_client.RestClient.get', - self.FIXED_IP_INFO, bytes_body, - status=200, fixed_ip='Identifier') - - def test_show_fixed_ip_with_str_body(self): - self._test_show_fixed_ip() - - def test_show_fixed_ip_with_bytes_body(self): - self._test_show_fixed_ip(True) - - def _test_reserve_fixed_ip(self, bytes_body=False): - self.check_service_client_function( - self.fixedIPsClient.reserve_fixed_ip, - 'tempest.lib.common.rest_client.RestClient.post', - {}, bytes_body, - status=202, fixed_ip='Identifier') - - def test_reserve_fixed_ip_with_str_body(self): - self._test_reserve_fixed_ip() - - def test_reserve_fixed_ip_with_bytes_body(self): - self._test_reserve_fixed_ip(True) diff --git a/tempest/tests/lib/services/compute/test_flavors_client.py b/tempest/tests/lib/services/compute/test_flavors_client.py deleted file mode 100644 index cbd17c688..000000000 --- a/tempest/tests/lib/services/compute/test_flavors_client.py +++ /dev/null @@ -1,255 +0,0 @@ -# Copyright 2015 IBM Corp. -# -# 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 copy - -import fixtures -from oslo_serialization import jsonutils as json - -from tempest.lib.services.compute import flavors_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib import fake_http -from tempest.tests.lib.services import base - - -class TestFlavorsClient(base.BaseServiceTest): - - FAKE_FLAVOR = { - "disk": 1, - "id": "1", - "links": [{ - "href": "http://openstack.example.com/v2/openstack/flavors/1", - "rel": "self"}, { - "href": "http://openstack.example.com/openstack/flavors/1", - "rel": "bookmark"}], - "name": "m1.tiny", - "ram": 512, - "swap": 1, - "vcpus": 1 - } - - EXTRA_SPECS = {"extra_specs": { - "key1": "value1", - "key2": "value2"} - } - - FAKE_FLAVOR_ACCESS = { - "flavor_id": "10", - "tenant_id": "1a951d988e264818afe520e78697dcbf" - } - - def setUp(self): - super(TestFlavorsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = flavors_client.FlavorsClient(fake_auth, - 'compute', 'regionOne') - - def _test_list_flavors(self, bytes_body=False): - flavor = copy.deepcopy(TestFlavorsClient.FAKE_FLAVOR) - # Remove extra attributes - for attribute in ('disk', 'vcpus', 'ram', 'swap'): - del flavor[attribute] - expected = {'flavors': [flavor]} - self.check_service_client_function( - self.client.list_flavors, - 'tempest.lib.common.rest_client.RestClient.get', - expected, - bytes_body) - - def test_list_flavors_str_body(self): - self._test_list_flavors(bytes_body=False) - - def test_list_flavors_byte_body(self): - self._test_list_flavors(bytes_body=True) - - def _test_show_flavor(self, bytes_body=False): - expected = {"flavor": TestFlavorsClient.FAKE_FLAVOR} - self.check_service_client_function( - self.client.show_flavor, - 'tempest.lib.common.rest_client.RestClient.get', - expected, - bytes_body, - flavor_id='fake-id') - - def test_show_flavor_str_body(self): - self._test_show_flavor(bytes_body=False) - - def test_show_flavor_byte_body(self): - self._test_show_flavor(bytes_body=True) - - def _test_create_flavor(self, bytes_body=False): - expected = {"flavor": TestFlavorsClient.FAKE_FLAVOR} - request = copy.deepcopy(TestFlavorsClient.FAKE_FLAVOR) - # The 'links' parameter should not be passed in - del request['links'] - self.check_service_client_function( - self.client.create_flavor, - 'tempest.lib.common.rest_client.RestClient.post', - expected, - bytes_body, - **request) - - def test_create_flavor_str_body(self): - self._test_create_flavor(bytes_body=False) - - def test_create_flavor__byte_body(self): - self._test_create_flavor(bytes_body=True) - - def test_delete_flavor(self): - self.check_service_client_function( - self.client.delete_flavor, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, status=202, flavor_id='c782b7a9-33cd-45f0-b795-7f87f456408b') - - def _test_is_resource_deleted(self, flavor_id, is_deleted=True, - bytes_body=False): - body = json.dumps({'flavors': [TestFlavorsClient.FAKE_FLAVOR]}) - if bytes_body: - body = body.encode('utf-8') - response = fake_http.fake_http_response({}, status=200), body - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.rest_client.RestClient.get', - return_value=response)) - self.assertEqual(is_deleted, - self.client.is_resource_deleted(flavor_id)) - - def test_is_resource_deleted_true_str_body(self): - self._test_is_resource_deleted('2', bytes_body=False) - - def test_is_resource_deleted_true_byte_body(self): - self._test_is_resource_deleted('2', bytes_body=True) - - def test_is_resource_deleted_false_str_body(self): - self._test_is_resource_deleted('1', is_deleted=False, bytes_body=False) - - def test_is_resource_deleted_false_byte_body(self): - self._test_is_resource_deleted('1', is_deleted=False, bytes_body=True) - - def _test_set_flavor_extra_spec(self, bytes_body=False): - self.check_service_client_function( - self.client.set_flavor_extra_spec, - 'tempest.lib.common.rest_client.RestClient.post', - TestFlavorsClient.EXTRA_SPECS, - bytes_body, - flavor_id='8c7aae5a-d315-4216-875b-ed9b6a5bcfc6', - **TestFlavorsClient.EXTRA_SPECS) - - def test_set_flavor_extra_spec_str_body(self): - self._test_set_flavor_extra_spec(bytes_body=False) - - def test_set_flavor_extra_spec_byte_body(self): - self._test_set_flavor_extra_spec(bytes_body=True) - - def _test_list_flavor_extra_specs(self, bytes_body=False): - self.check_service_client_function( - self.client.list_flavor_extra_specs, - 'tempest.lib.common.rest_client.RestClient.get', - TestFlavorsClient.EXTRA_SPECS, - bytes_body, - flavor_id='8c7aae5a-d315-4216-875b-ed9b6a5bcfc6') - - def test_list_flavor_extra_specs_str_body(self): - self._test_list_flavor_extra_specs(bytes_body=False) - - def test_list_flavor_extra_specs__byte_body(self): - self._test_list_flavor_extra_specs(bytes_body=True) - - def _test_show_flavor_extra_spec(self, bytes_body=False): - expected = {"key": "value"} - self.check_service_client_function( - self.client.show_flavor_extra_spec, - 'tempest.lib.common.rest_client.RestClient.get', - expected, - bytes_body, - flavor_id='8c7aae5a-d315-4216-875b-ed9b6a5bcfc6', - key='key') - - def test_show_flavor_extra_spec_str_body(self): - self._test_show_flavor_extra_spec(bytes_body=False) - - def test_show_flavor_extra_spec__byte_body(self): - self._test_show_flavor_extra_spec(bytes_body=True) - - def _test_update_flavor_extra_spec(self, bytes_body=False): - expected = {"key1": "value"} - self.check_service_client_function( - self.client.update_flavor_extra_spec, - 'tempest.lib.common.rest_client.RestClient.put', - expected, - bytes_body, - flavor_id='8c7aae5a-d315-4216-875b-ed9b6a5bcfc6', - key='key1', **expected) - - def test_update_flavor_extra_spec_str_body(self): - self._test_update_flavor_extra_spec(bytes_body=False) - - def test_update_flavor_extra_spec_byte_body(self): - self._test_update_flavor_extra_spec(bytes_body=True) - - def test_unset_flavor_extra_spec(self): - self.check_service_client_function( - self.client.unset_flavor_extra_spec, - 'tempest.lib.common.rest_client.RestClient.delete', {}, - flavor_id='c782b7a9-33cd-45f0-b795-7f87f456408b', key='key') - - def _test_list_flavor_access(self, bytes_body=False): - expected = {'flavor_access': [TestFlavorsClient.FAKE_FLAVOR_ACCESS]} - self.check_service_client_function( - self.client.list_flavor_access, - 'tempest.lib.common.rest_client.RestClient.get', - expected, - bytes_body, - flavor_id='8c7aae5a-d315-4216-875b-ed9b6a5bcfc6') - - def test_list_flavor_access_str_body(self): - self._test_list_flavor_access(bytes_body=False) - - def test_list_flavor_access_byte_body(self): - self._test_list_flavor_access(bytes_body=True) - - def _test_add_flavor_access(self, bytes_body=False): - expected = { - "flavor_access": [TestFlavorsClient.FAKE_FLAVOR_ACCESS] - } - self.check_service_client_function( - self.client.add_flavor_access, - 'tempest.lib.common.rest_client.RestClient.post', - expected, - bytes_body, - flavor_id='8c7aae5a-d315-4216-875b-ed9b6a5bcfc6', - tenant_id='1a951d988e264818afe520e78697dcbf') - - def test_add_flavor_access_str_body(self): - self._test_add_flavor_access(bytes_body=False) - - def test_add_flavor_access_byte_body(self): - self._test_add_flavor_access(bytes_body=True) - - def _test_remove_flavor_access(self, bytes_body=False): - expected = { - "flavor_access": [TestFlavorsClient.FAKE_FLAVOR_ACCESS] - } - self.check_service_client_function( - self.client.remove_flavor_access, - 'tempest.lib.common.rest_client.RestClient.post', - expected, - bytes_body, - flavor_id='10', - tenant_id='a6edd4d66ad04245b5d2d8716ecc91e3') - - def test_remove_flavor_access_str_body(self): - self._test_remove_flavor_access(bytes_body=False) - - def test_remove_flavor_access_byte_body(self): - self._test_remove_flavor_access(bytes_body=True) diff --git a/tempest/tests/lib/services/compute/test_floating_ip_pools_client.py b/tempest/tests/lib/services/compute/test_floating_ip_pools_client.py deleted file mode 100644 index b0c00f099..000000000 --- a/tempest/tests/lib/services/compute/test_floating_ip_pools_client.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 tempest.lib.services.compute import floating_ip_pools_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestFloatingIPPoolsClient(base.BaseServiceTest): - - FAKE_FLOATING_IP_POOLS = { - "floating_ip_pools": - [ - {"name": u'\u3042'}, - {"name": u'\u3044'} - ] - } - - def setUp(self): - super(TestFloatingIPPoolsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = floating_ip_pools_client.FloatingIPPoolsClient( - fake_auth, 'compute', 'regionOne') - - def test_list_floating_ip_pools_with_str_body(self): - self.check_service_client_function( - self.client.list_floating_ip_pools, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_FLOATING_IP_POOLS) - - def test_list_floating_ip_pools_with_bytes_body(self): - self.check_service_client_function( - self.client.list_floating_ip_pools, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_FLOATING_IP_POOLS, to_utf=True) diff --git a/tempest/tests/lib/services/compute/test_floating_ips_bulk_client.py b/tempest/tests/lib/services/compute/test_floating_ips_bulk_client.py deleted file mode 100644 index ace76f89a..000000000 --- a/tempest/tests/lib/services/compute/test_floating_ips_bulk_client.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 tempest.tests.lib import fake_auth_provider - -from tempest.lib.services.compute import floating_ips_bulk_client -from tempest.tests.lib.services import base - - -class TestFloatingIPsBulkClient(base.BaseServiceTest): - - FAKE_FIP_BULK_LIST = {"floating_ip_info": [{ - "address": "10.10.10.1", - "instance_uuid": None, - "fixed_ip": None, - "interface": "eth0", - "pool": "nova", - "project_id": None - }, - { - "address": "10.10.10.2", - "instance_uuid": None, - "fixed_ip": None, - "interface": "eth0", - "pool": "nova", - "project_id": None - }]} - - def setUp(self): - super(TestFloatingIPsBulkClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = floating_ips_bulk_client.FloatingIPsBulkClient( - fake_auth, 'compute', 'regionOne') - - def _test_list_floating_ips_bulk(self, bytes_body=False): - self.check_service_client_function( - self.client.list_floating_ips_bulk, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_FIP_BULK_LIST, - to_utf=bytes_body) - - def _test_create_floating_ips_bulk(self, bytes_body=False): - fake_fip_create_data = {"floating_ips_bulk_create": { - "ip_range": "192.168.1.0/24", "pool": "nova", "interface": "eth0"}} - self.check_service_client_function( - self.client.create_floating_ips_bulk, - 'tempest.lib.common.rest_client.RestClient.post', - fake_fip_create_data, - to_utf=bytes_body, - ip_range="192.168.1.0/24", pool="nova", interface="eth0") - - def _test_delete_floating_ips_bulk(self, bytes_body=False): - fake_fip_delete_data = {"floating_ips_bulk_delete": "192.168.1.0/24"} - self.check_service_client_function( - self.client.delete_floating_ips_bulk, - 'tempest.lib.common.rest_client.RestClient.put', - fake_fip_delete_data, - to_utf=bytes_body, - ip_range="192.168.1.0/24") - - def test_list_floating_ips_bulk_with_str_body(self): - self._test_list_floating_ips_bulk() - - def test_list_floating_ips_bulk_with_bytes_body(self): - self._test_list_floating_ips_bulk(True) - - def test_create_floating_ips_bulk_with_str_body(self): - self._test_create_floating_ips_bulk() - - def test_create_floating_ips_bulk_with_bytes_body(self): - self._test_create_floating_ips_bulk(True) - - def test_delete_floating_ips_bulk_with_str_body(self): - self._test_delete_floating_ips_bulk() - - def test_delete_floating_ips_bulk_with_bytes_body(self): - self._test_delete_floating_ips_bulk(True) diff --git a/tempest/tests/lib/services/compute/test_floating_ips_client.py b/tempest/tests/lib/services/compute/test_floating_ips_client.py deleted file mode 100644 index 950f9ce7b..000000000 --- a/tempest/tests/lib/services/compute/test_floating_ips_client.py +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright 2015 IBM Corp. -# -# 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 fixtures - -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.compute import floating_ips_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestFloatingIpsClient(base.BaseServiceTest): - - floating_ip = {"fixed_ip": None, - "id": "46d61064-13ba-4bf0-9557-69de824c3d6f", - "instance_id": "a1daa443-a6bb-463e-aea2-104b7d912eb8", - "ip": "10.10.10.1", - "pool": "nova"} - - def setUp(self): - super(TestFloatingIpsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = floating_ips_client.FloatingIPsClient( - fake_auth, 'compute', 'regionOne') - - def _test_list_floating_ips(self, bytes_body=False): - expected = {'floating_ips': [TestFloatingIpsClient.floating_ip]} - self.check_service_client_function( - self.client.list_floating_ips, - 'tempest.lib.common.rest_client.RestClient.get', - expected, - bytes_body) - - def test_list_floating_ips_str_body(self): - self._test_list_floating_ips(bytes_body=False) - - def test_list_floating_ips_byte_body(self): - self._test_list_floating_ips(bytes_body=True) - - def _test_show_floating_ip(self, bytes_body=False): - expected = {"floating_ip": TestFloatingIpsClient.floating_ip} - self.check_service_client_function( - self.client.show_floating_ip, - 'tempest.lib.common.rest_client.RestClient.get', - expected, - bytes_body, - floating_ip_id='a1daa443-a6bb-463e-aea2-104b7d912eb8') - - def test_show_floating_ip_str_body(self): - self._test_show_floating_ip(bytes_body=False) - - def test_show_floating_ip_byte_body(self): - self._test_show_floating_ip(bytes_body=True) - - def _test_create_floating_ip(self, bytes_body=False): - expected = {"floating_ip": TestFloatingIpsClient.floating_ip} - self.check_service_client_function( - self.client.create_floating_ip, - 'tempest.lib.common.rest_client.RestClient.post', - expected, - bytes_body, - pool_name='nova') - - def test_create_floating_ip_str_body(self): - self._test_create_floating_ip(bytes_body=False) - - def test_create_floating_ip_byte_body(self): - self._test_create_floating_ip(bytes_body=True) - - def test_delete_floating_ip(self): - self.check_service_client_function( - self.client.delete_floating_ip, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, status=202, floating_ip_id='fake-id') - - def test_associate_floating_ip_to_server(self): - self.check_service_client_function( - self.client.associate_floating_ip_to_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, status=202, floating_ip='10.10.10.1', - server_id='c782b7a9-33cd-45f0-b795-7f87f456408b') - - def test_disassociate_floating_ip_from_server(self): - self.check_service_client_function( - self.client.disassociate_floating_ip_from_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, status=202, floating_ip='10.10.10.1', - server_id='c782b7a9-33cd-45f0-b795-7f87f456408b') - - def test_is_resource_deleted_true(self): - self.useFixture(fixtures.MockPatch( - 'tempest.lib.services.compute.floating_ips_client.' - 'FloatingIPsClient.show_floating_ip', - side_effect=lib_exc.NotFound())) - self.assertTrue(self.client.is_resource_deleted('fake-id')) - - def test_is_resource_deleted_false(self): - self.useFixture(fixtures.MockPatch( - 'tempest.lib.services.compute.floating_ips_client.' - 'FloatingIPsClient.show_floating_ip', - return_value={"floating_ip": TestFloatingIpsClient.floating_ip})) - self.assertFalse(self.client.is_resource_deleted('fake-id')) diff --git a/tempest/tests/lib/services/compute/test_hosts_client.py b/tempest/tests/lib/services/compute/test_hosts_client.py deleted file mode 100644 index 78537c297..000000000 --- a/tempest/tests/lib/services/compute/test_hosts_client.py +++ /dev/null @@ -1,147 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 tempest.lib.services.compute import hosts_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestHostsClient(base.BaseServiceTest): - FAKE_HOST_DATA = { - "host": { - "resource": { - "cpu": 1, - "disk_gb": 1028, - "host": "c1a7de0ac9d94e4baceae031d05caae3", - "memory_mb": 8192, - "project": "(total)" - } - }, - "hosts": { - "host_name": "c1a7de0ac9d94e4baceae031d05caae3", - "service": "conductor", - "zone": "internal" - }, - "enable_hosts": { - "host": "65c5d5b7e3bd44308e67fc50f362aee6", - "maintenance_mode": "off_maintenance", - "status": "enabled" - } - } - - FAKE_CONTROL_DATA = { - "shutdown": { - "host": "c1a7de0ac9d94e4baceae031d05caae3", - "power_action": "shutdown" - }, - "startup": { - "host": "c1a7de0ac9d94e4baceae031d05caae3", - "power_action": "startup" - }, - "reboot": { - "host": "c1a7de0ac9d94e4baceae031d05caae3", - "power_action": "reboot" - }} - - HOST_DATA = {'host': [FAKE_HOST_DATA['host']]} - HOSTS_DATA = {'hosts': [FAKE_HOST_DATA['hosts']]} - ENABLE_HOST_DATA = FAKE_HOST_DATA['enable_hosts'] - HOST_ID = "c1a7de0ac9d94e4baceae031d05caae3" - TEST_HOST_DATA = { - "status": "enable", - "maintenance_mode": "disable" - } - - def setUp(self): - super(TestHostsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = hosts_client.HostsClient(fake_auth, 'compute', - 'regionOne') - self.params = {'hostname': self.HOST_ID} - self.func2mock = { - 'get': 'tempest.lib.common.rest_client.RestClient.get', - 'put': 'tempest.lib.common.rest_client.RestClient.put'} - - def _test_host_data(self, test_type='list', bytes_body=False): - expected_resp = self.HOST_DATA - if test_type != 'list': - function_call = self.client.show_host - else: - expected_resp = self.HOSTS_DATA - function_call = self.client.list_hosts - self.params = {'host_name': self.HOST_ID} - - self.check_service_client_function( - function_call, self.func2mock['get'], - expected_resp, bytes_body, - 200, **self.params) - - def _test_update_hosts(self, bytes_body=False): - expected_resp = self.ENABLE_HOST_DATA - self.check_service_client_function( - self.client.update_host, self.func2mock['put'], - expected_resp, bytes_body, - 200, **self.params) - - def _test_control_host(self, control_op='reboot', bytes_body=False): - if control_op == 'start': - expected_resp = self.FAKE_CONTROL_DATA['startup'] - function_call = self.client.startup_host - elif control_op == 'stop': - expected_resp = self.FAKE_CONTROL_DATA['shutdown'] - function_call = self.client.shutdown_host - else: - expected_resp = self.FAKE_CONTROL_DATA['reboot'] - function_call = self.client.reboot_host - - self.check_service_client_function( - function_call, self.func2mock['get'], - expected_resp, bytes_body, - 200, **self.params) - - def test_show_host_with_str_body(self): - self._test_host_data('show') - - def test_show_host_with_bytes_body(self): - self._test_host_data('show', True) - - def test_list_host_with_str_body(self): - self._test_host_data() - - def test_list_host_with_bytes_body(self): - self._test_host_data(bytes_body=True) - - def test_start_host_with_str_body(self): - self._test_control_host('start') - - def test_start_host_with_bytes_body(self): - self._test_control_host('start', True) - - def test_stop_host_with_str_body(self): - self._test_control_host('stop') - - def test_stop_host_with_bytes_body(self): - self._test_control_host('stop', True) - - def test_reboot_host_with_str_body(self): - self._test_control_host('reboot') - - def test_reboot_host_with_bytes_body(self): - self._test_control_host('reboot', True) - - def test_update_host_with_str_body(self): - self._test_update_hosts() - - def test_update_host_with_bytes_body(self): - self._test_update_hosts(True) diff --git a/tempest/tests/lib/services/compute/test_hypervisor_client.py b/tempest/tests/lib/services/compute/test_hypervisor_client.py deleted file mode 100644 index 89eb698a4..000000000 --- a/tempest/tests/lib/services/compute/test_hypervisor_client.py +++ /dev/null @@ -1,167 +0,0 @@ -# Copyright 2015 IBM Corp. -# -# 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 tempest.lib.services.compute import hypervisor_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestHypervisorClient(base.BaseServiceTest): - - hypervisor_id = "1" - hypervisor_name = "hyper.hostname.com" - - def setUp(self): - super(TestHypervisorClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = hypervisor_client.HypervisorClient( - fake_auth, 'compute', 'regionOne') - - def test_list_hypervisor_str_body(self): - self._test_list_hypervisor(bytes_body=False) - - def test_list_hypervisor_byte_body(self): - self._test_list_hypervisor(bytes_body=True) - - def _test_list_hypervisor(self, bytes_body=False): - expected = {"hypervisors": [{ - "id": 1, - "hypervisor_hostname": "hypervisor1.hostname.com"}, - { - "id": 2, - "hypervisor_hostname": "hypervisor2.hostname.com"}]} - self.check_service_client_function( - self.client.list_hypervisors, - 'tempest.lib.common.rest_client.RestClient.get', - expected, bytes_body) - - def test_show_hypervisor_str_body(self): - self._test_show_hypervisor(bytes_body=False) - - def test_show_hypervisor_byte_body(self): - self._test_show_hypervisor(bytes_body=True) - - def _test_show_hypervisor(self, bytes_body=False): - expected = {"hypervisor": { - "cpu_info": "?", - "current_workload": 0, - "disk_available_least": 1, - "host_ip": "10.10.10.10", - "free_disk_gb": 1028, - "free_ram_mb": 7680, - "hypervisor_hostname": "fake-mini", - "hypervisor_type": "fake", - "hypervisor_version": 1, - "id": 1, - "local_gb": 1028, - "local_gb_used": 0, - "memory_mb": 8192, - "memory_mb_used": 512, - "running_vms": 0, - "service": { - "host": "fake_host", - "id": 2}, - "vcpus": 1, - "vcpus_used": 0}} - self.check_service_client_function( - self.client.show_hypervisor, - 'tempest.lib.common.rest_client.RestClient.get', - expected, bytes_body, - hypervisor_id=self.hypervisor_id) - - def test_list_servers_on_hypervisor_str_body(self): - self._test_list_servers_on_hypervisor(bytes_body=False) - - def test_list_servers_on_hypervisor_byte_body(self): - self._test_list_servers_on_hypervisor(bytes_body=True) - - def _test_list_servers_on_hypervisor(self, bytes_body=False): - expected = {"hypervisors": [{ - "id": 1, - "hypervisor_hostname": "hyper.hostname.com", - "servers": [{ - "uuid": "e1ae8fc4-b72d-4c2f-a427-30dd420b6277", - "name": "instance-00000001"}, - { - "uuid": "e1ae8fc4-b72d-4c2f-a427-30dd42066666", - "name": "instance-00000002"} - ]} - ]} - self.check_service_client_function( - self.client.list_servers_on_hypervisor, - 'tempest.lib.common.rest_client.RestClient.get', - expected, bytes_body, - hypervisor_name=self.hypervisor_name) - - def test_show_hypervisor_statistics_str_body(self): - self._test_show_hypervisor_statistics(bytes_body=False) - - def test_show_hypervisor_statistics_byte_body(self): - self._test_show_hypervisor_statistics(bytes_body=True) - - def _test_show_hypervisor_statistics(self, bytes_body=False): - expected = { - "hypervisor_statistics": { - "count": 1, - "current_workload": 0, - "disk_available_least": 0, - "free_disk_gb": 1028, - "free_ram_mb": 7680, - "local_gb": 1028, - "local_gb_used": 0, - "memory_mb": 8192, - "memory_mb_used": 512, - "running_vms": 0, - "vcpus": 1, - "vcpus_used": 0}} - self.check_service_client_function( - self.client.show_hypervisor_statistics, - 'tempest.lib.common.rest_client.RestClient.get', - expected, bytes_body) - - def test_show_hypervisor_uptime_str_body(self): - self._test_show_hypervisor_uptime(bytes_body=False) - - def test_show_hypervisor_uptime_byte_body(self): - self._test_show_hypervisor_uptime(bytes_body=True) - - def _test_show_hypervisor_uptime(self, bytes_body=False): - expected = { - "hypervisor": { - "hypervisor_hostname": "fake-mini", - "id": 1, - "uptime": (" 08:32:11 up 93 days, 18:25, 12 users, " - " load average: 0.20, 0.12, 0.14") - }} - self.check_service_client_function( - self.client.show_hypervisor_uptime, - 'tempest.lib.common.rest_client.RestClient.get', - expected, bytes_body, - hypervisor_id=self.hypervisor_id) - - def test_search_hypervisor_str_body(self): - self._test_search_hypervisor(bytes_body=False) - - def test_search_hypervisor_byte_body(self): - self._test_search_hypervisor(bytes_body=True) - - def _test_search_hypervisor(self, bytes_body=False): - expected = {"hypervisors": [{ - "id": 2, - "hypervisor_hostname": "hyper.hostname.com"}]} - self.check_service_client_function( - self.client.search_hypervisor, - 'tempest.lib.common.rest_client.RestClient.get', - expected, bytes_body, - hypervisor_name=self.hypervisor_name) diff --git a/tempest/tests/lib/services/compute/test_images_client.py b/tempest/tests/lib/services/compute/test_images_client.py deleted file mode 100644 index c2c3b7618..000000000 --- a/tempest/tests/lib/services/compute/test_images_client.py +++ /dev/null @@ -1,264 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 copy - -import fixtures -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.compute import images_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestImagesClient(base.BaseServiceTest): - # Data Dictionaries used for testing # - FAKE_IMAGE_METADATA = { - "list": - {"metadata": { - "auto_disk_config": "True", - "Label": "Changed" - }}, - "set_item": - {"meta": { - "auto_disk_config": "True" - }}, - "show_item": - {"meta": { - "kernel_id": "nokernel", - }}, - "update": - {"metadata": { - "kernel_id": "False", - "Label": "UpdatedImage" - }}, - "set": - {"metadata": { - "Label": "Changed", - "auto_disk_config": "True" - }}, - "delete_item": {} - } - - FAKE_IMAGE_DATA = { - "list": - {"images": [ - {"id": "70a599e0-31e7-49b7-b260-868f441e862b", - "links": [ - {"href": "http://openstack.example.com/v2/openstack" + - "/images/70a599e0-31e7-49b7-b260-868f441e862b", - "rel": "self" - } - ], - "name": "fakeimage7" - }]}, - "show": {"image": { - "created": "2011-01-01T01:02:03Z", - "id": "70a599e0-31e7-49b7-b260-868f441e862b", - "links": [ - { - "href": "http://openstack.example.com/v2/openstack" + - "/images/70a599e0-31e7-49b7-b260-868f441e862b", - "rel": "self" - }, - ], - "metadata": { - "architecture": "x86_64", - "auto_disk_config": "True", - "kernel_id": "nokernel", - "ramdisk_id": "nokernel" - }, - "minDisk": 0, - "minRam": 0, - "name": "fakeimage7", - "progress": 100, - "status": "ACTIVE", - "updated": "2011-01-01T01:02:03Z"}}, - "create": {}, - "delete": {} - } - func2mock = { - 'get': 'tempest.lib.common.rest_client.RestClient.get', - 'post': 'tempest.lib.common.rest_client.RestClient.post', - 'put': 'tempest.lib.common.rest_client.RestClient.put', - 'delete': 'tempest.lib.common.rest_client.RestClient.delete'} - # Variable definition - FAKE_IMAGE_ID = FAKE_IMAGE_DATA['show']['image']['id'] - FAKE_SERVER_ID = "80a599e0-31e7-49b7-b260-868f441e343f" - FAKE_CREATE_INFO = {'location': 'None'} - FAKE_METADATA = FAKE_IMAGE_METADATA['show_item']['meta'] - - def setUp(self): - super(TestImagesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = images_client.ImagesClient(fake_auth, - "compute", "regionOne") - - def _test_image_operation(self, operation="delete", bytes_body=False): - response_code = 200 - mock_operation = self.func2mock['get'] - expected_op = self.FAKE_IMAGE_DATA[operation] - params = {"image_id": self.FAKE_IMAGE_ID} - headers = None - if operation == 'list': - function = self.client.list_images - elif operation == 'show': - function = self.client.show_image - elif operation == 'create': - function = self.client.create_image - mock_operation = self.func2mock['post'] - params = {"server_id": self.FAKE_SERVER_ID} - response_code = 202 - headers = { - 'connection': 'keep-alive', - 'content-length': '0', - 'content-type': 'application/json', - 'status': '202', - 'x-compute-request-id': 'req-fake', - 'vary': 'accept-encoding', - 'x-openstack-nova-api-version': 'v2.1', - 'date': '13 Oct 2015 05:55:36 GMT', - 'location': 'http://fake.com/images/fake' - } - else: - function = self.client.delete_image - mock_operation = self.func2mock['delete'] - response_code = 204 - - self.check_service_client_function( - function, mock_operation, expected_op, - bytes_body, response_code, headers, **params) - - def _test_image_metadata(self, operation="set_item", bytes_body=False): - response_code = 200 - expected_op = self.FAKE_IMAGE_METADATA[operation] - if operation == 'list': - function = self.client.list_image_metadata - mock_operation = self.func2mock['get'] - params = {"image_id": self.FAKE_IMAGE_ID} - - elif operation == 'set': - function = self.client.set_image_metadata - mock_operation = self.func2mock['put'] - params = {"image_id": "_dummy_data", - "meta": self.FAKE_METADATA} - - elif operation == 'update': - function = self.client.update_image_metadata - mock_operation = self.func2mock['post'] - params = {"image_id": self.FAKE_IMAGE_ID, - "meta": self.FAKE_METADATA} - - elif operation == 'show_item': - mock_operation = self.func2mock['get'] - function = self.client.show_image_metadata_item - params = {"image_id": self.FAKE_IMAGE_ID, - "key": "123"} - - elif operation == 'delete_item': - function = self.client.delete_image_metadata_item - mock_operation = self.func2mock['delete'] - response_code = 204 - params = {"image_id": self.FAKE_IMAGE_ID, - "key": "123"} - - else: - function = self.client.set_image_metadata_item - mock_operation = self.func2mock['put'] - params = {"image_id": self.FAKE_IMAGE_ID, - "key": "123", - "meta": self.FAKE_METADATA} - - self.check_service_client_function( - function, mock_operation, expected_op, - bytes_body, response_code, **params) - - def _test_resource_deleted(self, bytes_body=False): - params = {"id": self.FAKE_IMAGE_ID} - expected_op = self.FAKE_IMAGE_DATA['show'] - self.useFixture(fixtures.MockPatch('tempest.lib.services.compute' - '.images_client.ImagesClient.show_image', - side_effect=lib_exc.NotFound)) - self.assertEqual(True, self.client.is_resource_deleted(**params)) - tempdata = copy.deepcopy(self.FAKE_IMAGE_DATA['show']) - tempdata['image']['id'] = None - self.useFixture(fixtures.MockPatch('tempest.lib.services.compute' - '.images_client.ImagesClient.show_image', - return_value=expected_op)) - self.assertEqual(False, self.client.is_resource_deleted(**params)) - - def test_list_images_with_str_body(self): - self._test_image_operation('list') - - def test_list_images_with_bytes_body(self): - self._test_image_operation('list', True) - - def test_show_image_with_str_body(self): - self._test_image_operation('show') - - def test_show_image_with_bytes_body(self): - self._test_image_operation('show', True) - - def test_create_image_with_str_body(self): - self._test_image_operation('create') - - def test_create_image_with_bytes_body(self): - self._test_image_operation('create', True) - - def test_delete_image_with_str_body(self): - self._test_image_operation('delete') - - def test_delete_image_with_bytes_body(self): - self._test_image_operation('delete', True) - - def test_list_image_metadata_with_str_body(self): - self._test_image_metadata('list') - - def test_list_image_metadata_with_bytes_body(self): - self._test_image_metadata('list', True) - - def test_set_image_metadata_with_str_body(self): - self._test_image_metadata('set') - - def test_set_image_metadata_with_bytes_body(self): - self._test_image_metadata('set', True) - - def test_update_image_metadata_with_str_body(self): - self._test_image_metadata('update') - - def test_update_image_metadata_with_bytes_body(self): - self._test_image_metadata('update', True) - - def test_set_image_metadata_item_with_str_body(self): - self._test_image_metadata() - - def test_set_image_metadata_item_with_bytes_body(self): - self._test_image_metadata(bytes_body=True) - - def test_show_image_metadata_item_with_str_body(self): - self._test_image_metadata('show_item') - - def test_show_image_metadata_item_with_bytes_body(self): - self._test_image_metadata('show_item', True) - - def test_delete_image_metadata_item_with_str_body(self): - self._test_image_metadata('delete_item') - - def test_delete_image_metadata_item_with_bytes_body(self): - self._test_image_metadata('delete_item', True) - - def test_resource_delete_with_str_body(self): - self._test_resource_deleted() - - def test_resource_delete_with_bytes_body(self): - self._test_resource_deleted(True) diff --git a/tempest/tests/lib/services/compute/test_instance_usage_audit_log_client.py b/tempest/tests/lib/services/compute/test_instance_usage_audit_log_client.py deleted file mode 100644 index 21764ff5e..000000000 --- a/tempest/tests/lib/services/compute/test_instance_usage_audit_log_client.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 datetime - -from tempest.lib.services.compute import instance_usage_audit_log_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestInstanceUsagesAuditLogClient(base.BaseServiceTest): - - FAKE_AUDIT_LOG = { - "hosts_not_run": [ - "f4eb7cfd155f4574967f8b55a7faed75" - ], - "log": {}, - "num_hosts": 1, - "num_hosts_done": 0, - "num_hosts_not_run": 1, - "num_hosts_running": 0, - "overall_status": "0 of 1 hosts done. 0 errors.", - "period_beginning": "2012-12-01 00:00:00", - "period_ending": "2013-01-01 00:00:00", - "total_errors": 0, - "total_instances": 0 - } - - def setUp(self): - super(TestInstanceUsagesAuditLogClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = (instance_usage_audit_log_client. - InstanceUsagesAuditLogClient(fake_auth, 'compute', - 'regionOne')) - - def _test_list_instance_usage_audit_logs(self, bytes_body=False): - self.check_service_client_function( - self.client.list_instance_usage_audit_logs, - 'tempest.lib.common.rest_client.RestClient.get', - {"instance_usage_audit_logs": self.FAKE_AUDIT_LOG}, - bytes_body) - - def test_list_instance_usage_audit_logs_with_str_body(self): - self._test_list_instance_usage_audit_logs() - - def test_list_instance_usage_audit_logs_with_bytes_body(self): - self._test_list_instance_usage_audit_logs(bytes_body=True) - - def _test_show_instance_usage_audit_log(self, bytes_body=False): - before_time = datetime.datetime(2012, 12, 1, 0, 0) - self.check_service_client_function( - self.client.show_instance_usage_audit_log, - 'tempest.lib.common.rest_client.RestClient.get', - {"instance_usage_audit_log": self.FAKE_AUDIT_LOG}, - bytes_body, - time_before=before_time) - - def test_show_instance_usage_audit_log_with_str_body(self): - self._test_show_instance_usage_audit_log() - - def test_show_network_with_bytes_body_with_bytes_body(self): - self._test_show_instance_usage_audit_log(bytes_body=True) diff --git a/tempest/tests/lib/services/compute/test_interfaces_client.py b/tempest/tests/lib/services/compute/test_interfaces_client.py deleted file mode 100644 index 4d781033c..000000000 --- a/tempest/tests/lib/services/compute/test_interfaces_client.py +++ /dev/null @@ -1,98 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 tempest.lib.services.compute import interfaces_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestInterfacesClient(base.BaseServiceTest): - # Data Values to be used for testing # - FAKE_INTERFACE_DATA = { - "fixed_ips": [{ - "ip_address": "192.168.1.1", - "subnet_id": "f8a6e8f8-c2ec-497c-9f23-da9616de54ef" - }], - "mac_addr": "fa:16:3e:4c:2c:30", - "net_id": "3cb9bc59-5699-4588-a4b1-b87f96708bc6", - "port_id": "ce531f90-199f-48c0-816c-13e38010b442", - "port_state": "ACTIVE"} - - FAKE_SHOW_DATA = { - "interfaceAttachment": FAKE_INTERFACE_DATA} - FAKE_LIST_DATA = { - "interfaceAttachments": [FAKE_INTERFACE_DATA]} - - FAKE_SERVER_ID = "ec14c864-096e-4e27-bb8a-2c2b4dc6f3f5" - FAKE_PORT_ID = FAKE_SHOW_DATA['interfaceAttachment']['port_id'] - func2mock = { - 'delete': 'tempest.lib.common.rest_client.RestClient.delete', - 'get': 'tempest.lib.common.rest_client.RestClient.get', - 'post': 'tempest.lib.common.rest_client.RestClient.post'} - - def setUp(self): - super(TestInterfacesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = interfaces_client.InterfacesClient(fake_auth, - "compute", - "regionOne") - - def _test_interface_operation(self, operation="create", bytes_body=False): - response_code = 200 - expected_op = self.FAKE_SHOW_DATA - mock_operation = self.func2mock['get'] - params = {'server_id': self.FAKE_SERVER_ID, - 'port_id': self.FAKE_PORT_ID} - if operation == 'list': - expected_op = self.FAKE_LIST_DATA - function = self.client.list_interfaces - params = {'server_id': self.FAKE_SERVER_ID} - elif operation == 'show': - function = self.client.show_interface - elif operation == 'delete': - expected_op = {} - mock_operation = self.func2mock['delete'] - function = self.client.delete_interface - response_code = 202 - else: - function = self.client.create_interface - mock_operation = self.func2mock['post'] - - self.check_service_client_function( - function, mock_operation, expected_op, - bytes_body, response_code, **params) - - def test_list_interfaces_with_str_body(self): - self._test_interface_operation('list') - - def test_list_interfaces_with_bytes_body(self): - self._test_interface_operation('list', True) - - def test_show_interface_with_str_body(self): - self._test_interface_operation('show') - - def test_show_interface_with_bytes_body(self): - self._test_interface_operation('show', True) - - def test_delete_interface_with_str_body(self): - self._test_interface_operation('delete') - - def test_delete_interface_with_bytes_body(self): - self._test_interface_operation('delete', True) - - def test_create_interface_with_str_body(self): - self._test_interface_operation() - - def test_create_interface_with_bytes_body(self): - self._test_interface_operation(bytes_body=True) diff --git a/tempest/tests/lib/services/compute/test_keypairs_client.py b/tempest/tests/lib/services/compute/test_keypairs_client.py deleted file mode 100644 index ed3b9dd7f..000000000 --- a/tempest/tests/lib/services/compute/test_keypairs_client.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 copy - -from tempest.lib.services.compute import keypairs_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestKeyPairsClient(base.BaseServiceTest): - - FAKE_KEYPAIR = {"keypair": { - "public_key": "ssh-rsa foo Generated-by-Nova", - "name": u'\u2740(*\xb4\u25e1`*)\u2740', - "user_id": "525d55f98980415ba98e634972fa4a10", - "fingerprint": "76:24:66:49:d7:ca:6e:5c:77:ea:8e:bb:9c:15:5f:98" - }} - - def setUp(self): - super(TestKeyPairsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = keypairs_client.KeyPairsClient( - fake_auth, 'compute', 'regionOne') - - def _test_list_keypairs(self, bytes_body=False): - self.check_service_client_function( - self.client.list_keypairs, - 'tempest.lib.common.rest_client.RestClient.get', - {"keypairs": []}, - bytes_body) - - def test_list_keypairs_with_str_body(self): - self._test_list_keypairs() - - def test_list_keypairs_with_bytes_body(self): - self._test_list_keypairs(bytes_body=True) - - def _test_show_keypair(self, bytes_body=False): - fake_keypair = copy.deepcopy(self.FAKE_KEYPAIR) - fake_keypair["keypair"].update({ - "deleted": False, - "created_at": "2015-07-22T04:53:52.000000", - "updated_at": None, - "deleted_at": None, - "id": 1 - }) - - self.check_service_client_function( - self.client.show_keypair, - 'tempest.lib.common.rest_client.RestClient.get', - fake_keypair, - bytes_body, - keypair_name="test") - - def test_show_keypair_with_str_body(self): - self._test_show_keypair() - - def test_show_keypair_with_bytes_body(self): - self._test_show_keypair(bytes_body=True) - - def _test_create_keypair(self, bytes_body=False): - fake_keypair = copy.deepcopy(self.FAKE_KEYPAIR) - fake_keypair["keypair"].update({"private_key": "foo"}) - - self.check_service_client_function( - self.client.create_keypair, - 'tempest.lib.common.rest_client.RestClient.post', - fake_keypair, - bytes_body, - name="test") - - def test_create_keypair_with_str_body(self): - self._test_create_keypair() - - def test_create_keypair_with_bytes_body(self): - self._test_create_keypair(bytes_body=True) - - def test_delete_keypair(self): - self.check_service_client_function( - self.client.delete_keypair, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, status=202, keypair_name='test') diff --git a/tempest/tests/lib/services/compute/test_limits_client.py b/tempest/tests/lib/services/compute/test_limits_client.py deleted file mode 100644 index 5f3fa5a9c..000000000 --- a/tempest/tests/lib/services/compute/test_limits_client.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 tempest.lib.services.compute import limits_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestLimitsClient(base.BaseServiceTest): - - def setUp(self): - super(TestLimitsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = limits_client.LimitsClient( - fake_auth, 'compute', 'regionOne') - - def _test_show_limits(self, bytes_body=False): - expected = { - "limits": { - "rate": [], - "absolute": { - "maxServerMeta": 128, - "maxPersonality": 5, - "totalServerGroupsUsed": 0, - "maxImageMeta": 128, - "maxPersonalitySize": 10240, - "maxServerGroups": 10, - "maxSecurityGroupRules": 20, - "maxTotalKeypairs": 100, - "totalCoresUsed": 0, - "totalRAMUsed": 0, - "totalInstancesUsed": 0, - "maxSecurityGroups": 10, - "totalFloatingIpsUsed": 0, - "maxTotalCores": 20, - "totalSecurityGroupsUsed": 0, - "maxTotalFloatingIps": 10, - "maxTotalInstances": 10, - "maxTotalRAMSize": 51200, - "maxServerGroupMembers": 10 - } - } - } - - self.check_service_client_function( - self.client.show_limits, - 'tempest.lib.common.rest_client.RestClient.get', - expected, - bytes_body) - - def test_show_limits_with_str_body(self): - self._test_show_limits() - - def test_show_limits_with_bytes_body(self): - self._test_show_limits(bytes_body=True) diff --git a/tempest/tests/lib/services/compute/test_migrations_client.py b/tempest/tests/lib/services/compute/test_migrations_client.py deleted file mode 100644 index be62c0cc6..000000000 --- a/tempest/tests/lib/services/compute/test_migrations_client.py +++ /dev/null @@ -1,52 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 tempest.lib.services.compute import migrations_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestMigrationsClient(base.BaseServiceTest): - FAKE_MIGRATION_INFO = {"migrations": [{ - "created_at": "2012-10-29T13:42:02", - "dest_compute": "compute2", - "dest_host": "1.2.3.4", - "dest_node": "node2", - "id": 1234, - "instance_uuid": "e9e4fdd7-f956-44ff-bfeb-d654a96ab3a2", - "new_instance_type_id": 2, - "old_instance_type_id": 1, - "source_compute": "compute1", - "source_node": "node1", - "status": "finished", - "updated_at": "2012-10-29T13:42:02"}]} - - def setUp(self): - super(TestMigrationsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.mg_client_obj = migrations_client.MigrationsClient( - fake_auth, 'compute', 'regionOne') - - def _test_list_migrations(self, bytes_body=False): - self.check_service_client_function( - self.mg_client_obj.list_migrations, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_MIGRATION_INFO, - bytes_body) - - def test_list_migration_with_str_body(self): - self._test_list_migrations() - - def test_list_migration_with_bytes_body(self): - self._test_list_migrations(True) diff --git a/tempest/tests/lib/services/compute/test_networks_client.py b/tempest/tests/lib/services/compute/test_networks_client.py deleted file mode 100644 index 1908b5754..000000000 --- a/tempest/tests/lib/services/compute/test_networks_client.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 tempest.lib.services.compute import networks_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestNetworksClient(base.BaseServiceTest): - - FAKE_NETWORK = { - "bridge": None, - "vpn_public_port": None, - "dhcp_start": None, - "bridge_interface": None, - "share_address": None, - "updated_at": None, - "id": "34d5ae1e-5659-49cf-af80-73bccd7d7ad3", - "cidr_v6": None, - "deleted_at": None, - "gateway": None, - "rxtx_base": None, - "label": u'30d7', - "priority": None, - "project_id": None, - "vpn_private_address": None, - "deleted": None, - "vlan": None, - "broadcast": None, - "netmask": None, - "injected": None, - "cidr": None, - "vpn_public_address": None, - "multi_host": None, - "enable_dhcp": None, - "dns2": None, - "created_at": None, - "host": None, - "mtu": None, - "gateway_v6": None, - "netmask_v6": None, - "dhcp_server": None, - "dns1": None - } - - network_id = "34d5ae1e-5659-49cf-af80-73bccd7d7ad3" - - FAKE_NETWORKS = [FAKE_NETWORK] - - def setUp(self): - super(TestNetworksClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = networks_client.NetworksClient( - fake_auth, 'compute', 'regionOne') - - def _test_list_networks(self, bytes_body=False): - fake_list = {"networks": self.FAKE_NETWORKS} - self.check_service_client_function( - self.client.list_networks, - 'tempest.lib.common.rest_client.RestClient.get', - fake_list, - bytes_body) - - def test_list_networks_with_str_body(self): - self._test_list_networks() - - def test_list_networks_with_bytes_body(self): - self._test_list_networks(bytes_body=True) - - def _test_show_network(self, bytes_body=False): - self.check_service_client_function( - self.client.show_network, - 'tempest.lib.common.rest_client.RestClient.get', - {"network": self.FAKE_NETWORK}, - bytes_body, - network_id=self.network_id - ) - - def test_show_network_with_str_body(self): - self._test_show_network() - - def test_show_network_with_bytes_body(self): - self._test_show_network(bytes_body=True) diff --git a/tempest/tests/lib/services/compute/test_quota_classes_client.py b/tempest/tests/lib/services/compute/test_quota_classes_client.py deleted file mode 100644 index 22d8b91a3..000000000 --- a/tempest/tests/lib/services/compute/test_quota_classes_client.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 copy - -from tempest.lib.services.compute import quota_classes_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestQuotaClassesClient(base.BaseServiceTest): - - FAKE_QUOTA_CLASS_SET = { - "injected_file_content_bytes": 10240, - "metadata_items": 128, - "server_group_members": 10, - "server_groups": 10, - "ram": 51200, - "floating_ips": 10, - "key_pairs": 100, - "id": u'\u2740(*\xb4\u25e1`*)\u2740', - "instances": 10, - "security_group_rules": 20, - "security_groups": 10, - "injected_files": 5, - "cores": 20, - "fixed_ips": -1, - "injected_file_path_bytes": 255, - } - - def setUp(self): - super(TestQuotaClassesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = quota_classes_client.QuotaClassesClient( - fake_auth, 'compute', 'regionOne') - - def _test_show_quota_class_set(self, bytes_body=False): - fake_body = {'quota_class_set': self.FAKE_QUOTA_CLASS_SET} - self.check_service_client_function( - self.client.show_quota_class_set, - 'tempest.lib.common.rest_client.RestClient.get', - fake_body, - bytes_body, - quota_class_id="test") - - def test_show_quota_class_set_with_str_body(self): - self._test_show_quota_class_set() - - def test_show_quota_class_set_with_bytes_body(self): - self._test_show_quota_class_set(bytes_body=True) - - def test_update_quota_class_set(self): - fake_quota_class_set = copy.deepcopy(self.FAKE_QUOTA_CLASS_SET) - fake_quota_class_set.pop("id") - fake_body = {'quota_class_set': fake_quota_class_set} - self.check_service_client_function( - self.client.update_quota_class_set, - 'tempest.lib.common.rest_client.RestClient.put', - fake_body, - quota_class_id="test") diff --git a/tempest/tests/lib/services/compute/test_quotas_client.py b/tempest/tests/lib/services/compute/test_quotas_client.py deleted file mode 100644 index bbb8eb7d2..000000000 --- a/tempest/tests/lib/services/compute/test_quotas_client.py +++ /dev/null @@ -1,146 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 copy - -from tempest.lib.services.compute import quotas_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestQuotasClient(base.BaseServiceTest): - - FAKE_QUOTA_SET = { - "quota_set": { - "injected_file_content_bytes": 10240, - "metadata_items": 128, - "server_group_members": 10, - "server_groups": 10, - "ram": 51200, - "floating_ips": 10, - "key_pairs": 100, - "id": "8421f7be61064f50b680465c07f334af", - "instances": 10, - "security_group_rules": 20, - "injected_files": 5, - "cores": 20, - "fixed_ips": -1, - "injected_file_path_bytes": 255, - "security_groups": 10} - } - - project_id = "8421f7be61064f50b680465c07f334af" - fake_user_id = "65f09168cbb04eb593f3138b63b67b67" - - def setUp(self): - super(TestQuotasClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = quotas_client.QuotasClient( - fake_auth, 'compute', 'regionOne') - - def _get_quota_set(self, detail): - if not detail: - return self.FAKE_QUOTA_SET - fake_quota_set = {"quota_set": {}} - for key, val in self.FAKE_QUOTA_SET['quota_set'].items(): - fake_quota_set['quota_set'][key] = \ - {'limit': val, 'reserved': 0, 'in_use': 0} - fake_quota_set['quota_set']['id'] = "8421f7be61064f50b680465c07f334af" - return fake_quota_set - - def _test_show_quota_set(self, bytes_body=False, detail=False, - user_id=None): - if user_id: - self.check_service_client_function( - self.client.show_quota_set, - 'tempest.lib.common.rest_client.RestClient.get', - self._get_quota_set(detail), - to_utf=bytes_body, - tenant_id=self.project_id, - detail=detail, - user_id=user_id) - else: - self.check_service_client_function( - self.client.show_quota_set, - 'tempest.lib.common.rest_client.RestClient.get', - self._get_quota_set(detail), - to_utf=bytes_body, - tenant_id=self.project_id, - detail=detail) - - def test_show_quota_set_with_str_body(self): - self._test_show_quota_set() - - def test_show_quota_set_with_bytes_body(self): - self._test_show_quota_set(bytes_body=True) - - def test_show_quota_set_for_user_with_str_body(self): - self._test_show_quota_set(user_id=self.fake_user_id) - - def test_show_quota_set_for_user_with_bytes_body(self): - self._test_show_quota_set(bytes_body=True, user_id=self.fake_user_id) - - def test_show_quota_set_with_details(self): - self._test_show_quota_set(detail=True) - - def _test_show_default_quota_set(self, bytes_body=False): - self.check_service_client_function( - self.client.show_default_quota_set, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_QUOTA_SET, - to_utf=bytes_body, - tenant_id=self.project_id) - - def test_show_default_quota_set_with_str_body(self): - self._test_show_default_quota_set() - - def test_show_default_quota_set_with_bytes_body(self): - self._test_show_default_quota_set(bytes_body=True) - - def _test_update_quota_set(self, bytes_body=False, user_id=None): - fake_quota_set = copy.deepcopy(self.FAKE_QUOTA_SET) - fake_quota_set['quota_set'].pop("id") - if user_id: - self.check_service_client_function( - self.client.update_quota_set, - 'tempest.lib.common.rest_client.RestClient.put', - fake_quota_set, - to_utf=bytes_body, - tenant_id=self.project_id, - user_id=user_id) - else: - self.check_service_client_function( - self.client.update_quota_set, - 'tempest.lib.common.rest_client.RestClient.put', - fake_quota_set, - to_utf=bytes_body, - tenant_id=self.project_id) - - def test_update_quota_set_with_str_body(self): - self._test_update_quota_set() - - def test_update_quota_set_with_bytes_body(self): - self._test_update_quota_set(bytes_body=True) - - def test_update_quota_set_for_user_with_str_body(self): - self._test_update_quota_set(user_id=self.fake_user_id) - - def test_update_quota_set_for_user_with_bytes_body(self): - self._test_update_quota_set(bytes_body=True, user_id=self.fake_user_id) - - def test_delete_quota_set(self): - self.check_service_client_function( - self.client.delete_quota_set, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, status=202, tenant_id=self.project_id) diff --git a/tempest/tests/lib/services/compute/test_security_group_default_rules_client.py b/tempest/tests/lib/services/compute/test_security_group_default_rules_client.py deleted file mode 100644 index 86eee0256..000000000 --- a/tempest/tests/lib/services/compute/test_security_group_default_rules_client.py +++ /dev/null @@ -1,88 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 tempest.lib.services.compute import security_group_default_rules_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSecurityGroupDefaultRulesClient(base.BaseServiceTest): - FAKE_RULE = { - "from_port": 80, - "id": 1, - "ip_protocol": "TCP", - "ip_range": { - "cidr": "10.10.10.0/24" - }, - "to_port": 80 - } - - def setUp(self): - super(TestSecurityGroupDefaultRulesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = (security_group_default_rules_client. - SecurityGroupDefaultRulesClient(fake_auth, 'compute', - 'regionOne')) - - def _test_list_security_group_default_rules(self, bytes_body=False): - self.check_service_client_function( - self.client.list_security_group_default_rules, - 'tempest.lib.common.rest_client.RestClient.get', - {"security_group_default_rules": [self.FAKE_RULE]}, - to_utf=bytes_body) - - def test_list_security_group_default_rules_with_str_body(self): - self._test_list_security_group_default_rules() - - def test_list_security_group_default_rules_with_bytes_body(self): - self._test_list_security_group_default_rules(bytes_body=True) - - def _test_show_security_group_default_rule(self, bytes_body=False): - self.check_service_client_function( - self.client.show_security_group_default_rule, - 'tempest.lib.common.rest_client.RestClient.get', - {"security_group_default_rule": self.FAKE_RULE}, - to_utf=bytes_body, - security_group_default_rule_id=1) - - def test_show_security_group_default_rule_with_str_body(self): - self._test_show_security_group_default_rule() - - def test_show_security_group_default_rule_with_bytes_body(self): - self._test_show_security_group_default_rule(bytes_body=True) - - def _test_create_security_default_group_rule(self, bytes_body=False): - request_body = { - "to_port": 80, - "from_port": 80, - "ip_protocol": "TCP", - "cidr": "10.10.10.0/24" - } - self.check_service_client_function( - self.client.create_security_default_group_rule, - 'tempest.lib.common.rest_client.RestClient.post', - {"security_group_default_rule": self.FAKE_RULE}, - to_utf=bytes_body, **request_body) - - def test_create_security_default_group_rule_with_str_body(self): - self._test_create_security_default_group_rule() - - def test_create_security_default_group_rule_with_bytes_body(self): - self._test_create_security_default_group_rule(bytes_body=True) - - def test_delete_security_group_default_rule(self): - self.check_service_client_function( - self.client.delete_security_group_default_rule, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, status=204, security_group_default_rule_id=1) diff --git a/tempest/tests/lib/services/compute/test_security_group_rules_client.py b/tempest/tests/lib/services/compute/test_security_group_rules_client.py deleted file mode 100644 index 2b0a94dd7..000000000 --- a/tempest/tests/lib/services/compute/test_security_group_rules_client.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 tempest.lib.services.compute import security_group_rules_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSecurityGroupRulesClient(base.BaseServiceTest): - - FAKE_SECURITY_GROUP_RULE = { - "security_group_rule": { - "id": "2d021cf1-ce4b-4292-994f-7a785d62a144", - "ip_range": { - "cidr": "0.0.0.0/0" - }, - "parent_group_id": "48700ff3-30b8-4e63-845f-a79c9633e9fb", - "to_port": 443, - "ip_protocol": "tcp", - "group": {}, - "from_port": 443 - } - } - - def setUp(self): - super(TestSecurityGroupRulesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = security_group_rules_client.SecurityGroupRulesClient( - fake_auth, 'compute', 'regionOne') - - def _test_create_security_group_rule(self, bytes_body=False): - req_body = { - "from_port": "443", - "ip_protocol": "tcp", - "to_port": "443", - "cidr": "0.0.0.0/0", - "parent_group_id": "48700ff3-30b8-4e63-845f-a79c9633e9fb" - } - self.check_service_client_function( - self.client.create_security_group_rule, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_SECURITY_GROUP_RULE, - to_utf=bytes_body, **req_body) - - def test_create_security_group_rule_with_str_body(self): - self._test_create_security_group_rule() - - def test_create_security_group_rule_with_bytes_body(self): - self._test_create_security_group_rule(bytes_body=True) - - def test_delete_security_group_rule(self): - self.check_service_client_function( - self.client.delete_security_group_rule, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, status=202, group_rule_id='group-id') diff --git a/tempest/tests/lib/services/compute/test_security_groups_client.py b/tempest/tests/lib/services/compute/test_security_groups_client.py deleted file mode 100644 index 7bbf20e93..000000000 --- a/tempest/tests/lib/services/compute/test_security_groups_client.py +++ /dev/null @@ -1,113 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 fixtures - -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.compute import security_groups_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSecurityGroupsClient(base.BaseServiceTest): - - FAKE_SECURITY_GROUP_INFO = [{ - "description": "default", - "id": "3fb26eb3-581b-4420-9963-b0879a026506", - "name": "default", - "rules": [], - "tenant_id": "openstack" - }] - - def setUp(self): - super(TestSecurityGroupsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = security_groups_client.SecurityGroupsClient( - fake_auth, 'compute', 'regionOne') - - def _test_list_security_groups(self, bytes_body=False): - self.check_service_client_function( - self.client.list_security_groups, - 'tempest.lib.common.rest_client.RestClient.get', - {"security_groups": self.FAKE_SECURITY_GROUP_INFO}, - to_utf=bytes_body) - - def test_list_security_groups_with_str_body(self): - self._test_list_security_groups() - - def test_list_security_groups_with_bytes_body(self): - self._test_list_security_groups(bytes_body=True) - - def _test_show_security_group(self, bytes_body=False): - self.check_service_client_function( - self.client.show_security_group, - 'tempest.lib.common.rest_client.RestClient.get', - {"security_group": self.FAKE_SECURITY_GROUP_INFO[0]}, - to_utf=bytes_body, - security_group_id='fake-id') - - def test_show_security_group_with_str_body(self): - self._test_show_security_group() - - def test_show_security_group_with_bytes_body(self): - self._test_show_security_group(bytes_body=True) - - def _test_create_security_group(self, bytes_body=False): - post_body = {"name": "test", "description": "test_group"} - self.check_service_client_function( - self.client.create_security_group, - 'tempest.lib.common.rest_client.RestClient.post', - {"security_group": self.FAKE_SECURITY_GROUP_INFO[0]}, - to_utf=bytes_body, - kwargs=post_body) - - def test_create_security_group_with_str_body(self): - self._test_create_security_group() - - def test_create_security_group_with_bytes_body(self): - self._test_create_security_group(bytes_body=True) - - def _test_update_security_group(self, bytes_body=False): - req_body = {"name": "test", "description": "test_group"} - self.check_service_client_function( - self.client.update_security_group, - 'tempest.lib.common.rest_client.RestClient.put', - {"security_group": self.FAKE_SECURITY_GROUP_INFO[0]}, - to_utf=bytes_body, - security_group_id='fake-id', - kwargs=req_body) - - def test_update_security_group_with_str_body(self): - self._test_update_security_group() - - def test_update_security_group_with_bytes_body(self): - self._test_update_security_group(bytes_body=True) - - def test_delete_security_group(self): - self.check_service_client_function( - self.client.delete_security_group, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, status=202, security_group_id='fake-id') - - def test_is_resource_deleted_true(self): - mod = ('tempest.lib.services.compute.security_groups_client.' - 'SecurityGroupsClient.show_security_group') - self.useFixture(fixtures.MockPatch(mod, side_effect=lib_exc.NotFound)) - self.assertTrue(self.client.is_resource_deleted('fake-id')) - - def test_is_resource_deleted_false(self): - mod = ('tempest.lib.services.compute.security_groups_client.' - 'SecurityGroupsClient.show_security_group') - self.useFixture(fixtures.MockPatch(mod, return_value='success')) - self.assertFalse(self.client.is_resource_deleted('fake-id')) diff --git a/tempest/tests/lib/services/compute/test_server_groups_client.py b/tempest/tests/lib/services/compute/test_server_groups_client.py deleted file mode 100644 index 9055a36b8..000000000 --- a/tempest/tests/lib/services/compute/test_server_groups_client.py +++ /dev/null @@ -1,101 +0,0 @@ -# Copyright 2015 IBM Corp. -# -# 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 fixtures - -from tempest.lib.services.compute import base_compute_client -from tempest.lib.services.compute import server_groups_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib import fake_http -from tempest.tests.lib.services import base - - -class TestServerGroupsClient(base.BaseServiceTest): - - server_group = { - "id": "5bbcc3c4-1da2-4437-a48a-66f15b1b13f9", - "name": "test", - "policies": ["anti-affinity"], - "members": [], - "metadata": {}} - - def setUp(self): - super(TestServerGroupsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = server_groups_client.ServerGroupsClient( - fake_auth, 'compute', 'regionOne') - - def _test_create_server_group(self, bytes_body=False): - expected = {"server_group": self.server_group} - self.check_service_client_function( - self.client.create_server_group, - 'tempest.lib.common.rest_client.RestClient.post', expected, - bytes_body, name='fake-group', policies=['affinity']) - - def test_create_server_group_str_body(self): - self._test_create_server_group(bytes_body=False) - - def test_create_server_group_byte_body(self): - self._test_create_server_group(bytes_body=True) - - def test_delete_server_group(self): - response = fake_http.fake_http_response({}, status=204), '' - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.rest_client.RestClient.delete', - return_value=response)) - self.client.delete_server_group('fake-group') - - def _test_list_server_groups(self, bytes_body=False): - expected = {"server_groups": [self.server_group]} - self.check_service_client_function( - self.client.list_server_groups, - 'tempest.lib.common.rest_client.RestClient.get', - expected, bytes_body) - - def test_list_server_groups_str_body(self): - self._test_list_server_groups(bytes_body=False) - - def test_list_server_groups_byte_body(self): - self._test_list_server_groups(bytes_body=True) - - def _test_show_server_group(self, bytes_body=False): - expected = {"server_group": self.server_group} - self.check_service_client_function( - self.client.show_server_group, - 'tempest.lib.common.rest_client.RestClient.get', - expected, bytes_body, - server_group_id='5bbcc3c4-1da2-4437-a48a-66f15b1b13f9') - - def test_show_server_group_str_body(self): - self._test_show_server_group(bytes_body=False) - - def test_show_server_group_byte_body(self): - self._test_show_server_group(bytes_body=True) - - -class TestServerGroupsClientMinV213(TestServerGroupsClient): - - server_group = { - "id": "5bbcc3c4-1da2-4437-a48a-66f15b1b13f9", - "name": "test", - "policies": ["anti-affinity"], - "members": [], - "metadata": {}, - "project_id": "0beb4bffb7a445eb8eb05fee3ee7660a", - "user_id": "86031628064a4f99bb66ec03c507dcd8"} - - def setUp(self): - super(TestServerGroupsClientMinV213, self).setUp() - self.patchobject(base_compute_client, 'COMPUTE_MICROVERSION', - new='2.13') diff --git a/tempest/tests/lib/services/compute/test_servers_client.py b/tempest/tests/lib/services/compute/test_servers_client.py deleted file mode 100644 index 86f6ad585..000000000 --- a/tempest/tests/lib/services/compute/test_servers_client.py +++ /dev/null @@ -1,1076 +0,0 @@ -# Copyright 2015 IBM Corp. -# Copyright 2017 AT&T Corp. -# -# 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 copy - -import mock - -from tempest.lib.services.compute import base_compute_client -from tempest.lib.services.compute import servers_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestServersClient(base.BaseServiceTest): - - FAKE_SERVERS = {'servers': [{ - "id": "616fb98f-46ca-475e-917e-2563e5a8cd19", - "links": [ - { - "href": "http://os.co/v2/616fb98f-46ca-475e-917e-2563e5a8cd19", - "rel": "self" - }, - { - "href": "http://os.co/616fb98f-46ca-475e-917e-2563e5a8cd19", - "rel": "bookmark" - } - ], - "name": u"new\u1234-server-test"}] - } - - FAKE_SERVER_DIAGNOSTICS = { - "cpu0_time": 17300000000, - "memory": 524288, - "vda_errors": -1, - "vda_read": 262144, - "vda_read_req": 112, - "vda_write": 5778432, - "vda_write_req": 488, - "vnet1_rx": 2070139, - "vnet1_rx_drop": 0, - "vnet1_rx_errors": 0, - "vnet1_rx_packets": 26701, - "vnet1_tx": 140208, - "vnet1_tx_drop": 0, - "vnet1_tx_errors": 0, - "vnet1_tx_packets": 662 - } - - FAKE_SERVER_GET = {'server': { - "accessIPv4": "", - "accessIPv6": "", - "addresses": { - "private": [ - { - "addr": "192.168.0.3", - "version": 4 - } - ] - }, - "created": "2012-08-20T21:11:09Z", - "flavor": { - "id": "1", - "links": [ - { - "href": "http://os.com/openstack/flavors/1", - "rel": "bookmark" - } - ] - }, - "hostId": "65201c14a29663e06d0748e561207d998b343e1d164bfa0aafa9c45d", - "id": "893c7791-f1df-4c3d-8383-3caae9656c62", - "image": { - "id": "70a599e0-31e7-49b7-b260-868f441e862b", - "links": [ - { - "href": "http://imgs/70a599e0-31e7-49b7-b260-868f441e862b", - "rel": "bookmark" - } - ] - }, - "links": [ - { - "href": "http://v2/srvs/893c7791-f1df-4c3d-8383-3caae9656c62", - "rel": "self" - }, - { - "href": "http://srvs/893c7791-f1df-4c3d-8383-3caae9656c62", - "rel": "bookmark" - } - ], - "metadata": { - u"My Server N\u1234me": u"Apa\u1234che1" - }, - "name": u"new\u1234-server-test", - "progress": 0, - "status": "ACTIVE", - "tenant_id": "openstack", - "updated": "2012-08-20T21:11:09Z", - "user_id": "fake"} - } - - FAKE_SERVER_POST = {"server": { - "id": "616fb98f-46ca-475e-917e-2563e5a8cd19", - "adminPass": "fake-admin-pass", - "security_groups": [ - 'fake-security-group-1', - 'fake-security-group-2' - ], - "links": [ - { - "href": "http://os.co/v2/616fb98f-46ca-475e-917e-2563e5a8cd19", - "rel": "self" - }, - { - "href": "http://os.co/616fb98f-46ca-475e-917e-2563e5a8cd19", - "rel": "bookmark" - } - ], - "OS-DCF:diskConfig": "fake-disk-config"} - } - - FAKE_ADDRESS = {"addresses": { - "private": [ - { - "addr": "192.168.0.3", - "version": 4 - } - ]} - } - - FAKE_COMMON_VOLUME = { - "id": "a6b0875b-6b5d-4a5a-81eb-0c3aa62e5fdb", - "device": "fake-device", - "volumeId": "a6b0875b-46ca-475e-917e-0c3aa62e5fdb", - "serverId": "616fb98f-46ca-475e-917e-2563e5a8cd19" - } - - FAKE_VIRTUAL_INTERFACES = { - "id": "a6b0875b-46ca-475e-917e-0c3aa62e5fdb", - "mac_address": "00:25:90:5b:f8:c3", - "OS-EXT-VIF-NET:net_id": "fake-os-net-id" - } - - FAKE_INSTANCE_ACTIONS = { - "action": "fake-action", - "request_id": "16fb98f-46ca-475e-917e-2563e5a8cd19", - "user_id": "16fb98f-46ca-475e-917e-2563e5a8cd12", - "project_id": "16fb98f-46ca-475e-917e-2563e5a8cd34", - "start_time": "2016-10-02T10:00:00-05:00", - "message": "fake-msg", - "instance_uuid": "16fb98f-46ca-475e-917e-2563e5a8cd12" - } - - FAKE_VNC_CONSOLE = { - "type": "fake-type", - "url": "http://os.co/v2/616fb98f-46ca-475e-917e-2563e5a8cd19" - } - - FAKE_SERVER_PASSWORD = { - "adminPass": "fake-password", - } - - FAKE_INSTANCE_ACTION_EVENTS = { - "event": "fake-event", - "start_time": "2016-10-02T10:00:00-05:00", - "finish_time": "2016-10-02T10:00:00-05:00", - "result": "fake-result", - "traceback": "fake-trace-back" - } - - FAKE_SECURITY_GROUPS = [{ - "description": "default", - "id": "3fb26eb3-581b-4420-9963-b0879a026506", - "name": "default", - "rules": [], - "tenant_id": "openstack" - }] - - FAKE_INSTANCE_WITH_EVENTS = copy.deepcopy(FAKE_INSTANCE_ACTIONS) - FAKE_INSTANCE_WITH_EVENTS['events'] = [FAKE_INSTANCE_ACTION_EVENTS] - - FAKE_REBUILD_SERVER = copy.deepcopy(FAKE_SERVER_GET) - FAKE_REBUILD_SERVER['server']['adminPass'] = 'fake-admin-pass' - - FAKE_TAGS = ["foo", "bar"] - REPLACE_FAKE_TAGS = ["baz", "qux"] - - server_id = FAKE_SERVER_GET['server']['id'] - network_id = 'a6b0875b-6b5d-4a5a-81eb-0c3aa62e5fdb' - - def setUp(self): - super(TestServersClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = servers_client.ServersClient( - fake_auth, 'compute', 'regionOne') - self.addCleanup(mock.patch.stopall) - - def test_list_servers_with_str_body(self): - self._test_list_servers() - - def test_list_servers_with_bytes_body(self): - self._test_list_servers(bytes_body=True) - - def _test_list_servers(self, bytes_body=False): - self.check_service_client_function( - self.client.list_servers, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SERVERS, - bytes_body) - - def test_show_server_with_str_body(self): - self._test_show_server() - - def test_show_server_with_bytes_body(self): - self._test_show_server(bytes_body=True) - - def _test_show_server(self, bytes_body=False): - self.check_service_client_function( - self.client.show_server, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SERVER_GET, - bytes_body, - server_id=self.server_id - ) - - def test_delete_server(self): - self.check_service_client_function( - self.client.delete_server, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=204, - server_id=self.server_id - ) - - def test_create_server_with_str_body(self): - self._test_create_server() - - def test_create_server_with_bytes_body(self): - self._test_create_server(True) - - def _test_create_server(self, bytes_body=False): - self.check_service_client_function( - self.client.create_server, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_SERVER_POST, - bytes_body, - status=202, - name='fake-name', - imageRef='fake-image-ref', - flavorRef='fake-flavor-ref' - ) - - def test_list_addresses_with_str_body(self): - self._test_list_addresses() - - def test_list_addresses_with_bytes_body(self): - self._test_list_addresses(True) - - def _test_list_addresses(self, bytes_body=False): - self.check_service_client_function( - self.client.list_addresses, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_ADDRESS, - bytes_body, - server_id=self.server_id - ) - - def test_list_addresses_by_network_with_str_body(self): - self._test_list_addresses_by_network() - - def test_list_addresses_by_network_with_bytes_body(self): - self._test_list_addresses_by_network(True) - - def _test_list_addresses_by_network(self, bytes_body=False): - self.check_service_client_function( - self.client.list_addresses_by_network, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_ADDRESS['addresses'], - bytes_body, - server_id=self.server_id, - network_id=self.network_id - ) - - def test_action_with_str_body(self): - self._test_action() - - def test_action_with_bytes_body(self): - self._test_action(True) - - def _test_action(self, bytes_body=False): - self.check_service_client_function( - self.client.action, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - bytes_body, - server_id=self.server_id, - action_name='fake-action-name', - schema={'status_code': 200} - ) - - def test_create_backup_with_str_body(self): - self._test_create_backup() - - def test_create_backup_with_bytes_body(self): - self._test_create_backup(True) - - def _test_create_backup(self, bytes_body=False): - self.check_service_client_function( - self.client.create_backup, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - bytes_body, - status=202, - server_id=self.server_id, - backup_type='fake-backup', - rotation='fake-rotation', - name='fake-name' - ) - - def test_evacuate_server_with_str_body(self): - self._test_evacuate_server() - - def test_evacuate_server_with_bytes_body(self): - self._test_evacuate_server(bytes_body=True) - - def _test_evacuate_server(self, bytes_body=False): - kwargs = {'server_id': self.server_id, - 'host': 'fake-target-host'} - self.check_service_client_function( - self.client.evacuate_server, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_SERVER_PASSWORD, - bytes_body, - **kwargs) - - def test_change_password_with_str_body(self): - self._test_change_password() - - def test_change_password_with_bytes_body(self): - self._test_change_password(True) - - def _test_change_password(self, bytes_body=False): - self.check_service_client_function( - self.client.change_password, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - bytes_body, - status=202, - server_id=self.server_id, - adminPass='fake-admin-pass' - ) - - def test_show_password_with_str_body(self): - self._test_show_password() - - def test_show_password_with_bytes_body(self): - self._test_show_password(True) - - def _test_show_password(self, bytes_body=False): - self.check_service_client_function( - self.client.show_password, - 'tempest.lib.common.rest_client.RestClient.get', - {'password': 'fake-password'}, - bytes_body, - server_id=self.server_id - ) - - def test_delete_password(self): - self.check_service_client_function( - self.client.delete_password, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=204, - server_id=self.server_id - ) - - def test_reboot_server(self): - self.check_service_client_function( - self.client.reboot_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id, - type='fake-reboot-type' - ) - - def test_rebuild_server_with_str_body(self): - self._test_rebuild_server() - - def test_rebuild_server_with_bytes_body(self): - self._test_rebuild_server(True) - - def _test_rebuild_server(self, bytes_body=False): - self.check_service_client_function( - self.client.rebuild_server, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_REBUILD_SERVER, - bytes_body, - status=202, - server_id=self.server_id, - image_ref='fake-image-ref' - ) - - def test_resize_server(self): - self.check_service_client_function( - self.client.resize_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id, - flavor_ref='fake-flavor-ref' - ) - - def test_confirm_resize_server(self): - self.check_service_client_function( - self.client.confirm_resize_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=204, - server_id=self.server_id - ) - - def test_revert_resize(self): - self.check_service_client_function( - self.client.revert_resize_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_list_server_metadata_with_str_body(self): - self._test_list_server_metadata() - - def test_list_server_metadata_with_bytes_body(self): - self._test_list_server_metadata() - - def _test_list_server_metadata(self, bytes_body=False): - self.check_service_client_function( - self.client.list_server_metadata, - 'tempest.lib.common.rest_client.RestClient.get', - {'metadata': {'fake-key': 'fake-meta-data'}}, - bytes_body, - server_id=self.server_id - ) - - def test_set_server_metadata_with_str_body(self): - self._test_set_server_metadata() - - def test_set_server_metadata_with_bytes_body(self): - self._test_set_server_metadata(True) - - def _test_set_server_metadata(self, bytes_body=False): - self.check_service_client_function( - self.client.set_server_metadata, - 'tempest.lib.common.rest_client.RestClient.put', - {'metadata': {'fake-key': 'fake-meta-data'}}, - bytes_body, - server_id=self.server_id, - meta='fake-meta' - ) - - def test_update_server_metadata_with_str_body(self): - self._test_update_server_metadata() - - def test_update_server_metadata_with_bytes_body(self): - self._test_update_server_metadata(True) - - def _test_update_server_metadata(self, bytes_body=False): - self.check_service_client_function( - self.client.update_server_metadata, - 'tempest.lib.common.rest_client.RestClient.post', - {'metadata': {'fake-key': 'fake-meta-data'}}, - bytes_body, - server_id=self.server_id, - meta='fake-meta' - ) - - def test_show_server_metadata_item_with_str_body(self): - self._test_show_server_metadata() - - def test_show_server_metadata_item_with_bytes_body(self): - self._test_show_server_metadata(True) - - def _test_show_server_metadata(self, bytes_body=False): - self.check_service_client_function( - self.client.show_server_metadata_item, - 'tempest.lib.common.rest_client.RestClient.get', - {'meta': {'fake-key': 'fake-meta-data'}}, - bytes_body, - server_id=self.server_id, - key='fake-key' - ) - - def test_set_server_metadata_item_with_str_body(self): - self._test_set_server_metadata_item() - - def test_set_server_metadata_item_with_bytes_body(self): - self._test_set_server_metadata_item(True) - - def _test_set_server_metadata_item(self, bytes_body=False): - self.check_service_client_function( - self.client.set_server_metadata_item, - 'tempest.lib.common.rest_client.RestClient.put', - {'meta': {'fake-key': 'fake-meta-data'}}, - bytes_body, - server_id=self.server_id, - key='fake-key', - meta='fake-meta' - ) - - def test_delete_server_metadata(self): - self.check_service_client_function( - self.client.delete_server_metadata_item, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=204, - server_id=self.server_id, - key='fake-key' - ) - - def test_stop_server(self): - self.check_service_client_function( - self.client.stop_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_start_server(self): - self.check_service_client_function( - self.client.start_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_attach_volume_with_str_body(self): - self._test_attach_volume_server() - - def test_attach_volume_with_bytes_body(self): - self._test_attach_volume_server(True) - - def _test_attach_volume_server(self, bytes_body=False): - self.check_service_client_function( - self.client.attach_volume, - 'tempest.lib.common.rest_client.RestClient.post', - {'volumeAttachment': self.FAKE_COMMON_VOLUME}, - bytes_body, - server_id=self.server_id - ) - - def test_update_attached_volume(self): - self.check_service_client_function( - self.client.update_attached_volume, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - status=202, - server_id=self.server_id, - attachment_id='fake-attachment-id', - volumeId='fake-volume-id' - ) - - def test_detach_volume_with_str_body(self): - self._test_detach_volume_server() - - def test_detach_volume_with_bytes_body(self): - self._test_detach_volume_server(True) - - def _test_detach_volume_server(self, bytes_body=False): - self.check_service_client_function( - self.client.detach_volume, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - bytes_body, - status=202, - server_id=self.server_id, - volume_id=self.FAKE_COMMON_VOLUME['volumeId'] - ) - - def test_show_volume_attachment_with_str_body(self): - self._test_show_volume_attachment() - - def test_show_volume_attachment_with_bytes_body(self): - self._test_show_volume_attachment(True) - - def _test_show_volume_attachment(self, bytes_body=False): - self.check_service_client_function( - self.client.show_volume_attachment, - 'tempest.lib.common.rest_client.RestClient.get', - {'volumeAttachment': self.FAKE_COMMON_VOLUME}, - bytes_body, - server_id=self.server_id, - volume_id=self.FAKE_COMMON_VOLUME['volumeId'] - ) - - def test_list_volume_attachments_with_str_body(self): - self._test_list_volume_attachments() - - def test_list_volume_attachments_with_bytes_body(self): - self._test_list_volume_attachments(True) - - def _test_list_volume_attachments(self, bytes_body=False): - self.check_service_client_function( - self.client.list_volume_attachments, - 'tempest.lib.common.rest_client.RestClient.get', - {'volumeAttachments': [self.FAKE_COMMON_VOLUME]}, - bytes_body, - server_id=self.server_id - ) - - def test_add_security_group_with_str_body(self): - self._test_add_security_group() - - def test_add_security_group_with_bytes_body(self): - self._test_add_security_group(True) - - def _test_add_security_group(self, bytes_body=False): - self.check_service_client_function( - self.client.add_security_group, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - bytes_body, - status=202, - server_id=self.server_id, - name='fake-name' - ) - - def test_remove_security_group(self): - self.check_service_client_function( - self.client.remove_security_group, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id, - name='fake-name' - ) - - def test_live_migrate_server_with_str_body(self): - self._test_live_migrate_server() - - def test_live_migrate_server_with_bytes_body(self): - self._test_live_migrate_server(True) - - def _test_live_migrate_server(self, bytes_body=False): - self.check_service_client_function( - self.client.live_migrate_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - bytes_body, - status=202, - server_id=self.server_id - ) - - def test_migrate_server_with_str_body(self): - self._test_migrate_server() - - def test_migrate_server_with_bytes_body(self): - self._test_migrate_server(True) - - def _test_migrate_server(self, bytes_body=False): - self.check_service_client_function( - self.client.migrate_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - bytes_body, - status=202, - server_id=self.server_id - ) - - def test_lock_server(self): - self.check_service_client_function( - self.client.lock_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_unlock_server(self): - self.check_service_client_function( - self.client.unlock_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_suspend_server(self): - self.check_service_client_function( - self.client.suspend_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_resume_server(self): - self.check_service_client_function( - self.client.resume_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_pause_server(self): - self.check_service_client_function( - self.client.pause_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_unpause_server(self): - self.check_service_client_function( - self.client.unpause_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_reset_state(self): - self.check_service_client_function( - self.client.reset_state, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id, - state='fake-state' - ) - - def test_shelve_server(self): - self.check_service_client_function( - self.client.shelve_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_unshelve_server(self): - self.check_service_client_function( - self.client.unshelve_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_shelve_offload_server(self): - self.check_service_client_function( - self.client.shelve_offload_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_get_console_output_with_str_body(self): - self._test_get_console_output() - - def test_get_console_output_with_bytes_body(self): - self._test_get_console_output(True) - - def _test_get_console_output(self, bytes_body=False): - self.check_service_client_function( - self.client.get_console_output, - 'tempest.lib.common.rest_client.RestClient.post', - {'output': 'fake-output'}, - bytes_body, - server_id=self.server_id, - length='fake-length' - ) - - def test_list_virtual_interfaces_with_str_body(self): - self._test_list_virtual_interfaces() - - def test_list_virtual_interfaces_with_bytes_body(self): - self._test_list_virtual_interfaces(True) - - def _test_list_virtual_interfaces(self, bytes_body=False): - self.check_service_client_function( - self.client.list_virtual_interfaces, - 'tempest.lib.common.rest_client.RestClient.get', - {'virtual_interfaces': [self.FAKE_VIRTUAL_INTERFACES]}, - bytes_body, - server_id=self.server_id - ) - - def test_rescue_server_with_str_body(self): - self._test_rescue_server() - - def test_rescue_server_with_bytes_body(self): - self._test_rescue_server(True) - - def _test_rescue_server(self, bytes_body=False): - self.check_service_client_function( - self.client.rescue_server, - 'tempest.lib.common.rest_client.RestClient.post', - {'adminPass': 'fake-admin-pass'}, - bytes_body, - server_id=self.server_id - ) - - def test_unrescue_server(self): - self.check_service_client_function( - self.client.unrescue_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_show_server_diagnostics_with_str_body(self): - self._test_show_server_diagnostics() - - def test_show_server_diagnostics_with_bytes_body(self): - self._test_show_server_diagnostics(True) - - def _test_show_server_diagnostics(self, bytes_body=False): - self.check_service_client_function( - self.client.show_server_diagnostics, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SERVER_DIAGNOSTICS, - bytes_body, - status=200, - server_id=self.server_id - ) - - def test_list_instance_actions_with_str_body(self): - self._test_list_instance_actions() - - def test_list_instance_actions_with_bytes_body(self): - self._test_list_instance_actions(True) - - def _test_list_instance_actions(self, bytes_body=False): - self.check_service_client_function( - self.client.list_instance_actions, - 'tempest.lib.common.rest_client.RestClient.get', - {'instanceActions': [self.FAKE_INSTANCE_ACTIONS]}, - bytes_body, - server_id=self.server_id - ) - - def test_show_instance_action_with_str_body(self): - self._test_show_instance_action() - - def test_show_instance_action_with_bytes_body(self): - self._test_show_instance_action(True) - - def _test_show_instance_action(self, bytes_body=False): - self.check_service_client_function( - self.client.show_instance_action, - 'tempest.lib.common.rest_client.RestClient.get', - {'instanceAction': self.FAKE_INSTANCE_WITH_EVENTS}, - bytes_body, - server_id=self.server_id, - request_id='fake-request-id' - ) - - def test_force_delete_server(self): - self.check_service_client_function( - self.client.force_delete_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_restore_soft_deleted_server(self): - self.check_service_client_function( - self.client.restore_soft_deleted_server, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_reset_network(self): - self.check_service_client_function( - self.client.reset_network, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_inject_network_info(self): - self.check_service_client_function( - self.client.inject_network_info, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=202, - server_id=self.server_id - ) - - def test_get_vnc_console_with_str_body(self): - self._test_get_vnc_console() - - def test_get_vnc_console_with_bytes_body(self): - self._test_get_vnc_console(True) - - def _test_get_vnc_console(self, bytes_body=False): - self.check_service_client_function( - self.client.get_vnc_console, - 'tempest.lib.common.rest_client.RestClient.post', - {'console': self.FAKE_VNC_CONSOLE}, - bytes_body, - server_id=self.server_id, - type='fake-console-type' - ) - - def test_list_security_groups_by_server_with_str_body(self): - self._test_list_security_groups_by_server() - - def test_list_security_groups_by_server_with_bytes_body(self): - self._test_list_security_groups_by_server(True) - - def _test_list_security_groups_by_server(self, bytes_body=False): - self.check_service_client_function( - self.client.list_security_groups_by_server, - 'tempest.lib.common.rest_client.RestClient.get', - {'security_groups': self.FAKE_SECURITY_GROUPS}, - bytes_body, - server_id=self.server_id - ) - - @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION', - new_callable=mock.PropertyMock(return_value='2.26')) - def test_list_tags_str_body(self, _): - self._test_list_tags() - - @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION', - new_callable=mock.PropertyMock(return_value='2.26')) - def test_list_tags_byte_body(self, _): - self._test_list_tags(bytes_body=True) - - def _test_list_tags(self, bytes_body=False): - expected = {"tags": self.FAKE_TAGS} - self.check_service_client_function( - self.client.list_tags, - 'tempest.lib.common.rest_client.RestClient.get', - expected, - server_id=self.server_id, - to_utf=bytes_body) - - @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION', - new_callable=mock.PropertyMock(return_value='2.26')) - def test_update_all_tags_str_body(self, _): - self._test_update_all_tags() - - @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION', - new_callable=mock.PropertyMock(return_value='2.26')) - def test_update_all_tags_byte_body(self, _): - self._test_update_all_tags(bytes_body=True) - - def _test_update_all_tags(self, bytes_body=False): - expected = {"tags": self.REPLACE_FAKE_TAGS} - self.check_service_client_function( - self.client.update_all_tags, - 'tempest.lib.common.rest_client.RestClient.put', - expected, - server_id=self.server_id, - tags=self.REPLACE_FAKE_TAGS, - to_utf=bytes_body) - - @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION', - new_callable=mock.PropertyMock(return_value='2.26')) - def test_delete_all_tags(self, _): - self.check_service_client_function( - self.client.delete_all_tags, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - server_id=self.server_id, - status=204) - - @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION', - new_callable=mock.PropertyMock(return_value='2.26')) - def test_check_tag_existence_str_body(self, _): - self._test_check_tag_existence() - - @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION', - new_callable=mock.PropertyMock(return_value='2.26')) - def test_check_tag_existence_byte_body(self, _): - self._test_check_tag_existence(bytes_body=True) - - def _test_check_tag_existence(self, bytes_body=False): - self.check_service_client_function( - self.client.check_tag_existence, - 'tempest.lib.common.rest_client.RestClient.get', - {}, - server_id=self.server_id, - tag=self.FAKE_TAGS[0], - status=204, - to_utf=bytes_body) - - @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION', - new_callable=mock.PropertyMock(return_value='2.26')) - def test_update_tag_str_body(self, _): - self._test_update_tag() - - @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION', - new_callable=mock.PropertyMock(return_value='2.26')) - def test_update_tag_byte_body(self, _): - self._test_update_tag(bytes_body=True) - - def _test_update_tag(self, bytes_body=False): - self.check_service_client_function( - self.client.update_tag, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - server_id=self.server_id, - tag=self.FAKE_TAGS[0], - status=201, - headers={'location': 'fake_location'}, - to_utf=bytes_body) - - @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION', - new_callable=mock.PropertyMock(return_value='2.26')) - def test_delete_tag(self, _): - self.check_service_client_function( - self.client.delete_tag, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - server_id=self.server_id, - tag=self.FAKE_TAGS[0], - status=204, - ) - - -class TestServersClientMinV26(base.BaseServiceTest): - - def setUp(self): - super(TestServersClientMinV26, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = servers_client.ServersClient(fake_auth, 'compute', - 'regionOne') - base_compute_client.COMPUTE_MICROVERSION = '2.6' - self.server_id = "920eaac8-a284-4fd1-9c2c-b30f0181b125" - - def tearDown(self): - super(TestServersClientMinV26, self).tearDown() - base_compute_client.COMPUTE_MICROVERSION = None - - def test_get_remote_consoles(self): - self.check_service_client_function( - self.client.get_remote_console, - 'tempest.lib.common.rest_client.RestClient.post', - { - 'remote_console': { - 'protocol': 'serial', - 'type': 'serial', - 'url': 'ws://127.0.0.1:6083/?token=IllAllowIt' - } - }, - server_id=self.server_id, - console_type='serial', - protocol='serial', - ) diff --git a/tempest/tests/lib/services/compute/test_services_client.py b/tempest/tests/lib/services/compute/test_services_client.py deleted file mode 100644 index 2dd981c00..000000000 --- a/tempest/tests/lib/services/compute/test_services_client.py +++ /dev/null @@ -1,146 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 copy - -import mock - -from tempest.lib.services.compute import base_compute_client -from tempest.lib.services.compute import services_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestServicesClient(base.BaseServiceTest): - - FAKE_SERVICES = { - "services": - [{ - "status": "enabled", - "binary": "nova-conductor", - "zone": "internal", - "state": "up", - "updated_at": "2015-08-19T06:50:55.000000", - "host": "controller", - "disabled_reason": None, - "id": 1 - }] - } - - FAKE_SERVICE = { - "service": - { - "status": "enabled", - "binary": "nova-conductor", - "host": "controller" - } - } - - FAKE_UPDATE_FORCED_DOWN = { - "service": - { - "forced_down": True, - "binary": "nova-conductor", - "host": "controller" - } - } - - def setUp(self): - super(TestServicesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = services_client.ServicesClient( - fake_auth, 'compute', 'regionOne') - self.addCleanup(mock.patch.stopall) - - def test_list_services_with_str_body(self): - self.check_service_client_function( - self.client.list_services, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SERVICES) - - def test_list_services_with_bytes_body(self): - self.check_service_client_function( - self.client.list_services, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SERVICES, to_utf=True) - - def _test_enable_service(self, bytes_body=False): - self.check_service_client_function( - self.client.enable_service, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_SERVICE, - bytes_body, - host="nova-conductor", binary="controller") - - def test_enable_service_with_str_body(self): - self._test_enable_service() - - def test_enable_service_with_bytes_body(self): - self._test_enable_service(bytes_body=True) - - def _test_disable_service(self, bytes_body=False): - fake_service = copy.deepcopy(self.FAKE_SERVICE) - fake_service["service"]["status"] = "disable" - - self.check_service_client_function( - self.client.disable_service, - 'tempest.lib.common.rest_client.RestClient.put', - fake_service, - bytes_body, - host="nova-conductor", binary="controller") - - def test_disable_service_with_str_body(self): - self._test_disable_service() - - def test_disable_service_with_bytes_body(self): - self._test_disable_service(bytes_body=True) - - def _test_log_reason_disabled_service(self, bytes_body=False): - resp_body = copy.deepcopy(self.FAKE_SERVICE) - resp_body['service']['disabled_reason'] = 'test reason' - - self.check_service_client_function( - self.client.disable_log_reason, - 'tempest.lib.common.rest_client.RestClient.put', - resp_body, - bytes_body, - host="nova-conductor", - binary="controller", - disabled_reason='test reason') - - def test_log_reason_disabled_service_with_str_body(self): - self._test_log_reason_disabled_service() - - def test_log_reason_disabled_service_with_bytes_body(self): - self._test_log_reason_disabled_service(bytes_body=True) - - def _test_update_forced_down(self, bytes_body=False): - self.check_service_client_function( - self.client.update_forced_down, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_FORCED_DOWN, - bytes_body, - host="nova-conductor", - binary="controller", - forced_down=True) - - @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION', - new_callable=mock.PropertyMock(return_value='2.11')) - def test_update_forced_down_with_str_body(self, _): - self._test_update_forced_down() - - @mock.patch.object(base_compute_client, 'COMPUTE_MICROVERSION', - new_callable=mock.PropertyMock(return_value='2.11')) - def test_update_forced_down_with_bytes_body(self, _): - self._test_update_forced_down(bytes_body=True) diff --git a/tempest/tests/lib/services/compute/test_snapshots_client.py b/tempest/tests/lib/services/compute/test_snapshots_client.py deleted file mode 100644 index 1e2902c6b..000000000 --- a/tempest/tests/lib/services/compute/test_snapshots_client.py +++ /dev/null @@ -1,103 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 fixtures - -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.compute import snapshots_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSnapshotsClient(base.BaseServiceTest): - - FAKE_SNAPSHOT = { - "createdAt": "2015-10-02T16:27:54.724209", - "displayDescription": u"Another \u1234.", - "displayName": u"v\u1234-001", - "id": "100", - "size": 100, - "status": "available", - "volumeId": "12" - } - - FAKE_SNAPSHOTS = {"snapshots": [FAKE_SNAPSHOT]} - - def setUp(self): - super(TestSnapshotsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = snapshots_client.SnapshotsClient( - fake_auth, 'compute', 'regionOne') - - def _test_create_snapshot(self, bytes_body=False): - self.check_service_client_function( - self.client.create_snapshot, - 'tempest.lib.common.rest_client.RestClient.post', - {"snapshot": self.FAKE_SNAPSHOT}, - to_utf=bytes_body, status=200, - volume_id=self.FAKE_SNAPSHOT["volumeId"]) - - def test_create_snapshot_with_str_body(self): - self._test_create_snapshot() - - def test_create_shapshot_with_bytes_body(self): - self._test_create_snapshot(bytes_body=True) - - def _test_show_snapshot(self, bytes_body=False): - self.check_service_client_function( - self.client.show_snapshot, - 'tempest.lib.common.rest_client.RestClient.get', - {"snapshot": self.FAKE_SNAPSHOT}, - to_utf=bytes_body, snapshot_id=self.FAKE_SNAPSHOT["id"]) - - def test_show_snapshot_with_str_body(self): - self._test_show_snapshot() - - def test_show_snapshot_with_bytes_body(self): - self._test_show_snapshot(bytes_body=True) - - def _test_list_snapshots(self, bytes_body=False, **params): - self.check_service_client_function( - self.client.list_snapshots, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SNAPSHOTS, to_utf=bytes_body, **params) - - def test_list_snapshots_with_str_body(self): - self._test_list_snapshots() - - def test_list_snapshots_with_byte_body(self): - self._test_list_snapshots(bytes_body=True) - - def test_list_snapshots_with_params(self): - self._test_list_snapshots('fake') - - def test_delete_snapshot(self): - self.check_service_client_function( - self.client.delete_snapshot, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, status=202, snapshot_id=self.FAKE_SNAPSHOT['id']) - - def test_is_resource_deleted_true(self): - module = ('tempest.lib.services.compute.snapshots_client.' - 'SnapshotsClient.show_snapshot') - self.useFixture(fixtures.MockPatch( - module, side_effect=lib_exc.NotFound)) - self.assertTrue(self.client.is_resource_deleted('fake-id')) - - def test_is_resource_deleted_false(self): - module = ('tempest.lib.services.compute.snapshots_client.' - 'SnapshotsClient.show_snapshot') - self.useFixture(fixtures.MockPatch( - module, return_value={})) - self.assertFalse(self.client.is_resource_deleted('fake-id')) diff --git a/tempest/tests/lib/services/compute/test_tenant_networks_client.py b/tempest/tests/lib/services/compute/test_tenant_networks_client.py deleted file mode 100644 index f71aad9b0..000000000 --- a/tempest/tests/lib/services/compute/test_tenant_networks_client.py +++ /dev/null @@ -1,63 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 tempest.lib.services.compute import tenant_networks_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestTenantNetworksClient(base.BaseServiceTest): - - FAKE_NETWORK = { - "cidr": "None", - "id": "c2329eb4-cc8e-4439-ac4c-932369309e36", - "label": u'\u30d7' - } - - FAKE_NETWORKS = [FAKE_NETWORK] - - NETWORK_ID = FAKE_NETWORK['id'] - - def setUp(self): - super(TestTenantNetworksClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = tenant_networks_client.TenantNetworksClient( - fake_auth, 'compute', 'regionOne') - - def _test_list_tenant_networks(self, bytes_body=False): - self.check_service_client_function( - self.client.list_tenant_networks, - 'tempest.lib.common.rest_client.RestClient.get', - {"networks": self.FAKE_NETWORKS}, - bytes_body) - - def test_list_tenant_networks_with_str_body(self): - self._test_list_tenant_networks() - - def test_list_tenant_networks_with_bytes_body(self): - self._test_list_tenant_networks(bytes_body=True) - - def _test_show_tenant_network(self, bytes_body=False): - self.check_service_client_function( - self.client.show_tenant_network, - 'tempest.lib.common.rest_client.RestClient.get', - {"network": self.FAKE_NETWORK}, - bytes_body, - network_id=self.NETWORK_ID) - - def test_show_tenant_network_with_str_body(self): - self._test_show_tenant_network() - - def test_show_tenant_network_with_bytes_body(self): - self._test_show_tenant_network(bytes_body=True) diff --git a/tempest/tests/lib/services/compute/test_tenant_usages_client.py b/tempest/tests/lib/services/compute/test_tenant_usages_client.py deleted file mode 100644 index 49eae0872..000000000 --- a/tempest/tests/lib/services/compute/test_tenant_usages_client.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 tempest.lib.services.compute import tenant_usages_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestTenantUsagesClient(base.BaseServiceTest): - - FAKE_SERVER_USAGES = [{ - "ended_at": None, - "flavor": "m1.tiny", - "hours": 1.0, - "instance_id": "1f1deceb-17b5-4c04-84c7-e0d4499c8fe0", - "local_gb": 1, - "memory_mb": 512, - "name": "new-server-test", - "started_at": "2012-10-08T20:10:44.541277", - "state": "active", - "tenant_id": "openstack", - "uptime": 3600, - "vcpus": 1 - }] - - FAKE_TENANT_USAGES = [{ - "server_usages": FAKE_SERVER_USAGES, - "start": "2012-10-08T21:10:44.587336", - "stop": "2012-10-08T22:10:44.587336", - "tenant_id": "openstack", - "total_hours": 1, - "total_local_gb_usage": 1, - "total_memory_mb_usage": 512, - "total_vcpus_usage": 1 - }] - - def setUp(self): - super(TestTenantUsagesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = tenant_usages_client.TenantUsagesClient( - fake_auth, 'compute', 'regionOne') - - def _test_list_tenant_usages(self, bytes_body=False): - self.check_service_client_function( - self.client.list_tenant_usages, - 'tempest.lib.common.rest_client.RestClient.get', - {"tenant_usages": self.FAKE_TENANT_USAGES}, - to_utf=bytes_body) - - def test_list_tenant_usages_with_str_body(self): - self._test_list_tenant_usages() - - def test_list_tenant_usages_with_bytes_body(self): - self._test_list_tenant_usages(bytes_body=True) - - def _test_show_tenant_usage(self, bytes_body=False): - self.check_service_client_function( - self.client.show_tenant_usage, - 'tempest.lib.common.rest_client.RestClient.get', - {"tenant_usage": self.FAKE_TENANT_USAGES[0]}, - to_utf=bytes_body, - tenant_id='openstack') - - def test_show_tenant_usage_with_str_body(self): - self._test_show_tenant_usage() - - def test_show_tenant_usage_with_bytes_body(self): - self._test_show_tenant_usage(bytes_body=True) diff --git a/tempest/tests/lib/services/compute/test_versions_client.py b/tempest/tests/lib/services/compute/test_versions_client.py deleted file mode 100644 index 40d424f76..000000000 --- a/tempest/tests/lib/services/compute/test_versions_client.py +++ /dev/null @@ -1,136 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 copy - -import fixtures - -from tempest.lib.services.compute import versions_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestVersionsClient(base.BaseServiceTest): - - FAKE_INIT_VERSION = { - "version": { - "id": "v2.1", - "links": [ - { - "href": "http://openstack.example.com/v2.1/", - "rel": "self" - }, - { - "href": "http://docs.openstack.org/", - "rel": "describedby", - "type": "text/html" - } - ], - "status": "CURRENT", - "updated": "2013-07-23T11:33:21Z", - "version": "2.1", - "min_version": "2.1" - } - } - - FAKE_VERSIONS_INFO = { - "versions": [FAKE_INIT_VERSION["version"]] - } - - FAKE_VERSION_INFO = copy.deepcopy(FAKE_INIT_VERSION) - - FAKE_VERSION_INFO["version"]["media-types"] = [ - { - "base": "application/json", - "type": "application/vnd.openstack.compute+json;version=2.1" - } - ] - - def setUp(self): - super(TestVersionsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.versions_client = ( - versions_client.VersionsClient - (fake_auth, 'compute', 'regionOne')) - - def _test_versions_client(self, bytes_body=False): - self.check_service_client_function( - self.versions_client.list_versions, - 'tempest.lib.common.rest_client.RestClient.raw_request', - self.FAKE_VERSIONS_INFO, - bytes_body, - 200) - - def _test_get_version_by_url(self, bytes_body=False): - self.useFixture(fixtures.MockPatch( - "tempest.lib.common.rest_client.RestClient.token", - return_value="Dummy Token")) - params = {"version_url": self.versions_client._get_base_version_url()} - self.check_service_client_function( - self.versions_client.get_version_by_url, - 'tempest.lib.common.rest_client.RestClient.raw_request', - self.FAKE_VERSION_INFO, - bytes_body, - 200, **params) - - def test_list_versions_client_with_str_body(self): - self._test_versions_client() - - def test_list_versions_client_with_bytes_body(self): - self._test_versions_client(bytes_body=True) - - def test_get_version_by_url_with_str_body(self): - self._test_get_version_by_url() - - def test_get_version_by_url_with_bytes_body(self): - self._test_get_version_by_url(bytes_body=True) - - def _test_get_base_version_url(self, url, expected_base_url): - auth = fake_auth_provider.FakeAuthProvider(fake_base_url=url) - client = versions_client.VersionsClient(auth, 'compute', 'regionOne') - self.assertEqual(expected_base_url, client._get_base_version_url()) - - def test_get_base_version_url(self): - self._test_get_base_version_url('https://bar.org/v2/123', - 'https://bar.org/') - self._test_get_base_version_url('https://bar.org/v2.1/123', - 'https://bar.org/') - self._test_get_base_version_url('https://bar.org/v2.15/123', - 'https://bar.org/') - self._test_get_base_version_url('https://bar.org/v22.2/123', - 'https://bar.org/') - self._test_get_base_version_url('https://bar.org/v22/123', - 'https://bar.org/') - - def test_get_base_version_url_app_name(self): - self._test_get_base_version_url('https://bar.org/compute/v2/123', - 'https://bar.org/compute/') - self._test_get_base_version_url('https://bar.org/compute/v2.1/123', - 'https://bar.org/compute/') - self._test_get_base_version_url('https://bar.org/compute/v2.15/123', - 'https://bar.org/compute/') - self._test_get_base_version_url('https://bar.org/compute/v22.2/123', - 'https://bar.org/compute/') - self._test_get_base_version_url('https://bar.org/compute/v22/123', - 'https://bar.org/compute/') - - def test_get_base_version_url_double_slash(self): - self._test_get_base_version_url('https://bar.org//v2/123', - 'https://bar.org/') - self._test_get_base_version_url('https://bar.org//v2.1/123', - 'https://bar.org/') - self._test_get_base_version_url('https://bar.org/compute//v2/123', - 'https://bar.org/compute/') - self._test_get_base_version_url('https://bar.org/compute//v2.1/123', - 'https://bar.org/compute/') diff --git a/tempest/tests/lib/services/compute/test_volumes_client.py b/tempest/tests/lib/services/compute/test_volumes_client.py deleted file mode 100644 index 4b4f02ede..000000000 --- a/tempest/tests/lib/services/compute/test_volumes_client.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 copy - -import fixtures - -from tempest.lib import exceptions as lib_exc -from tempest.lib.services.compute import volumes_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestVolumesClient(base.BaseServiceTest): - - FAKE_VOLUME = { - "id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c", - "displayName": u"v\u12345ol-001", - "displayDescription": u"Another \u1234volume.", - "size": 30, - "status": "Active", - "volumeType": "289da7f8-6440-407c-9fb4-7db01ec49164", - "metadata": { - "contents": "junk" - }, - "availabilityZone": "us-east1", - "snapshotId": None, - "attachments": [], - "createdAt": "2012-02-14T20:53:07Z" - } - - FAKE_VOLUMES = {"volumes": [FAKE_VOLUME]} - - def setUp(self): - super(TestVolumesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = volumes_client.VolumesClient( - fake_auth, 'compute', 'regionOne') - - def _test_list_volumes(self, bytes_body=False, **params): - self.check_service_client_function( - self.client.list_volumes, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_VOLUMES, to_utf=bytes_body, **params) - - def test_list_volumes_with_str_body(self): - self._test_list_volumes() - - def test_list_volumes_with_byte_body(self): - self._test_list_volumes(bytes_body=True) - - def test_list_volumes_with_params(self): - self._test_list_volumes(name='fake') - - def _test_show_volume(self, bytes_body=False): - self.check_service_client_function( - self.client.show_volume, - 'tempest.lib.common.rest_client.RestClient.get', - {"volume": self.FAKE_VOLUME}, - to_utf=bytes_body, volume_id=self.FAKE_VOLUME['id']) - - def test_show_volume_with_str_body(self): - self._test_show_volume() - - def test_show_volume_with_bytes_body(self): - self._test_show_volume(bytes_body=True) - - def _test_create_volume(self, bytes_body=False): - post_body = copy.deepcopy(self.FAKE_VOLUME) - del post_body['id'] - del post_body['createdAt'] - del post_body['status'] - self.check_service_client_function( - self.client.create_volume, - 'tempest.lib.common.rest_client.RestClient.post', - {"volume": self.FAKE_VOLUME}, - to_utf=bytes_body, status=200, **post_body) - - def test_create_volume_with_str_body(self): - self._test_create_volume() - - def test_create_volume_with_bytes_body(self): - self._test_create_volume(bytes_body=True) - - def test_delete_volume(self): - self.check_service_client_function( - self.client.delete_volume, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, status=202, volume_id=self.FAKE_VOLUME['id']) - - def test_is_resource_deleted_true(self): - module = ('tempest.lib.services.compute.volumes_client.' - 'VolumesClient.show_volume') - self.useFixture(fixtures.MockPatch( - module, side_effect=lib_exc.NotFound)) - self.assertTrue(self.client.is_resource_deleted('fake-id')) - - def test_is_resource_deleted_false(self): - module = ('tempest.lib.services.compute.volumes_client.' - 'VolumesClient.show_volume') - self.useFixture(fixtures.MockPatch( - module, return_value={})) - self.assertFalse(self.client.is_resource_deleted('fake-id')) diff --git a/tempest/tests/lib/services/identity/__init__.py b/tempest/tests/lib/services/identity/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/identity/v2/__init__.py b/tempest/tests/lib/services/identity/v2/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/identity/v2/test_endpoints_client.py b/tempest/tests/lib/services/identity/v2/test_endpoints_client.py deleted file mode 100644 index 7d2cac275..000000000 --- a/tempest/tests/lib/services/identity/v2/test_endpoints_client.py +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.lib.services.identity.v2 import endpoints_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestEndpointsClient(base.BaseServiceTest): - FAKE_CREATE_ENDPOINT = { - "endpoint": { - "id": 1, - "tenantId": 1, - "region": "North", - "type": "compute", - "publicURL": "https://compute.north.public.com/v1", - "internalURL": "https://compute.north.internal.com/v1", - "adminURL": "https://compute.north.internal.com/v1" - } - } - - FAKE_LIST_ENDPOINTS = { - "endpoints": [ - { - "id": 1, - "tenantId": "1", - "region": "North", - "type": "compute", - "publicURL": "https://compute.north.public.com/v1", - "internalURL": "https://compute.north.internal.com/v1", - "adminURL": "https://compute.north.internal.com/v1" - }, - { - "id": 2, - "tenantId": "1", - "region": "South", - "type": "compute", - "publicURL": "https://compute.north.public.com/v1", - "internalURL": "https://compute.north.internal.com/v1", - "adminURL": "https://compute.north.internal.com/v1" - } - ] - } - - def setUp(self): - super(TestEndpointsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = endpoints_client.EndpointsClient(fake_auth, - 'identity', 'regionOne') - - def _test_create_endpoint(self, bytes_body=False): - self.check_service_client_function( - self.client.create_endpoint, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_ENDPOINT, - bytes_body, - service_id="b344506af7644f6794d9cb316600b020", - region="region-demo", - publicurl="https://compute.north.public.com/v1", - adminurl="https://compute.north.internal.com/v1", - internalurl="https://compute.north.internal.com/v1") - - def _test_list_endpoints(self, bytes_body=False): - self.check_service_client_function( - self.client.list_endpoints, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ENDPOINTS, - bytes_body) - - def test_create_endpoint_with_str_body(self): - self._test_create_endpoint() - - def test_create_endpoint_with_bytes_body(self): - self._test_create_endpoint(bytes_body=True) - - def test_list_endpoints_with_str_body(self): - self._test_list_endpoints() - - def test_list_endpoints_with_bytes_body(self): - self._test_list_endpoints(bytes_body=True) - - def test_delete_endpoint(self): - self.check_service_client_function( - self.client.delete_endpoint, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - endpoint_id="b344506af7644f6794d9cb316600b020", - status=204) diff --git a/tempest/tests/lib/services/identity/v2/test_identity_client.py b/tempest/tests/lib/services/identity/v2/test_identity_client.py deleted file mode 100644 index 303d1f733..000000000 --- a/tempest/tests/lib/services/identity/v2/test_identity_client.py +++ /dev/null @@ -1,230 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.lib.services.identity.v2 import identity_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestIdentityClient(base.BaseServiceTest): - FAKE_TOKEN = { - "tokens": { - "id": "cbc36478b0bd8e67e89", - "name": "FakeToken", - "type": "token", - } - } - - FAKE_ENDPOINTS_FOR_TOKEN = { - "endpoints_links": [], - "endpoints": [ - { - "name": "nova", - "adminURL": "https://nova.region-one.internal.com/" + - "v2/be1319401cfa4a0aa590b97cc7b64d8d", - "region": "RegionOne", - "internalURL": "https://nova.region-one.internal.com/" + - "v2/be1319401cfa4a0aa590b97cc7b64d8d", - "type": "compute", - "id": "11b41ee1b00841128b7333d4bf1a6140", - "publicURL": "https://nova.region-one.public.com/v2/" + - "be1319401cfa4a0aa590b97cc7b64d8d" - }, - { - "name": "neutron", - "adminURL": "https://neutron.region-one.internal.com/", - "region": "RegionOne", - "internalURL": "https://neutron.region-one.internal.com/", - "type": "network", - "id": "cdbfa3c416d741a9b5c968f2dc628acb", - "publicURL": "https://neutron.region-one.public.com/" - } - ] - } - - FAKE_API_INFO = { - "name": "API_info", - "type": "API", - "description": "test_description" - } - - FAKE_LIST_EXTENSIONS = { - "extensions": { - "values": [ - { - "updated": "2013-07-07T12:00:0-00:00", - "name": "OpenStack S3 API", - "links": [ - { - "href": "https://github.com/openstack/" + - "identity-api", - "type": "text/html", - "rel": "describedby" - } - ], - "namespace": "http://docs.openstack.org/identity/" + - "api/ext/s3tokens/v1.0", - "alias": "s3tokens", - "description": "OpenStack S3 API." - }, - { - "updated": "2013-12-17T12:00:0-00:00", - "name": "OpenStack Federation APIs", - "links": [ - { - "href": "https://github.com/openstack/" + - "identity-api", - "type": "text/html", - "rel": "describedby" - } - ], - "namespace": "http://docs.openstack.org/identity/" + - "api/ext/OS-FEDERATION/v1.0", - "alias": "OS-FEDERATION", - "description": "OpenStack Identity Providers Mechanism." - }, - { - "updated": "2014-01-20T12:00:0-00:00", - "name": "OpenStack Simple Certificate API", - "links": [ - { - "href": "https://github.com/openstack/" + - "identity-api", - "type": "text/html", - "rel": "describedby" - } - ], - "namespace": "http://docs.openstack.org/identity/api/" + - "ext/OS-SIMPLE-CERT/v1.0", - "alias": "OS-SIMPLE-CERT", - "description": "OpenStack simple certificate extension" - }, - { - "updated": "2013-07-07T12:00:0-00:00", - "name": "OpenStack OAUTH1 API", - "links": [ - { - "href": "https://github.com/openstack/" + - "identity-api", - "type": "text/html", - "rel": "describedby" - } - ], - "namespace": "http://docs.openstack.org/identity/" + - "api/ext/OS-OAUTH1/v1.0", - "alias": "OS-OAUTH1", - "description": "OpenStack OAuth Delegated Auth Mechanism." - }, - { - "updated": "2013-07-07T12:00:0-00:00", - "name": "OpenStack EC2 API", - "links": [ - { - "href": "https://github.com/openstack/" + - "identity-api", - "type": "text/html", - "rel": "describedby" - } - ], - "namespace": "http://docs.openstack.org/identity/api/" + - "ext/OS-EC2/v1.0", - "alias": "OS-EC2", - "description": "OpenStack EC2 Credentials backend." - } - ] - } - } - - def setUp(self): - super(TestIdentityClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = identity_client.IdentityClient(fake_auth, - 'identity', - 'regionOne') - - def _test_show_api_description(self, bytes_body=False): - self.check_service_client_function( - self.client.show_api_description, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_API_INFO, - bytes_body) - - def _test_list_extensions(self, bytes_body=False): - self.check_service_client_function( - self.client.list_extensions, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_EXTENSIONS, - bytes_body) - - def _test_show_token(self, bytes_body=False): - self.check_service_client_function( - self.client.show_token, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_TOKEN, - bytes_body, - token_id="cbc36478b0bd8e67e89") - - def _test_list_endpoints_for_token(self, bytes_body=False): - self.check_service_client_function( - self.client.list_endpoints_for_token, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_ENDPOINTS_FOR_TOKEN, - bytes_body, - token_id="cbc36478b0bd8e67e89") - - def _test_check_token_existence(self, bytes_body=False): - self.check_service_client_function( - self.client.check_token_existence, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - bytes_body, - token_id="cbc36478b0bd8e67e89") - - def test_show_api_description_with_str_body(self): - self._test_show_api_description() - - def test_show_api_description_with_bytes_body(self): - self._test_show_api_description(bytes_body=True) - - def test_show_list_extensions_with_str_body(self): - self._test_list_extensions() - - def test_show_list_extensions_with_bytes_body(self): - self._test_list_extensions(bytes_body=True) - - def test_show_token_with_str_body(self): - self._test_show_token() - - def test_show_token_with_bytes_body(self): - self._test_show_token(bytes_body=True) - - def test_list_endpoints_for_token_with_str_body(self): - self._test_list_endpoints_for_token() - - def test_list_endpoints_for_token_with_bytes_body(self): - self._test_list_endpoints_for_token(bytes_body=True) - - def test_check_token_existence_with_bytes_body(self): - self._test_check_token_existence(bytes_body=True) - - def test_check_token_existence_with_str_body(self): - self._test_check_token_existence() - - def test_delete_token(self): - self.check_service_client_function( - self.client.delete_token, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - token_id="cbc36478b0bd8e67e89", - status=204) diff --git a/tempest/tests/lib/services/identity/v2/test_roles_client.py b/tempest/tests/lib/services/identity/v2/test_roles_client.py deleted file mode 100644 index 464a71500..000000000 --- a/tempest/tests/lib/services/identity/v2/test_roles_client.py +++ /dev/null @@ -1,141 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.lib.services.identity.v2 import roles_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestRolesClient(base.BaseServiceTest): - FAKE_ROLE_INFO = { - "role": { - "id": "1", - "name": "test", - "description": "test_description" - } - } - - FAKE_LIST_ROLES = { - "roles": [ - { - "id": "1", - "name": "test", - "description": "test_description" - }, - { - "id": "2", - "name": "test2", - "description": "test2_description" - } - ] - } - - def setUp(self): - super(TestRolesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = roles_client.RolesClient(fake_auth, - 'identity', 'regionOne') - - def _test_create_role(self, bytes_body=False): - self.check_service_client_function( - self.client.create_role, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_ROLE_INFO, - bytes_body, - id="1", - name="test", - description="test_description") - - def _test_show_role(self, bytes_body=False): - self.check_service_client_function( - self.client.show_role, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_ROLE_INFO, - bytes_body, - role_id_or_name="1") - - def _test_list_roles(self, bytes_body=False): - self.check_service_client_function( - self.client.list_roles, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ROLES, - bytes_body) - - def _test_create_user_role_on_project(self, bytes_body=False): - self.check_service_client_function( - self.client.create_user_role_on_project, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_ROLE_INFO, - bytes_body, - tenant_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=200) - - def _test_list_user_roles_on_project(self, bytes_body=False): - self.check_service_client_function( - self.client.list_user_roles_on_project, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ROLES, - bytes_body, - tenant_id="b344506af7644f6794d9cb316600b020", - user_id="123") - - def test_create_role_with_str_body(self): - self._test_create_role() - - def test_create_role_with_bytes_body(self): - self._test_create_role(bytes_body=True) - - def test_show_role_with_str_body(self): - self._test_show_role() - - def test_show_role_with_bytes_body(self): - self._test_show_role(bytes_body=True) - - def test_list_roles_with_str_body(self): - self._test_list_roles() - - def test_list_roles_with_bytes_body(self): - self._test_list_roles(bytes_body=True) - - def test_delete_role(self): - self.check_service_client_function( - self.client.delete_role, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - role_id="1", - status=204) - - def test_create_user_role_on_project_with_str_body(self): - self._test_create_user_role_on_project() - - def test_create_user_role_on_project_with_bytes_body(self): - self._test_create_user_role_on_project(bytes_body=True) - - def test_list_user_roles_on_project_with_str_body(self): - self._test_list_user_roles_on_project() - - def test_list_user_roles_on_project_with_bytes_body(self): - self._test_list_user_roles_on_project(bytes_body=True) - - def test_delete_role_from_user_on_project(self): - self.check_service_client_function( - self.client.delete_role_from_user_on_project, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - tenant_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) diff --git a/tempest/tests/lib/services/identity/v2/test_services_client.py b/tempest/tests/lib/services/identity/v2/test_services_client.py deleted file mode 100644 index bafb6b1e8..000000000 --- a/tempest/tests/lib/services/identity/v2/test_services_client.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.lib.services.identity.v2 import services_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestServicesClient(base.BaseServiceTest): - FAKE_SERVICE_INFO = { - "OS-KSADM:service": { - "id": "1", - "name": "test", - "type": "compute", - "description": "test_description" - } - } - - FAKE_LIST_SERVICES = { - "OS-KSADM:services": [ - { - "id": "1", - "name": "test", - "type": "compute", - "description": "test_description" - }, - { - "id": "2", - "name": "test2", - "type": "compute", - "description": "test2_description" - } - ] - } - - def setUp(self): - super(TestServicesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = services_client.ServicesClient(fake_auth, - 'identity', 'regionOne') - - def _test_create_service(self, bytes_body=False): - self.check_service_client_function( - self.client.create_service, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_SERVICE_INFO, - bytes_body, - id="1", - name="test", - type="compute", - description="test_description") - - def _test_show_service(self, bytes_body=False): - self.check_service_client_function( - self.client.show_service, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SERVICE_INFO, - bytes_body, - service_id="1") - - def _test_list_services(self, bytes_body=False): - self.check_service_client_function( - self.client.list_services, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_SERVICES, - bytes_body) - - def test_create_service_with_str_body(self): - self._test_create_service() - - def test_create_service_with_bytes_body(self): - self._test_create_service(bytes_body=True) - - def test_show_service_with_str_body(self): - self._test_show_service() - - def test_show_service_with_bytes_body(self): - self._test_show_service(bytes_body=True) - - def test_delete_service(self): - self.check_service_client_function( - self.client.delete_service, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - service_id="1", - status=204) diff --git a/tempest/tests/lib/services/identity/v2/test_tenants_client.py b/tempest/tests/lib/services/identity/v2/test_tenants_client.py deleted file mode 100644 index ae3d13ab6..000000000 --- a/tempest/tests/lib/services/identity/v2/test_tenants_client.py +++ /dev/null @@ -1,131 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.lib.services.identity.v2 import tenants_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestTenantsClient(base.BaseServiceTest): - FAKE_TENANT_INFO = { - "tenant": { - "id": "1", - "name": "test", - "description": "test_description", - "enabled": True - } - } - - FAKE_LIST_TENANTS = { - "tenants": [ - { - "id": "1", - "name": "test", - "description": "test_description", - "enabled": True - }, - { - "id": "2", - "name": "test2", - "description": "test2_description", - "enabled": True - } - ] - } - - def setUp(self): - super(TestTenantsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = tenants_client.TenantsClient(fake_auth, - 'identity', 'regionOne') - - def _test_create_tenant(self, bytes_body=False): - self.check_service_client_function( - self.client.create_tenant, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_TENANT_INFO, - bytes_body, - name="test", - description="test_description") - - def _test_show_tenant(self, bytes_body=False): - self.check_service_client_function( - self.client.show_tenant, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_TENANT_INFO, - bytes_body, - tenant_id="1") - - def _test_update_tenant(self, bytes_body=False): - self.check_service_client_function( - self.client.update_tenant, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_TENANT_INFO, - bytes_body, - tenant_id="1", - name="test", - description="test_description") - - def _test_list_tenants(self, bytes_body=False): - self.check_service_client_function( - self.client.list_tenants, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_TENANTS, - bytes_body) - - def _test_list_tenant_users(self, bytes_body=False): - self.check_service_client_function( - self.client.list_tenant_users, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_TENANTS, - bytes_body, - tenant_id="1") - - def test_create_tenant_with_str_body(self): - self._test_create_tenant() - - def test_create_tenant_with_bytes_body(self): - self._test_create_tenant(bytes_body=True) - - def test_show_tenant_with_str_body(self): - self._test_show_tenant() - - def test_show_tenant_with_bytes_body(self): - self._test_show_tenant(bytes_body=True) - - def test_update_tenant_with_str_body(self): - self._test_update_tenant() - - def test_update_tenant_with_bytes_body(self): - self._test_update_tenant(bytes_body=True) - - def test_list_tenants_with_str_body(self): - self._test_list_tenants() - - def test_list_tenants_with_bytes_body(self): - self._test_list_tenants(bytes_body=True) - - def test_delete_tenant(self): - self.check_service_client_function( - self.client.delete_tenant, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - tenant_id="1", - status=204) - - def test_list_tenant_users_with_str_body(self): - self._test_list_tenant_users() - - def test_list_tenant_users_with_bytes_body(self): - self._test_list_tenant_users(bytes_body=True) diff --git a/tempest/tests/lib/services/identity/v2/test_token_client.py b/tempest/tests/lib/services/identity/v2/test_token_client.py deleted file mode 100644 index dfce9b37b..000000000 --- a/tempest/tests/lib/services/identity/v2/test_token_client.py +++ /dev/null @@ -1,104 +0,0 @@ -# Copyright 2015 Hewlett-Packard Development Company, L.P. -# -# 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 json - -import mock - -from tempest.lib.common import rest_client -from tempest.lib import exceptions -from tempest.lib.services.identity.v2 import token_client -from tempest.tests import base -from tempest.tests.lib import fake_http - - -class TestTokenClientV2(base.TestCase): - - def test_init_without_authurl(self): - self.assertRaises(exceptions.IdentityError, - token_client.TokenClient, None) - - def test_auth(self): - token_client_v2 = token_client.TokenClient('fake_url') - response = fake_http.fake_http_response( - None, status=200, - ) - body = {'access': {'token': 'fake_token'}} - - with mock.patch.object(token_client_v2, 'post') as post_mock: - post_mock.return_value = response, body - resp = token_client_v2.auth('fake_user', 'fake_pass') - - self.assertIsInstance(resp, rest_client.ResponseBody) - req_dict = json.dumps({ - 'auth': { - 'passwordCredentials': { - 'username': 'fake_user', - 'password': 'fake_pass', - }, - } - }, sort_keys=True) - post_mock.assert_called_once_with('fake_url/tokens', - body=req_dict) - - def test_auth_with_tenant(self): - token_client_v2 = token_client.TokenClient('fake_url') - response = fake_http.fake_http_response( - None, status=200, - ) - body = {'access': {'token': 'fake_token'}} - - with mock.patch.object(token_client_v2, 'post') as post_mock: - post_mock.return_value = response, body - resp = token_client_v2.auth('fake_user', 'fake_pass', - 'fake_tenant') - - self.assertIsInstance(resp, rest_client.ResponseBody) - req_dict = json.dumps({ - 'auth': { - 'tenantName': 'fake_tenant', - 'passwordCredentials': { - 'username': 'fake_user', - 'password': 'fake_pass', - }, - } - }, sort_keys=True) - post_mock.assert_called_once_with('fake_url/tokens', - body=req_dict) - - def test_request_with_str_body(self): - token_client_v2 = token_client.TokenClient('fake_url') - response = fake_http.fake_http_response( - None, status=200, - ) - body = str('{"access": {"token": "fake_token"}}') - - with mock.patch.object(token_client_v2, 'raw_request') as mock_raw_r: - mock_raw_r.return_value = response, body - resp, body = token_client_v2.request('GET', 'fake_uri') - self.assertIsInstance(body, dict) - - def test_request_with_bytes_body(self): - token_client_v2 = token_client.TokenClient('fake_url') - - response = fake_http.fake_http_response( - None, status=200, - ) - body = b'{"access": {"token": "fake_token"}}' - - with mock.patch.object(token_client_v2, 'raw_request') as mock_raw_r: - mock_raw_r.return_value = response, body - resp, body = token_client_v2.request('GET', 'fake_uri') - - self.assertIsInstance(body, dict) diff --git a/tempest/tests/lib/services/identity/v2/test_users_client.py b/tempest/tests/lib/services/identity/v2/test_users_client.py deleted file mode 100644 index 9534e4414..000000000 --- a/tempest/tests/lib/services/identity/v2/test_users_client.py +++ /dev/null @@ -1,243 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.lib.services.identity.v2 import users_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestUsersClient(base.BaseServiceTest): - FAKE_USER_INFO = { - "user": { - "id": "1", - "name": "test", - "email": "john.smith@example.org", - "enabled": True - } - } - - FAKE_LIST_USERS = { - "users": [ - { - "id": "1", - "name": "test", - "email": "john.smith@example.org", - "enabled": True - }, - { - "id": "2", - "name": "test2", - "email": "john.smith@example.org", - "enabled": True - } - ] - } - - FAKE_USER_EC2_CREDENTIAL_INFO = { - "credential": { - 'user_id': '9beb0e12f3e5416db8d7cccfc785db3b', - 'access': '79abf59acc77492a86170cbe2f1feafa', - 'secret': 'c4e7d3a691fd4563873d381a40320f46', - 'trust_id': None, - 'tenant_id': '596557269d7b4dd78631a602eb9f151d' - } - } - - FAKE_LIST_USER_EC2_CREDENTIALS = { - "credentials": [ - { - 'user_id': '9beb0e12f3e5416db8d7cccfc785db3b', - 'access': '79abf59acc77492a86170cbe2f1feafa', - 'secret': 'c4e7d3a691fd4563873d381a40320f46', - 'trust_id': None, - 'tenant_id': '596557269d7b4dd78631a602eb9f151d' - }, - { - 'user_id': '3beb0e12f3e5416db8d7cccfc785de4r', - 'access': '45abf59acc77492a86170cbe2f1fesde', - 'secret': 'g4e7d3a691fd4563873d381a40320e45', - 'trust_id': None, - 'tenant_id': '123557269d7b4dd78631a602eb9f112f' - } - ] - } - - def setUp(self): - super(TestUsersClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = users_client.UsersClient(fake_auth, - 'identity', 'regionOne') - - def _test_create_user(self, bytes_body=False): - self.check_service_client_function( - self.client.create_user, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_USER_INFO, - bytes_body, - name="test", - email="john.smith@example.org") - - def _test_update_user(self, bytes_body=False): - self.check_service_client_function( - self.client.update_user, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_USER_INFO, - bytes_body, - user_id="1", - name="test") - - def _test_show_user(self, bytes_body=False): - self.check_service_client_function( - self.client.show_user, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_USER_INFO, - bytes_body, - user_id="1") - - def _test_list_users(self, bytes_body=False): - self.check_service_client_function( - self.client.list_users, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_USERS, - bytes_body) - - def _test_update_user_enabled(self, bytes_body=False): - self.check_service_client_function( - self.client.update_user_enabled, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_USER_INFO, - bytes_body, - user_id="1", - enabled=True) - - def _test_update_user_password(self, bytes_body=False): - self.check_service_client_function( - self.client.update_user_password, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_USER_INFO, - bytes_body, - user_id="1", - password="pass") - - def _test_update_user_own_password(self, bytes_body=False): - self.check_service_client_function( - self.client.update_user_own_password, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_USER_INFO, - bytes_body, - user_id="1", - password="pass") - - def _test_create_user_ec2_credential(self, bytes_body=False): - self.check_service_client_function( - self.client.create_user_ec2_credential, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_USER_EC2_CREDENTIAL_INFO, - bytes_body, - user_id="1", - tenant_id="123") - - def _test_show_user_ec2_credential(self, bytes_body=False): - self.check_service_client_function( - self.client.show_user_ec2_credential, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_USER_EC2_CREDENTIAL_INFO, - bytes_body, - user_id="1", - access="123") - - def _test_list_user_ec2_credentials(self, bytes_body=False): - self.check_service_client_function( - self.client.list_user_ec2_credentials, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_USER_EC2_CREDENTIALS, - bytes_body, - user_id="1") - - def test_create_user_with_str_body(self): - self._test_create_user() - - def test_create_user_with_bytes_body(self): - self._test_create_user(bytes_body=True) - - def test_update_user_with_str_body(self): - self._test_update_user() - - def test_update_user_with_bytes_body(self): - self._test_update_user(bytes_body=True) - - def test_show_user_with_str_body(self): - self._test_show_user() - - def test_show_user_with_bytes_body(self): - self._test_show_user(bytes_body=True) - - def test_list_users_with_str_body(self): - self._test_list_users() - - def test_list_users_with_bytes_body(self): - self._test_list_users(bytes_body=True) - - def test_delete_user(self): - self.check_service_client_function( - self.client.delete_user, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - user_id="1", - status=204) - - def test_update_user_enabled_with_str_body(self): - self._test_update_user_enabled() - - def test_update_user_enabled_with_bytes_body(self): - self._test_update_user_enabled(bytes_body=True) - - def test_update_user_password_with_str_body(self): - self._test_update_user_password() - - def test_update_user_password_with_bytes_body(self): - self._test_update_user_password(bytes_body=True) - - def test_update_user_own_password_with_str_body(self): - self._test_update_user_own_password() - - def test_update_user_own_password_with_bytes_body(self): - self._test_update_user_own_password(bytes_body=True) - - def test_create_user_ec2_credential_with_str_body(self): - self._test_create_user_ec2_credential() - - def test_create_user_ec2_credential_with_bytes_body(self): - self._test_create_user_ec2_credential(bytes_body=True) - - def test_show_user_ec2_credential_with_str_body(self): - self._test_show_user_ec2_credential() - - def test_show_user_ec2_credential_with_bytes_body(self): - self._test_show_user_ec2_credential(bytes_body=True) - - def test_list_user_ec2_credentials_with_str_body(self): - self._test_list_user_ec2_credentials() - - def test_list_user_ec2_credentials_with_bytes_body(self): - self._test_list_user_ec2_credentials(bytes_body=True) - - def test_delete_user_ec2_credential(self): - self.check_service_client_function( - self.client.delete_user_ec2_credential, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - user_id="123", - access="1234", - status=204) diff --git a/tempest/tests/lib/services/identity/v3/__init__.py b/tempest/tests/lib/services/identity/v3/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/identity/v3/test_catalog_client.py b/tempest/tests/lib/services/identity/v3/test_catalog_client.py deleted file mode 100644 index 0ac8fe426..000000000 --- a/tempest/tests/lib/services/identity/v3/test_catalog_client.py +++ /dev/null @@ -1,86 +0,0 @@ -# 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 tempest.lib.services.identity.v3 import catalog_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestCatalogClient(base.BaseServiceTest): - FAKE_CATALOG_INFO = { - 'catalog': [ - { - 'endpoints': [ - { - 'id': '39dc322ce86c4111b4f06c2eeae0841b', - 'interface': 'public', - 'region': 'RegionOne', - 'url': 'http://localhost:5000' - }, - ], - 'id': 'ac58672276f848a7b1727850b3ebe826', - 'type': 'compute', - 'name': 'nova' - }, - { - 'endpoints': [ - { - 'id': '39dc322ce86c4111b4f06c2eeae0841b', - 'interface': 'public', - 'region': 'RegionOne', - 'url': 'http://localhost:5000' - }, - ], - 'id': 'b7c5ed2b486a46dbb4c221499d22991c', - 'type': 'image', - 'name': 'glance' - }, - { - 'endpoints': [ - { - 'id': '39dc322ce86c4111b4f06c2eeae0841b', - 'interface': 'public', - 'region': 'RegionOne', - 'url': 'http://localhost:5000' - }, - ], - 'id': '4363ae44bdf34a3981fde3b823cb9aa2', - 'type': 'identity', - 'name': 'keystone' - } - - ], - 'links': { - 'self': 'http://localhost/identity/v3/catalog', - 'previous': None, - 'next': None - } - } - - def setUp(self): - super(TestCatalogClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = catalog_client.CatalogClient(fake_auth, 'identity', - 'RegionOne') - - def test_show_catalog_with_bytes_body(self): - self._test_show_catalog(bytes_body=True) - - def test_show_catalog_with_str_body(self): - self._test_show_catalog() - - def _test_show_catalog(self, bytes_body=False): - self.check_service_client_function( - self.client.show_catalog, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CATALOG_INFO, - bytes_body) diff --git a/tempest/tests/lib/services/identity/v3/test_credentials_client.py b/tempest/tests/lib/services/identity/v3/test_credentials_client.py deleted file mode 100644 index 29d749665..000000000 --- a/tempest/tests/lib/services/identity/v3/test_credentials_client.py +++ /dev/null @@ -1,179 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.lib.services.identity.v3 import credentials_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestCredentialsClient(base.BaseServiceTest): - FAKE_CREATE_CREDENTIAL = { - "credential": { - "blob": "{\"access\":\"181920\",\"secret\":\"secretKey\"}", - "project_id": "731fc6f265cd486d900f16e84c5cb594", - "type": "ec2", - "user_id": "bb5476fd12884539b41d5a88f838d773" - } - } - - FAKE_INFO_CREDENTIAL = { - "credential": { - "user_id": "bb5476fd12884539b41d5a88f838d773", - "links": { - "self": "http://example.com/identity/v3/credentials/" + - "207e9b76935efc03804d3dd6ab52d22e9b22a0711e4" + - "ada4ff8b76165a07311d7" - }, - "blob": "{\"access\": \"a42a27755ce6442596b049bd7dd8a563\"," + - " \"secret\": \"71faf1d40bb24c82b479b1c6fbbd9f0c\"}", - "project_id": "6e01855f345f4c59812999b5e459137d", - "type": "ec2", - "id": "207e9b76935efc03804d3dd6ab52d22e9b22a0711e4ada4f" - } - } - - FAKE_LIST_CREDENTIALS = { - "credentials": [ - { - "user_id": "bb5476fd12884539b41d5a88f838d773", - "links": { - "self": "http://example.com/identity/v3/credentials/" + - "207e9b76935efc03804d3dd6ab52d22e9b22a0711e4" + - "ada4ff8b76165a07311d7" - }, - "blob": "{\"access\": \"a42a27755ce6442596b049bd7dd8a563\"," + - " \"secret\": \"71faf1d40bb24c82b479b1c6fbbd9f0c\"," + - " \"trust_id\": null}", - "project_id": "6e01855f345f4c59812999b5e459137d", - "type": "ec2", - "id": "207e9b76935efc03804d3dd6ab52d22e9b22a0711e4ada4f" - }, - { - "user_id": "6f556708d04b4ea6bc72d7df2296b71a", - "links": { - "self": "http://example.com/identity/v3/credentials/" + - "2441494e52ab6d594a34d74586075cb299489bdd1e9" + - "389e3ab06467a4f460609" - }, - "blob": "{\"access\": \"7da79ff0aa364e1396f067e352b9b79a\"," + - " \"secret\": \"7a18d68ba8834b799d396f3ff6f1e98c\"," + - " \"trust_id\": null}", - "project_id": "1a1d14690f3c4ec5bf5f321c5fde3c16", - "type": "ec2", - "id": "2441494e52ab6d594a34d74586075cb299489bdd1e9389e3" - }, - { - "user_id": "c14107e65d5c4a7f8894fc4b3fc209ff", - "links": { - "self": "http://example.com/identity/v3/credentials/" + - "3397b204b5f04c495bcdc8f34c8a39996f280f91726" + - "58241873e15f070ec79d7" - }, - "blob": "{\"access\": \"db9c58a558534a10a070110de4f9f20c\"," + - " \"secret\": \"973e790b88db447ba6f93bca02bc745b\"," + - " \"trust_id\": null}", - "project_id": "7396e43183db40dcbf40dd727637b548", - "type": "ec2", - "id": "3397b204b5f04c495bcdc8f34c8a39996f280f9172658241" - }, - { - "user_id": "bb5476fd12884539b41d5a88f838d773", - "links": { - "self": "http://example.com/identity/v3/credentials/" + - "7ef4faa904ae7b8b4ddc7bad15b05ee359dad7d7a9b" + - "82861d4ad92fdbbb2eb4e" - }, - "blob": "{\"access\": \"7d7559359b57419eb5f5f5dcd65ab57d\"," + - " \"secret\": \"570652bcf8c2483c86eb29e9734eed3c\"," + - " \"trust_id\": null}", - "project_id": "731fc6f265cd486d900f16e84c5cb594", - "type": "ec2", - "id": "7ef4faa904ae7b8b4ddc7bad15b05ee359dad7d7a9b82861" - }, - ], - "links": { - "self": "http://example.com/identity/v3/credentials", - "previous": None, - "next": None - } - } - - def setUp(self): - super(TestCredentialsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = credentials_client.CredentialsClient(fake_auth, - 'identity', - 'regionOne') - - def _test_create_credential(self, bytes_body=False): - self.check_service_client_function( - self.client.create_credential, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_CREDENTIAL, - bytes_body, status=201) - - def _test_show_credential(self, bytes_body=False): - self.check_service_client_function( - self.client.show_credential, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_INFO_CREDENTIAL, - bytes_body, - credential_id="207e9b76935efc03804d3dd6ab52d22e9b22a0711e4ada4f") - - def _test_update_credential(self, bytes_body=False): - self.check_service_client_function( - self.client.update_credential, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_INFO_CREDENTIAL, - bytes_body, - credential_id="207e9b76935efc03804d3dd6ab52d22e9b22a0711e4ada4f") - - def _test_list_credentials(self, bytes_body=False): - self.check_service_client_function( - self.client.list_credentials, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_CREDENTIALS, - bytes_body) - - def test_create_credential_with_str_body(self): - self._test_create_credential() - - def test_create_credential_with_bytes_body(self): - self._test_create_credential(bytes_body=True) - - def test_show_credential_with_str_body(self): - self._test_show_credential() - - def test_show_credential_with_bytes_body(self): - self._test_show_credential(bytes_body=True) - - def test_update_credential_with_str_body(self): - self._test_update_credential() - - def test_update_credential_with_bytes_body(self): - self._test_update_credential(bytes_body=True) - - def test_list_credentials_with_str_body(self): - self._test_list_credentials() - - def test_list_credentials_with_bytes_body(self): - self._test_list_credentials(bytes_body=True) - - def test_delete_credential(self): - self.check_service_client_function( - self.client.delete_credential, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - credential_id="207e9b76935efc03804d3dd6ab52d22e9b22a0711e4ada4f", - status=204) diff --git a/tempest/tests/lib/services/identity/v3/test_domain_configuration_client.py b/tempest/tests/lib/services/identity/v3/test_domain_configuration_client.py deleted file mode 100644 index 72e5bd2d5..000000000 --- a/tempest/tests/lib/services/identity/v3/test_domain_configuration_client.py +++ /dev/null @@ -1,217 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# 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 tempest.lib.services.identity.v3 import domain_configuration_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestDomainConfigurationClient(base.BaseServiceTest): - - FAKE_CONFIG_SETTINGS = { - "config": { - "identity": { - "driver": "ldap" - }, - "ldap": { - "url": "ldap://localhost", - "user": "", - "suffix": "cn=example,cn=com", - } - } - } - - FAKE_DOMAIN_ID = '07ef7d04-2941-4bee-8551-f79f08a021de' - - def setUp(self): - super(TestDomainConfigurationClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = domain_configuration_client.DomainConfigurationClient( - fake_auth, 'identity', 'regionOne') - - def _test_show_default_config_settings(self, bytes_body=False): - self.check_service_client_function( - self.client.show_default_config_settings, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CONFIG_SETTINGS, - bytes_body) - - def _test_show_default_group_config(self, bytes_body=False): - self.check_service_client_function( - self.client.show_default_group_config, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CONFIG_SETTINGS['config']['ldap'], - bytes_body, - group='ldap') - - def _test_show_default_group_option(self, bytes_body=False): - self.check_service_client_function( - self.client.show_default_group_option, - 'tempest.lib.common.rest_client.RestClient.get', - {'driver': 'ldap'}, - bytes_body, - group='identity', - option='driver') - - def _test_show_domain_group_option_config(self, bytes_body=False): - self.check_service_client_function( - self.client.show_domain_group_option_config, - 'tempest.lib.common.rest_client.RestClient.get', - {'driver': 'ldap'}, - bytes_body, - domain_id=self.FAKE_DOMAIN_ID, - group='identity', - option='driver') - - def _test_update_domain_group_option_config(self, bytes_body=False): - self.check_service_client_function( - self.client.update_domain_group_option_config, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_CONFIG_SETTINGS, - bytes_body, - domain_id=self.FAKE_DOMAIN_ID, - group='identity', - option='driver', - url='http://myldap/my_other_root') - - def _test_show_domain_group_config(self, bytes_body=False): - self.check_service_client_function( - self.client.show_domain_group_config, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CONFIG_SETTINGS['config']['ldap'], - bytes_body, - domain_id=self.FAKE_DOMAIN_ID, - group='ldap') - - def _test_update_domain_group_config(self, bytes_body=False): - self.check_service_client_function( - self.client.update_domain_group_config, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_CONFIG_SETTINGS['config']['ldap'], - bytes_body, - domain_id=self.FAKE_DOMAIN_ID, - group='ldap', - **self.FAKE_CONFIG_SETTINGS['config']) - - def _test_create_domain_config(self, bytes_body=False): - self.check_service_client_function( - self.client.create_domain_config, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_CONFIG_SETTINGS, - bytes_body, - domain_id=self.FAKE_DOMAIN_ID, - status=201) - - def _test_show_domain_config(self, bytes_body=False): - self.check_service_client_function( - self.client.show_domain_config, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CONFIG_SETTINGS, - bytes_body, - domain_id=self.FAKE_DOMAIN_ID) - - def _test_update_domain_config(self, bytes_body=False): - self.check_service_client_function( - self.client.update_domain_config, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_CONFIG_SETTINGS, - bytes_body, - domain_id=self.FAKE_DOMAIN_ID) - - def test_show_default_config_settings_with_str_body(self): - self._test_show_default_config_settings() - - def test_show_default_config_settings_with_bytes_body(self): - self._test_show_default_config_settings(bytes_body=True) - - def test_show_default_group_config_with_str_body(self): - self._test_show_default_group_config() - - def test_show_default_group_config_with_bytes_body(self): - self._test_show_default_group_config(bytes_body=True) - - def test_show_default_group_option_with_str_body(self): - self._test_show_default_group_option() - - def test_show_default_group_option_with_bytes_body(self): - self._test_show_default_group_option(bytes_body=True) - - def test_show_domain_group_option_config_with_str_body(self): - self._test_show_domain_group_option_config() - - def test_show_domain_group_option_config_with_bytes_body(self): - self._test_show_domain_group_option_config(bytes_body=True) - - def test_update_domain_group_option_config_with_str_body(self): - self._test_update_domain_group_option_config() - - def test_update_domain_group_option_config_with_bytes_body(self): - self._test_update_domain_group_option_config(bytes_body=True) - - def test_delete_domain_group_option_config(self): - self.check_service_client_function( - self.client.delete_domain_group_option_config, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=204, - domain_id=self.FAKE_DOMAIN_ID, - group='identity', - option='driver') - - def test_show_domain_group_config_with_str_body(self): - self._test_show_domain_group_config() - - def test_show_domain_group_config_with_bytes_body(self): - self._test_show_domain_group_config(bytes_body=True) - - def test_test_update_domain_group_config_with_str_body(self): - self._test_update_domain_group_config() - - def test_update_domain_group_config_with_bytes_body(self): - self._test_update_domain_group_config(bytes_body=True) - - def test_delete_domain_group_config(self): - self.check_service_client_function( - self.client.delete_domain_group_config, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=204, - domain_id=self.FAKE_DOMAIN_ID, - group='identity') - - def test_create_domain_config_with_str_body(self): - self._test_create_domain_config() - - def test_create_domain_config_with_bytes_body(self): - self._test_create_domain_config(bytes_body=True) - - def test_show_domain_config_with_str_body(self): - self._test_show_domain_config() - - def test_show_domain_config_with_bytes_body(self): - self._test_show_domain_config(bytes_body=True) - - def test_update_domain_config_with_str_body(self): - self._test_update_domain_config() - - def test_update_domain_config_with_bytes_body(self): - self._test_update_domain_config(bytes_body=True) - - def test_delete_domain_config(self): - self.check_service_client_function( - self.client.delete_domain_config, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=204, - domain_id=self.FAKE_DOMAIN_ID) diff --git a/tempest/tests/lib/services/identity/v3/test_domains_client.py b/tempest/tests/lib/services/identity/v3/test_domains_client.py deleted file mode 100644 index f89ced7c8..000000000 --- a/tempest/tests/lib/services/identity/v3/test_domains_client.py +++ /dev/null @@ -1,138 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# 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 tempest.lib.services.identity.v3 import domains_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestDomainsClient(base.BaseServiceTest): - FAKE_CREATE_DOMAIN = { - "domain": { - "description": "Domain description", - "enabled": True, - "name": "myDomain" - } - } - - FAKE_DOMAIN_INFO = { - "domain": { - "description": "Used for swift functional testing", - "enabled": True, - "id": "5a75994a3", - "links": { - "self": "http://example.com/identity/v3/domains/5a75994a3" - }, - "name": "swift_test" - } - } - - FAKE_LIST_DOMAINS = { - "domains": [ - { - "description": "Used for swift functional testing", - "enabled": True, - "id": "5a75994a3", - "links": { - "self": "http://example.com/identity/v3/domains/5a75994a3" - }, - "name": "swift_test" - }, - { - "description": "Owns users and tenants available on " + - "Identity API", - "enabled": True, - "id": "default", - "links": { - "self": "http://example.com/identity/v3/domains/default" - }, - "name": "Default" - } - ], - "links": { - "next": None, - "previous": None, - "self": "http://example.com/identity/v3/domains" - } - } - - def setUp(self): - super(TestDomainsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = domains_client.DomainsClient(fake_auth, - 'identity', - 'regionOne') - - def _test_create_domain(self, bytes_body=False): - self.check_service_client_function( - self.client.create_domain, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_DOMAIN, - bytes_body, - status=201) - - def _test_show_domain(self, bytes_body=False): - self.check_service_client_function( - self.client.show_domain, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_DOMAIN_INFO, - bytes_body, - domain_id="5a75994a3") - - def _test_list_domains(self, bytes_body=False): - self.check_service_client_function( - self.client.list_domains, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_DOMAINS, - bytes_body) - - def _test_update_domain(self, bytes_body=False): - self.check_service_client_function( - self.client.update_domain, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_DOMAIN_INFO, - bytes_body, - domain_id="5a75994a3") - - def test_create_domain_with_str_body(self): - self._test_create_domain() - - def test_create_domain_with_bytes_body(self): - self._test_create_domain(bytes_body=True) - - def test_show_domain_with_str_body(self): - self._test_show_domain() - - def test_show_domain_with_bytes_body(self): - self._test_show_domain(bytes_body=True) - - def test_list_domain_with_str_body(self): - self._test_list_domains() - - def test_list_domain_with_bytes_body(self): - self._test_list_domains(bytes_body=True) - - def test_update_domain_with_str_body(self): - self._test_update_domain() - - def test_update_domain_with_bytes_body(self): - self._test_update_domain(bytes_body=True) - - def test_delete_domain(self): - self.check_service_client_function( - self.client.delete_domain, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - domain_id="5a75994a3", - status=204) diff --git a/tempest/tests/lib/services/identity/v3/test_endpoint_filter_client.py b/tempest/tests/lib/services/identity/v3/test_endpoint_filter_client.py deleted file mode 100644 index 7faf6a02f..000000000 --- a/tempest/tests/lib/services/identity/v3/test_endpoint_filter_client.py +++ /dev/null @@ -1,165 +0,0 @@ -# Copyright 2017 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 tempest.lib.services.identity.v3 import endpoint_filter_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestEndPointsFilterClient(base.BaseServiceTest): - FAKE_LIST_PROJECTS_FOR_ENDPOINTS = { - "projects": [ - { - "domain_id": "1777c7", - "enabled": True, - "id": "1234ab1", - "type": "compute", - "links": { - "self": "http://example.com/identity/v3/projects/1234ab1" - }, - "name": "Project 1", - "description": "Project 1 description", - }, - { - "domain_id": "1777c7", - "enabled": True, - "id": "5678cd2", - "type": "compute", - "links": { - "self": "http://example.com/identity/v3/projects/5678cd2" - }, - "name": "Project 2", - "description": "Project 2 description", - } - ], - "links": { - "self": "http://example.com/identity/v3/OS-EP-FILTER/endpoints/\ - u6ay5u/projects", - "previous": None, - "next": None - } - } - - FAKE_LIST_ENDPOINTS_FOR_PROJECTS = { - "endpoints": [ - { - "id": "u6ay5u", - "interface": "public", - "url": "http://example.com/identity/", - "region": "north", - "links": { - "self": "http://example.com/identity/v3/endpoints/u6ay5u" - }, - "service_id": "5um4r", - }, - { - "id": "u6ay5u", - "interface": "internal", - "url": "http://example.com/identity/", - "region": "south", - "links": { - "self": "http://example.com/identity/v3/endpoints/u6ay5u" - }, - "service_id": "5um4r", - }, - ], - "links": { - "self": "http://example.com/identity/v3/OS-EP-FILTER/projects/\ - 1234ab1/endpoints", - "previous": None, - "next": None - } - } - - def setUp(self): - super(TestEndPointsFilterClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = endpoint_filter_client.EndPointsFilterClient( - fake_auth, 'identity', 'regionOne') - - def _test_add_endpoint_to_project(self, bytes_body=False): - self.check_service_client_function( - self.client.add_endpoint_to_project, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - bytes_body, - status=204, - project_id=3, - endpoint_id=4) - - def _test_check_endpoint_in_project(self, bytes_body=False): - self.check_service_client_function( - self.client.check_endpoint_in_project, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - bytes_body, - status=204, - project_id=3, - endpoint_id=4) - - def _test_list_projects_for_endpoint(self, bytes_body=False): - self.check_service_client_function( - self.client.list_projects_for_endpoint, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_PROJECTS_FOR_ENDPOINTS, - bytes_body, - status=200, - endpoint_id=3) - - def _test_list_endpoints_in_project(self, bytes_body=False): - self.check_service_client_function( - self.client.list_endpoints_in_project, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ENDPOINTS_FOR_PROJECTS, - bytes_body, - status=200, - project_id=4) - - def _test_delete_endpoint_from_project(self, bytes_body=False): - self.check_service_client_function( - self.client.delete_endpoint_from_project, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - bytes_body, - status=204, - project_id=3, - endpoint_id=4) - - def test_add_endpoint_to_project_with_str_body(self): - self._test_add_endpoint_to_project() - - def test_add_endpoint_to_project_with_bytes_body(self): - self._test_add_endpoint_to_project(bytes_body=True) - - def test_check_endpoint_in_project_with_str_body(self): - self._test_check_endpoint_in_project() - - def test_check_endpoint_in_project_with_bytes_body(self): - self._test_check_endpoint_in_project(bytes_body=True) - - def test_list_projects_for_endpoint_with_str_body(self): - self._test_list_projects_for_endpoint() - - def test_list_projects_for_endpoint_with_bytes_body(self): - self._test_list_projects_for_endpoint(bytes_body=True) - - def test_list_endpoints_in_project_with_str_body(self): - self._test_list_endpoints_in_project() - - def test_list_endpoints_in_project_with_bytes_body(self): - self._test_list_endpoints_in_project(bytes_body=True) - - def test_delete_endpoint_from_project(self): - self._test_delete_endpoint_from_project() diff --git a/tempest/tests/lib/services/identity/v3/test_endpoint_groups_client.py b/tempest/tests/lib/services/identity/v3/test_endpoint_groups_client.py deleted file mode 100644 index c724f0a33..000000000 --- a/tempest/tests/lib/services/identity/v3/test_endpoint_groups_client.py +++ /dev/null @@ -1,162 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 tempest.lib.services.identity.v3 import endpoint_groups_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestEndPointGroupsClient(base.BaseServiceTest): - FAKE_CREATE_ENDPOINT_GROUP = { - "endpoint_group": { - "id": 1, - "name": "FAKE_ENDPOINT_GROUP", - "description": "FAKE SERVICE ENDPOINT GROUP", - "filters": { - "service_id": 1 - } - } - } - - FAKE_ENDPOINT_GROUP_INFO = { - "endpoint_group": { - "id": 1, - "name": "FAKE_ENDPOINT_GROUP", - "description": "FAKE SERVICE ENDPOINT GROUP", - "links": { - "self": "http://example.com/identity/v3/OS-EP-FILTER/" + - "endpoint_groups/1" - }, - "filters": { - "service_id": 1 - } - } - } - - FAKE_LIST_ENDPOINT_GROUPS = { - "endpoint_groups": [ - { - "id": 1, - "name": "SERVICE_GROUP1", - "description": "FAKE SERVICE ENDPOINT GROUP", - "links": { - "self": "http://example.com/identity/v3/OS-EP-FILTER/" + - "endpoint_groups/1" - }, - "filters": { - "service_id": 1 - } - }, - { - "id": 2, - "name": "SERVICE_GROUP2", - "description": "FAKE SERVICE ENDPOINT GROUP", - "links": { - "self": "http://example.com/identity/v3/OS-EP-FILTER/" + - "endpoint_groups/2" - }, - "filters": { - "service_id": 2 - } - } - ] - } - - def setUp(self): - super(TestEndPointGroupsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = endpoint_groups_client.EndPointGroupsClient( - fake_auth, 'identity', 'regionOne') - - def _test_create_endpoint_group(self, bytes_body=False): - self.check_service_client_function( - self.client.create_endpoint_group, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_ENDPOINT_GROUP, - bytes_body, - status=201, - name="FAKE_ENDPOINT_GROUP", - filters={'service_id': "1"}) - - def _test_show_endpoint_group(self, bytes_body=False): - self.check_service_client_function( - self.client.show_endpoint_group, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_ENDPOINT_GROUP_INFO, - bytes_body, - endpoint_group_id="1") - - def _test_check_endpoint_group(self, bytes_body=False): - self.check_service_client_function( - self.client.check_endpoint_group, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - bytes_body, - status=200, - endpoint_group_id="1") - - def _test_update_endpoint_group(self, bytes_body=False): - self.check_service_client_function( - self.client.update_endpoint_group, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_ENDPOINT_GROUP_INFO, - bytes_body, - endpoint_group_id="1", - name="NewName") - - def _test_list_endpoint_groups(self, bytes_body=False): - self.check_service_client_function( - self.client.list_endpoint_groups, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ENDPOINT_GROUPS, - bytes_body) - - def test_create_endpoint_group_with_str_body(self): - self._test_create_endpoint_group() - - def test_create_endpoint_group_with_bytes_body(self): - self._test_create_endpoint_group(bytes_body=True) - - def test_show_endpoint_group_with_str_body(self): - self._test_show_endpoint_group() - - def test_show_endpoint_group_with_bytes_body(self): - self._test_show_endpoint_group(bytes_body=True) - - def test_check_endpoint_group_with_str_body(self): - self._test_check_endpoint_group() - - def test_check_endpoint_group_with_bytes_body(self): - self._test_check_endpoint_group(bytes_body=True) - - def test_list_endpoint_groups_with_str_body(self): - self._test_list_endpoint_groups() - - def test_list_endpoint_groups_with_bytes_body(self): - self._test_list_endpoint_groups(bytes_body=True) - - def test_update_endpoint_group_with_str_body(self): - self._test_update_endpoint_group() - - def test_update_endpoint_group_with_bytes_body(self): - self._test_update_endpoint_group(bytes_body=True) - - def test_delete_endpoint_group(self): - self.check_service_client_function( - self.client.delete_endpoint_group, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - endpoint_group_id="1", - status=204) diff --git a/tempest/tests/lib/services/identity/v3/test_endpoints_client.py b/tempest/tests/lib/services/identity/v3/test_endpoints_client.py deleted file mode 100644 index ca15dd160..000000000 --- a/tempest/tests/lib/services/identity/v3/test_endpoints_client.py +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# 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 tempest.lib.services.identity.v3 import endpoints_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestEndpointsClient(base.BaseServiceTest): - FAKE_CREATE_ENDPOINT = { - "endpoint": { - "id": 1, - "tenantId": 1, - "region": "North", - "type": "compute", - "publicURL": "https://compute.north.public.com/v1", - "internalURL": "https://compute.north.internal.com/v1", - "adminURL": "https://compute.north.internal.com/v1" - } - } - - FAKE_LIST_ENDPOINTS = { - "endpoints": [ - { - "id": 1, - "tenantId": "1", - "region": "North", - "type": "compute", - "publicURL": "https://compute.north.public.com/v1", - "internalURL": "https://compute.north.internal.com/v1", - "adminURL": "https://compute.north.internal.com/v1" - }, - { - "id": 2, - "tenantId": "1", - "region": "South", - "type": "compute", - "publicURL": "https://compute.north.public.com/v1", - "internalURL": "https://compute.north.internal.com/v1", - "adminURL": "https://compute.north.internal.com/v1" - } - ] - } - - FAKE_SERVICE_ID = "a4dc5060-f757-4662-b658-edd2aefbb41d" - - def setUp(self): - super(TestEndpointsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = endpoints_client.EndPointsClient(fake_auth, - 'identity', 'regionOne') - - def _test_create_endpoint(self, bytes_body=False): - self.check_service_client_function( - self.client.create_endpoint, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_ENDPOINT, - bytes_body, - status=201, - service_id="b344506af7644f6794d9cb316600b020", - region="region-demo", - publicurl="https://compute.north.public.com/v1", - adminurl="https://compute.north.internal.com/v1", - internalurl="https://compute.north.internal.com/v1") - - def _test_list_endpoints(self, bytes_body=False, mock_args='endpoints', - **params): - self.check_service_client_function( - self.client.list_endpoints, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ENDPOINTS, - bytes_body, - mock_args=[mock_args], - **params) - - def test_create_endpoint_with_str_body(self): - self._test_create_endpoint() - - def test_create_endpoint_with_bytes_body(self): - self._test_create_endpoint(bytes_body=True) - - def test_list_endpoints_with_str_body(self): - self._test_list_endpoints() - - def test_list_endpoints_with_bytes_body(self): - self._test_list_endpoints(bytes_body=True) - - def test_list_endpoints_with_params(self): - # Run the test separately for each param, to avoid assertion error - # resulting from randomized params order. - mock_args = 'endpoints?service_id=%s' % self.FAKE_SERVICE_ID - self._test_list_endpoints(mock_args=mock_args, - service_id=self.FAKE_SERVICE_ID) - - mock_args = 'endpoints?interface=public' - self._test_list_endpoints(mock_args=mock_args, interface='public') - - def test_delete_endpoint(self): - self.check_service_client_function( - self.client.delete_endpoint, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - endpoint_id="b344506af7644f6794d9cb316600b020", - status=204) diff --git a/tempest/tests/lib/services/identity/v3/test_groups_client.py b/tempest/tests/lib/services/identity/v3/test_groups_client.py deleted file mode 100644 index 38cf3ae1c..000000000 --- a/tempest/tests/lib/services/identity/v3/test_groups_client.py +++ /dev/null @@ -1,213 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# 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 tempest.lib.services.identity.v3 import groups_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestGroupsClient(base.BaseServiceTest): - FAKE_CREATE_GROUP = { - 'group': { - 'description': 'Tempest Group Description', - 'domain_id': 'TempestDomain', - 'name': 'Tempest Group', - } - } - - FAKE_GROUP_INFO = { - 'group': { - 'description': 'Tempest Group Description', - 'domain_id': 'TempestDomain', - 'id': '6e13e2068cf9466e98950595baf6bb35', - 'links': { - 'self': 'http://example.com/identity/v3/groups/' + - '6e13e2068cf9466e98950595baf6bb35' - }, - 'name': 'Tempest Group', - } - } - - FAKE_GROUP_LIST = { - 'links': { - 'self': 'http://example.com/identity/v3/groups', - 'previous': None, - 'next': None, - }, - 'groups': [ - { - 'description': 'Tempest Group One Description', - 'domain_id': 'TempestDomain', - 'id': '1c92f3453ed34291a074b87493455b8f', - 'links': { - 'self': 'http://example.com/identity/v3/groups/' + - '1c92f3453ed34291a074b87493455b8f' - }, - 'name': 'Tempest Group One', - }, - { - 'description': 'Tempest Group Two Description', - 'domain_id': 'TempestDomain', - 'id': 'ce9e7dafed3b4877a7d4466ed730a9ee', - 'links': { - 'self': 'http://example.com/identity/v3/groups/' + - 'ce9e7dafed3b4877a7d4466ed730a9ee' - }, - 'name': 'Tempest Group Two', - }, - ] - } - - FAKE_USER_LIST = { - 'links': { - 'self': 'http://example.com/identity/v3/groups/' + - '6e13e2068cf9466e98950595baf6bb35/users', - 'previous': None, - 'next': None, - }, - 'users': [ - { - 'domain_id': 'TempestDomain', - 'description': 'Tempest Test User One Description', - 'enabled': True, - 'id': '642688fa65a84217b86cef3c063de2b9', - 'name': 'TempestUserOne', - 'links': { - 'self': 'http://example.com/identity/v3/users/' + - '642688fa65a84217b86cef3c063de2b9' - } - }, - { - 'domain_id': 'TempestDomain', - 'description': 'Tempest Test User Two Description', - 'enabled': True, - 'id': '1048ead6f8ef4a859b44ffbce3ac0b52', - 'name': 'TempestUserTwo', - 'links': { - 'self': 'http://example.com/identity/v3/users/' + - '1048ead6f8ef4a859b44ffbce3ac0b52' - } - }, - ] - } - - def setUp(self): - super(TestGroupsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = groups_client.GroupsClient(fake_auth, 'identity', - 'regionOne') - - def _test_create_group(self, bytes_body=False): - self.check_service_client_function( - self.client.create_group, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_GROUP, - bytes_body, - status=201, - ) - - def _test_show_group(self, bytes_body=False): - self.check_service_client_function( - self.client.show_group, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_GROUP_INFO, - bytes_body, - group_id='6e13e2068cf9466e98950595baf6bb35', - ) - - def _test_list_groups(self, bytes_body=False): - self.check_service_client_function( - self.client.list_groups, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_GROUP_LIST, - bytes_body, - ) - - def _test_update_group(self, bytes_body=False): - self.check_service_client_function( - self.client.update_group, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_GROUP_INFO, - bytes_body, - group_id='6e13e2068cf9466e98950595baf6bb35', - name='NewName', - ) - - def _test_list_users_in_group(self, bytes_body=False): - self.check_service_client_function( - self.client.list_group_users, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_USER_LIST, - bytes_body, - group_id='6e13e2068cf9466e98950595baf6bb35', - ) - - def test_create_group_with_string_body(self): - self._test_create_group() - - def test_create_group_with_bytes_body(self): - self._test_create_group(bytes_body=True) - - def test_show_group_with_string_body(self): - self._test_show_group() - - def test_show_group_with_bytes_body(self): - self._test_show_group(bytes_body=True) - - def test_list_groups_with_string_body(self): - self._test_list_groups() - - def test_list_groups_with_bytes_body(self): - self._test_list_groups(bytes_body=True) - - def test_update_group_with_string_body(self): - self._test_update_group() - - def test_update_group_with_bytes_body(self): - self._test_update_group(bytes_body=True) - - def test_list_users_in_group_with_string_body(self): - self._test_list_users_in_group() - - def test_list_users_in_group_with_bytes_body(self): - self._test_list_users_in_group(bytes_body=True) - - def test_delete_group(self): - self.check_service_client_function( - self.client.delete_group, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - group_id='6e13e2068cf9466e98950595baf6bb35', - status=204, - ) - - def test_add_user_to_group(self): - self.check_service_client_function( - self.client.add_group_user, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - status=204, - group_id='6e13e2068cf9466e98950595baf6bb35', - user_id='642688fa65a84217b86cef3c063de2b9', - ) - - def test_check_user_in_group(self): - self.check_service_client_function( - self.client.check_group_user_existence, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - status=204, - group_id='6e13e2068cf9466e98950595baf6bb35', - user_id='642688fa65a84217b86cef3c063de2b9', - ) diff --git a/tempest/tests/lib/services/identity/v3/test_identity_client.py b/tempest/tests/lib/services/identity/v3/test_identity_client.py deleted file mode 100644 index 6572947fe..000000000 --- a/tempest/tests/lib/services/identity/v3/test_identity_client.py +++ /dev/null @@ -1,124 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.lib.services.identity.v3 import identity_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestIdentityClient(base.BaseServiceTest): - FAKE_TOKEN = { - "tokens": { - "id": "cbc36478b0bd8e67e89", - "name": "FakeToken", - "type": "token", - } - } - - FAKE_API_INFO = { - "name": "API_info", - "type": "API", - "description": "test_description" - } - - FAKE_AUTH_PROJECTS = { - "projects": [ - { - "domain_id": "1789d1", - "enabled": True, - "id": "263fd9", - "links": { - "self": "https://example.com/identity/v3/projects/263fd9" - }, - "name": "Test Group" - }, - { - "domain_id": "1789d1", - "enabled": True, - "id": "50ef01", - "links": { - "self": "https://example.com/identity/v3/projects/50ef01" - }, - "name": "Build Group" - } - ], - "links": { - "self": "https://example.com/identity/v3/auth/projects", - "previous": None, - "next": None - } - } - - def setUp(self): - super(TestIdentityClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = identity_client.IdentityClient(fake_auth, - 'identity', - 'regionOne') - - def _test_show_api_description(self, bytes_body=False): - self.check_service_client_function( - self.client.show_api_description, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_API_INFO, - bytes_body) - - def _test_show_token(self, bytes_body=False): - self.check_service_client_function( - self.client.show_token, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_TOKEN, - bytes_body, - resp_token="cbc36478b0bd8e67e89") - - def _test_list_auth_projects(self, bytes_body=False): - self.check_service_client_function( - self.client.list_auth_projects, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_AUTH_PROJECTS, - bytes_body) - - def test_show_api_description_with_str_body(self): - self._test_show_api_description() - - def test_show_api_description_with_bytes_body(self): - self._test_show_api_description(bytes_body=True) - - def test_show_token_with_str_body(self): - self._test_show_token() - - def test_show_token_with_bytes_body(self): - self._test_show_token(bytes_body=True) - - def test_delete_token(self): - self.check_service_client_function( - self.client.delete_token, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - resp_token="cbc36478b0bd8e67e89", - status=204) - - def test_check_token_existence(self): - self.check_service_client_function( - self.client.check_token_existence, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - resp_token="cbc36478b0bd8e67e89", - status=200) - - def test_list_auth_projects_with_str_body(self): - self._test_list_auth_projects() - - def test_list_auth_projects_with_bytes_body(self): - self._test_list_auth_projects(bytes_body=True) diff --git a/tempest/tests/lib/services/identity/v3/test_inherited_roles_client.py b/tempest/tests/lib/services/identity/v3/test_inherited_roles_client.py deleted file mode 100644 index 9da3cce61..000000000 --- a/tempest/tests/lib/services/identity/v3/test_inherited_roles_client.py +++ /dev/null @@ -1,220 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.lib.services.identity.v3 import inherited_roles_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestInheritedRolesClient(base.BaseServiceTest): - FAKE_LIST_INHERITED_ROLES = { - "roles": [ - { - "id": "1", - "name": "test", - "links": "example.com" - }, - { - "id": "2", - "name": "test2", - "links": "example.com" - } - ] - } - - def setUp(self): - super(TestInheritedRolesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = inherited_roles_client.InheritedRolesClient( - fake_auth, 'identity', 'regionOne') - - def _test_create_inherited_role_on_domains_user(self, bytes_body=False): - self.check_service_client_function( - self.client.create_inherited_role_on_domains_user, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - bytes_body, - domain_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) - - def _test_list_inherited_project_role_for_user_on_domain( - self, bytes_body=False): - self.check_service_client_function( - self.client.list_inherited_project_role_for_user_on_domain, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_INHERITED_ROLES, - bytes_body, - domain_id="b344506af7644f6794d9cb316600b020", - user_id="123") - - def _test_create_inherited_role_on_domains_group(self, bytes_body=False): - self.check_service_client_function( - self.client.create_inherited_role_on_domains_group, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - bytes_body, - domain_id="b344506af7644f6794d9cb316600b020", - group_id="123", - role_id="1234", - status=204) - - def _test_list_inherited_project_role_for_group_on_domain( - self, bytes_body=False): - self.check_service_client_function( - self.client.list_inherited_project_role_for_group_on_domain, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_INHERITED_ROLES, - bytes_body, - domain_id="b344506af7644f6794d9cb316600b020", - group_id="123") - - def _test_create_inherited_role_on_projects_user(self, bytes_body=False): - self.check_service_client_function( - self.client.create_inherited_role_on_projects_user, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - bytes_body, - project_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) - - def _test_create_inherited_role_on_projects_group(self, bytes_body=False): - self.check_service_client_function( - self.client.create_inherited_role_on_projects_group, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - bytes_body, - project_id="b344506af7644f6794d9cb316600b020", - group_id="123", - role_id="1234", - status=204) - - def test_create_inherited_role_on_domains_user_with_str_body(self): - self._test_create_inherited_role_on_domains_user() - - def test_create_inherited_role_on_domains_user_with_bytes_body(self): - self._test_create_inherited_role_on_domains_user(bytes_body=True) - - def test_create_inherited_role_on_domains_group_with_str_body(self): - self._test_create_inherited_role_on_domains_group() - - def test_create_inherited_role_on_domains_group_with_bytes_body(self): - self._test_create_inherited_role_on_domains_group(bytes_body=True) - - def test_create_inherited_role_on_projects_user_with_str_body(self): - self._test_create_inherited_role_on_projects_user() - - def test_create_inherited_role_on_projects_group_with_bytes_body(self): - self._test_create_inherited_role_on_projects_group(bytes_body=True) - - def test_list_inherited_project_role_for_user_on_domain_with_str_body( - self): - self._test_list_inherited_project_role_for_user_on_domain() - - def test_list_inherited_project_role_for_user_on_domain_with_bytes_body( - self): - self._test_list_inherited_project_role_for_user_on_domain( - bytes_body=True) - - def test_list_inherited_project_role_for_group_on_domain_with_str_body( - self): - self._test_list_inherited_project_role_for_group_on_domain() - - def test_list_inherited_project_role_for_group_on_domain_with_bytes_body( - self): - self._test_list_inherited_project_role_for_group_on_domain( - bytes_body=True) - - def test_delete_inherited_role_from_user_on_domain(self): - self.check_service_client_function( - self.client.delete_inherited_role_from_user_on_domain, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - domain_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) - - def test_check_user_inherited_project_role_on_domain(self): - self.check_service_client_function( - self.client.check_user_inherited_project_role_on_domain, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - domain_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) - - def test_delete_inherited_role_from_group_on_domain(self): - self.check_service_client_function( - self.client.delete_inherited_role_from_group_on_domain, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - domain_id="b344506af7644f6794d9cb316600b020", - group_id="123", - role_id="1234", - status=204) - - def test_check_group_inherited_project_role_on_domain(self): - self.check_service_client_function( - self.client.check_group_inherited_project_role_on_domain, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - domain_id="b344506af7644f6794d9cb316600b020", - group_id="123", - role_id="1234", - status=204) - - def test_delete_inherited_role_from_user_on_project(self): - self.check_service_client_function( - self.client.delete_inherited_role_from_user_on_project, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - project_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) - - def test_check_user_has_flag_on_inherited_to_project(self): - self.check_service_client_function( - self.client.check_user_has_flag_on_inherited_to_project, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - project_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) - - def test_delete_inherited_role_from_group_on_project(self): - self.check_service_client_function( - self.client.delete_inherited_role_from_group_on_project, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - project_id="b344506af7644f6794d9cb316600b020", - group_id="123", - role_id="1234", - status=204) - - def test_check_group_has_flag_on_inherited_to_project(self): - self.check_service_client_function( - self.client.check_group_has_flag_on_inherited_to_project, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - project_id="b344506af7644f6794d9cb316600b020", - group_id="123", - role_id="1234", - status=204) diff --git a/tempest/tests/lib/services/identity/v3/test_oauth_consumers_client.py b/tempest/tests/lib/services/identity/v3/test_oauth_consumers_client.py deleted file mode 100644 index 8d5379254..000000000 --- a/tempest/tests/lib/services/identity/v3/test_oauth_consumers_client.py +++ /dev/null @@ -1,160 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 tempest.lib.services.identity.v3 import oauth_consumers_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestOAUTHConsumerClient(base.BaseServiceTest): - FAKE_CREATE_CONSUMER = { - "consumer": { - 'description': 'A fake description 1' - } - - } - - FAKE_CONSUMER_INFO = { - "consumer": { - 'id': '6392c7d3b7a2062e09a07aa377', - 'links': { - 'self': 'http://example.com/identity/v3/' + - 'OS-OAUTH1/consumers/g6f2l9' - }, - 'description': 'A description that is fake' - } - - } - - FAKE_LIST_CONSUMERS = { - 'links': { - 'self': 'http://example.com/identity/v3/OS-OAUTH1/consumers/', - 'next': None, - 'previous': None - }, - 'consumers': [ - { - 'id': '6392c7d3b7a2062e09a07aa377', - 'links': { - 'self': 'http://example.com/identity/v3/' + - 'OS-OAUTH1/consumers/6b9f2g5' - }, - 'description': 'A description that is fake' - }, - { - 'id': '677a855c9e3eb3a3954b36aca6', - 'links': { - 'self': 'http://example.com/identity/v3/' + - 'OS-OAUTH1/consumers/6a9f2366' - }, - 'description': 'A very fake description 2' - }, - { - 'id': '9d3ac57b08d65e07826b5e506', - 'links': { - 'self': 'http://example.com/identity/v3/' + - 'OS-OAUTH1/consumers/626b5e506' - }, - 'description': 'A very fake description 3' - }, - { - 'id': 'b522d163b1a18e928aca9y426', - 'links': { - 'self': 'http://example.com/identity/v3/' + - 'OS-OAUTH1/consumers/g7ca9426' - }, - 'description': 'A very fake description 4' - }, - { - 'id': 'b7e47321b5ef9051f93c2049e', - 'links': { - 'self': 'http://example.com/identity/v3/' + - 'OS-OAUTH1/consumers/23d82049e' - }, - 'description': 'A very fake description 5' - } - ] - } - - def setUp(self): - super(TestOAUTHConsumerClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = oauth_consumers_client.OAUTHConsumerClient(fake_auth, - 'identity', - 'regionOne') - - def _test_create_consumer(self, bytes_body=False): - self.check_service_client_function( - self.client.create_consumer, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_CONSUMER, - bytes_body, - description=self.FAKE_CREATE_CONSUMER["consumer"]["description"], - status=201) - - def _test_show_consumer(self, bytes_body=False): - self.check_service_client_function( - self.client.show_consumer, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CONSUMER_INFO, - bytes_body, - consumer_id="6392c7d3b7a2062e09a07aa377") - - def _test_list_consumers(self, bytes_body=False): - self.check_service_client_function( - self.client.list_consumers, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_CONSUMERS, - bytes_body) - - def _test_update_consumer(self, bytes_body=False): - self.check_service_client_function( - self.client.update_consumer, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_CONSUMER_INFO, - bytes_body, - consumer_id="6392c7d3b7a2062e09a07aa377") - - def test_create_consumer_with_str_body(self): - self._test_create_consumer() - - def test_create_consumer_with_bytes_body(self): - self._test_create_consumer(bytes_body=True) - - def test_show_consumer_with_str_body(self): - self._test_show_consumer() - - def test_show_consumer_with_bytes_body(self): - self._test_show_consumer(bytes_body=True) - - def test_list_consumers_with_str_body(self): - self._test_list_consumers() - - def test_list_consumers_with_bytes_body(self): - self._test_list_consumers(bytes_body=True) - - def test_update_consumer_with_str_body(self): - self._test_update_consumer() - - def test_update_consumer_with_bytes_body(self): - self._test_update_consumer(bytes_body=True) - - def test_delete_consumer(self): - self.check_service_client_function( - self.client.delete_consumer, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - consumer_id="6392c7d3b7a2062e09a07aa377", - status=204) diff --git a/tempest/tests/lib/services/identity/v3/test_oauth_token_client.py b/tempest/tests/lib/services/identity/v3/test_oauth_token_client.py deleted file mode 100644 index 420ea5f24..000000000 --- a/tempest/tests/lib/services/identity/v3/test_oauth_token_client.py +++ /dev/null @@ -1,215 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 fixtures - -from tempest.lib.services.identity.v3 import oauth_token_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib import fake_http -from tempest.tests.lib.services import base - - -class TestOAUTHTokenClient(base.BaseServiceTest): - FAKE_CREATE_REQUEST_TOKEN = { - 'oauth_token': '29971f', - 'oauth_token_secret': '238eb8', - 'oauth_expires_at': '2013-09-11T06:07:51.501805Z' - } - - FAKE_AUTHORIZE_REQUEST_TOKEN = { - 'token': { - 'oauth_verifier': '8171' - } - } - - FAKE_CREATE_ACCESS_TOKEN = { - 'oauth_token': 'accd36', - 'oauth_token_secret': 'aa47da', - 'oauth_expires_at': '2013-09-11T06:07:51.501805Z' - } - - FAKE_ACCESS_TOKEN_INFO = { - 'access_token': { - 'consumer_id': '7fea2d', - 'id': '6be26a', - 'expires_at': '2013-09-11T06:07:51.501805Z', - 'links': { - 'roles': 'http://example.com/identity/v3/' + - 'users/ce9e07/OS-OAUTH1/access_tokens/6be26a/roles', - 'self': 'http://example.com/identity/v3/' + - 'users/ce9e07/OS-OAUTH1/access_tokens/6be26a' - }, - 'project_id': 'b9fca3', - 'authorizing_user_id': 'ce9e07' - } - } - - FAKE_LIST_ACCESS_TOKENS = { - 'access_tokens': [ - { - 'consumer_id': '7fea2d', - 'id': '6be26a', - 'expires_at': '2013-09-11T06:07:51.501805Z', - 'links': { - 'roles': 'http://example.com/identity/v3/' + - 'users/ce9e07/OS-OAUTH1/access_tokens/' + - '6be26a/roles', - 'self': 'http://example.com/identity/v3/' + - 'users/ce9e07/OS-OAUTH1/access_tokens/6be26a' - }, - 'project_id': 'b9fca3', - 'authorizing_user_id': 'ce9e07' - } - ], - 'links': { - 'next': None, - 'previous': None, - 'self': 'http://example.com/identity/v3/' + - 'users/ce9e07/OS-OAUTH1/access_tokens' - } - } - - FAKE_LIST_ACCESS_TOKEN_ROLES = { - 'roles': [ - { - 'id': '26b860', - 'domain_id': 'fake_domain', - 'links': { - 'self': 'http://example.com/identity/v3/' + - 'roles/26b860' - }, - 'name': 'fake_role' - } - ], - 'links': { - 'next': None, - 'previous': None, - 'self': 'http://example.com/identity/v3/' + - 'users/ce9e07/OS-OAUTH1/access_tokens/6be26a/roles' - } - } - - FAKE_ACCESS_TOKEN_ROLE_INFO = { - 'role': { - 'id': '26b860', - 'domain_id': 'fake_domain', - 'links': { - 'self': 'http://example.com/identity/v3/' + - 'roles/26b860' - }, - 'name': 'fake_role' - } - } - - def setUp(self): - super(TestOAUTHTokenClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = oauth_token_client.OAUTHTokenClient(fake_auth, - 'identity', - 'regionOne') - - def _mock_token_response(self, body): - temp_response = [key + '=' + value for key, value in body.items()] - return '&'.join(temp_response) - - def _test_authorize_request_token(self, bytes_body=False): - self.check_service_client_function( - self.client.authorize_request_token, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_AUTHORIZE_REQUEST_TOKEN, - bytes_body, - request_token_id=self.FAKE_CREATE_REQUEST_TOKEN['oauth_token'], - role_ids=['26b860'], - status=200) - - def test_create_request_token(self): - mock_resp = self._mock_token_response(self.FAKE_CREATE_REQUEST_TOKEN) - resp = fake_http.fake_http_response(None, status=201), mock_resp - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.rest_client.RestClient.post', - return_value=resp)) - - resp = self.client.create_request_token( - consumer_key='12345', - consumer_secret='23456', - project_id='c8f58432c6f00162f04d3250f') - self.assertEqual(self.FAKE_CREATE_REQUEST_TOKEN, resp) - - def test_authorize_token_request_with_str_body(self): - self._test_authorize_request_token() - - def test_authorize_token_request_with_bytes_body(self): - self._test_authorize_request_token(bytes_body=True) - - def test_create_access_token(self): - mock_resp = self._mock_token_response(self.FAKE_CREATE_ACCESS_TOKEN) - req_secret = self.FAKE_CREATE_REQUEST_TOKEN['oauth_token_secret'] - resp = fake_http.fake_http_response(None, status=201), mock_resp - self.useFixture(fixtures.MockPatch( - 'tempest.lib.common.rest_client.RestClient.post', - return_value=resp)) - - resp = self.client.create_access_token( - consumer_key='12345', - consumer_secret='23456', - request_key=self.FAKE_CREATE_REQUEST_TOKEN['oauth_token'], - request_secret=req_secret, - oauth_verifier='8171') - self.assertEqual(self.FAKE_CREATE_ACCESS_TOKEN, resp) - - def test_get_access_token(self): - self.check_service_client_function( - self.client.get_access_token, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_ACCESS_TOKEN_INFO, - user_id='ce9e07', - access_token_id=self.FAKE_ACCESS_TOKEN_INFO['access_token']['id'], - status=200) - - def test_list_access_tokens(self): - self.check_service_client_function( - self.client.list_access_tokens, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ACCESS_TOKENS, - user_id='ce9e07', - status=200) - - def test_revoke_access_token(self): - self.check_service_client_function( - self.client.revoke_access_token, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - user_id=self.FAKE_ACCESS_TOKEN_INFO['access_token']['consumer_id'], - access_token_id=self.FAKE_ACCESS_TOKEN_INFO['access_token']['id'], - status=204) - - def test_list_access_token_roles(self): - self.check_service_client_function( - self.client.list_access_token_roles, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ACCESS_TOKEN_ROLES, - user_id='ce9e07', - access_token_id=self.FAKE_ACCESS_TOKEN_INFO['access_token']['id'], - status=200) - - def test_get_access_token_role(self): - self.check_service_client_function( - self.client.get_access_token_role, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_ACCESS_TOKEN_ROLE_INFO, - user_id='ce9e07', - access_token_id=self.FAKE_ACCESS_TOKEN_INFO['access_token']['id'], - role_id=self.FAKE_ACCESS_TOKEN_ROLE_INFO['role']['id'], - status=200) diff --git a/tempest/tests/lib/services/identity/v3/test_policies_client.py b/tempest/tests/lib/services/identity/v3/test_policies_client.py deleted file mode 100644 index 66c3d6540..000000000 --- a/tempest/tests/lib/services/identity/v3/test_policies_client.py +++ /dev/null @@ -1,152 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# 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 tempest.lib.services.identity.v3 import policies_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestPoliciesClient(base.BaseServiceTest): - FAKE_CREATE_POLICY = { - "policy": { - "blob": "{'foobar_user': 'role:compute-user'}", - "project_id": "0426ac1e48f642ef9544c2251e07e261", - "type": "application/json", - "user_id": "0ffd248c55b443eaac5253b4e9cbf9b5" - } - } - - FAKE_POLICY_INFO = { - "policy": { - "blob": { - "foobar_user": [ - "role:compute-user" - ] - }, - "id": "717273", - "links": { - "self": "http://example.com/identity/v3/policies/717273" - }, - "project_id": "456789", - "type": "application/json", - "user_id": "616263" - } - } - - FAKE_LIST_POLICIES = { - "links": { - "next": None, - "previous": None, - "self": "http://example.com/identity/v3/policies" - }, - "policies": [ - { - "blob": { - "foobar_user": [ - "role:compute-user" - ] - }, - "id": "717273", - "links": { - "self": "http://example.com/identity/v3/policies/717273" - }, - "project_id": "456789", - "type": "application/json", - "user_id": "616263" - }, - { - "blob": { - "foobar_user": [ - "role:compute-user" - ] - }, - "id": "717274", - "links": { - "self": "http://example.com/identity/v3/policies/717274" - }, - "project_id": "456789", - "type": "application/json", - "user_id": "616263" - } - ] - } - - def setUp(self): - super(TestPoliciesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = policies_client.PoliciesClient(fake_auth, - 'identity', 'regionOne') - - def _test_create_policy(self, bytes_body=False): - self.check_service_client_function( - self.client.create_policy, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_POLICY, - bytes_body, - status=201) - - def _test_show_policy(self, bytes_body=False): - self.check_service_client_function( - self.client.show_policy, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_POLICY_INFO, - bytes_body, - policy_id="717273") - - def _test_list_policies(self, bytes_body=False): - self.check_service_client_function( - self.client.list_policies, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_POLICIES, - bytes_body) - - def _test_update_policy(self, bytes_body=False): - self.check_service_client_function( - self.client.update_policy, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_POLICY_INFO, - bytes_body, - policy_id="717273") - - def test_create_policy_with_str_body(self): - self._test_create_policy() - - def test_create_policy_with_bytes_body(self): - self._test_create_policy(bytes_body=True) - - def test_show_policy_with_str_body(self): - self._test_show_policy() - - def test_show_policy_with_bytes_body(self): - self._test_show_policy(bytes_body=True) - - def test_list_policies_with_str_body(self): - self._test_list_policies() - - def test_list_policies_with_bytes_body(self): - self._test_list_policies(bytes_body=True) - - def test_update_policy_with_str_body(self): - self._test_update_policy() - - def test_update_policy_with_bytes_body(self): - self._test_update_policy(bytes_body=True) - - def test_delete_policy(self): - self.check_service_client_function( - self.client.delete_policy, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - policy_id="717273", - status=204) diff --git a/tempest/tests/lib/services/identity/v3/test_projects_client.py b/tempest/tests/lib/services/identity/v3/test_projects_client.py deleted file mode 100644 index 6ffbcdef2..000000000 --- a/tempest/tests/lib/services/identity/v3/test_projects_client.py +++ /dev/null @@ -1,178 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# 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 tempest.lib.services.identity.v3 import projects_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestProjectsClient(base.BaseServiceTest): - FAKE_CREATE_PROJECT = { - "project": { - "description": "My new project", - "domain_id": "default", - "enabled": True, - "is_domain": False, - "name": "myNewProject" - } - } - - FAKE_PROJECT_INFO = { - "project": { - "is_domain": False, - "description": None, - "domain_id": "default", - "enabled": True, - "id": "0c4e939acacf4376bdcd1129f1a054ad", - "links": { - "self": "http://example.com/identity/v3/projects/0c4e" + - "939acacf4376bdcd1129f1a054ad" - }, - "name": "admin", - "parent_id": "default" - } - } - - FAKE_LIST_PROJECTS = { - "links": { - "next": None, - "previous": None, - "self": "http://example.com/identity/v3/projects" - }, - "projects": [ - { - "is_domain": False, - "description": None, - "domain_id": "default", - "enabled": True, - "id": "0c4e939acacf4376bdcd1129f1a054ad", - "links": { - "self": "http://example.com/identity/v3/projects" + - "/0c4e939acacf4376bdcd1129f1a054ad" - }, - "name": "admin", - "parent_id": None - }, - { - "is_domain": False, - "description": None, - "domain_id": "default", - "enabled": True, - "id": "0cbd49cbf76d405d9c86562e1d579bd3", - "links": { - "self": "http://example.com/identity/v3/projects" + - "/0cbd49cbf76d405d9c86562e1d579bd3" - }, - "name": "demo", - "parent_id": None - }, - { - "is_domain": False, - "description": None, - "domain_id": "default", - "enabled": True, - "id": "2db68fed84324f29bb73130c6c2094fb", - "links": { - "self": "http://example.com/identity/v3/projects" + - "/2db68fed84324f29bb73130c6c2094fb" - }, - "name": "swifttenanttest2", - "parent_id": None - }, - { - "is_domain": False, - "description": None, - "domain_id": "default", - "enabled": True, - "id": "3d594eb0f04741069dbbb521635b21c7", - "links": { - "self": "http://example.com/identity/v3/projects" + - "/3d594eb0f04741069dbbb521635b21c7" - }, - "name": "service", - "parent_id": None - } - ] - } - - def setUp(self): - super(TestProjectsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = projects_client.ProjectsClient(fake_auth, - 'identity', - 'regionOne') - - def _test_create_project(self, bytes_body=False): - self.check_service_client_function( - self.client.create_project, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_PROJECT, - bytes_body, - name=self.FAKE_CREATE_PROJECT["project"]["name"], - status=201) - - def _test_show_project(self, bytes_body=False): - self.check_service_client_function( - self.client.show_project, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_PROJECT_INFO, - bytes_body, - project_id="0c4e939acacf4376bdcd1129f1a054ad") - - def _test_list_projects(self, bytes_body=False): - self.check_service_client_function( - self.client.list_projects, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_PROJECTS, - bytes_body) - - def _test_update_project(self, bytes_body=False): - self.check_service_client_function( - self.client.update_project, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_PROJECT_INFO, - bytes_body, - project_id="0c4e939acacf4376bdcd1129f1a054ad") - - def test_create_project_with_str_body(self): - self._test_create_project() - - def test_create_project_with_bytes_body(self): - self._test_create_project(bytes_body=True) - - def test_show_project_with_str_body(self): - self._test_show_project() - - def test_show_project_with_bytes_body(self): - self._test_show_project(bytes_body=True) - - def test_list_projects_with_str_body(self): - self._test_list_projects() - - def test_list_projects_with_bytes_body(self): - self._test_list_projects(bytes_body=True) - - def test_update_project_with_str_body(self): - self._test_update_project() - - def test_update_project_with_bytes_body(self): - self._test_update_project(bytes_body=True) - - def test_delete_project(self): - self.check_service_client_function( - self.client.delete_project, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - project_id="0c4e939acacf4376bdcd1129f1a054ad", - status=204) diff --git a/tempest/tests/lib/services/identity/v3/test_regions_client.py b/tempest/tests/lib/services/identity/v3/test_regions_client.py deleted file mode 100644 index a2cb86fe2..000000000 --- a/tempest/tests/lib/services/identity/v3/test_regions_client.py +++ /dev/null @@ -1,125 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# 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 tempest.lib.services.identity.v3 import regions_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestRegionsClient(base.BaseServiceTest): - FAKE_CREATE_REGION = { - "region": { - "description": "My subregion", - "id": "RegionOneSubRegion", - "parent_region_id": "RegionOne" - } - } - - FAKE_REGION_INFO = { - "region": { - "description": "My subregion 3", - "id": "RegionThree", - "links": { - "self": "http://example.com/identity/v3/regions/RegionThree" - }, - "parent_region_id": "RegionOne" - } - } - - FAKE_LIST_REGIONS = { - "links": { - "next": None, - "previous": None, - "self": "http://example.com/identity/v3/regions" - }, - "regions": [ - { - "description": "", - "id": "RegionOne", - "links": { - "self": "http://example.com/identity/v3/regions/RegionOne" - }, - "parent_region_id": None - } - ] - } - - def setUp(self): - super(TestRegionsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = regions_client.RegionsClient(fake_auth, 'identity', - 'regionOne') - - def _test_create_region(self, bytes_body=False): - self.check_service_client_function( - self.client.create_region, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_REGION, - bytes_body, - status=201) - - def _test_show_region(self, bytes_body=False): - self.check_service_client_function( - self.client.show_region, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_REGION_INFO, - bytes_body, - region_id="RegionThree") - - def _test_list_regions(self, bytes_body=False): - self.check_service_client_function( - self.client.list_regions, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_REGIONS, - bytes_body) - - def _test_update_region(self, bytes_body=False): - self.check_service_client_function( - self.client.update_region, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_REGION_INFO, - bytes_body, - region_id="RegionThree") - - def test_create_region_with_str_body(self): - self._test_create_region() - - def test_create_region_with_bytes_body(self): - self._test_create_region(bytes_body=True) - - def test_show_region_with_str_body(self): - self._test_show_region() - - def test_show_region_with_bytes_body(self): - self._test_show_region(bytes_body=True) - - def test_list_regions_with_str_body(self): - self._test_list_regions() - - def test_list_regions_with_bytes_body(self): - self._test_list_regions(bytes_body=True) - - def test_update_region_with_str_body(self): - self._test_update_region() - - def test_update_region_with_bytes_body(self): - self._test_update_region(bytes_body=True) - - def test_delete_region(self): - self.check_service_client_function( - self.client.delete_region, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - region_id="RegionThree", - status=204) diff --git a/tempest/tests/lib/services/identity/v3/test_role_assignments_client.py b/tempest/tests/lib/services/identity/v3/test_role_assignments_client.py deleted file mode 100644 index 7d304c12e..000000000 --- a/tempest/tests/lib/services/identity/v3/test_role_assignments_client.py +++ /dev/null @@ -1,206 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# 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 tempest.lib.services.identity.v3 import role_assignments_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestRoleAssignmentsClient(base.BaseServiceTest): - - FAKE_USER_ID = "313234" - FAKE_GROUP_ID = "101112" - - FAKE_ROLE1_ID = "123456" - FAKE_ROLE2_ID = "123457" - - FAKE_PROJECT_ID = "456789" - FAKE_DOMAIN_ID = "102030" - - FAKE_USER_PROJECT_ASSIGNMENT = { - "links": { - "assignment": "http://example.com/identity/v3/projects/" - "%s/users/%s/roles/%s" % (FAKE_PROJECT_ID, - FAKE_USER_ID, - FAKE_ROLE2_ID) - }, - "role": { - "id": FAKE_ROLE2_ID - }, - "scope": { - "project": { - "id": FAKE_PROJECT_ID - } - }, - "user": { - "id": FAKE_USER_ID - } - } - - FAKE_GROUP_PROJECT_ASSIGNMENT = { - "links": { - "assignment": "http://example.com/identity/v3/projects/" - "%s/groups/%s/roles/%s" % (FAKE_PROJECT_ID, - FAKE_GROUP_ID, - FAKE_ROLE1_ID) - }, - "role": { - "id": FAKE_ROLE1_ID - }, - "scope": { - "project": { - "id": FAKE_PROJECT_ID - } - }, - "group": { - "id": FAKE_GROUP_ID - } - } - - FAKE_USER_PROJECT_EFFECTIVE_ASSIGNMENT = { - "links": { - "assignment": "http://example.com/identity/v3/projects/" - "%s/groups/%s/roles/%s" % (FAKE_PROJECT_ID, - FAKE_GROUP_ID, - FAKE_ROLE1_ID), - "membership": "http://example.com/identity/v3/groups/" - "%s/users/%s" % (FAKE_GROUP_ID, FAKE_USER_ID) - }, - "role": { - "id": FAKE_ROLE1_ID - }, - "scope": { - "project": { - "id": FAKE_PROJECT_ID - } - }, - "user": { - "id": FAKE_USER_ID - } - } - - FAKE_USER_DOMAIN_ASSIGNMENT = { - "links": { - "assignment": "http://example.com/identity/v3/domains/" - "%s/users/%s/roles/%s" % (FAKE_DOMAIN_ID, - FAKE_USER_ID, - FAKE_ROLE1_ID) - }, - "role": { - "id": FAKE_ROLE1_ID - }, - "scope": { - "domain": { - "id": FAKE_DOMAIN_ID - } - }, - "user": { - "id": FAKE_USER_ID - } - } - - FAKE_GROUP_PROJECT_ASSIGNMENTS = { - "role_assignments": [ - FAKE_GROUP_PROJECT_ASSIGNMENT - ], - "links": { - "self": "http://example.com/identity/v3/role_assignments?" - "scope.project.id=%s&group.id=%s&effective" % ( - FAKE_PROJECT_ID, FAKE_GROUP_ID), - "previous": None, - "next": None - } - } - - FAKE_USER_PROJECT_EFFECTIVE_ASSIGNMENTS = { - "role_assignments": [ - FAKE_USER_PROJECT_ASSIGNMENT, - FAKE_USER_PROJECT_EFFECTIVE_ASSIGNMENT - ], - "links": { - "self": "http://example.com/identity/v3/role_assignments?" - "scope.project.id=%s&user.id=%s&effective" % ( - FAKE_PROJECT_ID, FAKE_USER_ID), - "previous": None, - "next": None - } - } - - FAKE_USER_DOMAIN_ASSIGNMENTS = { - "role_assignments": [ - FAKE_USER_DOMAIN_ASSIGNMENT - ], - "links": { - "self": "http://example.com/identity/v3/role_assignments?" - "scope.domain.id=%s&user.id=%s&effective" % ( - FAKE_DOMAIN_ID, FAKE_USER_ID), - "previous": None, - "next": None - } - } - - def setUp(self): - super(TestRoleAssignmentsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = role_assignments_client.RoleAssignmentsClient( - fake_auth, 'identity', 'regionOne') - - def _test_list_user_project_effective_assignments(self, bytes_body=False): - params = {'scope.project.id': self.FAKE_PROJECT_ID, - 'user.id': self.FAKE_USER_ID} - self.check_service_client_function( - self.client.list_role_assignments, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_USER_PROJECT_EFFECTIVE_ASSIGNMENTS, - bytes_body, - effective=True, - **params) - - def test_list_user_project_effective_assignments_with_str_body(self): - self._test_list_user_project_effective_assignments() - - def test_list_user_project_effective_assignments_with_bytes_body(self): - self._test_list_user_project_effective_assignments(bytes_body=True) - - def _test_list_group_project_assignments(self, bytes_body=False): - params = {'scope.project.id': self.FAKE_PROJECT_ID, - 'group.id': self.FAKE_GROUP_ID} - self.check_service_client_function( - self.client.list_role_assignments, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_GROUP_PROJECT_ASSIGNMENTS, - bytes_body, - **params) - - def test_list_group_project_assignments_with_str_body(self): - self._test_list_group_project_assignments() - - def test_list_group_project_assignments_with_bytes_body(self): - self._test_list_group_project_assignments(bytes_body=True) - - def _test_list_user_domain_assignments(self, bytes_body=False): - params = {'scope.domain.id': self.FAKE_DOMAIN_ID, - 'user.id': self.FAKE_USER_ID} - self.check_service_client_function( - self.client.list_role_assignments, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_GROUP_PROJECT_ASSIGNMENTS, - bytes_body, - **params) - - def test_list_user_domain_assignments_with_str_body(self): - self._test_list_user_domain_assignments() - - def test_list_user_domain_assignments_with_bytes_body(self): - self._test_list_user_domain_assignments(bytes_body=True) diff --git a/tempest/tests/lib/services/identity/v3/test_roles_client.py b/tempest/tests/lib/services/identity/v3/test_roles_client.py deleted file mode 100644 index 8d6bb423a..000000000 --- a/tempest/tests/lib/services/identity/v3/test_roles_client.py +++ /dev/null @@ -1,508 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.lib.services.identity.v3 import roles_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestRolesClient(base.BaseServiceTest): - - FAKE_ROLE_ID = "1" - FAKE_ROLE_NAME = "test" - FAKE_DOMAIN_ID = "1" - - FAKE_ROLE_ID_2 = "2" - FAKE_ROLE_NAME_2 = "test2" - - FAKE_ROLE_ID_3 = "3" - FAKE_ROLE_NAME_3 = "test3" - - FAKE_ROLE_ID_4 = "4" - FAKE_ROLE_NAME_4 = "test4" - - FAKE_ROLE_ID_5 = "5" - FAKE_ROLE_NAME_5 = "test5" - - FAKE_ROLE_ID_6 = "6" - FAKE_ROLE_NAME_6 = "test6" - - FAKE_ROLE_INFO = { - "role": { - "domain_id": FAKE_DOMAIN_ID, - "id": FAKE_ROLE_ID, - "name": FAKE_ROLE_NAME, - "links": { - "self": "http://example.com/identity/v3/roles/%s" % ( - FAKE_ROLE_ID) - } - } - } - - FAKE_ROLE_INFO_2 = { - "role": { - "domain_id": FAKE_DOMAIN_ID, - "id": FAKE_ROLE_ID_2, - "name": FAKE_ROLE_NAME_2, - "links": { - "self": "http://example.com/identity/v3/roles/%s" % ( - FAKE_ROLE_ID_2) - } - } - } - - FAKE_LIST_ROLES = {"roles": [FAKE_ROLE_INFO, FAKE_ROLE_INFO_2]} - - FAKE_ROLE_INFERENCE_RULE = { - "role_inference": { - "prior_role": { - "id": FAKE_ROLE_ID, - "name": FAKE_ROLE_NAME, - "links": { - "self": "http://example.com/identity/v3/roles/%s" % ( - FAKE_ROLE_ID) - } - }, - "implies": { - "id": FAKE_ROLE_ID_2, - "name": FAKE_ROLE_NAME_2, - "links": { - "self": "http://example.com/identity/v3/roles/%s" % ( - FAKE_ROLE_ID_2) - } - } - }, - "links": { - "self": "http://example.com/identity/v3/roles/" - "%s/implies/%s" % (FAKE_ROLE_ID, FAKE_ROLE_ID_2) - } - } - - COMMON_FAKE_LIST_ROLE_INFERENCE_RULES = [ - { - "prior_role": { - "id": FAKE_ROLE_ID, - "name": FAKE_ROLE_NAME, - "links": { - "self": "http://example.com/identity/v3/roles/%s" % ( - FAKE_ROLE_ID) - } - }, - "implies": [ - { - "id": FAKE_ROLE_ID_2, - "name": FAKE_ROLE_NAME_2, - "links": { - "self": "http://example.com/identity/v3/roles/%s" % ( - FAKE_ROLE_ID_2) - } - }, - { - "id": FAKE_ROLE_ID_3, - "name": FAKE_ROLE_NAME_3, - "links": { - "self": "http://example.com/identity/v3/roles/%s" % ( - FAKE_ROLE_ID_3) - } - } - ] - }, - { - "prior_role": { - "id": FAKE_ROLE_ID_4, - "name": FAKE_ROLE_NAME_4, - "links": { - "self": "http://example.com/identity/v3/roles/%s" % ( - FAKE_ROLE_ID_4) - } - }, - "implies": [ - { - "id": FAKE_ROLE_ID_5, - "name": FAKE_ROLE_NAME_5, - "links": { - "self": "http://example.com/identity/v3/roles/%s" % ( - FAKE_ROLE_ID_5) - } - }, - { - "id": FAKE_ROLE_ID_6, - "name": FAKE_ROLE_NAME_6, - "links": { - "self": "http://example.com/identity/v3/roles/%s" % ( - FAKE_ROLE_ID_6) - } - } - ] - } - ] - - FAKE_LIST_ROLE_INFERENCE_RULES = { - "role_inference": COMMON_FAKE_LIST_ROLE_INFERENCE_RULES[0], - "links": { - "self": "http://example.com/identity/v3/roles/" - "%s/implies" % FAKE_ROLE_ID - } - } - - FAKE_LIST_ALL_ROLE_INFERENCE_RULES = { - "role_inferences": COMMON_FAKE_LIST_ROLE_INFERENCE_RULES, - "links": { - "self": "http://example.com/identity/v3/role_inferences" - } - } - - def setUp(self): - super(TestRolesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = roles_client.RolesClient(fake_auth, - 'identity', 'regionOne') - - def _test_create_role(self, bytes_body=False): - self.check_service_client_function( - self.client.create_role, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_ROLE_INFO, - bytes_body, - domain_id=self.FAKE_DOMAIN_ID, - name=self.FAKE_ROLE_NAME, - status=201) - - def _test_show_role(self, bytes_body=False): - self.check_service_client_function( - self.client.show_role, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_ROLE_INFO, - bytes_body, - role_id=self.FAKE_ROLE_ID) - - def _test_list_roles(self, bytes_body=False): - self.check_service_client_function( - self.client.list_roles, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ROLES, - bytes_body) - - def _test_update_role(self, bytes_body=False): - self.check_service_client_function( - self.client.update_role, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_ROLE_INFO, - bytes_body, - role_id=self.FAKE_ROLE_ID, - name=self.FAKE_ROLE_NAME) - - def _test_create_user_role_on_project(self, bytes_body=False): - self.check_service_client_function( - self.client.create_user_role_on_project, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - bytes_body, - project_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) - - def _test_create_user_role_on_domain(self, bytes_body=False): - self.check_service_client_function( - self.client.create_user_role_on_domain, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - bytes_body, - domain_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) - - def _test_list_user_roles_on_project(self, bytes_body=False): - self.check_service_client_function( - self.client.list_user_roles_on_project, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ROLES, - bytes_body, - project_id="b344506af7644f6794d9cb316600b020", - user_id="123") - - def _test_list_user_roles_on_domain(self, bytes_body=False): - self.check_service_client_function( - self.client.list_user_roles_on_domain, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ROLES, - bytes_body, - domain_id="b344506af7644f6794d9cb316600b020", - user_id="123") - - def _test_create_group_role_on_project(self, bytes_body=False): - self.check_service_client_function( - self.client.create_group_role_on_project, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - bytes_body, - project_id="b344506af7644f6794d9cb316600b020", - group_id="123", - role_id="1234", - status=204) - - def _test_create_group_role_on_domain(self, bytes_body=False): - self.check_service_client_function( - self.client.create_group_role_on_domain, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - bytes_body, - domain_id="b344506af7644f6794d9cb316600b020", - group_id="123", - role_id="1234", - status=204) - - def _test_list_group_roles_on_project(self, bytes_body=False): - self.check_service_client_function( - self.client.list_group_roles_on_project, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ROLES, - bytes_body, - project_id="b344506af7644f6794d9cb316600b020", - group_id="123") - - def _test_list_group_roles_on_domain(self, bytes_body=False): - self.check_service_client_function( - self.client.list_group_roles_on_domain, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ROLES, - bytes_body, - domain_id="b344506af7644f6794d9cb316600b020", - group_id="123") - - def _test_create_role_inference_rule(self, bytes_body=False): - self.check_service_client_function( - self.client.create_role_inference_rule, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_ROLE_INFERENCE_RULE, - bytes_body, - status=201, - prior_role=self.FAKE_ROLE_ID, - implies_role=self.FAKE_ROLE_ID_2) - - def _test_show_role_inference_rule(self, bytes_body=False): - self.check_service_client_function( - self.client.show_role_inference_rule, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_ROLE_INFERENCE_RULE, - bytes_body, - prior_role=self.FAKE_ROLE_ID, - implies_role=self.FAKE_ROLE_ID_2) - - def _test_list_role_inferences_rules(self, bytes_body=False): - self.check_service_client_function( - self.client.list_role_inferences_rules, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ROLE_INFERENCE_RULES, - bytes_body, - prior_role=self.FAKE_ROLE_ID) - - def _test_list_all_role_inference_rules(self, bytes_body=False): - self.check_service_client_function( - self.client.list_all_role_inference_rules, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_ALL_ROLE_INFERENCE_RULES, - bytes_body) - - def test_create_role_with_str_body(self): - self._test_create_role() - - def test_create_role_with_bytes_body(self): - self._test_create_role(bytes_body=True) - - def test_show_role_with_str_body(self): - self._test_show_role() - - def test_show_role_with_bytes_body(self): - self._test_show_role(bytes_body=True) - - def test_list_roles_with_str_body(self): - self._test_list_roles() - - def test_list_roles_with_bytes_body(self): - self._test_list_roles(bytes_body=True) - - def test_update_role_with_str_body(self): - self._test_update_role() - - def test_update_role_with_bytes_body(self): - self._test_update_role(bytes_body=True) - - def test_delete_role(self): - self.check_service_client_function( - self.client.delete_role, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - role_id=self.FAKE_ROLE_ID, - status=204) - - def test_create_user_role_on_project_with_str_body(self): - self._test_create_user_role_on_project() - - def test_create_user_role_on_project_with_bytes_body(self): - self._test_create_user_role_on_project(bytes_body=True) - - def test_create_user_role_on_domain_with_str_body(self): - self._test_create_user_role_on_domain() - - def test_create_user_role_on_domain_with_bytes_body(self): - self._test_create_user_role_on_domain(bytes_body=True) - - def test_create_group_role_on_domain_with_str_body(self): - self._test_create_group_role_on_domain() - - def test_create_group_role_on_domain_with_bytes_body(self): - self._test_create_group_role_on_domain(bytes_body=True) - - def test_list_user_roles_on_project_with_str_body(self): - self._test_list_user_roles_on_project() - - def test_list_user_roles_on_project_with_bytes_body(self): - self._test_list_user_roles_on_project(bytes_body=True) - - def test_list_user_roles_on_domain_with_str_body(self): - self._test_list_user_roles_on_domain() - - def test_list_user_roles_on_domain_with_bytes_body(self): - self._test_list_user_roles_on_domain(bytes_body=True) - - def test_list_group_roles_on_domain_with_str_body(self): - self._test_list_group_roles_on_domain() - - def test_list_group_roles_on_domain_with_bytes_body(self): - self._test_list_group_roles_on_domain(bytes_body=True) - - def test_delete_role_from_user_on_project(self): - self.check_service_client_function( - self.client.delete_role_from_user_on_project, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - project_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) - - def test_delete_role_from_user_on_domain(self): - self.check_service_client_function( - self.client.delete_role_from_user_on_domain, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - domain_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) - - def test_delete_role_from_group_on_project(self): - self.check_service_client_function( - self.client.delete_role_from_group_on_project, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - project_id="b344506af7644f6794d9cb316600b020", - group_id="123", - role_id="1234", - status=204) - - def test_delete_role_from_group_on_domain(self): - self.check_service_client_function( - self.client.delete_role_from_group_on_domain, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - domain_id="b344506af7644f6794d9cb316600b020", - group_id="123", - role_id="1234", - status=204) - - def test_check_user_role_existence_on_project(self): - self.check_service_client_function( - self.client.check_user_role_existence_on_project, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - project_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) - - def test_check_user_role_existence_on_domain(self): - self.check_service_client_function( - self.client.check_user_role_existence_on_domain, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - domain_id="b344506af7644f6794d9cb316600b020", - user_id="123", - role_id="1234", - status=204) - - def test_check_role_from_group_on_project_existence(self): - self.check_service_client_function( - self.client.check_role_from_group_on_project_existence, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - project_id="b344506af7644f6794d9cb316600b020", - group_id="123", - role_id="1234", - status=204) - - def test_check_role_from_group_on_domain_existence(self): - self.check_service_client_function( - self.client.check_role_from_group_on_domain_existence, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - domain_id="b344506af7644f6794d9cb316600b020", - group_id="123", - role_id="1234", - status=204) - - def test_create_role_inference_rule_with_str_body(self): - self._test_create_role_inference_rule() - - def test_create_role_inference_rule_with_bytes_body(self): - self._test_create_role_inference_rule(bytes_body=True) - - def test_show_role_inference_rule_with_str_body(self): - self._test_show_role_inference_rule() - - def test_show_role_inference_rule_with_bytes_body(self): - self._test_show_role_inference_rule(bytes_body=True) - - def test_list_role_inferences_rules_with_str_body(self): - self._test_list_role_inferences_rules() - - def test_list_role_inferences_rules_with_bytes_body(self): - self._test_list_role_inferences_rules(bytes_body=True) - - def test_check_role_inference_rule(self): - self.check_service_client_function( - self.client.check_role_inference_rule, - 'tempest.lib.common.rest_client.RestClient.head', - {}, - status=204, - prior_role=self.FAKE_ROLE_ID, - implies_role=self.FAKE_ROLE_ID_2) - - def test_delete_role_inference_rule(self): - self.check_service_client_function( - self.client.delete_role_inference_rule, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=204, - prior_role=self.FAKE_ROLE_ID, - implies_role=self.FAKE_ROLE_ID_2) - - def test_list_all_role_inference_rules_with_str_body(self): - self._test_list_all_role_inference_rules() - - def test_list_all_role_inference_rules_with_bytes_body(self): - self._test_list_all_role_inference_rules(bytes_body=True) diff --git a/tempest/tests/lib/services/identity/v3/test_services_client.py b/tempest/tests/lib/services/identity/v3/test_services_client.py deleted file mode 100644 index b464644f4..000000000 --- a/tempest/tests/lib/services/identity/v3/test_services_client.py +++ /dev/null @@ -1,156 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# 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 tempest.lib.services.identity.v3 import services_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestServicesClient(base.BaseServiceTest): - FAKE_CREATE_SERVICE = { - "service": { - "type": "compute", - "name": "compute2", - "description": "Compute service 2" - } - } - - FAKE_SERVICE_INFO = { - "service": { - "description": "Keystone Identity Service", - "enabled": True, - "id": "686766", - "links": { - "self": "http://example.com/identity/v3/services/686766" - }, - "name": "keystone", - "type": "identity" - } - } - - FAKE_LIST_SERVICES = { - "links": { - "next": None, - "previous": None, - "self": "http://example.com/identity/v3/services" - }, - "services": [ - { - "description": "Nova Compute Service", - "enabled": True, - "id": "1999c3", - "links": { - "self": "http://example.com/identity/v3/services/1999c3" - }, - "name": "nova", - "type": "compute" - }, - { - "description": "Cinder Volume Service V2", - "enabled": True, - "id": "392166", - "links": { - "self": "http://example.com/identity/v3/services/392166" - }, - "name": "cinderv2", - "type": "volumev2" - }, - { - "description": "Neutron Service", - "enabled": True, - "id": "4fe41a", - "links": { - "self": "http://example.com/identity/v3/services/4fe41a" - }, - "name": "neutron", - "type": "network" - } - ] - } - - def setUp(self): - super(TestServicesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = services_client.ServicesClient(fake_auth, 'identity', - 'regionOne') - - def _test_create_service(self, bytes_body=False): - self.check_service_client_function( - self.client.create_service, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_SERVICE, - bytes_body, - status=201) - - def _test_show_service(self, bytes_body=False): - self.check_service_client_function( - self.client.show_service, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SERVICE_INFO, - bytes_body, - service_id="686766") - - def _test_list_services(self, bytes_body=False, mock_args='services', - **params): - self.check_service_client_function( - self.client.list_services, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_SERVICES, - bytes_body, - mock_args=[mock_args], - **params) - - def _test_update_service(self, bytes_body=False): - self.check_service_client_function( - self.client.update_service, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_SERVICE_INFO, - bytes_body, - service_id="686766") - - def test_create_service_with_str_body(self): - self._test_create_service() - - def test_create_service_with_bytes_body(self): - self._test_create_service(bytes_body=True) - - def test_show_service_with_str_body(self): - self._test_show_service() - - def test_show_service_with_bytes_body(self): - self._test_show_service(bytes_body=True) - - def test_list_services_with_str_body(self): - self._test_list_services() - - def test_list_services_with_bytes_body(self): - self._test_list_services(bytes_body=True) - - def test_list_services_with_params(self): - self._test_list_services( - type='fake-type', mock_args='services?type=fake-type') - - def test_update_service_with_str_body(self): - self._test_update_service() - - def test_update_service_with_bytes_body(self): - self._test_update_service(bytes_body=True) - - def test_delete_service(self): - self.check_service_client_function( - self.client.delete_service, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - service_id="686766", - status=204) diff --git a/tempest/tests/lib/services/identity/v3/test_token_client.py b/tempest/tests/lib/services/identity/v3/test_token_client.py deleted file mode 100644 index 38e8c4a4e..000000000 --- a/tempest/tests/lib/services/identity/v3/test_token_client.py +++ /dev/null @@ -1,153 +0,0 @@ -# Copyright 2015 Hewlett-Packard Development Company, L.P. -# -# 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 json - -import mock - -from tempest.lib.common import rest_client -from tempest.lib import exceptions -from tempest.lib.services.identity.v3 import token_client -from tempest.tests import base -from tempest.tests.lib import fake_identity - - -class TestTokenClientV3(base.TestCase): - - def test_init_without_authurl(self): - self.assertRaises(exceptions.IdentityError, - token_client.V3TokenClient, None) - - def test_auth(self): - token_client_v3 = token_client.V3TokenClient('fake_url') - response, body_text = fake_identity._fake_v3_response(None, None) - body = json.loads(body_text) - - with mock.patch.object(token_client_v3, 'post') as post_mock: - post_mock.return_value = response, body - resp = token_client_v3.auth(username='fake_user', - password='fake_pass') - - self.assertIsInstance(resp, rest_client.ResponseBody) - req_dict = json.dumps({ - 'auth': { - 'identity': { - 'methods': ['password'], - 'password': { - 'user': { - 'name': 'fake_user', - 'password': 'fake_pass', - } - } - }, - } - }, sort_keys=True) - post_mock.assert_called_once_with('fake_url/auth/tokens', - body=req_dict) - - def test_auth_with_project_id_and_domain_id(self): - token_client_v3 = token_client.V3TokenClient('fake_url') - response, body_text = fake_identity._fake_v3_response(None, None) - body = json.loads(body_text) - - with mock.patch.object(token_client_v3, 'post') as post_mock: - post_mock.return_value = response, body - resp = token_client_v3.auth( - username='fake_user', password='fake_pass', - project_id='fcac2a055a294e4c82d0a9c21c620eb4', - user_domain_id='14f4a9a99973404d8c20ba1d2af163ff', - project_domain_id='291f63ae9ac54ee292ca09e5f72d9676') - - self.assertIsInstance(resp, rest_client.ResponseBody) - req_dict = json.dumps({ - 'auth': { - 'identity': { - 'methods': ['password'], - 'password': { - 'user': { - 'name': 'fake_user', - 'password': 'fake_pass', - 'domain': { - 'id': '14f4a9a99973404d8c20ba1d2af163ff' - } - } - } - }, - 'scope': { - 'project': { - 'id': 'fcac2a055a294e4c82d0a9c21c620eb4', - 'domain': { - 'id': '291f63ae9ac54ee292ca09e5f72d9676' - } - } - } - } - }, sort_keys=True) - post_mock.assert_called_once_with('fake_url/auth/tokens', - body=req_dict) - - def test_auth_with_tenant(self): - token_client_v3 = token_client.V3TokenClient('fake_url') - response, body_text = fake_identity._fake_v3_response(None, None) - body = json.loads(body_text) - - with mock.patch.object(token_client_v3, 'post') as post_mock: - post_mock.return_value = response, body - resp = token_client_v3.auth(username='fake_user', - password='fake_pass', - project_name='fake_tenant') - - self.assertIsInstance(resp, rest_client.ResponseBody) - req_dict = json.dumps({ - 'auth': { - 'identity': { - 'methods': ['password'], - 'password': { - 'user': { - 'name': 'fake_user', - 'password': 'fake_pass', - } - }}, - 'scope': { - 'project': { - 'name': 'fake_tenant' - } - }, - } - }, sort_keys=True) - - post_mock.assert_called_once_with('fake_url/auth/tokens', - body=req_dict) - - def test_request_with_str_body(self): - token_client_v3 = token_client.V3TokenClient('fake_url') - - with mock.patch.object(token_client_v3, 'raw_request') as mock_raw_r: - mock_raw_r.return_value = ( - fake_identity._fake_v3_response(None, None)) - resp, body = token_client_v3.request('GET', 'fake_uri') - - self.assertIsInstance(body, dict) - - def test_request_with_bytes_body(self): - token_client_v3 = token_client.V3TokenClient('fake_url') - - response, body_text = fake_identity._fake_v3_response(None, None) - body = body_text.encode('utf-8') - - with mock.patch.object(token_client_v3, 'raw_request') as mock_raw_r: - mock_raw_r.return_value = response, body - resp, body = token_client_v3.request('GET', 'fake_uri') - - self.assertIsInstance(body, dict) diff --git a/tempest/tests/lib/services/identity/v3/test_trusts_client.py b/tempest/tests/lib/services/identity/v3/test_trusts_client.py deleted file mode 100644 index a1ca0204c..000000000 --- a/tempest/tests/lib/services/identity/v3/test_trusts_client.py +++ /dev/null @@ -1,150 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# 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 tempest.lib.services.identity.v3 import trusts_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestTrustsClient(base.BaseServiceTest): - FAKE_CREATE_TRUST = { - "trust": { - "expires_at": "2013-02-27T18:30:59.999999Z", - "impersonation": True, - "allow_redelegation": True, - "project_id": "ddef321", - "roles": [ - { - "name": "member" - } - ], - "trustee_user_id": "86c0d5", - "trustor_user_id": "a0fdfd" - } - } - - FAKE_LIST_TRUSTS = { - "trusts": [ - { - "id": "1ff900", - "expires_at": - "2013-02-27T18:30:59.999999Z", - "impersonation": True, - "links": { - "self": - "http://example.com/identity/v3/OS-TRUST/trusts/1ff900" - }, - "project_id": "0f1233", - "trustee_user_id": "86c0d5", - "trustor_user_id": "a0fdfd" - }, - { - "id": "f4513a", - "impersonation": False, - "links": { - "self": - "http://example.com/identity/v3/OS-TRUST/trusts/f45513a" - }, - "project_id": "0f1233", - "trustee_user_id": "86c0d5", - "trustor_user_id": "3cd2ce" - } - ] - } - - FAKE_TRUST_INFO = { - "trust": { - "id": "987fe8", - "expires_at": "2013-02-27T18:30:59.999999Z", - "impersonation": True, - "links": { - "self": - "http://example.com/identity/v3/OS-TRUST/trusts/987fe8" - }, - "roles": [ - { - "id": "ed7b78", - "links": { - "self": - "http://example.com/identity/v3/roles/ed7b78" - }, - "name": "member" - } - ], - "roles_links": { - "next": None, - "previous": None, - "self": - "http://example.com/identity/v3/OS-TRUST/trusts/1ff900/roles" - }, - "project_id": "0f1233", - "trustee_user_id": "be34d1", - "trustor_user_id": "56ae32" - } - } - - def setUp(self): - super(TestTrustsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = trusts_client.TrustsClient(fake_auth, 'identity', - 'regionOne') - - def _test_create_trust(self, bytes_body=False): - self.check_service_client_function( - self.client.create_trust, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_TRUST, - bytes_body, - status=201) - - def _test_show_trust(self, bytes_body=False): - self.check_service_client_function( - self.client.show_trust, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_TRUST_INFO, - bytes_body, - trust_id="1ff900") - - def _test_list_trusts(self, bytes_body=False): - self.check_service_client_function( - self.client.list_trusts, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_TRUSTS, - bytes_body) - - def test_create_trust_with_str_body(self): - self._test_create_trust() - - def test_create_trust_with_bytes_body(self): - self._test_create_trust(bytes_body=True) - - def test_show_trust_with_str_body(self): - self._test_show_trust() - - def test_show_trust_with_bytes_body(self): - self._test_show_trust(bytes_body=True) - - def test_list_trusts_with_str_body(self): - self._test_list_trusts() - - def test_list_trusts_with_bytes_body(self): - self._test_list_trusts(bytes_body=True) - - def test_delete_trust(self): - self.check_service_client_function( - self.client.delete_trust, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - trust_id="1ff900", - status=204) diff --git a/tempest/tests/lib/services/identity/v3/test_users_client.py b/tempest/tests/lib/services/identity/v3/test_users_client.py deleted file mode 100644 index 5b572f5e5..000000000 --- a/tempest/tests/lib/services/identity/v3/test_users_client.py +++ /dev/null @@ -1,205 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# 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 tempest.lib.services.identity.v3 import users_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestUsersClient(base.BaseServiceTest): - FAKE_CREATE_USER = { - 'user': { - 'default_project_id': '95f8c3f8e7b54409a418fc30717f9ae0', - 'domain_id': '8347b31afc3545c4b311cb4cce788a08', - 'enabled': True, - 'name': 'Tempest User', - 'password': 'TempestPassword', - } - } - - FAKE_USER_INFO = { - 'user': { - 'default_project_id': '95f8c3f8e7b54409a418fc30717f9ae0', - 'domain_id': '8347b31afc3545c4b311cb4cce788a08', - 'enabled': True, - 'id': '817fb3c23fd7465ba6d7fe1b1320121d', - 'links': { - 'self': 'http://example.com/identity', - }, - 'name': 'Tempest User', - 'password_expires_at': '2016-11-06T15:32:17.000000', - } - } - - FAKE_USER_LIST = { - 'links': { - 'next': None, - 'previous': None, - 'self': 'http://example.com/identity/v3/users', - }, - 'users': [ - { - 'domain_id': 'TempestDomain', - 'enabled': True, - 'id': '817fb3c23fd7465ba6d7fe1b1320121d', - 'links': { - 'self': 'http://example.com/identity/v3/users/' + - '817fb3c23fd7465ba6d7fe1b1320121d', - }, - 'name': 'Tempest User', - 'password_expires_at': '2016-11-06T15:32:17.000000', - }, - { - 'domain_id': 'TempestDomain', - 'enabled': True, - 'id': 'bdbfb1e2f1344be197e90a778379cca1', - 'links': { - 'self': 'http://example.com/identity/v3/users/' + - 'bdbfb1e2f1344be197e90a778379cca1', - }, - 'name': 'Tempest User', - 'password_expires_at': None, - }, - ] - } - - FAKE_GROUP_LIST = { - 'links': { - 'self': 'http://example.com/identity/v3/groups', - 'previous': None, - 'next': None, - }, - 'groups': [ - { - 'description': 'Tempest Group One Description', - 'domain_id': 'TempestDomain', - 'id': '1c92f3453ed34291a074b87493455b8f', - 'links': { - 'self': 'http://example.com/identity/v3/groups/' + - '1c92f3453ed34291a074b87493455b8f' - }, - 'name': 'Tempest Group One', - }, - { - 'description': 'Tempest Group Two Description', - 'domain_id': 'TempestDomain', - 'id': 'ce9e7dafed3b4877a7d4466ed730a9ee', - 'links': { - 'self': 'http://example.com/identity/v3/groups/' + - 'ce9e7dafed3b4877a7d4466ed730a9ee' - }, - 'name': 'Tempest Group Two', - }, - ] - } - - def setUp(self): - super(TestUsersClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = users_client.UsersClient(fake_auth, 'identity', - 'regionOne') - - def _test_create_user(self, bytes_body=False): - self.check_service_client_function( - self.client.create_user, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_USER, - bytes_body, - status=201, - ) - - def _test_show_user(self, bytes_body=False): - self.check_service_client_function( - self.client.show_user, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_USER_INFO, - bytes_body, - user_id='817fb3c23fd7465ba6d7fe1b1320121d', - ) - - def _test_list_users(self, bytes_body=False): - self.check_service_client_function( - self.client.list_users, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_USER_LIST, - bytes_body, - ) - - def _test_update_user(self, bytes_body=False): - self.check_service_client_function( - self.client.update_user, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_USER_INFO, - bytes_body, - user_id='817fb3c23fd7465ba6d7fe1b1320121d', - name='NewName', - ) - - def _test_list_user_groups(self, bytes_body=False): - self.check_service_client_function( - self.client.list_user_groups, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_GROUP_LIST, - bytes_body, - user_id='817fb3c23fd7465ba6d7fe1b1320121d', - ) - - def test_create_user_with_string_body(self): - self._test_create_user() - - def test_create_user_with_bytes_body(self): - self._test_create_user(bytes_body=True) - - def test_show_user_with_string_body(self): - self._test_show_user() - - def test_show_user_with_bytes_body(self): - self._test_show_user(bytes_body=True) - - def test_list_users_with_string_body(self): - self._test_list_users() - - def test_list_users_with_bytes_body(self): - self._test_list_users(bytes_body=True) - - def test_update_user_with_string_body(self): - self._test_update_user() - - def test_update_user_with_bytes_body(self): - self._test_update_user(bytes_body=True) - - def test_list_user_groups_with_string_body(self): - self._test_list_user_groups() - - def test_list_user_groups_with_bytes_body(self): - self._test_list_user_groups(bytes_body=True) - - def test_delete_user(self): - self.check_service_client_function( - self.client.delete_user, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - user_id='817fb3c23fd7465ba6d7fe1b1320121d', - status=204, - ) - - def test_change_user_password(self): - self.check_service_client_function( - self.client.update_user_password, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - status=204, - user_id='817fb3c23fd7465ba6d7fe1b1320121d', - password='NewTempestPassword', - original_password='OldTempestPassword') diff --git a/tempest/tests/lib/services/identity/v3/test_versions_client.py b/tempest/tests/lib/services/identity/v3/test_versions_client.py deleted file mode 100644 index 3bfaf1ea3..000000000 --- a/tempest/tests/lib/services/identity/v3/test_versions_client.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright 2017 NEC Corporation. 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 tempest.lib.services.identity.v3 import versions_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestIdentityClient(base.BaseServiceTest): - - FAKE_VERSIONS_INFO = { - "versions": { - "values": [ - {"status": "stable", "updated": "2017-02-22T00:00:00Z", - "media-types": [ - {"base": "application/json", "type": - "application/vnd.openstack.identity-v3+json"} - ], - "id": "v3.8", - "links": [ - {"href": "https://15.184.67.226/identity_admin/v3/", - "rel": "self"} - ]}, - {"status": "deprecated", "updated": "2016-08-04T00:00:00Z", - "media-types": [ - {"base": "application/json", - "type": "application/vnd.openstack.identity-v2.0+json"} - ], - "id": "v2.0", - "links": [ - {"href": "https://15.184.67.226/identity_admin/v2.0/", - "rel": "self"}, - {"href": "https://docs.openstack.org/", - "type": "text/html", "rel": "describedby"} - ]} - ] - } - } - - def setUp(self): - super(TestIdentityClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = versions_client.VersionsClient(fake_auth, - 'identity', - 'regionOne') - - def _test_list_versions(self, bytes_body=False): - self.check_service_client_function( - self.client.list_versions, - 'tempest.lib.common.rest_client.RestClient.raw_request', - self.FAKE_VERSIONS_INFO, - bytes_body, - 300) - - def test_list_versions_with_str_body(self): - self._test_list_versions() - - def test_list_versions_with_bytes_body(self): - self._test_list_versions(bytes_body=True) diff --git a/tempest/tests/lib/services/image/__init__.py b/tempest/tests/lib/services/image/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/image/v1/__init__.py b/tempest/tests/lib/services/image/v1/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/image/v1/test_image_members_client.py b/tempest/tests/lib/services/image/v1/test_image_members_client.py deleted file mode 100644 index a5a6128c0..000000000 --- a/tempest/tests/lib/services/image/v1/test_image_members_client.py +++ /dev/null @@ -1,84 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.lib.services.image.v1 import image_members_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestImageMembersClient(base.BaseServiceTest): - FAKE_LIST_IMAGE_MEMBERS = { - "members": [ - { - "created_at": "2013-10-07T17:58:03Z", - "image_id": "dbc999e3-c52f-4200-bedd-3b18fe7f87fe", - "member_id": "123456789", - "status": "pending", - "updated_at": "2013-10-07T17:58:03Z" - }, - { - "created_at": "2013-10-07T17:58:55Z", - "image_id": "dbc999e3-c52f-4200-bedd-3b18fe7f87fe", - "member_id": "987654321", - "status": "accepted", - "updated_at": "2013-10-08T12:08:55Z" - } - ] - } - - def setUp(self): - super(TestImageMembersClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = image_members_client.ImageMembersClient(fake_auth, - 'image', - 'regionOne') - - def _test_list_image_members(self, bytes_body=False): - self.check_service_client_function( - self.client.list_image_members, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_IMAGE_MEMBERS, - bytes_body, - image_id="0ae74cc5-5147-4239-9ce2-b0c580f7067e") - - def _test_create_image_member(self, bytes_body=False): - self.check_service_client_function( - self.client.create_image_member, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - bytes_body, - image_id="0ae74cc5-5147-4239-9ce2-b0c580f7067e", - member_id="8989447062e04a818baf9e073fd04fa7", - status=204) - - def test_list_image_members_with_str_body(self): - self._test_list_image_members() - - def test_list_image_members_with_bytes_body(self): - self._test_list_image_members(bytes_body=True) - - def test_create_image_member_with_str_body(self): - self._test_create_image_member() - - def test_create_image_member_with_bytes_body(self): - self._test_create_image_member(bytes_body=True) - - def test_delete_image_member(self): - self.check_service_client_function( - self.client.delete_image_member, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - image_id="0ae74cc5-5147-4239-9ce2-b0c580f7067e", - member_id="8989447062e04a818baf9e073fd04fa7", - status=204) diff --git a/tempest/tests/lib/services/image/v2/__init__.py b/tempest/tests/lib/services/image/v2/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/image/v2/test_image_members_client.py b/tempest/tests/lib/services/image/v2/test_image_members_client.py deleted file mode 100644 index 703b6e1c8..000000000 --- a/tempest/tests/lib/services/image/v2/test_image_members_client.py +++ /dev/null @@ -1,90 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.lib.services.image.v2 import image_members_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestImageMembersClient(base.BaseServiceTest): - FAKE_CREATE_SHOW_UPDATE_IMAGE_MEMBER = { - "status": "pending", - "created_at": "2013-11-26T07:21:21Z", - "updated_at": "2013-11-26T07:21:21Z", - "image_id": "0ae74cc5-5147-4239-9ce2-b0c580f7067e", - "member_id": "8989447062e04a818baf9e073fd04fa7", - "schema": "/v2/schemas/member" - } - - def setUp(self): - super(TestImageMembersClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = image_members_client.ImageMembersClient(fake_auth, - 'image', - 'regionOne') - - def _test_show_image_member(self, bytes_body=False): - self.check_service_client_function( - self.client.show_image_member, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CREATE_SHOW_UPDATE_IMAGE_MEMBER, - bytes_body, - image_id="0ae74cc5-5147-4239-9ce2-b0c580f7067e", - member_id="8989447062e04a818baf9e073fd04fa7") - - def _test_create_image_member(self, bytes_body=False): - self.check_service_client_function( - self.client.create_image_member, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_SHOW_UPDATE_IMAGE_MEMBER, - bytes_body, - image_id="0ae74cc5-5147-4239-9ce2-b0c580f7067e", - member_id="8989447062e04a818baf9e073fd04fa7") - - def _test_update_image_member(self, bytes_body=False): - self.check_service_client_function( - self.client.update_image_member, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_CREATE_SHOW_UPDATE_IMAGE_MEMBER, - bytes_body, - image_id="0ae74cc5-5147-4239-9ce2-b0c580f7067e", - member_id="8989447062e04a818baf9e073fd04fa7", - schema="/v2/schemas/member2") - - def test_show_image_member_with_str_body(self): - self._test_show_image_member() - - def test_show_image_member_with_bytes_body(self): - self._test_show_image_member(bytes_body=True) - - def test_create_image_member_with_str_body(self): - self._test_create_image_member() - - def test_create_image_member_with_bytes_body(self): - self._test_create_image_member(bytes_body=True) - - def test_delete_image_member(self): - self.check_service_client_function( - self.client.delete_image_member, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - image_id="0ae74cc5-5147-4239-9ce2-b0c580f7067e", - member_id="8989447062e04a818baf9e073fd04fa7", - status=204) - - def test_update_image_member_with_str_body(self): - self._test_update_image_member() - - def test_update_image_member_with_bytes_body(self): - self._test_update_image_member(bytes_body=True) diff --git a/tempest/tests/lib/services/image/v2/test_images_client.py b/tempest/tests/lib/services/image/v2/test_images_client.py deleted file mode 100644 index 964898557..000000000 --- a/tempest/tests/lib/services/image/v2/test_images_client.py +++ /dev/null @@ -1,111 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.lib.services.image.v2 import images_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestImagesClient(base.BaseServiceTest): - FAKE_CREATE_UPDATE_SHOW_IMAGE = { - "id": "e485aab9-0907-4973-921c-bb6da8a8fcf8", - "name": u"\u2740(*\xb4\u25e2`*)\u2740", - "status": "active", - "visibility": "public", - "size": 2254249, - "checksum": "2cec138d7dae2aa59038ef8c9aec2390", - "tags": [ - "fedora", - "beefy" - ], - "created_at": "2012-08-10T19:23:50Z", - "updated_at": "2012-08-12T11:11:33Z", - "self": "/v2/images/da3b75d9-3f4a-40e7-8a2c-bfab23927dea", - "file": "/v2/images/da3b75d9-3f4a-40e7-8a2c-bfab23927dea/file", - "schema": "/v2/schemas/image", - "owner": None, - "min_ram": None, - "min_disk": None, - "disk_format": None, - "virtual_size": None, - "container_format": None - } - - def setUp(self): - super(TestImagesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = images_client.ImagesClient(fake_auth, - 'image', 'regionOne') - - def _test_update_image(self, bytes_body=False): - self.check_service_client_function( - self.client.update_image, - 'tempest.lib.common.rest_client.RestClient.patch', - self.FAKE_CREATE_UPDATE_SHOW_IMAGE, - bytes_body, - image_id="e485aab9-0907-4973-921c-bb6da8a8fcf8", - patch=[{"op": "add", "path": "/a/b/c", "value": ["foo", "bar"]}]) - - def _test_create_image(self, bytes_body=False): - self.check_service_client_function( - self.client.create_image, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_UPDATE_SHOW_IMAGE, - bytes_body, - name="virtual machine image", - status=201) - - def _test_show_image(self, bytes_body=False): - self.check_service_client_function( - self.client.show_image, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CREATE_UPDATE_SHOW_IMAGE, - bytes_body, - image_id="e485aab9-0907-4973-921c-bb6da8a8fcf8") - - def test_create_image_with_str_body(self): - self._test_create_image() - - def test_create_image_with_bytes_body(self): - self._test_create_image(bytes_body=True) - - def test_update_image_with_str_body(self): - self._test_update_image() - - def test_update_image_with_bytes_body(self): - self._test_update_image(bytes_body=True) - - def test_deactivate_image(self): - self.check_service_client_function( - self.client.deactivate_image, - 'tempest.lib.common.rest_client.RestClient.post', - {}, image_id="e485aab9-0907-4973-921c-bb6da8a8fcf8", status=204) - - def test_reactivate_image(self): - self.check_service_client_function( - self.client.reactivate_image, - 'tempest.lib.common.rest_client.RestClient.post', - {}, image_id="e485aab9-0907-4973-921c-bb6da8a8fcf8", status=204) - - def test_delete_image(self): - self.check_service_client_function( - self.client.delete_image, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, image_id="e485aab9-0907-4973-921c-bb6da8a8fcf8", status=204) - - def test_show_image_with_str_body(self): - self._test_show_image() - - def test_show_image_with_bytes_body(self): - self._test_show_image(bytes_body=True) diff --git a/tempest/tests/lib/services/image/v2/test_namespace_object_client.py b/tempest/tests/lib/services/image/v2/test_namespace_object_client.py deleted file mode 100644 index 8d2966041..000000000 --- a/tempest/tests/lib/services/image/v2/test_namespace_object_client.py +++ /dev/null @@ -1,210 +0,0 @@ -# Copyright 2016 EasyStack. 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 tempest.lib.services.image.v2 import namespace_objects_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestNamespaceObjectClient(base.BaseServiceTest): - FAKE_CREATE_SHOW_OBJECTS = { - "created_at": "2016-09-19T18:20:56Z", - "description": "You can configure the CPU limits.", - "name": "CPU Limits", - "properties": { - "quota:cpu_period": { - "description": "Specifies the enforcement interval", - "maximum": 1000000, - "minimum": 1000, - "title": "Quota: CPU Period", - "type": "integer" - }, - "quota:cpu_quota": { - "description": "Specifies the maximum allowed bandwidth ", - "title": "Quota: CPU Quota", - "type": "integer" - }, - "quota:cpu_shares": { - "description": "Specifies the proportional weighted share.", - "title": "Quota: CPU Shares", - "type": "integer" - } - }, - "required": [], - "schema": "/v2/schemas/metadefs/object", - "self": "/v2/metadefs/namespaces/OS::Compute::Quota/objects/CPU", - "updated_at": "2016-09-19T18:20:56Z" - } - - FAKE_LIST_OBJECTS = { - "objects": [ - { - "created_at": "2016-09-18T18:16:35Z", - "description": "You can configure the CPU limits.", - "name": "CPU Limits", - "properties": { - "quota:cpu_period": { - "description": "Specifies the enforcement interval ", - "maximum": 1000000, - "minimum": 1000, - "title": "Quota: CPU Period", - "type": "integer" - }, - "quota:cpu_quota": { - "description": "Specifies the maximum.", - "title": "Quota: CPU Quota", - "type": "integer" - }, - "quota:cpu_shares": { - "description": " Desc.", - "title": "Quota: CPU Shares", - "type": "integer" - } - }, - "required": [], - "schema": "/v2/schemas/metadefs/object", - "self": - "/v2/metadefs/namespaces/OS::Compute::Quota/objects/CPU" - }, - { - "created_at": "2016-09-18T18:16:35Z", - "description": "Using disk I/O quotas.", - "name": "Disk QoS", - "properties": { - "quota:disk_read_bytes_sec": { - "description": "Sets disk I/O quota.", - "title": "Quota: Disk read bytes / sec", - "type": "integer" - }, - "quota:disk_read_iops_sec": { - "description": "Sets disk I/O quota", - "title": "Quota: Disk read IOPS / sec", - "type": "integer" - }, - "quota:disk_total_bytes_sec": { - "description": "Sets disk I/O quota.", - "title": "Quota: Disk Total Bytes / sec", - "type": "integer" - }, - "quota:disk_total_iops_sec": { - "description": "Sets disk I/O quota.", - "title": "Quota: Disk Total IOPS / sec", - "type": "integer" - }, - "quota:disk_write_bytes_sec": { - "description": "Sets disk I/O quota.", - "title": "Quota: Disk Write Bytes / sec", - "type": "integer" - }, - "quota:disk_write_iops_sec": { - "description": "Sets disk I/O quota.", - "title": "Quota: Disk Write IOPS / sec", - "type": "integer" - } - }, - "required": [], - "schema": "/v2/schemas/metadefs/object", - "self": - "/v2/metadefs/namespaces/OS::Compute::Quota/objects/Disk QoS" - }, - ], - "schema": "v2/schemas/metadefs/objects" - } - - FAKE_UPDATE_OBJECTS = { - "description": "You can configure the CPU limits.", - "name": "CPU", - "properties": { - "quota:cpu_shares": { - "description": "Specify.", - "title": "Quota: CPU Shares", - "type": "integer" - } - }, - "required": [] - } - - def setUp(self): - super(TestNamespaceObjectClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = namespace_objects_client.NamespaceObjectsClient( - fake_auth, 'image', 'regionOne') - - def _test_create_namespace_objects(self, bytes_body=False): - self.check_service_client_function( - self.client.create_namespace_object, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_SHOW_OBJECTS, - bytes_body, status=201, - namespace="OS::Compute::Hypervisor", - object_name="OS::Glance::Image") - - def _test_list_namespace_objects(self, bytes_body=False): - self.check_service_client_function( - self.client.list_namespace_objects, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_OBJECTS, - bytes_body, - namespace="OS::Compute::Hypervisor") - - def _test_show_namespace_objects(self, bytes_body=False): - self.check_service_client_function( - self.client.show_namespace_object, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CREATE_SHOW_OBJECTS, - bytes_body, - namespace="OS::Compute::Hypervisor", - object_name="OS::Glance::Image") - - def _test_update_namespace_objects(self, bytes_body=False): - self.check_service_client_function( - self.client.update_namespace_object, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_OBJECTS, - bytes_body, - namespace="OS::Compute::Hypervisor", - object_name="OS::Glance::Image", - name="CPU") - - def test_create_namespace_object_with_str_body(self): - self._test_create_namespace_objects() - - def test_create_namespace_object_with_bytes_body(self): - self._test_create_namespace_objects(bytes_body=True) - - def test_list_namespace_object_with_str_body(self): - self._test_list_namespace_objects() - - def test_list_namespace_object_with_bytes_body(self): - self._test_list_namespace_objects(bytes_body=True) - - def test_show_namespace_object_with_str_body(self): - self._test_show_namespace_objects() - - def test_show_namespace_object_with_bytes_body(self): - self._test_show_namespace_objects(bytes_body=True) - - def test_update_namespace_object_with_str_body(self): - self._test_update_namespace_objects() - - def test_update_namespace_object_with_bytes_body(self): - self._test_update_namespace_objects(bytes_body=True) - - def test_delete_namespace_objects(self): - self.check_service_client_function( - self.client.delete_namespace_object, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, namespace="OS::Compute::Hypervisor", - object_name="OS::Glance::Image", - status=204) diff --git a/tempest/tests/lib/services/image/v2/test_namespace_properties_client.py b/tempest/tests/lib/services/image/v2/test_namespace_properties_client.py deleted file mode 100644 index 1d56db6da..000000000 --- a/tempest/tests/lib/services/image/v2/test_namespace_properties_client.py +++ /dev/null @@ -1,191 +0,0 @@ -# Copyright 2016 EasyStack. 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 tempest.lib.services.image.v2 import namespace_properties_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestNamespacePropertiesClient(base.BaseServiceTest): - FAKE_CREATE_SHOW_NAMESPACE_PROPERTY = { - "description": "property", - "enum": ["xen", "qemu", "kvm", "lxc", "uml", "vmware", "hyperv"], - "name": "OS::Glance::Image", - "title": "Hypervisor Type", - "type": "string" - } - - FAKE_LIST_NAMESPACE_PROPERTY = { - "properties": { - "hw_disk_bus": { - "description": "property.", - "enum": ["scsi", "virtio", "uml", "xen", "ide", "usb"], - "title": "Disk Bus", - "type": "string" - }, - "hw_machine_type": { - "description": "desc.", - "title": "Machine Type", - "type": "string" - }, - "hw_qemu_guest_agent": { - "description": "desc.", - "enum": [ - "yes", - "no" - ], - "title": "QEMU Guest Agent", - "type": "string" - }, - "hw_rng_model": { - "default": "virtio", - "description": "desc", - "title": "Random Number Generator Device", - "type": "string" - }, - "hw_scsi_model": { - "default": "virtio-scsi", - "description": "desc.", - "title": "SCSI Model", - "type": "string" - }, - "hw_video_model": { - "description": "The video image driver used.", - "enum": [ - "vga", - "cirrus", - "vmvga", - "xen", - "qxl" - ], - "title": "Video Model", - "type": "string" - }, - "hw_video_ram": { - "description": "desc.", - "title": "Max Video Ram", - "type": "integer" - }, - "hw_vif_model": { - "description": "desc.", - "enum": ["e1000", - "ne2k_pci", - "pcnet", - "rtl8139", - "virtio", - "e1000", - "e1000e", - "VirtualE1000", - "VirtualE1000e", - "VirtualPCNet32", - "VirtualSriovEthernetCard", - "VirtualVmxnet", - "netfront", - "ne2k_pci" - ], - "title": "Virtual Network Interface", - "type": "string" - }, - "os_command_line": { - "description": "desc.", - "title": "Kernel Command Line", - "type": "string" - } - } - } - - FAKE_UPDATE_NAMESPACE_PROPERTY = { - "description": "property", - "enum": ["xen", "qemu", "kvm", "lxc", "uml", "vmware", "hyperv"], - "name": "OS::Glance::Image", - "title": "update Hypervisor Type", - "type": "string" - } - - def setUp(self): - super(TestNamespacePropertiesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = namespace_properties_client.NamespacePropertiesClient( - fake_auth, 'image', 'regionOne') - - def _test_create_namespace_property(self, bytes_body=False): - self.check_service_client_function( - self.client.create_namespace_property, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_SHOW_NAMESPACE_PROPERTY, - bytes_body, status=201, - namespace="OS::Compute::Hypervisor", - title="Hypervisor Type", name="OS::Glance::Image", - type="string", - enum=["xen", "qemu", "kvm", "lxc", "uml", "vmware", "hyperv"]) - - def _test_list_namespace_property(self, bytes_body=False): - self.check_service_client_function( - self.client.list_namespace_properties, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_NAMESPACE_PROPERTY, - bytes_body, - namespace="OS::Compute::Hypervisor") - - def _test_show_namespace_property(self, bytes_body=False): - self.check_service_client_function( - self.client.show_namespace_properties, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CREATE_SHOW_NAMESPACE_PROPERTY, - bytes_body, - namespace="OS::Compute::Hypervisor", - property_name="OS::Glance::Image") - - def _test_update_namespace_property(self, bytes_body=False): - self.check_service_client_function( - self.client.update_namespace_properties, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_NAMESPACE_PROPERTY, - bytes_body, - namespace="OS::Compute::Hypervisor", - property_name="OS::Glance::Image", - title="update Hypervisor Type", type="string", - enum=["xen", "qemu", "kvm", "lxc", "uml", "vmware", "hyperv"], - name="OS::Glance::Image") - - def test_create_namespace_property_with_str_body(self): - self._test_create_namespace_property() - - def test_create_namespace_property_with_bytes_body(self): - self._test_create_namespace_property(bytes_body=True) - - def test_list_namespace_property_with_str_body(self): - self._test_list_namespace_property() - - def test_list_namespace_property_with_bytes_body(self): - self._test_list_namespace_property(bytes_body=True) - - def test_show_namespace_property_with_str_body(self): - self._test_show_namespace_property() - - def test_show_namespace_property_with_bytes_body(self): - self._test_show_namespace_property(bytes_body=True) - - def test_update_namespace_property_with_str_body(self): - self._test_update_namespace_property() - - def test_update_namespace_property_with_bytes_body(self): - self._test_update_namespace_property(bytes_body=True) - - def test_delete_namespace(self): - self.check_service_client_function( - self.client.delete_namespace_property, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, namespace="OS::Compute::Hypervisor", - property_name="OS::Glance::Image", status=204) diff --git a/tempest/tests/lib/services/image/v2/test_namespace_tags_client.py b/tempest/tests/lib/services/image/v2/test_namespace_tags_client.py deleted file mode 100644 index 2faa5be1d..000000000 --- a/tempest/tests/lib/services/image/v2/test_namespace_tags_client.py +++ /dev/null @@ -1,126 +0,0 @@ -# Copyright 2016 EasyStack. 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 tempest.lib.services.image.v2 import namespace_tags_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestNamespaceTagsClient(base.BaseServiceTest): - FAKE_CREATE_SHOW_TAGS = { - "created_at": "2015-05-09T01:12:31Z", - "name": "added-sample-tag", - "updated_at": "2015-05-09T01:12:31Z" - } - - FAKE_LIST_TAGS = { - "tags": [ - { - "name": "sample-tag1" - }, - { - "name": "sample-tag2" - }, - { - "name": "sample-tag3" - } - ] - } - - FAKE_UPDATE_TAGS = {"name": "new-tag-name"} - - def setUp(self): - super(TestNamespaceTagsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = namespace_tags_client.NamespaceTagsClient( - fake_auth, 'image', 'regionOne') - - def _test_create_namespace_tags(self, bytes_body=False): - self.check_service_client_function( - self.client.create_namespace_tags, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_SHOW_TAGS, - bytes_body, status=201, - namespace="OS::Compute::Hypervisor", - tags=[{"name": "sample-tag1"}, - {"name": "sample-tag2"}, - {"name": "sample-tag3"}]) - - def _test_list_namespace_tags(self, bytes_body=False): - self.check_service_client_function( - self.client.list_namespace_tags, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_TAGS, - bytes_body, - namespace="OS::Compute::Hypervisor") - - def _test_create_namespace_tag_definition(self, bytes_body=False): - self.check_service_client_function( - self.client.create_namespace_tag, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_SHOW_TAGS, - bytes_body, - status=201, - namespace="OS::Compute::Hypervisor", - tag_name="added-sample-tag") - - def _test_show_namespace_tag_definition(self, bytes_body=False): - self.check_service_client_function( - self.client.show_namespace_tag, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CREATE_SHOW_TAGS, - bytes_body, - namespace="OS::Compute::Hypervisor", - tag_name="added-sample-tag") - - def _test_update_namespace_tag_definition(self, bytes_body=False): - self.check_service_client_function( - self.client.update_namespace_tag, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_OBJECTS, - bytes_body, - namespace="OS::Compute::Hypervisor", - tag_name="added-sample-tag", - name="new-tag-name") - - def test_create_namespace_tags_with_str_body(self): - self._test_create_namespace_tags() - - def test_create_namespace_tags_with_bytes_body(self): - self._test_create_namespace_tags(bytes_body=True) - - def test_list_namespace_tags_with_str_body(self): - self._test_list_namespace_tags() - - def test_list_namespace_tags_with_bytes_body(self): - self._test_list_namespace_tags(bytes_body=True) - - def test_create_namespace_tag_with_str_body(self): - self._test_create_namespace_tag_definition() - - def test_create_namespace_tag_with_bytes_body(self): - self._test_create_namespace_tag_definition(bytes_body=True) - - def test_show_namespace_tag_with_str_body(self): - self._test_show_namespace_tag_definition() - - def test_show_namespace_tag_with_bytes_body(self): - self._test_show_namespace_tag_definition(bytes_body=True) - - def test_delete_all_namespace_tags(self): - self.check_service_client_function( - self.client.delete_namespace_tags, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, status=200, - namespace="OS::Compute::Hypervisor") diff --git a/tempest/tests/lib/services/image/v2/test_namespaces_client.py b/tempest/tests/lib/services/image/v2/test_namespaces_client.py deleted file mode 100644 index 4cb9d01a7..000000000 --- a/tempest/tests/lib/services/image/v2/test_namespaces_client.py +++ /dev/null @@ -1,93 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.lib.services.image.v2 import namespaces_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestNamespacesClient(base.BaseServiceTest): - FAKE_CREATE_SHOW_NAMESPACE = { - "namespace": "OS::Compute::Hypervisor", - "visibility": "public", - "description": "Tempest", - "display_name": u"\u2740(*\xb4\u25e1`*)\u2740", - "protected": True - } - - FAKE_UPDATE_NAMESPACE = { - "namespace": "OS::Compute::Hypervisor", - "visibility": "public", - "description": "Tempest", - "display_name": u"\u2740(*\xb4\u25e2`*)\u2740", - "protected": True - } - - def setUp(self): - super(TestNamespacesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = namespaces_client.NamespacesClient(fake_auth, - 'image', 'regionOne') - - def _test_show_namespace(self, bytes_body=False): - self.check_service_client_function( - self.client.show_namespace, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_CREATE_SHOW_NAMESPACE, - bytes_body, - namespace="OS::Compute::Hypervisor") - - def _test_create_namespace(self, bytes_body=False): - self.check_service_client_function( - self.client.create_namespace, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_SHOW_NAMESPACE, - bytes_body, - namespace="OS::Compute::Hypervisor", - visibility="public", description="Tempest", - display_name=u"\u2740(*\xb4\u25e1`*)\u2740", protected=True, - status=201) - - def _test_update_namespace(self, bytes_body=False): - self.check_service_client_function( - self.client.update_namespace, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_NAMESPACE, - bytes_body, - namespace="OS::Compute::Hypervisor", - display_name=u"\u2740(*\xb4\u25e2`*)\u2740", protected=True) - - def test_show_namespace_with_str_body(self): - self._test_show_namespace() - - def test_show_namespace_with_bytes_body(self): - self._test_show_namespace(bytes_body=True) - - def test_create_namespace_with_str_body(self): - self._test_create_namespace() - - def test_create_namespace_with_bytes_body(self): - self._test_create_namespace(bytes_body=True) - - def test_delete_namespace(self): - self.check_service_client_function( - self.client.delete_namespace, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, namespace="OS::Compute::Hypervisor", status=204) - - def test_update_namespace_with_str_body(self): - self._test_update_namespace() - - def test_update_namespace_with_bytes_body(self): - self._test_update_namespace(bytes_body=True) diff --git a/tempest/tests/lib/services/image/v2/test_resource_types_client.py b/tempest/tests/lib/services/image/v2/test_resource_types_client.py deleted file mode 100644 index 2e3b117f5..000000000 --- a/tempest/tests/lib/services/image/v2/test_resource_types_client.py +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.lib.services.image.v2 import resource_types_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestResouceTypesClient(base.BaseServiceTest): - FAKE_LIST_RESOURCETYPES = { - "resource_types": [ - { - "created_at": "2014-08-28T18:13:04Z", - "name": "OS::Glance::Image", - "updated_at": "2014-08-28T18:13:04Z" - }, - { - "created_at": "2014-08-28T18:13:04Z", - "name": "OS::Cinder::Volume", - "updated_at": "2014-08-28T18:13:04Z" - }, - { - "created_at": "2014-08-28T18:13:04Z", - "name": "OS::Nova::Flavor", - "updated_at": "2014-08-28T18:13:04Z" - }, - { - "created_at": "2014-08-28T18:13:04Z", - "name": "OS::Nova::Aggregate", - "updated_at": "2014-08-28T18:13:04Z" - }, - { - "created_at": "2014-08-28T18:13:04Z", - "name": u"\u2740(*\xb4\u25e1`*)\u2740", - "updated_at": "2014-08-28T18:13:04Z" - } - ] - } - - def setUp(self): - super(TestResouceTypesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = resource_types_client.ResourceTypesClient(fake_auth, - 'image', - 'regionOne') - - def _test_list_resouce_types(self, bytes_body=False): - self.check_service_client_function( - self.client.list_resource_types, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_RESOURCETYPES, - bytes_body) - - def test_list_resouce_types_with_str_body(self): - self._test_list_resouce_types() - - def test_list_resouce_types_with_bytes_body(self): - self._test_list_resouce_types(bytes_body=True) diff --git a/tempest/tests/lib/services/image/v2/test_schemas_client.py b/tempest/tests/lib/services/image/v2/test_schemas_client.py deleted file mode 100644 index 4c4b86acd..000000000 --- a/tempest/tests/lib/services/image/v2/test_schemas_client.py +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.lib.services.image.v2 import schemas_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSchemasClient(base.BaseServiceTest): - FAKE_SHOW_SCHEMA = { - "links": [ - { - "href": "{schema}", - "rel": "describedby" - } - ], - "name": "members", - "properties": { - "members": { - "items": { - "name": "member", - "properties": { - "created_at": { - "description": ("Date and time of image member" - " creation"), - "type": "string" - }, - "image_id": { - "description": "An identifier for the image", - "pattern": ("^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}" - "-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}" - "-([0-9a-fA-F]){12}$"), - "type": "string" - }, - "member_id": { - "description": ("An identifier for the image" - " member (tenantId)"), - "type": "string" - }, - "schema": { - "type": "string" - }, - "status": { - "description": "The status of this image member", - "enum": [ - "pending", - "accepted", - "rejected" - ], - "type": "string" - }, - "updated_at": { - "description": ("Date and time of last" - " modification of image member"), - "type": "string" - } - } - }, - "type": "array" - }, - "schema": { - "type": "string" - } - } - } - - def setUp(self): - super(TestSchemasClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = schemas_client.SchemasClient(fake_auth, - 'image', 'regionOne') - - def _test_show_schema(self, bytes_body=False): - self.check_service_client_function( - self.client.show_schema, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SHOW_SCHEMA, - bytes_body, - schema="member") - - def test_show_schema_with_str_body(self): - self._test_show_schema() - - def test_show_schema_with_bytes_body(self): - self._test_show_schema(bytes_body=True) diff --git a/tempest/tests/lib/services/image/v2/test_versions_client.py b/tempest/tests/lib/services/image/v2/test_versions_client.py deleted file mode 100644 index 6234b0699..000000000 --- a/tempest/tests/lib/services/image/v2/test_versions_client.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright 2017 NEC Corporation. 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 tempest.lib.services.image.v2 import versions_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestVersionsClient(base.BaseServiceTest): - - FAKE_VERSIONS_INFO = { - "versions": [ - { - "status": "CURRENT", "id": "v2.5", - "links": [ - {"href": "https://10.220.1.21:9292/v2/", "rel": "self"} - ] - }, - { - "status": "SUPPORTED", "id": "v2.4", - "links": [ - {"href": "https://10.220.1.21:9292/v2/", "rel": "self"} - ] - }, - { - "status": "SUPPORTED", "id": "v2.3", - "links": [ - {"href": "https://10.220.1.21:9292/v2/", "rel": "self"} - ] - }, - { - "status": "SUPPORTED", "id": "v2.2", - "links": [ - {"href": "https://10.220.1.21:9292/v2/", "rel": "self"} - ] - }, - { - "status": "SUPPORTED", "id": "v2.1", - "links": [ - {"href": "https://10.220.1.21:9292/v2/", "rel": "self"} - ] - }, - { - "status": "SUPPORTED", "id": "v2.0", - "links": [ - {"href": "https://10.220.1.21:9292/v2/", "rel": "self"} - ] - }, - { - "status": "DEPRECATED", "id": "v1.1", - "links": [ - {"href": "https://10.220.1.21:9292/v1/", "rel": "self"} - ] - }, - { - "status": "DEPRECATED", "id": "v1.0", - "links": [ - {"href": "https://10.220.1.21:9292/v1/", "rel": "self"} - ] - } - ] - } - - def setUp(self): - super(TestVersionsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = versions_client.VersionsClient(fake_auth, - 'image', - 'regionOne') - - def _test_list_versions(self, bytes_body=False): - self.check_service_client_function( - self.client.list_versions, - 'tempest.lib.common.rest_client.RestClient.raw_request', - self.FAKE_VERSIONS_INFO, - bytes_body, - 300) - - def test_list_versions_with_str_body(self): - self._test_list_versions() - - def test_list_versions_with_bytes_body(self): - self._test_list_versions(bytes_body=True) diff --git a/tempest/tests/lib/services/network/__init__.py b/tempest/tests/lib/services/network/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/network/test_base_network_client.py b/tempest/tests/lib/services/network/test_base_network_client.py deleted file mode 100644 index e121cec9d..000000000 --- a/tempest/tests/lib/services/network/test_base_network_client.py +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 mock - -from tempest.lib.services.network import base as base_network_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib import fake_http -from tempest.tests.lib.services import base - - -class TestBaseNetworkClient(base.BaseServiceTest): - - def setUp(self): - super(TestBaseNetworkClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = base_network_client.BaseNetworkClient( - fake_auth, 'compute', 'regionOne') - - self.mock_expected_success = mock.patch.object( - self.client, 'expected_success').start() - - def _assert_empty(self, resp): - self.assertEqual([], list(resp.keys())) - - @mock.patch('tempest.lib.common.rest_client.RestClient.post') - def test_create_resource(self, mock_post): - response = fake_http.fake_http_response(headers=None, status=201) - mock_post.return_value = response, '{"baz": "qux"}' - - post_data = {'foo': 'bar'} - resp = self.client.create_resource('/fake_url', post_data) - - self.assertEqual({'status': '201'}, resp.response) - self.assertEqual("qux", resp["baz"]) - mock_post.assert_called_once_with('v2.0/fake_url', '{"foo": "bar"}') - self.mock_expected_success.assert_called_once_with( - 201, 201) - - @mock.patch('tempest.lib.common.rest_client.RestClient.post') - def test_create_resource_expect_different_values(self, mock_post): - response = fake_http.fake_http_response(headers=None, status=200) - mock_post.return_value = response, '{}' - - post_data = {'foo': 'bar'} - resp = self.client.create_resource('/fake_url', post_data, - expect_response_code=200, - expect_empty_body=True) - - self.assertEqual({'status': '200'}, resp.response) - self._assert_empty(resp) - mock_post.assert_called_once_with('v2.0/fake_url', '{"foo": "bar"}') - self.mock_expected_success.assert_called_once_with( - 200, 200) - - @mock.patch('tempest.lib.common.rest_client.RestClient.put') - def test_update_resource(self, mock_put): - response = fake_http.fake_http_response(headers=None, status=200) - mock_put.return_value = response, '{"baz": "qux"}' - - put_data = {'foo': 'bar'} - resp = self.client.update_resource('/fake_url', put_data) - - self.assertEqual({'status': '200'}, resp.response) - self.assertEqual("qux", resp["baz"]) - mock_put.assert_called_once_with('v2.0/fake_url', '{"foo": "bar"}') - self.mock_expected_success.assert_called_once_with( - 200, 200) - - @mock.patch('tempest.lib.common.rest_client.RestClient.put') - def test_update_resource_expect_different_values(self, mock_put): - response = fake_http.fake_http_response(headers=None, status=201) - mock_put.return_value = response, '{}' - - put_data = {'foo': 'bar'} - resp = self.client.update_resource('/fake_url', put_data, - expect_response_code=201, - expect_empty_body=True) - - self.assertEqual({'status': '201'}, resp.response) - self._assert_empty(resp) - mock_put.assert_called_once_with('v2.0/fake_url', '{"foo": "bar"}') - self.mock_expected_success.assert_called_once_with( - 201, 201) diff --git a/tempest/tests/lib/services/network/test_extensions_client.py b/tempest/tests/lib/services/network/test_extensions_client.py deleted file mode 100644 index 27eb4858d..000000000 --- a/tempest/tests/lib/services/network/test_extensions_client.py +++ /dev/null @@ -1,201 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 tempest.lib.services.network import extensions_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestExtensionsClient(base.BaseServiceTest): - - FAKE_EXTENSIONS = { - "extensions": [ - { - "updated": "2013-01-20T00:00:00-00:00", - "name": "Neutron Service Type Management", - "links": [], - "alias": "service-type", - "description": "API for retrieving service providers for" - " Neutron advanced services" - }, - { - "updated": "2012-10-05T10:00:00-00:00", - "name": "security-group", - "links": [], - "alias": "security-group", - "description": "The security groups extension." - }, - { - "updated": "2013-02-07T10:00:00-00:00", - "name": "L3 Agent Scheduler", - "links": [], - "alias": "l3_agent_scheduler", - "description": "Schedule routers among l3 agents" - }, - { - "updated": "2013-02-07T10:00:00-00:00", - "name": "Loadbalancer Agent Scheduler", - "links": [], - "alias": "lbaas_agent_scheduler", - "description": "Schedule pools among lbaas agents" - }, - { - "updated": "2013-03-28T10:00:00-00:00", - "name": "Neutron L3 Configurable external gateway mode", - "links": [], - "alias": "ext-gw-mode", - "description": - "Extension of the router abstraction for specifying whether" - " SNAT should occur on the external gateway" - }, - { - "updated": "2014-02-03T10:00:00-00:00", - "name": "Port Binding", - "links": [], - "alias": "binding", - "description": "Expose port bindings of a virtual port to" - " external application" - }, - { - "updated": "2012-09-07T10:00:00-00:00", - "name": "Provider Network", - "links": [], - "alias": "provider", - "description": "Expose mapping of virtual networks to" - " physical networks" - }, - { - "updated": "2013-02-03T10:00:00-00:00", - "name": "agent", - "links": [], - "alias": "agent", - "description": "The agent management extension." - }, - { - "updated": "2012-07-29T10:00:00-00:00", - "name": "Quota management support", - "links": [], - "alias": "quotas", - "description": "Expose functions for quotas management per" - " tenant" - }, - { - "updated": "2013-02-07T10:00:00-00:00", - "name": "DHCP Agent Scheduler", - "links": [], - "alias": "dhcp_agent_scheduler", - "description": "Schedule networks among dhcp agents" - }, - { - "updated": "2013-06-27T10:00:00-00:00", - "name": "Multi Provider Network", - "links": [], - "alias": "multi-provider", - "description": "Expose mapping of virtual networks to" - " multiple physical networks" - }, - { - "updated": "2013-01-14T10:00:00-00:00", - "name": "Neutron external network", - "links": [], - "alias": "external-net", - "description": "Adds external network attribute to network" - " resource." - }, - { - "updated": "2012-07-20T10:00:00-00:00", - "name": "Neutron L3 Router", - "links": [], - "alias": "router", - "description": "Router abstraction for basic L3 forwarding" - " between L2 Neutron networks and access to external" - " networks via a NAT gateway." - }, - { - "updated": "2013-07-23T10:00:00-00:00", - "name": "Allowed Address Pairs", - "links": [], - "alias": "allowed-address-pairs", - "description": "Provides allowed address pairs" - }, - { - "updated": "2013-03-17T12:00:00-00:00", - "name": "Neutron Extra DHCP opts", - "links": [], - "alias": "extra_dhcp_opt", - "description": "Extra options configuration for DHCP. For" - " example PXE boot options to DHCP clients can be specified" - " (e.g. tftp-server, server-ip-address, bootfile-name)" - }, - { - "updated": "2012-10-07T10:00:00-00:00", - "name": "LoadBalancing service", - "links": [], - "alias": "lbaas", - "description": "Extension for LoadBalancing service" - }, - { - "updated": "2013-02-01T10:00:00-00:00", - "name": "Neutron Extra Route", - "links": [], - "alias": "extraroute", - "description": "Extra routes configuration for L3 router" - }, - { - "updated": "2016-01-24T10:00:00-00:00", - "name": "Neutron Port Data Plane Status", - "links": [], - "alias": "data-plane-status", - "description": "Status of the underlying data plane." - } - ] - } - - FAKE_EXTENSION_ALIAS = "service-type" - - def setUp(self): - super(TestExtensionsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.extensions_client = extensions_client.ExtensionsClient( - fake_auth, "network", "regionOne") - - def _test_list_extensions(self, bytes_body=False): - self.check_service_client_function( - self.extensions_client.list_extensions, - "tempest.lib.common.rest_client.RestClient.get", - self.FAKE_EXTENSIONS, - bytes_body, - 200) - - def _test_show_extension(self, bytes_body=False): - self.check_service_client_function( - self.extensions_client.show_extension, - "tempest.lib.common.rest_client.RestClient.get", - {"extension": self.FAKE_EXTENSIONS["extensions"][0]}, - bytes_body, - 200, - ext_alias=self.FAKE_EXTENSION_ALIAS) - - def test_list_extensions_with_str_body(self): - self._test_list_extensions() - - def test_list_extensions_with_bytes_body(self): - self._test_list_extensions(bytes_body=True) - - def test_show_extension_with_str_body(self): - self._test_show_extension() - - def test_show_extension_with_bytes_body(self): - self._test_show_extension(bytes_body=True) diff --git a/tempest/tests/lib/services/network/test_floating_ips_client.py b/tempest/tests/lib/services/network/test_floating_ips_client.py deleted file mode 100644 index c5b1845ae..000000000 --- a/tempest/tests/lib/services/network/test_floating_ips_client.py +++ /dev/null @@ -1,145 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 copy - -from tempest.lib.services.network import floating_ips_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestFloatingIPsClient(base.BaseServiceTest): - - FAKE_FLOATING_IPS = { - "floatingips": [ - { - "router_id": "d23abc8d-2991-4a55-ba98-2aaea84cc72f", - "description": "for test", - "created_at": "2016-12-21T10:55:50Z", - "updated_at": "2016-12-21T10:55:53Z", - "revision_number": 1, - "project_id": "4969c491a3c74ee4af974e6d800c62de", - "tenant_id": "4969c491a3c74ee4af974e6d800c62de", - "floating_network_id": "376da547-b977-4cfe-9cba-275c80debf57", - "fixed_ip_address": "10.0.0.3", - "floating_ip_address": "172.24.4.228", - "port_id": "ce705c24-c1ef-408a-bda3-7bbd946164ab", - "id": "2f245a7b-796b-4f26-9cf9-9e82d248fda7", - "status": "ACTIVE" - }, - { - "router_id": None, - "description": "for test", - "created_at": "2016-12-21T11:55:50Z", - "updated_at": "2016-12-21T11:55:53Z", - "revision_number": 2, - "project_id": "4969c491a3c74ee4af974e6d800c62de", - "tenant_id": "4969c491a3c74ee4af974e6d800c62de", - "floating_network_id": "376da547-b977-4cfe-9cba-275c80debf57", - "fixed_ip_address": None, - "floating_ip_address": "172.24.4.227", - "port_id": None, - "id": "61cea855-49cb-4846-997d-801b70c71bdd", - "status": "DOWN" - } - ] - } - - FAKE_FLOATING_IP_ID = "2f245a7b-796b-4f26-9cf9-9e82d248fda7" - - def setUp(self): - super(TestFloatingIPsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.floating_ips_client = floating_ips_client.FloatingIPsClient( - fake_auth, "compute", "regionOne") - - def _test_list_floatingips(self, bytes_body=False): - self.check_service_client_function( - self.floating_ips_client.list_floatingips, - "tempest.lib.common.rest_client.RestClient.get", - self.FAKE_FLOATING_IPS, - bytes_body, - 200) - - def _test_create_floatingip(self, bytes_body=False): - self.check_service_client_function( - self.floating_ips_client.create_floatingip, - "tempest.lib.common.rest_client.RestClient.post", - {"floatingip": self.FAKE_FLOATING_IPS["floatingips"][1]}, - bytes_body, - 201, - floating_network_id="172.24.4.228") - - def _test_show_floatingip(self, bytes_body=False): - self.check_service_client_function( - self.floating_ips_client.show_floatingip, - "tempest.lib.common.rest_client.RestClient.get", - {"floatingip": self.FAKE_FLOATING_IPS["floatingips"][0]}, - bytes_body, - 200, - floatingip_id=self.FAKE_FLOATING_IP_ID) - - def _test_update_floatingip(self, bytes_body=False): - update_kwargs = { - "port_id": "fc861431-0e6c-4842-a0ed-e2363f9bc3a8" - } - - resp_body = { - "floatingip": copy.deepcopy( - self.FAKE_FLOATING_IPS["floatingips"][0] - ) - } - resp_body["floatingip"].update(update_kwargs) - - self.check_service_client_function( - self.floating_ips_client.update_floatingip, - "tempest.lib.common.rest_client.RestClient.put", - resp_body, - bytes_body, - 200, - floatingip_id=self.FAKE_FLOATING_IP_ID, - **update_kwargs) - - def test_list_floatingips_with_str_body(self): - self._test_list_floatingips() - - def test_list_floatingips_with_bytes_body(self): - self._test_list_floatingips(bytes_body=True) - - def test_create_floatingip_with_str_body(self): - self._test_create_floatingip() - - def test_create_floatingip_with_bytes_body(self): - self._test_create_floatingip(bytes_body=True) - - def test_show_floatingips_with_str_body(self): - self._test_show_floatingip() - - def test_show_floatingips_with_bytes_body(self): - self._test_show_floatingip(bytes_body=True) - - def test_update_floatingip_with_str_body(self): - self._test_update_floatingip() - - def test_update_floatingip_with_bytes_body(self): - self._test_update_floatingip(bytes_body=True) - - def test_delete_floatingip(self): - self.check_service_client_function( - self.floating_ips_client.delete_floatingip, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=204, - floatingip_id=self.FAKE_FLOATING_IP_ID) diff --git a/tempest/tests/lib/services/network/test_metering_label_rules_client.py b/tempest/tests/lib/services/network/test_metering_label_rules_client.py deleted file mode 100644 index 047c34f5a..000000000 --- a/tempest/tests/lib/services/network/test_metering_label_rules_client.py +++ /dev/null @@ -1,110 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 tempest.lib.services.network import metering_label_rules_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestMeteringLabelRulesClient(base.BaseServiceTest): - - FAKE_METERING_LABEL_RULES = { - "metering_label_rules": [ - { - "remote_ip_prefix": "20.0.0.0/24", - "direction": "ingress", - "metering_label_id": "e131d186-b02d-4c0b-83d5-0c0725c4f812", - "id": "9536641a-7d14-4dc5-afaf-93a973ce0eb8", - "excluded": False - }, - { - "remote_ip_prefix": "10.0.0.0/24", - "direction": "ingress", - "metering_label_id": "e131d186-b02d-4c0b-83d5-0c0725c4f812", - "id": "ffc6fd15-40de-4e7d-b617-34d3f7a93aec", - "excluded": False - } - ] - } - - FAKE_METERING_LABEL_RULE = { - "remote_ip_prefix": "20.0.0.0/24", - "direction": "ingress", - "metering_label_id": "e131d186-b02d-4c0b-83d5-0c0725c4f812" - } - - FAKE_METERING_LABEL_ID = "e131d186-b02d-4c0b-83d5-0c0725c4f812" - FAKE_METERING_LABEL_RULE_ID = "9536641a-7d14-4dc5-afaf-93a973ce0eb8" - - def setUp(self): - super(TestMeteringLabelRulesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.metering_label_rules_client = \ - metering_label_rules_client.MeteringLabelRulesClient( - fake_auth, "network", "regionOne") - - def _test_list_metering_label_rules(self, bytes_body=False): - self.check_service_client_function( - self.metering_label_rules_client.list_metering_label_rules, - "tempest.lib.common.rest_client.RestClient.get", - self.FAKE_METERING_LABEL_RULES, - bytes_body, - 200) - - def _test_create_metering_label_rule(self, bytes_body=False): - self.check_service_client_function( - self.metering_label_rules_client.create_metering_label_rule, - "tempest.lib.common.rest_client.RestClient.post", - {"metering_label_rule": self.FAKE_METERING_LABEL_RULES[ - "metering_label_rules"][0]}, - bytes_body, - 201, - **self.FAKE_METERING_LABEL_RULE) - - def _test_show_metering_label_rule(self, bytes_body=False): - self.check_service_client_function( - self.metering_label_rules_client.show_metering_label_rule, - "tempest.lib.common.rest_client.RestClient.get", - {"metering_label_rule": self.FAKE_METERING_LABEL_RULES[ - "metering_label_rules"][0]}, - bytes_body, - 200, - metering_label_rule_id=self.FAKE_METERING_LABEL_RULE_ID) - - def test_delete_metering_label_rule(self): - self.check_service_client_function( - self.metering_label_rules_client.delete_metering_label_rule, - "tempest.lib.common.rest_client.RestClient.delete", - {}, - status=204, - metering_label_rule_id=self.FAKE_METERING_LABEL_RULE_ID) - - def test_list_metering_label_rules_with_str_body(self): - self._test_list_metering_label_rules() - - def test_list_metering_label_rules_with_bytes_body(self): - self._test_list_metering_label_rules(bytes_body=True) - - def test_create_metering_label_rule_with_str_body(self): - self._test_create_metering_label_rule() - - def test_create_metering_label_rule_with_bytes_body(self): - self._test_create_metering_label_rule(bytes_body=True) - - def test_show_metering_label_rule_with_str_body(self): - self._test_show_metering_label_rule() - - def test_show_metering_label_rule_with_bytes_body(self): - self._test_show_metering_label_rule(bytes_body=True) diff --git a/tempest/tests/lib/services/network/test_metering_labels_client.py b/tempest/tests/lib/services/network/test_metering_labels_client.py deleted file mode 100644 index a048326d1..000000000 --- a/tempest/tests/lib/services/network/test_metering_labels_client.py +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 tempest.lib.services.network import metering_labels_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestMeteringLabelsClient(base.BaseServiceTest): - - FAKE_METERING_LABELS = { - "metering_labels": [ - { - "project_id": "45345b0ee1ea477fac0f541b2cb79cd4", - "tenant_id": "45345b0ee1ea477fac0f541b2cb79cd4", - "description": "label1 description", - "name": "label1", - "id": "a6700594-5b7a-4105-8bfe-723b346ce866", - "shared": False - }, - { - "project_id": "45345b0ee1ea477fac0f541b2cb79cd4", - "tenant_id": "45345b0ee1ea477fac0f541b2cb79cd4", - "description": "label2 description", - "name": "label2", - "id": "e131d186-b02d-4c0b-83d5-0c0725c4f812", - "shared": False - } - ] - } - - FAKE_METERING_LABEL_ID = "a6700594-5b7a-4105-8bfe-723b346ce866" - - def setUp(self): - super(TestMeteringLabelsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.metering_labels_client = \ - metering_labels_client.MeteringLabelsClient( - fake_auth, "network", "regionOne") - - def _test_list_metering_labels(self, bytes_body=False): - self.check_service_client_function( - self.metering_labels_client.list_metering_labels, - "tempest.lib.common.rest_client.RestClient.get", - self.FAKE_METERING_LABELS, - bytes_body, - 200) - - def _test_create_metering_label(self, bytes_body=False): - self.check_service_client_function( - self.metering_labels_client.create_metering_label, - "tempest.lib.common.rest_client.RestClient.post", - {"metering_label": self.FAKE_METERING_LABELS[ - "metering_labels"][1]}, - bytes_body, - 201, - name="label1", - description="label1 description", - shared=False) - - def _test_show_metering_label(self, bytes_body=False): - self.check_service_client_function( - self.metering_labels_client.show_metering_label, - "tempest.lib.common.rest_client.RestClient.get", - {"metering_label": self.FAKE_METERING_LABELS[ - "metering_labels"][0]}, - bytes_body, - 200, - metering_label_id=self.FAKE_METERING_LABEL_ID) - - def test_delete_metering_label(self): - self.check_service_client_function( - self.metering_labels_client.delete_metering_label, - "tempest.lib.common.rest_client.RestClient.delete", - {}, - status=204, - metering_label_id=self.FAKE_METERING_LABEL_ID) - - def test_list_metering_labels_with_str_body(self): - self._test_list_metering_labels() - - def test_list_metering_labels_with_bytes_body(self): - self._test_list_metering_labels(bytes_body=True) - - def test_create_metering_label_with_str_body(self): - self._test_create_metering_label() - - def test_create_metering_label_with_bytes_body(self): - self._test_create_metering_label(bytes_body=True) - - def test_show_metering_label_with_str_body(self): - self._test_show_metering_label() - - def test_show_metering_label_with_bytes_body(self): - self._test_show_metering_label(bytes_body=True) diff --git a/tempest/tests/lib/services/network/test_ports_client.py b/tempest/tests/lib/services/network/test_ports_client.py deleted file mode 100644 index 20ef3f1e6..000000000 --- a/tempest/tests/lib/services/network/test_ports_client.py +++ /dev/null @@ -1,198 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 copy - -from tempest.lib.services.network import ports_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestPortsClient(base.BaseServiceTest): - - FAKE_PORTS = { - "ports": [ - { - "admin_state_up": True, - "allowed_address_pairs": [], - "data_plane_status": None, - "description": "", - "device_id": "9ae135f4-b6e0-4dad-9e91-3c223e385824", - "device_owner": "network:router_gateway", - "extra_dhcp_opts": [], - "fixed_ips": [ - { - "ip_address": "172.24.4.2", - "subnet_id": "008ba151-0b8c-4a67-98b5-0d2b87666062" - } - ], - "id": "d80b1a3b-4fc1-49f3-952e-1e2ab7081d8b", - "mac_address": "fa:16:3e:58:42:ed", - "name": "", - "network_id": "70c1db1f-b701-45bd-96e0-a313ee3430b3", - "project_id": "", - "security_groups": [], - "status": "ACTIVE", - "tenant_id": "" - }, - { - "admin_state_up": True, - "allowed_address_pairs": [], - "data_plane_status": None, - "description": "", - "device_id": "9ae135f4-b6e0-4dad-9e91-3c223e385824", - "device_owner": "network:router_interface", - "extra_dhcp_opts": [], - "fixed_ips": [ - { - "ip_address": "10.0.0.1", - "subnet_id": "288bf4a1-51ba-43b6-9d0a-520e9005db17" - } - ], - "id": "f71a6703-d6de-4be1-a91a-a570ede1d159", - "mac_address": "fa:16:3e:bb:3c:e4", - "name": "", - "network_id": "f27aa545-cbdd-4907-b0c6-c9e8b039dcc2", - "project_id": "d397de8a63f341818f198abb0966f6f3", - "security_groups": [], - "status": "ACTIVE", - "tenant_id": "d397de8a63f341818f198abb0966f6f3" - } - ] - } - - FAKE_PORT_ID = "d80b1a3b-4fc1-49f3-952e-1e2ab7081d8b" - - FAKE_PORT1 = { - "admin_state_up": True, - "name": "", - "network_id": "70c1db1f-b701-45bd-96e0-a313ee3430b3" - } - - FAKE_PORT2 = { - "admin_state_up": True, - "name": "", - "network_id": "f27aa545-cbdd-4907-b0c6-c9e8b039dcc2" - } - - FAKE_PORTS_REQ = { - "ports": [ - FAKE_PORT1, - FAKE_PORT2 - ] - } - - def setUp(self): - super(TestPortsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.ports_client = ports_client.PortsClient( - fake_auth, "network", "regionOne") - - def _test_list_ports(self, bytes_body=False): - self.check_service_client_function( - self.ports_client.list_ports, - "tempest.lib.common.rest_client.RestClient.get", - self.FAKE_PORTS, - bytes_body, - 200) - - def _test_create_port(self, bytes_body=False): - self.check_service_client_function( - self.ports_client.create_port, - "tempest.lib.common.rest_client.RestClient.post", - {"port": self.FAKE_PORTS["ports"][0]}, - bytes_body, - 201, - **self.FAKE_PORT1) - - def _test_create_bulk_ports(self, bytes_body=False): - self.check_service_client_function( - self.ports_client.create_bulk_ports, - "tempest.lib.common.rest_client.RestClient.post", - self.FAKE_PORTS, - bytes_body, - 201, - ports=self.FAKE_PORTS_REQ) - - def _test_show_port(self, bytes_body=False): - self.check_service_client_function( - self.ports_client.show_port, - "tempest.lib.common.rest_client.RestClient.get", - {"port": self.FAKE_PORTS["ports"][0]}, - bytes_body, - 200, - port_id=self.FAKE_PORT_ID) - - def _test_update_port(self, bytes_body=False): - update_kwargs = { - "admin_state_up": True, - "device_id": "d90a13da-be41-461f-9f99-1dbcf438fdf2", - "device_owner": "compute:nova", - "name": "test-for-port-update" - } - - resp_body = { - "port": copy.deepcopy( - self.FAKE_PORTS["ports"][0] - ) - } - resp_body["port"].update(update_kwargs) - - self.check_service_client_function( - self.ports_client.update_port, - "tempest.lib.common.rest_client.RestClient.put", - resp_body, - bytes_body, - 200, - port_id=self.FAKE_PORT_ID, - **update_kwargs) - - def test_delete_port(self): - self.check_service_client_function( - self.ports_client.delete_port, - "tempest.lib.common.rest_client.RestClient.delete", - {}, - status=204, - port_id=self.FAKE_PORT_ID) - - def test_list_ports_with_str_body(self): - self._test_list_ports() - - def test_list_ports_with_bytes_body(self): - self._test_list_ports(bytes_body=True) - - def test_create_port_with_str_body(self): - self._test_create_port() - - def test_create_port_with_bytes_body(self): - self._test_create_port(bytes_body=True) - - def test_create_bulk_port_with_str_body(self): - self._test_create_bulk_ports() - - def test_create_bulk_port_with_bytes_body(self): - self._test_create_bulk_ports(bytes_body=True) - - def test_show_port_with_str_body(self): - self._test_show_port() - - def test_show_port_with_bytes_body(self): - self._test_show_port(bytes_body=True) - - def test_update_port_with_str_body(self): - self._test_update_port() - - def test_update_port_with_bytes_body(self): - self._test_update_port(bytes_body=True) diff --git a/tempest/tests/lib/services/network/test_quotas_client.py b/tempest/tests/lib/services/network/test_quotas_client.py deleted file mode 100644 index e76bc9c17..000000000 --- a/tempest/tests/lib/services/network/test_quotas_client.py +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 tempest.lib.services.network import quotas_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestQuotasClient(base.BaseServiceTest): - - FAKE_QUOTAS = { - "quotas": [ - { - "floatingip": 50, - "network": 15, - "port": 50, - "project_id": "bab7d5c60cd041a0a36f7c4b6e1dd978", - "rbac_policy": -1, - "router": 10, - "security_group": 10, - "security_group_rule": 100, - "subnet": 10, - "subnetpool": -1, - "tenant_id": "bab7d5c60cd041a0a36f7c4b6e1dd978" - } - ] - } - - FAKE_QUOTA_TENANT_ID = "bab7d5c60cd041a0a36f7c4b6e1dd978" - - def setUp(self): - super(TestQuotasClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.quotas_client = quotas_client.QuotasClient( - fake_auth, "network", "regionOne") - - def _test_list_quotas(self, bytes_body=False): - self.check_service_client_function( - self.quotas_client.list_quotas, - "tempest.lib.common.rest_client.RestClient.get", - self.FAKE_QUOTAS, - bytes_body, - 200) - - def _test_show_quotas(self, bytes_body=False): - self.check_service_client_function( - self.quotas_client.show_quotas, - "tempest.lib.common.rest_client.RestClient.get", - {"quota": self.FAKE_QUOTAS["quotas"][0]}, - bytes_body, - 200, - tenant_id=self.FAKE_QUOTA_TENANT_ID) - - def _test_update_quotas(self, bytes_body=False): - self.check_service_client_function( - self.quotas_client.update_quotas, - "tempest.lib.common.rest_client.RestClient.put", - {"quota": self.FAKE_QUOTAS["quotas"][0]}, - bytes_body, - 200, - tenant_id=self.FAKE_QUOTA_TENANT_ID) - - def test_reset_quotas(self): - self.check_service_client_function( - self.quotas_client.reset_quotas, - "tempest.lib.common.rest_client.RestClient.delete", - {}, - status=204, - tenant_id=self.FAKE_QUOTA_TENANT_ID) - - def test_list_quotas_with_str_body(self): - self._test_list_quotas() - - def test_list_quotas_with_bytes_body(self): - self._test_list_quotas(bytes_body=True) - - def test_show_quotas_with_str_body(self): - self._test_show_quotas() - - def test_show_quotas_with_bytes_body(self): - self._test_show_quotas(bytes_body=True) - - def test_update_quotas_with_str_body(self): - self._test_update_quotas() - - def test_update_quotas_with_bytes_body(self): - self._test_update_quotas(bytes_body=True) diff --git a/tempest/tests/lib/services/network/test_routers_client.py b/tempest/tests/lib/services/network/test_routers_client.py deleted file mode 100644 index 2fa599343..000000000 --- a/tempest/tests/lib/services/network/test_routers_client.py +++ /dev/null @@ -1,109 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.lib.services.network import routers_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestRoutersClient(base.BaseServiceTest): - FAKE_CREATE_ROUTER = { - "router": { - "name": u'\u2740(*\xb4\u25e1`*)\u2740', - "external_gateway_info": { - "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b", - "enable_snat": True, - "external_fixed_ips": [ - { - "subnet_id": "255.255.255.0", - "ip": "192.168.10.1" - } - ] - }, - "admin_state_up": True, - "id": "8604a0de-7f6b-409a-a47c-a1cc7bc77b2e" - } - } - - FAKE_UPDATE_ROUTER = { - "router": { - "name": u'\u2740(*\xb4\u25e1`*)\u2740', - "external_gateway_info": { - "network_id": "8ca37218-28ff-41cb-9b10-039601ea7e6b", - "enable_snat": True, - "external_fixed_ips": [ - { - "subnet_id": "255.255.255.0", - "ip": "192.168.10.1" - } - ] - }, - "admin_state_up": False, - "id": "8604a0de-7f6b-409a-a47c-a1cc7bc77b2e" - } - } - - def setUp(self): - super(TestRoutersClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = routers_client.RoutersClient(fake_auth, - 'network', 'regionOne') - - def _test_list_routers(self, bytes_body=False): - self.check_service_client_function( - self.client.list_routers, - 'tempest.lib.common.rest_client.RestClient.get', - {"routers": []}, - bytes_body) - - def _test_create_router(self, bytes_body=False): - self.check_service_client_function( - self.client.create_router, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_ROUTER, - bytes_body, - name="another_router", admin_state_up="true", status=201) - - def _test_update_router(self, bytes_body=False): - self.check_service_client_function( - self.client.update_router, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_ROUTER, - bytes_body, - router_id="8604a0de-7f6b-409a-a47c-a1cc7bc77b2e", - admin_state_up=False) - - def test_list_routers_with_str_body(self): - self._test_list_routers() - - def test_list_routers_with_bytes_body(self): - self._test_list_routers(bytes_body=True) - - def test_create_router_with_str_body(self): - self._test_create_router() - - def test_create_router_with_bytes_body(self): - self._test_create_router(bytes_body=True) - - def test_delete_router(self): - self.check_service_client_function( - self.client.delete_router, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, router_id="1", status=204) - - def test_update_router_with_str_body(self): - self._test_update_router() - - def test_update_router_with_bytes_body(self): - self._test_update_router(bytes_body=True) diff --git a/tempest/tests/lib/services/network/test_security_group_rules_client.py b/tempest/tests/lib/services/network/test_security_group_rules_client.py deleted file mode 100644 index b9c17a15f..000000000 --- a/tempest/tests/lib/services/network/test_security_group_rules_client.py +++ /dev/null @@ -1,138 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 copy - -import mock -from oslo_serialization import jsonutils as json - -from tempest.lib.services.network import base as network_base -from tempest.lib.services.network import security_group_rules_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSecurityGroupsClient(base.BaseServiceTest): - - FAKE_SEC_GROUP_RULE_ID = "3c0e45ff-adaf-4124-b083-bf390e5482ff" - - FAKE_SECURITY_GROUP_RULES = { - "security_group_rules": [ - { - "direction": "egress", - "ethertype": "IPv6", - "id": "3c0e45ff-adaf-4124-b083-bf390e5482ff", - "port_range_max": None, - "port_range_min": None, - "protocol": None, - "remote_group_id": None, - "remote_ip_prefix": None, - "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", - "project_id": "e4f50856753b4dc6afee5fa6b9b6c550", - "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550", - "description": "" - }, - { - "direction": "egress", - "ethertype": "IPv4", - "id": "93aa42e5-80db-4581-9391-3a608bd0e448", - "port_range_max": None, - "port_range_min": None, - "protocol": None, - "remote_group_id": None, - "remote_ip_prefix": None, - "security_group_id": "85cc3048-abc3-43cc-89b3-377341426ac5", - "project_id": "e4f50856753b4dc6afee5fa6b9b6c550", - "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550", - "description": "" - } - ] - } - - FAKE_SECURITY_GROUP_RULE = copy.copy( - FAKE_SECURITY_GROUP_RULES['security_group_rules'][0]) - - def setUp(self): - super(TestSecurityGroupsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = security_group_rules_client.SecurityGroupRulesClient( - fake_auth, 'network', 'regionOne') - - def _test_list_security_group_rules(self, bytes_body=False): - self.check_service_client_function( - self.client.list_security_group_rules, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SECURITY_GROUP_RULES, - bytes_body, - mock_args='v2.0/security-group-rules') - - def _test_create_security_group_rule(self, bytes_body=False): - kwargs = {'direction': 'egress', - 'security_group_id': '85cc3048-abc3-43cc-89b3-377341426ac5', - 'remote_ip_prefix': None} - payload = json.dumps({"security_group_rule": kwargs}, sort_keys=True) - json_dumps = json.dumps - - # NOTE: Use sort_keys for json.dumps so that the expected and actual - # payloads are guaranteed to be identical for mock_args assert check. - with mock.patch.object(network_base.json, 'dumps') as mock_dumps: - mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True) - - self.check_service_client_function( - self.client.create_security_group_rule, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_SECURITY_GROUP_RULE, - bytes_body, - status=201, - mock_args=['v2.0/security-group-rules', payload], - **kwargs) - - def _test_show_security_group_rule(self, bytes_body=False): - self.check_service_client_function( - self.client.show_security_group_rule, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SECURITY_GROUP_RULE, - bytes_body, - security_group_rule_id=self.FAKE_SEC_GROUP_RULE_ID, - mock_args='v2.0/security-group-rules/%s' - % self.FAKE_SEC_GROUP_RULE_ID) - - def test_list_security_group_rules_with_str_body(self): - self._test_list_security_group_rules() - - def test_list_security_group_rules_with_bytes_body(self): - self._test_list_security_group_rules(bytes_body=True) - - def test_create_security_group_rule_with_str_body(self): - self._test_create_security_group_rule() - - def test_create_security_group_rule_with_bytes_body(self): - self._test_create_security_group_rule(bytes_body=True) - - def test_show_security_group_rule_with_str_body(self): - self._test_show_security_group_rule() - - def test_show_security_group_rule_with_bytes_body(self): - self._test_show_security_group_rule(bytes_body=True) - - def test_delete_security_group_rule(self): - self.check_service_client_function( - self.client.delete_security_group_rule, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=204, - security_group_rule_id=self.FAKE_SEC_GROUP_RULE_ID, - mock_args='v2.0/security-group-rules/%s' - % self.FAKE_SEC_GROUP_RULE_ID) diff --git a/tempest/tests/lib/services/network/test_security_groups_client.py b/tempest/tests/lib/services/network/test_security_groups_client.py deleted file mode 100644 index f96805f3b..000000000 --- a/tempest/tests/lib/services/network/test_security_groups_client.py +++ /dev/null @@ -1,174 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 copy - -import mock -from oslo_serialization import jsonutils as json - -from tempest.lib.services.network import base as network_base -from tempest.lib.services.network import security_groups_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSecurityGroupsClient(base.BaseServiceTest): - - FAKE_SEC_GROUP_ID = "85cc3048-abc3-43cc-89b3-377341426ac5" - - FAKE_SECURITY_GROUPS = { - "security_groups": [ - { - "description": "default", - "id": FAKE_SEC_GROUP_ID, - "name": "fake-security-group-name", - "security_group_rules": [ - { - "direction": "egress", - "ethertype": "IPv4", - "id": "38ce2d8e-e8f1-48bd-83c2-d33cb9f50c3d", - "port_range_max": None, - "port_range_min": None, - "protocol": None, - "remote_group_id": None, - "remote_ip_prefix": None, - "security_group_id": FAKE_SEC_GROUP_ID, - "project_id": "e4f50856753b4dc6afee5fa6b9b6c550", - "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550", - "description": "" - }, - { - "direction": "egress", - "ethertype": "IPv6", - "id": "565b9502-12de-4ffd-91e9-68885cff6ae1", - "port_range_max": None, - "port_range_min": None, - "protocol": None, - "remote_group_id": None, - "remote_ip_prefix": None, - "security_group_id": FAKE_SEC_GROUP_ID, - "project_id": "e4f50856753b4dc6afee5fa6b9b6c550", - "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550", - "description": "" - } - ], - "project_id": "e4f50856753b4dc6afee5fa6b9b6c550", - "tenant_id": "e4f50856753b4dc6afee5fa6b9b6c550" - } - ] - } - - FAKE_SECURITY_GROUP = { - "security_group": copy.deepcopy( - FAKE_SECURITY_GROUPS["security_groups"][0]) - } - - def setUp(self): - super(TestSecurityGroupsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = security_groups_client.SecurityGroupsClient( - fake_auth, 'network', 'regionOne') - - def _test_list_security_groups(self, bytes_body=False): - self.check_service_client_function( - self.client.list_security_groups, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SECURITY_GROUPS, - bytes_body, - mock_args='v2.0/security-groups') - - def _test_create_security_group(self, bytes_body=False): - kwargs = {'name': 'fake-security-group-name'} - payload = json.dumps({"security_group": kwargs}, sort_keys=True) - json_dumps = json.dumps - - # NOTE: Use sort_keys for json.dumps so that the expected and actual - # payloads are guaranteed to be identical for mock_args assert check. - with mock.patch.object(network_base.json, 'dumps') as mock_dumps: - mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True) - - self.check_service_client_function( - self.client.create_security_group, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_SECURITY_GROUP, - bytes_body, - status=201, - mock_args=['v2.0/security-groups', payload], - **kwargs) - - def _test_show_security_group(self, bytes_body=False): - self.check_service_client_function( - self.client.show_security_group, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SECURITY_GROUP, - bytes_body, - security_group_id=self.FAKE_SEC_GROUP_ID, - mock_args='v2.0/security-groups/%s' % self.FAKE_SEC_GROUP_ID) - - def _test_update_security_group(self, bytes_body=False): - kwargs = {'name': 'updated-security-group-name'} - resp_body = copy.deepcopy(self.FAKE_SECURITY_GROUP) - resp_body["security_group"]["name"] = 'updated-security-group-name' - - payload = json.dumps({'security_group': kwargs}, sort_keys=True) - json_dumps = json.dumps - - # NOTE: Use sort_keys for json.dumps so that the expected and actual - # payloads are guaranteed to be identical for mock_args assert check. - with mock.patch.object(network_base.json, 'dumps') as mock_dumps: - mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True) - - self.check_service_client_function( - self.client.update_security_group, - 'tempest.lib.common.rest_client.RestClient.put', - resp_body, - bytes_body, - security_group_id=self.FAKE_SEC_GROUP_ID, - mock_args=['v2.0/security-groups/%s' % self.FAKE_SEC_GROUP_ID, - payload], - **kwargs) - - def test_list_security_groups_with_str_body(self): - self._test_list_security_groups() - - def test_list_security_groups_with_bytes_body(self): - self._test_list_security_groups(bytes_body=True) - - def test_create_security_group_with_str_body(self): - self._test_create_security_group() - - def test_create_security_group_with_bytes_body(self): - self._test_create_security_group(bytes_body=True) - - def test_show_security_group_with_str_body(self): - self._test_show_security_group() - - def test_show_security_group_with_bytes_body(self): - self._test_show_security_group(bytes_body=True) - - def test_update_security_group_with_str_body(self): - self._test_update_security_group() - - def test_update_security_group_with_bytes_body(self): - self._test_update_security_group(bytes_body=True) - - def test_delete_security_group(self): - self.check_service_client_function( - self.client.delete_security_group, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=204, - security_group_id=self.FAKE_SEC_GROUP_ID, - mock_args='v2.0/security-groups/%s' % self.FAKE_SEC_GROUP_ID) diff --git a/tempest/tests/lib/services/network/test_service_providers_client.py b/tempest/tests/lib/services/network/test_service_providers_client.py deleted file mode 100644 index ae11ef0c7..000000000 --- a/tempest/tests/lib/services/network/test_service_providers_client.py +++ /dev/null @@ -1,37 +0,0 @@ -# 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 tempest.lib.services.network import service_providers_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestServiceProvidersClient(base.BaseServiceTest): - def setUp(self): - super(TestServiceProvidersClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = service_providers_client.ServiceProvidersClient( - fake_auth, 'network', 'regionOne') - - def _test_list_service_providers(self, bytes_body=False): - self.check_service_client_function( - self.client.list_service_providers, - 'tempest.lib.common.rest_client.RestClient.get', - {"service_providers": []}, - bytes_body) - - def test_list_service_providers_with_str_body(self): - self._test_list_service_providers() - - def test_list_service_providers_with_bytes_body(self): - self._test_list_service_providers(bytes_body=True) diff --git a/tempest/tests/lib/services/network/test_subnetpools_client.py b/tempest/tests/lib/services/network/test_subnetpools_client.py deleted file mode 100644 index 3abb43844..000000000 --- a/tempest/tests/lib/services/network/test_subnetpools_client.py +++ /dev/null @@ -1,163 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 copy - -from tempest.lib.services.network import subnetpools_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSubnetsClient(base.BaseServiceTest): - - FAKE_SUBNETPOOLS = { - "subnetpools": [ - { - "min_prefixlen": "64", - "address_scope_id": None, - "default_prefixlen": "64", - "id": "03f761e6-eee0-43fc-a921-8acf64c14988", - "max_prefixlen": "64", - "name": "my-subnet-pool-ipv6", - "default_quota": None, - "is_default": False, - "project_id": "9fadcee8aa7c40cdb2114fff7d569c08", - "tenant_id": "9fadcee8aa7c40cdb2114fff7d569c08", - "prefixes": [ - "2001:db8:0:2::/64", - "2001:db8::/63" - ], - "ip_version": 6, - "shared": False, - "description": "", - "revision_number": 2 - }, - { - "min_prefixlen": "24", - "address_scope_id": None, - "default_prefixlen": "25", - "id": "f49a1319-423a-4ee6-ba54-1d95a4f6cc68", - "max_prefixlen": "30", - "name": "my-subnet-pool-ipv4", - "default_quota": None, - "is_default": False, - "project_id": "9fadcee8aa7c40cdb2114fff7d569c08", - "tenant_id": "9fadcee8aa7c40cdb2114fff7d569c08", - "prefixes": [ - "10.10.0.0/21", - "192.168.0.0/16" - ], - "ip_version": 4, - "shared": False, - "description": "", - "revision_number": 2 - } - ] - } - - FAKE_SUBNETPOOL_ID = "03f761e6-eee0-43fc-a921-8acf64c14988" - - def setUp(self): - super(TestSubnetsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.subnetpools_client = subnetpools_client.SubnetpoolsClient( - fake_auth, 'compute', 'regionOne') - - def _test_list_subnetpools(self, bytes_body=False): - self.check_service_client_function( - self.subnetpools_client.list_subnetpools, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SUBNETPOOLS, - bytes_body, - 200) - - def _test_create_subnetpool(self, bytes_body=False): - self.check_service_client_function( - self.subnetpools_client.create_subnetpool, - 'tempest.lib.common.rest_client.RestClient.post', - {'subnetpool': self.FAKE_SUBNETPOOLS['subnetpools'][1]}, - bytes_body, - 201, - name="my-subnet-pool-ipv4", - prefixes=["192.168.0.0/16", "10.10.0.0/21"]) - - def _test_show_subnetpool(self, bytes_body=False): - self.check_service_client_function( - self.subnetpools_client.show_subnetpool, - 'tempest.lib.common.rest_client.RestClient.get', - {'subnetpool': self.FAKE_SUBNETPOOLS['subnetpools'][0]}, - bytes_body, - 200, - subnetpool_id=self.FAKE_SUBNETPOOL_ID) - - def _test_update_subnetpool(self, bytes_body=False): - update_kwargs = { - "name": "my-new-subnetpool-name", - "prefixes": [ - "2001:db8::/64", - "2001:db8:0:1::/64", - "2001:db8:0:2::/64" - ], - "min_prefixlen": 64, - "default_prefixlen": 64, - "max_prefixlen": 64 - } - - resp_body = { - 'subnetpool': copy.deepcopy( - self.FAKE_SUBNETPOOLS['subnetpools'][0]) - } - resp_body['subnetpool'].update(update_kwargs) - - self.check_service_client_function( - self.subnetpools_client.update_subnetpool, - 'tempest.lib.common.rest_client.RestClient.put', - resp_body, - bytes_body, - 200, - subnetpool_id=self.FAKE_SUBNETPOOL_ID, - **update_kwargs) - - def test_list_subnetpools_with_str_body(self): - self._test_list_subnetpools() - - def test_list_subnetpools_with_bytes_body(self): - self._test_list_subnetpools(bytes_body=True) - - def test_create_subnetpool_with_str_body(self): - self._test_create_subnetpool() - - def test_create_subnetpool_with_bytes_body(self): - self._test_create_subnetpool(bytes_body=True) - - def test_show_subnetpool_with_str_body(self): - self._test_show_subnetpool() - - def test_show_subnetpool_with_bytes_body(self): - self._test_show_subnetpool(bytes_body=True) - - def test_update_subnet_with_str_body(self): - self._test_update_subnetpool() - - def test_update_subnet_with_bytes_body(self): - self._test_update_subnetpool(bytes_body=True) - - def test_delete_subnetpool(self): - self.check_service_client_function( - self.subnetpools_client.delete_subnetpool, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=204, - subnetpool_id=self.FAKE_SUBNETPOOL_ID) diff --git a/tempest/tests/lib/services/network/test_subnets_client.py b/tempest/tests/lib/services/network/test_subnets_client.py deleted file mode 100644 index 0aadf5482..000000000 --- a/tempest/tests/lib/services/network/test_subnets_client.py +++ /dev/null @@ -1,250 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 copy - -from tempest.lib.services.network import subnets_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSubnetsClient(base.BaseServiceTest): - - FAKE_SUBNET = { - "subnet": { - "name": "", - "enable_dhcp": True, - "network_id": "d32019d3-bc6e-4319-9c1d-6722fc136a22", - "segment_id": None, - "project_id": "4fd44f30292945e481c7b8a0c8908869", - "tenant_id": "4fd44f30292945e481c7b8a0c8908869", - "dns_nameservers": [], - "allocation_pools": [ - { - "start": "192.168.199.2", - "end": "192.168.199.254" - } - ], - "host_routes": [], - "ip_version": 4, - "gateway_ip": "192.168.199.1", - "cidr": "192.168.199.0/24", - "id": "3b80198d-4f7b-4f77-9ef5-774d54e17126", - "created_at": "2016-10-10T14:35:47Z", - "description": "", - "ipv6_address_mode": None, - "ipv6_ra_mode": None, - "revision_number": 2, - "service_types": [], - "subnetpool_id": None, - "updated_at": "2016-10-10T14:35:47Z" - } - } - - FAKE_UPDATED_SUBNET = { - "subnet": { - "name": "my_subnet", - "enable_dhcp": True, - "network_id": "db193ab3-96e3-4cb3-8fc5-05f4296d0324", - "segment_id": None, - "project_id": "26a7980765d0414dbc1fc1f88cdb7e6e", - "tenant_id": "26a7980765d0414dbc1fc1f88cdb7e6e", - "dns_nameservers": [], - "allocation_pools": [ - { - "start": "10.0.0.2", - "end": "10.0.0.254" - } - ], - "host_routes": [], - "ip_version": 4, - "gateway_ip": "10.0.0.1", - "cidr": "10.0.0.0/24", - "id": "08eae331-0402-425a-923c-34f7cfe39c1b", - "description": "" - } - } - - FAKE_SUBNETS = { - "subnets": [ - { - "name": "private-subnet", - "enable_dhcp": True, - "network_id": "db193ab3-96e3-4cb3-8fc5-05f4296d0324", - "segment_id": None, - "project_id": "26a7980765d0414dbc1fc1f88cdb7e6e", - "tenant_id": "26a7980765d0414dbc1fc1f88cdb7e6e", - "dns_nameservers": [], - "allocation_pools": [ - { - "start": "10.0.0.2", - "end": "10.0.0.254" - } - ], - "host_routes": [], - "ip_version": 4, - "gateway_ip": "10.0.0.1", - "cidr": "10.0.0.0/24", - "id": "08eae331-0402-425a-923c-34f7cfe39c1b", - "created_at": "2016-10-10T14:35:34Z", - "description": "", - "ipv6_address_mode": None, - "ipv6_ra_mode": None, - "revision_number": 2, - "service_types": [], - "subnetpool_id": None, - "updated_at": "2016-10-10T14:35:34Z" - }, - { - "name": "my_subnet", - "enable_dhcp": True, - "network_id": "d32019d3-bc6e-4319-9c1d-6722fc136a22", - "segment_id": None, - "project_id": "4fd44f30292945e481c7b8a0c8908869", - "tenant_id": "4fd44f30292945e481c7b8a0c8908869", - "dns_nameservers": [], - "allocation_pools": [ - { - "start": "192.0.0.2", - "end": "192.255.255.254" - } - ], - "host_routes": [], - "ip_version": 4, - "gateway_ip": "192.0.0.1", - "cidr": "192.0.0.0/8", - "id": "54d6f61d-db07-451c-9ab3-b9609b6b6f0b", - "created_at": "2016-10-10T14:35:47Z", - "description": "", - "ipv6_address_mode": None, - "ipv6_ra_mode": None, - "revision_number": 2, - "service_types": [], - "subnetpool_id": None, - "updated_at": "2016-10-10T14:35:47Z" - } - ] - } - - FAKE_BULK_SUBNETS = copy.deepcopy(FAKE_SUBNETS) - - FAKE_SUBNET_ID = "54d6f61d-db07-451c-9ab3-b9609b6b6f0b" - - FAKE_NETWORK_ID = "d32019d3-bc6e-4319-9c1d-6722fc136a22" - - def setUp(self): - super(TestSubnetsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.subnets_client = subnets_client.SubnetsClient( - fake_auth, 'compute', 'regionOne') - - def _test_create_subnet(self, bytes_body=False): - self.check_service_client_function( - self.subnets_client.create_subnet, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_SUBNET, - bytes_body, - 201, - network_id=self.FAKE_NETWORK_ID, - ip_version=4, - cidr="192.168.199.0/24") - - def _test_update_subnet(self, bytes_body=False): - self.check_service_client_function( - self.subnets_client.update_subnet, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATED_SUBNET, - bytes_body, - 200, - subnet_id=self.FAKE_SUBNET_ID, - name="fake_updated_subnet_name") - - def _test_show_subnet(self, bytes_body=False): - self.check_service_client_function( - self.subnets_client.show_subnet, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SUBNET, - bytes_body, - 200, - subnet_id=self.FAKE_SUBNET_ID) - - def _test_list_subnets(self, bytes_body=False): - self.check_service_client_function( - self.subnets_client.list_subnets, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SUBNETS, - bytes_body, - 200) - - def _test_create_bulk_subnets(self, bytes_body=False): - kwargs = { - "subnets": [ - { - "cidr": "192.168.199.0/24", - "ip_version": 4, - "network_id": "e6031bc2-901a-4c66-82da-f4c32ed89406" - }, - { - "cidr": "10.56.4.0/22", - "ip_version": 4, - "network_id": "64239a54-dcc4-4b39-920b-b37c2144effa" - } - ] - } - self.check_service_client_function( - self.subnets_client.create_bulk_subnets, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_SUBNETS, - bytes_body, - 201, - **kwargs) - - def test_create_subnet_with_str_body(self): - self._test_create_subnet() - - def test_create_subnet_with_bytes_body(self): - self._test_create_subnet(bytes_body=True) - - def test_update_subnet_with_str_body(self): - self._test_update_subnet() - - def test_update_subnet_with_bytes_body(self): - self._test_update_subnet(bytes_body=True) - - def test_show_subnet_with_str_body(self): - self._test_show_subnet() - - def test_show_subnet_with_bytes_body(self): - self._test_show_subnet(bytes_body=True) - - def test_list_subnets_with_str_body(self): - self._test_list_subnets() - - def test_list_subnets_with_bytes_body(self): - self._test_list_subnets(bytes_body=True) - - def test_delete_subnet(self): - self.check_service_client_function( - self.subnets_client.delete_subnet, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=204, - subnet_id=self.FAKE_SUBNET_ID) - - def test_create_bulk_subnets_with_str_body(self): - self._test_create_bulk_subnets() - - def test_create_bulk_subnets_with_bytes_body(self): - self._test_create_bulk_subnets(bytes_body=True) diff --git a/tempest/tests/lib/services/network/test_tags_client.py b/tempest/tests/lib/services/network/test_tags_client.py deleted file mode 100644 index dbe50a045..000000000 --- a/tempest/tests/lib/services/network/test_tags_client.py +++ /dev/null @@ -1,123 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 tempest.lib.services.network import tags_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestTagsClient(base.BaseServiceTest): - - FAKE_TAGS = { - "tags": [ - "red", - "blue" - ] - } - - FAKE_RESOURCE_TYPE = 'network' - - FAKE_RESOURCE_ID = '7a8f904b-c1ed-4446-a87d-60440c02934b' - - def setUp(self): - super(TestTagsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = tags_client.TagsClient( - fake_auth, 'network', 'regionOne') - - def _test_update_all_tags(self, bytes_body=False): - self.check_service_client_function( - self.client.update_all_tags, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_TAGS, - bytes_body, - resource_type=self.FAKE_RESOURCE_TYPE, - resource_id=self.FAKE_RESOURCE_ID, - tags=self.FAKE_TAGS) - - def _test_check_tag_existence(self, bytes_body=False): - self.check_service_client_function( - self.client.check_tag_existence, - 'tempest.lib.common.rest_client.RestClient.get', - {}, - bytes_body, - resource_type=self.FAKE_RESOURCE_TYPE, - resource_id=self.FAKE_RESOURCE_ID, - tag=self.FAKE_TAGS['tags'][0], - status=204) - - def _test_create_tag(self, bytes_body=False): - self.check_service_client_function( - self.client.create_tag, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - bytes_body, - resource_type=self.FAKE_RESOURCE_TYPE, - resource_id=self.FAKE_RESOURCE_ID, - tag=self.FAKE_TAGS['tags'][0], - status=201) - - def _test_list_tags(self, bytes_body=False): - self.check_service_client_function( - self.client.list_tags, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_TAGS, - bytes_body, - resource_type=self.FAKE_RESOURCE_TYPE, - resource_id=self.FAKE_RESOURCE_ID) - - def test_update_all_tags_with_str_body(self): - self._test_update_all_tags() - - def test_update_all_tags_with_bytes_body(self): - self._test_update_all_tags(bytes_body=True) - - def test_delete_all_tags(self): - self.check_service_client_function( - self.client.delete_all_tags, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - resource_type=self.FAKE_RESOURCE_TYPE, - resource_id=self.FAKE_RESOURCE_ID, - status=204) - - def test_check_tag_existence_with_str_body(self): - self._test_check_tag_existence() - - def test_check_tag_existence_with_bytes_body(self): - self._test_check_tag_existence(bytes_body=True) - - def test_create_tag_with_str_body(self): - self._test_create_tag() - - def test_create_tag_with_bytes_body(self): - self._test_create_tag(bytes_body=True) - - def test_list_tags_with_str_body(self): - self._test_list_tags() - - def test_list_tags_with_bytes_body(self): - self._test_list_tags(bytes_body=True) - - def test_delete_tag(self): - self.check_service_client_function( - self.client.delete_tag, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - resource_type=self.FAKE_RESOURCE_TYPE, - resource_id=self.FAKE_RESOURCE_ID, - tag=self.FAKE_TAGS['tags'][0], - status=204) diff --git a/tempest/tests/lib/services/network/test_versions_client.py b/tempest/tests/lib/services/network/test_versions_client.py deleted file mode 100644 index 026dc6de2..000000000 --- a/tempest/tests/lib/services/network/test_versions_client.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2016 VMware, Inc. 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 copy - -from tempest.lib.services.network import versions_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestNetworkVersionsClient(base.BaseServiceTest): - - FAKE_INIT_VERSION = { - "version": { - "id": "v2.0", - "links": [ - { - "href": "http://openstack.example.com/v2.0/", - "rel": "self" - }, - { - "href": "http://docs.openstack.org/", - "rel": "describedby", - "type": "text/html" - } - ], - "status": "CURRENT" - } - } - - FAKE_VERSIONS_INFO = { - "versions": [FAKE_INIT_VERSION["version"]] - } - - FAKE_VERSION_INFO = copy.deepcopy(FAKE_INIT_VERSION) - - FAKE_VERSION_INFO["version"]["media-types"] = [ - { - "base": "application/json", - "type": "application/vnd.openstack.network+json;version=2.0" - } - ] - - def setUp(self): - super(TestNetworkVersionsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.versions_client = ( - versions_client.NetworkVersionsClient - (fake_auth, 'compute', 'regionOne')) - - def _test_versions_client(self, bytes_body=False): - self.check_service_client_function( - self.versions_client.list_versions, - 'tempest.lib.common.rest_client.RestClient.raw_request', - self.FAKE_VERSIONS_INFO, - bytes_body, - 200) - - def test_list_versions_client_with_str_body(self): - self._test_versions_client() - - def test_list_versions_client_with_bytes_body(self): - self._test_versions_client(bytes_body=True) diff --git a/tempest/tests/lib/services/test_clients.py b/tempest/tests/lib/services/test_clients.py deleted file mode 100644 index a837199c7..000000000 --- a/tempest/tests/lib/services/test_clients.py +++ /dev/null @@ -1,370 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# 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 types - -import fixtures -import mock -import testtools - -from tempest.lib import auth -from tempest.lib import exceptions -from tempest.lib.services import clients -from tempest.tests import base -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib import fake_credentials - - -has_attribute = testtools.matchers.MatchesPredicateWithParams( - lambda x, y: hasattr(x, y), '{0} does not have an attribute {1}') - - -class TestClientsFactory(base.TestCase): - - def setUp(self): - super(TestClientsFactory, self).setUp() - self.classes = [] - - def _setup_fake_module(self, class_names=None, extra_dict=None): - class_names = class_names or [] - fake_module = types.ModuleType('fake_service_client') - _dict = {} - # Add fake classes to the fake module - for name in class_names: - _dict[name] = type(name, (object,), {}) - # Store it for assertions - self.classes.append(_dict[name]) - if extra_dict: - _dict[extra_dict] = extra_dict - fake_module.__dict__.update(_dict) - fixture_importlib = self.useFixture(fixtures.MockPatch( - 'importlib.import_module', return_value=fake_module)) - return fixture_importlib.mock - - def test___init___one_class(self): - fake_partial = 'fake_partial' - partial_mock = self.useFixture(fixtures.MockPatch( - 'tempest.lib.services.clients.ClientsFactory._get_partial_class', - return_value=fake_partial)).mock - class_names = ['FakeServiceClient1'] - mock_importlib = self._setup_fake_module(class_names=class_names) - auth_provider = fake_auth_provider.FakeAuthProvider() - params = {'k1': 'v1', 'k2': 'v2'} - factory = clients.ClientsFactory('fake_path', class_names, - auth_provider, **params) - # Assert module has been imported - mock_importlib.assert_called_once_with('fake_path') - # All attributes have been created - for client in class_names: - self.assertThat(factory, has_attribute(client)) - # Partial have been invoked correctly - partial_mock.assert_called_once_with( - self.classes[0], auth_provider, params) - # Get the clients - for name in class_names: - self.assertEqual(fake_partial, getattr(factory, name)) - - def test___init___two_classes(self): - fake_partial = 'fake_partial' - partial_mock = self.useFixture(fixtures.MockPatch( - 'tempest.lib.services.clients.ClientsFactory._get_partial_class', - return_value=fake_partial)).mock - class_names = ['FakeServiceClient1', 'FakeServiceClient2'] - mock_importlib = self._setup_fake_module(class_names=class_names) - auth_provider = fake_auth_provider.FakeAuthProvider() - params = {'k1': 'v1', 'k2': 'v2'} - factory = clients.ClientsFactory('fake_path', class_names, - auth_provider, **params) - # Assert module has been imported - mock_importlib.assert_called_once_with('fake_path') - # All attributes have been created - for client in class_names: - self.assertThat(factory, has_attribute(client)) - # Partial have been invoked the right number of times - partial_mock.call_count = len(class_names) - # Get the clients - for name in class_names: - self.assertEqual(fake_partial, getattr(factory, name)) - - def test___init___no_module(self): - auth_provider = fake_auth_provider.FakeAuthProvider() - class_names = ['FakeServiceClient1', 'FakeServiceClient2'] - self.assertRaises(ImportError, clients.ClientsFactory, - 'fake_module', class_names, auth_provider) - - def test___init___not_a_class(self): - class_names = ['FakeServiceClient1', 'FakeServiceClient2'] - extended_class_names = class_names + ['not_really_a_class'] - self._setup_fake_module( - class_names=class_names, extra_dict='not_really_a_class') - auth_provider = fake_auth_provider.FakeAuthProvider() - expected_msg = '.*not_really_a_class.*str.*' - with testtools.ExpectedException(TypeError, expected_msg): - clients.ClientsFactory('fake_module', extended_class_names, - auth_provider) - - def test___init___class_not_found(self): - class_names = ['FakeServiceClient1', 'FakeServiceClient2'] - extended_class_names = class_names + ['not_really_a_class'] - self._setup_fake_module(class_names=class_names) - auth_provider = fake_auth_provider.FakeAuthProvider() - expected_msg = '.*not_really_a_class.*fake_service_client.*' - with testtools.ExpectedException(AttributeError, expected_msg): - clients.ClientsFactory('fake_module', extended_class_names, - auth_provider) - - def test__get_partial_class_no_later_kwargs(self): - expected_fake_client = 'not_really_a_client' - self._setup_fake_module(class_names=[]) - auth_provider = fake_auth_provider.FakeAuthProvider() - params = {'k1': 'v1', 'k2': 'v2'} - factory = clients.ClientsFactory( - 'fake_path', [], auth_provider, **params) - klass_mock = mock.Mock(return_value=expected_fake_client) - partial = factory._get_partial_class(klass_mock, auth_provider, params) - # Class has not be initialised yet - klass_mock.assert_not_called() - # Use partial and assert on parameters - client = partial() - self.assertEqual(expected_fake_client, client) - klass_mock.assert_called_once_with(auth_provider=auth_provider, - **params) - - def test__get_partial_class_later_kwargs(self): - expected_fake_client = 'not_really_a_client' - self._setup_fake_module(class_names=[]) - auth_provider = fake_auth_provider.FakeAuthProvider() - params = {'k1': 'v1', 'k2': 'v2'} - later_params = {'k2': 'v4', 'k3': 'v3'} - factory = clients.ClientsFactory( - 'fake_path', [], auth_provider, **params) - klass_mock = mock.Mock(return_value=expected_fake_client) - partial = factory._get_partial_class(klass_mock, auth_provider, params) - # Class has not be initialised yet - klass_mock.assert_not_called() - # Use partial and assert on parameters - client = partial(**later_params) - params.update(later_params) - self.assertEqual(expected_fake_client, client) - klass_mock.assert_called_once_with(auth_provider=auth_provider, - **params) - - def test__get_partial_class_with_alias(self): - expected_fake_client = 'not_really_a_client' - client_alias = 'fake_client' - self._setup_fake_module(class_names=[]) - auth_provider = fake_auth_provider.FakeAuthProvider() - params = {'k1': 'v1', 'k2': 'v2'} - later_params = {'k2': 'v4', 'k3': 'v3'} - factory = clients.ClientsFactory( - 'fake_path', [], auth_provider, **params) - klass_mock = mock.Mock(return_value=expected_fake_client) - partial = factory._get_partial_class(klass_mock, auth_provider, params) - # Class has not be initialised yet - klass_mock.assert_not_called() - # Use partial and assert on parameters - client = partial(alias=client_alias, **later_params) - params.update(later_params) - self.assertEqual(expected_fake_client, client) - klass_mock.assert_called_once_with(auth_provider=auth_provider, - **params) - self.assertThat(factory, has_attribute(client_alias)) - self.assertEqual(expected_fake_client, getattr(factory, client_alias)) - - -class TestServiceClients(base.TestCase): - - def setUp(self): - super(TestServiceClients, self).setUp() - self.useFixture(fixtures.MockPatch( - 'tempest.lib.services.clients.tempest_modules', return_value={})) - self.useFixture(fixtures.MockPatch( - 'tempest.lib.services.clients._tempest_internal_modules', - return_value=set(['fake_service1']))) - - def test___init___creds_v2_uri(self): - # Verify that no API request is made, since no mock - # is required to run the test successfully - creds = fake_credentials.FakeKeystoneV2Credentials() - uri = 'fake_uri' - _manager = clients.ServiceClients(creds, identity_uri=uri) - self.assertIsInstance(_manager.auth_provider, - auth.KeystoneV2AuthProvider) - - def test___init___creds_v3_uri(self): - # Verify that no API request is made, since no mock - # is required to run the test successfully - creds = fake_credentials.FakeKeystoneV3Credentials() - uri = 'fake_uri' - _manager = clients.ServiceClients(creds, identity_uri=uri) - self.assertIsInstance(_manager.auth_provider, - auth.KeystoneV3AuthProvider) - - def test___init___base_creds_uri(self): - creds = fake_credentials.FakeCredentials() - uri = 'fake_uri' - with testtools.ExpectedException(exceptions.InvalidCredentials): - clients.ServiceClients(creds, identity_uri=uri) - - def test___init___invalid_creds_uri(self): - creds = fake_credentials.FakeKeystoneV2Credentials() - delattr(creds, 'username') - uri = 'fake_uri' - with testtools.ExpectedException(exceptions.InvalidCredentials): - clients.ServiceClients(creds, identity_uri=uri) - - def test___init___creds_uri_none(self): - creds = fake_credentials.FakeKeystoneV2Credentials() - msg = ("Invalid Credentials\nDetails: ServiceClients requires a " - "non-empty") - with testtools.ExpectedException(exceptions.InvalidCredentials, - value_re=msg): - clients.ServiceClients(creds, None) - - def test___init___creds_uri_params(self): - creds = fake_credentials.FakeKeystoneV2Credentials() - expeted_params = {'fake_param1': 'fake_value1', - 'fake_param2': 'fake_value2'} - params = {'fake_service1': expeted_params} - uri = 'fake_uri' - _manager = clients.ServiceClients(creds, identity_uri=uri, - client_parameters=params) - self.assertIn('fake_service1', _manager.parameters) - for _key in expeted_params: - self.assertIn(_key, _manager.parameters['fake_service1'].keys()) - self.assertEqual(expeted_params[_key], - _manager.parameters['fake_service1'].get(_key)) - - def test___init___creds_uri_params_unknown_services(self): - creds = fake_credentials.FakeKeystoneV2Credentials() - fake_params = {'fake_param1': 'fake_value1'} - params = {'unknown_service1': fake_params, - 'unknown_service2': fake_params} - uri = 'fake_uri' - msg = "(?=.*{0})(?=.*{1})".format(*list(params.keys())) - with testtools.ExpectedException( - exceptions.UnknownServiceClient, value_re=msg): - clients.ServiceClients(creds, identity_uri=uri, - client_parameters=params) - - def _get_manager(self, init_region='fake_region'): - # Get a manager to invoke _setup_parameters on - creds = fake_credentials.FakeKeystoneV2Credentials() - return clients.ServiceClients(creds, identity_uri='fake_uri', - region=init_region) - - def test__setup_parameters_none_no_region(self): - kwargs = {} - _manager = self._get_manager(init_region=None) - _params = _manager._setup_parameters(kwargs) - self.assertNotIn('region', _params) - - def test__setup_parameters_none(self): - kwargs = {} - _manager = self._get_manager() - _params = _manager._setup_parameters(kwargs) - self.assertIn('region', _params) - self.assertEqual('fake_region', _params['region']) - - def test__setup_parameters_all(self): - expected_params = {'region': 'fake_region1', - 'catalog_type': 'fake_service2_mod', - 'fake_param1': 'fake_value1', - 'fake_param2': 'fake_value2'} - _manager = self._get_manager() - _params = _manager._setup_parameters(expected_params) - for _key in _params.keys(): - self.assertEqual(expected_params[_key], - _params[_key]) - - def test_register_service_client_module(self): - expected_params = {'fake_param1': 'fake_value1', - 'fake_param2': 'fake_value2'} - _manager = self._get_manager(init_region='fake_region_default') - # Mock after the _manager is setup to preserve the call count - factory_mock = self.useFixture(fixtures.MockPatch( - 'tempest.lib.services.clients.ClientsFactory')).mock - _manager.register_service_client_module( - name='fake_module', - service_version='fake_service', - module_path='fake.path.to.module', - client_names=[], - **expected_params) - self.assertThat(_manager, has_attribute('fake_module')) - # Assert called once, without check for exact parameters - self.assertTrue(factory_mock.called) - self.assertEqual(1, factory_mock.call_count) - # Assert expected params are in with their values - actual_kwargs = factory_mock.call_args[1] - self.assertIn('region', actual_kwargs) - self.assertEqual('fake_region_default', actual_kwargs['region']) - for param in expected_params: - self.assertIn(param, actual_kwargs) - self.assertEqual(expected_params[param], actual_kwargs[param]) - # Assert the new service is registered - self.assertIn('fake_service', _manager._registered_services) - - def test_register_service_client_module_override_default(self): - new_region = 'new_region' - expected_params = {'fake_param1': 'fake_value1', - 'fake_param2': 'fake_value2', - 'region': new_region} - _manager = self._get_manager(init_region='fake_region_default') - # Mock after the _manager is setup to preserve the call count - factory_mock = self.useFixture(fixtures.MockPatch( - 'tempest.lib.services.clients.ClientsFactory')).mock - _manager.register_service_client_module( - name='fake_module', - service_version='fake_service', - module_path='fake.path.to.module', - client_names=[], - **expected_params) - self.assertThat(_manager, has_attribute('fake_module')) - # Assert called once, without check for exact parameters - self.assertTrue(factory_mock.called) - self.assertEqual(1, factory_mock.call_count) - # Assert expected params are in with their values - actual_kwargs = factory_mock.call_args[1] - self.assertIn('region', actual_kwargs) - self.assertEqual(new_region, actual_kwargs['region']) - for param in expected_params: - self.assertIn(param, actual_kwargs) - self.assertEqual(expected_params[param], actual_kwargs[param]) - # Assert the new service is registered - self.assertIn('fake_service', _manager._registered_services) - - def test_register_service_client_module_duplicate_name(self): - self.useFixture(fixtures.MockPatch( - 'tempest.lib.services.clients.ClientsFactory')).mock - _manager = self._get_manager() - name_owner = 'this_is_a_string' - setattr(_manager, 'fake_module', name_owner) - expected_error = '.*' + name_owner - with testtools.ExpectedException( - exceptions.ServiceClientRegistrationException, expected_error): - _manager.register_service_client_module( - name='fake_module', module_path='fake.path.to.module', - service_version='fake_service', client_names=[]) - - def test_register_service_client_module_duplicate_service(self): - self.useFixture(fixtures.MockPatch( - 'tempest.lib.services.clients.ClientsFactory')).mock - _manager = self._get_manager() - duplicate_service = 'fake_service1' - expected_error = '.*' + duplicate_service - with testtools.ExpectedException( - exceptions.ServiceClientRegistrationException, expected_error): - _manager.register_service_client_module( - name='fake_module', module_path='fake.path.to.module', - service_version=duplicate_service, client_names=[]) diff --git a/tempest/tests/lib/services/volume/__init__.py b/tempest/tests/lib/services/volume/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/volume/v1/__init__.py b/tempest/tests/lib/services/volume/v1/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/volume/v1/test_encryption_types_client.py b/tempest/tests/lib/services/volume/v1/test_encryption_types_client.py deleted file mode 100644 index 585904e91..000000000 --- a/tempest/tests/lib/services/volume/v1/test_encryption_types_client.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.lib.services.volume.v1 import encryption_types_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestEncryptionTypesClient(base.BaseServiceTest): - FAKE_CREATE_ENCRYPTION_TYPE = { - "encryption": { - "id": "cbc36478b0bd8e67e89", - "name": "FakeEncryptionType", - "type": "fakeType", - "provider": "LuksEncryptor", - "cipher": "aes-xts-plain64", - "key_size": "512", - "control_location": "front-end" - } - } - - FAKE_INFO_ENCRYPTION_TYPE = { - "encryption": { - "name": "FakeEncryptionType", - "type": "fakeType", - "description": "test_description", - "volume_type": "fakeType", - "provider": "LuksEncryptor", - "cipher": "aes-xts-plain64", - "key_size": "512", - "control_location": "front-end" - } - } - - def setUp(self): - super(TestEncryptionTypesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = encryption_types_client.EncryptionTypesClient(fake_auth, - 'volume', - 'regionOne' - ) - - def _test_create_encryption(self, bytes_body=False): - self.check_service_client_function( - self.client.create_encryption_type, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_ENCRYPTION_TYPE, - bytes_body, volume_type_id="cbc36478b0bd8e67e89") - - def _test_show_encryption_type(self, bytes_body=False): - self.check_service_client_function( - self.client.show_encryption_type, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_INFO_ENCRYPTION_TYPE, - bytes_body, volume_type_id="cbc36478b0bd8e67e89") - - def test_create_encryption_type_with_str_body(self): - self._test_create_encryption() - - def test_create_encryption_type_with_bytes_body(self): - self._test_create_encryption(bytes_body=True) - - def test_show_encryption_type_with_str_body(self): - self._test_show_encryption_type() - - def test_show_encryption_type_with_bytes_body(self): - self._test_show_encryption_type(bytes_body=True) - - def test_delete_encryption_type(self): - self.check_service_client_function( - self.client.delete_encryption_type, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - volume_type_id="cbc36478b0bd8e67e89", - status=202) diff --git a/tempest/tests/lib/services/volume/v1/test_quotas_client.py b/tempest/tests/lib/services/volume/v1/test_quotas_client.py deleted file mode 100644 index f9e76afe6..000000000 --- a/tempest/tests/lib/services/volume/v1/test_quotas_client.py +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.lib.services.volume.v1 import quotas_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestQuotasClient(base.BaseServiceTest): - FAKE_QUOTAS = { - "quota_set": { - "cores": 20, - "fixed_ips": -1, - "floating_ips": 10, - "id": "fake_tenant", - "injected_file_content_bytes": 10240, - "injected_file_path_bytes": 255, - "injected_files": 5, - "instances": 10, - "key_pairs": 100, - "metadata_items": 128, - "ram": 51200, - "security_group_rules": 20, - "security_groups": 10 - } - } - - FAKE_UPDATE_QUOTAS_REQUEST = { - "quota_set": { - "security_groups": 45 - } - } - - def setUp(self): - super(TestQuotasClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = quotas_client.QuotasClient(fake_auth, - 'volume', - 'regionOne') - - def _test_show_default_quota_set(self, bytes_body=False): - self.check_service_client_function( - self.client.show_default_quota_set, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_QUOTAS, - bytes_body, tenant_id="fake_tenant") - - def _test_show_quota_set(self, bytes_body=False): - self.check_service_client_function( - self.client.show_quota_set, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_QUOTAS, - bytes_body, tenant_id="fake_tenant") - - def _test_update_quota_set(self, bytes_body=False): - self.check_service_client_function( - self.client.update_quota_set, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_QUOTAS_REQUEST, - bytes_body, tenant_id="fake_tenant") - - def test_show_default_quota_set_with_str_body(self): - self._test_show_default_quota_set() - - def test_show_default_quota_set_with_bytes_body(self): - self._test_show_default_quota_set(bytes_body=True) - - def test_show_quota_set_with_str_body(self): - self._test_show_quota_set() - - def test_show_quota_set_with_bytes_body(self): - self._test_show_quota_set(bytes_body=True) - - def test_update_quota_set_with_str_body(self): - self._test_update_quota_set() - - def test_update_quota_set_with_bytes_body(self): - self._test_update_quota_set(bytes_body=True) - - def test_delete_quota_set(self): - self.check_service_client_function( - self.client.delete_quota_set, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - tenant_id="fake_tenant") diff --git a/tempest/tests/lib/services/volume/v1/test_snapshots_client.py b/tempest/tests/lib/services/volume/v1/test_snapshots_client.py deleted file mode 100644 index 49191e323..000000000 --- a/tempest/tests/lib/services/volume/v1/test_snapshots_client.py +++ /dev/null @@ -1,200 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.lib.services.volume.v1 import snapshots_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSnapshotsClient(base.BaseServiceTest): - FAKE_CREATE_SNAPSHOT = { - "snapshot": { - "display_name": "snap-001", - "display_description": "Daily backup", - "volume_id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c", - "force": True - } - } - - FAKE_UPDATE_SNAPSHOT_REQUEST = { - "metadata": { - "key": "v1" - } - } - - FAKE_INFO_SNAPSHOT = { - "snapshot": { - "id": "3fbbcccf-d058-4502-8844-6feeffdf4cb5", - "display_name": "snap-001", - "display_description": "Daily backup", - "volume_id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c", - "status": "available", - "size": 30, - "created_at": "2012-02-29T03:50:07Z" - } - } - - FAKE_LIST_SNAPSHOTS = { - "snapshots": [ - { - "id": "3fbbcccf-d058-4502-8844-6feeffdf4cb5", - "display_name": "snap-001", - "display_description": "Daily backup", - "volume_id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c", - "status": "available", - "size": 30, - "created_at": "2012-02-29T03:50:07Z", - "metadata": { - "contents": "junk" - } - }, - { - "id": "e479997c-650b-40a4-9dfe-77655818b0d2", - "display_name": "snap-002", - "display_description": "Weekly backup", - "volume_id": "76b8950a-8594-4e5b-8dce-0dfa9c696358", - "status": "available", - "size": 25, - "created_at": "2012-03-19T01:52:47Z", - "metadata": {} - } - ] - } - - def setUp(self): - super(TestSnapshotsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = snapshots_client.SnapshotsClient(fake_auth, - 'volume', - 'regionOne') - - def _test_create_snapshot(self, bytes_body=False): - self.check_service_client_function( - self.client.create_snapshot, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_SNAPSHOT, - bytes_body) - - def _test_show_snapshot(self, bytes_body=False): - self.check_service_client_function( - self.client.show_snapshot, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_INFO_SNAPSHOT, - bytes_body, - snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5") - - def _test_list_snapshots(self, bytes_body=False): - self.check_service_client_function( - self.client.list_snapshots, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_SNAPSHOTS, - bytes_body, - detail=True) - - def _test_create_snapshot_metadata(self, bytes_body=False): - self.check_service_client_function( - self.client.create_snapshot_metadata, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_INFO_SNAPSHOT, - bytes_body, - snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5", - metadata={"key": "v1"}) - - def _test_update_snapshot(self, bytes_body=False): - self.check_service_client_function( - self.client.update_snapshot, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_SNAPSHOT_REQUEST, - bytes_body, - snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5") - - def _test_show_snapshot_metadata(self, bytes_body=False): - self.check_service_client_function( - self.client.show_snapshot_metadata, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_UPDATE_SNAPSHOT_REQUEST, - bytes_body, - snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5") - - def _test_update_snapshot_metadata(self, bytes_body=False): - self.check_service_client_function( - self.client.update_snapshot_metadata, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_SNAPSHOT_REQUEST, - bytes_body, snapshot_id="cbc36478b0bd8e67e89") - - def _test_update_snapshot_metadata_item(self, bytes_body=False): - self.check_service_client_function( - self.client.update_snapshot_metadata_item, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_INFO_SNAPSHOT, - bytes_body, volume_type_id="cbc36478b0bd8e67e89") - - def test_create_snapshot_with_str_body(self): - self._test_create_snapshot() - - def test_create_snapshot_with_bytes_body(self): - self._test_create_snapshot(bytes_body=True) - - def test_show_snapshot_with_str_body(self): - self._test_show_snapshot() - - def test_show_snapshot_with_bytes_body(self): - self._test_show_snapshot(bytes_body=True) - - def test_list_snapshots_with_str_body(self): - self._test_list_snapshots() - - def test_list_snapshots_with_bytes_body(self): - self._test_list_snapshots(bytes_body=True) - - def test_create_snapshot_metadata_with_str_body(self): - self._test_create_snapshot_metadata() - - def test_create_snapshot_metadata_with_bytes_body(self): - self._test_create_snapshot_metadata(bytes_body=True) - - def test_update_snapshot_with_str_body(self): - self._test_update_snapshot() - - def test_update_snapshot_with_bytes_body(self): - self._test_update_snapshot(bytes_body=True) - - def test_show_snapshot_metadata_with_str_body(self): - self._test_show_snapshot_metadata() - - def test_show_snapshot_metadata_with_bytes_body(self): - self._test_show_snapshot_metadata(bytes_body=True) - - def test_update_snapshot_metadata_with_str_body(self): - self._test_update_snapshot_metadata() - - def test_update_snapshot_metadata_with_bytes_body(self): - self._test_update_snapshot_metadata(bytes_body=True) - - def test_force_delete_snapshot(self): - self.check_service_client_function( - self.client.force_delete_snapshot, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - snapshot_id="521752a6-acf6-4b2d-bc7a-119f9148cd8c", - status=202) - - def test_delete_snapshot(self): - self.check_service_client_function( - self.client.delete_snapshot, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - snapshot_id="521752a6-acf6-4b2d-bc7a-119f9148cd8c", - status=202) diff --git a/tempest/tests/lib/services/volume/v2/__init__.py b/tempest/tests/lib/services/volume/v2/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/volume/v2/test_backups_client.py b/tempest/tests/lib/services/volume/v2/test_backups_client.py deleted file mode 100644 index 14e5fb0be..000000000 --- a/tempest/tests/lib/services/volume/v2/test_backups_client.py +++ /dev/null @@ -1,117 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# 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 tempest.lib.services.volume.v2 import backups_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestBackupsClient(base.BaseServiceTest): - - FAKE_BACKUP_LIST = { - "backups": [ - { - "id": "2ef47aee-8844-490c-804d-2a8efe561c65", - "links": [ - { - "href": "fake-url-1", - "rel": "self" - }, - { - "href": "fake-url-2", - "rel": "bookmark" - } - ], - "name": "backup001" - } - ] - } - - FAKE_BACKUP_LIST_WITH_DETAIL = { - "backups": [ - { - "availability_zone": "az1", - "container": "volumebackups", - "created_at": "2013-04-02T10:35:27.000000", - "description": None, - "fail_reason": None, - "id": "2ef47aee-8844-490c-804d-2a8efe561c65", - "links": [ - { - "href": "fake-url-1", - "rel": "self" - }, - { - "href": "fake-url-2", - "rel": "bookmark" - } - ], - "name": "backup001", - "object_count": 22, - "size": 1, - "status": "available", - "volume_id": "e5185058-943a-4cb4-96d9-72c184c337d6", - "is_incremental": True, - "has_dependent_backups": False - } - ] - } - - def setUp(self): - super(TestBackupsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = backups_client.BackupsClient(fake_auth, - 'volume', - 'regionOne') - - def _test_list_backups(self, detail=False, mock_args='backups', - bytes_body=False, **params): - if detail: - resp_body = self.FAKE_BACKUP_LIST_WITH_DETAIL - else: - resp_body = self.FAKE_BACKUP_LIST - self.check_service_client_function( - self.client.list_backups, - 'tempest.lib.common.rest_client.RestClient.get', - resp_body, - to_utf=bytes_body, - mock_args=[mock_args], - detail=detail, - **params) - - def test_list_backups_with_str_body(self): - self._test_list_backups() - - def test_list_backups_with_bytes_body(self): - self._test_list_backups(bytes_body=True) - - def test_list_backups_with_detail_with_str_body(self): - mock_args = "backups/detail" - self._test_list_backups(detail=True, mock_args=mock_args) - - def test_list_backups_with_detail_with_bytes_body(self): - mock_args = "backups/detail" - self._test_list_backups(detail=True, mock_args=mock_args, - bytes_body=True) - - def test_list_backups_with_params(self): - # Run the test separately for each param, to avoid assertion error - # resulting from randomized params order. - mock_args = 'backups?sort_key=name' - self._test_list_backups(mock_args=mock_args, sort_key='name') - - mock_args = 'backups/detail?limit=10' - self._test_list_backups(detail=True, mock_args=mock_args, - bytes_body=True, limit=10) diff --git a/tempest/tests/lib/services/volume/v2/test_capabilities_client.py b/tempest/tests/lib/services/volume/v2/test_capabilities_client.py deleted file mode 100644 index 3d3f1e119..000000000 --- a/tempest/tests/lib/services/volume/v2/test_capabilities_client.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 tempest.lib.services.volume.v2 import capabilities_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestCapabilitiesClient(base.BaseServiceTest): - - FAKE_BACKEND_CAPABILITIES = { - "namespace": "OS::Storage::Capabilities::fake", - "vendor_name": "OpenStack", - "volume_backend_name": "lvmdriver-1", - "pool_name": "pool", - "driver_version": "2.0.0", - "storage_protocol": "iSCSI", - "display_name": "Capabilities of Cinder LVM driver", - "description": ( - "These are volume type options provided by Cinder LVM driver."), - "visibility": "public", - "replication_targets": [], - "properties": { - "compression": { - "title": "Compression", - "description": "Enables compression.", - "type": "boolean" - }, - "qos": { - "title": "QoS", - "description": "Enables QoS.", - "type": "boolean" - }, - "replication": { - "title": "Replication", - "description": "Enables replication.", - "type": "boolean" - }, - "thin_provisioning": { - "title": "Thin Provisioning", - "description": "Sets thin provisioning.", - "type": "boolean" - } - } - } - - def setUp(self): - super(TestCapabilitiesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = capabilities_client.CapabilitiesClient( - fake_auth, 'volume', 'regionOne') - - def _test_show_backend_capabilities(self, bytes_body=False): - self.check_service_client_function( - self.client.show_backend_capabilities, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_BACKEND_CAPABILITIES, - bytes_body, - host='lvmdriver-1') - - def test_show_backend_capabilities_with_str_body(self): - self._test_show_backend_capabilities() - - def test_show_backend_capabilities_with_bytes_body(self): - self._test_show_backend_capabilities(bytes_body=True) diff --git a/tempest/tests/lib/services/volume/v2/test_encryption_types_client.py b/tempest/tests/lib/services/volume/v2/test_encryption_types_client.py deleted file mode 100644 index d0290911e..000000000 --- a/tempest/tests/lib/services/volume/v2/test_encryption_types_client.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.lib.services.volume.v2 import encryption_types_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestEncryptionTypesClient(base.BaseServiceTest): - FAKE_CREATE_ENCRYPTION_TYPE = { - "encryption": { - "id": "cbc36478b0bd8e67e89", - "name": "FakeEncryptionType", - "type": "fakeType", - "provider": "LuksEncryptor", - "cipher": "aes-xts-plain64", - "key_size": "512", - "control_location": "front-end" - } - } - - FAKE_INFO_ENCRYPTION_TYPE = { - "encryption": { - "name": "FakeEncryptionType", - "type": "fakeType", - "description": "test_description", - "volume_type": "fakeType", - "provider": "LuksEncryptor", - "cipher": "aes-xts-plain64", - "key_size": "512", - "control_location": "front-end" - } - } - - def setUp(self): - super(TestEncryptionTypesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = encryption_types_client.EncryptionTypesClient(fake_auth, - 'volume', - 'regionOne' - ) - - def _test_create_encryption(self, bytes_body=False): - self.check_service_client_function( - self.client.create_encryption_type, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_ENCRYPTION_TYPE, - bytes_body, volume_type_id="cbc36478b0bd8e67e89") - - def _test_show_encryption_type(self, bytes_body=False): - self.check_service_client_function( - self.client.show_encryption_type, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_INFO_ENCRYPTION_TYPE, - bytes_body, volume_type_id="cbc36478b0bd8e67e89") - - def test_create_encryption_type_with_str_body(self): - self._test_create_encryption() - - def test_create_encryption_type_with_bytes_body(self): - self._test_create_encryption(bytes_body=True) - - def test_show_encryption_type_with_str_body(self): - self._test_show_encryption_type() - - def test_show_encryption_type_with_bytes_body(self): - self._test_show_encryption_type(bytes_body=True) - - def test_delete_encryption_type(self): - self.check_service_client_function( - self.client.delete_encryption_type, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - volume_type_id="cbc36478b0bd8e67e89", - status=202) diff --git a/tempest/tests/lib/services/volume/v2/test_extensions_client.py b/tempest/tests/lib/services/volume/v2/test_extensions_client.py deleted file mode 100644 index c0ee42125..000000000 --- a/tempest/tests/lib/services/volume/v2/test_extensions_client.py +++ /dev/null @@ -1,70 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# 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 tempest.lib.services.volume.v2 import extensions_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestExtensionsClient(base.BaseServiceTest): - - FAKE_EXTENSION_LIST = { - "extensions": [ - { - "updated": "2012-03-12T00:00:00+00:00", - "name": "QuotaClasses", - "links": [], - "namespace": "fake-namespace-1", - "alias": "os-quota-class-sets", - "description": "Quota classes management support." - }, - { - "updated": "2013-05-29T00:00:00+00:00", - "name": "VolumeTransfer", - "links": [], - "namespace": "fake-namespace-2", - "alias": "os-volume-transfer", - "description": "Volume transfer management support." - }, - { - "updated": "2014-02-10T00:00:00+00:00", - "name": "VolumeManage", - "links": [], - "namespace": "fake-namespace-3", - "alias": "os-volume-manage", - "description": "Manage existing backend storage by Cinder." - } - ] - } - - def setUp(self): - super(TestExtensionsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = extensions_client.ExtensionsClient(fake_auth, - 'volume', - 'regionOne') - - def _test_list_extensions(self, bytes_body=False): - self.check_service_client_function( - self.client.list_extensions, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_EXTENSION_LIST, - bytes_body) - - def test_list_extensions_with_str_body(self): - self._test_list_extensions() - - def test_list_extensions_with_bytes_body(self): - self._test_list_extensions(bytes_body=True) diff --git a/tempest/tests/lib/services/volume/v2/test_hosts_client.py b/tempest/tests/lib/services/volume/v2/test_hosts_client.py deleted file mode 100644 index e10791014..000000000 --- a/tempest/tests/lib/services/volume/v2/test_hosts_client.py +++ /dev/null @@ -1,97 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# 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 tempest.lib.services.volume.v2 import hosts_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestQuotasClient(base.BaseServiceTest): - FAKE_LIST_HOSTS = { - "hosts": [ - { - "service-status": "available", - "service": "cinder-scheduler", - "zone": "nova", - "service-state": "enabled", - "host_name": "fake-host", - "last-update": "2017-04-12T04:26:03.000000" - }, - { - "service-status": "available", - "service": "cinder-volume", - "zone": "nova", - "service-state": "enabled", - "host_name": "fake-host@rbd", - "last-update": "2017-04-12T04:26:07.000000" - } - ] - } - - FAKE_HOST_INFO = { - "host": [ - { - "resource": { - "volume_count": "2", - "total_volume_gb": "2", - "total_snapshot_gb": "0", - "project": "(total)", - "host": "fake-host", - "snapshot_count": "0" - } - }, - { - "resource": { - "volume_count": "2", - "total_volume_gb": "2", - "total_snapshot_gb": "0", - "project": "f21a9c86d7114bf99c711f4874d80474", - "host": "fake-host", - "snapshot_count": "0" - } - } - ] - } - - def setUp(self): - super(TestQuotasClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = hosts_client.HostsClient(fake_auth, - 'volume', - 'regionOne') - - def _test_list_hosts(self, bytes_body=False): - self.check_service_client_function( - self.client.list_hosts, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_HOSTS, bytes_body) - - def _test_show_host(self, bytes_body=False): - self.check_service_client_function( - self.client.show_host, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_HOST_INFO, bytes_body, host_name='fake-host') - - def test_list_hosts_with_str_body(self): - self._test_list_hosts() - - def test_list_hosts_with_bytes_body(self): - self._test_list_hosts(bytes_body=True) - - def test_show_host_with_str_body(self): - self._test_show_host() - - def test_show_host_with_bytes_body(self): - self._test_show_host(bytes_body=True) diff --git a/tempest/tests/lib/services/volume/v2/test_limits_client.py b/tempest/tests/lib/services/volume/v2/test_limits_client.py deleted file mode 100644 index 202054c02..000000000 --- a/tempest/tests/lib/services/volume/v2/test_limits_client.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# 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 tempest.lib.services.volume.v2 import limits_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestLimitsClient(base.BaseServiceTest): - - FAKE_LIMIT_INFO = { - "limits": { - "rate": [], - "absolute": { - "totalSnapshotsUsed": 0, - "maxTotalBackups": 10, - "maxTotalVolumeGigabytes": 1000, - "maxTotalSnapshots": 10, - "maxTotalBackupGigabytes": 1000, - "totalBackupGigabytesUsed": 0, - "maxTotalVolumes": 10, - "totalVolumesUsed": 0, - "totalBackupsUsed": 0, - "totalGigabytesUsed": 0 - } - } - } - - def setUp(self): - super(TestLimitsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = limits_client.LimitsClient(fake_auth, - 'volume', - 'regionOne') - - def _test_show_limits(self, bytes_body=False): - self.check_service_client_function( - self.client.show_limits, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIMIT_INFO, - bytes_body) - - def test_show_limits_with_str_body(self): - self._test_show_limits() - - def test_show_limits_with_bytes_body(self): - self._test_show_limits(bytes_body=True) diff --git a/tempest/tests/lib/services/volume/v2/test_quota_classes_client.py b/tempest/tests/lib/services/volume/v2/test_quota_classes_client.py deleted file mode 100644 index e715fccc9..000000000 --- a/tempest/tests/lib/services/volume/v2/test_quota_classes_client.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# 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 copy - -from tempest.lib.services.volume.v2 import quota_classes_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestQuotaClassesClient(base.BaseServiceTest): - - FAKE_QUOTA_CLASS_SET = { - "id": "test", - "gigabytes": 2000, - "volumes": 200, - "snapshots": 50, - "backups": 20, - "backup_gigabytes": 1500, - "per_volume_gigabytes": 500, - } - - def setUp(self): - super(TestQuotaClassesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = quota_classes_client.QuotaClassesClient( - fake_auth, 'volume', 'regionOne') - - def _test_show_quota_class_set(self, bytes_body=False): - fake_body = {'quota_class_set': self.FAKE_QUOTA_CLASS_SET} - self.check_service_client_function( - self.client.show_quota_class_set, - 'tempest.lib.common.rest_client.RestClient.get', - fake_body, - bytes_body, - quota_class_id="test") - - def _test_update_quota_class_set(self, bytes_body=False): - fake_quota_class_set = copy.deepcopy(self.FAKE_QUOTA_CLASS_SET) - fake_quota_class_set.pop("id") - fake_body = {'quota_class_set': fake_quota_class_set} - self.check_service_client_function( - self.client.update_quota_class_set, - 'tempest.lib.common.rest_client.RestClient.put', - fake_body, - bytes_body, - quota_class_id="test") - - def test_show_quota_class_set_with_str_body(self): - self._test_show_quota_class_set() - - def test_show_quota_class_set_with_bytes_body(self): - self._test_show_quota_class_set(bytes_body=True) - - def test_update_quota_class_set_with_str_boy(self): - self._test_update_quota_class_set() - - def test_update_quota_class_set_with_bytes_body(self): - self._test_update_quota_class_set(bytes_body=True) diff --git a/tempest/tests/lib/services/volume/v2/test_quotas_client.py b/tempest/tests/lib/services/volume/v2/test_quotas_client.py deleted file mode 100644 index 6384350d2..000000000 --- a/tempest/tests/lib/services/volume/v2/test_quotas_client.py +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.lib.services.volume.v2 import quotas_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestQuotasClient(base.BaseServiceTest): - FAKE_QUOTAS = { - "quota_set": { - "gigabytes": 5, - "snapshots": 10, - "volumes": 20 - } - } - - FAKE_UPDATE_QUOTAS_REQUEST = { - "quota_set": { - "security_groups": 45 - } - } - - def setUp(self): - super(TestQuotasClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = quotas_client.QuotasClient(fake_auth, - 'volume', - 'regionOne') - - def _test_show_default_quota_set(self, bytes_body=False): - self.check_service_client_function( - self.client.show_default_quota_set, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_QUOTAS, - bytes_body, tenant_id="fake_tenant") - - def _test_show_quota_set(self, bytes_body=False): - self.check_service_client_function( - self.client.show_quota_set, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_QUOTAS, - bytes_body, tenant_id="fake_tenant") - - def _test_update_quota_set(self, bytes_body=False): - self.check_service_client_function( - self.client.update_quota_set, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_QUOTAS_REQUEST, - bytes_body, tenant_id="fake_tenant") - - def test_show_default_quota_set_with_str_body(self): - self._test_show_default_quota_set() - - def test_show_default_quota_set_with_bytes_body(self): - self._test_show_default_quota_set(bytes_body=True) - - def test_show_quota_set_with_str_body(self): - self._test_show_quota_set() - - def test_show_quota_set_with_bytes_body(self): - self._test_show_quota_set(bytes_body=True) - - def test_update_quota_set_with_str_body(self): - self._test_update_quota_set() - - def test_update_quota_set_with_bytes_body(self): - self._test_update_quota_set(bytes_body=True) - - def test_delete_quota_set(self): - self.check_service_client_function( - self.client.delete_quota_set, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - tenant_id="fake_tenant") diff --git a/tempest/tests/lib/services/volume/v2/test_scheduler_stats_client.py b/tempest/tests/lib/services/volume/v2/test_scheduler_stats_client.py deleted file mode 100644 index 8a5f25fd0..000000000 --- a/tempest/tests/lib/services/volume/v2/test_scheduler_stats_client.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2017 AT&T Corporation. -# 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 tempest.lib.services.volume.v2 import scheduler_stats_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSchedulerStatsClient(base.BaseServiceTest): - FAKE_POOLS_LIST = { - "pools": [ - { - "name": "pool1", - "capabilities": { - "updated": "2014-10-28T00:00:00-00:00", - "total_capacity": 1024, - "free_capacity": 100, - "volume_backend_name": "pool1", - "reserved_percentage": 0, - "driver_version": "1.0.0", - "storage_protocol": "iSCSI", - "QoS_support": False - } - }, - { - "name": "pool2", - "capabilities": { - "updated": "2014-10-28T00:00:00-00:00", - "total_capacity": 512, - "free_capacity": 200, - "volume_backend_name": "pool2", - "reserved_percentage": 0, - "driver_version": "1.0.2", - "storage_protocol": "iSER", - "QoS_support": True - } - } - ] - } - - def setUp(self): - super(TestSchedulerStatsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = scheduler_stats_client.SchedulerStatsClient( - fake_auth, 'volume', 'regionOne') - - def _test_list_pools(self, bytes_body=False, detail=False): - resp_body = [] - if detail: - resp_body = self.FAKE_POOLS_LIST - else: - resp_body = {'pools': [{'name': pool['name']} - for pool in self.FAKE_POOLS_LIST['pools']]} - self.check_service_client_function( - self.client.list_pools, - 'tempest.lib.common.rest_client.RestClient.get', - resp_body, - bytes_body, - detail=detail) - - def test_list_pools_with_str_body(self): - self._test_list_pools() - - def test_list_pools_with_str_body_and_detail(self): - self._test_list_pools(detail=True) - - def test_list_pools_with_bytes_body(self): - self._test_list_pools(bytes_body=True) - - def test_list_pools_with_bytes_body_and_detail(self): - self._test_list_pools(bytes_body=True, detail=True) diff --git a/tempest/tests/lib/services/volume/v2/test_snapshot_manage_client.py b/tempest/tests/lib/services/volume/v2/test_snapshot_manage_client.py deleted file mode 100644 index 3fe8970a8..000000000 --- a/tempest/tests/lib/services/volume/v2/test_snapshot_manage_client.py +++ /dev/null @@ -1,83 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# 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 mock - -from oslo_serialization import jsonutils as json - -from tempest.lib.services.volume.v2 import snapshot_manage_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSnapshotManageClient(base.BaseServiceTest): - - SNAPSHOT_MANAGE_REQUEST = { - "snapshot": { - "description": "snapshot-manage-description", - "metadata": None, - "ref": { - "source-name": "_snapshot-22b71da0-94f9-4aca-ad45-7522b3fa96bb" - }, - "name": "snapshot-managed", - "volume_id": "7c064b34-1e4b-40bd-93ca-4ac5a973661b" - } - } - - SNAPSHOT_MANAGE_RESPONSE = { - "snapshot": { - "status": "creating", - "description": "snapshot-manage-description", - "updated_at": None, - "volume_id": "32bafcc8-7109-42cd-8342-70d8de2bedef", - "id": "8fd6eb9d-0a82-456d-b1ec-dea4ac7f1ee2", - "size": 1, - "name": "snapshot-managed", - "created_at": "2017-07-11T10:07:58.000000", - "metadata": {} - } - } - - def setUp(self): - super(TestSnapshotManageClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = snapshot_manage_client.SnapshotManageClient(fake_auth, - 'volume', - 'regionOne') - - def _test_manage_snapshot(self, bytes_body=False): - payload = json.dumps(self.SNAPSHOT_MANAGE_REQUEST, sort_keys=True) - json_dumps = json.dumps - - # NOTE: Use sort_keys for json.dumps so that the expected and actual - # payloads are guaranteed to be identical for mock_args assert check. - with mock.patch.object(snapshot_manage_client.json, - 'dumps') as mock_dumps: - mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True) - - self.check_service_client_function( - self.client.manage_snapshot, - 'tempest.lib.common.rest_client.RestClient.post', - self.SNAPSHOT_MANAGE_RESPONSE, - to_utf=bytes_body, - status=202, - mock_args=['os-snapshot-manage', payload], - **self.SNAPSHOT_MANAGE_REQUEST['snapshot']) - - def test_manage_snapshot_with_str_body(self): - self._test_manage_snapshot() - - def test_manage_snapshot_with_bytes_body(self): - self._test_manage_snapshot(bytes_body=True) diff --git a/tempest/tests/lib/services/volume/v2/test_snapshots_client.py b/tempest/tests/lib/services/volume/v2/test_snapshots_client.py deleted file mode 100644 index c9f57a0d7..000000000 --- a/tempest/tests/lib/services/volume/v2/test_snapshots_client.py +++ /dev/null @@ -1,222 +0,0 @@ -# Copyright 2016 NEC Corporation. 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 tempest.lib.services.volume.v2 import snapshots_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestSnapshotsClient(base.BaseServiceTest): - FAKE_CREATE_SNAPSHOT = { - "snapshot": { - "display_name": "snap-001", - "display_description": "Daily backup", - "volume_id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c", - "force": True - } - } - - FAKE_UPDATE_SNAPSHOT_REQUEST = { - "metadata": { - "key": "v1" - } - } - - FAKE_INFO_SNAPSHOT = { - "snapshot": { - "id": "3fbbcccf-d058-4502-8844-6feeffdf4cb5", - "display_name": "snap-001", - "display_description": "Daily backup", - "volume_id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c", - "status": "available", - "size": 30, - "created_at": "2012-02-29T03:50:07Z" - } - } - - FAKE_LIST_SNAPSHOTS = { - "snapshots": [ - { - "id": "3fbbcccf-d058-4502-8844-6feeffdf4cb5", - "display_name": "snap-001", - "display_description": "Daily backup", - "volume_id": "521752a6-acf6-4b2d-bc7a-119f9148cd8c", - "status": "available", - "size": 30, - "created_at": "2012-02-29T03:50:07Z", - "metadata": { - "contents": "junk" - } - }, - { - "id": "e479997c-650b-40a4-9dfe-77655818b0d2", - "display_name": "snap-002", - "display_description": "Weekly backup", - "volume_id": "76b8950a-8594-4e5b-8dce-0dfa9c696358", - "status": "available", - "size": 25, - "created_at": "2012-03-19T01:52:47Z", - "metadata": {} - } - ] - } - - FAKE_SNAPSHOT_METADATA_ITEM = { - "meta": { - "key1": "value1" - } - } - - def setUp(self): - super(TestSnapshotsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = snapshots_client.SnapshotsClient(fake_auth, - 'volume', - 'regionOne') - - def _test_create_snapshot(self, bytes_body=False): - self.check_service_client_function( - self.client.create_snapshot, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_SNAPSHOT, - bytes_body, - status=202) - - def _test_show_snapshot(self, bytes_body=False): - self.check_service_client_function( - self.client.show_snapshot, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_INFO_SNAPSHOT, - bytes_body, - snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5") - - def _test_list_snapshots(self, bytes_body=False): - self.check_service_client_function( - self.client.list_snapshots, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_SNAPSHOTS, - bytes_body, - detail=True) - - def _test_create_snapshot_metadata(self, bytes_body=False): - self.check_service_client_function( - self.client.create_snapshot_metadata, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_INFO_SNAPSHOT, - bytes_body, - snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5", - metadata={"key": "v1"}) - - def _test_update_snapshot(self, bytes_body=False): - self.check_service_client_function( - self.client.update_snapshot, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_SNAPSHOT_REQUEST, - bytes_body, - snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5") - - def _test_show_snapshot_metadata(self, bytes_body=False): - self.check_service_client_function( - self.client.show_snapshot_metadata, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_UPDATE_SNAPSHOT_REQUEST, - bytes_body, - snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5") - - def _test_update_snapshot_metadata(self, bytes_body=False): - self.check_service_client_function( - self.client.update_snapshot_metadata, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_UPDATE_SNAPSHOT_REQUEST, - bytes_body, snapshot_id="cbc36478b0bd8e67e89") - - def _test_update_snapshot_metadata_item(self, bytes_body=False): - self.check_service_client_function( - self.client.update_snapshot_metadata_item, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_INFO_SNAPSHOT, - bytes_body, volume_type_id="cbc36478b0bd8e67e89") - - def _test_show_snapshot_metadata_item(self, bytes_body=False): - self.check_service_client_function( - self.client.show_snapshot_metadata_item, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SNAPSHOT_METADATA_ITEM, - bytes_body, - snapshot_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5", - id="key1") - - def test_create_snapshot_with_str_body(self): - self._test_create_snapshot() - - def test_create_snapshot_with_bytes_body(self): - self._test_create_snapshot(bytes_body=True) - - def test_show_snapshot_with_str_body(self): - self._test_show_snapshot() - - def test_show_snapshot_with_bytes_body(self): - self._test_show_snapshot(bytes_body=True) - - def test_list_snapshots_with_str_body(self): - self._test_list_snapshots() - - def test_list_snapshots_with_bytes_body(self): - self._test_list_snapshots(bytes_body=True) - - def test_create_snapshot_metadata_with_str_body(self): - self._test_create_snapshot_metadata() - - def test_create_snapshot_metadata_with_bytes_body(self): - self._test_create_snapshot_metadata(bytes_body=True) - - def test_update_snapshot_with_str_body(self): - self._test_update_snapshot() - - def test_update_snapshot_with_bytes_body(self): - self._test_update_snapshot(bytes_body=True) - - def test_show_snapshot_metadata_with_str_body(self): - self._test_show_snapshot_metadata() - - def test_show_snapshot_metadata_with_bytes_body(self): - self._test_show_snapshot_metadata(bytes_body=True) - - def test_update_snapshot_metadata_with_str_body(self): - self._test_update_snapshot_metadata() - - def test_update_snapshot_metadata_with_bytes_body(self): - self._test_update_snapshot_metadata(bytes_body=True) - - def test_show_snapshot_metadata_item_with_str_body(self): - self._test_show_snapshot_metadata_item() - - def test_show_snapshot_metadata_item_with_bytes_body(self): - self._test_show_snapshot_metadata_item(bytes_body=True) - - def test_force_delete_snapshot(self): - self.check_service_client_function( - self.client.force_delete_snapshot, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - snapshot_id="521752a6-acf6-4b2d-bc7a-119f9148cd8c", - status=202) - - def test_delete_snapshot(self): - self.check_service_client_function( - self.client.delete_snapshot, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - snapshot_id="521752a6-acf6-4b2d-bc7a-119f9148cd8c", - status=202) diff --git a/tempest/tests/lib/services/volume/v2/test_transfers_client.py b/tempest/tests/lib/services/volume/v2/test_transfers_client.py deleted file mode 100644 index 84f499283..000000000 --- a/tempest/tests/lib/services/volume/v2/test_transfers_client.py +++ /dev/null @@ -1,158 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# 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 copy - -import mock -from oslo_serialization import jsonutils as json - -from tempest.lib.services.volume.v2 import transfers_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestTransfersClient(base.BaseServiceTest): - - FAKE_VOLUME_TRANSFER_ID = "0e89cdd1-6249-421b-96d8-25fac0623d42" - - FAKE_VOLUME_TRANSFER_INFO = { - "transfer": { - "id": FAKE_VOLUME_TRANSFER_ID, - "name": "fake-volume-transfer", - "volume_id": "47bf04ef-1ea5-4c5f-a375-430a086d6747", - "created_at": "2017-04-18T09:10:03.000000", - "links": [ - { - "href": "fake-url-1", - "rel": "self" - }, - { - "href": "fake-url-2", - "rel": "bookmark" - } - ] - } - } - - def setUp(self): - super(TestTransfersClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = transfers_client.TransfersClient(fake_auth, - 'volume', - 'regionOne') - - def _test_create_volume_transfer(self, bytes_body=False): - resp_body = copy.deepcopy(self.FAKE_VOLUME_TRANSFER_INFO) - resp_body['transfer'].update({"auth_key": "fake-auth-key"}) - kwargs = {"name": "fake-volume-transfer", - "volume_id": "47bf04ef-1ea5-4c5f-a375-430a086d6747"} - payload = json.dumps({"transfer": kwargs}, sort_keys=True) - json_dumps = json.dumps - - # NOTE: Use sort_keys for json.dumps so that the expected and actual - # payloads are guaranteed to be identical for mock_args assert check. - with mock.patch.object(transfers_client.json, 'dumps') as mock_dumps: - mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True) - - self.check_service_client_function( - self.client.create_volume_transfer, - 'tempest.lib.common.rest_client.RestClient.post', - resp_body, - to_utf=bytes_body, - status=202, - mock_args=['os-volume-transfer', payload], - **kwargs) - - def _test_accept_volume_transfer(self, bytes_body=False): - resp_body = copy.deepcopy(self.FAKE_VOLUME_TRANSFER_INFO) - resp_body['transfer'].pop('created_at') - kwargs = {"auth_key": "fake-auth-key"} - payload = json.dumps({"accept": kwargs}, sort_keys=True) - json_dumps = json.dumps - - # NOTE: Use sort_keys for json.dumps so that the expected and actual - # payloads are guaranteed to be identical for mock_args assert check. - with mock.patch.object(transfers_client.json, 'dumps') as mock_dumps: - mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True) - - self.check_service_client_function( - self.client.accept_volume_transfer, - 'tempest.lib.common.rest_client.RestClient.post', - resp_body, - to_utf=bytes_body, - status=202, - mock_args=['os-volume-transfer/%s/accept' % - self.FAKE_VOLUME_TRANSFER_ID, payload], - transfer_id=self.FAKE_VOLUME_TRANSFER_ID, - **kwargs) - - def _test_show_volume_transfer(self, bytes_body=False): - resp_body = self.FAKE_VOLUME_TRANSFER_INFO - self.check_service_client_function( - self.client.show_volume_transfer, - 'tempest.lib.common.rest_client.RestClient.get', - resp_body, - to_utf=bytes_body, - transfer_id="0e89cdd1-6249-421b-96d8-25fac0623d42") - - def _test_list_volume_transfers(self, detail=False, bytes_body=False): - resp_body = copy.deepcopy(self.FAKE_VOLUME_TRANSFER_INFO) - if not detail: - resp_body['transfer'].pop('created_at') - resp_body = {"transfers": [resp_body['transfer']]} - self.check_service_client_function( - self.client.list_volume_transfers, - 'tempest.lib.common.rest_client.RestClient.get', - resp_body, - to_utf=bytes_body, - detail=detail) - - def test_create_volume_transfer_with_str_body(self): - self._test_create_volume_transfer() - - def test_create_volume_transfer_with_bytes_body(self): - self._test_create_volume_transfer(bytes_body=True) - - def test_accept_volume_transfer_with_str_body(self): - self._test_accept_volume_transfer() - - def test_accept_volume_transfer_with_bytes_body(self): - self._test_accept_volume_transfer(bytes_body=True) - - def test_show_volume_transfer_with_str_body(self): - self._test_show_volume_transfer() - - def test_show_volume_transfer_with_bytes_body(self): - self._test_show_volume_transfer(bytes_body=True) - - def test_list_volume_transfers_with_str_body(self): - self._test_list_volume_transfers() - - def test_list_volume_transfers_with_bytes_body(self): - self._test_list_volume_transfers(bytes_body=True) - - def test_list_volume_transfers_with_detail_with_str_body(self): - self._test_list_volume_transfers(detail=True) - - def test_list_volume_transfers_with_detail_with_bytes_body(self): - self._test_list_volume_transfers(detail=True, bytes_body=True) - - def test_delete_volume_transfer(self): - self.check_service_client_function( - self.client.delete_volume_transfer, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - status=202, - transfer_id="0e89cdd1-6249-421b-96d8-25fac0623d42") diff --git a/tempest/tests/lib/services/volume/v2/test_volume_manage_client.py b/tempest/tests/lib/services/volume/v2/test_volume_manage_client.py deleted file mode 100644 index ea4a9f996..000000000 --- a/tempest/tests/lib/services/volume/v2/test_volume_manage_client.py +++ /dev/null @@ -1,111 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# 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 mock - -from oslo_serialization import jsonutils as json - -from tempest.lib.services.volume.v2 import volume_manage_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestVolumeManageClient(base.BaseServiceTest): - - VOLUME_MANAGE_REQUEST = { - "volume": { - "host": "controller1@rbd#rbd", - "name": "volume-managed", - "availability_zone": "nova", - "bootable": False, - "metadata": None, - "ref": { - "source-name": "volume-2ce6ca46-e6c1-4fe5-8268-3a1c536fcbf3" - }, - "volume_type": None, - "description": "volume-manage-description" - } - } - - VOLUME_MANAGE_RESPONSE = { - "volume": { - "migration_status": None, - "attachments": [], - "links": [ - { - "href": "fake-url-1", - "rel": "self" - }, - { - "href": "fake-url-2", - "rel": "bookmark" - } - ], - "availability_zone": "nova", - "os-vol-host-attr:host": "controller1@rbd#rbd", - "encrypted": False, - "updated_at": None, - "replication_status": None, - "snapshot_id": None, - "id": "c07cd4a4-b52b-4511-a176-fbaa2011a227", - "size": 0, - "user_id": "142d8663efce464c89811c63e45bd82e", - "os-vol-tenant-attr:tenant_id": "f21a9c86d7114bf99c711f4874d80474", - "os-vol-mig-status-attr:migstat": None, - "metadata": {}, - "status": "creating", - "description": "volume-manage-description", - "multiattach": False, - "source_volid": None, - "consistencygroup_id": None, - "os-vol-mig-status-attr:name_id": None, - "name": "volume-managed", - "bootable": "false", - "created_at": "2017-07-11T09:14:01.000000", - "volume_type": None - } - } - - def setUp(self): - super(TestVolumeManageClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = volume_manage_client.VolumeManageClient(fake_auth, - 'volume', - 'regionOne') - - def _test_manage_volume(self, bytes_body=False): - payload = json.dumps(self.VOLUME_MANAGE_REQUEST, sort_keys=True) - json_dumps = json.dumps - - # NOTE: Use sort_keys for json.dumps so that the expected and actual - # payloads are guaranteed to be identical for mock_args assert check. - with mock.patch.object(volume_manage_client.json, - 'dumps') as mock_dumps: - mock_dumps.side_effect = lambda d: json_dumps(d, sort_keys=True) - - self.check_service_client_function( - self.client.manage_volume, - 'tempest.lib.common.rest_client.RestClient.post', - self.VOLUME_MANAGE_RESPONSE, - to_utf=bytes_body, - status=202, - mock_args=['os-volume-manage', payload], - **self.VOLUME_MANAGE_REQUEST['volume']) - - def test_manage_volume_with_str_body(self): - self._test_manage_volume() - - def test_manage_volume_with_bytes_body(self): - self._test_manage_volume(bytes_body=True) diff --git a/tempest/tests/lib/services/volume/v2/test_volumes_client.py b/tempest/tests/lib/services/volume/v2/test_volumes_client.py deleted file mode 100644 index e53e0a2a8..000000000 --- a/tempest/tests/lib/services/volume/v2/test_volumes_client.py +++ /dev/null @@ -1,95 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# 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 tempest.lib.services.volume.v2 import volumes_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestVolumesClient(base.BaseServiceTest): - - FAKE_VOLUME_METADATA_ITEM = { - "meta": { - "key1": "value1" - } - } - - def setUp(self): - super(TestVolumesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = volumes_client.VolumesClient(fake_auth, - 'volume', - 'regionOne') - - def _test_retype_volume(self, bytes_body=False): - kwargs = { - "new_type": "dedup-tier-replication", - "migration_policy": "never" - } - - self.check_service_client_function( - self.client.retype_volume, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - to_utf=bytes_body, - status=202, - volume_id="a3be971b-8de5-4bdf-bdb8-3d8eb0fb69f8", - **kwargs - ) - - def _test_force_detach_volume(self, bytes_body=False): - kwargs = { - 'attachment_id': '6980e295-920f-412e-b189-05c50d605acd', - 'connector': { - 'initiator': 'iqn.2017-04.org.fake:01' - } - } - - self.check_service_client_function( - self.client.force_detach_volume, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - to_utf=bytes_body, - status=202, - volume_id="a3be971b-8de5-4bdf-bdb8-3d8eb0fb69f8", - **kwargs - ) - - def _test_show_volume_metadata_item(self, bytes_body=False): - self.check_service_client_function( - self.client.show_volume_metadata_item, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_VOLUME_METADATA_ITEM, - to_utf=bytes_body, - volume_id="a3be971b-8de5-4bdf-bdb8-3d8eb0fb69f8", - id="key1") - - def test_force_detach_volume_with_str_body(self): - self._test_force_detach_volume() - - def test_force_detach_volume_with_bytes_body(self): - self._test_force_detach_volume(bytes_body=True) - - def test_show_volume_metadata_item_with_str_body(self): - self._test_show_volume_metadata_item() - - def test_show_volume_metadata_item_with_bytes_body(self): - self._test_show_volume_metadata_item(bytes_body=True) - - def test_retype_volume_with_str_body(self): - self._test_retype_volume() - - def test_retype_volume_with_bytes_body(self): - self._test_retype_volume(bytes_body=True) diff --git a/tempest/tests/lib/services/volume/v3/__init__.py b/tempest/tests/lib/services/volume/v3/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/lib/services/volume/v3/test_backups_client.py b/tempest/tests/lib/services/volume/v3/test_backups_client.py deleted file mode 100644 index f1ce98797..000000000 --- a/tempest/tests/lib/services/volume/v3/test_backups_client.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# 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 tempest.lib.services.volume.v3 import backups_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestBackupsClient(base.BaseServiceTest): - - FAKE_BACKUP_UPDATE = { - "backup": { - "id": "4c65c15f-a5c5-464b-b92a-90e4c04636a7", - "name": "fake-backup-name", - "links": "fake-links" - } - } - - def setUp(self): - super(TestBackupsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = backups_client.BackupsClient(fake_auth, - 'volume', - 'regionOne') - - def _test_update_backup(self, bytes_body=False): - self.check_service_client_function( - self.client.update_backup, - 'tempest.lib.common.rest_client.RestClient.put', - self.FAKE_BACKUP_UPDATE, - bytes_body, - backup_id='4c65c15f-a5c5-464b-b92a-90e4c04636a7') - - def test_update_backup_with_str_body(self): - self._test_update_backup() - - def test_update_backup_with_bytes_body(self): - self._test_update_backup(bytes_body=True) diff --git a/tempest/tests/lib/services/volume/v3/test_group_types_client.py b/tempest/tests/lib/services/volume/v3/test_group_types_client.py deleted file mode 100644 index 0f456a26b..000000000 --- a/tempest/tests/lib/services/volume/v3/test_group_types_client.py +++ /dev/null @@ -1,124 +0,0 @@ -# Copyright (C) 2017 Dell Inc. or its subsidiaries. -# -# 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 tempest.lib.services.volume.v3 import group_types_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestGroupTypesClient(base.BaseServiceTest): - FAKE_CREATE_GROUP_TYPE = { - "group_type": { - "name": "group-type-001", - "description": "Test group type 1", - "group_specs": {}, - "is_public": True, - } - } - - FAKE_INFO_GROUP_TYPE = { - "group_type": { - "id": "0e701ab8-1bec-4b9f-b026-a7ba4af13578", - "name": "group-type-001", - "description": "Test group type 1", - "is_public": True, - "created_at": "20127-06-20T03:50:07Z", - "group_specs": {}, - } - } - - FAKE_LIST_GROUP_TYPES = { - "group_types": [ - { - "id": "0e701ab8-1bec-4b9f-b026-a7ba4af13578", - "name": "group-type-001", - "description": "Test group type 1", - "is_public": True, - "created_at": "2017-06-20T03:50:07Z", - "group_specs": {}, - }, - { - "id": "e479997c-650b-40a4-9dfe-77655818b0d2", - "name": "group-type-002", - "description": "Test group type 2", - "is_public": True, - "created_at": "2017-06-19T01:52:47Z", - "group_specs": {}, - }, - { - "id": "c5c4769e-213c-40a6-a568-8e797bb691d4", - "name": "group-type-003", - "description": "Test group type 3", - "is_public": True, - "created_at": "2017-06-18T06:34:32Z", - "group_specs": {}, - } - ] - } - - def setUp(self): - super(TestGroupTypesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = group_types_client.GroupTypesClient(fake_auth, - 'volume', - 'regionOne') - - def _test_create_group_type(self, bytes_body=False): - self.check_service_client_function( - self.client.create_group_type, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_GROUP_TYPE, - bytes_body, - status=202) - - def _test_show_group_type(self, bytes_body=False): - self.check_service_client_function( - self.client.show_group_type, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_INFO_GROUP_TYPE, - bytes_body, - group_type_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5") - - def _test_list_group_types(self, bytes_body=False): - self.check_service_client_function( - self.client.list_group_types, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_GROUP_TYPES, - bytes_body) - - def test_create_group_type_with_str_body(self): - self._test_create_group_type() - - def test_create_group_type_with_bytes_body(self): - self._test_create_group_type(bytes_body=True) - - def test_delete_group_type(self): - self.check_service_client_function( - self.client.delete_group_type, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - group_type_id='0e58433f-d108-4bf3-a22c-34e6b71ef86b', - status=202) - - def test_show_group_type_with_str_body(self): - self._test_show_group_type() - - def test_show_group_type_with_bytes_body(self): - self._test_show_group_type(bytes_body=True) - - def test_list_group_types_with_str_body(self): - self._test_list_group_types() - - def test_list_group_types_with_bytes_body(self): - self._test_list_group_types(bytes_body=True) diff --git a/tempest/tests/lib/services/volume/v3/test_groups_client.py b/tempest/tests/lib/services/volume/v3/test_groups_client.py deleted file mode 100644 index 00db5b46a..000000000 --- a/tempest/tests/lib/services/volume/v3/test_groups_client.py +++ /dev/null @@ -1,136 +0,0 @@ -# Copyright (C) 2017 Dell Inc. or its subsidiaries. -# -# 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 tempest.lib.services.volume.v3 import groups_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestGroupsClient(base.BaseServiceTest): - FAKE_CREATE_GROUP = { - "group": { - "name": "group-001", - "description": "Test group 1", - "group_type": "0e58433f-d108-4bf3-a22c-34e6b71ef86b", - "volume_types": ["2103099d-7cc3-4e52-a2f1-23a5284416f3"], - "availability_zone": "az1", - } - } - - FAKE_INFO_GROUP = { - "group": { - "id": "0e701ab8-1bec-4b9f-b026-a7ba4af13578", - "name": "group-001", - "description": "Test group 1", - "group_type": "0e58433f-d108-4bf3-a22c-34e6b71ef86b", - "volume_types": ["2103099d-7cc3-4e52-a2f1-23a5284416f3"], - "status": "available", - "availability_zone": "az1", - "created_at": "20127-06-20T03:50:07Z" - } - } - - FAKE_LIST_GROUPS = { - "groups": [ - { - "id": "0e701ab8-1bec-4b9f-b026-a7ba4af13578", - "name": "group-001", - "description": "Test group 1", - "group_type": "0e58433f-d108-4bf3-a22c-34e6b71ef86b", - "volume_types": ["2103099d-7cc3-4e52-a2f1-23a5284416f3"], - "status": "available", - "availability_zone": "az1", - "created_at": "2017-06-20T03:50:07Z", - }, - { - "id": "e479997c-650b-40a4-9dfe-77655818b0d2", - "name": "group-002", - "description": "Test group 2", - "group_snapshot_id": "79c9afdb-7e46-4d71-9249-1f022886963c", - "group_type": "0e58433f-d108-4bf3-a22c-34e6b71ef86b", - "volume_types": ["2103099d-7cc3-4e52-a2f1-23a5284416f3"], - "status": "available", - "availability_zone": "az1", - "created_at": "2017-06-19T01:52:47Z", - }, - { - "id": "c5c4769e-213c-40a6-a568-8e797bb691d4", - "name": "group-003", - "description": "Test group 3", - "source_group_id": "e92f9dc7-0b20-492d-8ab2-3ad8fdac270e", - "group_type": "0e58433f-d108-4bf3-a22c-34e6b71ef86b", - "volume_types": ["2103099d-7cc3-4e52-a2f1-23a5284416f3"], - "status": "available", - "availability_zone": "az1", - "created_at": "2017-06-18T06:34:32Z", - } - ] - } - - def setUp(self): - super(TestGroupsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = groups_client.GroupsClient(fake_auth, - 'volume', - 'regionOne') - - def _test_create_group(self, bytes_body=False): - self.check_service_client_function( - self.client.create_group, - 'tempest.lib.common.rest_client.RestClient.post', - self.FAKE_CREATE_GROUP, - bytes_body, - status=202) - - def _test_show_group(self, bytes_body=False): - self.check_service_client_function( - self.client.show_group, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_INFO_GROUP, - bytes_body, - group_id="3fbbcccf-d058-4502-8844-6feeffdf4cb5") - - def _test_list_groups(self, bytes_body=False): - self.check_service_client_function( - self.client.list_groups, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_GROUPS, - bytes_body, - detail=True) - - def test_create_group_with_str_body(self): - self._test_create_group() - - def test_create_group_with_bytes_body(self): - self._test_create_group(bytes_body=True) - - def test_show_group_with_str_body(self): - self._test_show_group() - - def test_show_group_with_bytes_body(self): - self._test_show_group(bytes_body=True) - - def test_list_groups_with_str_body(self): - self._test_list_groups() - - def test_list_groups_with_bytes_body(self): - self._test_list_groups(bytes_body=True) - - def test_delete_group(self): - self.check_service_client_function( - self.client.delete_group, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - group_id='0e701ab8-1bec-4b9f-b026-a7ba4af13578', - status=202) diff --git a/tempest/tests/lib/services/volume/v3/test_user_messages_client.py b/tempest/tests/lib/services/volume/v3/test_user_messages_client.py deleted file mode 100644 index 4aeed5f43..000000000 --- a/tempest/tests/lib/services/volume/v3/test_user_messages_client.py +++ /dev/null @@ -1,92 +0,0 @@ -# Copyright 2016 Red Hat. 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 tempest.lib.services.volume.v3 import messages_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestUserMessagesClient(base.BaseServiceTest): - USER_MESSAGE_INFO = { - "created_at": "2016-11-21T06:16:34.000000", - "guaranteed_until": "2016-12-21T06:16:34.000000", - "user_message": "No storage could be allocated for this volume " - "request. You may be able to try another size or" - " volume type.", - "resource_uuid": "c570b406-bf0b-4067-9398-f0bb09a7d9d7", - "request_id": "req-8f68681e-9b6b-4009-b94c-ac0811595451", - "message_level": "ERROR", - "id": "9a7dafbd-a156-4540-8996-50e71b5dcadf", - "resource_type": "VOLUME", - "links": [ - {"href": "http://192.168.100.230:8776/v3/" - "a678cb65f701462ea2257245cd640829/messages/" - "9a7dafbd-a156-4540-8996-50e71b5dcadf", - "rel": "self"}, - {"href": "http://192.168.100.230:8776/" - "a678cb65f701462ea2257245cd640829/messages/" - "9a7dafbd-a156-4540-8996-50e71b5dcadf", - "rel": "bookmark"}] - } - FAKE_SHOW_USER_MESSAGE = { - "message": dict(event_id="000002", **USER_MESSAGE_INFO)} - - FAKE_LIST_USER_MESSAGES = { - "messages": [ - dict(event_id="000003", **USER_MESSAGE_INFO), - dict(event_id="000004", **USER_MESSAGE_INFO) - ] - } - - def setUp(self): - super(TestUserMessagesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = messages_client.MessagesClient(fake_auth, - 'volume', - 'regionOne') - - def _test_show_user_message(self, bytes_body=False): - self.check_service_client_function( - self.client.show_message, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_SHOW_USER_MESSAGE, - bytes_body, - message_id="9a7dafbd-a156-4540-8996-50e71b5dcadf") - - def _test_list_user_message(self, bytes_body=False): - self.check_service_client_function( - self.client.list_messages, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_LIST_USER_MESSAGES, - bytes_body) - - def test_list_user_message_with_str_body(self): - self._test_list_user_message() - - def test_list_user_message_with_bytes_body(self): - self._test_list_user_message(bytes_body=True) - - def test_show_user_message_with_str_body(self): - self._test_show_user_message() - - def test_show_user_message_with_bytes_body(self): - self._test_show_user_message(bytes_body=True) - - def test_delete_user_message(self): - self.check_service_client_function( - self.client.delete_message, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - message_id="9a7dafbd-a156-4540-8996-50e71b5dcadf", - status=204) diff --git a/tempest/tests/lib/services/volume/v3/test_versions_client.py b/tempest/tests/lib/services/volume/v3/test_versions_client.py deleted file mode 100644 index 9627b9a2b..000000000 --- a/tempest/tests/lib/services/volume/v3/test_versions_client.py +++ /dev/null @@ -1,91 +0,0 @@ -# Copyright 2017 NEC Corporation. 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 tempest.lib.services.volume.v3 import versions_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestVersionsClient(base.BaseServiceTest): - - FAKE_VERSIONS_INFO = { - "versions": [ - { - "status": "DEPRECATED", "updated": "2016-05-02T20:25:19Z", - "links": [ - {"href": "http://docs.openstack.org/", "type": "text/html", - "rel": "describedby"}, - {"href": "https://10.30.197.39:8776/v1/", "rel": "self"} - ], - "min_version": "", - "version": "", - "media-types": [ - {"base": "application/json", - "type": "application/vnd.openstack.volume+json;version=1"} - ], - "id": "v1.0" - }, - { - "status": "DEPRECATED", "updated": "2017-02-25T12:00:00Z", - "links": [ - {"href": "http://docs.openstack.org/", "type": "text/html", - "rel": "describedby"}, - {"href": "https://10.30.197.39:8776/v2/", "rel": "self"} - ], - "min_version": "", - "version": "", - "media-types": [ - {"base": "application/json", - "type": "application/vnd.openstack.volume+json;version=1"} - ], - "id": "v2.0" - }, - { - "status": "CURRENT", "updated": "2016-02-08T12:20:21Z", - "links": [ - {"href": "http://docs.openstack.org/", "type": "text/html", - "rel": "describedby"}, - {"href": "https://10.30.197.39:8776/v3/", "rel": "self"} - ], - "min_version": "3.0", - "version": "3.28", - "media-types": [ - {"base": "application/json", - "type": "application/vnd.openstack.volume+json;version=1"} - ], - "id": "v3.0" - } - ] - } - - def setUp(self): - super(TestVersionsClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = versions_client.VersionsClient(fake_auth, - 'volume', - 'regionOne') - - def _test_list_versions(self, bytes_body=False): - self.check_service_client_function( - self.client.list_versions, - 'tempest.lib.common.rest_client.RestClient.raw_request', - self.FAKE_VERSIONS_INFO, - bytes_body, - 300) - - def test_list_versions_with_str_body(self): - self._test_list_versions() - - def test_list_versions_with_bytes_body(self): - self._test_list_versions(bytes_body=True) diff --git a/tempest/tests/lib/services/volume/v3/test_volumes_client.py b/tempest/tests/lib/services/volume/v3/test_volumes_client.py deleted file mode 100644 index a515fd34a..000000000 --- a/tempest/tests/lib/services/volume/v3/test_volumes_client.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2017 FiberHome Telecommunication Technologies CO.,LTD -# 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 tempest.lib.services.volume.v3 import volumes_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestVolumesClient(base.BaseServiceTest): - - FAKE_VOLUME_SUMMARY = { - "volume-summary": { - "total_size": 20, - "total_count": 5 - } - } - - def setUp(self): - super(TestVolumesClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = volumes_client.VolumesClient(fake_auth, - 'volume', - 'regionOne') - - def _test_show_volume_summary(self, bytes_body=False): - self.check_service_client_function( - self.client.show_volume_summary, - 'tempest.lib.common.rest_client.RestClient.get', - self.FAKE_VOLUME_SUMMARY, - bytes_body) - - def test_show_volume_summary_with_str_body(self): - self._test_show_volume_summary() - - def test_show_volume_summary_with_bytes_body(self): - self._test_show_volume_summary(bytes_body=True) diff --git a/tempest/tests/lib/test_auth.py b/tempest/tests/lib/test_auth.py deleted file mode 100644 index c3a792f41..000000000 --- a/tempest/tests/lib/test_auth.py +++ /dev/null @@ -1,915 +0,0 @@ -# Copyright 2014 IBM 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 copy -import datetime - -import fixtures -import testtools - -from tempest.lib import auth -from tempest.lib import exceptions -from tempest.lib.services.identity.v2 import token_client as v2_client -from tempest.lib.services.identity.v3 import token_client as v3_client -from tempest.tests import base -from tempest.tests.lib import fake_credentials -from tempest.tests.lib import fake_identity - - -def fake_get_credentials(fill_in=True, identity_version='v2', **kwargs): - return fake_credentials.FakeCredentials() - - -class BaseAuthTestsSetUp(base.TestCase): - _auth_provider_class = None - credentials = fake_credentials.FakeCredentials() - - def _auth(self, credentials, auth_url, **params): - """returns auth method according to keystone""" - return self._auth_provider_class(credentials, auth_url, **params) - - def setUp(self): - super(BaseAuthTestsSetUp, self).setUp() - self.patchobject(auth, 'get_credentials', fake_get_credentials) - self.auth_provider = self._auth(self.credentials, - fake_identity.FAKE_AUTH_URL) - - -class TestBaseAuthProvider(BaseAuthTestsSetUp): - """Tests for base AuthProvider - - This tests auth.AuthProvider class which is base for the other so we - obviously don't test not implemented method or the ones which strongly - depends on them. - """ - - class FakeAuthProviderImpl(auth.AuthProvider): - def _decorate_request(self): - pass - - def _fill_credentials(self): - pass - - def _get_auth(self): - pass - - def base_url(self): - pass - - def is_expired(self): - pass - - _auth_provider_class = FakeAuthProviderImpl - - def _auth(self, credentials, auth_url, **params): - """returns auth method according to keystone""" - return self._auth_provider_class(credentials, **params) - - def test_check_credentials_bad_type(self): - self.assertFalse(self.auth_provider.check_credentials([])) - - def test_auth_data_property_when_cache_exists(self): - self.auth_provider.cache = 'foo' - self.useFixture(fixtures.MockPatchObject(self.auth_provider, - 'is_expired', - return_value=False)) - self.assertEqual('foo', getattr(self.auth_provider, 'auth_data')) - - def test_delete_auth_data_property_through_deleter(self): - self.auth_provider.cache = 'foo' - del self.auth_provider.auth_data - self.assertIsNone(self.auth_provider.cache) - - def test_delete_auth_data_property_through_clear_auth(self): - self.auth_provider.cache = 'foo' - self.auth_provider.clear_auth() - self.assertIsNone(self.auth_provider.cache) - - def test_set_and_reset_alt_auth_data(self): - self.auth_provider.set_alt_auth_data('foo', 'bar') - self.assertEqual(self.auth_provider.alt_part, 'foo') - self.assertEqual(self.auth_provider.alt_auth_data, 'bar') - - self.auth_provider.reset_alt_auth_data() - self.assertIsNone(self.auth_provider.alt_part) - self.assertIsNone(self.auth_provider.alt_auth_data) - - def test_auth_class(self): - self.assertRaises(TypeError, - auth.AuthProvider, - fake_credentials.FakeCredentials) - - -class TestKeystoneV2AuthProvider(BaseAuthTestsSetUp): - _endpoints = fake_identity.IDENTITY_V2_RESPONSE['access']['serviceCatalog'] - _auth_provider_class = auth.KeystoneV2AuthProvider - credentials = fake_credentials.FakeKeystoneV2Credentials() - - def setUp(self): - super(TestKeystoneV2AuthProvider, self).setUp() - self.patchobject(v2_client.TokenClient, 'raw_request', - fake_identity._fake_v2_response) - self.target_url = 'test_api' - - def _get_fake_identity(self): - return fake_identity.IDENTITY_V2_RESPONSE['access'] - - def _get_fake_alt_identity(self): - return fake_identity.ALT_IDENTITY_V2_RESPONSE['access'] - - def _get_result_url_from_endpoint(self, ep, endpoint_type='publicURL', - replacement=None): - if replacement: - return ep[endpoint_type].replace('v2', replacement) - return ep[endpoint_type] - - def _get_token_from_fake_identity(self): - return fake_identity.TOKEN - - def _get_from_fake_identity(self, attr): - access = fake_identity.IDENTITY_V2_RESPONSE['access'] - if attr == 'user_id': - return access['user']['id'] - elif attr == 'tenant_id': - return access['token']['tenant']['id'] - - def _test_request_helper(self, filters, expected): - url, headers, body = self.auth_provider.auth_request('GET', - self.target_url, - filters=filters) - - self.assertEqual(expected['url'], url) - self.assertEqual(expected['token'], headers['X-Auth-Token']) - self.assertEqual(expected['body'], body) - - def _auth_data_with_expiry(self, date_as_string): - token, access = self.auth_provider.auth_data - access['token']['expires'] = date_as_string - return token, access - - def test_request(self): - filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion' - } - - url = self._get_result_url_from_endpoint( - self._endpoints[0]['endpoints'][1]) + '/' + self.target_url - - expected = { - 'body': None, - 'url': url, - 'token': self._get_token_from_fake_identity(), - } - self._test_request_helper(filters, expected) - - def test_request_with_alt_auth_cleans_alt(self): - """Test alternate auth data for headers - - Assert that when the alt data is provided for headers, after an - auth_request the data alt_data is cleaned-up. - """ - self.auth_provider.set_alt_auth_data( - 'headers', - (fake_identity.ALT_TOKEN, self._get_fake_alt_identity())) - filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'fakeRegion' - } - self.auth_provider.auth_request('GET', self.target_url, - filters=filters) - - # Assert alt auth data is clear after it - self.assertIsNone(self.auth_provider.alt_part) - self.assertIsNone(self.auth_provider.alt_auth_data) - - def _test_request_with_identical_alt_auth(self, part): - """Test alternate but identical auth data for headers - - Assert that when the alt data is provided, but it's actually - identical, an exception is raised. - """ - self.auth_provider.set_alt_auth_data( - part, - (fake_identity.TOKEN, self._get_fake_identity())) - filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'fakeRegion' - } - - self.assertRaises(exceptions.BadAltAuth, - self.auth_provider.auth_request, - 'GET', self.target_url, filters=filters) - - def test_request_with_identical_alt_auth_headers(self): - self._test_request_with_identical_alt_auth('headers') - - def test_request_with_identical_alt_auth_url(self): - self._test_request_with_identical_alt_auth('url') - - def test_request_with_identical_alt_auth_body(self): - self._test_request_with_identical_alt_auth('body') - - def test_request_with_alt_part_without_alt_data(self): - """Test empty alternate auth data - - Assert that when alt_part is defined, the corresponding original - request element is kept the same. - """ - filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'fakeRegion' - } - self.auth_provider.set_alt_auth_data('headers', None) - - url, headers, body = self.auth_provider.auth_request('GET', - self.target_url, - filters=filters) - # The original headers where empty - self.assertNotEqual(url, self.target_url) - self.assertIsNone(headers) - self.assertIsNone(body) - - def _test_request_with_alt_part_without_alt_data_no_change(self, body): - """Test empty alternate auth data with no effect - - Assert that when alt_part is defined, no auth_data is provided, - and the corresponding original request element was not going to - be changed anyways, and exception is raised - """ - filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'fakeRegion' - } - self.auth_provider.set_alt_auth_data('body', None) - - self.assertRaises(exceptions.BadAltAuth, - self.auth_provider.auth_request, - 'GET', self.target_url, filters=filters) - - def test_request_with_alt_part_without_alt_data_no_change_headers(self): - self._test_request_with_alt_part_without_alt_data_no_change('headers') - - def test_request_with_alt_part_without_alt_data_no_change_url(self): - self._test_request_with_alt_part_without_alt_data_no_change('url') - - def test_request_with_alt_part_without_alt_data_no_change_body(self): - self._test_request_with_alt_part_without_alt_data_no_change('body') - - def test_request_with_bad_service(self): - filters = { - 'service': 'BAD_SERVICE', - 'endpoint_type': 'publicURL', - 'region': 'fakeRegion' - } - self.assertRaises(exceptions.EndpointNotFound, - self.auth_provider.auth_request, 'GET', - self.target_url, filters=filters) - - def test_request_without_service(self): - filters = { - 'service': None, - 'endpoint_type': 'publicURL', - 'region': 'fakeRegion' - } - self.assertRaises(exceptions.EndpointNotFound, - self.auth_provider.auth_request, 'GET', - self.target_url, filters=filters) - - def test_check_credentials_missing_attribute(self): - for attr in ['username', 'password']: - cred = copy.copy(self.credentials) - del cred[attr] - self.assertFalse(self.auth_provider.check_credentials(cred)) - - def test_fill_credentials(self): - self.auth_provider.fill_credentials() - creds = self.auth_provider.credentials - for attr in ['user_id', 'tenant_id']: - self.assertEqual(self._get_from_fake_identity(attr), - getattr(creds, attr)) - - def _test_base_url_helper(self, expected_url, filters, - auth_data=None): - - url = self.auth_provider.base_url(filters, auth_data) - self.assertEqual(url, expected_url) - - def test_base_url(self): - self.filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion' - } - expected = self._get_result_url_from_endpoint( - self._endpoints[0]['endpoints'][1]) - self._test_base_url_helper(expected, self.filters) - - def test_base_url_to_get_admin_endpoint(self): - self.filters = { - 'service': 'compute', - 'endpoint_type': 'adminURL', - 'region': 'FakeRegion' - } - expected = self._get_result_url_from_endpoint( - self._endpoints[0]['endpoints'][1], endpoint_type='adminURL') - self._test_base_url_helper(expected, self.filters) - - def test_base_url_unknown_region(self): - """If the region is unknown, the first endpoint is returned.""" - self.filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'AintNoBodyKnowThisRegion' - } - expected = self._get_result_url_from_endpoint( - self._endpoints[0]['endpoints'][0]) - self._test_base_url_helper(expected, self.filters) - - def test_base_url_with_non_existent_service(self): - self.filters = { - 'service': 'BAD_SERVICE', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion' - } - self.assertRaises(exceptions.EndpointNotFound, - self._test_base_url_helper, None, self.filters) - - def test_base_url_without_service(self): - self.filters = { - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion' - } - self.assertRaises(exceptions.EndpointNotFound, - self._test_base_url_helper, None, self.filters) - - def test_base_url_with_known_name(self): - """If name and service is known, return the endpoint.""" - self.filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion', - 'name': 'nova' - } - expected = self._get_result_url_from_endpoint( - self._endpoints[0]['endpoints'][1]) - self._test_base_url_helper(expected, self.filters) - - def test_base_url_with_known_name_and_unknown_servce(self): - """Test with Known Name and Unknown service - - If the name is known but the service is unknown, raise an exception. - """ - self.filters = { - 'service': 'AintNoBodyKnowThatService', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion', - 'name': 'AintNoBodyKnowThatName' - } - self.assertRaises(exceptions.EndpointNotFound, - self._test_base_url_helper, None, self.filters) - - def test_base_url_with_unknown_name_and_known_service(self): - """Test with Unknown Name and Known Service - - If the name is unknown, raise an exception. Note that filtering by - name is only successful service exists. - """ - - self.filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion', - 'name': 'AintNoBodyKnowThatName' - } - self.assertRaises(exceptions.EndpointNotFound, - self._test_base_url_helper, None, self.filters) - - def test_base_url_without_name(self): - self.filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion', - } - expected = self._get_result_url_from_endpoint( - self._endpoints[0]['endpoints'][1]) - self._test_base_url_helper(expected, self.filters) - - def test_base_url_with_api_version_filter(self): - self.filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion', - 'api_version': 'v12' - } - expected = self._get_result_url_from_endpoint( - self._endpoints[0]['endpoints'][1], replacement='v12') - self._test_base_url_helper(expected, self.filters) - - def test_base_url_with_skip_path_filter(self): - self.filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion', - 'skip_path': True - } - expected = 'http://fake_url/' - self._test_base_url_helper(expected, self.filters) - - def test_base_url_with_unversioned_endpoint(self): - auth_data = { - 'serviceCatalog': [ - { - 'type': 'identity', - 'endpoints': [ - { - 'region': 'FakeRegion', - 'publicURL': 'http://fake_url' - } - ] - } - ] - } - - filters = { - 'service': 'identity', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion', - 'api_version': 'v2.0' - } - - expected = 'http://fake_url/v2.0' - self._test_base_url_helper(expected, filters, ('token', auth_data)) - - def test_base_url_with_extra_path_endpoint(self): - auth_data = { - 'serviceCatalog': [ - { - 'type': 'compute', - 'endpoints': [ - { - 'region': 'FakeRegion', - 'publicURL': 'http://fake_url/some_path/v2.0' - } - ] - } - ] - } - - filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion', - 'api_version': 'v2.0' - } - - expected = 'http://fake_url/some_path/v2.0' - self._test_base_url_helper(expected, filters, ('token', auth_data)) - - def test_base_url_with_unversioned_extra_path_endpoint(self): - auth_data = { - 'serviceCatalog': [ - { - 'type': 'compute', - 'endpoints': [ - { - 'region': 'FakeRegion', - 'publicURL': 'http://fake_url/some_path' - } - ] - } - ] - } - - filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion', - 'api_version': 'v2.0' - } - - expected = 'http://fake_url/some_path/v2.0' - self._test_base_url_helper(expected, filters, ('token', auth_data)) - - def test_token_not_expired(self): - expiry_data = datetime.datetime.utcnow() + datetime.timedelta(days=1) - self._verify_expiry(expiry_data=expiry_data, should_be_expired=False) - - def test_token_expired(self): - expiry_data = datetime.datetime.utcnow() - datetime.timedelta(hours=1) - self._verify_expiry(expiry_data=expiry_data, should_be_expired=True) - - def test_token_not_expired_to_be_renewed(self): - expiry_data = (datetime.datetime.utcnow() + - self.auth_provider.token_expiry_threshold / 2) - self._verify_expiry(expiry_data=expiry_data, should_be_expired=True) - - def _verify_expiry(self, expiry_data, should_be_expired): - for expiry_format in self.auth_provider.EXPIRY_DATE_FORMATS: - auth_data = self._auth_data_with_expiry( - expiry_data.strftime(expiry_format)) - self.assertEqual(self.auth_provider.is_expired(auth_data), - should_be_expired) - - def test_set_scope_all_valid(self): - for scope in self.auth_provider.SCOPES: - self.auth_provider.scope = scope - self.assertEqual(scope, self.auth_provider.scope) - - def test_set_scope_invalid(self): - with testtools.ExpectedException(exceptions.InvalidScope, - '.* invalid_scope .*'): - self.auth_provider.scope = 'invalid_scope' - - -class TestKeystoneV3AuthProvider(TestKeystoneV2AuthProvider): - _endpoints = fake_identity.IDENTITY_V3_RESPONSE['token']['catalog'] - _auth_provider_class = auth.KeystoneV3AuthProvider - credentials = fake_credentials.FakeKeystoneV3Credentials() - - def setUp(self): - super(TestKeystoneV3AuthProvider, self).setUp() - self.patchobject(v3_client.V3TokenClient, 'raw_request', - fake_identity._fake_v3_response) - - def _get_fake_identity(self): - return fake_identity.IDENTITY_V3_RESPONSE['token'] - - def _get_fake_alt_identity(self): - return fake_identity.ALT_IDENTITY_V3['token'] - - def _get_result_url_from_endpoint(self, ep, replacement=None): - if replacement: - return ep['url'].replace('v3', replacement) - return ep['url'] - - def _auth_data_with_expiry(self, date_as_string): - token, access = self.auth_provider.auth_data - access['expires_at'] = date_as_string - return token, access - - def _get_from_fake_identity(self, attr): - token = fake_identity.IDENTITY_V3_RESPONSE['token'] - if attr == 'user_id': - return token['user']['id'] - elif attr == 'project_id': - return token['project']['id'] - elif attr == 'user_domain_id': - return token['user']['domain']['id'] - elif attr == 'project_domain_id': - return token['project']['domain']['id'] - - def test_check_credentials_missing_attribute(self): - # reset credentials to fresh ones - self.credentials.reset() - for attr in ['username', 'password', 'user_domain_name', - 'project_domain_name']: - cred = copy.copy(self.credentials) - del cred[attr] - self.assertFalse(self.auth_provider.check_credentials(cred), - "Credentials should be invalid without %s" % attr) - - def test_check_domain_credentials_missing_attribute(self): - # reset credentials to fresh ones - self.credentials.reset() - domain_creds = fake_credentials.FakeKeystoneV3DomainCredentials() - for attr in ['username', 'password', 'user_domain_name']: - cred = copy.copy(domain_creds) - del cred[attr] - self.assertFalse(self.auth_provider.check_credentials(cred), - "Credentials should be invalid without %s" % attr) - - def test_fill_credentials(self): - self.auth_provider.fill_credentials() - creds = self.auth_provider.credentials - for attr in ['user_id', 'project_id', 'user_domain_id', - 'project_domain_id']: - self.assertEqual(self._get_from_fake_identity(attr), - getattr(creds, attr)) - - # Overwrites v2 test - def test_base_url_to_get_admin_endpoint(self): - self.filters = { - 'service': 'compute', - 'endpoint_type': 'admin', - 'region': 'MiddleEarthRegion' - } - expected = self._get_result_url_from_endpoint( - self._endpoints[0]['endpoints'][2]) - self._test_base_url_helper(expected, self.filters) - - # Overwrites v2 test - def test_base_url_with_unversioned_endpoint(self): - auth_data = { - 'catalog': [ - { - 'type': 'identity', - 'endpoints': [ - { - 'region': 'FakeRegion', - 'url': 'http://fake_url', - 'interface': 'public' - } - ] - } - ] - } - - filters = { - 'service': 'identity', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion', - 'api_version': 'v3' - } - - expected = 'http://fake_url/v3' - self._test_base_url_helper(expected, filters, ('token', auth_data)) - - def test_base_url_with_extra_path_endpoint(self): - auth_data = { - 'catalog': [ - { - 'type': 'compute', - 'endpoints': [ - { - 'region': 'FakeRegion', - 'url': 'http://fake_url/some_path/v2.0', - 'interface': 'public' - } - ] - } - ] - } - - filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion', - 'api_version': 'v2.0' - } - - expected = 'http://fake_url/some_path/v2.0' - self._test_base_url_helper(expected, filters, ('token', auth_data)) - - def test_base_url_with_unversioned_extra_path_endpoint(self): - auth_data = { - 'catalog': [ - { - 'type': 'compute', - 'endpoints': [ - { - 'region': 'FakeRegion', - 'url': 'http://fake_url/some_path', - 'interface': 'public' - } - ] - } - ] - } - - filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion', - 'api_version': 'v2.0' - } - - expected = 'http://fake_url/some_path/v2.0' - self._test_base_url_helper(expected, filters, ('token', auth_data)) - - # Base URL test with scope only for V3 - def test_base_url_scope_project(self): - self.auth_provider.scope = 'project' - self.filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion' - } - expected = self._get_result_url_from_endpoint( - self._endpoints[0]['endpoints'][1]) - self._test_base_url_helper(expected, self.filters) - - # Base URL test with scope only for V3 - def test_base_url_unscoped_identity(self): - self.auth_provider.scope = 'unscoped' - self.patchobject(v3_client.V3TokenClient, 'raw_request', - fake_identity._fake_v3_response_no_scope) - self.filters = { - 'service': 'identity', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion' - } - expected = fake_identity.FAKE_AUTH_URL - self._test_base_url_helper(expected, self.filters) - - # Base URL test with scope only for V3 - def test_base_url_unscoped_other(self): - self.auth_provider.scope = 'unscoped' - self.patchobject(v3_client.V3TokenClient, 'raw_request', - fake_identity._fake_v3_response_no_scope) - self.filters = { - 'service': 'compute', - 'endpoint_type': 'publicURL', - 'region': 'FakeRegion' - } - self.assertRaises(exceptions.EndpointNotFound, - self.auth_provider.base_url, - auth_data=self.auth_provider.auth_data, - filters=self.filters) - - def test_auth_parameters_with_scope_unset(self): - # No scope defaults to 'project' - all_creds = fake_credentials.FakeKeystoneV3AllCredentials() - self.auth_provider.credentials = all_creds - auth_params = self.auth_provider._auth_params() - self.assertNotIn('scope', auth_params.keys()) - for attr in all_creds.get_init_attributes(): - if attr.startswith('domain_'): - self.assertNotIn(attr, auth_params.keys()) - else: - self.assertIn(attr, auth_params.keys()) - self.assertEqual(getattr(all_creds, attr), auth_params[attr]) - - def test_auth_parameters_with_project_scope(self): - all_creds = fake_credentials.FakeKeystoneV3AllCredentials() - self.auth_provider.credentials = all_creds - self.auth_provider.scope = 'project' - auth_params = self.auth_provider._auth_params() - self.assertNotIn('scope', auth_params.keys()) - for attr in all_creds.get_init_attributes(): - if attr.startswith('domain_'): - self.assertNotIn(attr, auth_params.keys()) - else: - self.assertIn(attr, auth_params.keys()) - self.assertEqual(getattr(all_creds, attr), auth_params[attr]) - - def test_auth_parameters_with_domain_scope(self): - all_creds = fake_credentials.FakeKeystoneV3AllCredentials() - self.auth_provider.credentials = all_creds - self.auth_provider.scope = 'domain' - auth_params = self.auth_provider._auth_params() - self.assertNotIn('scope', auth_params.keys()) - for attr in all_creds.get_init_attributes(): - if attr.startswith('project_'): - self.assertNotIn(attr, auth_params.keys()) - else: - self.assertIn(attr, auth_params.keys()) - self.assertEqual(getattr(all_creds, attr), auth_params[attr]) - - def test_auth_parameters_unscoped(self): - all_creds = fake_credentials.FakeKeystoneV3AllCredentials() - self.auth_provider.credentials = all_creds - self.auth_provider.scope = 'unscoped' - auth_params = self.auth_provider._auth_params() - self.assertNotIn('scope', auth_params.keys()) - for attr in all_creds.get_init_attributes(): - if attr.startswith('project_') or attr.startswith('domain_'): - self.assertNotIn(attr, auth_params.keys()) - else: - self.assertIn(attr, auth_params.keys()) - self.assertEqual(getattr(all_creds, attr), auth_params[attr]) - - -class TestKeystoneV3Credentials(base.TestCase): - def testSetAttrUserDomain(self): - creds = auth.KeystoneV3Credentials() - creds.user_domain_name = 'user_domain' - creds.domain_name = 'domain' - self.assertEqual('user_domain', creds.user_domain_name) - creds = auth.KeystoneV3Credentials() - creds.domain_name = 'domain' - creds.user_domain_name = 'user_domain' - self.assertEqual('user_domain', creds.user_domain_name) - - def testSetAttrProjectDomain(self): - creds = auth.KeystoneV3Credentials() - creds.project_domain_name = 'project_domain' - creds.domain_name = 'domain' - self.assertEqual('project_domain', creds.user_domain_name) - creds = auth.KeystoneV3Credentials() - creds.domain_name = 'domain' - creds.project_domain_name = 'project_domain' - self.assertEqual('project_domain', creds.project_domain_name) - - def testProjectTenantNoCollision(self): - creds = auth.KeystoneV3Credentials(tenant_id='tenant') - self.assertEqual('tenant', creds.project_id) - creds = auth.KeystoneV3Credentials(project_id='project') - self.assertEqual('project', creds.tenant_id) - creds = auth.KeystoneV3Credentials(tenant_name='tenant') - self.assertEqual('tenant', creds.project_name) - creds = auth.KeystoneV3Credentials(project_name='project') - self.assertEqual('project', creds.tenant_name) - - def testProjectTenantCollision(self): - attrs = {'tenant_id': 'tenant', 'project_id': 'project'} - self.assertRaises( - exceptions.InvalidCredentials, auth.KeystoneV3Credentials, **attrs) - attrs = {'tenant_name': 'tenant', 'project_name': 'project'} - self.assertRaises( - exceptions.InvalidCredentials, auth.KeystoneV3Credentials, **attrs) - - -class TestReplaceVersion(base.TestCase): - def test_version_no_trailing_path(self): - self.assertEqual( - 'http://localhost:35357/v2.0', - auth.replace_version('http://localhost:35357/v3', 'v2.0')) - - def test_version_no_trailing_path_solidus(self): - self.assertEqual( - 'http://localhost:35357/v2.0/', - auth.replace_version('http://localhost:35357/v3/', 'v2.0')) - - def test_version_trailing_path(self): - self.assertEqual( - 'http://localhost:35357/v2.0/uuid', - auth.replace_version('http://localhost:35357/v3/uuid', 'v2.0')) - - def test_version_trailing_path_solidus(self): - self.assertEqual( - 'http://localhost:35357/v2.0/uuid/', - auth.replace_version('http://localhost:35357/v3/uuid/', 'v2.0')) - - def test_no_version_base(self): - self.assertEqual( - 'http://localhost:35357/v2.0', - auth.replace_version('http://localhost:35357', 'v2.0')) - - def test_no_version_base_solidus(self): - self.assertEqual( - 'http://localhost:35357/v2.0', - auth.replace_version('http://localhost:35357/', 'v2.0')) - - def test_no_version_path(self): - self.assertEqual( - 'http://localhost/identity/v2.0', - auth.replace_version('http://localhost/identity', 'v2.0')) - - def test_no_version_path_solidus(self): - self.assertEqual( - 'http://localhost/identity/v2.0', - auth.replace_version('http://localhost/identity/', 'v2.0')) - - def test_path_version(self): - self.assertEqual( - 'http://localhost/identity/v2.0', - auth.replace_version('http://localhost/identity/v3', 'v2.0')) - - def test_path_version_solidus(self): - self.assertEqual( - 'http://localhost/identity/v2.0/', - auth.replace_version('http://localhost/identity/v3/', 'v2.0')) - - def test_path_version_trailing_path(self): - self.assertEqual( - 'http://localhost/identity/v2.0/uuid', - auth.replace_version('http://localhost/identity/v3/uuid', 'v2.0')) - - def test_path_version_trailing_path_solidus(self): - self.assertEqual( - 'http://localhost/identity/v2.0/uuid/', - auth.replace_version('http://localhost/identity/v3/uuid/', 'v2.0')) - - -class TestKeystoneV3AuthProvider_DomainScope(BaseAuthTestsSetUp): - _endpoints = fake_identity.IDENTITY_V3_RESPONSE['token']['catalog'] - _auth_provider_class = auth.KeystoneV3AuthProvider - credentials = fake_credentials.FakeKeystoneV3Credentials() - - def setUp(self): - super(TestKeystoneV3AuthProvider_DomainScope, self).setUp() - self.patchobject(v3_client.V3TokenClient, 'raw_request', - fake_identity._fake_v3_response_domain_scope) - - def test_get_auth_with_domain_scope(self): - self.auth_provider.scope = 'domain' - _, auth_data = self.auth_provider.get_auth() - self.assertIn('domain', auth_data) - self.assertNotIn('project', auth_data) - - -class TestGetCredentials(base.TestCase): - - def test_invalid_identity_version(self): - with testtools.ExpectedException(exceptions.InvalidIdentityVersion, - '.* v1 .*'): - auth.get_credentials('http://localhost/identity/v3', - identity_version='v1') diff --git a/tempest/tests/lib/test_base.py b/tempest/tests/lib/test_base.py deleted file mode 100644 index 27cda1a2c..000000000 --- a/tempest/tests/lib/test_base.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2014 Mirantis Inc. -# 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 testtools - -from tempest.lib import base -from tempest.lib import exceptions - - -class TestAttr(base.BaseTestCase): - - def test_has_no_attrs(self): - self.assertEqual( - 'tempest.tests.lib.test_base.TestAttr.test_has_no_attrs', - self.id() - ) - - @testtools.testcase.attr('foo') - def test_has_one_attr(self): - self.assertEqual( - 'tempest.tests.lib.test_base.TestAttr.test_has_one_attr[foo]', - self.id() - ) - - @testtools.testcase.attr('foo') - @testtools.testcase.attr('bar') - def test_has_two_attrs(self): - self.assertEqual( - 'tempest.tests.lib.test_base.TestAttr.test_has_two_attrs[bar,foo]', - self.id(), - ) - - -class TestSetUpClass(base.BaseTestCase): - - @classmethod - def setUpClass(cls): # noqa - """Simulate absence of super() call.""" - - def setUp(self): - try: - # We expect here RuntimeError exception because 'setUpClass' - # has not called 'super'. - super(TestSetUpClass, self).setUp() - except RuntimeError: - pass - else: - raise exceptions.TempestException( - "If you see this, then expected exception was not raised.") - - def test_setup_class_raises_runtime_error(self): - """No-op test just to call setUp.""" diff --git a/tempest/tests/lib/test_credentials.py b/tempest/tests/lib/test_credentials.py deleted file mode 100644 index c910d6d6d..000000000 --- a/tempest/tests/lib/test_credentials.py +++ /dev/null @@ -1,182 +0,0 @@ -# Copyright 2014 Hewlett-Packard Development Company, L.P. -# 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 copy - -from tempest.lib import auth -from tempest.lib import exceptions -from tempest.lib.services.identity.v2 import token_client as v2_client -from tempest.lib.services.identity.v3 import token_client as v3_client -from tempest.tests import base -from tempest.tests.lib import fake_identity - - -class CredentialsTests(base.TestCase): - attributes = {} - credentials_class = auth.Credentials - - def _get_credentials(self, attributes=None): - if attributes is None: - attributes = self.attributes - return self.credentials_class(**attributes) - - def _check(self, credentials, credentials_class, filled): - # Check the right version of credentials has been returned - self.assertIsInstance(credentials, credentials_class) - # Check the id attributes are filled in - # NOTE(andreaf) project_* attributes are accepted as input but - # never set on the credentials object - attributes = [x for x in credentials.ATTRIBUTES if ( - '_id' in x and x != 'domain_id' and x != 'project_id')] - for attr in attributes: - if filled: - self.assertIsNotNone(getattr(credentials, attr)) - else: - self.assertIsNone(getattr(credentials, attr)) - - def test_create(self): - creds = self._get_credentials() - self.assertEqual(self.attributes, creds._initial) - - def test_create_invalid_attr(self): - self.assertRaises(exceptions.InvalidCredentials, - self._get_credentials, - attributes=dict(invalid='fake')) - - def test_is_valid(self): - creds = self._get_credentials() - self.assertRaises(NotImplementedError, creds.is_valid) - - -class KeystoneV2CredentialsTests(CredentialsTests): - attributes = { - 'username': 'fake_username', - 'password': 'fake_password', - 'tenant_name': 'fake_tenant_name' - } - - identity_response = fake_identity._fake_v2_response - credentials_class = auth.KeystoneV2Credentials - tokenclient_class = v2_client.TokenClient - identity_version = 'v2' - - def setUp(self): - super(KeystoneV2CredentialsTests, self).setUp() - self.patchobject(self.tokenclient_class, 'raw_request', - self.identity_response) - - def _verify_credentials(self, credentials_class, creds_dict, filled=True): - creds = auth.get_credentials(fake_identity.FAKE_AUTH_URL, - fill_in=filled, - identity_version=self.identity_version, - **creds_dict) - self._check(creds, credentials_class, filled) - - def test_get_credentials(self): - self._verify_credentials(credentials_class=self.credentials_class, - creds_dict=self.attributes) - - def test_get_credentials_not_filled(self): - self._verify_credentials(credentials_class=self.credentials_class, - creds_dict=self.attributes, - filled=False) - - def test_is_valid(self): - creds = self._get_credentials() - self.assertTrue(creds.is_valid()) - - def _test_is_not_valid(self, ignore_key): - creds = self._get_credentials() - for attr in self.attributes: - if attr == ignore_key: - continue - temp_attr = getattr(creds, attr) - delattr(creds, attr) - self.assertFalse(creds.is_valid(), - "Credentials should be invalid without %s" % attr) - setattr(creds, attr, temp_attr) - - def test_is_not_valid(self): - # NOTE(mtreinish): A KeystoneV2 credential object is valid without - # a tenant_name. So skip that check. See tempest.auth for the valid - # credential requirements - self._test_is_not_valid('tenant_name') - - def test_reset_all_attributes(self): - creds = self._get_credentials() - initial_creds = copy.deepcopy(creds) - set_attr = creds.__dict__.keys() - missing_attr = set(creds.ATTRIBUTES).difference(set_attr) - # Set all unset attributes, then reset - for attr in missing_attr: - setattr(creds, attr, 'fake' + attr) - creds.reset() - # Check reset credentials are same as initial ones - self.assertEqual(creds, initial_creds) - - def test_reset_single_attribute(self): - creds = self._get_credentials() - initial_creds = copy.deepcopy(creds) - set_attr = creds.__dict__.keys() - missing_attr = set(creds.ATTRIBUTES).difference(set_attr) - # Set one unset attributes, then reset - for attr in missing_attr: - setattr(creds, attr, 'fake' + attr) - creds.reset() - # Check reset credentials are same as initial ones - self.assertEqual(creds, initial_creds) - - -class KeystoneV3CredentialsTests(KeystoneV2CredentialsTests): - attributes = { - 'username': 'fake_username', - 'password': 'fake_password', - 'project_name': 'fake_project_name', - 'user_domain_name': 'fake_domain_name' - } - - credentials_class = auth.KeystoneV3Credentials - identity_response = fake_identity._fake_v3_response - tokenclient_class = v3_client.V3TokenClient - identity_version = 'v3' - - def test_is_not_valid(self): - # NOTE(mtreinish) For a Keystone V3 credential object a project name - # is not required to be valid, so we skip that check. See tempest.auth - # for the valid credential requirements - self._test_is_not_valid('project_name') - - def test_synced_attributes(self): - attributes = self.attributes - # Create V3 credentials with tenant instead of project, and user_domain - for attr in ['project_id', 'user_domain_id']: - attributes[attr] = 'fake_' + attr - creds = self._get_credentials(attributes) - self.assertEqual(creds.project_name, creds.tenant_name) - self.assertEqual(creds.project_id, creds.tenant_id) - self.assertEqual(creds.user_domain_name, creds.project_domain_name) - self.assertEqual(creds.user_domain_id, creds.project_domain_id) - # Replace user_domain with project_domain - del attributes['user_domain_name'] - del attributes['user_domain_id'] - del attributes['project_name'] - del attributes['project_id'] - for attr in ['project_domain_name', 'project_domain_id', - 'tenant_name', 'tenant_id']: - attributes[attr] = 'fake_' + attr - self.assertEqual(creds.tenant_name, creds.project_name) - self.assertEqual(creds.tenant_id, creds.project_id) - self.assertEqual(creds.project_domain_name, creds.user_domain_name) - self.assertEqual(creds.project_domain_id, creds.user_domain_id) diff --git a/tempest/tests/lib/test_decorators.py b/tempest/tests/lib/test_decorators.py deleted file mode 100644 index bbebcd3b2..000000000 --- a/tempest/tests/lib/test_decorators.py +++ /dev/null @@ -1,184 +0,0 @@ -# Copyright 2013 IBM Corp -# Copyright 2015 Hewlett-Packard Development Company, L.P. -# -# 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 mock -import testtools - -from tempest.lib import base as test -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.tests import base - - -class TestAttrDecorator(base.TestCase): - def _test_attr_helper(self, expected_attrs, **decorator_args): - @decorators.attr(**decorator_args) - def foo(): - pass - - # By our decorators.attr decorator the attribute __testtools_attrs - # will be set only for 'type' argument, so we test it first. - if 'type' in decorator_args: - # this is what testtools sets - self.assertEqual(getattr(foo, '__testtools_attrs'), - set(expected_attrs)) - - def test_attr_without_type(self): - self._test_attr_helper(expected_attrs='baz', bar='baz') - - def test_attr_decorator_with_list_type(self): - # if type is 'smoke' we'll get the original list of types - self._test_attr_helper(expected_attrs=['smoke', 'foo'], - type=['smoke', 'foo']) - - def test_attr_decorator_with_unknown_type(self): - self._test_attr_helper(expected_attrs=['foo'], type='foo') - - def test_attr_decorator_with_duplicated_type(self): - self._test_attr_helper(expected_attrs=['foo'], type=['foo', 'foo']) - - -class TestSkipBecauseDecorator(base.TestCase): - def _test_skip_because_helper(self, expected_to_skip=True, - **decorator_args): - class TestFoo(test.BaseTestCase): - _interface = 'json' - - @decorators.skip_because(**decorator_args) - def test_bar(self): - return 0 - - t = TestFoo('test_bar') - if expected_to_skip: - self.assertRaises(testtools.TestCase.skipException, t.test_bar) - else: - # assert that test_bar returned 0 - self.assertEqual(TestFoo('test_bar').test_bar(), 0) - - def test_skip_because_bug(self): - self._test_skip_because_helper(bug='12345') - - def test_skip_because_bug_and_condition_true(self): - self._test_skip_because_helper(bug='12348', condition=True) - - def test_skip_because_bug_and_condition_false(self): - self._test_skip_because_helper(expected_to_skip=False, - bug='12349', condition=False) - - def test_skip_because_bug_without_bug_never_skips(self): - """Never skip without a bug parameter.""" - self._test_skip_because_helper(expected_to_skip=False, - condition=True) - self._test_skip_because_helper(expected_to_skip=False) - - def test_skip_because_invalid_bug_number(self): - """Raise ValueError if with an invalid bug number""" - self.assertRaises(ValueError, self._test_skip_because_helper, - bug='critical_bug') - - -class TestIdempotentIdDecorator(base.TestCase): - def _test_helper(self, _id, **decorator_args): - @decorators.idempotent_id(_id) - def foo(): - """Docstring""" - pass - - return foo - - def _test_helper_without_doc(self, _id, **decorator_args): - @decorators.idempotent_id(_id) - def foo(): - pass - - return foo - - def test_positive(self): - _id = data_utils.rand_uuid() - foo = self._test_helper(_id) - self.assertIn('id-%s' % _id, getattr(foo, '__testtools_attrs')) - self.assertTrue(foo.__doc__.startswith('Test idempotent id: %s' % _id)) - - def test_positive_without_doc(self): - _id = data_utils.rand_uuid() - foo = self._test_helper_without_doc(_id) - self.assertTrue(foo.__doc__.startswith('Test idempotent id: %s' % _id)) - - def test_idempotent_id_not_str(self): - _id = 42 - self.assertRaises(TypeError, self._test_helper, _id) - - def test_idempotent_id_not_valid_uuid(self): - _id = '42' - self.assertRaises(ValueError, self._test_helper, _id) - - -class TestSkipUnlessAttrDecorator(base.TestCase): - def _test_skip_unless_attr(self, attr, expected_to_skip=True): - class TestFoo(test.BaseTestCase): - expected_attr = not expected_to_skip - - @decorators.skip_unless_attr(attr) - def test_foo(self): - pass - - t = TestFoo('test_foo') - if expected_to_skip: - self.assertRaises(testtools.TestCase.skipException, - t.test_foo) - else: - try: - t.test_foo() - except Exception: - raise testtools.TestCase.failureException() - - def test_skip_attr_does_not_exist(self): - self._test_skip_unless_attr('unexpected_attr') - - def test_skip_attr_false(self): - self._test_skip_unless_attr('expected_attr') - - def test_no_skip_for_attr_exist_and_true(self): - self._test_skip_unless_attr('expected_attr', expected_to_skip=False) - - -class TestRelatedBugDecorator(base.TestCase): - def test_relatedbug_when_no_exception(self): - f = mock.Mock() - sentinel = object() - - @decorators.related_bug(bug="1234", status_code=500) - def test_foo(self): - f(self) - - test_foo(sentinel) - f.assert_called_once_with(sentinel) - - def test_relatedbug_when_exception(self): - class MyException(Exception): - def __init__(self, status_code): - self.status_code = status_code - - def f(self): - raise MyException(status_code=500) - - @decorators.related_bug(bug="1234", status_code=500) - def test_foo(self): - f(self) - - with mock.patch.object(decorators.LOG, 'error') as m_error: - self.assertRaises(MyException, test_foo, object()) - - m_error.assert_called_once_with(mock.ANY, '1234', '1234') diff --git a/tempest/tests/lib/test_ssh.py b/tempest/tests/lib/test_ssh.py deleted file mode 100644 index a16da1c15..000000000 --- a/tempest/tests/lib/test_ssh.py +++ /dev/null @@ -1,305 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# -# 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 io import StringIO -import socket - -import mock -import six -import testtools - -from tempest.lib.common import ssh -from tempest.lib import exceptions -from tempest.tests import base -import tempest.tests.utils as utils - - -class TestSshClient(base.TestCase): - - SELECT_POLLIN = 1 - - @mock.patch('paramiko.RSAKey.from_private_key') - @mock.patch('six.StringIO') - def test_pkey_calls_paramiko_RSAKey(self, cs_mock, rsa_mock): - cs_mock.return_value = mock.sentinel.csio - pkey = 'mykey' - ssh.Client('localhost', 'root', pkey=pkey) - rsa_mock.assert_called_once_with(mock.sentinel.csio) - cs_mock.assert_called_once_with('mykey') - rsa_mock.reset_mock() - cs_mock.reset_mock() - pkey = mock.sentinel.pkey - # Shouldn't call out to load a file from RSAKey, since - # a sentinel isn't a basestring... - ssh.Client('localhost', 'root', pkey=pkey) - self.assertEqual(0, rsa_mock.call_count) - self.assertEqual(0, cs_mock.call_count) - - def _set_ssh_connection_mocks(self): - client_mock = mock.MagicMock() - client_mock.connect.return_value = True - return (self.patch('paramiko.SSHClient'), - self.patch('paramiko.AutoAddPolicy'), - client_mock) - - def test_get_ssh_connection(self): - c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks() - s_mock = self.patch('time.sleep') - - c_mock.return_value = client_mock - aa_mock.return_value = mock.sentinel.aa - - # Test normal case for successful connection on first try - client = ssh.Client('localhost', 'root', timeout=2) - client._get_ssh_connection(sleep=1) - - aa_mock.assert_called_once_with() - client_mock.set_missing_host_key_policy.assert_called_once_with( - mock.sentinel.aa) - expected_connect = [mock.call( - 'localhost', - port=22, - username='root', - pkey=None, - key_filename=None, - look_for_keys=False, - timeout=10.0, - password=None, - sock=None - )] - self.assertEqual(expected_connect, client_mock.connect.mock_calls) - self.assertEqual(0, s_mock.call_count) - - def test_get_ssh_connection_over_ssh(self): - c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks() - proxy_client_mock = mock.MagicMock() - proxy_client_mock.connect.return_value = True - s_mock = self.patch('time.sleep') - - c_mock.side_effect = [client_mock, proxy_client_mock] - aa_mock.return_value = mock.sentinel.aa - - proxy_client = ssh.Client('proxy-host', 'proxy-user', timeout=2) - client = ssh.Client('localhost', 'root', timeout=2, - proxy_client=proxy_client) - client._get_ssh_connection(sleep=1) - - aa_mock.assert_has_calls([mock.call(), mock.call()]) - proxy_client_mock.set_missing_host_key_policy.assert_called_once_with( - mock.sentinel.aa) - proxy_expected_connect = [mock.call( - 'proxy-host', - port=22, - username='proxy-user', - pkey=None, - key_filename=None, - look_for_keys=False, - timeout=10.0, - password=None, - sock=None - )] - self.assertEqual(proxy_expected_connect, - proxy_client_mock.connect.mock_calls) - client_mock.set_missing_host_key_policy.assert_called_once_with( - mock.sentinel.aa) - expected_connect = [mock.call( - 'localhost', - port=22, - username='root', - pkey=None, - key_filename=None, - look_for_keys=False, - timeout=10.0, - password=None, - sock=proxy_client_mock.get_transport().open_session() - )] - self.assertEqual(expected_connect, client_mock.connect.mock_calls) - self.assertEqual(0, s_mock.call_count) - - @mock.patch('time.sleep') - def test_get_ssh_connection_two_attemps(self, sleep_mock): - c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks() - - c_mock.return_value = client_mock - client_mock.connect.side_effect = [ - socket.error, - mock.MagicMock() - ] - - client = ssh.Client('localhost', 'root', timeout=1) - client._get_ssh_connection(sleep=1) - # We slept 2 seconds: because sleep is "1" and backoff is "1" too - sleep_mock.assert_called_once_with(2) - self.assertEqual(2, client_mock.connect.call_count) - - def test_get_ssh_connection_timeout(self): - c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks() - - timeout = 2 - time_mock = self.patch('time.time') - time_mock.side_effect = utils.generate_timeout_series(timeout + 1) - - c_mock.return_value = client_mock - client_mock.connect.side_effect = [ - socket.error, - socket.error, - socket.error, - ] - - client = ssh.Client('localhost', 'root', timeout=timeout) - # We need to mock LOG here because LOG.info() calls time.time() - # in order to preprend a timestamp. - with mock.patch.object(ssh, 'LOG'): - self.assertRaises(exceptions.SSHTimeout, - client._get_ssh_connection) - - # time.time() should be called twice, first to start the timer - # and then to compute the timedelta - self.assertEqual(2, time_mock.call_count) - - @mock.patch('select.POLLIN', SELECT_POLLIN, create=True) - def test_timeout_in_exec_command(self): - chan_mock, poll_mock, _ = self._set_mocks_for_select([0, 0, 0], True) - - # Test for a timeout condition immediately raised - client = ssh.Client('localhost', 'root', timeout=2) - with testtools.ExpectedException(exceptions.TimeoutException): - client.exec_command("test") - - chan_mock.fileno.assert_called_once_with() - chan_mock.exec_command.assert_called_once_with("test") - chan_mock.shutdown_write.assert_called_once_with() - - poll_mock.register.assert_called_once_with( - chan_mock, self.SELECT_POLLIN) - poll_mock.poll.assert_called_once_with(10) - - @mock.patch('select.POLLIN', SELECT_POLLIN, create=True) - def test_exec_command(self): - chan_mock, poll_mock, select_mock = ( - self._set_mocks_for_select([[1, 0, 0]], True)) - - chan_mock.recv_exit_status.return_value = 0 - chan_mock.recv.return_value = b'' - chan_mock.recv_stderr.return_value = b'' - - client = ssh.Client('localhost', 'root', timeout=2) - client.exec_command("test") - - chan_mock.fileno.assert_called_once_with() - chan_mock.exec_command.assert_called_once_with("test") - chan_mock.shutdown_write.assert_called_once_with() - - select_mock.assert_called_once_with() - poll_mock.register.assert_called_once_with( - chan_mock, self.SELECT_POLLIN) - poll_mock.poll.assert_called_once_with(10) - chan_mock.recv_ready.assert_called_once_with() - chan_mock.recv.assert_called_once_with(1024) - chan_mock.recv_stderr_ready.assert_called_once_with() - chan_mock.recv_stderr.assert_called_once_with(1024) - chan_mock.recv_exit_status.assert_called_once_with() - - def _set_mocks_for_select(self, poll_data, ito_value=False): - gsc_mock = self.patch('tempest.lib.common.ssh.Client.' - '_get_ssh_connection') - ito_mock = self.patch('tempest.lib.common.ssh.Client._is_timed_out') - csp_mock = self.patch( - 'tempest.lib.common.ssh.Client._can_system_poll') - csp_mock.return_value = True - - select_mock = self.patch('select.poll', create=True) - client_mock = mock.MagicMock() - tran_mock = mock.MagicMock() - chan_mock = mock.MagicMock() - poll_mock = mock.MagicMock() - - select_mock.return_value = poll_mock - gsc_mock.return_value = client_mock - ito_mock.return_value = ito_value - client_mock.get_transport.return_value = tran_mock - tran_mock.open_session().__enter__.return_value = chan_mock - if isinstance(poll_data[0], list): - poll_mock.poll.side_effect = poll_data - else: - poll_mock.poll.return_value = poll_data - - return chan_mock, poll_mock, select_mock - - _utf8_string = six.unichr(1071) - _utf8_bytes = _utf8_string.encode("utf-8") - - @mock.patch('select.POLLIN', SELECT_POLLIN, create=True) - def test_exec_good_command_output(self): - chan_mock, poll_mock, _ = self._set_mocks_for_select([1, 0, 0]) - closed_prop = mock.PropertyMock(return_value=True) - type(chan_mock).closed = closed_prop - - chan_mock.recv_exit_status.return_value = 0 - chan_mock.recv.side_effect = [self._utf8_bytes[0:1], - self._utf8_bytes[1:], b'R', b''] - chan_mock.recv_stderr.return_value = b'' - - client = ssh.Client('localhost', 'root', timeout=2) - out_data = client.exec_command("test") - self.assertEqual(self._utf8_string + 'R', out_data) - - @mock.patch('select.POLLIN', SELECT_POLLIN, create=True) - def test_exec_bad_command_output(self): - chan_mock, poll_mock, _ = self._set_mocks_for_select([1, 0, 0]) - closed_prop = mock.PropertyMock(return_value=True) - type(chan_mock).closed = closed_prop - - chan_mock.recv_exit_status.return_value = 1 - chan_mock.recv.return_value = b'' - chan_mock.recv_stderr.side_effect = [b'R', self._utf8_bytes[0:1], - self._utf8_bytes[1:], b''] - - client = ssh.Client('localhost', 'root', timeout=2) - exc = self.assertRaises(exceptions.SSHExecCommandFailed, - client.exec_command, "test") - self.assertIn('R' + self._utf8_string, six.text_type(exc)) - - def test_exec_command_no_select(self): - gsc_mock = self.patch('tempest.lib.common.ssh.Client.' - '_get_ssh_connection') - csp_mock = self.patch( - 'tempest.lib.common.ssh.Client._can_system_poll') - csp_mock.return_value = False - - select_mock = self.patch('select.poll', create=True) - client_mock = mock.MagicMock() - tran_mock = mock.MagicMock() - chan_mock = mock.MagicMock() - - # Test for proper reading of STDOUT and STDERROR - - gsc_mock.return_value = client_mock - client_mock.get_transport.return_value = tran_mock - tran_mock.open_session().__enter__.return_value = chan_mock - chan_mock.recv_exit_status.return_value = 0 - - std_out_mock = mock.MagicMock(StringIO) - std_err_mock = mock.MagicMock(StringIO) - chan_mock.makefile.return_value = std_out_mock - chan_mock.makefile_stderr.return_value = std_err_mock - - client = ssh.Client('localhost', 'root', timeout=2) - client.exec_command("test") - - chan_mock.makefile.assert_called_once_with('rb', 1024) - chan_mock.makefile_stderr.assert_called_once_with('rb', 1024) - std_out_mock.read.assert_called_once_with() - std_err_mock.read.assert_called_once_with() - self.assertFalse(select_mock.called) diff --git a/tempest/tests/lib/test_tempest_lib.py b/tempest/tests/lib/test_tempest_lib.py deleted file mode 100644 index 4d9f09989..000000000 --- a/tempest/tests/lib/test_tempest_lib.py +++ /dev/null @@ -1,26 +0,0 @@ -# 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. - -""" -test_tempest.lib ----------------------------------- - -Tests for `tempest.lib` module. -""" - -from tempest.tests import base - - -class TestTempest_lib(base.TestCase): - - def test_something(self): - pass diff --git a/tempest/tests/services/__init__.py b/tempest/tests/services/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/services/object_storage/__init__.py b/tempest/tests/services/object_storage/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tempest/tests/services/object_storage/test_bulk_middleware_client.py b/tempest/tests/services/object_storage/test_bulk_middleware_client.py deleted file mode 100644 index 163b48e6f..000000000 --- a/tempest/tests/services/object_storage/test_bulk_middleware_client.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright 2017 NEC Corporation. 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 tempest.services.object_storage import bulk_middleware_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestBulkMiddlewareClient(base.BaseServiceTest): - - def setUp(self): - super(TestBulkMiddlewareClient, self).setUp() - fake_auth = fake_auth_provider.FakeAuthProvider() - self.client = bulk_middleware_client.BulkMiddlewareClient( - fake_auth, 'object-storage', 'regionOne') - - def test_upload_archive(self): - url = 'test_path?extract-archive=tar' - data = 'test_data' - self.check_service_client_function( - self.client.upload_archive, - 'tempest.lib.common.rest_client.RestClient.put', - {}, - mock_args=[url, data, {}], - resp_as_string=True, - upload_path='test_path', data=data, archive_file_format='tar') - - def test_delete_bulk_data(self): - url = '?bulk-delete' - data = 'test_data' - self.check_service_client_function( - self.client.delete_bulk_data, - 'tempest.lib.common.rest_client.RestClient.delete', - {}, - mock_args=[url, {}, data], - resp_as_string=True, - data=data) - - def _test_delete_bulk_data_with_post(self, status): - url = '?bulk-delete' - data = 'test_data' - self.check_service_client_function( - self.client.delete_bulk_data_with_post, - 'tempest.lib.common.rest_client.RestClient.post', - {}, - mock_args=[url, data, {}], - resp_as_string=True, - status=status, - data=data) - - def test_delete_bulk_data_with_post_200(self): - self._test_delete_bulk_data_with_post(200) - - def test_delete_bulk_data_with_post_204(self): - self._test_delete_bulk_data_with_post(204) diff --git a/tempest/tests/services/object_storage/test_capabilities_client.py b/tempest/tests/services/object_storage/test_capabilities_client.py deleted file mode 100644 index 5279bf474..000000000 --- a/tempest/tests/services/object_storage/test_capabilities_client.py +++ /dev/null @@ -1,54 +0,0 @@ -# Copyright 2016 IBM 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 tempest.services.object_storage import capabilities_client -from tempest.tests.lib import fake_auth_provider -from tempest.tests.lib.services import base - - -class TestCapabilitiesClient(base.BaseServiceTest): - - def setUp(self): - super(TestCapabilitiesClient, self).setUp() - self.fake_auth = fake_auth_provider.FakeAuthProvider() - self.url = self.fake_auth.base_url(None) - self.client = capabilities_client.CapabilitiesClient( - self.fake_auth, 'swift', 'region1') - - def _test_list_capabilities(self, bytes_body=False): - resp = { - "swift": { - "version": "1.11.0" - }, - "slo": { - "max_manifest_segments": 1000, - "max_manifest_size": 2097152, - "min_segment_size": 1 - }, - "staticweb": {}, - "tempurl": {} - } - self.check_service_client_function( - self.client.list_capabilities, - 'tempest.lib.common.rest_client.RestClient.get', - resp, - bytes_body) - - def test_list_capabilities_with_str_body(self): - self._test_list_capabilities() - - def test_list_capabilities_with_bytes_body(self): - self._test_list_capabilities(True) diff --git a/tempest/tests/services/object_storage/test_object_client.py b/tempest/tests/services/object_storage/test_object_client.py deleted file mode 100644 index 748614c7e..000000000 --- a/tempest/tests/services/object_storage/test_object_client.py +++ /dev/null @@ -1,108 +0,0 @@ -# Copyright 2016 IBM 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 mock - -from tempest.lib import exceptions -from tempest.services.object_storage import object_client -from tempest.tests import base -from tempest.tests.lib import fake_auth_provider - - -class TestObjectClient(base.TestCase): - - def setUp(self): - super(TestObjectClient, self).setUp() - self.fake_auth = fake_auth_provider.FakeAuthProvider() - self.url = self.fake_auth.base_url(None) - self.object_client = object_client.ObjectClient(self.fake_auth, - 'swift', 'region1') - - @mock.patch.object(object_client, 'create_connection') - def test_create_object_continue_no_data(self, mock_poc): - self._validate_create_object_continue(None, mock_poc) - - @mock.patch.object(object_client, 'create_connection') - def test_create_object_continue_with_data(self, mock_poc): - self._validate_create_object_continue('hello', mock_poc) - - @mock.patch.object(object_client, 'create_connection') - def test_create_continue_with_no_continue_received(self, mock_poc): - self._validate_create_object_continue('hello', mock_poc, - initial_status=201) - - def _validate_create_object_continue(self, req_data, - mock_poc, initial_status=100): - - expected_hdrs = { - 'X-Auth-Token': self.fake_auth.get_token(), - 'content-length': 0 if req_data is None else len(req_data), - 'Expect': '100-continue'} - - # Setup the Mocks prior to invoking the object creation - mock_resp_cls = mock.Mock() - mock_resp_cls._read_status.return_value = ("1", initial_status, "OK") - - mock_poc.return_value.response_class.return_value = mock_resp_cls - - # This is the final expected return value - mock_poc.return_value.getresponse.return_value.status = 201 - mock_poc.return_value.getresponse.return_value.reason = 'OK' - - # Call method to PUT object using expect:100-continue - cnt = "container1" - obj = "object1" - path = "/%s/%s" % (cnt, obj) - - # If the expected initial status is not 100, then an exception - # should be thrown and the connection closed - if initial_status is 100: - status, reason = \ - self.object_client.create_object_continue(cnt, obj, req_data) - else: - self.assertRaises(exceptions.UnexpectedResponseCode, - self.object_client.create_object_continue, cnt, - obj, req_data) - mock_poc.return_value.close.assert_called_once_with() - - # Verify that putrequest is called 1 time with the appropriate values - mock_poc.return_value.putrequest.assert_called_once_with('PUT', path) - - # Verify that headers were written, including "Expect:100-continue" - calls = [] - - for header, value in expected_hdrs.items(): - calls.append(mock.call(header, value)) - - mock_poc.return_value.putheader.assert_has_calls(calls, False) - mock_poc.return_value.endheaders.assert_called_once_with() - - # The following steps are only taken if the initial status is 100 - if initial_status is 100: - # Verify that the method returned what it was supposed to - self.assertEqual(status, 201) - - # Verify that _safe_read was called once to remove the CRLF - # after the 100 response - mock_rc = mock_poc.return_value.response_class.return_value - mock_rc._safe_read.assert_called_once_with(2) - - # Verify the actual data was written via send - mock_poc.return_value.send.assert_called_once_with(req_data) - - # Verify that the getresponse method was called to receive - # the final - mock_poc.return_value.getresponse.assert_called_once_with() diff --git a/tempest/tests/test_base_test.py b/tempest/tests/test_base_test.py deleted file mode 100644 index 6c6f612e2..000000000 --- a/tempest/tests/test_base_test.py +++ /dev/null @@ -1,110 +0,0 @@ -# Copyright 2016 IBM Corp. -# -# 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 mock - -from tempest import clients -from tempest.common import credentials_factory as credentials -from tempest import config -from tempest.lib.common import fixed_network -from tempest import test -from tempest.tests import base -from tempest.tests import fake_config - - -class TestBaseTestCase(base.TestCase): - def setUp(self): - super(TestBaseTestCase, self).setUp() - self.useFixture(fake_config.ConfigFixture()) - self.fixed_network_name = 'fixed-net' - config.CONF.compute.fixed_network_name = self.fixed_network_name - config.CONF.service_available.neutron = True - - @mock.patch.object(test.BaseTestCase, 'get_client_manager') - @mock.patch.object(test.BaseTestCase, '_get_credentials_provider') - @mock.patch.object(fixed_network, 'get_tenant_network') - def test_get_tenant_network(self, mock_gtn, mock_gprov, mock_gcm): - net_client = mock.Mock() - mock_prov = mock.Mock() - mock_gcm.return_value.compute_networks_client = net_client - mock_gprov.return_value = mock_prov - - test.BaseTestCase.get_tenant_network() - - mock_gcm.assert_called_once_with(credential_type='primary') - mock_gprov.assert_called_once_with() - mock_gtn.assert_called_once_with(mock_prov, net_client, - self.fixed_network_name) - - @mock.patch.object(test.BaseTestCase, 'get_client_manager') - @mock.patch.object(test.BaseTestCase, '_get_credentials_provider') - @mock.patch.object(fixed_network, 'get_tenant_network') - @mock.patch.object(test.BaseTestCase, 'get_identity_version') - @mock.patch.object(credentials, 'is_admin_available') - @mock.patch.object(clients, 'Manager') - def test_get_tenant_network_with_nova_net(self, mock_man, mock_iaa, - mock_giv, mock_gtn, mock_gcp, - mock_gcm): - config.CONF.service_available.neutron = False - mock_prov = mock.Mock() - mock_admin_man = mock.Mock() - mock_iaa.return_value = True - mock_gcp.return_value = mock_prov - mock_man.return_value = mock_admin_man - - test.BaseTestCase.get_tenant_network() - - mock_man.assert_called_once_with( - mock_prov.get_admin_creds.return_value.credentials) - mock_iaa.assert_called_once_with( - identity_version=mock_giv.return_value) - mock_gcp.assert_called_once_with() - mock_gtn.assert_called_once_with( - mock_prov, mock_admin_man.compute_networks_client, - self.fixed_network_name) - - @mock.patch.object(test.BaseTestCase, 'get_client_manager') - @mock.patch.object(test.BaseTestCase, '_get_credentials_provider') - @mock.patch.object(fixed_network, 'get_tenant_network') - def test_get_tenant_network_with_alt_creds(self, mock_gtn, mock_gprov, - mock_gcm): - net_client = mock.Mock() - mock_prov = mock.Mock() - mock_gcm.return_value.compute_networks_client = net_client - mock_gprov.return_value = mock_prov - - test.BaseTestCase.get_tenant_network(credentials_type='alt') - - mock_gcm.assert_called_once_with(credential_type='alt') - mock_gprov.assert_called_once_with() - mock_gtn.assert_called_once_with(mock_prov, net_client, - self.fixed_network_name) - - @mock.patch.object(test.BaseTestCase, 'get_client_manager') - @mock.patch.object(test.BaseTestCase, '_get_credentials_provider') - @mock.patch.object(fixed_network, 'get_tenant_network') - def test_get_tenant_network_with_role_creds(self, mock_gtn, mock_gprov, - mock_gcm): - net_client = mock.Mock() - mock_prov = mock.Mock() - mock_gcm.return_value.compute_networks_client = net_client - mock_gprov.return_value = mock_prov - creds = ['foo_type', 'role1'] - - test.BaseTestCase.get_tenant_network(credentials_type=creds) - - mock_gcm.assert_called_once_with(roles=['role1']) - mock_gprov.assert_called_once_with() - mock_gtn.assert_called_once_with(mock_prov, net_client, - self.fixed_network_name) diff --git a/tempest/tests/test_config.py b/tempest/tests/test_config.py deleted file mode 100644 index 2808a9cf9..000000000 --- a/tempest/tests/test_config.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# 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 testtools - -from tempest import config -from tempest.lib import exceptions -from tempest.tests import base -from tempest.tests import fake_config - - -class TestServiceClientConfig(base.TestCase): - - expected_common_params = set(['disable_ssl_certificate_validation', - 'ca_certs', 'trace_requests']) - expected_extra_params = set(['service', 'endpoint_type', 'region', - 'build_timeout', 'build_interval']) - - def setUp(self): - super(TestServiceClientConfig, self).setUp() - self.useFixture(fake_config.ServiceClientsConfigFixture()) - self.patchobject(config, 'CONF', - fake_config.ServiceClientsFakePrivate()) - self.CONF = config.CONF - - def test_service_client_config_no_service(self): - params = config.service_client_config() - for param_name in self.expected_common_params: - self.assertIn(param_name, params) - for param_name in self.expected_extra_params: - self.assertNotIn(param_name, params) - self.assertEqual( - self.CONF.identity.disable_ssl_certificate_validation, - params['disable_ssl_certificate_validation']) - self.assertEqual(self.CONF.identity.ca_certificates_file, - params['ca_certs']) - self.assertEqual(self.CONF.debug.trace_requests, - params['trace_requests']) - - def test_service_client_config_service_all(self): - params = config.service_client_config( - service_client_name='fake-service1') - for param_name in self.expected_common_params: - self.assertIn(param_name, params) - for param_name in self.expected_extra_params: - self.assertIn(param_name, params) - self.assertEqual(self.CONF.fake_service1.catalog_type, - params['service']) - self.assertEqual(self.CONF.fake_service1.endpoint_type, - params['endpoint_type']) - self.assertEqual(self.CONF.fake_service1.region, params['region']) - self.assertEqual(self.CONF.fake_service1.build_timeout, - params['build_timeout']) - self.assertEqual(self.CONF.fake_service1.build_interval, - params['build_interval']) - - def test_service_client_config_service_minimal(self): - params = config.service_client_config( - service_client_name='fake-service2') - for param_name in self.expected_common_params: - self.assertIn(param_name, params) - for param_name in self.expected_extra_params: - self.assertIn(param_name, params) - self.assertEqual(self.CONF.fake_service2.catalog_type, - params['service']) - self.assertEqual(self.CONF.fake_service2.endpoint_type, - params['endpoint_type']) - self.assertEqual(self.CONF.identity.region, params['region']) - self.assertEqual(self.CONF.compute.build_timeout, - params['build_timeout']) - self.assertEqual(self.CONF.compute.build_interval, - params['build_interval']) - - def test_service_client_config_service_unknown(self): - unknown_service = 'unknown_service' - with testtools.ExpectedException(exceptions.UnknownServiceClient, - '.*' + unknown_service + '.*'): - config.service_client_config(service_client_name=unknown_service) diff --git a/tempest/tests/test_decorators.py b/tempest/tests/test_decorators.py deleted file mode 100644 index 2fc84dc6e..000000000 --- a/tempest/tests/test_decorators.py +++ /dev/null @@ -1,265 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# 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 fixtures -from oslo_config import cfg -import testtools - -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest import test -from tempest.tests import base -from tempest.tests import fake_config - - -class BaseDecoratorsTest(base.TestCase): - def setUp(self): - super(BaseDecoratorsTest, self).setUp() - self.config_fixture = self.useFixture(fake_config.ConfigFixture()) - self.patchobject(config, 'TempestConfigPrivate', - fake_config.FakePrivate) - - -class TestIdempotentIdDecorator(BaseDecoratorsTest): - - def _test_helper(self, _id, **decorator_args): - @test.idempotent_id(_id) - def foo(): - """Docstring""" - pass - - return foo - - def _test_helper_without_doc(self, _id, **decorator_args): - @test.idempotent_id(_id) - def foo(): - pass - - return foo - - def test_positive(self): - _id = data_utils.rand_uuid() - foo = self._test_helper(_id) - self.assertIn('id-%s' % _id, getattr(foo, '__testtools_attrs')) - self.assertTrue(foo.__doc__.startswith('Test idempotent id: %s' % _id)) - - def test_positive_without_doc(self): - _id = data_utils.rand_uuid() - foo = self._test_helper_without_doc(_id) - self.assertTrue(foo.__doc__.startswith('Test idempotent id: %s' % _id)) - - def test_idempotent_id_not_str(self): - _id = 42 - self.assertRaises(TypeError, self._test_helper, _id) - - def test_idempotent_id_not_valid_uuid(self): - _id = '42' - self.assertRaises(ValueError, self._test_helper, _id) - - -class TestServicesDecorator(BaseDecoratorsTest): - def _test_services_helper(self, *decorator_args): - class TestFoo(test.BaseTestCase): - @test.services(*decorator_args) - def test_bar(self): - return 0 - - t = TestFoo('test_bar') - self.assertEqual(set(decorator_args), getattr(t.test_bar, - '__testtools_attrs')) - self.assertEqual(t.test_bar(), 0) - - def test_services_decorator_with_single_service(self): - self._test_services_helper('compute') - - def test_services_decorator_with_multiple_services(self): - self._test_services_helper('compute', 'network') - - def test_services_decorator_with_duplicated_service(self): - self._test_services_helper('compute', 'compute') - - def test_services_decorator_with_invalid_service(self): - self.assertRaises(test.InvalidServiceTag, - self._test_services_helper, 'compute', - 'bad_service') - - def test_services_decorator_with_service_valid_and_unavailable(self): - self.useFixture(fixtures.MockPatchObject(test.CONF.service_available, - 'cinder', False)) - self.assertRaises(testtools.TestCase.skipException, - self._test_services_helper, 'compute', - 'volume') - - def test_services_list(self): - service_list = test.get_service_list() - for service in service_list: - try: - self._test_services_helper(service) - except test.InvalidServiceTag: - self.fail('%s is not listed in the valid service tag list' - % service) - except KeyError: - # NOTE(mtreinish): This condition is to test for an entry in - # the outer decorator list but not in the service_list dict. - # However, because we're looping over the service_list dict - # it's unlikely we'll trigger this. So manual review is still - # need for the list in the outer decorator. - self.fail('%s is in the list of valid service tags but there ' - 'is no corresponding entry in the dict returned from' - ' get_service_list()' % service) - except testtools.TestCase.skipException: - # Test didn't raise an exception because of an incorrect list - # entry so move onto the next entry - continue - - -class TestRequiresExtDecorator(BaseDecoratorsTest): - def setUp(self): - super(TestRequiresExtDecorator, self).setUp() - cfg.CONF.set_default('api_extensions', ['enabled_ext', 'another_ext'], - 'compute-feature-enabled') - - def _test_requires_ext_helper(self, expected_to_skip=True, - **decorator_args): - class TestFoo(test.BaseTestCase): - @test.requires_ext(**decorator_args) - def test_bar(self): - return 0 - - t = TestFoo('test_bar') - if expected_to_skip: - self.assertRaises(testtools.TestCase.skipException, t.test_bar) - else: - try: - self.assertEqual(t.test_bar(), 0) - except testtools.TestCase.skipException: - # We caught a skipException but we didn't expect to skip - # this test so raise a hard test failure instead. - raise testtools.TestCase.failureException( - "Not supposed to skip") - - def test_requires_ext_decorator(self): - self._test_requires_ext_helper(expected_to_skip=False, - extension='enabled_ext', - service='compute') - - def test_requires_ext_decorator_disabled_ext(self): - self._test_requires_ext_helper(extension='disabled_ext', - service='compute') - - def test_requires_ext_decorator_with_all_ext_enabled(self): - cfg.CONF.set_default('api_extensions', ['all'], - group='compute-feature-enabled') - self._test_requires_ext_helper(expected_to_skip=False, - extension='random_ext', - service='compute') - - def test_requires_ext_decorator_bad_service(self): - self.assertRaises(KeyError, - self._test_requires_ext_helper, - extension='enabled_ext', - service='bad_service') - - -class TestConfigDecorators(BaseDecoratorsTest): - def setUp(self): - super(TestConfigDecorators, self).setUp() - cfg.CONF.set_default('nova', True, 'service_available') - cfg.CONF.set_default('glance', False, 'service_available') - - def _assert_skip_message(self, func, skip_msg): - try: - func() - self.fail() - except testtools.TestCase.skipException as skip_exc: - self.assertEqual(skip_exc.args[0], skip_msg) - - def _test_skip_unless_config(self, expected_to_skip=True, *decorator_args): - - class TestFoo(test.BaseTestCase): - @config.skip_unless_config(*decorator_args) - def test_bar(self): - return 0 - - t = TestFoo('test_bar') - if expected_to_skip: - self.assertRaises(testtools.TestCase.skipException, t.test_bar) - if (len(decorator_args) >= 3): - # decorator_args[2]: skip message specified - self._assert_skip_message(t.test_bar, decorator_args[2]) - else: - try: - self.assertEqual(t.test_bar(), 0) - except testtools.TestCase.skipException: - # We caught a skipException but we didn't expect to skip - # this test so raise a hard test failure instead. - raise testtools.TestCase.failureException( - "Not supposed to skip") - - def _test_skip_if_config(self, expected_to_skip=True, - *decorator_args): - - class TestFoo(test.BaseTestCase): - @config.skip_if_config(*decorator_args) - def test_bar(self): - return 0 - - t = TestFoo('test_bar') - if expected_to_skip: - self.assertRaises(testtools.TestCase.skipException, t.test_bar) - if (len(decorator_args) >= 3): - # decorator_args[2]: skip message specified - self._assert_skip_message(t.test_bar, decorator_args[2]) - else: - try: - self.assertEqual(t.test_bar(), 0) - except testtools.TestCase.skipException: - # We caught a skipException but we didn't expect to skip - # this test so raise a hard test failure instead. - raise testtools.TestCase.failureException( - "Not supposed to skip") - - def test_skip_unless_no_group(self): - self._test_skip_unless_config(True, 'fake_group', 'an_option') - - def test_skip_unless_no_option(self): - self._test_skip_unless_config(True, 'service_available', - 'not_an_option') - - def test_skip_unless_false_option(self): - self._test_skip_unless_config(True, 'service_available', 'glance') - - def test_skip_unless_false_option_msg(self): - self._test_skip_unless_config(True, 'service_available', 'glance', - 'skip message') - - def test_skip_unless_true_option(self): - self._test_skip_unless_config(False, - 'service_available', 'nova') - - def test_skip_if_no_group(self): - self._test_skip_if_config(False, 'fake_group', 'an_option') - - def test_skip_if_no_option(self): - self._test_skip_if_config(False, 'service_available', 'not_an_option') - - def test_skip_if_false_option(self): - self._test_skip_if_config(False, 'service_available', 'glance') - - def test_skip_if_true_option(self): - self._test_skip_if_config(True, 'service_available', 'nova') - - def test_skip_if_true_option_msg(self): - self._test_skip_if_config(True, 'service_available', 'nova', - 'skip message') diff --git a/tempest/tests/test_hacking.py b/tempest/tests/test_hacking.py deleted file mode 100644 index f005c219f..000000000 --- a/tempest/tests/test_hacking.py +++ /dev/null @@ -1,182 +0,0 @@ -# Copyright 2014 Matthew Treinish -# -# 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 tempest.hacking import checks -from tempest.tests import base - - -class HackingTestCase(base.TestCase): - """Test class for hacking rule - - This class tests the hacking checks in tempest.hacking.checks by passing - strings to the check methods like the pep8/flake8 parser would. The parser - loops over each line in the file and then passes the parameters to the - check method. The parameter names in the check method dictate what type of - object is passed to the check method. The parameter types are:: - - logical_line: A processed line with the following modifications: - - Multi-line statements converted to a single line. - - Stripped left and right. - - Contents of strings replaced with "xxx" of same length. - - Comments removed. - physical_line: Raw line of text from the input file. - lines: a list of the raw lines from the input file - tokens: the tokens that contribute to this logical line - line_number: line number in the input file - total_lines: number of lines in the input file - blank_lines: blank lines before this one - indent_char: indentation character in this file (" " or "\t") - indent_level: indentation (with tabs expanded to multiples of 8) - previous_indent_level: indentation on previous line - previous_logical: previous logical line - filename: Path of the file being run through pep8 - - When running a test on a check method the return will be False/None if - there is no violation in the sample input. If there is an error a tuple is - returned with a position in the line, and a message. So to check the result - just assertTrue if the check is expected to fail and assertFalse if it - should pass. - """ - def test_no_setup_teardown_class_for_tests(self): - self.assertTrue(checks.no_setup_teardown_class_for_tests( - " def setUpClass(cls):", './tempest/tests/fake_test.py')) - self.assertIsNone(checks.no_setup_teardown_class_for_tests( - " def setUpClass(cls): # noqa", './tempest/tests/fake_test.py')) - self.assertTrue(checks.no_setup_teardown_class_for_tests( - " def setUpClass(cls):", './tempest/api/fake_test.py')) - self.assertTrue(checks.no_setup_teardown_class_for_tests( - " def setUpClass(cls):", './tempest/scenario/fake_test.py')) - self.assertFalse(checks.no_setup_teardown_class_for_tests( - " def setUpClass(cls):", './tempest/test.py')) - self.assertTrue(checks.no_setup_teardown_class_for_tests( - " def tearDownClass(cls):", './tempest/tests/fake_test.py')) - self.assertIsNone(checks.no_setup_teardown_class_for_tests( - " def tearDownClass(cls): # noqa", './tempest/tests/fake_test.py')) - self.assertTrue(checks.no_setup_teardown_class_for_tests( - " def tearDownClass(cls):", './tempest/api/fake_test.py')) - self.assertTrue(checks.no_setup_teardown_class_for_tests( - " def tearDownClass(cls):", './tempest/scenario/fake_test.py')) - self.assertFalse(checks.no_setup_teardown_class_for_tests( - " def tearDownClass(cls):", './tempest/test.py')) - - def test_import_no_clients_in_api_and_scenario_tests(self): - for client in checks.PYTHON_CLIENTS: - string = "import " + client + "client" - self.assertTrue( - checks.import_no_clients_in_api_and_scenario_tests( - string, './tempest/api/fake_test.py')) - self.assertTrue( - checks.import_no_clients_in_api_and_scenario_tests( - string, './tempest/scenario/fake_test.py')) - self.assertFalse( - checks.import_no_clients_in_api_and_scenario_tests( - string, './tempest/test.py')) - - def test_scenario_tests_need_service_tags(self): - self.assertFalse(checks.scenario_tests_need_service_tags( - 'def test_fake:', './tempest/scenario/test_fake.py', - "@test.services('compute')")) - self.assertFalse(checks.scenario_tests_need_service_tags( - 'def test_fake_test:', './tempest/api/compute/test_fake.py', - "@test.services('image')")) - self.assertFalse(checks.scenario_tests_need_service_tags( - 'def test_fake:', './tempest/scenario/orchestration/test_fake.py', - "@test.services('compute')")) - self.assertTrue(checks.scenario_tests_need_service_tags( - 'def test_fake_test:', './tempest/scenario/test_fake.py', - '\n')) - self.assertTrue(checks.scenario_tests_need_service_tags( - 'def test_fake:', './tempest/scenario/orchestration/test_fake.py', - "\n")) - - def test_no_vi_headers(self): - # NOTE(mtreinish) The lines parameter is used only for finding the - # line location in the file. So these tests just pass a list of an - # arbitrary length to use for verifying the check function. - self.assertTrue(checks.no_vi_headers( - '# vim: tabstop=4 shiftwidth=4 softtabstop=4', 1, range(250))) - self.assertTrue(checks.no_vi_headers( - '# vim: tabstop=4 shiftwidth=4 softtabstop=4', 249, range(250))) - self.assertFalse(checks.no_vi_headers( - '# vim: tabstop=4 shiftwidth=4 softtabstop=4', 149, range(250))) - - def test_service_tags_not_in_module_path(self): - self.assertTrue(checks.service_tags_not_in_module_path( - "@test.services('compute')", './tempest/api/compute/fake_test.py')) - self.assertFalse(checks.service_tags_not_in_module_path( - "@test.services('compute')", - './tempest/scenario/compute/fake_test.py')) - self.assertFalse(checks.service_tags_not_in_module_path( - "@test.services('compute')", './tempest/api/image/fake_test.py')) - - def test_no_hyphen_at_end_of_rand_name(self): - self.assertIsNone(checks.no_hyphen_at_end_of_rand_name( - 'data_utils.rand_name("fake-resource")', './tempest/test_foo.py')) - self.assertEqual(2, len(list(checks.no_hyphen_at_end_of_rand_name( - 'data_utils.rand_name("fake-resource-")', './tempest/test_foo.py') - ))) - - def test_no_mutable_default_args(self): - self.assertEqual(1, len(list(checks.no_mutable_default_args( - " def function1(para={}):")))) - - self.assertEqual(1, len(list(checks.no_mutable_default_args( - "def function2(para1, para2, para3=[])")))) - - self.assertEqual(0, len(list(checks.no_mutable_default_args( - "defined = []")))) - - self.assertEqual(0, len(list(checks.no_mutable_default_args( - "defined, undefined = [], {}")))) - - def test_no_testtools_skip_decorator(self): - self.assertEqual(1, len(list(checks.no_testtools_skip_decorator( - " @testtools.skip('Bug xxx')")))) - self.assertEqual(0, len(list(checks.no_testtools_skip_decorator( - " @testtools.skipUnless(CONF.something, 'msg')")))) - self.assertEqual(0, len(list(checks.no_testtools_skip_decorator( - " @testtools.skipIf(CONF.something, 'msg')")))) - - def test_dont_import_local_tempest_code_into_lib(self): - self.assertEqual(0, len(list(checks.dont_import_local_tempest_into_lib( - "from tempest.common import waiters", - './tempest/common/compute.py')))) - self.assertEqual(0, len(list(checks.dont_import_local_tempest_into_lib( - "from tempest import config", - './tempest/common/compute.py')))) - self.assertEqual(0, len(list(checks.dont_import_local_tempest_into_lib( - "import tempest.exception", - './tempest/common/compute.py')))) - self.assertEqual(1, len(list(checks.dont_import_local_tempest_into_lib( - "from tempest.common import waiters", - './tempest/lib/common/compute.py')))) - self.assertEqual(1, len(list(checks.dont_import_local_tempest_into_lib( - "from tempest import config", - './tempest/lib/common/compute.py')))) - self.assertEqual(1, len(list(checks.dont_import_local_tempest_into_lib( - "import tempest.exception", - './tempest/lib/common/compute.py')))) - - def test_dont_use_config_in_tempest_lib(self): - self.assertFalse(list(checks.dont_use_config_in_tempest_lib( - 'from tempest import config', './tempest/common/compute.py'))) - self.assertFalse(list(checks.dont_use_config_in_tempest_lib( - 'from oslo_concurrency import lockutils', - './tempest/lib/auth.py'))) - self.assertTrue(list(checks.dont_use_config_in_tempest_lib( - 'from tempest import config', './tempest/lib/auth.py'))) - self.assertTrue(list(checks.dont_use_config_in_tempest_lib( - 'from oslo_config import cfg', './tempest/lib/decorators.py'))) - self.assertTrue(list(checks.dont_use_config_in_tempest_lib( - 'import tempest.config', './tempest/lib/common/rest_client.py'))) diff --git a/tempest/tests/test_list_tests.py b/tempest/tests/test_list_tests.py deleted file mode 100644 index a23887965..000000000 --- a/tempest/tests/test_list_tests.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2013 IBM Corp. -# -# 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 os -import re -import subprocess - -import six - -from tempest.tests import base - - -class TestTestList(base.TestCase): - - def test_testr_list_tests_no_errors(self): - # Remove unit test discover path from env to test tempest tests - test_env = os.environ.copy() - test_env.pop('OS_TEST_PATH') - import_failures = [] - p = subprocess.Popen(['testr', 'list-tests'], stdout=subprocess.PIPE, - env=test_env) - ids, err = p.communicate() - self.assertEqual(0, p.returncode, - "test discovery failed, one or more files cause an " - "error on import %s" % ids) - ids = six.text_type(ids).split('\n') - for test_id in ids: - if re.match('(\w+\.){3}\w+', test_id): - if not test_id.startswith('tempest.'): - parts = test_id.partition('tempest') - fail_id = parts[1] + parts[2] - import_failures.append(fail_id) - error_message = ("The following tests have import failures and aren't" - " being run with test filters %s" % import_failures) - self.assertFalse(import_failures, error_message) diff --git a/tempest/tests/test_microversions.py b/tempest/tests/test_microversions.py deleted file mode 100644 index 173accbd5..000000000 --- a/tempest/tests/test_microversions.py +++ /dev/null @@ -1,153 +0,0 @@ -# Copyright 2015 NEC Corporation. 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 oslo_config import cfg -import testtools - -from tempest.api.compute import base as compute_base -from tempest import config -from tempest.lib import exceptions -from tempest.tests import base -from tempest.tests import fake_config - - -class VersionTestNoneTolatest(compute_base.BaseV2ComputeTest): - min_microversion = None - max_microversion = 'latest' - - -class VersionTestNoneTo2_2(compute_base.BaseV2ComputeTest): - min_microversion = None - max_microversion = '2.2' - - -class VersionTest2_3ToLatest(compute_base.BaseV2ComputeTest): - min_microversion = '2.3' - max_microversion = 'latest' - - -class VersionTest2_5To2_10(compute_base.BaseV2ComputeTest): - min_microversion = '2.5' - max_microversion = '2.10' - - -class VersionTest2_10To2_10(compute_base.BaseV2ComputeTest): - min_microversion = '2.10' - max_microversion = '2.10' - - -class InvalidVersionTest(compute_base.BaseV2ComputeTest): - min_microversion = '2.11' - max_microversion = '2.1' - - -class TestMicroversionsTestsClass(base.TestCase): - - def setUp(self): - super(TestMicroversionsTestsClass, self).setUp() - self.useFixture(fake_config.ConfigFixture()) - self.patchobject(config, 'TempestConfigPrivate', - fake_config.FakePrivate) - - def _test_version(self, cfg_min, cfg_max, - expected_pass_tests, - expected_skip_tests): - cfg.CONF.set_default('min_microversion', - cfg_min, group='compute') - cfg.CONF.set_default('max_microversion', - cfg_max, group='compute') - try: - for test_class in expected_pass_tests: - test_class.skip_checks() - for test_class in expected_skip_tests: - self.assertRaises(testtools.TestCase.skipException, - test_class.skip_checks) - except testtools.TestCase.skipException as e: - raise testtools.TestCase.failureException(e.message) - - def test_config_version_none_none(self): - expected_pass_tests = [VersionTestNoneTolatest, VersionTestNoneTo2_2] - expected_skip_tests = [VersionTest2_3ToLatest, VersionTest2_5To2_10, - VersionTest2_10To2_10] - self._test_version(None, None, - expected_pass_tests, - expected_skip_tests) - - def test_config_version_none_23(self): - expected_pass_tests = [VersionTestNoneTolatest, VersionTestNoneTo2_2, - VersionTest2_3ToLatest] - expected_skip_tests = [VersionTest2_5To2_10, VersionTest2_10To2_10] - self._test_version(None, '2.3', - expected_pass_tests, - expected_skip_tests) - - def test_config_version_22_latest(self): - expected_pass_tests = [VersionTestNoneTolatest, VersionTestNoneTo2_2, - VersionTest2_3ToLatest, VersionTest2_5To2_10, - VersionTest2_10To2_10] - expected_skip_tests = [] - self._test_version('2.2', 'latest', - expected_pass_tests, - expected_skip_tests) - - def test_config_version_22_23(self): - expected_pass_tests = [VersionTestNoneTolatest, VersionTestNoneTo2_2, - VersionTest2_3ToLatest] - expected_skip_tests = [VersionTest2_5To2_10, VersionTest2_10To2_10] - self._test_version('2.2', '2.3', - expected_pass_tests, - expected_skip_tests) - - def test_config_version_210_210(self): - expected_pass_tests = [VersionTestNoneTolatest, - VersionTest2_3ToLatest, - VersionTest2_5To2_10, - VersionTest2_10To2_10] - expected_skip_tests = [VersionTestNoneTo2_2] - self._test_version('2.10', '2.10', - expected_pass_tests, - expected_skip_tests) - - def test_config_version_none_latest(self): - expected_pass_tests = [VersionTestNoneTolatest, VersionTestNoneTo2_2, - VersionTest2_3ToLatest, VersionTest2_5To2_10, - VersionTest2_10To2_10] - expected_skip_tests = [] - self._test_version(None, 'latest', - expected_pass_tests, - expected_skip_tests) - - def test_config_version_latest_latest(self): - expected_pass_tests = [VersionTestNoneTolatest, VersionTest2_3ToLatest] - expected_skip_tests = [VersionTestNoneTo2_2, VersionTest2_5To2_10, - VersionTest2_10To2_10] - self._test_version('latest', 'latest', - expected_pass_tests, - expected_skip_tests) - - def test_config_invalid_version(self): - cfg.CONF.set_default('min_microversion', - '2.5', group='compute') - cfg.CONF.set_default('max_microversion', - '2.1', group='compute') - self.assertRaises(exceptions.InvalidAPIVersionRange, - VersionTestNoneTolatest.skip_checks) - - def test_config_version_invalid_test_version(self): - cfg.CONF.set_default('min_microversion', - None, group='compute') - cfg.CONF.set_default('max_microversion', - '2.13', group='compute') - self.assertRaises(exceptions.InvalidAPIVersionRange, - InvalidVersionTest.skip_checks) diff --git a/tempest/tests/test_tempest_plugin.py b/tempest/tests/test_tempest_plugin.py deleted file mode 100644 index 13e249937..000000000 --- a/tempest/tests/test_tempest_plugin.py +++ /dev/null @@ -1,79 +0,0 @@ -# Copyright (c) 2015 Deutsche Telekom AG -# 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 tempest.lib.services import clients -from tempest.test_discover import plugins -from tempest.tests import base -from tempest.tests import fake_tempest_plugin as fake_plugin - - -class TestPluginDiscovery(base.TestCase): - def test_load_tests_with_one_plugin(self): - # we can't mock stevedore since it's a singleton and already executed - # during test discovery. So basically this test covers the plugin loop - # and the abstract plugin interface. - manager = plugins.TempestTestPluginManager() - fake_obj = fake_plugin.FakeStevedoreObj() - manager.ext_plugins = [fake_obj] - result = manager.get_plugin_load_tests_tuple() - - self.assertEqual(fake_plugin.FakePlugin.expected_load_test, - result[fake_obj.name]) - - def test_load_tests_with_two_plugins(self): - manager = plugins.TempestTestPluginManager() - obj1 = fake_plugin.FakeStevedoreObj('fake01') - obj2 = fake_plugin.FakeStevedoreObj('fake02') - manager.ext_plugins = [obj1, obj2] - result = manager.get_plugin_load_tests_tuple() - - self.assertEqual(fake_plugin.FakePlugin.expected_load_test, - result['fake01']) - self.assertEqual(fake_plugin.FakePlugin.expected_load_test, - result['fake02']) - - def test__register_service_clients_with_one_plugin(self): - registry = clients.ClientsRegistry() - manager = plugins.TempestTestPluginManager() - fake_obj = fake_plugin.FakeStevedoreObj() - manager.ext_plugins = [fake_obj] - manager._register_service_clients() - expected_result = fake_plugin.FakePlugin.expected_service_clients - registered_clients = registry.get_service_clients() - self.assertIn(fake_obj.name, registered_clients) - self.assertEqual(expected_result, registered_clients[fake_obj.name]) - - def test__get_service_clients_with_two_plugins(self): - registry = clients.ClientsRegistry() - manager = plugins.TempestTestPluginManager() - obj1 = fake_plugin.FakeStevedoreObj('fake01') - obj2 = fake_plugin.FakeStevedoreObj('fake02') - manager.ext_plugins = [obj1, obj2] - manager._register_service_clients() - expected_result = fake_plugin.FakePlugin.expected_service_clients - registered_clients = registry.get_service_clients() - self.assertIn('fake01', registered_clients) - self.assertIn('fake02', registered_clients) - self.assertEqual(expected_result, registered_clients['fake01']) - self.assertEqual(expected_result, registered_clients['fake02']) - - def test__register_service_clients_one_plugin_no_service_clients(self): - registry = clients.ClientsRegistry() - manager = plugins.TempestTestPluginManager() - fake_obj = fake_plugin.FakeStevedoreObjNoServiceClients() - manager.ext_plugins = [fake_obj] - manager._register_service_clients() - registered_clients = registry.get_service_clients() - self.assertNotIn(fake_obj.name, registered_clients) diff --git a/tempest/tests/utils.py b/tempest/tests/utils.py deleted file mode 100644 index 9c3049dc7..000000000 --- a/tempest/tests/utils.py +++ /dev/null @@ -1,29 +0,0 @@ -# Copyright 2016 OpenStack Foundation -# -# 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. -# - - -def generate_timeout_series(timeout): - """Generate a series of times that exceeds the given timeout. - - Yields a series of fake time.time() floating point numbers - such that the difference between each pair in the series just - exceeds the timeout value that is passed in. Useful for - mocking time.time() in methods that otherwise wait for timeout - seconds. - """ - iteration = 0 - while True: - iteration += 1 - yield (iteration * timeout) + iteration diff --git a/tempest/version.py b/tempest/version.py deleted file mode 100644 index bc9f65137..000000000 --- a/tempest/version.py +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2016 Hewlett-Packard Enterprise Development Company, L.P. -# -# 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 pbr.version - -version_info = pbr.version.VersionInfo('tempest') diff --git a/test-requirements.txt b/test-requirements.txt deleted file mode 100644 index 6a5ea0300..000000000 --- a/test-requirements.txt +++ /dev/null @@ -1,12 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. -hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0 -# needed for doc build -sphinx>=1.6.2 # BSD -openstackdocstheme>=1.11.0 # Apache-2.0 -reno!=2.3.1,>=1.8.0 # Apache-2.0 -mock>=2.0 # BSD -coverage!=4.4,>=4.0 # Apache-2.0 -oslotest>=1.10.0 # Apache-2.0 -flake8-import-order==0.11 # LGPLv3 diff --git a/tools/check_logs.py b/tools/check_logs.py deleted file mode 100755 index fc21f755d..000000000 --- a/tools/check_logs.py +++ /dev/null @@ -1,196 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2013 Red Hat, Inc. -# 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 argparse -import gzip -import os -import re -import sys - -import six -import six.moves.urllib.request as urlreq -import yaml - -# DEVSTACK_GATE_GRENADE is either unset if grenade is not running -# or a string describing what type of grenade run to perform. -is_grenade = os.environ.get('DEVSTACK_GATE_GRENADE') is not None -dump_all_errors = True - -# As logs are made clean, remove from this set -allowed_dirty = set([ - 'c-api', - 'ceilometer-acentral', - 'ceilometer-acompute', - 'ceilometer-alarm-evaluator', - 'ceilometer-anotification', - 'ceilometer-api', - 'ceilometer-collector', - 'c-vol', - 'g-api', - 'h-api', - 'h-eng', - 'ir-cond', - 'n-api', - 'n-cpu', - 'n-net', - 'q-agt', - 'q-dhcp', - 'q-lbaas', - 'q-meta', - 'q-metering', - 'q-svc', - 's-proxy']) - - -def process_files(file_specs, url_specs, whitelists): - regexp = re.compile(r"^.* (ERROR|CRITICAL|TRACE) .*\[.*\-.*\]") - logs_with_errors = [] - for (name, filename) in file_specs: - whitelist = whitelists.get(name, []) - with open(filename) as content: - if scan_content(name, content, regexp, whitelist): - logs_with_errors.append(name) - for (name, url) in url_specs: - whitelist = whitelists.get(name, []) - req = urlreq.Request(url) - req.add_header('Accept-Encoding', 'gzip') - page = urlreq.urlopen(req) - buf = six.StringIO(page.read()) - f = gzip.GzipFile(fileobj=buf) - if scan_content(name, f.read().splitlines(), regexp, whitelist): - logs_with_errors.append(name) - return logs_with_errors - - -def scan_content(name, content, regexp, whitelist): - had_errors = False - for line in content: - if not line.startswith("Stderr:") and regexp.match(line): - whitelisted = False - for w in whitelist: - pat = ".*%s.*%s.*" % (w['module'].replace('.', '\\.'), - w['message']) - if re.match(pat, line): - whitelisted = True - break - if not whitelisted or dump_all_errors: - if not whitelisted: - had_errors = True - return had_errors - - -def collect_url_logs(url): - page = urlreq.urlopen(url) - content = page.read() - logs = re.findall('(screen-[\w-]+\.txt\.gz)', content) - return logs - - -def main(opts): - if opts.directory and opts.url or not (opts.directory or opts.url): - print("Must provide exactly one of -d or -u") - return 1 - print("Checking logs...") - WHITELIST_FILE = os.path.join( - os.path.abspath(os.path.dirname(os.path.dirname(__file__))), - "etc", "whitelist.yaml") - - file_matcher = re.compile(r".*screen-([\w-]+)\.log") - files = [] - if opts.directory: - d = opts.directory - for f in os.listdir(d): - files.append(os.path.join(d, f)) - files_to_process = [] - for f in files: - m = file_matcher.match(f) - if m: - files_to_process.append((m.group(1), f)) - - url_matcher = re.compile(r".*screen-([\w-]+)\.txt\.gz") - urls = [] - if opts.url: - for logfile in collect_url_logs(opts.url): - urls.append("%s/%s" % (opts.url, logfile)) - urls_to_process = [] - for u in urls: - m = url_matcher.match(u) - if m: - urls_to_process.append((m.group(1), u)) - - whitelists = {} - with open(WHITELIST_FILE) as stream: - loaded = yaml.safe_load(stream) - if loaded: - for (name, l) in six.iteritems(loaded): - for w in l: - assert 'module' in w, 'no module in %s' % name - assert 'message' in w, 'no message in %s' % name - whitelists = loaded - logs_with_errors = process_files(files_to_process, urls_to_process, - whitelists) - - failed = False - if logs_with_errors: - log_files = set(logs_with_errors) - for log in log_files: - msg = '%s log file has errors' % log - if log not in allowed_dirty: - msg += ' and is not allowed to have them' - failed = True - print(msg) - print("\nPlease check the respective log files to see the errors") - if failed: - if is_grenade: - print("Currently not failing grenade runs with errors") - return 0 - return 1 - print("ok") - return 0 - -usage = """ -Find non-white-listed log errors in log files from a devstack-gate run. -Log files will be searched for ERROR or CRITICAL messages. If any -error messages do not match any of the whitelist entries contained in -etc/whitelist.yaml, those messages will be printed to the console and -failure will be returned. A file directory containing logs or a url to the -log files of an OpenStack gate job can be provided. - -The whitelist yaml looks like: - -log-name: - - module: "a.b.c" - message: "regexp" - - module: "a.b.c" - message: "regexp" - -repeated for each log file with a whitelist. -""" - -parser = argparse.ArgumentParser(description=usage) -parser.add_argument('-d', '--directory', - help="Directory containing log files") -parser.add_argument('-u', '--url', - help="url containing logs from an OpenStack gate job") - -if __name__ == "__main__": - try: - sys.exit(main(parser.parse_args())) - except Exception as e: - print("Failure in script: %s" % e) - # Don't fail if there is a problem with the script. - sys.exit(0) diff --git a/tools/find_stack_traces.py b/tools/find_stack_traces.py deleted file mode 100755 index 1f2b88b44..000000000 --- a/tools/find_stack_traces.py +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2013 IBM 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 gzip -import pprint -import re -import sys - -import six -import six.moves.urllib.request as urlreq - - -pp = pprint.PrettyPrinter() - -NOVA_TIMESTAMP = r"\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d\.\d\d\d" - -NOVA_REGEX = r"(?P%s) (?P\d+ )?(?P(ERROR|TRACE)) " \ - "(?P[\w\.]+) (?P.*)" % (NOVA_TIMESTAMP) - - -class StackTrace(object): - timestamp = None - pid = None - level = "" - module = "" - msg = "" - - def __init__(self, timestamp=None, pid=None, level="", module="", - msg=""): - self.timestamp = timestamp - self.pid = pid - self.level = level - self.module = module - self.msg = msg - - def append(self, msg): - self.msg = self.msg + msg - - def is_same(self, data): - return (data['timestamp'] == self.timestamp and - data['level'] == self.level) - - def not_none(self): - return self.timestamp is not None - - def __str__(self): - buff = "<%s %s %s>\n" % (self.timestamp, self.level, self.module) - for line in self.msg.splitlines(): - buff = buff + line + "\n" - return buff - - -def hunt_for_stacktrace(url): - """Return TRACE or ERROR lines out of logs.""" - req = urlreq.Request(url) - req.add_header('Accept-Encoding', 'gzip') - page = urlreq.urlopen(req) - buf = six.StringIO(page.read()) - f = gzip.GzipFile(fileobj=buf) - content = f.read() - - traces = [] - trace = StackTrace() - for line in content.splitlines(): - m = re.match(NOVA_REGEX, line) - if m: - data = m.groupdict() - if trace.not_none() and trace.is_same(data): - trace.append(data['msg'] + "\n") - else: - trace = StackTrace( - timestamp=data.get('timestamp'), - pid=data.get('pid'), - level=data.get('level'), - module=data.get('module'), - msg=data.get('msg')) - - else: - if trace.not_none(): - traces.append(trace) - trace = StackTrace() - - # once more at the end to pick up any stragglers - if trace.not_none(): - traces.append(trace) - - return traces - - -def log_url(url, log): - return "%s/%s" % (url, log) - - -def collect_logs(url): - page = urlreq.urlopen(url) - content = page.read() - logs = re.findall('(screen-[\w-]+\.txt\.gz)', content) - return logs - - -def usage(): - print(""" -Usage: find_stack_traces.py - -Hunts for stack traces in a devstack run. Must provide it a base log url -from a tempest devstack run. Should start with http and end with /logs/. - -Returns a report listing stack traces out of the various files where -they are found. -""") - sys.exit(0) - - -def print_stats(items, fname, verbose=False): - errors = len([x for x in items if x.level == "ERROR"]) - traces = len([x for x in items if x.level == "TRACE"]) - print("%d ERRORS found in %s" % (errors, fname)) - print("%d TRACES found in %s" % (traces, fname)) - - if verbose: - for item in items: - print(item) - print("\n\n") - - -def main(): - if len(sys.argv) == 2: - url = sys.argv[1] - loglist = collect_logs(url) - - # probably wrong base url - if not loglist: - usage() - - for log in loglist: - logurl = log_url(url, log) - traces = hunt_for_stacktrace(logurl) - - if traces: - print_stats(traces, log, verbose=True) - - else: - usage() - -if __name__ == '__main__': - main() diff --git a/tools/generate-tempest-plugins-list.py b/tools/generate-tempest-plugins-list.py deleted file mode 100644 index 99df0d120..000000000 --- a/tools/generate-tempest-plugins-list.py +++ /dev/null @@ -1,89 +0,0 @@ -#! /usr/bin/env python - -# Copyright 2016 Hewlett Packard Enterprise Development Company, L.P. -# -# 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. - -# This script is intended to be run as part of a periodic proposal bot -# job in OpenStack infrastructure. -# -# In order to function correctly, the environment in which the -# script runs must have -# * network access to the review.openstack.org Gerrit API -# working directory -# * network access to https://git.openstack.org/cgit - -import json -import re - -try: - # For Python 3.0 and later - from urllib.error import HTTPError as HTTPError - import urllib.request as urllib -except ImportError: - # Fall back to Python 2's urllib2 - import urllib2 as urllib - from urllib2 import HTTPError as HTTPError - - -url = 'https://review.openstack.org/projects/' - -# This is what a project looks like -''' - "openstack-attic/akanda": { - "id": "openstack-attic%2Fakanda", - "state": "READ_ONLY" - }, -''' - - -def is_in_openstack_namespace(proj): - return proj.startswith('openstack/') - -# Rather than returning a 404 for a nonexistent file, cgit delivers a -# 0-byte response to a GET request. It also does not provide a -# Content-Length in a HEAD response, so the way we tell if a file exists -# is to check the length of the entire GET response body. - - -def has_tempest_plugin(proj): - try: - r = urllib.urlopen( - "https://git.openstack.org/cgit/%s/plain/setup.cfg" % proj) - except HTTPError as err: - if err.code == 404: - return False - p = re.compile('^tempest\.test_plugins', re.M) - if p.findall(r.read().decode('utf-8')): - return True - else: - False - -r = urllib.urlopen(url) -# Gerrit prepends 4 garbage octets to the JSON, in order to counter -# cross-site scripting attacks. Therefore we must discard it so the -# json library won't choke. -projects = sorted(filter(is_in_openstack_namespace, json.loads(r.read()[4:]))) - -# Retrieve projects having no deb, ui or spec namespace as those namespaces -# do not contains tempest plugins. -projects_list = [i for i in projects if not (i.startswith('openstack/deb-') or - i.endswith('-ui') or - i.endswith('-specs'))] - -found_plugins = list(filter(has_tempest_plugin, projects_list)) - -# Every element of the found_plugins list begins with "openstack/". -# We drop those initial 10 octets when printing the list. -for project in found_plugins: - print(project[10:]) diff --git a/tools/generate-tempest-plugins-list.sh b/tools/generate-tempest-plugins-list.sh deleted file mode 100755 index e6aad8695..000000000 --- a/tools/generate-tempest-plugins-list.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2016 Hewlett Packard Enterprise Development Company, L.P. -# -# 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. - -# This script is intended to be run as a periodic proposal bot job -# in OpenStack infrastructure, though you can run it as a one-off. -# -# In order to function correctly, the environment in which the -# script runs must have -# * a writable doc/source directory relative to the current -# working directory -# AND ( ( -# * git -# * all git repos meant to be searched for plugins cloned and -# at the desired level of up-to-datedness -# * the environment variable git_dir pointing to the location -# * of said git repositories -# ) OR ( -# * network access to the review.openstack.org Gerrit API -# working directory -# * network access to https://git.openstack.org/cgit -# )) -# -# If a file named data/tempest-plugins-registry.header or -# data/tempest-plugins-registry.footer is found relative to the -# current working directory, it will be prepended or appended to -# the generated reStructuredText plugins table respectively. - -set -ex - -( -declare -A plugins - -if [[ -r data/tempest-plugins-registry.header ]]; then - cat data/tempest-plugins-registry.header -fi - -sorted_plugins=$(python tools/generate-tempest-plugins-list.py) - -for k in ${sorted_plugins}; do - project=${k:0:28} - giturl="git://git.openstack.org/openstack/${k:0:26}" - printf "|%-28s|%-73s|\n" "${project}" "${giturl}" - printf "+----------------------------+-------------------------------------------------------------------------+\n" -done - -if [[ -r data/tempest-plugins-registry.footer ]]; then - cat data/tempest-plugins-registry.footer -fi -) > doc/source/plugin-registry.rst - -if [[ -n ${1} ]]; then - cp doc/source/plugin-registry.rst ${1}/doc/source/plugin-registry.rst -fi diff --git a/tools/skip_tracker.py b/tools/skip_tracker.py deleted file mode 100755 index 44f5874db..000000000 --- a/tools/skip_tracker.py +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2012 OpenStack Foundation -# 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. - -""" -Track test skips via launchpadlib API and raise alerts if a bug -is fixed but a skip is still in the Tempest test code -""" - -from tempest.lib.cmd import skip_tracker - - -if __name__ == '__main__': - print("DEPRECATED: `skip_tracker.py` is already deprecated, " - "use `skip-tracker` command instead.") - skip_tracker.main() diff --git a/tools/tempest-plugin-sanity.sh b/tools/tempest-plugin-sanity.sh deleted file mode 100644 index a4f706e01..000000000 --- a/tools/tempest-plugin-sanity.sh +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env bash - -# Copyright 2017 Red Hat, Inc. -# 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. - -# This script is intended to check the sanity of tempest plugins against -# tempest master. -# What it does: -# * Creates the virtualenv -# * Install tempest -# * Retrive the project lists having tempest plugin if project name is -# given. -# * For each project in a list, It does: -# * Clone the Project -# * Install the Project and also installs dependencies from -# test-requirements.txt. -# * Create Tempest workspace -# * List tempest plugins -# * List tempest plugins tests -# * Uninstall the project and its dependencies -# * Again Install tempest -# * Again repeat the step from cloning project -# -# If one of the step fails, The script will exit with failure. - -if [ "$1" == "-h" ]; then - echo -e "This script performs the sanity of tempest plugins to find -configuration and dependency issues with the tempest.\n -Usage: sh ./tools/tempest-plugin-sanity.sh [Run sanity on tempest plugins]" - exit 0 -fi - -set -ex - -# retrieve a list of projects having tempest plugins -PROJECT_LIST="$(python tools/generate-tempest-plugins-list.py)" -# List of projects having tempest plugin stale or unmaintained from long time -BLACKLIST="trio2o" - -# Function to clone project using zuul-cloner or from git -function clone_project() { - if [ -e /usr/zuul-env/bin/zuul-cloner ]; then - /usr/zuul-env/bin/zuul-cloner --cache-dir /opt/git \ - git://git.openstack.org \ - openstack/"$1" - - elif [ -e /usr/bin/git ]; then - /usr/bin/git clone git://git.openstack.org/openstack/"$1" \ - openstack/"$1" - - fi -} - -# Create virtualenv to perform sanity operation -SANITY_DIR=$(pwd) -virtualenv "$SANITY_DIR"/.venv -export TVENV="$SANITY_DIR/tools/with_venv.sh" -cd "$SANITY_DIR" - -# Install tempest in a venv -"$TVENV" pip install . - -# Function to install project -function install_project() { - "$TVENV" pip install "$SANITY_DIR"/openstack/"$1" - # Check for test-requirements.txt file in a project then install it. - if [ -e "$SANITY_DIR"/openstack/"$1"/test-requirements.txt ]; then - "$TVENV" pip install -r "$SANITY_DIR"/openstack/"$1"/test-requirements.txt - fi -} - -# Function to perform sanity checking on Tempest plugin -function tempest_sanity() { - "$TVENV" tempest init "$SANITY_DIR"/tempest_sanity - cd "$SANITY_DIR"/tempest_sanity - "$TVENV" tempest list-plugins - "$TVENV" tempest run -l - # Delete tempest workspace - "$TVENV" tempest workspace remove --name tempest_sanity --rmdir - cd "$SANITY_DIR" -} - -# Function to uninstall project -function uninstall_project() { - "$TVENV" pip uninstall -y "$SANITY_DIR"/openstack/"$1" - # Check for *requirements.txt file in a project then uninstall it. - if [ -e "$SANITY_DIR"/openstack/"$1"/*requirements.txt ]; then - "$TVENV" pip uninstall -y -r "$SANITY_DIR"/openstack/"$1"/*requirements.txt - fi - # Remove the project directory after sanity run - rm -fr "$SANITY_DIR"/openstack/"$1" -} - -# Function to run sanity check on each project -function plugin_sanity_check() { - clone_project "$1" && install_project "$1" && tempest_sanity "$1" \ - && uninstall_project "$1" && "$TVENV" pip install . -} - -# Log status -passed_plugin='' -failed_plugin='' -# Perform sanity on all tempest plugin projects -for project in $PROJECT_LIST; do - # Remove blacklisted tempest plugins - if ! [[ `echo $BLACKLIST | grep -c $project ` -gt 0 ]]; then - plugin_sanity_check $project && passed_plugin+=", $project" || \ - failed_plugin+=", $project" - fi -done diff --git a/tools/tox_install.sh b/tools/tox_install.sh deleted file mode 100755 index 43468e450..000000000 --- a/tools/tox_install.sh +++ /dev/null @@ -1,30 +0,0 @@ -#!/usr/bin/env bash - -# Client constraint file contains this client version pin that is in conflict -# with installing the client from source. We should remove the version pin in -# the constraints file before applying it for from-source installation. - -CONSTRAINTS_FILE=$1 -shift 1 - -set -e - -# NOTE(tonyb): Place this in the tox enviroment's log dir so it will get -# published to logs.openstack.org for easy debugging. -localfile="$VIRTUAL_ENV/log/upper-constraints.txt" - -if [[ $CONSTRAINTS_FILE != http* ]]; then - CONSTRAINTS_FILE=file://$CONSTRAINTS_FILE -fi -# NOTE(tonyb): need to add curl to bindep.txt if the project supports bindep -curl $CONSTRAINTS_FILE --insecure --progress-bar --output $localfile - -pip install -c$localfile openstack-requirements - -# This is the main purpose of the script: Allow local installation of -# the current repo. It is listed in constraints file and thus any -# install will be constrained and we need to unconstrain it. -edit-constraints $localfile -- $CLIENT_NAME - -pip install -c$localfile -U $* -exit $? diff --git a/tools/with_venv.sh b/tools/with_venv.sh deleted file mode 100755 index 408b5f132..000000000 --- a/tools/with_venv.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash -TOOLS_PATH=${TOOLS_PATH:-$(dirname $0)/../} -VENV_PATH=${VENV_PATH:-${TOOLS_PATH}} -VENV_DIR=${VENV_DIR:-/.venv} -VENV=${VENV:-${VENV_PATH}/${VENV_DIR}} -source ${VENV}/bin/activate && "$@" diff --git a/tox.ini b/tox.ini deleted file mode 100644 index 6f37d00e5..000000000 --- a/tox.ini +++ /dev/null @@ -1,193 +0,0 @@ -[tox] -envlist = pep8,py35,py27,pip-check-reqs -minversion = 2.3.1 -skipsdist = True - -[tempestenv] -sitepackages = False -setenv = - VIRTUAL_ENV={envdir} - OS_TEST_PATH=./tempest/test_discover - BRANCH_NAME=master - CLIENT_NAME=tempest -deps = - -r{toxinidir}/requirements.txt - -[testenv] -setenv = - VIRTUAL_ENV={envdir} - OS_TEST_PATH=./tempest/tests - PYTHONWARNINGS=default::DeprecationWarning - BRANCH_NAME=master - CLIENT_NAME=tempest -passenv = OS_STDOUT_CAPTURE OS_STDERR_CAPTURE OS_TEST_TIMEOUT OS_TEST_LOCK_PATH OS_TEST_PATH TEMPEST_CONFIG TEMPEST_CONFIG_DIR http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY ZUUL_CACHE_DIR REQUIREMENTS_PIP_LOCATION GENERATE_TEMPEST_PLUGIN_LIST -usedevelop = True -install_command = - {toxinidir}/tools/tox_install.sh {env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages} -whitelist_externals = * -deps = - -r{toxinidir}/requirements.txt - -r{toxinidir}/test-requirements.txt -commands = - find . -type f -name "*.pyc" -delete - ostestr {posargs} - -[testenv:genconfig] -commands = oslo-config-generator --config-file tempest/cmd/config-generator.tempest.conf - -[testenv:cover] -commands = python setup.py testr --coverage --testr-arg='tempest\.tests {posargs}' - -[testenv:all] -envdir = .tox/tempest -sitepackages = {[tempestenv]sitepackages} -# 'all' includes slow tests -setenv = - {[tempestenv]setenv} - OS_TEST_TIMEOUT={env:OS_TEST_TIMEOUT:1200} -deps = {[tempestenv]deps} -commands = - find . -type f -name "*.pyc" -delete - tempest run --regex {posargs} - -[testenv:ostestr] -sitepackages = {[tempestenv]sitepackages} -# 'all' includes slow tests -setenv = - {[tempestenv]setenv} - OS_TEST_TIMEOUT={env:OS_TEST_TIMEOUT:1200} -deps = {[tempestenv]deps} -commands = - find . -type f -name "*.pyc" -delete - ostestr {posargs} - -[testenv:all-plugin] -sitepackages = True -# 'all' includes slow tests -setenv = - {[tempestenv]setenv} - OS_TEST_TIMEOUT={env:OS_TEST_TIMEOUT:1200} -deps = {[tempestenv]deps} -commands = - find . -type f -name "*.pyc" -delete - tempest run --regex {posargs} - -[testenv:full] -envdir = .tox/tempest -sitepackages = {[tempestenv]sitepackages} -setenv = {[tempestenv]setenv} -deps = {[tempestenv]deps} -# The regex below is used to select which tests to run and exclude the slow tag: -# See the testrepository bug: https://bugs.launchpad.net/testrepository/+bug/1208610 -commands = - find . -type f -name "*.pyc" -delete - tempest run --regex '(?!.*\[.*\bslow\b.*\])(^tempest\.api)' {posargs} - tempest run --combine --serial --regex '(?!.*\[.*\bslow\b.*\])(^tempest\.scenario)' {posargs} - -[testenv:full-serial] -envdir = .tox/tempest -sitepackages = {[tempestenv]sitepackages} -setenv = {[tempestenv]setenv} -deps = {[tempestenv]deps} -# The regex below is used to select which tests to run and exclude the slow tag: -# See the testrepository bug: https://bugs.launchpad.net/testrepository/+bug/1208610 -commands = - find . -type f -name "*.pyc" -delete - tempest run --serial --regex '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario))' {posargs} - -[testenv:scenario] -envdir = .tox/tempest -sitepackages = {[tempestenv]sitepackages} -setenv = {[tempestenv]setenv} -deps = {[tempestenv]deps} -# The regex below is used to select all scenario tests -commands = - find . -type f -name "*.pyc" -delete - tempest run --serial --regex '(^tempest\.scenario)' {posargs} - -[testenv:smoke] -envdir = .tox/tempest -sitepackages = {[tempestenv]sitepackages} -setenv = {[tempestenv]setenv} -deps = {[tempestenv]deps} -commands = - find . -type f -name "*.pyc" -delete - tempest run --regex '\[.*\bsmoke\b.*\]' {posargs} - -[testenv:smoke-serial] -envdir = .tox/tempest -sitepackages = {[tempestenv]sitepackages} -setenv = {[tempestenv]setenv} -deps = {[tempestenv]deps} -# This is still serial because neutron doesn't work with parallel. See: -# https://bugs.launchpad.net/tempest/+bug/1216076 so the neutron smoke -# job would fail if we moved it to parallel. -commands = - find . -type f -name "*.pyc" -delete - tempest run --serial --regex '\[.*\bsmoke\b.*\]' {posargs} - -[testenv:venv] -commands = {posargs} - -[testenv:venv-tempest] -envdir = .tox/tempest -sitepackages = {[tempestenv]sitepackages} -setenv = {[tempestenv]setenv} -deps = {[tempestenv]deps} -commands = {posargs} - -[testenv:docs] -commands = - python setup.py build_sphinx {posargs} - -[testenv:pep8] -commands = - flake8 {posargs} - check-uuid - -[testenv:uuidgen] -commands = - check-uuid --fix - -[hacking] -local-check-factory = tempest.hacking.checks.factory -import_exceptions = tempest.services - -[flake8] -# E125 is a won't fix until https://github.com/jcrocholl/pep8/issues/126 is resolved. For further detail see https://review.openstack.org/#/c/36788/ -# E123 skipped because it is ignored by default in the default pep8 -# E129 skipped because it is too limiting when combined with other rules -ignore = E125,E123,E129 -show-source = True -exclude = .git,.venv,.tox,dist,doc,*egg -enable-extensions = H106,H203,H904 -import-order-style = pep8 - -[testenv:releasenotes] -commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html - -[testenv:pip-check-reqs] -# Do not install test-requirements as that will pollute the virtualenv for -# determining missing packages. -# This also means that pip-check-reqs must be installed separately, outside -# of the requirements.txt files -deps = pip_check_reqs - -r{toxinidir}/requirements.txt -commands= - pip-extra-reqs -d --ignore-file=tempest/tests/* tempest - pip-missing-reqs -d --ignore-file=tempest/tests/* tempest - - -[testenv:bindep] -# Do not install any requirements. We want this to be fast and work even if -# system dependencies are missing, since it's used to tell you what system -# dependencies are missing! This also means that bindep must be installed -# separately, outside of the requirements files. -deps = bindep -commands = bindep test - -[testenv:plugin-sanity-check] -# perform tempest plugin sanity -whitelist_externals = bash -commands = - bash tools/tempest-plugin-sanity.sh