Merge "Remove deprecated legacy credentials provider"
diff --git a/doc/source/plugin.rst b/doc/source/plugin.rst
index ad26741..9640469 100644
--- a/doc/source/plugin.rst
+++ b/doc/source/plugin.rst
@@ -15,10 +15,22 @@
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. If there is an interface from
-tempest that you need to rely on in your plugin 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.
+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
-------------------
diff --git a/tempest/tests/lib/cli/test_execute.py b/tempest/tests/lib/cli/test_execute.py
index b846c46..cc9c94c 100644
--- a/tempest/tests/lib/cli/test_execute.py
+++ b/tempest/tests/lib/cli/test_execute.py
@@ -12,26 +12,65 @@
# under the License.
+import mock
+import subprocess
+
from tempest.lib.cli import base as cli_base
from tempest.lib import exceptions
from tempest.tests import base
class TestExecute(base.TestCase):
- def test_execute_success(self):
+
+ @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)
- def test_execute_failure(self):
+ @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)
- def test_execute_failure_raise_exception(self):
+ @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)