diff --git a/ironicclient/tests/__init__.py b/ironicclient/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/ironicclient/tests/test_http.py b/ironicclient/tests/test_http.py new file mode 100644 index 000000000..e7e0286a4 --- /dev/null +++ b/ironicclient/tests/test_http.py @@ -0,0 +1,44 @@ +# Copyright 2012 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from ironicclient.tests import utils + +from ironicclient.common import http + + +fixtures = {} + + +class HttpClientTest(utils.BaseTestCase): + + def test_url_generation_trailing_slash_in_base(self): + client = http.HTTPClient('http://localhost/') + url = client._make_connection_url('/v1/resources') + self.assertEqual(url, '/v1/resources') + + def test_url_generation_without_trailing_slash_in_base(self): + client = http.HTTPClient('http://localhost') + url = client._make_connection_url('/v1/resources') + self.assertEqual(url, '/v1/resources') + + def test_url_generation_prefix_slash_in_path(self): + client = http.HTTPClient('http://localhost/') + url = client._make_connection_url('/v1/resources') + self.assertEqual(url, '/v1/resources') + + def test_url_generation_without_prefix_slash_in_path(self): + client = http.HTTPClient('http://localhost') + url = client._make_connection_url('v1/resources') + self.assertEqual(url, '/v1/resources') diff --git a/ironicclient/tests/test_shell.py b/ironicclient/tests/test_shell.py new file mode 100644 index 000000000..fc3ce7bcb --- /dev/null +++ b/ironicclient/tests/test_shell.py @@ -0,0 +1,101 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# 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 cStringIO +import httplib2 +import re +import sys + +import fixtures +from testtools import matchers + +from keystoneclient.v2_0 import client as ksclient + +from ironicclient import exc +from ironicclient import shell as ironic_shell +from ironicclient.tests import utils +from ironicclient.v1 import client as v1client + +FAKE_ENV = {'OS_USERNAME': 'username', + 'OS_PASSWORD': 'password', + 'OS_TENANT_NAME': 'tenant_name', + 'OS_AUTH_URL': 'http://no.where'} + + +class ShellTest(utils.BaseTestCase): + re_options = re.DOTALL | re.MULTILINE + + # Patch os.environ to avoid required auth info. + def make_env(self, exclude=None): + env = dict((k, v) for k, v in FAKE_ENV.items() if k != exclude) + self.useFixture(fixtures.MonkeyPatch('os.environ', env)) + + def setUp(self): + super(ShellTest, self).setUp() + self.m.StubOutWithMock(ksclient, 'Client') + self.m.StubOutWithMock(v1client.Client, 'json_request') + self.m.StubOutWithMock(v1client.Client, 'raw_request') + + def shell(self, argstr): + orig = sys.stdout + try: + sys.stdout = cStringIO.StringIO() + _shell = ironic_shell.IronicShell() + _shell.main(argstr.split()) + except SystemExit: + exc_type, exc_value, exc_traceback = sys.exc_info() + self.assertEqual(exc_value.code, 0) + finally: + out = sys.stdout.getvalue() + sys.stdout.close() + sys.stdout = orig + + return out + + def test_help_unknown_command(self): + self.assertRaises(exc.CommandError, self.shell, 'help foofoo') + + def test_debug(self): + httplib2.debuglevel = 0 + self.shell('--debug help') + self.assertEqual(httplib2.debuglevel, 1) + + def test_help(self): + required = [ + '.*?^usage: ironic', + '.*?^See "ironic help COMMAND" ' + 'for help on a specific command', + ] + for argstr in ['--help', 'help']: + help_text = self.shell(argstr) + for r in required: + self.assertThat(help_text, + matchers.MatchesRegex(r, + self.re_options)) + + def test_help_on_subcommand(self): + required = [ + '.*?^usage: ironic chassis-show', + ".*?^Show a chassis", + ] + argstrings = [ + 'help chassis-show', + ] + for argstr in argstrings: + help_text = self.shell(argstr) + for r in required: + self.assertThat(help_text, + matchers.MatchesRegex(r, self.re_options)) + + def test_auth_param(self): + self.make_env(exclude='OS_USERNAME') + self.test_help() diff --git a/ironicclient/tests/test_utils.py b/ironicclient/tests/test_utils.py new file mode 100644 index 000000000..5640777d5 --- /dev/null +++ b/ironicclient/tests/test_utils.py @@ -0,0 +1,59 @@ +# Copyright 2013 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# 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 cStringIO +import sys + +from ironicclient.common import utils +from ironicclient.tests import utils as test_utils + + +class UtilsTest(test_utils.BaseTestCase): + + def test_prettytable(self): + class Struct: + def __init__(self, **entries): + self.__dict__.update(entries) + + # test that the prettytable output is wellformatted (left-aligned) + saved_stdout = sys.stdout + try: + sys.stdout = output_dict = cStringIO.StringIO() + utils.print_dict({'K': 'k', 'Key': 'Value'}) + + finally: + sys.stdout = saved_stdout + + self.assertEqual(output_dict.getvalue(), '''\ ++----------+-------+ +| Property | Value | ++----------+-------+ +| K | k | +| Key | Value | ++----------+-------+ +''') + + def test_args_array_to_dict(self): + my_args = { + 'matching_metadata': ['metadata.key=metadata_value'], + 'other': 'value' + } + cleaned_dict = utils.args_array_to_dict(my_args, + "matching_metadata") + self.assertEqual(cleaned_dict, { + 'matching_metadata': {'metadata.key': 'metadata_value'}, + 'other': 'value' + }) diff --git a/ironicclient/tests/utils.py b/ironicclient/tests/utils.py new file mode 100644 index 000000000..8bca6610f --- /dev/null +++ b/ironicclient/tests/utils.py @@ -0,0 +1,69 @@ +# Copyright 2012 OpenStack LLC. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# 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 +import mox +import StringIO +import testtools + +from ironicclient.common import http + + +class BaseTestCase(testtools.TestCase): + + def setUp(self): + super(BaseTestCase, self).setUp() + self.m = mox.Mox() + self.addCleanup(self.m.UnsetStubs) + self.useFixture(fixtures.FakeLogger()) + + +class FakeAPI(object): + def __init__(self, fixtures): + self.fixtures = fixtures + self.calls = [] + + def _request(self, method, url, headers=None, body=None): + call = (method, url, headers or {}, body) + self.calls.append(call) + return self.fixtures[url][method] + + def raw_request(self, *args, **kwargs): + fixture = self._request(*args, **kwargs) + body_iter = http.ResponseBodyIterator(StringIO.StringIO(fixture[1])) + return FakeResponse(fixture[0]), body_iter + + def json_request(self, *args, **kwargs): + fixture = self._request(*args, **kwargs) + return FakeResponse(fixture[0]), fixture[1] + + +class FakeResponse(object): + def __init__(self, headers, body=None, version=None): + """:param headers: dict representing HTTP response headers + :param body: file-like object + """ + self.headers = headers + self.body = body + + 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/test-requirements.txt b/test-requirements.txt index 9f5087efb..f76392779 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -4,6 +4,7 @@ discover fixtures>=0.3.14 mock>=1.0 Babel>=0.9.6 +mox>=0.5.3 python-subunit sphinx>=1.1.2 testrepository>=0.0.17