Merge "Use find_test_caller in test_utils instead of in misc"
diff --git a/README.rst b/README.rst
index 725a890..fe65dcd 100644
--- a/README.rst
+++ b/README.rst
@@ -70,12 +70,12 @@
it's recommended that you copy or rename tempest.conf.sample to tempest.conf
and make those changes to that file in /etc/tempest
-#. Setup a local working Tempest dir. This is done by using the tempest init
+#. Setup a local Tempest workspace. This is done by using the tempest init
command::
$ tempest init cloud-01
- works the same as::
+ which also works the same as::
$ mkdir cloud-01 && cd cloud-01 && tempest init
@@ -91,8 +91,19 @@
any changes to it otherwise Tempest will not know how to load it.
#. Once the configuration is done you're now ready to run Tempest. This can
- be done with testr directly or any `testr`_ based test runner, like
- `ostestr`_. For example, from the working dir running::
+ 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 regarless 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))'
diff --git a/doc/source/run.rst b/doc/source/run.rst
index 07fa5f7..ce7f03e 100644
--- a/doc/source/run.rst
+++ b/doc/source/run.rst
@@ -1,3 +1,5 @@
+.. _tempest_run:
+
-----------
Tempest Run
-----------
diff --git a/requirements.txt b/requirements.txt
index 7d01f69..84be219 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -14,7 +14,7 @@
oslo.i18n>=2.1.0 # Apache-2.0
oslo.log>=1.14.0 # Apache-2.0
oslo.serialization>=1.10.0 # Apache-2.0
-oslo.utils>=3.11.0 # Apache-2.0
+oslo.utils>=3.14.0 # Apache-2.0
six>=1.9.0 # MIT
fixtures>=3.0.0 # Apache-2.0/BSD
testscenarios>=0.4 # Apache-2.0/BSD
diff --git a/tempest/api/identity/admin/v3/test_projects.py b/tempest/api/identity/admin/v3/test_projects.py
index 607bebe..b53cfae 100644
--- a/tempest/api/identity/admin/v3/test_projects.py
+++ b/tempest/api/identity/admin/v3/test_projects.py
@@ -13,10 +13,15 @@
# License for the specific language governing permissions and limitations
# under the License.
+import testtools
+
from tempest.api.identity import base
from tempest.common.utils import data_utils
+from tempest import config
from tempest import test
+CONF = config.CONF
+
class ProjectsTestJSON(base.BaseIdentityV3AdminTest):
@@ -52,6 +57,37 @@
self.assertEqual(project_name, body['name'])
self.assertEqual(self.data.domain['id'], body['domain_id'])
+ @testtools.skipUnless(CONF.identity_feature_enabled.reseller,
+ 'Reseller not available.')
+ @test.idempotent_id('1854f9c0-70bc-4d11-a08a-1c789d339e3d')
+ def test_project_create_with_parent(self):
+ # Create root project without providing a parent_id
+ self.data.setup_test_domain()
+ domain_id = self.data.domain['id']
+
+ root_project_name = data_utils.rand_name('root_project')
+ root_project = self.projects_client.create_project(
+ root_project_name, domain_id=domain_id)['project']
+ self.addCleanup(
+ self.projects_client.delete_project, root_project['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.projects_client.create_project(
+ project_name, domain_id=domain_id,
+ parent_id=root_project_id)['project']
+ self.data.projects.append(project)
+ parent_id = project['parent_id']
+ self.assertEqual(project_name, project['name'])
+ self.assertEqual(root_project_id, parent_id)
+
@test.idempotent_id('1f66dc76-50cc-4741-a200-af984509e480')
def test_project_create_enabled(self):
# Create a project that is enabled
diff --git a/tempest/api/identity/base.py b/tempest/api/identity/base.py
index 7a1e3a5..df39390 100644
--- a/tempest/api/identity/base.py
+++ b/tempest/api/identity/base.py
@@ -218,21 +218,21 @@
def teardown_all(self):
for user in self.users:
test_utils.call_and_ignore_notfound_exc(
- self.users_client.delete_user, user)
+ self.users_client.delete_user, user['id'])
for tenant in self.tenants:
test_utils.call_and_ignore_notfound_exc(
- self.projects_client.delete_tenant, tenant)
+ self.projects_client.delete_tenant, tenant['id'])
for project in reversed(self.projects):
test_utils.call_and_ignore_notfound_exc(
- self.projects_client.delete_project, project)
+ self.projects_client.delete_project, project['id'])
for role in self.roles:
test_utils.call_and_ignore_notfound_exc(
- self.roles_client.delete_role, role)
+ self.roles_client.delete_role, role['id'])
for domain in self.domains:
test_utils.call_and_ignore_notfound_exc(
- self.domains_client.update_domain, domain, enabled=False)
+ self.domains_client.update_domain, domain['id'], enabled=False)
test_utils.call_and_ignore_notfound_exc(
- self.domains_client.delete_domain, domain)
+ self.domains_client.delete_domain, domain['id'])
class DataGeneratorV2(BaseDataGenerator):
diff --git a/tempest/cmd/run.py b/tempest/cmd/run.py
index 8777c0e..5270cac 100644
--- a/tempest/cmd/run.py
+++ b/tempest/cmd/run.py
@@ -64,6 +64,14 @@
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
@@ -83,6 +91,7 @@
from oslo_log import log as logging
from testrepository.commands import run_argv
+from tempest.cmd import init
from tempest.cmd import workspace
from tempest import config
@@ -93,7 +102,9 @@
class TempestRun(command.Command):
- def _set_env(self):
+ 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:
@@ -108,9 +119,19 @@
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):
- self._set_env()
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(
@@ -126,6 +147,10 @@
# 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)
@@ -157,6 +182,9 @@
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', action='store_true',
diff --git a/tempest/config.py b/tempest/config.py
index eb5e23a..8ec8b24 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -191,7 +191,12 @@
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'")
+ "To get the list of extensions run: 'keystone discover'"),
+ # TODO(rodrigods): Remove the reseller flag when Kilo and Liberty is end
+ # of life.
+ cfg.BoolOpt('reseller',
+ default=False,
+ help='Does the environment support reseller?')
]
compute_group = cfg.OptGroup(name='compute',