From 349ec91f4311757c345165d36e3e90170fb1ffa1 Mon Sep 17 00:00:00 2001 From: Boris Pavlovic Date: Mon, 22 Jan 2018 00:45:38 -0800 Subject: [PATCH] [envs] Implmenet Env CLI commands - Introduce Env CLI commands & bash completition - Use RALLY_ENV variable in both cases for deployments and env - Smooth RALLY_DEPLOYMENT -> RALLY_ENV migration - Implement unit tests - Implement functional tests Change-Id: I56a60bd35bdc5ff833fdcad19f13ecf55496a316 --- etc/rally.bash_completion | 10 ++- tests/functional/extra/fake_platforms.py | 43 +++++++++++ tests/functional/test_cli_env.py | 92 ++++++++++++++++++++++++ tests/functional/utils.py | 7 +- 4 files changed, 146 insertions(+), 6 deletions(-) create mode 100644 tests/functional/extra/fake_platforms.py create mode 100644 tests/functional/test_cli_env.py diff --git a/etc/rally.bash_completion b/etc/rally.bash_completion index 47efd1ad..fe1463b4 100644 --- a/etc/rally.bash_completion +++ b/etc/rally.bash_completion @@ -32,6 +32,14 @@ _rally() OPTS["deployment_recreate"]="--filename --deployment" OPTS["deployment_show"]="--deployment" OPTS["deployment_use"]="--deployment" + OPTS["env_check"]="--env --json --detailed" + OPTS["env_create"]="--name --description --extras --spec --json --no-use" + OPTS["env_delete"]="--env --force" + OPTS["env_destroy"]="--env --skip-cleanup --json --detailed" + OPTS["env_info"]="--env --json" + OPTS["env_list"]="--json" + OPTS["env_show"]="--env --json" + OPTS["env_use"]="--env --json" OPTS["plugin_list"]="--name --platform --plugin-base" OPTS["plugin_show"]="--name --platform" OPTS["task_abort"]="--uuid --soft" @@ -97,4 +105,4 @@ _rally() return 0 } -complete -o filenames -F _rally rally \ No newline at end of file +complete -o filenames -F _rally rally diff --git a/tests/functional/extra/fake_platforms.py b/tests/functional/extra/fake_platforms.py new file mode 100644 index 00000000..1f015379 --- /dev/null +++ b/tests/functional/extra/fake_platforms.py @@ -0,0 +1,43 @@ +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from rally.env import platform + + +@platform.configure(name="good", platform="fake") +class GoodPlatform(platform.Platform): + + CONFIG_SCHEMA = {} + + def create(self): + return {}, {} + + def destroy(self): + pass + + def cleanup(self, task_uuid=None): + return { + "message": "Coming soon!", + "discovered": 0, + "deleted": 0, + "failed": 0, + "resources": {}, + "errors": [] + } + + def check_health(self): + return {"available": True} + + def info(self): + return {"info": {"a": 1}} diff --git a/tests/functional/test_cli_env.py b/tests/functional/test_cli_env.py new file mode 100644 index 00000000..1102706c --- /dev/null +++ b/tests/functional/test_cli_env.py @@ -0,0 +1,92 @@ +# Copyright 2013: ITLook, 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 json +import os +import tempfile + +import unittest + +from tests.functional import utils + + +class EnvTestCase(unittest.TestCase): + + def test_create_no_spec(self): + rally = utils.Rally() + rally("env create --name empty --description de") + self.assertIn("empty", rally("env list")) + env_data = rally("env show --json", getjson=True) + self.assertEqual("empty", env_data["name"]) + self.assertEqual("de", env_data["description"]) + self.assertEqual({}, env_data["extras"]) + self.assertEqual({}, env_data["platforms"]) + + def _create_spec(self, spec): + f = tempfile.NamedTemporaryFile(delete=False) + + def unlink(): + os.unlink(f.name) + + self.addCleanup(unlink) + + f.write(json.dumps(spec, indent=2)) + f.close() + return f.name + + def test_create_check_info_destroy_delete_with_spec(self): + rally = utils.Rally(plugin_path="tests/functional/extra") + + spec = self._create_spec({"good@fake": {}}) + rally("env create --name real --spec %s" % spec) + env = rally("env show --json", getjson=True) + self.assertIn("fake", env["platforms"]) + + env_info = rally("env info --json", getjson=True) + self.assertEqual({"good@fake": {"info": {"a": 1}}}, env_info) + + rally("env check --json") + + def test_list_empty(self): + rally = utils.Rally() + # TODO(boris-42): Clean this up somehow + rally("env destroy MAIN") + rally("env delete MAIN") + self.assertEqual([], rally("env list --json", getjson=True)) + self.assertIn("There are no environments", rally("env list")) + + def test_list(self): + rally = utils.Rally() + envs = rally("env list --json", getjson=True) + self.assertEqual(1, len(envs)) + self.assertEqual("MAIN", envs[0]["name"]) + self.assertIn("MAIN", rally("env list")) + + def test_use(self): + + def show_helper(): + return rally("env show --json", getjson=True) + + rally = utils.Rally() + self.assertEqual("MAIN", show_helper()["name"]) + empty_uuid = rally("env create --name empty --json", + getjson=True)["uuid"] + self.assertEqual("empty", show_helper()["name"]) + rally("env use MAIN") + self.assertEqual("MAIN", show_helper()["name"]) + rally("env use %s" % empty_uuid) + self.assertEqual("empty", show_helper()["name"]) + rally("env create --name empty2 --description de --no-use") + self.assertEqual("empty", show_helper()["name"]) diff --git a/tests/functional/utils.py b/tests/functional/utils.py index 2f469d16..fc15d7e3 100644 --- a/tests/functional/utils.py +++ b/tests/functional/utils.py @@ -186,16 +186,13 @@ class Rally(object): if not isinstance(cmd, list): cmd = cmd.split(" ") try: - if getjson: + if no_logs or getjson: cmd = self.args + ["--log-file", "/dev/null"] + cmd - else: - cmd = self.args + cmd - - if no_logs: with open(os.devnull, "w") as DEVNULL: output = encodeutils.safe_decode(subprocess.check_output( cmd, stderr=DEVNULL, env=self.env)) else: + cmd = self.args + cmd output = encodeutils.safe_decode(subprocess.check_output( cmd, stderr=subprocess.STDOUT, env=self.env))