From d9d8cc614eccaffefdfd4aa4f536745f0aabc5e3 Mon Sep 17 00:00:00 2001 From: Chris Dent Date: Thu, 12 Mar 2015 13:31:06 +0000 Subject: Move unit tests into their own subdirectory This is in preparation of moving functional tests currently in tempest in-tree. No surprises in this change: * move files * update the local imports Same number of tests run, all still pass. Change-Id: Ibfeac44421c5f36740b1377868f5ec469b2893f5 --- .testr.conf | 2 +- ceilometerclient/tests/fakes.py | 64 -- ceilometerclient/tests/test_client.py | 158 --- ceilometerclient/tests/test_exc.py | 71 -- ceilometerclient/tests/test_shell.py | 225 ---- ceilometerclient/tests/test_utils.py | 265 ----- ceilometerclient/tests/unit/__init__.py | 0 ceilometerclient/tests/unit/fakes.py | 64 ++ ceilometerclient/tests/unit/test_client.py | 158 +++ ceilometerclient/tests/unit/test_exc.py | 71 ++ ceilometerclient/tests/unit/test_shell.py | 225 ++++ ceilometerclient/tests/unit/test_utils.py | 265 +++++ ceilometerclient/tests/unit/utils.py | 24 + ceilometerclient/tests/unit/v1/__init__.py | 0 ceilometerclient/tests/unit/v1/test_meters.py | 162 +++ ceilometerclient/tests/unit/v1/test_projects.py | 65 ++ ceilometerclient/tests/unit/v1/test_resources.py | 161 +++ ceilometerclient/tests/unit/v1/test_samples.py | 196 ++++ ceilometerclient/tests/unit/v1/test_users.py | 65 ++ ceilometerclient/tests/unit/v2/__init__.py | 0 ceilometerclient/tests/unit/v2/test_alarms.py | 540 +++++++++ ceilometerclient/tests/unit/v2/test_event_types.py | 50 + ceilometerclient/tests/unit/v2/test_events.py | 198 ++++ ceilometerclient/tests/unit/v2/test_options.py | 239 ++++ .../tests/unit/v2/test_query_alarm_history.py | 66 ++ .../tests/unit/v2/test_query_alarms.py | 74 ++ .../tests/unit/v2/test_query_samples.py | 67 ++ ceilometerclient/tests/unit/v2/test_resources.py | 118 ++ ceilometerclient/tests/unit/v2/test_samples.py | 198 ++++ ceilometerclient/tests/unit/v2/test_shell.py | 1175 ++++++++++++++++++++ ceilometerclient/tests/unit/v2/test_statistics.py | 224 ++++ .../tests/unit/v2/test_trait_descriptions.py | 56 + ceilometerclient/tests/unit/v2/test_traits.py | 62 ++ ceilometerclient/tests/utils.py | 24 - ceilometerclient/tests/v1/__init__.py | 0 ceilometerclient/tests/v1/test_meters.py | 162 --- ceilometerclient/tests/v1/test_projects.py | 65 -- ceilometerclient/tests/v1/test_resources.py | 161 --- ceilometerclient/tests/v1/test_samples.py | 196 ---- ceilometerclient/tests/v1/test_users.py | 65 -- ceilometerclient/tests/v2/__init__.py | 0 ceilometerclient/tests/v2/test_alarms.py | 540 --------- ceilometerclient/tests/v2/test_event_types.py | 50 - ceilometerclient/tests/v2/test_events.py | 198 ---- ceilometerclient/tests/v2/test_options.py | 239 ---- .../tests/v2/test_query_alarm_history.py | 66 -- ceilometerclient/tests/v2/test_query_alarms.py | 74 -- ceilometerclient/tests/v2/test_query_samples.py | 67 -- ceilometerclient/tests/v2/test_resources.py | 118 -- ceilometerclient/tests/v2/test_samples.py | 198 ---- ceilometerclient/tests/v2/test_shell.py | 1175 -------------------- ceilometerclient/tests/v2/test_statistics.py | 224 ---- .../tests/v2/test_trait_descriptions.py | 56 - ceilometerclient/tests/v2/test_traits.py | 62 -- 54 files changed, 4524 insertions(+), 4524 deletions(-) delete mode 100644 ceilometerclient/tests/fakes.py delete mode 100644 ceilometerclient/tests/test_client.py delete mode 100644 ceilometerclient/tests/test_exc.py delete mode 100644 ceilometerclient/tests/test_shell.py delete mode 100644 ceilometerclient/tests/test_utils.py create mode 100644 ceilometerclient/tests/unit/__init__.py create mode 100644 ceilometerclient/tests/unit/fakes.py create mode 100644 ceilometerclient/tests/unit/test_client.py create mode 100644 ceilometerclient/tests/unit/test_exc.py create mode 100644 ceilometerclient/tests/unit/test_shell.py create mode 100644 ceilometerclient/tests/unit/test_utils.py create mode 100644 ceilometerclient/tests/unit/utils.py create mode 100644 ceilometerclient/tests/unit/v1/__init__.py create mode 100644 ceilometerclient/tests/unit/v1/test_meters.py create mode 100644 ceilometerclient/tests/unit/v1/test_projects.py create mode 100644 ceilometerclient/tests/unit/v1/test_resources.py create mode 100644 ceilometerclient/tests/unit/v1/test_samples.py create mode 100644 ceilometerclient/tests/unit/v1/test_users.py create mode 100644 ceilometerclient/tests/unit/v2/__init__.py create mode 100644 ceilometerclient/tests/unit/v2/test_alarms.py create mode 100644 ceilometerclient/tests/unit/v2/test_event_types.py create mode 100644 ceilometerclient/tests/unit/v2/test_events.py create mode 100644 ceilometerclient/tests/unit/v2/test_options.py create mode 100644 ceilometerclient/tests/unit/v2/test_query_alarm_history.py create mode 100644 ceilometerclient/tests/unit/v2/test_query_alarms.py create mode 100644 ceilometerclient/tests/unit/v2/test_query_samples.py create mode 100644 ceilometerclient/tests/unit/v2/test_resources.py create mode 100644 ceilometerclient/tests/unit/v2/test_samples.py create mode 100644 ceilometerclient/tests/unit/v2/test_shell.py create mode 100644 ceilometerclient/tests/unit/v2/test_statistics.py create mode 100644 ceilometerclient/tests/unit/v2/test_trait_descriptions.py create mode 100644 ceilometerclient/tests/unit/v2/test_traits.py delete mode 100644 ceilometerclient/tests/utils.py delete mode 100644 ceilometerclient/tests/v1/__init__.py delete mode 100644 ceilometerclient/tests/v1/test_meters.py delete mode 100644 ceilometerclient/tests/v1/test_projects.py delete mode 100644 ceilometerclient/tests/v1/test_resources.py delete mode 100644 ceilometerclient/tests/v1/test_samples.py delete mode 100644 ceilometerclient/tests/v1/test_users.py delete mode 100644 ceilometerclient/tests/v2/__init__.py delete mode 100644 ceilometerclient/tests/v2/test_alarms.py delete mode 100644 ceilometerclient/tests/v2/test_event_types.py delete mode 100644 ceilometerclient/tests/v2/test_events.py delete mode 100644 ceilometerclient/tests/v2/test_options.py delete mode 100644 ceilometerclient/tests/v2/test_query_alarm_history.py delete mode 100644 ceilometerclient/tests/v2/test_query_alarms.py delete mode 100644 ceilometerclient/tests/v2/test_query_samples.py delete mode 100644 ceilometerclient/tests/v2/test_resources.py delete mode 100644 ceilometerclient/tests/v2/test_samples.py delete mode 100644 ceilometerclient/tests/v2/test_shell.py delete mode 100644 ceilometerclient/tests/v2/test_statistics.py delete mode 100644 ceilometerclient/tests/v2/test_trait_descriptions.py delete mode 100644 ceilometerclient/tests/v2/test_traits.py diff --git a/.testr.conf b/.testr.conf index 818fbc3..77a2a70 100644 --- a/.testr.conf +++ b/.testr.conf @@ -1,4 +1,4 @@ [DEFAULT] -test_command=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 ${PYTHON:-python} -m subunit.run discover -t ./ ./ $LISTOPT $IDOPTION +test_command=OS_STDOUT_CAPTURE=1 OS_STDERR_CAPTURE=1 ${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./ceilometerclient/tests/unit} $LISTOPT $IDOPTION test_id_option=--load-list $IDFILE test_list_option=--list diff --git a/ceilometerclient/tests/fakes.py b/ceilometerclient/tests/fakes.py deleted file mode 100644 index 10d8d8c..0000000 --- a/ceilometerclient/tests/fakes.py +++ /dev/null @@ -1,64 +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 keystoneclient.v2_0 import client as ksclient - - -def script_keystone_client(): - ksclient.Client(auth_url='http://no.where', - insecure=False, - password='password', - tenant_id='', - tenant_name='tenant_name', - username='username').AndReturn(FakeKeystone('abcd1234')) - - -def fake_headers(): - return {'X-Auth-Token': 'abcd1234', - 'Content-Type': 'application/json', - 'Accept': 'application/json', - 'User-Agent': 'python-ceilometerclient'} - - -class FakeServiceCatalog(object): - @staticmethod - def url_for(endpoint_type, service_type): - return 'http://192.168.1.5:8004/v1/f14b41234' - - -class FakeKeystone(object): - service_catalog = FakeServiceCatalog() - - def __init__(self, auth_token): - self.auth_token = auth_token - - -class FakeHTTPResponse(object): - - version = 1.1 - - def __init__(self, status, reason, headers, body): - self.headers = headers - self.body = body - self.status = status - self.reason = reason - - def getheader(self, name, default=None): - return self.headers.get(name, default) - - def getheaders(self): - return self.headers.items() - - def read(self, amt=None): - b = self.body - self.body = None - return b diff --git a/ceilometerclient/tests/test_client.py b/ceilometerclient/tests/test_client.py deleted file mode 100644 index 45472a4..0000000 --- a/ceilometerclient/tests/test_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. - -import types - -import mock - -from ceilometerclient import client -from ceilometerclient.tests import fakes -from ceilometerclient.tests import utils -from ceilometerclient.v1 import client as v1client -from ceilometerclient.v2 import client as v2client - -FAKE_ENV = { - 'username': 'username', - 'password': 'password', - 'tenant_name': 'tenant_name', - 'auth_url': 'http://no.where', - 'ceilometer_url': 'http://no.where', - 'auth_plugin': 'fake_auth', - 'token': '1234', - 'user_domain_name': 'default', - 'project_domain_name': 'default', -} - - -class ClientTest(utils.BaseTestCase): - - @staticmethod - def create_client(env, api_version=2, endpoint=None, exclude=[]): - env = dict((k, v) for k, v in env.items() - if k not in exclude) - - return client.get_client(api_version, **env) - - def test_client_version(self): - c1 = self.create_client(env=FAKE_ENV, api_version=1) - self.assertIsInstance(c1, v1client.Client) - - c2 = self.create_client(env=FAKE_ENV, api_version=2) - self.assertIsInstance(c2, v2client.Client) - - def test_client_auth_lambda(self): - env = FAKE_ENV.copy() - env['token'] = lambda: env['token'] - self.assertIsInstance(env['token'], - types.FunctionType) - c2 = self.create_client(env) - self.assertIsInstance(c2, v2client.Client) - - def test_client_auth_non_lambda(self): - env = FAKE_ENV.copy() - env['token'] = "1234" - self.assertIsInstance(env['token'], str) - c2 = self.create_client(env) - self.assertIsInstance(c2, v2client.Client) - - @mock.patch('keystoneclient.v2_0.client', fakes.FakeKeystone) - def test_client_without_auth_plugin(self): - env = FAKE_ENV.copy() - del env['auth_plugin'] - c = self.create_client(env, api_version=2, endpoint='fake_endpoint') - self.assertIsInstance(c.auth_plugin, client.AuthPlugin) - - def test_client_without_auth_plugin_keystone_v3(self): - env = FAKE_ENV.copy() - del env['auth_plugin'] - expected = { - 'username': 'username', - 'endpoint': 'http://no.where', - 'tenant_name': 'tenant_name', - 'service_type': None, - 'token': '1234', - 'endpoint_type': None, - 'auth_url': 'http://no.where', - 'tenant_id': None, - 'cacert': None, - 'password': 'password', - 'user_domain_name': 'default', - 'user_domain_id': None, - 'project_domain_name': 'default', - 'project_domain_id': None, - } - with mock.patch('ceilometerclient.client.AuthPlugin') as auth_plugin: - self.create_client(env, api_version=2, endpoint='http://no.where') - auth_plugin.assert_called_with(**expected) - - def test_client_with_auth_plugin(self): - c = self.create_client(FAKE_ENV, api_version=2) - self.assertIsInstance(c.auth_plugin, str) - - def test_v2_client_timeout_invalid_value(self): - env = FAKE_ENV.copy() - env['timeout'] = 'abc' - self.assertRaises(ValueError, self.create_client, env) - env['timeout'] = '1.5' - self.assertRaises(ValueError, self.create_client, env) - - def _test_v2_client_timeout_integer(self, timeout, expected_value): - env = FAKE_ENV.copy() - env['timeout'] = timeout - expected = { - 'auth_plugin': 'fake_auth', - 'timeout': expected_value, - 'original_ip': None, - 'http': None, - 'region_name': None, - 'verify': True, - 'timings': None, - 'keyring_saver': None, - 'cert': None, - 'endpoint_type': None, - 'user_agent': None, - 'debug': None, - } - cls = 'ceilometerclient.openstack.common.apiclient.client.HTTPClient' - with mock.patch(cls) as mocked: - self.create_client(env) - mocked.assert_called_with(**expected) - - def test_v2_client_timeout_zero(self): - self._test_v2_client_timeout_integer(0, None) - - def test_v2_client_timeout_valid_value(self): - self._test_v2_client_timeout_integer(30, 30) - - def test_v2_client_cacert_in_verify(self): - env = FAKE_ENV.copy() - env['cacert'] = '/path/to/cacert' - client = self.create_client(env) - self.assertEqual('/path/to/cacert', client.client.verify) - - def test_v2_client_certfile_and_keyfile(self): - env = FAKE_ENV.copy() - env['cert_file'] = '/path/to/cert' - env['key_file'] = '/path/to/keycert' - client = self.create_client(env) - self.assertEqual(('/path/to/cert', '/path/to/keycert'), - client.client.cert) - - -class ClientTest2(ClientTest): - @staticmethod - def create_client(env, api_version=2, endpoint=None, exclude=[]): - env = dict((k, v) for k, v in env.items() - if k not in exclude) - - # Run the same tests with direct instantiation of the Client - return client.Client(api_version, endpoint, **env) diff --git a/ceilometerclient/tests/test_exc.py b/ceilometerclient/tests/test_exc.py deleted file mode 100644 index 9c8f146..0000000 --- a/ceilometerclient/tests/test_exc.py +++ /dev/null @@ -1,71 +0,0 @@ -# Copyright 2013 eNovance -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# 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 ceilometerclient import exc -from ceilometerclient.tests import utils - -HTTPEXCEPTIONS = {'HTTPBadRequest': exc.HTTPBadRequest, - 'HTTPUnauthorized': exc.HTTPUnauthorized, - 'HTTPForbidden': exc.HTTPForbidden, - 'HTTPNotFound': exc.HTTPNotFound, - 'HTTPMethodNotAllowed': exc.HTTPMethodNotAllowed, - 'HTTPConflict': exc.HTTPConflict, - 'HTTPOverLimit': exc.HTTPOverLimit, - 'HTTPInternalServerError': exc.HTTPInternalServerError, - 'HTTPNotImplemented': exc.HTTPNotImplemented, - 'HTTPBadGateway': exc.HTTPBadGateway, - 'HTTPServiceUnavailable': exc.HTTPServiceUnavailable} - - -class HTTPExceptionsTest(utils.BaseTestCase): - def test_str_no_details(self): - for k, v in HTTPEXCEPTIONS.items(): - exception = v() - ret_str = k + " (HTTP " + str(exception.code) + ")" - self.assertEqual(ret_str, str(exception)) - - def test_str_no_json(self): - for k, v in HTTPEXCEPTIONS.items(): - exception = v(details="foo") - ret_str = k + " (HTTP " + str(exception.code) + ")" - self.assertEqual(ret_str, str(exception)) - - def test_str_no_error_message(self): - for k, v in HTTPEXCEPTIONS.items(): - exception = v(details=json.dumps({})) - ret_str = k + " (HTTP " + str(exception.code) + ")" - self.assertEqual(ret_str, str(exception)) - - def test_str_no_faultstring(self): - for k, v in HTTPEXCEPTIONS.items(): - exception = v( - details=json.dumps({"error_message": {"foo": "bar"}})) - ret_str = k + " (HTTP " + str(exception.code) + ")" - self.assertEqual(ret_str, str(exception)) - - def test_str_error_message_unknown_format(self): - for k, v in HTTPEXCEPTIONS.items(): - exception = v(details=json.dumps({"error_message": "oops"})) - ret_str = k + " (HTTP " + str(exception.code) + ")" - self.assertEqual(ret_str, str(exception)) - - def test_str_faultstring(self): - for k, v in HTTPEXCEPTIONS.items(): - exception = v(details=json.dumps( - {"error_message": {"faultstring": "oops"}})) - ret_str = k + " (HTTP " + str(exception.code) + ") ERROR oops" - self.assertEqual(ret_str, str(exception)) diff --git a/ceilometerclient/tests/test_shell.py b/ceilometerclient/tests/test_shell.py deleted file mode 100644 index 6d6403b..0000000 --- a/ceilometerclient/tests/test_shell.py +++ /dev/null @@ -1,225 +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 sys - -import fixtures -from keystoneclient import session as ks_session -import mock -import six -from testtools import matchers - -from ceilometerclient import exc -from ceilometerclient.openstack.common.apiclient import client as api_client -from ceilometerclient import shell as ceilometer_shell -from ceilometerclient.tests import utils -from ceilometerclient.v2 import client as v2client - -FAKE_V2_ENV = {'OS_USERNAME': 'username', - 'OS_PASSWORD': 'password', - 'OS_TENANT_NAME': 'tenant_name', - 'OS_AUTH_URL': 'http://localhost:5000/v2.0'} - -FAKE_V3_ENV = {'OS_USERNAME': 'username', - 'OS_PASSWORD': 'password', - 'OS_USER_DOMAIN_NAME': 'domain_name', - 'OS_PROJECT_ID': '1234567890', - 'OS_AUTH_URL': 'http://localhost:5000/v3'} - - -class ShellTestBase(utils.BaseTestCase): - - # Patch os.environ to avoid required auth info. - def make_env(self, env_version, exclude=None): - env = dict((k, v) for k, v in env_version.items() if k != exclude) - self.useFixture(fixtures.MonkeyPatch('os.environ', env)) - - -class ShellHelpTest(ShellTestBase): - RE_OPTIONS = re.DOTALL | re.MULTILINE - - @mock.patch('sys.stdout', new=six.StringIO()) - @mock.patch.object(ks_session, 'Session', mock.MagicMock()) - @mock.patch.object(v2client.client.HTTPClient, - 'client_request', mock.MagicMock()) - def shell(self, argstr): - try: - _shell = ceilometer_shell.CeilometerShell() - _shell.main(argstr.split()) - except SystemExit: - exc_type, exc_value, exc_traceback = sys.exc_info() - self.assertEqual(exc_value.code, 0) - - return sys.stdout.getvalue() - - def test_help_unknown_command(self): - self.assertRaises(exc.CommandError, self.shell, 'help foofoo') - - def test_help(self): - required = [ - '.*?^usage: ceilometer', - '.*?^See "ceilometer 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: ceilometer meter-list', - ".*?^List the user's meter", - ] - argstrings = [ - 'help meter-list', - ] - for argstr in argstrings: - help_text = self.shell(argstr) - for r in required: - self.assertThat(help_text, - matchers.MatchesRegex(r, self.RE_OPTIONS)) - - -class ShellKeystoneV2Test(ShellTestBase): - - @mock.patch.object(ks_session, 'Session') - def test_debug_switch_raises_error(self, mock_ksclient): - mock_ksclient.side_effect = exc.HTTPUnauthorized - self.make_env(FAKE_V2_ENV) - args = ['--debug', 'event-list'] - self.assertRaises(exc.CommandError, ceilometer_shell.main, args) - - @mock.patch.object(ks_session, 'Session') - def test_dash_d_switch_raises_error(self, mock_ksclient): - mock_ksclient.side_effect = exc.CommandError("FAIL") - self.make_env(FAKE_V2_ENV) - args = ['-d', 'event-list'] - self.assertRaises(exc.CommandError, ceilometer_shell.main, args) - - @mock.patch('sys.stderr') - @mock.patch.object(ks_session, 'Session') - def test_no_debug_switch_no_raises_errors(self, mock_ksclient, __): - mock_ksclient.side_effect = exc.HTTPUnauthorized("FAIL") - self.make_env(FAKE_V2_ENV) - args = ['event-list'] - self.assertRaises(SystemExit, ceilometer_shell.main, args) - - -class ShellKeystoneV3Test(ShellTestBase): - - @mock.patch.object(ks_session, 'Session') - def test_debug_switch_raises_error(self, mock_ksclient): - mock_ksclient.side_effect = exc.HTTPUnauthorized - self.make_env(FAKE_V3_ENV) - args = ['--debug', 'event-list'] - self.assertRaises(exc.CommandError, ceilometer_shell.main, args) - - @mock.patch.object(ks_session, 'Session') - def test_dash_d_switch_raises_error(self, mock_ksclient): - mock_ksclient.side_effect = exc.CommandError("FAIL") - self.make_env(FAKE_V3_ENV) - args = ['-d', 'event-list'] - self.assertRaises(exc.CommandError, ceilometer_shell.main, args) - - @mock.patch('sys.stderr') - @mock.patch.object(ks_session, 'Session') - def test_no_debug_switch_no_raises_errors(self, mock_ksclient, __): - mock_ksclient.side_effect = exc.HTTPUnauthorized("FAIL") - self.make_env(FAKE_V3_ENV) - args = ['event-list'] - self.assertRaises(SystemExit, ceilometer_shell.main, args) - - -class ShellTimeoutTest(ShellTestBase): - - @mock.patch('sys.stderr', new=six.StringIO()) - def _test_timeout(self, timeout, expected_msg): - args = ['--timeout', timeout, 'alarm-list'] - self.assertRaises(SystemExit, ceilometer_shell.main, args) - self.assertEqual(expected_msg, sys.stderr.getvalue().splitlines()[-1]) - - def test_timeout_invalid_value(self): - expected_msg = ('ceilometer: error: argument --timeout: ' - 'abc must be an integer') - self._test_timeout('abc', expected_msg) - - def test_timeout_negative_value(self): - expected_msg = ('ceilometer: error: argument --timeout: ' - '-1 must be greater than 0') - self._test_timeout('-1', expected_msg) - - def test_timeout_float_value(self): - expected_msg = ('ceilometer: error: argument --timeout: ' - '1.5 must be an integer') - self._test_timeout('1.5', expected_msg) - - def test_timeout_zero(self): - expected_msg = ('ceilometer: error: argument --timeout: ' - '0 must be greater than 0') - self._test_timeout('0', expected_msg) - - -class ShellInsecureTest(ShellTestBase): - - @mock.patch.object(api_client, 'HTTPClient') - def test_insecure_true_ceilometer(self, mocked_client): - self.make_env(FAKE_V2_ENV) - args = ['--debug', '--os-insecure', 'true', 'alarm-list'] - self.assertIsNone(ceilometer_shell.main(args)) - args, kwargs = mocked_client.call_args - self.assertEqual(False, kwargs.get('verify')) - - @mock.patch.object(ks_session, 'Session') - def test_insecure_true_keystone(self, mocked_session): - mocked_session.side_effect = exc.HTTPUnauthorized("FAIL") - self.make_env(FAKE_V2_ENV) - args = ['--debug', '--os-insecure', 'true', 'alarm-list'] - self.assertRaises(exc.CommandError, ceilometer_shell.main, args) - mocked_session.assert_called_with(verify=False, cert='') - - @mock.patch.object(api_client, 'HTTPClient') - def test_insecure_false_ceilometer(self, mocked_client): - self.make_env(FAKE_V2_ENV) - args = ['--debug', '--os-insecure', 'false', 'alarm-list'] - self.assertIsNone(ceilometer_shell.main(args)) - args, kwargs = mocked_client.call_args - self.assertEqual(True, kwargs.get('verify')) - - @mock.patch.object(ks_session, 'Session') - def test_insecure_false_keystone(self, mocked_session): - mocked_session.side_effect = exc.HTTPUnauthorized("FAIL") - self.make_env(FAKE_V2_ENV) - args = ['--debug', '--os-insecure', 'false', 'alarm-list'] - self.assertRaises(exc.CommandError, ceilometer_shell.main, args) - mocked_session.assert_called_with(verify=True, cert='') - - -class ShellEndpointTest(ShellTestBase): - - @mock.patch('ceilometerclient.v2.client.Client') - def _test_endpoint_and_token(self, token_name, endpoint_name, mocked): - args = ['--debug', token_name, 'fake-token', - endpoint_name, 'http://fake-url', 'alarm-list'] - self.assertEqual(None, ceilometer_shell.main(args)) - args, kwargs = mocked.call_args - self.assertEqual('http://fake-url', kwargs.get('endpoint')) - self.assertEqual('fake-token', kwargs.get('token')) - - def test_endpoint_and_token(self): - self._test_endpoint_and_token('--os-auth-token', '--ceilometer-url') - self._test_endpoint_and_token('--os-auth-token', '--os-endpoint') - self._test_endpoint_and_token('--os-token', '--ceilometer-url') - self._test_endpoint_and_token('--os-token', '--os-endpoint') diff --git a/ceilometerclient/tests/test_utils.py b/ceilometerclient/tests/test_utils.py deleted file mode 100644 index 23235d3..0000000 --- a/ceilometerclient/tests/test_utils.py +++ /dev/null @@ -1,265 +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 itertools - -import mock -import six - -from ceilometerclient.common import utils -from ceilometerclient.tests import utils as test_utils - - -class UtilsTest(test_utils.BaseTestCase): - - def test_prettytable(self): - class Struct(object): - def __init__(self, **entries): - self.__dict__.update(entries) - - # test that the prettytable output is wellformatted (left-aligned) - with mock.patch('sys.stdout', new=six.StringIO()) as stdout: - utils.print_dict({'K': 'k', 'Key': 'Value'}) - self.assertEqual('''\ -+----------+-------+ -| Property | Value | -+----------+-------+ -| K | k | -| Key | Value | -+----------+-------+ -''', stdout.getvalue()) - - with mock.patch('sys.stdout', new=six.StringIO()) as stdout: - utils.print_dict({'alarm_id': '262567fd-d79a-4bbb-a9d0-59d879b6', - 'name': u'\u6d4b\u8bd5', - 'description': u'\u6d4b\u8bd5', - 'state': 'insufficient data', - 'repeat_actions': 'False', - 'type': 'threshold', - 'threshold': '1.0', - 'statistic': 'avg', - 'time_constraints': '[{name: c1,' - '\\n description: test,' - '\\n start: 0 18 * * *,' - '\\n duration: 1,' - '\\n timezone: US}]'}, - wrap=72) - expected = u'''\ -+------------------+----------------------------------+ -| Property | Value | -+------------------+----------------------------------+ -| alarm_id | 262567fd-d79a-4bbb-a9d0-59d879b6 | -| description | \u6d4b\u8bd5 | -| name | \u6d4b\u8bd5 | -| repeat_actions | False | -| state | insufficient data | -| statistic | avg | -| threshold | 1.0 | -| time_constraints | [{name: c1, | -| | description: test, | -| | start: 0 18 * * *, | -| | duration: 1, | -| | timezone: US}] | -| type | threshold | -+------------------+----------------------------------+ -''' - # py2 prints str type, py3 prints unicode type - if six.PY2: - expected = expected.encode('utf-8') - self.assertEqual(expected, stdout.getvalue()) - - def test_print_list(self): - class Foo(object): - def __init__(self, one, two, three): - self.one = one - self.two = two - self.three = three - - foo_list = [ - Foo(10, 'a', 'B'), - Foo(8, 'c', 'c'), - Foo(12, '0', 'Z')] - - def do_print_list(sortby): - with mock.patch('sys.stdout', new=six.StringIO()) as stdout: - utils.print_list(foo_list, - ['one', 'two', 'three'], - ['1st', '2nd', '3rd'], - {'one': lambda o: o.one * 10}, - sortby) - return stdout.getvalue() - - printed = do_print_list(None) - self.assertEqual(printed, '''\ -+-----+-----+-----+ -| 1st | 2nd | 3rd | -+-----+-----+-----+ -| 100 | a | B | -| 80 | c | c | -| 120 | 0 | Z | -+-----+-----+-----+ -''') - - printed = do_print_list(0) - self.assertEqual(printed, '''\ -+-----+-----+-----+ -| 1st | 2nd | 3rd | -+-----+-----+-----+ -| 80 | c | c | -| 100 | a | B | -| 120 | 0 | Z | -+-----+-----+-----+ -''') - - printed = do_print_list(1) - self.assertEqual(printed, '''\ -+-----+-----+-----+ -| 1st | 2nd | 3rd | -+-----+-----+-----+ -| 120 | 0 | Z | -| 100 | a | B | -| 80 | c | c | -+-----+-----+-----+ -''') - - 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' - }) - - def test_args_array_to_list_of_dicts(self): - starts = ['0 11 * * *', '"0 11 * * *"', '\'0 11 * * *\''] - timezones = [None, 'US/Eastern', '"US/Eastern"', '\'US/Eastern\''] - descs = [None, 'de sc', '"de sc"', '\'de sc\''] - for start, tz, desc in itertools.product(starts, timezones, descs): - my_args = { - 'time_constraints': ['name=const1;start=%s;duration=1' - % start], - 'other': 'value' - } - expected = { - 'time_constraints': [dict(name='const1', - start='0 11 * * *', - duration='1')], - 'other': 'value' - } - if tz: - my_args['time_constraints'][0] += ';timezone=%s' % tz - expected['time_constraints'][0]['timezone'] = 'US/Eastern' - if desc: - my_args['time_constraints'][0] += ';description=%s' % desc - expected['time_constraints'][0]['description'] = 'de sc' - - cleaned = utils.args_array_to_list_of_dicts(my_args, - 'time_constraints') - self.assertEqual(expected, cleaned) - - def test_key_with_slash_to_nested_dict(self): - my_args = { - 'combination_rule/alarm_ids': ['id1', 'id2'], - 'combination_rule/operator': 'and', - 'threshold_rule/threshold': 400, - 'threshold_rule/statictic': 'avg', - 'threshold_rule/comparison_operator': 'or', - } - nested_dict = utils.key_with_slash_to_nested_dict(my_args) - self.assertEqual(nested_dict, { - 'combination_rule': {'alarm_ids': ['id1', 'id2'], - 'operator': 'and'}, - 'threshold_rule': {'threshold': 400, - 'statictic': 'avg', - 'comparison_operator': 'or'}, - }) - - def test_arg(self): - @utils.arg(help="not_required_no_default.") - def not_required_no_default(): - pass - _, args = not_required_no_default.__dict__['arguments'][0] - self.assertEqual(args['help'], "not_required_no_default.") - - @utils.arg(required=True, help="required_no_default.") - def required_no_default(): - pass - _, args = required_no_default.__dict__['arguments'][0] - self.assertEqual(args['help'], "required_no_default. Required.") - - @utils.arg(default=42, help="not_required_default.") - def not_required_default(): - pass - _, args = not_required_default.__dict__['arguments'][0] - self.assertEqual(args['help'], "not_required_default. Defaults to 42.") - - def test_merge_nested_dict(self): - dest = {'key': 'value', - 'nested': {'key2': 'value2', - 'key3': 'value3', - 'nested2': {'key': 'value', - 'some': 'thing'}}} - source = {'key': 'modified', - 'nested': {'key3': 'modified3', - 'nested2': {'key5': 'value5'}}} - utils.merge_nested_dict(dest, source, depth=1) - - self.assertEqual(dest, {'key': 'modified', - 'nested': {'key2': 'value2', - 'key3': 'modified3', - 'nested2': {'key5': 'value5'}}}) - - def test_merge_nested_dict_no_depth(self): - dest = {'key': 'value', - 'nested': {'key2': 'value2', - 'key3': 'value3', - 'nested2': {'key': 'value', - 'some': 'thing'}}} - source = {'key': 'modified', - 'nested': {'key3': 'modified3', - 'nested2': {'key5': 'value5'}}} - utils.merge_nested_dict(dest, source) - - self.assertEqual(dest, {'key': 'modified', - 'nested': {'key3': 'modified3', - 'nested2': {'key5': 'value5'}}}) - - @mock.patch('prettytable.PrettyTable') - def test_format_nested_list_of_dict(self, pt_mock): - actual_rows = [] - - def mock_add_row(row): - actual_rows.append(row) - - table = mock.Mock() - table.add_row = mock_add_row - table.get_string.return_value = "the table" - - test_data = [ - {'column_1': 'value_11', 'column_2': 'value_21'}, - {'column_1': 'value_12', 'column_2': 'value_22'} - - ] - columns = ['column_1', 'column_2'] - pt_mock.return_value = table - - rval = utils.format_nested_list_of_dict(test_data, columns) - self.assertEqual("the table", rval) - self.assertEqual([['value_11', 'value_21'], ['value_12', 'value_22']], - actual_rows) diff --git a/ceilometerclient/tests/unit/__init__.py b/ceilometerclient/tests/unit/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ceilometerclient/tests/unit/fakes.py b/ceilometerclient/tests/unit/fakes.py new file mode 100644 index 0000000..10d8d8c --- /dev/null +++ b/ceilometerclient/tests/unit/fakes.py @@ -0,0 +1,64 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from keystoneclient.v2_0 import client as ksclient + + +def script_keystone_client(): + ksclient.Client(auth_url='http://no.where', + insecure=False, + password='password', + tenant_id='', + tenant_name='tenant_name', + username='username').AndReturn(FakeKeystone('abcd1234')) + + +def fake_headers(): + return {'X-Auth-Token': 'abcd1234', + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'User-Agent': 'python-ceilometerclient'} + + +class FakeServiceCatalog(object): + @staticmethod + def url_for(endpoint_type, service_type): + return 'http://192.168.1.5:8004/v1/f14b41234' + + +class FakeKeystone(object): + service_catalog = FakeServiceCatalog() + + def __init__(self, auth_token): + self.auth_token = auth_token + + +class FakeHTTPResponse(object): + + version = 1.1 + + def __init__(self, status, reason, headers, body): + self.headers = headers + self.body = body + self.status = status + self.reason = reason + + def getheader(self, name, default=None): + return self.headers.get(name, default) + + def getheaders(self): + return self.headers.items() + + def read(self, amt=None): + b = self.body + self.body = None + return b diff --git a/ceilometerclient/tests/unit/test_client.py b/ceilometerclient/tests/unit/test_client.py new file mode 100644 index 0000000..d582d93 --- /dev/null +++ b/ceilometerclient/tests/unit/test_client.py @@ -0,0 +1,158 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# 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 mock + +from ceilometerclient import client +from ceilometerclient.tests.unit import fakes +from ceilometerclient.tests.unit import utils +from ceilometerclient.v1 import client as v1client +from ceilometerclient.v2 import client as v2client + +FAKE_ENV = { + 'username': 'username', + 'password': 'password', + 'tenant_name': 'tenant_name', + 'auth_url': 'http://no.where', + 'ceilometer_url': 'http://no.where', + 'auth_plugin': 'fake_auth', + 'token': '1234', + 'user_domain_name': 'default', + 'project_domain_name': 'default', +} + + +class ClientTest(utils.BaseTestCase): + + @staticmethod + def create_client(env, api_version=2, endpoint=None, exclude=[]): + env = dict((k, v) for k, v in env.items() + if k not in exclude) + + return client.get_client(api_version, **env) + + def test_client_version(self): + c1 = self.create_client(env=FAKE_ENV, api_version=1) + self.assertIsInstance(c1, v1client.Client) + + c2 = self.create_client(env=FAKE_ENV, api_version=2) + self.assertIsInstance(c2, v2client.Client) + + def test_client_auth_lambda(self): + env = FAKE_ENV.copy() + env['token'] = lambda: env['token'] + self.assertIsInstance(env['token'], + types.FunctionType) + c2 = self.create_client(env) + self.assertIsInstance(c2, v2client.Client) + + def test_client_auth_non_lambda(self): + env = FAKE_ENV.copy() + env['token'] = "1234" + self.assertIsInstance(env['token'], str) + c2 = self.create_client(env) + self.assertIsInstance(c2, v2client.Client) + + @mock.patch('keystoneclient.v2_0.client', fakes.FakeKeystone) + def test_client_without_auth_plugin(self): + env = FAKE_ENV.copy() + del env['auth_plugin'] + c = self.create_client(env, api_version=2, endpoint='fake_endpoint') + self.assertIsInstance(c.auth_plugin, client.AuthPlugin) + + def test_client_without_auth_plugin_keystone_v3(self): + env = FAKE_ENV.copy() + del env['auth_plugin'] + expected = { + 'username': 'username', + 'endpoint': 'http://no.where', + 'tenant_name': 'tenant_name', + 'service_type': None, + 'token': '1234', + 'endpoint_type': None, + 'auth_url': 'http://no.where', + 'tenant_id': None, + 'cacert': None, + 'password': 'password', + 'user_domain_name': 'default', + 'user_domain_id': None, + 'project_domain_name': 'default', + 'project_domain_id': None, + } + with mock.patch('ceilometerclient.client.AuthPlugin') as auth_plugin: + self.create_client(env, api_version=2, endpoint='http://no.where') + auth_plugin.assert_called_with(**expected) + + def test_client_with_auth_plugin(self): + c = self.create_client(FAKE_ENV, api_version=2) + self.assertIsInstance(c.auth_plugin, str) + + def test_v2_client_timeout_invalid_value(self): + env = FAKE_ENV.copy() + env['timeout'] = 'abc' + self.assertRaises(ValueError, self.create_client, env) + env['timeout'] = '1.5' + self.assertRaises(ValueError, self.create_client, env) + + def _test_v2_client_timeout_integer(self, timeout, expected_value): + env = FAKE_ENV.copy() + env['timeout'] = timeout + expected = { + 'auth_plugin': 'fake_auth', + 'timeout': expected_value, + 'original_ip': None, + 'http': None, + 'region_name': None, + 'verify': True, + 'timings': None, + 'keyring_saver': None, + 'cert': None, + 'endpoint_type': None, + 'user_agent': None, + 'debug': None, + } + cls = 'ceilometerclient.openstack.common.apiclient.client.HTTPClient' + with mock.patch(cls) as mocked: + self.create_client(env) + mocked.assert_called_with(**expected) + + def test_v2_client_timeout_zero(self): + self._test_v2_client_timeout_integer(0, None) + + def test_v2_client_timeout_valid_value(self): + self._test_v2_client_timeout_integer(30, 30) + + def test_v2_client_cacert_in_verify(self): + env = FAKE_ENV.copy() + env['cacert'] = '/path/to/cacert' + client = self.create_client(env) + self.assertEqual('/path/to/cacert', client.client.verify) + + def test_v2_client_certfile_and_keyfile(self): + env = FAKE_ENV.copy() + env['cert_file'] = '/path/to/cert' + env['key_file'] = '/path/to/keycert' + client = self.create_client(env) + self.assertEqual(('/path/to/cert', '/path/to/keycert'), + client.client.cert) + + +class ClientTest2(ClientTest): + @staticmethod + def create_client(env, api_version=2, endpoint=None, exclude=[]): + env = dict((k, v) for k, v in env.items() + if k not in exclude) + + # Run the same tests with direct instantiation of the Client + return client.Client(api_version, endpoint, **env) diff --git a/ceilometerclient/tests/unit/test_exc.py b/ceilometerclient/tests/unit/test_exc.py new file mode 100644 index 0000000..db8df32 --- /dev/null +++ b/ceilometerclient/tests/unit/test_exc.py @@ -0,0 +1,71 @@ +# Copyright 2013 eNovance +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# 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 ceilometerclient import exc +from ceilometerclient.tests.unit import utils + +HTTPEXCEPTIONS = {'HTTPBadRequest': exc.HTTPBadRequest, + 'HTTPUnauthorized': exc.HTTPUnauthorized, + 'HTTPForbidden': exc.HTTPForbidden, + 'HTTPNotFound': exc.HTTPNotFound, + 'HTTPMethodNotAllowed': exc.HTTPMethodNotAllowed, + 'HTTPConflict': exc.HTTPConflict, + 'HTTPOverLimit': exc.HTTPOverLimit, + 'HTTPInternalServerError': exc.HTTPInternalServerError, + 'HTTPNotImplemented': exc.HTTPNotImplemented, + 'HTTPBadGateway': exc.HTTPBadGateway, + 'HTTPServiceUnavailable': exc.HTTPServiceUnavailable} + + +class HTTPExceptionsTest(utils.BaseTestCase): + def test_str_no_details(self): + for k, v in HTTPEXCEPTIONS.items(): + exception = v() + ret_str = k + " (HTTP " + str(exception.code) + ")" + self.assertEqual(ret_str, str(exception)) + + def test_str_no_json(self): + for k, v in HTTPEXCEPTIONS.items(): + exception = v(details="foo") + ret_str = k + " (HTTP " + str(exception.code) + ")" + self.assertEqual(ret_str, str(exception)) + + def test_str_no_error_message(self): + for k, v in HTTPEXCEPTIONS.items(): + exception = v(details=json.dumps({})) + ret_str = k + " (HTTP " + str(exception.code) + ")" + self.assertEqual(ret_str, str(exception)) + + def test_str_no_faultstring(self): + for k, v in HTTPEXCEPTIONS.items(): + exception = v( + details=json.dumps({"error_message": {"foo": "bar"}})) + ret_str = k + " (HTTP " + str(exception.code) + ")" + self.assertEqual(ret_str, str(exception)) + + def test_str_error_message_unknown_format(self): + for k, v in HTTPEXCEPTIONS.items(): + exception = v(details=json.dumps({"error_message": "oops"})) + ret_str = k + " (HTTP " + str(exception.code) + ")" + self.assertEqual(ret_str, str(exception)) + + def test_str_faultstring(self): + for k, v in HTTPEXCEPTIONS.items(): + exception = v(details=json.dumps( + {"error_message": {"faultstring": "oops"}})) + ret_str = k + " (HTTP " + str(exception.code) + ") ERROR oops" + self.assertEqual(ret_str, str(exception)) diff --git a/ceilometerclient/tests/unit/test_shell.py b/ceilometerclient/tests/unit/test_shell.py new file mode 100644 index 0000000..7d06ab7 --- /dev/null +++ b/ceilometerclient/tests/unit/test_shell.py @@ -0,0 +1,225 @@ +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# 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 sys + +import fixtures +from keystoneclient import session as ks_session +import mock +import six +from testtools import matchers + +from ceilometerclient import exc +from ceilometerclient.openstack.common.apiclient import client as api_client +from ceilometerclient import shell as ceilometer_shell +from ceilometerclient.tests.unit import utils +from ceilometerclient.v2 import client as v2client + +FAKE_V2_ENV = {'OS_USERNAME': 'username', + 'OS_PASSWORD': 'password', + 'OS_TENANT_NAME': 'tenant_name', + 'OS_AUTH_URL': 'http://localhost:5000/v2.0'} + +FAKE_V3_ENV = {'OS_USERNAME': 'username', + 'OS_PASSWORD': 'password', + 'OS_USER_DOMAIN_NAME': 'domain_name', + 'OS_PROJECT_ID': '1234567890', + 'OS_AUTH_URL': 'http://localhost:5000/v3'} + + +class ShellTestBase(utils.BaseTestCase): + + # Patch os.environ to avoid required auth info. + def make_env(self, env_version, exclude=None): + env = dict((k, v) for k, v in env_version.items() if k != exclude) + self.useFixture(fixtures.MonkeyPatch('os.environ', env)) + + +class ShellHelpTest(ShellTestBase): + RE_OPTIONS = re.DOTALL | re.MULTILINE + + @mock.patch('sys.stdout', new=six.StringIO()) + @mock.patch.object(ks_session, 'Session', mock.MagicMock()) + @mock.patch.object(v2client.client.HTTPClient, + 'client_request', mock.MagicMock()) + def shell(self, argstr): + try: + _shell = ceilometer_shell.CeilometerShell() + _shell.main(argstr.split()) + except SystemExit: + exc_type, exc_value, exc_traceback = sys.exc_info() + self.assertEqual(exc_value.code, 0) + + return sys.stdout.getvalue() + + def test_help_unknown_command(self): + self.assertRaises(exc.CommandError, self.shell, 'help foofoo') + + def test_help(self): + required = [ + '.*?^usage: ceilometer', + '.*?^See "ceilometer 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: ceilometer meter-list', + ".*?^List the user's meter", + ] + argstrings = [ + 'help meter-list', + ] + for argstr in argstrings: + help_text = self.shell(argstr) + for r in required: + self.assertThat(help_text, + matchers.MatchesRegex(r, self.RE_OPTIONS)) + + +class ShellKeystoneV2Test(ShellTestBase): + + @mock.patch.object(ks_session, 'Session') + def test_debug_switch_raises_error(self, mock_ksclient): + mock_ksclient.side_effect = exc.HTTPUnauthorized + self.make_env(FAKE_V2_ENV) + args = ['--debug', 'event-list'] + self.assertRaises(exc.CommandError, ceilometer_shell.main, args) + + @mock.patch.object(ks_session, 'Session') + def test_dash_d_switch_raises_error(self, mock_ksclient): + mock_ksclient.side_effect = exc.CommandError("FAIL") + self.make_env(FAKE_V2_ENV) + args = ['-d', 'event-list'] + self.assertRaises(exc.CommandError, ceilometer_shell.main, args) + + @mock.patch('sys.stderr') + @mock.patch.object(ks_session, 'Session') + def test_no_debug_switch_no_raises_errors(self, mock_ksclient, __): + mock_ksclient.side_effect = exc.HTTPUnauthorized("FAIL") + self.make_env(FAKE_V2_ENV) + args = ['event-list'] + self.assertRaises(SystemExit, ceilometer_shell.main, args) + + +class ShellKeystoneV3Test(ShellTestBase): + + @mock.patch.object(ks_session, 'Session') + def test_debug_switch_raises_error(self, mock_ksclient): + mock_ksclient.side_effect = exc.HTTPUnauthorized + self.make_env(FAKE_V3_ENV) + args = ['--debug', 'event-list'] + self.assertRaises(exc.CommandError, ceilometer_shell.main, args) + + @mock.patch.object(ks_session, 'Session') + def test_dash_d_switch_raises_error(self, mock_ksclient): + mock_ksclient.side_effect = exc.CommandError("FAIL") + self.make_env(FAKE_V3_ENV) + args = ['-d', 'event-list'] + self.assertRaises(exc.CommandError, ceilometer_shell.main, args) + + @mock.patch('sys.stderr') + @mock.patch.object(ks_session, 'Session') + def test_no_debug_switch_no_raises_errors(self, mock_ksclient, __): + mock_ksclient.side_effect = exc.HTTPUnauthorized("FAIL") + self.make_env(FAKE_V3_ENV) + args = ['event-list'] + self.assertRaises(SystemExit, ceilometer_shell.main, args) + + +class ShellTimeoutTest(ShellTestBase): + + @mock.patch('sys.stderr', new=six.StringIO()) + def _test_timeout(self, timeout, expected_msg): + args = ['--timeout', timeout, 'alarm-list'] + self.assertRaises(SystemExit, ceilometer_shell.main, args) + self.assertEqual(expected_msg, sys.stderr.getvalue().splitlines()[-1]) + + def test_timeout_invalid_value(self): + expected_msg = ('ceilometer: error: argument --timeout: ' + 'abc must be an integer') + self._test_timeout('abc', expected_msg) + + def test_timeout_negative_value(self): + expected_msg = ('ceilometer: error: argument --timeout: ' + '-1 must be greater than 0') + self._test_timeout('-1', expected_msg) + + def test_timeout_float_value(self): + expected_msg = ('ceilometer: error: argument --timeout: ' + '1.5 must be an integer') + self._test_timeout('1.5', expected_msg) + + def test_timeout_zero(self): + expected_msg = ('ceilometer: error: argument --timeout: ' + '0 must be greater than 0') + self._test_timeout('0', expected_msg) + + +class ShellInsecureTest(ShellTestBase): + + @mock.patch.object(api_client, 'HTTPClient') + def test_insecure_true_ceilometer(self, mocked_client): + self.make_env(FAKE_V2_ENV) + args = ['--debug', '--os-insecure', 'true', 'alarm-list'] + self.assertIsNone(ceilometer_shell.main(args)) + args, kwargs = mocked_client.call_args + self.assertEqual(False, kwargs.get('verify')) + + @mock.patch.object(ks_session, 'Session') + def test_insecure_true_keystone(self, mocked_session): + mocked_session.side_effect = exc.HTTPUnauthorized("FAIL") + self.make_env(FAKE_V2_ENV) + args = ['--debug', '--os-insecure', 'true', 'alarm-list'] + self.assertRaises(exc.CommandError, ceilometer_shell.main, args) + mocked_session.assert_called_with(verify=False, cert='') + + @mock.patch.object(api_client, 'HTTPClient') + def test_insecure_false_ceilometer(self, mocked_client): + self.make_env(FAKE_V2_ENV) + args = ['--debug', '--os-insecure', 'false', 'alarm-list'] + self.assertIsNone(ceilometer_shell.main(args)) + args, kwargs = mocked_client.call_args + self.assertEqual(True, kwargs.get('verify')) + + @mock.patch.object(ks_session, 'Session') + def test_insecure_false_keystone(self, mocked_session): + mocked_session.side_effect = exc.HTTPUnauthorized("FAIL") + self.make_env(FAKE_V2_ENV) + args = ['--debug', '--os-insecure', 'false', 'alarm-list'] + self.assertRaises(exc.CommandError, ceilometer_shell.main, args) + mocked_session.assert_called_with(verify=True, cert='') + + +class ShellEndpointTest(ShellTestBase): + + @mock.patch('ceilometerclient.v2.client.Client') + def _test_endpoint_and_token(self, token_name, endpoint_name, mocked): + args = ['--debug', token_name, 'fake-token', + endpoint_name, 'http://fake-url', 'alarm-list'] + self.assertEqual(None, ceilometer_shell.main(args)) + args, kwargs = mocked.call_args + self.assertEqual('http://fake-url', kwargs.get('endpoint')) + self.assertEqual('fake-token', kwargs.get('token')) + + def test_endpoint_and_token(self): + self._test_endpoint_and_token('--os-auth-token', '--ceilometer-url') + self._test_endpoint_and_token('--os-auth-token', '--os-endpoint') + self._test_endpoint_and_token('--os-token', '--ceilometer-url') + self._test_endpoint_and_token('--os-token', '--os-endpoint') diff --git a/ceilometerclient/tests/unit/test_utils.py b/ceilometerclient/tests/unit/test_utils.py new file mode 100644 index 0000000..00bd416 --- /dev/null +++ b/ceilometerclient/tests/unit/test_utils.py @@ -0,0 +1,265 @@ +# 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 itertools + +import mock +import six + +from ceilometerclient.common import utils +from ceilometerclient.tests.unit import utils as test_utils + + +class UtilsTest(test_utils.BaseTestCase): + + def test_prettytable(self): + class Struct(object): + def __init__(self, **entries): + self.__dict__.update(entries) + + # test that the prettytable output is wellformatted (left-aligned) + with mock.patch('sys.stdout', new=six.StringIO()) as stdout: + utils.print_dict({'K': 'k', 'Key': 'Value'}) + self.assertEqual('''\ ++----------+-------+ +| Property | Value | ++----------+-------+ +| K | k | +| Key | Value | ++----------+-------+ +''', stdout.getvalue()) + + with mock.patch('sys.stdout', new=six.StringIO()) as stdout: + utils.print_dict({'alarm_id': '262567fd-d79a-4bbb-a9d0-59d879b6', + 'name': u'\u6d4b\u8bd5', + 'description': u'\u6d4b\u8bd5', + 'state': 'insufficient data', + 'repeat_actions': 'False', + 'type': 'threshold', + 'threshold': '1.0', + 'statistic': 'avg', + 'time_constraints': '[{name: c1,' + '\\n description: test,' + '\\n start: 0 18 * * *,' + '\\n duration: 1,' + '\\n timezone: US}]'}, + wrap=72) + expected = u'''\ ++------------------+----------------------------------+ +| Property | Value | ++------------------+----------------------------------+ +| alarm_id | 262567fd-d79a-4bbb-a9d0-59d879b6 | +| description | \u6d4b\u8bd5 | +| name | \u6d4b\u8bd5 | +| repeat_actions | False | +| state | insufficient data | +| statistic | avg | +| threshold | 1.0 | +| time_constraints | [{name: c1, | +| | description: test, | +| | start: 0 18 * * *, | +| | duration: 1, | +| | timezone: US}] | +| type | threshold | ++------------------+----------------------------------+ +''' + # py2 prints str type, py3 prints unicode type + if six.PY2: + expected = expected.encode('utf-8') + self.assertEqual(expected, stdout.getvalue()) + + def test_print_list(self): + class Foo(object): + def __init__(self, one, two, three): + self.one = one + self.two = two + self.three = three + + foo_list = [ + Foo(10, 'a', 'B'), + Foo(8, 'c', 'c'), + Foo(12, '0', 'Z')] + + def do_print_list(sortby): + with mock.patch('sys.stdout', new=six.StringIO()) as stdout: + utils.print_list(foo_list, + ['one', 'two', 'three'], + ['1st', '2nd', '3rd'], + {'one': lambda o: o.one * 10}, + sortby) + return stdout.getvalue() + + printed = do_print_list(None) + self.assertEqual(printed, '''\ ++-----+-----+-----+ +| 1st | 2nd | 3rd | ++-----+-----+-----+ +| 100 | a | B | +| 80 | c | c | +| 120 | 0 | Z | ++-----+-----+-----+ +''') + + printed = do_print_list(0) + self.assertEqual(printed, '''\ ++-----+-----+-----+ +| 1st | 2nd | 3rd | ++-----+-----+-----+ +| 80 | c | c | +| 100 | a | B | +| 120 | 0 | Z | ++-----+-----+-----+ +''') + + printed = do_print_list(1) + self.assertEqual(printed, '''\ ++-----+-----+-----+ +| 1st | 2nd | 3rd | ++-----+-----+-----+ +| 120 | 0 | Z | +| 100 | a | B | +| 80 | c | c | ++-----+-----+-----+ +''') + + 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' + }) + + def test_args_array_to_list_of_dicts(self): + starts = ['0 11 * * *', '"0 11 * * *"', '\'0 11 * * *\''] + timezones = [None, 'US/Eastern', '"US/Eastern"', '\'US/Eastern\''] + descs = [None, 'de sc', '"de sc"', '\'de sc\''] + for start, tz, desc in itertools.product(starts, timezones, descs): + my_args = { + 'time_constraints': ['name=const1;start=%s;duration=1' + % start], + 'other': 'value' + } + expected = { + 'time_constraints': [dict(name='const1', + start='0 11 * * *', + duration='1')], + 'other': 'value' + } + if tz: + my_args['time_constraints'][0] += ';timezone=%s' % tz + expected['time_constraints'][0]['timezone'] = 'US/Eastern' + if desc: + my_args['time_constraints'][0] += ';description=%s' % desc + expected['time_constraints'][0]['description'] = 'de sc' + + cleaned = utils.args_array_to_list_of_dicts(my_args, + 'time_constraints') + self.assertEqual(expected, cleaned) + + def test_key_with_slash_to_nested_dict(self): + my_args = { + 'combination_rule/alarm_ids': ['id1', 'id2'], + 'combination_rule/operator': 'and', + 'threshold_rule/threshold': 400, + 'threshold_rule/statictic': 'avg', + 'threshold_rule/comparison_operator': 'or', + } + nested_dict = utils.key_with_slash_to_nested_dict(my_args) + self.assertEqual(nested_dict, { + 'combination_rule': {'alarm_ids': ['id1', 'id2'], + 'operator': 'and'}, + 'threshold_rule': {'threshold': 400, + 'statictic': 'avg', + 'comparison_operator': 'or'}, + }) + + def test_arg(self): + @utils.arg(help="not_required_no_default.") + def not_required_no_default(): + pass + _, args = not_required_no_default.__dict__['arguments'][0] + self.assertEqual(args['help'], "not_required_no_default.") + + @utils.arg(required=True, help="required_no_default.") + def required_no_default(): + pass + _, args = required_no_default.__dict__['arguments'][0] + self.assertEqual(args['help'], "required_no_default. Required.") + + @utils.arg(default=42, help="not_required_default.") + def not_required_default(): + pass + _, args = not_required_default.__dict__['arguments'][0] + self.assertEqual(args['help'], "not_required_default. Defaults to 42.") + + def test_merge_nested_dict(self): + dest = {'key': 'value', + 'nested': {'key2': 'value2', + 'key3': 'value3', + 'nested2': {'key': 'value', + 'some': 'thing'}}} + source = {'key': 'modified', + 'nested': {'key3': 'modified3', + 'nested2': {'key5': 'value5'}}} + utils.merge_nested_dict(dest, source, depth=1) + + self.assertEqual(dest, {'key': 'modified', + 'nested': {'key2': 'value2', + 'key3': 'modified3', + 'nested2': {'key5': 'value5'}}}) + + def test_merge_nested_dict_no_depth(self): + dest = {'key': 'value', + 'nested': {'key2': 'value2', + 'key3': 'value3', + 'nested2': {'key': 'value', + 'some': 'thing'}}} + source = {'key': 'modified', + 'nested': {'key3': 'modified3', + 'nested2': {'key5': 'value5'}}} + utils.merge_nested_dict(dest, source) + + self.assertEqual(dest, {'key': 'modified', + 'nested': {'key3': 'modified3', + 'nested2': {'key5': 'value5'}}}) + + @mock.patch('prettytable.PrettyTable') + def test_format_nested_list_of_dict(self, pt_mock): + actual_rows = [] + + def mock_add_row(row): + actual_rows.append(row) + + table = mock.Mock() + table.add_row = mock_add_row + table.get_string.return_value = "the table" + + test_data = [ + {'column_1': 'value_11', 'column_2': 'value_21'}, + {'column_1': 'value_12', 'column_2': 'value_22'} + + ] + columns = ['column_1', 'column_2'] + pt_mock.return_value = table + + rval = utils.format_nested_list_of_dict(test_data, columns) + self.assertEqual("the table", rval) + self.assertEqual([['value_11', 'value_21'], ['value_12', 'value_22']], + actual_rows) diff --git a/ceilometerclient/tests/unit/utils.py b/ceilometerclient/tests/unit/utils.py new file mode 100644 index 0000000..57bc276 --- /dev/null +++ b/ceilometerclient/tests/unit/utils.py @@ -0,0 +1,24 @@ +# 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 fixtures +import testtools + + +class BaseTestCase(testtools.TestCase): + + def setUp(self): + super(BaseTestCase, self).setUp() + self.useFixture(fixtures.FakeLogger()) diff --git a/ceilometerclient/tests/unit/v1/__init__.py b/ceilometerclient/tests/unit/v1/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ceilometerclient/tests/unit/v1/test_meters.py b/ceilometerclient/tests/unit/v1/test_meters.py new file mode 100644 index 0000000..afd9a1b --- /dev/null +++ b/ceilometerclient/tests/unit/v1/test_meters.py @@ -0,0 +1,162 @@ +# 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 ceilometerclient.openstack.common.apiclient import client +from ceilometerclient.openstack.common.apiclient import fake_client +from ceilometerclient.tests.unit import utils +import ceilometerclient.v1.meters + + +fixtures = { + '/v1/meters': { + 'GET': ( + {}, + {'meters': [ + { + 'resource_id': 'a', + 'project_id': 'dig_the_ditch', + 'user_id': 'freddy', + 'name': 'this', + 'type': 'counter', + }, + { + 'resource_id': 'b', + 'project_id': 'dig_the_ditch', + 'user_id': 'joey', + 'name': 'this', + 'type': 'counter', + }, + ]}, + ), + }, + '/v1/users/joey/meters': { + 'GET': ( + {}, + {'meters': [ + { + 'resource_id': 'b', + 'project_id': 'dig_the_ditch', + 'user_id': 'joey', + 'name': 'this', + 'type': 'counter', + }, + ]}, + ), + }, + '/v1/projects/dig_the_ditch/meters': { + 'GET': ( + {}, + {'meters': [ + { + 'resource_id': 'b', + 'project_id': 'dig_the_ditch', + 'user_id': 'joey', + 'name': 'this', + 'type': 'counter', + }, + ]}, + ), + }, + '/v1/sources/openstack/meters': { + 'GET': ( + {}, + {'meters': [ + { + 'resource_id': 'b', + 'project_id': 'dig_the_ditch', + 'user_id': 'joey', + 'name': 'this', + 'type': 'counter', + }, + { + 'resource_id': 'q', + 'project_id': 'dig_the_trench', + 'user_id': 'joey', + 'name': 'this', + 'type': 'counter', + }, + ]}, + ), + }, + '/v1/meters?metadata.zxc_id=foo': { + 'GET': ( + {}, + {'meters': [ + { + 'resource_id': 'b', + 'project_id': 'dig_the_ditch', + 'user_id': 'joey', + 'name': 'this', + 'type': 'counter', + }, + ]}, + ), + }, +} + + +class MeterManagerTest(utils.BaseTestCase): + + def setUp(self): + super(MeterManagerTest, self).setUp() + self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) + self.api = client.BaseClient(self.http_client) + self.mgr = ceilometerclient.v1.meters.MeterManager(self.api) + + def test_list_all(self): + resources = list(self.mgr.list()) + expect = [ + 'GET', '/v1/meters' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(resources), 2) + self.assertEqual(resources[0].resource_id, 'a') + self.assertEqual(resources[1].resource_id, 'b') + + def test_list_by_source(self): + resources = list(self.mgr.list(source='openstack')) + expect = [ + 'GET', '/v1/sources/openstack/meters' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(resources), 2) + self.assertEqual(resources[0].resource_id, 'b') + self.assertEqual(resources[1].resource_id, 'q') + + def test_list_by_user(self): + resources = list(self.mgr.list(user_id='joey')) + expect = [ + 'GET', '/v1/users/joey/meters' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(resources), 1) + self.assertEqual(resources[0].resource_id, 'b') + + def test_list_by_project(self): + resources = list(self.mgr.list(project_id='dig_the_ditch')) + expect = [ + 'GET', '/v1/projects/dig_the_ditch/meters' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(resources), 1) + self.assertEqual(resources[0].resource_id, 'b') + + def test_list_by_metaquery(self): + resources = list(self.mgr.list(metaquery='metadata.zxc_id=foo')) + expect = [ + 'GET', '/v1/meters?metadata.zxc_id=foo' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(resources), 1) + self.assertEqual(resources[0].resource_id, 'b') diff --git a/ceilometerclient/tests/unit/v1/test_projects.py b/ceilometerclient/tests/unit/v1/test_projects.py new file mode 100644 index 0000000..7b31bce --- /dev/null +++ b/ceilometerclient/tests/unit/v1/test_projects.py @@ -0,0 +1,65 @@ +# 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 ceilometerclient.openstack.common.apiclient import client +from ceilometerclient.openstack.common.apiclient import fake_client +from ceilometerclient.tests.unit import utils +import ceilometerclient.v1.meters + + +fixtures = { + '/v1/projects': { + 'GET': ( + {}, + {'projects': [ + 'a', + 'b', + ]}, + ), + }, + '/v1/sources/source_b/projects': { + 'GET': ( + {}, + {'projects': ['b']}, + ), + }, +} + + +class ProjectManagerTest(utils.BaseTestCase): + + def setUp(self): + super(ProjectManagerTest, self).setUp() + self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) + self.api = client.BaseClient(self.http_client) + self.mgr = ceilometerclient.v1.meters.ProjectManager(self.api) + + def test_list_all(self): + projects = list(self.mgr.list()) + expect = [ + 'GET', '/v1/projects' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(projects), 2) + self.assertEqual(projects[0].project_id, 'a') + self.assertEqual(projects[1].project_id, 'b') + + def test_list_by_source(self): + projects = list(self.mgr.list(source='source_b')) + expect = [ + 'GET', '/v1/sources/source_b/projects' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(projects), 1) + self.assertEqual(projects[0].project_id, 'b') diff --git a/ceilometerclient/tests/unit/v1/test_resources.py b/ceilometerclient/tests/unit/v1/test_resources.py new file mode 100644 index 0000000..cfc4f6c --- /dev/null +++ b/ceilometerclient/tests/unit/v1/test_resources.py @@ -0,0 +1,161 @@ +# 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 ceilometerclient.openstack.common.apiclient import client +from ceilometerclient.openstack.common.apiclient import fake_client +from ceilometerclient.tests.unit import utils +import ceilometerclient.v1.meters + + +fixtures = { + '/v1/resources': { + 'GET': ( + {}, + {'resources': [ + { + 'resource_id': 'a', + 'project_id': 'project_bla', + 'user_id': 'freddy', + 'timestamp': 'now', + 'meter': ['this', 'that'], + 'metadata': {'zxc_id': 'bla'}, + }, + { + 'resource_id': 'b', + 'project_id': 'dig_the_ditch', + 'user_id': 'joey', + 'timestamp': 'now', + 'meter': ['this', 'that'], + 'metadata': {'zxc_id': 'foo'}, + }, + ]}, + ), + }, + '/v1/users/joey/resources': { + 'GET': ( + {}, + {'resources': [ + { + 'resource_id': 'b', + 'project_id': 'dig_the_ditch', + 'user_id': 'joey', + 'timestamp': 'now', + 'meter': ['this', 'that'], + 'metadata': {'zxc_id': 'foo'}, + }, + ]}, + ), + }, + '/v1/resources?metadata.zxc_id=foo': { + 'GET': ( + {}, + {'resources': [ + { + 'resource_id': 'b', + 'project_id': 'dig_the_ditch', + 'user_id': 'joey', + 'timestamp': 'now', + 'meter': ['this', 'that'], + 'metadata': {'zxc_id': 'foo'}, + }, + ]}, + ), + }, + '/v1/projects/project_bla/resources': { + 'GET': ( + {}, + {'resources': [ + { + 'resource_id': 'a', + 'project_id': 'project_bla', + 'user_id': 'freddy', + 'timestamp': 'now', + 'meter': ['this', 'that'], + 'metadata': {'zxc_id': 'bla'}, + }, + ]}, + ), + }, + '/v1/resources?start_timestamp=now&end_timestamp=now': { + 'GET': ( + {}, + {'resources': [ + { + 'resource_id': 'b', + 'project_id': 'dig_the_ditch', + 'user_id': 'joey', + 'timestamp': 'now', + 'meter': ['this', 'that'], + 'metadata': {'zxc_id': 'foo'}, + }, + ]}, + ), + }, +} + + +class ResourceManagerTest(utils.BaseTestCase): + + def setUp(self): + super(ResourceManagerTest, self).setUp() + self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) + self.api = client.BaseClient(self.http_client) + self.mgr = ceilometerclient.v1.meters.ResourceManager(self.api) + + def test_list_all(self): + resources = list(self.mgr.list()) + expect = [ + 'GET', '/v1/resources' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(resources), 2) + self.assertEqual(resources[0].resource_id, 'a') + self.assertEqual(resources[1].resource_id, 'b') + + def test_list_by_user(self): + resources = list(self.mgr.list(user_id='joey')) + expect = [ + 'GET', '/v1/users/joey/resources' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(resources), 1) + self.assertEqual(resources[0].resource_id, 'b') + + def test_list_by_metaquery(self): + resources = list(self.mgr.list(metaquery='metadata.zxc_id=foo')) + expect = [ + 'GET', '/v1/resources?metadata.zxc_id=foo' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(resources), 1) + self.assertEqual(resources[0].resource_id, 'b') + + def test_list_by_project(self): + resources = list(self.mgr.list(project_id='project_bla')) + expect = [ + 'GET', '/v1/projects/project_bla/resources' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(resources), 1) + self.assertEqual(resources[0].resource_id, 'a') + + def test_list_by_timestamp(self): + resources = list(self.mgr.list(start_timestamp='now', + end_timestamp='now')) + expect = [ + 'GET', '/v1/resources?start_timestamp=now&end_timestamp=now' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(resources), 1) + self.assertEqual(resources[0].resource_id, 'b') diff --git a/ceilometerclient/tests/unit/v1/test_samples.py b/ceilometerclient/tests/unit/v1/test_samples.py new file mode 100644 index 0000000..0f1a029 --- /dev/null +++ b/ceilometerclient/tests/unit/v1/test_samples.py @@ -0,0 +1,196 @@ +# 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 ceilometerclient.openstack.common.apiclient import client +from ceilometerclient.openstack.common.apiclient import fake_client +from ceilometerclient.tests.unit import utils +import ceilometerclient.v1.meters + + +fixtures = { + '/v1/users/freddy/meters/balls': { + 'GET': ( + {}, + {'events': [ + { + 'resource_id': 'inst-0045', + 'project_id': 'melbourne_open', + 'user_id': 'freddy', + 'name': 'tennis', + 'type': 'counter', + 'unit': 'balls', + 'volume': 3, + 'timestamp': None, + 'resource_metadata': None, + }, + ]}, + ), + }, + '/v1/sources/openstack/meters/this': { + 'GET': ( + {}, + {'events': [ + { + 'resource_id': 'b', + 'project_id': 'dig_the_ditch', + 'user_id': 'joey', + 'name': 'this', + 'type': 'counter', + 'unit': 'b', + 'volume': 45, + 'timestamp': None, + 'resource_metadata': None, + }, + ]}, + ), + }, + '/v1/projects/dig_the_ditch/meters/meters': { + 'GET': ( + {}, + {'events': [ + { + 'resource_id': 'b', + 'project_id': 'dig_the_ditch', + 'user_id': 'joey', + 'name': 'meters', + 'type': 'counter', + 'unit': 'meters', + 'volume': 345, + 'timestamp': None, + 'resource_metadata': None, + }, + ]}, + ), + }, + '/v1/meters?metadata.zxc_id=foo': { + 'GET': ( + {}, + {'events': [ + { + 'resource_id': 'b', + 'project_id': 'dig_the_ditch', + 'user_id': 'joey', + 'name': 'this', + 'type': 'counter', + 'unit': 'meters', + 'volume': 98, + 'timestamp': None, + 'resource_metadata': {'zxc_id': 'foo'}, + }, + ]}, + ), + }, + '/v1/users/freddy/meters/balls?start_timestamp=now&end_timestamp=now': { + 'GET': ( + {}, + {'events': [ + { + 'resource_id': 'inst-0045', + 'project_id': 'melbourne_open', + 'user_id': 'freddy', + 'name': 'tennis', + 'type': 'counter', + 'unit': 'balls', + 'volume': 3, + 'timestamp': 'now', + 'resource_metadata': None, + }, + + ]}, + ), + }, + '/v1/meters': { + 'GET': ( + {}, + {'meters': []}, + ), + }, +} + + +class SampleManagerTest(utils.BaseTestCase): + + def setUp(self): + super(SampleManagerTest, self).setUp() + self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) + self.api = client.BaseClient(self.http_client) + self.mgr = ceilometerclient.v1.meters.SampleManager(self.api) + + def test_list_all(self): + samples = list(self.mgr.list(counter_name=None)) + expect = [ + 'GET', '/v1/meters' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(samples), 0) + + def test_list_by_source(self): + samples = list(self.mgr.list(source='openstack', + counter_name='this')) + expect = [ + 'GET', '/v1/sources/openstack/meters/this' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(samples), 1) + self.assertEqual(samples[0].resource_id, 'b') + + def test_list_by_user(self): + samples = list(self.mgr.list(user_id='freddy', + counter_name='balls')) + expect = [ + 'GET', '/v1/users/freddy/meters/balls' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(samples), 1) + self.assertEqual(samples[0].project_id, 'melbourne_open') + self.assertEqual(samples[0].user_id, 'freddy') + self.assertEqual(samples[0].volume, 3) + + def test_list_by_project(self): + samples = list(self.mgr.list(project_id='dig_the_ditch', + counter_name='meters')) + expect = [ + 'GET', '/v1/projects/dig_the_ditch/meters/meters' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(samples), 1) + self.assertEqual(samples[0].project_id, 'dig_the_ditch') + self.assertEqual(samples[0].volume, 345) + self.assertEqual(samples[0].unit, 'meters') + + def test_list_by_metaquery(self): + samples = list(self.mgr.list(metaquery='metadata.zxc_id=foo', + counter_name='this')) + expect = [ + 'GET', '/v1/meters?metadata.zxc_id=foo' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(samples), 1) + self.assertEqual(samples[0].resource_metadata['zxc_id'], 'foo') + + def test_list_by_timestamp(self): + samples = list(self.mgr.list(user_id='freddy', + counter_name='balls', + start_timestamp='now', + end_timestamp='now')) + expect = [ + 'GET', + '/v1/users/freddy/meters/balls?' + + 'start_timestamp=now&end_timestamp=now' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(samples), 1) + self.assertEqual(samples[0].project_id, 'melbourne_open') + self.assertEqual(samples[0].user_id, 'freddy') + self.assertEqual(samples[0].volume, 3) diff --git a/ceilometerclient/tests/unit/v1/test_users.py b/ceilometerclient/tests/unit/v1/test_users.py new file mode 100644 index 0000000..e8e98a1 --- /dev/null +++ b/ceilometerclient/tests/unit/v1/test_users.py @@ -0,0 +1,65 @@ +# 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 ceilometerclient.openstack.common.apiclient import client +from ceilometerclient.openstack.common.apiclient import fake_client +from ceilometerclient.tests.unit import utils +import ceilometerclient.v1.meters + + +fixtures = { + '/v1/users': { + 'GET': ( + {}, + {'users': [ + 'a', + 'b', + ]}, + ), + }, + '/v1/sources/source_b/users': { + 'GET': ( + {}, + {'users': ['b']}, + ), + }, +} + + +class UserManagerTest(utils.BaseTestCase): + + def setUp(self): + super(UserManagerTest, self).setUp() + self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) + self.api = client.BaseClient(self.http_client) + self.mgr = ceilometerclient.v1.meters.UserManager(self.api) + + def test_list_all(self): + users = list(self.mgr.list()) + expect = [ + 'GET', '/v1/users' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(users), 2) + self.assertEqual(users[0].user_id, 'a') + self.assertEqual(users[1].user_id, 'b') + + def test_list_by_source(self): + users = list(self.mgr.list(source='source_b')) + expect = [ + 'GET', '/v1/sources/source_b/users' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(users), 1) + self.assertEqual(users[0].user_id, 'b') diff --git a/ceilometerclient/tests/unit/v2/__init__.py b/ceilometerclient/tests/unit/v2/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ceilometerclient/tests/unit/v2/test_alarms.py b/ceilometerclient/tests/unit/v2/test_alarms.py new file mode 100644 index 0000000..4239d2f --- /dev/null +++ b/ceilometerclient/tests/unit/v2/test_alarms.py @@ -0,0 +1,540 @@ +# +# Copyright 2013 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 copy + +import six +from six.moves import xrange # noqa +import testtools + +from ceilometerclient import exc +from ceilometerclient.openstack.common.apiclient import client +from ceilometerclient.openstack.common.apiclient import fake_client +from ceilometerclient.v2 import alarms + +AN_ALARM = {u'alarm_actions': [u'http://site:8000/alarm'], + u'ok_actions': [u'http://site:8000/ok'], + u'description': u'An alarm', + u'type': u'threshold', + u'severity': 'low', + u'threshold_rule': { + u'meter_name': u'storage.objects', + u'query': [{u'field': u'key_name', + u'op': u'eq', + u'value': u'key_value'}], + u'evaluation_periods': 2, + u'period': 240.0, + u'statistic': u'avg', + u'threshold': 200.0, + u'comparison_operator': 'gt'}, + u'time_constraints': [ + { + u'name': u'cons1', + u'description': u'desc1', + u'start': u'0 11 * * *', + u'duration': 300, + u'timezone': u''}, + { + u'name': u'cons2', + u'description': u'desc2', + u'start': u'0 23 * * *', + u'duration': 600, + u'timezone': ''}], + u'timestamp': u'2013-05-09T13:41:23.085000', + u'enabled': True, + u'alarm_id': u'alarm-id', + u'state': u'ok', + u'insufficient_data_actions': [u'http://site:8000/nodata'], + u'user_id': u'user-id', + u'project_id': u'project-id', + u'state_timestamp': u'2013-05-09T13:41:23.085000', + u'repeat_actions': False, + u'name': 'SwiftObjectAlarm'} +CREATE_ALARM = copy.deepcopy(AN_ALARM) +del CREATE_ALARM['timestamp'] +del CREATE_ALARM['state_timestamp'] +del CREATE_ALARM['alarm_id'] +CREATE_ALARM_WITHOUT_TC = copy.deepcopy(CREATE_ALARM) +del CREATE_ALARM_WITHOUT_TC['time_constraints'] +DELTA_ALARM = {u'alarm_actions': ['url1', 'url2']} +DELTA_ALARM_RULE = {u'comparison_operator': u'lt', + u'threshold': 42.1, + u'meter_name': u'foobar', + u'query': [{u'field': u'key_name', + u'op': u'eq', + u'value': u'key_value'}]} +DELTA_ALARM_TC = [{u'name': u'cons1', + u'duration': 500}] +DELTA_ALARM['time_constraints'] = DELTA_ALARM_TC +UPDATED_ALARM = copy.deepcopy(AN_ALARM) +UPDATED_ALARM.update(DELTA_ALARM) +UPDATED_ALARM['threshold_rule'].update(DELTA_ALARM_RULE) +DELTA_ALARM['remove_time_constraints'] = 'cons2' +UPDATED_ALARM['time_constraints'] = [{u'name': u'cons1', + u'description': u'desc1', + u'start': u'0 11 * * *', + u'duration': 500, + u'timezone': u''}] +DELTA_ALARM['threshold_rule'] = DELTA_ALARM_RULE +UPDATE_ALARM = copy.deepcopy(UPDATED_ALARM) +UPDATE_ALARM['remove_time_constraints'] = 'cons2' +del UPDATE_ALARM['user_id'] +del UPDATE_ALARM['project_id'] +del UPDATE_ALARM['name'] +del UPDATE_ALARM['alarm_id'] +del UPDATE_ALARM['timestamp'] +del UPDATE_ALARM['state_timestamp'] + +AN_LEGACY_ALARM = {u'alarm_actions': [u'http://site:8000/alarm'], + u'ok_actions': [u'http://site:8000/ok'], + u'description': u'An alarm', + u'matching_metadata': {u'key_name': u'key_value'}, + u'evaluation_periods': 2, + u'timestamp': u'2013-05-09T13:41:23.085000', + u'enabled': True, + u'meter_name': u'storage.objects', + u'period': 240.0, + u'alarm_id': u'alarm-id', + u'state': u'ok', + u'severity': u'low', + u'insufficient_data_actions': [u'http://site:8000/nodata'], + u'statistic': u'avg', + u'threshold': 200.0, + u'user_id': u'user-id', + u'project_id': u'project-id', + u'state_timestamp': u'2013-05-09T13:41:23.085000', + u'comparison_operator': 'gt', + u'repeat_actions': False, + u'name': 'SwiftObjectAlarm'} +CREATE_LEGACY_ALARM = copy.deepcopy(AN_LEGACY_ALARM) +del CREATE_LEGACY_ALARM['timestamp'] +del CREATE_LEGACY_ALARM['state_timestamp'] +del CREATE_LEGACY_ALARM['alarm_id'] +DELTA_LEGACY_ALARM = {u'alarm_actions': ['url1', 'url2'], + u'comparison_operator': u'lt', + u'meter_name': u'foobar', + u'threshold': 42.1} +DELTA_LEGACY_ALARM['time_constraints'] = [{u'name': u'cons1', + u'duration': 500}] +DELTA_LEGACY_ALARM['remove_time_constraints'] = 'cons2' +UPDATED_LEGACY_ALARM = copy.deepcopy(AN_LEGACY_ALARM) +UPDATED_LEGACY_ALARM.update(DELTA_LEGACY_ALARM) +UPDATE_LEGACY_ALARM = copy.deepcopy(UPDATED_LEGACY_ALARM) +del UPDATE_LEGACY_ALARM['user_id'] +del UPDATE_LEGACY_ALARM['project_id'] +del UPDATE_LEGACY_ALARM['name'] +del UPDATE_LEGACY_ALARM['alarm_id'] +del UPDATE_LEGACY_ALARM['timestamp'] +del UPDATE_LEGACY_ALARM['state_timestamp'] + +FULL_DETAIL = ('{"alarm_actions": [], ' + '"user_id": "8185aa72421a4fd396d4122cba50e1b5", ' + '"name": "scombo", ' + '"timestamp": "2013-10-03T08:58:33.647912", ' + '"enabled": true, ' + '"state_timestamp": "2013-10-03T08:58:33.647912", ' + '"rule": {"operator": "or", "alarm_ids": ' + '["062cc907-3a9f-4867-ab3b-fa83212b39f7"]}, ' + '"alarm_id": "alarm-id, ' + '"state": "insufficient data", ' + '"insufficient_data_actions": [], ' + '"repeat_actions": false, ' + '"ok_actions": [], ' + '"project_id": "57d04f24d0824b78b1ea9bcecedbda8f", ' + '"type": "combination", ' + '"description": "Combined state of alarms ' + '062cc907-3a9f-4867-ab3b-fa83212b39f7"}') +ALARM_HISTORY = [{'on_behalf_of': '57d04f24d0824b78b1ea9bcecedbda8f', + 'user_id': '8185aa72421a4fd396d4122cba50e1b5', + 'event_id': 'c74a8611-6553-4764-a860-c15a6aabb5d0', + 'timestamp': '2013-10-03T08:59:28.326000', + 'detail': '{"state": "alarm"}', + 'alarm_id': 'alarm-id', + 'project_id': '57d04f24d0824b78b1ea9bcecedbda8f', + 'type': 'state transition'}, + {'on_behalf_of': '57d04f24d0824b78b1ea9bcecedbda8f', + 'user_id': '8185aa72421a4fd396d4122cba50e1b5', + 'event_id': 'c74a8611-6553-4764-a860-c15a6aabb5d0', + 'timestamp': '2013-10-03T08:59:28.326000', + 'detail': '{"description": "combination of one"}', + 'alarm_id': 'alarm-id', + 'project_id': '57d04f24d0824b78b1ea9bcecedbda8f', + 'type': 'rule change'}, + {'on_behalf_of': '57d04f24d0824b78b1ea9bcecedbda8f', + 'user_id': '8185aa72421a4fd396d4122cba50e1b5', + 'event_id': '4fd7df9e-190d-4471-8884-dc5a33d5d4bb', + 'timestamp': '2013-10-03T08:58:33.647000', + 'detail': FULL_DETAIL, + 'alarm_id': 'alarm-id', + 'project_id': '57d04f24d0824b78b1ea9bcecedbda8f', + 'type': 'creation'}] + +fixtures = { + '/v2/alarms': + { + 'GET': ( + {}, + [AN_ALARM], + ), + 'POST': ( + {}, + CREATE_ALARM, + ), + }, + '/v2/alarms/alarm-id': + { + 'GET': ( + {}, + AN_ALARM, + ), + 'PUT': ( + {}, + UPDATED_ALARM, + ), + 'DELETE': ( + {}, + None, + ), + }, + '/v2/alarms/unk-alarm-id': + { + 'GET': ( + {}, + None, + ), + 'PUT': ( + {}, + None, + ), + }, + '/v2/alarms/alarm-id/state': + { + 'PUT': ( + {}, + {'alarm': 'alarm'} + ), + 'GET': ( + {}, + {'alarm': 'alarm'} + ), + + }, + '/v2/alarms?q.field=project_id&q.field=name&q.op=&q.op=' + '&q.type=&q.type=&q.value=project-id&q.value=SwiftObjectAlarm': + { + 'GET': ( + {}, + [AN_ALARM], + ), + }, + '/v2/alarms/victim-id': + { + 'DELETE': ( + {}, + None, + ), + }, + '/v2/alarms/alarm-id/history': + { + 'GET': ( + {}, + ALARM_HISTORY, + ), + }, + '/v2/alarms/alarm-id/history?q.field=timestamp&q.op=&q.type=&q.value=NOW': + { + 'GET': ( + {}, + ALARM_HISTORY, + ), + }, +} + + +class AlarmManagerTest(testtools.TestCase): + + def setUp(self): + super(AlarmManagerTest, self).setUp() + self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) + self.api = client.BaseClient(self.http_client) + self.mgr = alarms.AlarmManager(self.api) + + def test_list_all(self): + alarms = list(self.mgr.list()) + expect = [ + 'GET', '/v2/alarms' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(alarms), 1) + self.assertEqual(alarms[0].alarm_id, 'alarm-id') + + def test_list_with_query(self): + alarms = list(self.mgr.list(q=[{"field": "project_id", + "value": "project-id"}, + {"field": "name", + "value": "SwiftObjectAlarm"}])) + expect = [ + 'GET', + '/v2/alarms?q.field=project_id&q.field=name&q.op=&q.op=' + '&q.type=&q.type=&q.value=project-id&q.value=SwiftObjectAlarm', + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(alarms), 1) + self.assertEqual(alarms[0].alarm_id, 'alarm-id') + + def test_get(self): + alarm = self.mgr.get(alarm_id='alarm-id') + expect = [ + 'GET', '/v2/alarms/alarm-id' + ] + self.http_client.assert_called(*expect) + self.assertIsNotNone(alarm) + self.assertEqual(alarm.alarm_id, 'alarm-id') + self.assertEqual(alarm.rule, alarm.threshold_rule) + + def test_create(self): + alarm = self.mgr.create(**CREATE_ALARM) + expect = [ + 'POST', '/v2/alarms' + ] + self.http_client.assert_called(*expect, body=CREATE_ALARM) + self.assertIsNotNone(alarm) + + def test_update(self): + alarm = self.mgr.update(alarm_id='alarm-id', **UPDATE_ALARM) + expect_get = [ + 'GET', '/v2/alarms/alarm-id' + ] + expect_put = [ + 'PUT', '/v2/alarms/alarm-id', UPDATED_ALARM + ] + self.http_client.assert_called(*expect_get, pos=0) + self.http_client.assert_called(*expect_put, pos=1) + self.assertIsNotNone(alarm) + self.assertEqual(alarm.alarm_id, 'alarm-id') + for (key, value) in six.iteritems(UPDATED_ALARM): + self.assertEqual(getattr(alarm, key), value) + + def test_update_delta(self): + alarm = self.mgr.update(alarm_id='alarm-id', **DELTA_ALARM) + expect_get = [ + 'GET', '/v2/alarms/alarm-id' + ] + expect_put = [ + 'PUT', '/v2/alarms/alarm-id', UPDATED_ALARM + ] + self.http_client.assert_called(*expect_get, pos=0) + self.http_client.assert_called(*expect_put, pos=1) + self.assertIsNotNone(alarm) + self.assertEqual(alarm.alarm_id, 'alarm-id') + for (key, value) in six.iteritems(UPDATED_ALARM): + self.assertEqual(getattr(alarm, key), value) + + def test_set_state(self): + state = self.mgr.set_state(alarm_id='alarm-id', state='alarm') + expect = [ + 'PUT', '/v2/alarms/alarm-id/state' + ] + self.http_client.assert_called(*expect, body='alarm') + self.assertEqual(state, {'alarm': 'alarm'}) + + def test_get_state(self): + state = self.mgr.get_state(alarm_id='alarm-id') + expect = [ + 'GET', '/v2/alarms/alarm-id/state' + ] + self.http_client.assert_called(*expect) + self.assertEqual(state, {'alarm': 'alarm'}) + + def test_delete(self): + deleted = self.mgr.delete(alarm_id='victim-id') + expect = [ + 'DELETE', '/v2/alarms/victim-id' + ] + self.http_client.assert_called(*expect) + self.assertIsNone(deleted) + + def test_get_from_alarm_class(self): + alarm = self.mgr.get(alarm_id='alarm-id') + self.assertIsNotNone(alarm) + alarm.get() + expect = [ + 'GET', '/v2/alarms/alarm-id' + ] + self.http_client.assert_called(*expect, pos=0) + self.http_client.assert_called(*expect, pos=1) + self.assertEqual('alarm-id', alarm.alarm_id) + self.assertEqual(alarm.threshold_rule, alarm.rule) + + def test_get_state_from_alarm_class(self): + alarm = self.mgr.get(alarm_id='alarm-id') + self.assertIsNotNone(alarm) + state = alarm.get_state() + expect_get_1 = [ + 'GET', '/v2/alarms/alarm-id' + ] + expect_get_2 = [ + 'GET', '/v2/alarms/alarm-id/state' + ] + self.http_client.assert_called(*expect_get_1, pos=0) + self.http_client.assert_called(*expect_get_2, pos=1) + self.assertEqual('alarm', state) + + def test_update_missing(self): + alarm = None + try: + alarm = self.mgr.update(alarm_id='unk-alarm-id', **UPDATE_ALARM) + except exc.CommandError: + pass + self.assertEqual(alarm, None) + + def test_delete_from_alarm_class(self): + alarm = self.mgr.get(alarm_id='alarm-id') + self.assertIsNotNone(alarm) + deleted = alarm.delete() + expect_get = [ + 'GET', '/v2/alarms/alarm-id' + ] + expect_delete = [ + 'DELETE', '/v2/alarms/alarm-id' + ] + self.http_client.assert_called(*expect_get, pos=0) + self.http_client.assert_called(*expect_delete, pos=1) + self.assertIsNone(deleted) + + def _do_test_get_history(self, q, url): + history = self.mgr.get_history(q=q, alarm_id='alarm-id') + expect = ['GET', url] + self.http_client.assert_called(*expect) + for i in xrange(len(history)): + change = history[i] + self.assertIsInstance(change, alarms.AlarmChange) + for k, v in six.iteritems(ALARM_HISTORY[i]): + self.assertEqual(getattr(change, k), v) + + def test_get_all_history(self): + url = '/v2/alarms/alarm-id/history' + self._do_test_get_history(None, url) + + def test_get_constrained_history(self): + q = [dict(field='timestamp', value='NOW')] + url = ('/v2/alarms/alarm-id/history?q.field=timestamp' + '&q.op=&q.type=&q.value=NOW') + self._do_test_get_history(q, url) + + +class AlarmLegacyManagerTest(testtools.TestCase): + + def setUp(self): + super(AlarmLegacyManagerTest, self).setUp() + self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) + self.api = client.BaseClient(self.http_client) + self.mgr = alarms.AlarmManager(self.api) + + def test_create(self): + alarm = self.mgr.create(**CREATE_LEGACY_ALARM) + expect = [ + 'POST', '/v2/alarms', CREATE_ALARM_WITHOUT_TC, + ] + self.http_client.assert_called(*expect) + self.assertIsNotNone(alarm) + + def test_create_counter_name(self): + create = {} + create.update(CREATE_LEGACY_ALARM) + create['counter_name'] = CREATE_LEGACY_ALARM['meter_name'] + del create['meter_name'] + alarm = self.mgr.create(**create) + expect = [ + 'POST', '/v2/alarms', CREATE_ALARM_WITHOUT_TC, + ] + self.http_client.assert_called(*expect) + self.assertIsNotNone(alarm) + + def test_update(self): + alarm = self.mgr.update(alarm_id='alarm-id', **DELTA_LEGACY_ALARM) + expect_put = [ + 'PUT', '/v2/alarms/alarm-id', UPDATED_ALARM + ] + self.http_client.assert_called(*expect_put) + self.assertIsNotNone(alarm) + self.assertEqual(alarm.alarm_id, 'alarm-id') + for (key, value) in six.iteritems(UPDATED_ALARM): + self.assertEqual(getattr(alarm, key), value) + + def test_update_counter_name(self): + updated = {} + updated.update(UPDATE_LEGACY_ALARM) + updated['counter_name'] = UPDATED_LEGACY_ALARM['meter_name'] + del updated['meter_name'] + alarm = self.mgr.update(alarm_id='alarm-id', **updated) + expect_put = [ + 'PUT', '/v2/alarms/alarm-id', UPDATED_ALARM + ] + self.http_client.assert_called(*expect_put) + self.assertIsNotNone(alarm) + self.assertEqual(alarm.alarm_id, 'alarm-id') + for (key, value) in six.iteritems(UPDATED_ALARM): + self.assertEqual(getattr(alarm, key), value) + + +class AlarmTimeConstraintTest(testtools.TestCase): + + def setUp(self): + super(AlarmTimeConstraintTest, self).setUp() + self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) + self.api = client.BaseClient(self.http_client) + self.mgr = alarms.AlarmManager(self.api) + + def test_add_new(self): + new_constraint = dict(name='cons3', + start='0 0 * * *', + duration=500) + kwargs = dict(time_constraints=[new_constraint]) + self.mgr.update(alarm_id='alarm-id', **kwargs) + body = copy.deepcopy(AN_ALARM) + body[u'time_constraints'] = \ + AN_ALARM[u'time_constraints'] + [new_constraint] + expect = [ + 'PUT', '/v2/alarms/alarm-id', body + ] + self.http_client.assert_called(*expect) + + def test_update_existing(self): + updated_constraint = dict(name='cons2', + duration=500) + kwargs = dict(time_constraints=[updated_constraint]) + self.mgr.update(alarm_id='alarm-id', **kwargs) + body = copy.deepcopy(AN_ALARM) + body[u'time_constraints'][1] = dict(name='cons2', + description='desc2', + start='0 23 * * *', + duration=500, + timezone='') + + expect = [ + 'PUT', '/v2/alarms/alarm-id', body + ] + self.http_client.assert_called(*expect) + + def test_remove(self): + kwargs = dict(remove_time_constraints=['cons2']) + self.mgr.update(alarm_id='alarm-id', **kwargs) + body = copy.deepcopy(AN_ALARM) + body[u'time_constraints'] = AN_ALARM[u'time_constraints'][:1] + expect = [ + 'PUT', '/v2/alarms/alarm-id', body + ] + self.http_client.assert_called(*expect) diff --git a/ceilometerclient/tests/unit/v2/test_event_types.py b/ceilometerclient/tests/unit/v2/test_event_types.py new file mode 100644 index 0000000..7dc1508 --- /dev/null +++ b/ceilometerclient/tests/unit/v2/test_event_types.py @@ -0,0 +1,50 @@ +# 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. + + +from ceilometerclient.openstack.common.apiclient import client +from ceilometerclient.openstack.common.apiclient import fake_client +from ceilometerclient.tests.unit import utils +import ceilometerclient.v2.event_types + + +fixtures = { + '/v2/event_types/': { + 'GET': ( + {}, + ['Foo', 'Bar', 'Sna', 'Fu'] + ), + } +} + + +class EventTypesManagerTest(utils.BaseTestCase): + + def setUp(self): + super(EventTypesManagerTest, self).setUp() + self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) + self.api = client.BaseClient(self.http_client) + self.mgr = ceilometerclient.v2.event_types.EventTypeManager(self.api) + + def test_list(self): + event_types = list(self.mgr.list()) + expect = [ + 'GET', '/v2/event_types/' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(event_types), 4) + self.assertEqual(event_types[0].event_type, "Foo") + self.assertEqual(event_types[1].event_type, "Bar") + self.assertEqual(event_types[2].event_type, "Sna") + self.assertEqual(event_types[3].event_type, "Fu") diff --git a/ceilometerclient/tests/unit/v2/test_events.py b/ceilometerclient/tests/unit/v2/test_events.py new file mode 100644 index 0000000..6cb1c1e --- /dev/null +++ b/ceilometerclient/tests/unit/v2/test_events.py @@ -0,0 +1,198 @@ +# 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. +from ceilometerclient.openstack.common.apiclient import client +from ceilometerclient.openstack.common.apiclient import fake_client +from ceilometerclient.tests.unit import utils +import ceilometerclient.v2.events + + +fixtures = { + '/v2/events': { + 'GET': ( + {}, + [ + { + 'message_id': '1', + 'event_type': 'Foo', + 'generated': '1970-01-01T00:00:00', + 'traits': {'trait_A': 'abc'}, + }, + { + 'message_id': '2', + 'event_type': 'Foo', + 'generated': '1970-01-01T00:00:00', + 'traits': {'trait_A': 'def'}, + }, + { + 'message_id': '3', + 'event_type': 'Bar', + 'generated': '1970-01-01T00:00:00', + 'traits': {'trait_B': 'bartrait'}, + }, + ] + ), + }, + '/v2/events?q.field=hostname&q.op=&q.type=string&q.value=localhost': + { + 'GET': ( + {}, + [ + { + 'message_id': '1', + 'event_type': 'Foo', + 'generated': '1970-01-01T00:00:00', + 'traits': {'trait_A': 'abc', + 'hostname': 'localhost'}, + }, + { + 'message_id': '2', + 'event_type': 'Foo', + 'generated': '1970-01-01T00:00:00', + 'traits': {'trait_A': 'def', + 'hostname': 'localhost'}, + } + ] + ), + }, + '/v2/events?q.field=hostname&q.op=&q.type=&q.value=foreignhost': + { + 'GET': ( + {}, + [ + { + 'message_id': '1', + 'event_type': 'Foo', + 'generated': '1970-01-01T00:00:00', + 'traits': {'trait_A': 'abc', + 'hostname': 'foreignhost'}, + }, + { + 'message_id': '2', + 'event_type': 'Foo', + 'generated': '1970-01-01T00:00:00', + 'traits': {'trait_A': 'def', + 'hostname': 'foreignhost'}, + } + ] + ), + }, + '/v2/events?q.field=hostname&q.field=num_cpus&q.op=&q.op=' + '&q.type=&q.type=integer&q.value=localhost&q.value=5': + { + 'GET': ( + {}, + [ + { + 'message_id': '1', + 'event_type': 'Bar', + 'generated': '1970-01-01T00:00:00', + 'traits': {'trait_A': 'abc', + 'hostname': 'localhost', + 'num_cpus': '5'}, + }, + ] + ), + }, + + '/v2/events/2': + { + 'GET': ( + {}, + { + 'message_id': '2', + 'event_type': 'Foo', + 'generated': '1970-01-01T00:00:00', + 'traits': {'trait_A': 'def', + 'intTrait': '42'}, + } + ), + }, +} + + +class EventManagerTest(utils.BaseTestCase): + + def setUp(self): + super(EventManagerTest, self).setUp() + self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) + self.api = client.BaseClient(self.http_client) + self.mgr = ceilometerclient.v2.events.EventManager(self.api) + + def test_list_all(self): + events = list(self.mgr.list()) + expect = [ + 'GET', '/v2/events' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(events), 3) + self.assertEqual(events[0].event_type, 'Foo') + self.assertEqual(events[1].event_type, 'Foo') + self.assertEqual(events[2].event_type, 'Bar') + + def test_list_one(self): + event = self.mgr.get(2) + expect = [ + 'GET', '/v2/events/2' + ] + self.http_client.assert_called(*expect) + self.assertIsNotNone(event) + self.assertEqual(event.event_type, 'Foo') + + def test_list_with_query(self): + events = list(self.mgr.list(q=[{"field": "hostname", + "value": "localhost", + "type": "string"}])) + expect = [ + 'GET', '/v2/events?q.field=hostname&q.op=&q.type=string' + '&q.value=localhost' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(events), 2) + self.assertEqual(events[0].event_type, 'Foo') + + def test_list_with_query_no_type(self): + events = list(self.mgr.list(q=[{"field": "hostname", + "value": "foreignhost"}])) + expect = [ + 'GET', '/v2/events?q.field=hostname&q.op=' + '&q.type=&q.value=foreignhost' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(events), 2) + self.assertEqual(events[0].event_type, 'Foo') + + def test_list_with_multiple_filters(self): + events = list(self.mgr.list(q=[{"field": "hostname", + "value": "localhost"}, + {"field": "num_cpus", + "value": "5", + "type": "integer"}])) + + expect = [ + 'GET', '/v2/events?q.field=hostname&q.field=num_cpus&q.op=&q.op=' + '&q.type=&q.type=integer&q.value=localhost&q.value=5' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(events), 1) + + def test_get_from_event_class(self): + event = self.mgr.get(2) + self.assertIsNotNone(event) + event.get() + expect = [ + 'GET', '/v2/events/2' + ] + self.http_client.assert_called(*expect, pos=0) + self.http_client.assert_called(*expect, pos=1) + self.assertEqual('Foo', event.event_type) diff --git a/ceilometerclient/tests/unit/v2/test_options.py b/ceilometerclient/tests/unit/v2/test_options.py new file mode 100644 index 0000000..1a9ec24 --- /dev/null +++ b/ceilometerclient/tests/unit/v2/test_options.py @@ -0,0 +1,239 @@ +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +from ceilometerclient.tests.unit import utils +from ceilometerclient.v2 import options + + +class BuildUrlTest(utils.BaseTestCase): + + def test_one(self): + url = options.build_url('/', [{'field': 'this', + 'op': 'gt', + 'value': 43}]) + self.assertEqual(url, '/?q.field=this&q.op=gt&q.type=&q.value=43') + + def test_two(self): + url = options.build_url('/', [{'field': 'this', + 'op': 'gt', + 'value': 43}, + {'field': 'that', + 'op': 'lt', + 'value': 88}]) + ops = 'q.op=gt&q.op=lt' + vals = 'q.value=43&q.value=88' + types = 'q.type=&q.type=' + fields = 'q.field=this&q.field=that' + self.assertEqual(url, '/?%s&%s&%s&%s' % (fields, ops, types, vals)) + + def test_default_op(self): + url = options.build_url('/', [{'field': 'this', + 'value': 43}]) + self.assertEqual(url, '/?q.field=this&q.op=&q.type=&q.value=43') + + def test_one_param(self): + url = options.build_url('/', None, ['period=60']) + self.assertEqual(url, '/?period=60') + + def test_two_params(self): + url = options.build_url('/', None, ['period=60', + 'others=value']) + self.assertEqual(url, '/?period=60&others=value') + + def test_with_data_type(self): + url = options.build_url('/', [{'field': 'f1', + 'value': '10', + 'type': 'integer'}]) + + self.assertEqual('/?q.field=f1&q.op=&q.type=integer&q.value=10', url) + + +class CliTest(utils.BaseTestCase): + + def test_one(self): + ar = options.cli_to_array('this<=34') + self.assertEqual(ar, [{'field': 'this', 'op': 'le', + 'value': '34', 'type': ''}]) + + def test_two(self): + ar = options.cli_to_array('this<=34;that!=foo') + self.assertEqual(ar, [{'field': 'this', 'op': 'le', + 'value': '34', 'type': ''}, + {'field': 'that', 'op': 'ne', + 'value': 'foo', 'type': ''}]) + + def test_negative(self): + ar = options.cli_to_array('this>=-783') + self.assertEqual(ar, [{'field': 'this', 'op': 'ge', + 'value': '-783', 'type': ''}]) + + def test_float(self): + ar = options.cli_to_array('this<=283.347') + self.assertEqual(ar, [{'field': 'this', + 'op': 'le', 'value': '283.347', + 'type': ''}]) + + def test_comma(self): + ar = options.cli_to_array('this=2.4,fooo=doof') + self.assertEqual([{'field': 'this', + 'op': 'eq', + 'value': '2.4,fooo=doof', + 'type': ''}], + ar) + + def test_special_character(self): + ar = options.cli_to_array('key~123=value!123') + self.assertEqual([{'field': 'key~123', + 'op': 'eq', + 'value': 'value!123', + 'type': ''}], + ar) + + def _do_test_typed_float_op(self, op, op_str): + ar = options.cli_to_array('that%sfloat::283.347' % op) + self.assertEqual([{'field': 'that', + 'type': 'float', + 'value': '283.347', + 'op': op_str}], + ar) + + def test_typed_float_eq(self): + self._do_test_typed_float_op('<', 'lt') + + def test_typed_float_le(self): + self._do_test_typed_float_op('<=', 'le') + + def test_typed_string_whitespace(self): + ar = options.cli_to_array('state=string::insufficient data') + self.assertEqual([{'field': 'state', + 'op': 'eq', + 'type': 'string', + 'value': 'insufficient data'}], + ar) + + def test_typed_string_whitespace_complex(self): + ar = options.cli_to_array( + 'that>=float::99.9999;state=string::insufficient data' + ) + self.assertEqual([{'field': 'that', + 'op': 'ge', + 'type': 'float', + 'value': '99.9999'}, + {'field': 'state', + 'op': 'eq', + 'type': 'string', + 'value': 'insufficient data'}], + ar) + + def test_invalid_operator(self): + self.assertRaises(ValueError, options.cli_to_array, + 'this=2.4;fooo-doof') + + def test_with_dot(self): + ar = options.cli_to_array('metadata.this<=34') + self.assertEqual(ar, [{'field': 'metadata.this', + 'op': 'le', 'value': '34', + 'type': ''}]) + + def test_single_char_field_or_value(self): + ar = options.cli_to_array('m<=34;large.thing>s;x!=y') + self.assertEqual([{'field': 'm', + 'op': 'le', + 'value': '34', + 'type': ''}, + {'field': 'large.thing', + 'op': 'gt', + 'value': 's', + 'type': ''}, + {'field': 'x', + 'op': 'ne', + 'value': 'y', + 'type': ''}], + ar) + + def test_without_data_type(self): + ar = options.cli_to_array('hostname=localhost') + self.assertEqual(ar, [{'field': 'hostname', + 'op': 'eq', + 'value': 'localhost', + 'type': ''}]) + + def test_with_string_data_type(self): + ar = options.cli_to_array('hostname=string::localhost') + self.assertEqual(ar, [{'field': 'hostname', + 'op': 'eq', + 'type': 'string', + 'value': 'localhost'}]) + + def test_with_int_data_type(self): + ar = options.cli_to_array('port=integer::1234') + self.assertEqual(ar, [{'field': 'port', + 'op': 'eq', + 'type': 'integer', + 'value': '1234'}]) + + def test_with_bool_data_type(self): + ar = options.cli_to_array('port=boolean::true') + self.assertEqual(ar, [{'field': 'port', + 'op': 'eq', + 'type': 'boolean', + 'value': 'true'}]) + + def test_with_float_data_type(self): + ar = options.cli_to_array('average=float::1234.5678') + self.assertEqual(ar, [{'field': 'average', + 'op': 'eq', + 'type': 'float', + 'value': '1234.5678'}]) + + def test_with_datetime_data_type(self): + ar = options.cli_to_array('timestamp=datetime::sometimestamp') + self.assertEqual(ar, [{'field': 'timestamp', + 'op': 'eq', + 'type': 'datetime', + 'value': 'sometimestamp'}]) + + def test_with_incorrect_type(self): + ar = options.cli_to_array('timestamp=invalid::sometimestamp') + self.assertEqual(ar, [{'field': 'timestamp', + 'op': 'eq', + 'type': '', + 'value': 'invalid::sometimestamp'}]) + + def test_with_single_colon(self): + ar = options.cli_to_array('timestamp=datetime:sometimestamp') + self.assertEqual(ar, [{'field': 'timestamp', + 'op': 'eq', + 'type': '', + 'value': 'datetime:sometimestamp'}]) + + def test_missing_key(self): + self.assertRaises(ValueError, options.cli_to_array, + 'average=float::1234.0;>=string::hello') + + def test_missing_value(self): + self.assertRaises(ValueError, options.cli_to_array, + 'average=float::1234.0;house>=') + + def test_timestamp_value(self): + ar = options.cli_to_array( + 'project=cow;timestamp>=datetime::2014-03-11T16:02:58' + ) + self.assertEqual([{'field': 'project', + 'op': 'eq', + 'type': '', + 'value': 'cow'}, + {'field': 'timestamp', + 'op': 'ge', + 'type': 'datetime', + 'value': '2014-03-11T16:02:58'}], + ar) diff --git a/ceilometerclient/tests/unit/v2/test_query_alarm_history.py b/ceilometerclient/tests/unit/v2/test_query_alarm_history.py new file mode 100644 index 0000000..014b894 --- /dev/null +++ b/ceilometerclient/tests/unit/v2/test_query_alarm_history.py @@ -0,0 +1,66 @@ +# Copyright Ericsson AB 2014. All rights reserved +# +# Authors: Ildiko Vancsa +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from ceilometerclient.openstack.common.apiclient import client +from ceilometerclient.openstack.common.apiclient import fake_client +from ceilometerclient.tests.unit import utils +from ceilometerclient.v2 import query + + +ALARMCHANGE = {"alarm_id": "e8ff32f772a44a478182c3fe1f7cad6a", + "event_id": "c74a8611-6553-4764-a860-c15a6aabb5d0", + "detail": "{\"threshold\": 42.0, \"evaluation_periods\": 4}", + "on_behalf_of": "92159030020611e3b26dde429e99ee8c", + "project_id": "b6f16144010811e387e4de429e99ee8c", + "timestamp": "2014-03-11T16:02:58.376261", + "type": "rule change", + "user_id": "3e5d11fda79448ac99ccefb20be187ca" + } + +QUERY = {"filter": {"and": [{">": {"timestamp": "2014-03-11T16:02:58"}}, + {"=": {"type": "rule change"}}]}, + "orderby": [{"timestamp": "desc"}], + "limit": 10} + +base_url = '/v2/query/alarms/history' +fixtures = { + base_url: + { + 'POST': ( + {}, + [ALARMCHANGE], + ), + }, +} + + +class QueryAlarmsManagerTest(utils.BaseTestCase): + + def setUp(self): + super(QueryAlarmsManagerTest, self).setUp() + self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) + self.api = client.BaseClient(self.http_client) + self.mgr = query.QueryAlarmHistoryManager(self.api) + + def test_query(self): + alarm_history = self.mgr.query(**QUERY) + expect = [ + + 'POST', '/v2/query/alarms/history', QUERY, + + ] + self.http_client.assert_called(*expect) + self.assertEqual(1, len(alarm_history)) diff --git a/ceilometerclient/tests/unit/v2/test_query_alarms.py b/ceilometerclient/tests/unit/v2/test_query_alarms.py new file mode 100644 index 0000000..e633938 --- /dev/null +++ b/ceilometerclient/tests/unit/v2/test_query_alarms.py @@ -0,0 +1,74 @@ +# Copyright Ericsson AB 2014. All rights reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from ceilometerclient.openstack.common.apiclient import client +from ceilometerclient.openstack.common.apiclient import fake_client +from ceilometerclient.tests.unit import utils +from ceilometerclient.v2 import query + + +ALARM = {"alarm_actions": ["http://site:8000/alarm"], + "alarm_id": None, + "combination_rule": { + "alarm_ids": [ + "739e99cb-c2ec-4718-b900-332502355f38", + "153462d0-a9b8-4b5b-8175-9e4b05e9b856"], + "operator": "or"}, + "description": "An alarm", + "enabled": True, + "insufficient_data_actions": ["http://site:8000/nodata"], + "name": "SwiftObjectAlarm", + "ok_actions": ["http://site:8000/ok"], + "project_id": "c96c887c216949acbdfbd8b494863567", + "repeat_actions": False, + "state": "ok", + "state_timestamp": "2014-02-20T10:37:15.589860", + "threshold_rule": None, + "timestamp": "2014-02-20T10:37:15.589856", + "type": "combination", + "user_id": "c96c887c216949acbdfbd8b494863567"} + +QUERY = {"filter": {"and": [{"!=": {"state": "ok"}}, + {"=": {"type": "combination"}}]}, + "orderby": [{"state_timestamp": "desc"}], + "limit": 10} + +base_url = '/v2/query/alarms' +fixtures = { + base_url: + { + 'POST': ( + {}, + [ALARM], + ), + }, +} + + +class QueryAlarmsManagerTest(utils.BaseTestCase): + + def setUp(self): + super(QueryAlarmsManagerTest, self).setUp() + self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) + self.api = client.BaseClient(self.http_client) + self.mgr = query.QueryAlarmsManager(self.api) + + def test_query(self): + alarms = self.mgr.query(**QUERY) + expect = [ + 'POST', '/v2/query/alarms', QUERY, + ] + + self.http_client.assert_called(*expect) + self.assertEqual(1, len(alarms)) diff --git a/ceilometerclient/tests/unit/v2/test_query_samples.py b/ceilometerclient/tests/unit/v2/test_query_samples.py new file mode 100644 index 0000000..16828fe --- /dev/null +++ b/ceilometerclient/tests/unit/v2/test_query_samples.py @@ -0,0 +1,67 @@ +# Copyright Ericsson AB 2014. All rights reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +from ceilometerclient.openstack.common.apiclient import client +from ceilometerclient.openstack.common.apiclient import fake_client +from ceilometerclient.tests.unit import utils +from ceilometerclient.v2 import query + + +SAMPLE = {u'id': u'b55d1526-9929-11e3-a3f6-02163e5df1e6', + u'metadata': { + u'name1': u'value1', + u'name2': u'value2'}, + u'meter': 'instance', + u'project_id': u'35b17138-b364-4e6a-a131-8f3099c5be68', + u'resource_id': u'bd9431c1-8d69-4ad3-803a-8d4a6b89fd36', + u'source': u'openstack', + u'timestamp': u'2014-02-19T05:50:16.673604', + u'type': u'gauge', + u'unit': u'instance', + u'volume': 1, + u'user_id': 'efd87807-12d2-4b38-9c70-5f5c2ac427ff'} + +QUERY = {"filter": {"and": [{"=": {"source": "openstack"}}, + {">": {"timestamp": "2014-02-19T05:50:16"}}]}, + "orderby": [{"timestamp": "desc"}, {"volume": "asc"}], + "limit": 10} + +base_url = '/v2/query/samples' +fixtures = { + base_url: + { + 'POST': ( + {}, + [SAMPLE], + ), + }, +} + + +class QuerySamplesManagerTest(utils.BaseTestCase): + + def setUp(self): + super(QuerySamplesManagerTest, self).setUp() + self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) + self.api = client.BaseClient(self.http_client) + self.mgr = query.QuerySamplesManager(self.api) + + def test_query(self): + samples = self.mgr.query(**QUERY) + expect = [ + + 'POST', '/v2/query/samples', QUERY, + ] + self.http_client.assert_called(*expect) + self.assertEqual(1, len(samples)) diff --git a/ceilometerclient/tests/unit/v2/test_resources.py b/ceilometerclient/tests/unit/v2/test_resources.py new file mode 100644 index 0000000..4aa9131 --- /dev/null +++ b/ceilometerclient/tests/unit/v2/test_resources.py @@ -0,0 +1,118 @@ +# 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 ceilometerclient.openstack.common.apiclient import client +from ceilometerclient.openstack.common.apiclient import fake_client +from ceilometerclient.tests.unit import utils +import ceilometerclient.v2.resources + + +fixtures = { + '/v2/resources': { + 'GET': ( + {}, + [ + { + 'resource_id': 'a', + 'project_id': 'project_bla', + 'user_id': 'freddy', + 'metadata': {'zxc_id': 'bla'}, + }, + { + 'resource_id': 'b', + 'project_id': 'dig_the_ditch', + 'user_id': 'joey', + 'metadata': {'zxc_id': 'foo'}, + }, + ] + ), + }, + '/v2/resources?q.field=resource_id&q.op=&q.type=&q.value=a': + { + 'GET': ( + {}, + [ + { + 'resource_id': 'a', + 'project_id': 'project_bla', + 'user_id': 'freddy', + 'metadata': {'zxc_id': 'bla'}, + }, + ] + ), + }, + '/v2/resources/a': + { + 'GET': ( + {}, + { + 'resource_id': 'a', + 'project_id': 'project_bla', + 'user_id': 'freddy', + 'metadata': {'zxc_id': 'bla'}, + }, + ), + }, +} + + +class ResourceManagerTest(utils.BaseTestCase): + + def setUp(self): + super(ResourceManagerTest, self).setUp() + self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) + self.api = client.BaseClient(self.http_client) + self.mgr = ceilometerclient.v2.resources.ResourceManager(self.api) + + def test_list_all(self): + resources = list(self.mgr.list()) + expect = [ + 'GET', '/v2/resources' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(resources), 2) + self.assertEqual(resources[0].resource_id, 'a') + self.assertEqual(resources[1].resource_id, 'b') + + def test_list_one(self): + resource = self.mgr.get(resource_id='a') + expect = [ + 'GET', '/v2/resources/a' + ] + self.http_client.assert_called(*expect) + self.assertIsNotNone(resource) + self.assertEqual(resource.resource_id, 'a') + + def test_list_by_query(self): + resources = list(self.mgr.list(q=[{"field": "resource_id", + "value": "a"}, + ])) + expect = [ + 'GET', '/v2/resources?q.field=resource_id&q.op=' + '&q.type=&q.value=a' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(resources), 1) + self.assertEqual(resources[0].resource_id, 'a') + + def test_get_from_resource_class(self): + resource = self.mgr.get(resource_id='a') + self.assertIsNotNone(resource) + resource.get() + expect = [ + 'GET', '/v2/resources/a' + ] + self.http_client.assert_called(*expect, pos=0) + self.http_client.assert_called(*expect, pos=1) + self.assertEqual('a', resource.resource_id) diff --git a/ceilometerclient/tests/unit/v2/test_samples.py b/ceilometerclient/tests/unit/v2/test_samples.py new file mode 100644 index 0000000..1d42fb4 --- /dev/null +++ b/ceilometerclient/tests/unit/v2/test_samples.py @@ -0,0 +1,198 @@ +# 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 copy + +from ceilometerclient.openstack.common.apiclient import client +from ceilometerclient.openstack.common.apiclient import fake_client +from ceilometerclient.tests.unit import utils +import ceilometerclient.v2.samples + +GET_OLD_SAMPLE = {u'counter_name': u'instance', + u'user_id': u'user-id', + u'resource_id': u'resource-id', + u'timestamp': u'2012-07-02T10:40:00', + u'source': u'test_source', + u'message_id': u'54558a1c-6ef3-11e2-9875-5453ed1bbb5f', + u'counter_unit': u'', + u'counter_volume': 1.0, + u'project_id': u'project1', + u'resource_metadata': {u'tag': u'self.counter', + u'display_name': u'test-server'}, + u'counter_type': u'cumulative'} +CREATE_SAMPLE = copy.deepcopy(GET_OLD_SAMPLE) +del CREATE_SAMPLE['message_id'] +del CREATE_SAMPLE['source'] + +GET_SAMPLE = { + "user_id": None, + "resource_id": "9b651dfd-7d30-402b-972e-212b2c4bfb05", + "timestamp": "2014-11-03T13:37:46", + "meter": "image", + "volume": 1.0, + "source": "openstack", + "recorded_at": "2014-11-03T13:37:46.994458", + "project_id": "2cc3a7bb859b4bacbeab0aa9ca673033", + "type": "gauge", + "id": "98b5f258-635e-11e4-8bdd-0025647390c1", + "unit": "image", + "resource_metadata": {}, +} + +METER_URL = '/v2/meters/instance' +SAMPLE_URL = '/v2/samples' +QUERIES = ('q.field=resource_id&q.field=source&q.op=&q.op=' + '&q.type=&q.type=&q.value=foo&q.value=bar') +LIMIT = 'limit=1' + +OLD_SAMPLE_FIXTURES = { + METER_URL: { + 'GET': ( + {}, + [GET_OLD_SAMPLE] + ), + 'POST': ( + {}, + [CREATE_SAMPLE], + ), + }, + '%s?%s' % (METER_URL, QUERIES): { + 'GET': ( + {}, + [], + ), + }, + '%s?%s' % (METER_URL, LIMIT): { + 'GET': ( + {}, + [GET_OLD_SAMPLE] + ), + } +} +SAMPLE_FIXTURES = { + SAMPLE_URL: { + 'GET': ( + (), + [GET_SAMPLE] + ), + }, + '%s?%s' % (SAMPLE_URL, QUERIES): { + 'GET': ( + {}, + [], + ), + }, + '%s?%s' % (SAMPLE_URL, LIMIT): { + 'GET': ( + {}, + [GET_SAMPLE], + ), + }, + '%s/%s' % (SAMPLE_URL, GET_SAMPLE['id']): { + 'GET': ( + {}, + GET_SAMPLE, + ), + }, +} + + +class OldSampleManagerTest(utils.BaseTestCase): + + def setUp(self): + super(OldSampleManagerTest, self).setUp() + self.http_client = fake_client.FakeHTTPClient( + fixtures=OLD_SAMPLE_FIXTURES) + self.api = client.BaseClient(self.http_client) + self.mgr = ceilometerclient.v2.samples.OldSampleManager(self.api) + + def test_list_by_meter_name(self): + samples = list(self.mgr.list(meter_name='instance')) + expect = [ + 'GET', '/v2/meters/instance' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(samples), 1) + self.assertEqual(samples[0].resource_id, 'resource-id') + + def test_list_by_meter_name_extended(self): + samples = list(self.mgr.list(meter_name='instance', + q=[ + {"field": "resource_id", + "value": "foo"}, + {"field": "source", + "value": "bar"}, + ])) + expect = ['GET', '%s?%s' % (METER_URL, QUERIES)] + self.http_client.assert_called(*expect) + self.assertEqual(len(samples), 0) + + def test_create(self): + sample = self.mgr.create(**CREATE_SAMPLE) + expect = [ + 'POST', '/v2/meters/instance' + ] + self.http_client.assert_called(*expect, body=[CREATE_SAMPLE]) + self.assertIsNotNone(sample) + + def test_limit(self): + samples = list(self.mgr.list(meter_name='instance', limit=1)) + expect = ['GET', '/v2/meters/instance?limit=1'] + self.http_client.assert_called(*expect) + self.assertEqual(len(samples), 1) + + +class SampleManagerTest(utils.BaseTestCase): + + def setUp(self): + super(SampleManagerTest, self).setUp() + self.http_client = fake_client.FakeHTTPClient( + fixtures=SAMPLE_FIXTURES) + self.api = client.BaseClient(self.http_client) + self.mgr = ceilometerclient.v2.samples.SampleManager(self.api) + + def test_sample_list(self): + samples = list(self.mgr.list()) + expect = [ + 'GET', '/v2/samples' + ] + self.http_client.assert_called(*expect) + self.assertEqual(1, len(samples)) + self.assertEqual('9b651dfd-7d30-402b-972e-212b2c4bfb05', + samples[0].resource_id) + + def test_sample_list_with_queries(self): + queries = [ + {"field": "resource_id", + "value": "foo"}, + {"field": "source", + "value": "bar"}, + ] + samples = list(self.mgr.list(q=queries)) + expect = ['GET', '%s?%s' % (SAMPLE_URL, QUERIES)] + self.http_client.assert_called(*expect) + self.assertEqual(0, len(samples)) + + def test_sample_list_with_limit(self): + samples = list(self.mgr.list(limit=1)) + expect = ['GET', '/v2/samples?limit=1'] + self.http_client.assert_called(*expect) + self.assertEqual(1, len(samples)) + + def test_sample_get(self): + sample = self.mgr.get(GET_SAMPLE['id']) + expect = ['GET', '/v2/samples/' + GET_SAMPLE['id']] + self.http_client.assert_called(*expect) + self.assertEqual(GET_SAMPLE, sample.to_dict()) diff --git a/ceilometerclient/tests/unit/v2/test_shell.py b/ceilometerclient/tests/unit/v2/test_shell.py new file mode 100644 index 0000000..a4b9f33 --- /dev/null +++ b/ceilometerclient/tests/unit/v2/test_shell.py @@ -0,0 +1,1175 @@ +# Copyright Ericsson AB 2014. All rights reserved +# +# Authors: Balazs Gibizer +# Ildiko Vancsa +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# 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 sys + +import mock +import six +from testtools import matchers + +from ceilometerclient import exc +from ceilometerclient import shell as base_shell +from ceilometerclient.tests.unit import test_shell +from ceilometerclient.tests.unit import utils +from ceilometerclient.v2 import alarms +from ceilometerclient.v2 import events +from ceilometerclient.v2 import samples +from ceilometerclient.v2 import shell as ceilometer_shell +from ceilometerclient.v2 import statistics + + +class ShellAlarmStateCommandsTest(utils.BaseTestCase): + + ALARM_ID = 'foobar' + + def setUp(self): + super(ShellAlarmStateCommandsTest, self).setUp() + self.cc = mock.Mock() + self.cc.alarms = mock.Mock() + self.args = mock.Mock() + self.args.alarm_id = self.ALARM_ID + + def test_alarm_state_get(self): + ceilometer_shell.do_alarm_state_get(self.cc, self.args) + self.cc.alarms.get_state.assert_called_once_with(self.ALARM_ID) + self.assertFalse(self.cc.alarms.set_state.called) + + def test_alarm_state_set(self): + self.args.state = 'ok' + ceilometer_shell.do_alarm_state_set(self.cc, self.args) + self.cc.alarms.set_state.assert_called_once_with(self.ALARM_ID, 'ok') + self.assertFalse(self.cc.alarms.get_state.called) + + +class ShellAlarmHistoryCommandTest(utils.BaseTestCase): + + ALARM_ID = '768ff714-8cfb-4db9-9753-d484cb33a1cc' + FULL_DETAIL = ('{"alarm_actions": [], ' + '"user_id": "8185aa72421a4fd396d4122cba50e1b5", ' + '"name": "scombo", ' + '"timestamp": "2013-10-03T08:58:33.647912", ' + '"enabled": true, ' + '"state_timestamp": "2013-10-03T08:58:33.647912", ' + '"rule": {"operator": "or", "alarm_ids": ' + '["062cc907-3a9f-4867-ab3b-fa83212b39f7"]}, ' + '"alarm_id": "768ff714-8cfb-4db9-9753-d484cb33a1cc", ' + '"state": "insufficient data", ' + '"insufficient_data_actions": [], ' + '"repeat_actions": false, ' + '"ok_actions": [], ' + '"project_id": "57d04f24d0824b78b1ea9bcecedbda8f", ' + '"type": "combination", ' + '"description": "Combined state of alarms ' + '062cc907-3a9f-4867-ab3b-fa83212b39f7"}') + ALARM_HISTORY = [{'on_behalf_of': '57d04f24d0824b78b1ea9bcecedbda8f', + 'user_id': '8185aa72421a4fd396d4122cba50e1b5', + 'event_id': 'c74a8611-6553-4764-a860-c15a6aabb5d0', + 'timestamp': '2013-10-03T08:59:28.326000', + 'detail': '{"state": "alarm"}', + 'alarm_id': '768ff714-8cfb-4db9-9753-d484cb33a1cc', + 'project_id': '57d04f24d0824b78b1ea9bcecedbda8f', + 'type': 'state transition'}, + {'on_behalf_of': '57d04f24d0824b78b1ea9bcecedbda8f', + 'user_id': '8185aa72421a4fd396d4122cba50e1b5', + 'event_id': 'c74a8611-6553-4764-a860-c15a6aabb5d0', + 'timestamp': '2013-10-03T08:59:28.326000', + 'detail': '{"description": "combination of one"}', + 'alarm_id': '768ff714-8cfb-4db9-9753-d484cb33a1cc', + 'project_id': '57d04f24d0824b78b1ea9bcecedbda8f', + 'type': 'rule change'}, + {'on_behalf_of': '57d04f24d0824b78b1ea9bcecedbda8f', + 'user_id': '8185aa72421a4fd396d4122cba50e1b5', + 'event_id': '4fd7df9e-190d-4471-8884-dc5a33d5d4bb', + 'timestamp': '2013-10-03T08:58:33.647000', + 'detail': FULL_DETAIL, + 'alarm_id': '768ff714-8cfb-4db9-9753-d484cb33a1cc', + 'project_id': '57d04f24d0824b78b1ea9bcecedbda8f', + 'type': 'creation'}] + TIMESTAMP_RE = (' +\| (\d{4})-(\d{2})-(\d{2})T' + '(\d{2})\:(\d{2})\:(\d{2})\.(\d{6}) \| +') + + def setUp(self): + super(ShellAlarmHistoryCommandTest, self).setUp() + self.cc = mock.Mock() + self.cc.alarms = mock.Mock() + self.args = mock.Mock() + self.args.alarm_id = self.ALARM_ID + + @mock.patch('sys.stdout', new=six.StringIO()) + def _do_test_alarm_history(self, raw_query=None, parsed_query=None): + self.args.query = raw_query + history = [alarms.AlarmChange(mock.Mock(), change) + for change in self.ALARM_HISTORY] + self.cc.alarms.get_history.return_value = history + + ceilometer_shell.do_alarm_history(self.cc, self.args) + self.cc.alarms.get_history.assert_called_once_with( + q=parsed_query, + alarm_id=self.ALARM_ID + ) + out = sys.stdout.getvalue() + required = [ + '.*creation%sname: scombo.*' % self.TIMESTAMP_RE, + '.*rule change%sdescription: combination of one.*' % + self.TIMESTAMP_RE, + '.*state transition%sstate: alarm.*' % self.TIMESTAMP_RE, + ] + for r in required: + self.assertThat(out, matchers.MatchesRegex(r, re.DOTALL)) + + def test_alarm_all_history(self): + self._do_test_alarm_history() + + def test_alarm_constrained_history(self): + parsed_query = [dict(field='timestamp', + value='2013-10-03T08:59:28', + op='gt', + type='')] + self._do_test_alarm_history(raw_query='timestamp>2013-10-03T08:59:28', + parsed_query=parsed_query) + + +class ShellAlarmCommandTest(utils.BaseTestCase): + + ALARM_ID = '768ff714-8cfb-4db9-9753-d484cb33a1cc' + ALARM = {"alarm_actions": ["log://"], + "ok_actions": [], + "description": "instance running hot", + "timestamp": "2013-11-20T10:38:42.206952", + "enabled": True, + "state_timestamp": "2013-11-19T17:20:44", + "threshold_rule": {"meter_name": "cpu_util", + "evaluation_periods": 3, + "period": 600, + "statistic": "avg", + "threshold": 99.0, + "query": [{"field": "resource_id", + "value": "INSTANCE_ID", + "op": "eq"}], + "comparison_operator": "gt"}, + "time_constraints": [{"name": "cons1", + "description": "desc1", + "start": "0 11 * * *", + "duration": 300, + "timezone": ""}, + {"name": "cons2", + "description": "desc2", + "start": "0 23 * * *", + "duration": 600, + "timezone": ""}], + "alarm_id": ALARM_ID, + "state": "insufficient data", + "severity": "low", + "insufficient_data_actions": [], + "repeat_actions": True, + "user_id": "528d9b68fa774689834b5c04b4564f8a", + "project_id": "ed9d4e2be2a748bc80108053cf4598f5", + "type": "threshold", + "name": "cpu_high"} + + THRESHOLD_ALARM_CLI_ARGS = [ + '--name', 'cpu_high', + '--description', 'instance running hot', + '--meter-name', 'cpu_util', + '--threshold', '70.0', + '--comparison-operator', 'gt', + '--statistic', 'avg', + '--period', '600', + '--evaluation-periods', '3', + '--alarm-action', 'log://', + '--alarm-action', 'http://example.com/alarm/state', + '--query', 'resource_id=INSTANCE_ID' + ] + + def setUp(self): + super(ShellAlarmCommandTest, self).setUp() + self.cc = mock.Mock() + self.cc.alarms = mock.Mock() + self.args = mock.Mock() + self.args.alarm_id = self.ALARM_ID + + @mock.patch('sys.stdout', new=six.StringIO()) + def _do_test_alarm_update_repeat_actions(self, method, repeat_actions): + self.args.threshold = 42.0 + if repeat_actions is not None: + self.args.repeat_actions = repeat_actions + alarm = [alarms.Alarm(mock.Mock(), self.ALARM)] + self.cc.alarms.get.return_value = alarm + self.cc.alarms.update.return_value = alarm[0] + + method(self.cc, self.args) + args, kwargs = self.cc.alarms.update.call_args + self.assertEqual(self.ALARM_ID, args[0]) + self.assertEqual(42.0, kwargs.get('threshold')) + if repeat_actions is not None: + self.assertEqual(repeat_actions, kwargs.get('repeat_actions')) + else: + self.assertNotIn('repeat_actions', kwargs) + + def test_alarm_update_repeat_actions_untouched(self): + method = ceilometer_shell.do_alarm_update + self._do_test_alarm_update_repeat_actions(method, None) + + def test_alarm_update_repeat_actions_set(self): + method = ceilometer_shell.do_alarm_update + self._do_test_alarm_update_repeat_actions(method, True) + + def test_alarm_update_repeat_actions_clear(self): + method = ceilometer_shell.do_alarm_update + self._do_test_alarm_update_repeat_actions(method, False) + + def test_alarm_combination_update_repeat_actions_untouched(self): + method = ceilometer_shell.do_alarm_combination_update + self._do_test_alarm_update_repeat_actions(method, None) + + def test_alarm_combination_update_repeat_actions_set(self): + method = ceilometer_shell.do_alarm_combination_update + self._do_test_alarm_update_repeat_actions(method, True) + + def test_alarm_combination_update_repeat_actions_clear(self): + method = ceilometer_shell.do_alarm_combination_update + self._do_test_alarm_update_repeat_actions(method, False) + + def test_alarm_threshold_update_repeat_actions_untouched(self): + method = ceilometer_shell.do_alarm_threshold_update + self._do_test_alarm_update_repeat_actions(method, None) + + def test_alarm_threshold_update_repeat_actions_set(self): + method = ceilometer_shell.do_alarm_threshold_update + self._do_test_alarm_update_repeat_actions(method, True) + + def test_alarm_threshold_update_repeat_actions_clear(self): + method = ceilometer_shell.do_alarm_threshold_update + self._do_test_alarm_update_repeat_actions(method, False) + + @mock.patch('sys.stdout', new=six.StringIO()) + def test_alarm_threshold_create_args(self): + argv = ['alarm-threshold-create'] + self.THRESHOLD_ALARM_CLI_ARGS + self._test_alarm_threshold_action_args('create', argv) + + def test_alarm_threshold_update_args(self): + argv = ['alarm-threshold-update', 'x'] + self.THRESHOLD_ALARM_CLI_ARGS + self._test_alarm_threshold_action_args('update', argv) + + @mock.patch('sys.stdout', new=six.StringIO()) + def _test_alarm_threshold_action_args(self, action, argv): + shell = base_shell.CeilometerShell() + _, args = shell.parse_args(argv) + + alarm = alarms.Alarm(mock.Mock(), self.ALARM) + getattr(self.cc.alarms, action).return_value = alarm + + func = getattr(ceilometer_shell, 'do_alarm_threshold_' + action) + func(self.cc, args) + _, kwargs = getattr(self.cc.alarms, action).call_args + self._check_alarm_threshold_args(kwargs) + + def _check_alarm_threshold_args(self, kwargs): + self.assertEqual('cpu_high', kwargs.get('name')) + self.assertEqual('instance running hot', kwargs.get('description')) + actions = ['log://', 'http://example.com/alarm/state'] + self.assertEqual(actions, kwargs.get('alarm_actions')) + self.assertIn('threshold_rule', kwargs) + rule = kwargs['threshold_rule'] + self.assertEqual('cpu_util', rule.get('meter_name')) + self.assertEqual(70.0, rule.get('threshold')) + self.assertEqual('gt', rule.get('comparison_operator')) + self.assertEqual('avg', rule.get('statistic')) + self.assertEqual(600, rule.get('period')) + self.assertEqual(3, rule.get('evaluation_periods')) + query = dict(field='resource_id', type='', + value='INSTANCE_ID', op='eq') + self.assertEqual([query], rule['query']) + + @mock.patch('sys.stdout', new=six.StringIO()) + def test_alarm_create_time_constraints(self): + shell = base_shell.CeilometerShell() + argv = ['alarm-threshold-create', + '--name', 'cpu_high', + '--meter-name', 'cpu_util', + '--threshold', '70.0', + '--time-constraint', + 'name=cons1;start="0 11 * * *";duration=300', + '--time-constraint', + 'name=cons2;start="0 23 * * *";duration=600', + ] + _, args = shell.parse_args(argv) + + alarm = alarms.Alarm(mock.Mock(), self.ALARM) + self.cc.alarms.create.return_value = alarm + + ceilometer_shell.do_alarm_threshold_create(self.cc, args) + _, kwargs = self.cc.alarms.create.call_args + time_constraints = [dict(name='cons1', start='0 11 * * *', + duration='300'), + dict(name='cons2', start='0 23 * * *', + duration='600')] + self.assertEqual(time_constraints, kwargs['time_constraints']) + + +class ShellSampleListCommandTest(utils.BaseTestCase): + + METER = 'cpu_util' + SAMPLE_VALUES = ( + ("cpu_util", + "5dcf5537-3161-4e25-9235-407e1385bd35", + "2013-10-15T05:50:30", + "%", + 0.261666666667, + "gauge", + "86536501-b2c9-48f6-9c6a-7a5b14ba7482"), + ("cpu_util", + "87d197e9-9cf6-4c25-bc66-1b1f4cedb52f", + "2013-10-15T05:50:29", + "%", + 0.261666666667, + "gauge", + "fe2a91ec-602b-4b55-8cba-5302ce3b916e",), + ("cpu_util", + "5dcf5537-3161-4e25-9235-407e1385bd35", + "2013-10-15T05:40:30", + "%", + 0.251247920133, + "gauge", + "52768bcb-b4e9-4db9-a30c-738c758b6f43"), + ("cpu_util", + "87d197e9-9cf6-4c25-bc66-1b1f4cedb52f", + "2013-10-15T05:40:29", + "%", + 0.26, + "gauge", + "31ae614a-ac6b-4fb9-b106-4667bae03308"), + ) + + OLD_SAMPLES = [ + dict(counter_name=s[0], + resource_id=s[1], + timestamp=s[2], + counter_unit=s[3], + counter_volume=s[4], + counter_type=s[5]) + for s in SAMPLE_VALUES + ] + + SAMPLES = [ + dict(meter=s[0], + resource_id=s[1], + timestamp=s[2], + unit=s[3], + volume=s[4], + type=s[5], + id=s[6]) + for s in SAMPLE_VALUES + ] + + def setUp(self): + super(ShellSampleListCommandTest, self).setUp() + self.cc = mock.Mock() + self.cc.samples = mock.Mock() + self.cc.new_samples = mock.Mock() + self.args = mock.Mock() + self.args.query = None + self.args.limit = None + + @mock.patch('sys.stdout', new=six.StringIO()) + def test_old_sample_list(self): + self.args.meter = self.METER + sample_list = [samples.OldSample(mock.Mock(), sample) + for sample in self.OLD_SAMPLES] + self.cc.samples.list.return_value = sample_list + + ceilometer_shell.do_sample_list(self.cc, self.args) + self.cc.samples.list.assert_called_once_with( + meter_name=self.METER, + q=None, + limit=None) + + self.assertEqual('''\ ++--------------------------------------+----------+-------+----------------\ ++------+---------------------+ +| Resource ID | Name | Type | Volume \ +| Unit | Timestamp | ++--------------------------------------+----------+-------+----------------\ ++------+---------------------+ +| 5dcf5537-3161-4e25-9235-407e1385bd35 | cpu_util | gauge | 0.261666666667 \ +| % | 2013-10-15T05:50:30 | +| 87d197e9-9cf6-4c25-bc66-1b1f4cedb52f | cpu_util | gauge | 0.261666666667 \ +| % | 2013-10-15T05:50:29 | +| 5dcf5537-3161-4e25-9235-407e1385bd35 | cpu_util | gauge | 0.251247920133 \ +| % | 2013-10-15T05:40:30 | +| 87d197e9-9cf6-4c25-bc66-1b1f4cedb52f | cpu_util | gauge | 0.26 \ +| % | 2013-10-15T05:40:29 | ++--------------------------------------+----------+-------+----------------\ ++------+---------------------+ +''', sys.stdout.getvalue()) + + @mock.patch('sys.stdout', new=six.StringIO()) + def test_sample_list(self): + self.args.meter = None + sample_list = [samples.Sample(mock.Mock(), sample) + for sample in self.SAMPLES] + self.cc.new_samples.list.return_value = sample_list + + ceilometer_shell.do_sample_list(self.cc, self.args) + self.cc.new_samples.list.assert_called_once_with( + q=None, + limit=None) + + self.assertEqual('''\ ++--------------------------------------+--------------------------------------\ ++----------+-------+----------------+------+---------------------+ +| ID | Resource ID \ +| Name | Type | Volume | Unit | Timestamp | ++--------------------------------------+--------------------------------------\ ++----------+-------+----------------+------+---------------------+ +| 86536501-b2c9-48f6-9c6a-7a5b14ba7482 | 5dcf5537-3161-4e25-9235-407e1385bd35 \ +| cpu_util | gauge | 0.261666666667 | % | 2013-10-15T05:50:30 | +| fe2a91ec-602b-4b55-8cba-5302ce3b916e | 87d197e9-9cf6-4c25-bc66-1b1f4cedb52f \ +| cpu_util | gauge | 0.261666666667 | % | 2013-10-15T05:50:29 | +| 52768bcb-b4e9-4db9-a30c-738c758b6f43 | 5dcf5537-3161-4e25-9235-407e1385bd35 \ +| cpu_util | gauge | 0.251247920133 | % | 2013-10-15T05:40:30 | +| 31ae614a-ac6b-4fb9-b106-4667bae03308 | 87d197e9-9cf6-4c25-bc66-1b1f4cedb52f \ +| cpu_util | gauge | 0.26 | % | 2013-10-15T05:40:29 | ++--------------------------------------+--------------------------------------\ ++----------+-------+----------------+------+---------------------+ +''', sys.stdout.getvalue()) + + +class ShellSampleShowCommandTest(utils.BaseTestCase): + + SAMPLE = { + "user_id": None, + "resource_id": "9b651dfd-7d30-402b-972e-212b2c4bfb05", + "timestamp": "2014-11-03T13:37:46", + "meter": "image", + "volume": 1.0, + "source": "openstack", + "recorded_at": "2014-11-03T13:37:46.994458", + "project_id": "2cc3a7bb859b4bacbeab0aa9ca673033", + "type": "gauge", + "id": "98b5f258-635e-11e4-8bdd-0025647390c1", + "unit": "image", + "metadata": { + "name": "cirros-0.3.2-x86_64-uec", + } + } + + def setUp(self): + super(ShellSampleShowCommandTest, self).setUp() + self.cc = mock.Mock() + self.cc.new_samples = mock.Mock() + self.args = mock.Mock() + self.args.sample_id = "98b5f258-635e-11e4-8bdd-0025647390c1" + + @mock.patch('sys.stdout', new=six.StringIO()) + def test_sample_show(self): + sample = samples.Sample(mock.Mock(), self.SAMPLE) + self.cc.new_samples.get.return_value = sample + + ceilometer_shell.do_sample_show(self.cc, self.args) + self.cc.new_samples.get.assert_called_once_with( + "98b5f258-635e-11e4-8bdd-0025647390c1") + + self.assertEqual('''\ ++-------------+--------------------------------------+ +| Property | Value | ++-------------+--------------------------------------+ +| id | 98b5f258-635e-11e4-8bdd-0025647390c1 | +| metadata | {"name": "cirros-0.3.2-x86_64-uec"} | +| meter | image | +| project_id | 2cc3a7bb859b4bacbeab0aa9ca673033 | +| recorded_at | 2014-11-03T13:37:46.994458 | +| resource_id | 9b651dfd-7d30-402b-972e-212b2c4bfb05 | +| source | openstack | +| timestamp | 2014-11-03T13:37:46 | +| type | gauge | +| unit | image | +| user_id | None | +| volume | 1.0 | ++-------------+--------------------------------------+ +''', sys.stdout.getvalue()) + + +class ShellSampleCreateCommandTest(utils.BaseTestCase): + + METER = 'instance' + METER_TYPE = 'gauge' + RESOURCE_ID = '0564c64c-3545-4e34-abfb-9d18e5f2f2f9' + SAMPLE_VOLUME = '1' + METER_UNIT = 'instance' + SAMPLE = [{ + u'counter_name': u'instance', + u'user_id': u'21b442b8101d407d8242b6610e0ed0eb', + u'resource_id': u'0564c64c-3545-4e34-abfb-9d18e5f2f2f9', + u'timestamp': u'2014-01-10T03: 05: 33.951170', + u'message_id': u'1247cbe6-79a4-11e3-a296-000c294c58e2', + u'source': u'384260c6987b451d8290e66e1f108082: openstack', + u'counter_unit': u'instance', + u'counter_volume': 1.0, + u'project_id': u'384260c6987b451d8290e66e1f108082', + u'resource_metadata': {}, + u'counter_type': u'gauge' + }] + + def setUp(self): + super(ShellSampleCreateCommandTest, self).setUp() + self.cc = mock.Mock() + self.cc.samples = mock.Mock() + self.args = mock.Mock() + self.args.meter_name = self.METER + self.args.meter_type = self.METER_TYPE + self.args.meter_unit = self.METER_UNIT + self.args.resource_id = self.RESOURCE_ID + self.args.sample_volume = self.SAMPLE_VOLUME + + @mock.patch('sys.stdout', new=six.StringIO()) + def test_sample_create(self): + ret_sample = [samples.OldSample(mock.Mock(), sample) + for sample in self.SAMPLE] + self.cc.samples.create.return_value = ret_sample + + ceilometer_shell.do_sample_create(self.cc, self.args) + + self.assertEqual('''\ ++-------------------+---------------------------------------------+ +| Property | Value | ++-------------------+---------------------------------------------+ +| message_id | 1247cbe6-79a4-11e3-a296-000c294c58e2 | +| name | instance | +| project_id | 384260c6987b451d8290e66e1f108082 | +| resource_id | 0564c64c-3545-4e34-abfb-9d18e5f2f2f9 | +| resource_metadata | {} | +| source | 384260c6987b451d8290e66e1f108082: openstack | +| timestamp | 2014-01-10T03: 05: 33.951170 | +| type | gauge | +| unit | instance | +| user_id | 21b442b8101d407d8242b6610e0ed0eb | +| volume | 1.0 | ++-------------------+---------------------------------------------+ +''', sys.stdout.getvalue()) + + +class ShellQuerySamplesCommandTest(utils.BaseTestCase): + + SAMPLE = [{u'id': u'b55d1526-9929-11e3-a3f6-02163e5df1e6', + u'metadata': { + u'name1': u'value1', + u'name2': u'value2'}, + u'meter': 'instance', + u'project_id': u'35b17138-b364-4e6a-a131-8f3099c5be68', + u'resource_id': u'bd9431c1-8d69-4ad3-803a-8d4a6b89fd36', + u'source': u'openstack', + u'timestamp': u'2014-02-19T05:50:16.673604', + u'type': u'gauge', + u'unit': u'instance', + u'volume': 1, + u'user_id': 'efd87807-12d2-4b38-9c70-5f5c2ac427ff'}] + + QUERY = {"filter": {"and": [{"=": {"source": "openstack"}}, + {">": {"timestamp": "2014-02-19T05:50:16"}}]}, + "orderby": [{"timestamp": "desc"}, {"volume": "asc"}], + "limit": 10} + + def setUp(self): + super(ShellQuerySamplesCommandTest, self).setUp() + self.cc = mock.Mock() + self.args = mock.Mock() + self.args.filter = self.QUERY["filter"] + self.args.orderby = self.QUERY["orderby"] + self.args.limit = self.QUERY["limit"] + + @mock.patch('sys.stdout', new=six.StringIO()) + def test_query(self): + ret_sample = [samples.Sample(mock.Mock(), sample) + for sample in self.SAMPLE] + self.cc.query_samples.query.return_value = ret_sample + + ceilometer_shell.do_query_samples(self.cc, self.args) + + self.assertEqual('''\ ++--------------------------------------+----------+-------+--------+---------\ +-+----------------------------+ +| Resource ID | Meter | Type | Volume | Unit \ + | Timestamp | ++--------------------------------------+----------+-------+--------+---------\ +-+----------------------------+ +| bd9431c1-8d69-4ad3-803a-8d4a6b89fd36 | instance | gauge | 1 | instance\ + | 2014-02-19T05:50:16.673604 | ++--------------------------------------+----------+-------+--------+---------\ +-+----------------------------+ +''', sys.stdout.getvalue()) + + +class ShellQueryAlarmsCommandTest(utils.BaseTestCase): + + ALARM = [{"alarm_actions": ["http://site:8000/alarm"], + "alarm_id": "768ff714-8cfb-4db9-9753-d484cb33a1cc", + "combination_rule": { + "alarm_ids": [ + "739e99cb-c2ec-4718-b900-332502355f38", + "153462d0-a9b8-4b5b-8175-9e4b05e9b856"], + "operator": "or"}, + "description": "An alarm", + "enabled": True, + "insufficient_data_actions": ["http://site:8000/nodata"], + "name": "SwiftObjectAlarm", + "ok_actions": ["http://site:8000/ok"], + "project_id": "c96c887c216949acbdfbd8b494863567", + "repeat_actions": False, + "state": "ok", + "severity": "critical", + "state_timestamp": "2014-02-20T10:37:15.589860", + "threshold_rule": None, + "timestamp": "2014-02-20T10:37:15.589856", + "time_constraints": [{"name": "test", "start": "0 23 * * *", + "duration": 10800}], + "type": "combination", + "user_id": "c96c887c216949acbdfbd8b494863567"}] + + QUERY = {"filter": {"and": [{"!=": {"state": "ok"}}, + {"=": {"type": "combination"}}]}, + "orderby": [{"state_timestamp": "desc"}], + "limit": 10} + + def setUp(self): + super(ShellQueryAlarmsCommandTest, self).setUp() + self.cc = mock.Mock() + self.args = mock.Mock() + self.args.filter = self.QUERY["filter"] + self.args.orderby = self.QUERY["orderby"] + self.args.limit = self.QUERY["limit"] + + @mock.patch('sys.stdout', new=six.StringIO()) + def test_query(self): + ret_alarm = [alarms.Alarm(mock.Mock(), alarm) + for alarm in self.ALARM] + self.cc.query_alarms.query.return_value = ret_alarm + + ceilometer_shell.do_query_alarms(self.cc, self.args) + + self.assertEqual('''\ ++--------------------------------------+------------------+-------+----------+\ +---------+------------+-------------------------------------------------------\ +-----------------------------------------------+-------------------------------\ +-+ +| Alarm ID | Name | State | Severity \ +| Enabled | Continuous | Alarm condition \ + | Time constraints \ + | ++--------------------------------------+------------------+-------+----------+\ +---------+------------+-------------------------------------------------------\ +-----------------------------------------------+--------------------------------+ +| 768ff714-8cfb-4db9-9753-d484cb33a1cc | SwiftObjectAlarm | ok | critical \ +| True | False | combinated states (OR) of \ +739e99cb-c2ec-4718-b900-332502355f38, 153462d0-a9b8-4b5b-8175-9e4b05e9b856 |\ + test at 0 23 * * * for 10800s | ++--------------------------------------+------------------+-------+----------+\ +---------+------------+-------------------------------------------------------\ +-----------------------------------------------+------------------------------\ +--+ +''', sys.stdout.getvalue()) + + @mock.patch('sys.stdout', new=six.StringIO()) + def test_time_constraints_compatibility(self): + # client should be backwards compatible + alarm_without_tc = dict(self.ALARM[0]) + del alarm_without_tc['time_constraints'] + + # NOTE(nsaje): Since we're accessing a nonexisting key in the resource, + # the resource is looking it up with the manager (which is a mock). + manager_mock = mock.Mock() + del manager_mock.get + ret_alarm = [alarms.Alarm(manager_mock, alarm_without_tc)] + self.cc.query_alarms.query.return_value = ret_alarm + + ceilometer_shell.do_query_alarms(self.cc, self.args) + + self.assertEqual('''\ ++--------------------------------------+------------------+-------+----------+\ +---------+------------+-------------------------------------------------------\ +-----------------------------------------------+------------------+ +| Alarm ID | Name | State | Severity \ +| Enabled | Continuous | Alarm condition \ + | Time constraints | ++--------------------------------------+------------------+-------+----------+\ +---------+------------+-------------------------------------------------------\ +-----------------------------------------------+------------------+ +| 768ff714-8cfb-4db9-9753-d484cb33a1cc | SwiftObjectAlarm | ok | critical \ +| True | False | combinated states (OR) of \ +739e99cb-c2ec-4718-b900-332502355f38, 153462d0-a9b8-4b5b-8175-9e4b05e9b856 \ +| None | ++--------------------------------------+------------------+-------+----------+\ +---------+------------+-------------------------------------------------------\ +-----------------------------------------------+------------------+ +''', sys.stdout.getvalue()) + + +class ShellQueryAlarmHistoryCommandTest(utils.BaseTestCase): + + ALARM_HISTORY = [{"alarm_id": "e8ff32f772a44a478182c3fe1f7cad6a", + "event_id": "c74a8611-6553-4764-a860-c15a6aabb5d0", + "detail": + "{\"threshold\": 42.0, \"evaluation_periods\": 4}", + "on_behalf_of": "92159030020611e3b26dde429e99ee8c", + "project_id": "b6f16144010811e387e4de429e99ee8c", + "timestamp": "2014-03-11T16:02:58.376261", + "type": "rule change", + "user_id": "3e5d11fda79448ac99ccefb20be187ca" + }] + + QUERY = {"filter": {"and": [{">": {"timestamp": "2014-03-11T16:02:58"}}, + {"=": {"type": "rule change"}}]}, + "orderby": [{"timestamp": "desc"}], + "limit": 10} + + def setUp(self): + super(ShellQueryAlarmHistoryCommandTest, self).setUp() + self.cc = mock.Mock() + self.args = mock.Mock() + self.args.filter = self.QUERY["filter"] + self.args.orderby = self.QUERY["orderby"] + self.args.limit = self.QUERY["limit"] + + @mock.patch('sys.stdout', new=six.StringIO()) + def test_query(self): + ret_alarm_history = [alarms.AlarmChange(mock.Mock(), alarm_history) + for alarm_history in self.ALARM_HISTORY] + self.cc.query_alarm_history.query.return_value = ret_alarm_history + + ceilometer_shell.do_query_alarm_history(self.cc, self.args) + + self.assertEqual('''\ ++----------------------------------+--------------------------------------+-\ +------------+----------------------------------------------+----------------\ +------------+ +| Alarm ID | Event ID | \ +Type | Detail | Timestamp \ + | ++----------------------------------+--------------------------------------+-\ +------------+----------------------------------------------+----------------\ +------------+ +| e8ff32f772a44a478182c3fe1f7cad6a | c74a8611-6553-4764-a860-c15a6aabb5d0 | \ +rule change | {"threshold": 42.0, "evaluation_periods": 4} | 2014-03-11T16:0\ +2:58.376261 | ++----------------------------------+--------------------------------------+-\ +------------+----------------------------------------------+----------------\ +------------+ +''', sys.stdout.getvalue()) + + +class ShellStatisticsTest(utils.BaseTestCase): + def setUp(self): + super(ShellStatisticsTest, self).setUp() + self.cc = mock.Mock() + self.displays = { + 'duration': 'Duration', + 'duration_end': 'Duration End', + 'duration_start': 'Duration Start', + 'period': 'Period', + 'period_end': 'Period End', + 'period_start': 'Period Start', + 'groupby': 'Group By', + 'avg': 'Avg', + 'count': 'Count', + 'max': 'Max', + 'min': 'Min', + 'sum': 'Sum', + 'stddev': 'Standard deviation', + 'cardinality': 'Cardinality' + } + self.args = mock.Mock() + self.args.meter_name = 'instance' + self.args.aggregate = [] + self.args.groupby = None + self.args.query = None + + def test_statistics_list_simple(self): + samples = [ + {u'count': 135, + u'duration_start': u'2013-02-04T10:51:42', + u'min': 1.0, + u'max': 1.0, + u'duration_end': + u'2013-02-05T15:46:09', + u'duration': 1734.0, + u'avg': 1.0, + u'sum': 135.0}, + ] + fields = [ + 'period', + 'period_start', + 'period_end', + 'max', + 'min', + 'avg', + 'sum', + 'count', + 'duration', + 'duration_start', + 'duration_end', + ] + statistics_ret = [ + statistics.Statistics(mock.Mock(), sample) for sample in samples + ] + self.cc.statistics.list.return_value = statistics_ret + with mock.patch('ceilometerclient.v2.shell.utils.print_list') as pmock: + ceilometer_shell.do_statistics(self.cc, self.args) + pmock.assert_called_with( + statistics_ret, + fields, + [self.displays[f] for f in fields] + ) + + def test_statistics_list_groupby(self): + samples = [ + {u'count': 135, + u'duration_start': u'2013-02-04T10:51:42', + u'min': 1.0, + u'max': 1.0, + u'duration_end': + u'2013-02-05T15:46:09', + u'duration': 1734.0, + u'avg': 1.0, + u'sum': 135.0, + u'groupby': {u'resource_id': u'foo'} + }, + {u'count': 12, + u'duration_start': u'2013-02-04T10:51:42', + u'min': 1.0, + u'max': 1.0, + u'duration_end': + u'2013-02-05T15:46:09', + u'duration': 1734.0, + u'avg': 1.0, + u'sum': 12.0, + u'groupby': {u'resource_id': u'bar'} + }, + ] + fields = [ + 'period', + 'period_start', + 'period_end', + 'groupby', + 'max', + 'min', + 'avg', + 'sum', + 'count', + 'duration', + 'duration_start', + 'duration_end', + ] + self.args.groupby = 'resource_id' + statistics_ret = [ + statistics.Statistics(mock.Mock(), sample) for sample in samples + ] + self.cc.statistics.list.return_value = statistics_ret + with mock.patch('ceilometerclient.v2.shell.utils.print_list') as pmock: + ceilometer_shell.do_statistics(self.cc, self.args) + pmock.assert_called_with( + statistics_ret, + fields, + [self.displays[f] for f in fields], + ) + + def test_statistics_list_aggregates(self): + samples = [ + {u'aggregate': {u'cardinality/resource_id': 4.0, u'count': 2.0}, + u'count': 2, + u'duration': 0.442451, + u'duration_end': u'2014-03-12T14:00:21.774154', + u'duration_start': u'2014-03-12T14:00:21.331703', + u'groupby': None, + u'period': 0, + u'period_end': u'2014-03-12T14:00:21.774154', + u'period_start': u'2014-03-12T14:00:21.331703', + u'unit': u'instance', + }, + ] + fields = [ + 'period', + 'period_start', + 'period_end', + 'count', + 'cardinality/resource_id', + 'duration', + 'duration_start', + 'duration_end', + ] + self.args.aggregate = ['count', 'cardinality<-resource_id'] + statistics_ret = [ + statistics.Statistics(mock.Mock(), sample) for sample in samples + ] + self.cc.statistics.list.return_value = statistics_ret + with mock.patch('ceilometerclient.v2.shell.utils.print_list') as pmock: + ceilometer_shell.do_statistics(self.cc, self.args) + pmock.assert_called_with( + statistics_ret, + fields, + [self.displays.get(f, f) for f in fields], + ) + + +class ShellEmptyIdTest(utils.BaseTestCase): + """Test empty field which will cause calling incorrect rest uri.""" + + def _test_entity_action_with_empty_values(self, entity, + *args, **kwargs): + positional = kwargs.pop('positional', False) + for value in ('', ' ', ' ', '\t'): + self._test_entity_action_with_empty_value(entity, value, + positional, *args) + + def _test_entity_action_with_empty_value(self, entity, value, + positional, *args): + new_args = [value] if positional else ['--%s' % entity, value] + argv = list(args) + new_args + shell = base_shell.CeilometerShell() + with mock.patch('ceilometerclient.exc.CommandError') as e: + e.return_value = exc.BaseException() + self.assertRaises(exc.BaseException, shell.parse_args, argv) + entity = entity.replace('-', '_') + e.assert_called_with('%s should not be empty' % entity) + + def _test_alarm_action_with_empty_ids(self, method, *args): + args = [method] + list(args) + self._test_entity_action_with_empty_values('alarm_id', + positional=True, *args) + + def test_alarm_show_with_empty_id(self): + self._test_alarm_action_with_empty_ids('alarm-show') + + def test_alarm_update_with_empty_id(self): + self._test_alarm_action_with_empty_ids('alarm-update') + + def test_alarm_threshold_update_with_empty_id(self): + self._test_alarm_action_with_empty_ids('alarm-threshold-update') + + def test_alarm_combination_update_with_empty_id(self): + self._test_alarm_action_with_empty_ids('alarm-combination-update') + + def test_alarm_delete_with_empty_id(self): + self._test_alarm_action_with_empty_ids('alarm-delete') + + def test_alarm_state_get_with_empty_id(self): + self._test_alarm_action_with_empty_ids('alarm-state-get') + + def test_alarm_state_set_with_empty_id(self): + args = ['alarm-state-set', '--state', 'ok'] + self._test_alarm_action_with_empty_ids(*args) + + def test_alarm_history_with_empty_id(self): + self._test_alarm_action_with_empty_ids('alarm-history') + + def test_event_show_with_empty_message_id(self): + args = ['event-show'] + self._test_entity_action_with_empty_values('message_id', *args) + + def test_resource_show_with_empty_id(self): + args = ['resource-show'] + self._test_entity_action_with_empty_values('resource_id', *args) + + def test_sample_list_with_empty_meter(self): + args = ['sample-list'] + self._test_entity_action_with_empty_values('meter', *args) + + def test_sample_create_with_empty_meter(self): + args = ['sample-create', '-r', 'x', '--meter-type', 'gauge', + '--meter-unit', 'B', '--sample-volume', '1'] + self._test_entity_action_with_empty_values('meter-name', *args) + + def test_statistics_with_empty_meter(self): + args = ['statistics'] + self._test_entity_action_with_empty_values('meter', *args) + + def test_trait_description_list_with_empty_event_type(self): + args = ['trait-description-list'] + self._test_entity_action_with_empty_values('event_type', *args) + + def test_trait_list_with_empty_event_type(self): + args = ['trait-list', '--trait_name', 'x'] + self._test_entity_action_with_empty_values('event_type', *args) + + def test_trait_list_with_empty_trait_name(self): + args = ['trait-list', '--event_type', 'x'] + self._test_entity_action_with_empty_values('trait_name', *args) + + +class ShellObsoletedArgsTest(utils.BaseTestCase): + """Test arguments that have been obsoleted.""" + + def _test_entity_obsoleted(self, entity, value, positional, *args): + new_args = [value] if positional else ['--%s' % entity, value] + argv = list(args) + new_args + shell = base_shell.CeilometerShell() + with mock.patch('sys.stdout', new_callable=six.StringIO) as stdout: + shell.parse_args(argv) + self.assertIn('obsolete', stdout.getvalue()) + + def test_obsolete_alarm_id(self): + for method in ['alarm-show', 'alarm-update', 'alarm-threshold-update', + 'alarm-combination-update', 'alarm-delete', + 'alarm-state-get', 'alarm-history']: + self._test_entity_obsoleted('alarm_id', 'abcde', False, method) + + +class ShellEventListCommandTest(utils.BaseTestCase): + + EVENTS = [ + { + "traits": [], + "generated": "2015-01-12T04:03:25.741471", + "message_id": "fb2bef58-88af-4380-8698-e0f18fcf452d", + "event_type": "compute.instance.create.start", + "traits": [{ + "name": "state", + "type": "string", + "value": "building", + }], + }, + { + "traits": [], + "generated": "2015-01-12T04:03:28.452495", + "message_id": "9b20509a-576b-4995-acfa-1a24ee5cf49f", + "event_type": "compute.instance.create.end", + "traits": [{ + "name": "state", + "type": "string", + "value": "active", + }], + }, + ] + + def setUp(self): + super(ShellEventListCommandTest, self).setUp() + self.cc = mock.Mock() + self.args = mock.Mock() + self.args.query = None + self.args.no_traits = None + + @mock.patch('sys.stdout', new=six.StringIO()) + def test_event_list(self): + ret_events = [events.Event(mock.Mock(), event) + for event in self.EVENTS] + self.cc.events.list.return_value = ret_events + ceilometer_shell.do_event_list(self.cc, self.args) + self.assertEqual('''\ ++--------------------------------------+-------------------------------+\ +----------------------------+-------------------------------+ +| Message ID | Event Type |\ + Generated | Traits | ++--------------------------------------+-------------------------------+\ +----------------------------+-------------------------------+ +| fb2bef58-88af-4380-8698-e0f18fcf452d | compute.instance.create.start |\ + 2015-01-12T04:03:25.741471 | +-------+--------+----------+ | +| | |\ + | | name | type | value | | +| | |\ + | +-------+--------+----------+ | +| | |\ + | | state | string | building | | +| | |\ + | +-------+--------+----------+ | +| 9b20509a-576b-4995-acfa-1a24ee5cf49f | compute.instance.create.end |\ + 2015-01-12T04:03:28.452495 | +-------+--------+--------+ | +| | |\ + | | name | type | value | | +| | |\ + | +-------+--------+--------+ | +| | |\ + | | state | string | active | | +| | |\ + | +-------+--------+--------+ | ++--------------------------------------+-------------------------------+\ +----------------------------+-------------------------------+ +''', sys.stdout.getvalue()) + + @mock.patch('sys.stdout', new=six.StringIO()) + def test_event_list_no_traits(self): + self.args.no_traits = True + ret_events = [events.Event(mock.Mock(), event) + for event in self.EVENTS] + self.cc.events.list.return_value = ret_events + ceilometer_shell.do_event_list(self.cc, self.args) + self.assertEqual('''\ ++--------------------------------------+-------------------------------\ ++----------------------------+ +| Message ID | Event Type \ +| Generated | ++--------------------------------------+-------------------------------\ ++----------------------------+ +| fb2bef58-88af-4380-8698-e0f18fcf452d | compute.instance.create.start \ +| 2015-01-12T04:03:25.741471 | +| 9b20509a-576b-4995-acfa-1a24ee5cf49f | compute.instance.create.end \ +| 2015-01-12T04:03:28.452495 | ++--------------------------------------+-------------------------------\ ++----------------------------+ +''', sys.stdout.getvalue()) + + +class ShellShadowedArgsTest(test_shell.ShellTestBase): + + def _test_project_id_alarm(self, command, args, method): + self.make_env(test_shell.FAKE_V2_ENV) + cli_args = [ + '--os-project-id', '0ba30185ddf44834914a0b859d244c56', + '--debug', command, + '--project-id', 'the-project-id-i-want-to-set', + '--name', 'project-id-test'] + args + with mock.patch.object(alarms.AlarmManager, method) as mocked: + base_shell.main(cli_args) + args, kwargs = mocked.call_args + self.assertEqual('the-project-id-i-want-to-set', + kwargs.get('project_id')) + + def test_project_id_threshold_alarm(self): + cli_args = ['--meter-name', 'cpu', '--threshold', '90'] + self._test_project_id_alarm('alarm-create', cli_args, 'create') + self._test_project_id_alarm('alarm-threshold-create', + cli_args, 'create') + cli_args += ['--alarm_id', '437b7ed0-3733-4054-a877-e9a297b8be85'] + self._test_project_id_alarm('alarm-update', cli_args, 'update') + self._test_project_id_alarm('alarm-threshold-update', + cli_args, 'update') + + def test_project_id_combination_alarm(self): + cli_args = ['--alarm_ids', 'fb16a05a-669d-414e-8bbe-93aa381df6a8', + '--alarm_ids', 'b189bcca-0a7b-49a9-a244-a927ac291881'] + self._test_project_id_alarm('alarm-combination-create', + cli_args, 'create') + cli_args += ['--alarm_id', '437b7ed0-3733-4054-a877-e9a297b8be85'] + self._test_project_id_alarm('alarm-combination-update', + cli_args, 'update') + + @mock.patch.object(samples.OldSampleManager, 'create') + def test_project_id_sample_create(self, mocked): + self.make_env(test_shell.FAKE_V2_ENV) + cli_args = [ + '--os-project-id', '0ba30185ddf44834914a0b859d244c56', + '--debug', 'sample-create', + '--project-id', 'the-project-id-i-want-to-set', + '--resource-id', 'b666633d-9bb6-4e05-89c0-ee5a8752fb0b', + '--meter-name', 'cpu', + '--meter-type', 'cumulative', + '--meter-unit', 'ns', + '--sample-volume', '10086', + ] + base_shell.main(cli_args) + args, kwargs = mocked.call_args + self.assertEqual('the-project-id-i-want-to-set', + kwargs.get('project_id')) diff --git a/ceilometerclient/tests/unit/v2/test_statistics.py b/ceilometerclient/tests/unit/v2/test_statistics.py new file mode 100644 index 0000000..d2f7aee --- /dev/null +++ b/ceilometerclient/tests/unit/v2/test_statistics.py @@ -0,0 +1,224 @@ +# 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 ceilometerclient.openstack.common.apiclient import client +from ceilometerclient.openstack.common.apiclient import fake_client +from ceilometerclient.tests.unit import utils +import ceilometerclient.v2.statistics + +base_url = '/v2/meters/instance/statistics' +qry = ('q.field=resource_id&q.field=source&q.op=&q.op=' + '&q.type=&q.type=&q.value=foo&q.value=bar') +period = '&period=60' +groupby = '&groupby=resource_id' +aggregate_query = ("aggregate.func=cardinality&aggregate.param=resource_id" + "&aggregate.func=count") +samples = [ + {u'count': 135, + u'duration_start': u'2013-02-04T10:51:42', + u'min': 1.0, + u'max': 1.0, + u'duration_end': + u'2013-02-05T15:46:09', + u'duration': 1734.0, + u'avg': 1.0, + u'sum': 135.0}, +] +groupby_samples = [ + {u'count': 135, + u'duration_start': u'2013-02-04T10:51:42', + u'min': 1.0, + u'max': 1.0, + u'duration_end': + u'2013-02-05T15:46:09', + u'duration': 1734.0, + u'avg': 1.0, + u'sum': 135.0, + u'groupby': {u'resource_id': u'foo'} + }, + {u'count': 12, + u'duration_start': u'2013-02-04T10:51:42', + u'min': 1.0, + u'max': 1.0, + u'duration_end': + u'2013-02-05T15:46:09', + u'duration': 1734.0, + u'avg': 1.0, + u'sum': 12.0, + u'groupby': {u'resource_id': u'bar'} + }, +] +aggregate_samples = [ + {u'aggregate': {u'cardinality/resource_id': 4.0, u'count': 2.0}, + u'count': 2, + u'duration': 0.442451, + u'duration_end': u'2014-03-12T14:00:21.774154', + u'duration_start': u'2014-03-12T14:00:21.331703', + u'groupby': None, + u'period': 0, + u'period_end': u'2014-03-12T14:00:21.774154', + u'period_start': u'2014-03-12T14:00:21.331703', + u'unit': u'instance', + }, +] +fixtures = { + base_url: + { + 'GET': ( + {}, + samples + ), + }, + '%s?%s' % (base_url, qry): + { + 'GET': ( + {}, + samples + ), + }, + '%s?%s%s' % (base_url, qry, period): + { + 'GET': ( + {}, + samples + ), + }, + '%s?%s%s' % (base_url, qry, groupby): + { + 'GET': ( + {}, + groupby_samples + ), + }, + '%s?%s' % (base_url, aggregate_query): + { + 'GET': ( + {}, + aggregate_samples + ), + } +} + + +class StatisticsManagerTest(utils.BaseTestCase): + + def setUp(self): + super(StatisticsManagerTest, self).setUp() + self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) + self.api = client.BaseClient(self.http_client) + self.mgr = ceilometerclient.v2.statistics.StatisticsManager(self.api) + + def test_list_by_meter_name(self): + stats = list(self.mgr.list(meter_name='instance')) + expect = [ + 'GET', '/v2/meters/instance/statistics' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(stats), 1) + self.assertEqual(stats[0].count, 135) + + def test_list_by_meter_name_extended(self): + stats = list(self.mgr.list(meter_name='instance', + q=[ + {"field": "resource_id", + "value": "foo"}, + {"field": "source", + "value": "bar"}, + ])) + expect = [ + 'GET', '%s?%s' % (base_url, qry) + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(stats), 1) + self.assertEqual(stats[0].count, 135) + + def test_list_by_meter_name_with_period(self): + stats = list(self.mgr.list(meter_name='instance', + q=[ + {"field": "resource_id", + "value": "foo"}, + {"field": "source", + "value": "bar"}, + ], + period=60)) + expect = [ + 'GET', '%s?%s%s' % (base_url, qry, period) + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(stats), 1) + self.assertEqual(stats[0].count, 135) + + def test_list_by_meter_name_with_groupby(self): + stats = list(self.mgr.list(meter_name='instance', + q=[ + {"field": "resource_id", + "value": "foo"}, + {"field": "source", + "value": "bar"}, + ], + groupby=['resource_id'])) + expect = [ + 'GET', + '%s?%s%s' % (base_url, qry, groupby) + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(stats), 2) + self.assertEqual(stats[0].count, 135) + self.assertEqual(stats[1].count, 12) + self.assertEqual(stats[0].groupby.get('resource_id'), 'foo') + self.assertEqual(stats[1].groupby.get('resource_id'), 'bar') + + def test_list_by_meter_name_with_groupby_as_str(self): + stats = list(self.mgr.list(meter_name='instance', + q=[ + {"field": "resource_id", + "value": "foo"}, + {"field": "source", + "value": "bar"}, + ], + groupby='resource_id')) + expect = [ + 'GET', + '%s?%s%s' % (base_url, qry, groupby) + ] + self.http_client.assert_called(*expect) + self.assertEqual(2, len(stats)) + self.assertEqual(135, stats[0].count) + self.assertEqual(12, stats[1].count) + self.assertEqual('foo', stats[0].groupby.get('resource_id')) + self.assertEqual('bar', stats[1].groupby.get('resource_id')) + + def test_list_by_meter_name_with_aggregates(self): + aggregates = [ + { + 'func': 'count', + }, + { + 'func': 'cardinality', + 'param': 'resource_id', + }, + ] + stats = list(self.mgr.list(meter_name='instance', + aggregates=aggregates)) + expect = [ + 'GET', + '%s?%s' % (base_url, aggregate_query) + ] + self.http_client.assert_called(*expect) + self.assertEqual(1, len(stats)) + self.assertEqual(2, stats[0].count) + self.assertEqual(2.0, stats[0].aggregate.get('count')) + self.assertEqual(4.0, stats[0].aggregate.get( + 'cardinality/resource_id', + )) diff --git a/ceilometerclient/tests/unit/v2/test_trait_descriptions.py b/ceilometerclient/tests/unit/v2/test_trait_descriptions.py new file mode 100644 index 0000000..abe8288 --- /dev/null +++ b/ceilometerclient/tests/unit/v2/test_trait_descriptions.py @@ -0,0 +1,56 @@ +# 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. +from ceilometerclient.openstack.common.apiclient import client +from ceilometerclient.openstack.common.apiclient import fake_client +from ceilometerclient.tests.unit import utils +import ceilometerclient.v2.trait_descriptions + + +fixtures = { + '/v2/event_types/Foo/traits': { + 'GET': ( + {}, + [ + {'name': 'trait_1', 'type': 'string'}, + {'name': 'trait_2', 'type': 'integer'}, + {'name': 'trait_3', 'type': 'datetime'} + ] + ), + } +} + + +class TraitDescriptionManagerTest(utils.BaseTestCase): + + def setUp(self): + super(TraitDescriptionManagerTest, self).setUp() + self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) + self.api = client.BaseClient(self.http_client) + self.mgr = (ceilometerclient.v2.trait_descriptions. + TraitDescriptionManager(self.api)) + + def test_list(self): + trait_descriptions = list(self.mgr.list('Foo')) + expect = [ + 'GET', '/v2/event_types/Foo/traits' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(trait_descriptions), 3) + for i, vals in enumerate([('trait_1', 'string'), + ('trait_2', 'integer'), + ('trait_3', 'datetime')]): + + name, type = vals + self.assertEqual(trait_descriptions[i].name, name) + self.assertEqual(trait_descriptions[i].type, type) diff --git a/ceilometerclient/tests/unit/v2/test_traits.py b/ceilometerclient/tests/unit/v2/test_traits.py new file mode 100644 index 0000000..7b44a69 --- /dev/null +++ b/ceilometerclient/tests/unit/v2/test_traits.py @@ -0,0 +1,62 @@ +# 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. +from ceilometerclient.openstack.common.apiclient import client +from ceilometerclient.openstack.common.apiclient import fake_client +from ceilometerclient.tests.unit import utils +import ceilometerclient.v2.traits + + +fixtures = { + '/v2/event_types/Foo/traits/trait_1': { + 'GET': ( + {}, + [ + {'name': 'trait_1', + 'type': 'datetime', + 'value': '2014-01-07T17:22:10.925553'}, + {'name': 'trait_1', + 'type': 'datetime', + 'value': '2014-01-07T17:23:10.925553'} + ] + ), + } +} + + +class TraitManagerTest(utils.BaseTestCase): + + def setUp(self): + super(TraitManagerTest, self).setUp() + self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) + self.api = client.BaseClient(self.http_client) + self.mgr = ceilometerclient.v2.traits.TraitManager(self.api) + + def test_list(self): + traits = list(self.mgr.list('Foo', 'trait_1')) + expect = [ + 'GET', '/v2/event_types/Foo/traits/trait_1' + ] + self.http_client.assert_called(*expect) + self.assertEqual(len(traits), 2) + for i, vals in enumerate([('trait_1', + 'datetime', + '2014-01-07T17:22:10.925553'), + ('trait_1', + 'datetime', + '2014-01-07T17:23:10.925553')]): + + name, type, value = vals + self.assertEqual(traits[i].name, name) + self.assertEqual(traits[i].type, type) + self.assertEqual(traits[i].value, value) diff --git a/ceilometerclient/tests/utils.py b/ceilometerclient/tests/utils.py deleted file mode 100644 index 57bc276..0000000 --- a/ceilometerclient/tests/utils.py +++ /dev/null @@ -1,24 +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 fixtures -import testtools - - -class BaseTestCase(testtools.TestCase): - - def setUp(self): - super(BaseTestCase, self).setUp() - self.useFixture(fixtures.FakeLogger()) diff --git a/ceilometerclient/tests/v1/__init__.py b/ceilometerclient/tests/v1/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/ceilometerclient/tests/v1/test_meters.py b/ceilometerclient/tests/v1/test_meters.py deleted file mode 100644 index 1c883b7..0000000 --- a/ceilometerclient/tests/v1/test_meters.py +++ /dev/null @@ -1,162 +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 ceilometerclient.openstack.common.apiclient import client -from ceilometerclient.openstack.common.apiclient import fake_client -from ceilometerclient.tests import utils -import ceilometerclient.v1.meters - - -fixtures = { - '/v1/meters': { - 'GET': ( - {}, - {'meters': [ - { - 'resource_id': 'a', - 'project_id': 'dig_the_ditch', - 'user_id': 'freddy', - 'name': 'this', - 'type': 'counter', - }, - { - 'resource_id': 'b', - 'project_id': 'dig_the_ditch', - 'user_id': 'joey', - 'name': 'this', - 'type': 'counter', - }, - ]}, - ), - }, - '/v1/users/joey/meters': { - 'GET': ( - {}, - {'meters': [ - { - 'resource_id': 'b', - 'project_id': 'dig_the_ditch', - 'user_id': 'joey', - 'name': 'this', - 'type': 'counter', - }, - ]}, - ), - }, - '/v1/projects/dig_the_ditch/meters': { - 'GET': ( - {}, - {'meters': [ - { - 'resource_id': 'b', - 'project_id': 'dig_the_ditch', - 'user_id': 'joey', - 'name': 'this', - 'type': 'counter', - }, - ]}, - ), - }, - '/v1/sources/openstack/meters': { - 'GET': ( - {}, - {'meters': [ - { - 'resource_id': 'b', - 'project_id': 'dig_the_ditch', - 'user_id': 'joey', - 'name': 'this', - 'type': 'counter', - }, - { - 'resource_id': 'q', - 'project_id': 'dig_the_trench', - 'user_id': 'joey', - 'name': 'this', - 'type': 'counter', - }, - ]}, - ), - }, - '/v1/meters?metadata.zxc_id=foo': { - 'GET': ( - {}, - {'meters': [ - { - 'resource_id': 'b', - 'project_id': 'dig_the_ditch', - 'user_id': 'joey', - 'name': 'this', - 'type': 'counter', - }, - ]}, - ), - }, -} - - -class MeterManagerTest(utils.BaseTestCase): - - def setUp(self): - super(MeterManagerTest, self).setUp() - self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) - self.api = client.BaseClient(self.http_client) - self.mgr = ceilometerclient.v1.meters.MeterManager(self.api) - - def test_list_all(self): - resources = list(self.mgr.list()) - expect = [ - 'GET', '/v1/meters' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(resources), 2) - self.assertEqual(resources[0].resource_id, 'a') - self.assertEqual(resources[1].resource_id, 'b') - - def test_list_by_source(self): - resources = list(self.mgr.list(source='openstack')) - expect = [ - 'GET', '/v1/sources/openstack/meters' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(resources), 2) - self.assertEqual(resources[0].resource_id, 'b') - self.assertEqual(resources[1].resource_id, 'q') - - def test_list_by_user(self): - resources = list(self.mgr.list(user_id='joey')) - expect = [ - 'GET', '/v1/users/joey/meters' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(resources), 1) - self.assertEqual(resources[0].resource_id, 'b') - - def test_list_by_project(self): - resources = list(self.mgr.list(project_id='dig_the_ditch')) - expect = [ - 'GET', '/v1/projects/dig_the_ditch/meters' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(resources), 1) - self.assertEqual(resources[0].resource_id, 'b') - - def test_list_by_metaquery(self): - resources = list(self.mgr.list(metaquery='metadata.zxc_id=foo')) - expect = [ - 'GET', '/v1/meters?metadata.zxc_id=foo' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(resources), 1) - self.assertEqual(resources[0].resource_id, 'b') diff --git a/ceilometerclient/tests/v1/test_projects.py b/ceilometerclient/tests/v1/test_projects.py deleted file mode 100644 index 2f34a5c..0000000 --- a/ceilometerclient/tests/v1/test_projects.py +++ /dev/null @@ -1,65 +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 ceilometerclient.openstack.common.apiclient import client -from ceilometerclient.openstack.common.apiclient import fake_client -from ceilometerclient.tests import utils -import ceilometerclient.v1.meters - - -fixtures = { - '/v1/projects': { - 'GET': ( - {}, - {'projects': [ - 'a', - 'b', - ]}, - ), - }, - '/v1/sources/source_b/projects': { - 'GET': ( - {}, - {'projects': ['b']}, - ), - }, -} - - -class ProjectManagerTest(utils.BaseTestCase): - - def setUp(self): - super(ProjectManagerTest, self).setUp() - self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) - self.api = client.BaseClient(self.http_client) - self.mgr = ceilometerclient.v1.meters.ProjectManager(self.api) - - def test_list_all(self): - projects = list(self.mgr.list()) - expect = [ - 'GET', '/v1/projects' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(projects), 2) - self.assertEqual(projects[0].project_id, 'a') - self.assertEqual(projects[1].project_id, 'b') - - def test_list_by_source(self): - projects = list(self.mgr.list(source='source_b')) - expect = [ - 'GET', '/v1/sources/source_b/projects' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(projects), 1) - self.assertEqual(projects[0].project_id, 'b') diff --git a/ceilometerclient/tests/v1/test_resources.py b/ceilometerclient/tests/v1/test_resources.py deleted file mode 100644 index 4eac3fe..0000000 --- a/ceilometerclient/tests/v1/test_resources.py +++ /dev/null @@ -1,161 +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 ceilometerclient.openstack.common.apiclient import client -from ceilometerclient.openstack.common.apiclient import fake_client -from ceilometerclient.tests import utils -import ceilometerclient.v1.meters - - -fixtures = { - '/v1/resources': { - 'GET': ( - {}, - {'resources': [ - { - 'resource_id': 'a', - 'project_id': 'project_bla', - 'user_id': 'freddy', - 'timestamp': 'now', - 'meter': ['this', 'that'], - 'metadata': {'zxc_id': 'bla'}, - }, - { - 'resource_id': 'b', - 'project_id': 'dig_the_ditch', - 'user_id': 'joey', - 'timestamp': 'now', - 'meter': ['this', 'that'], - 'metadata': {'zxc_id': 'foo'}, - }, - ]}, - ), - }, - '/v1/users/joey/resources': { - 'GET': ( - {}, - {'resources': [ - { - 'resource_id': 'b', - 'project_id': 'dig_the_ditch', - 'user_id': 'joey', - 'timestamp': 'now', - 'meter': ['this', 'that'], - 'metadata': {'zxc_id': 'foo'}, - }, - ]}, - ), - }, - '/v1/resources?metadata.zxc_id=foo': { - 'GET': ( - {}, - {'resources': [ - { - 'resource_id': 'b', - 'project_id': 'dig_the_ditch', - 'user_id': 'joey', - 'timestamp': 'now', - 'meter': ['this', 'that'], - 'metadata': {'zxc_id': 'foo'}, - }, - ]}, - ), - }, - '/v1/projects/project_bla/resources': { - 'GET': ( - {}, - {'resources': [ - { - 'resource_id': 'a', - 'project_id': 'project_bla', - 'user_id': 'freddy', - 'timestamp': 'now', - 'meter': ['this', 'that'], - 'metadata': {'zxc_id': 'bla'}, - }, - ]}, - ), - }, - '/v1/resources?start_timestamp=now&end_timestamp=now': { - 'GET': ( - {}, - {'resources': [ - { - 'resource_id': 'b', - 'project_id': 'dig_the_ditch', - 'user_id': 'joey', - 'timestamp': 'now', - 'meter': ['this', 'that'], - 'metadata': {'zxc_id': 'foo'}, - }, - ]}, - ), - }, -} - - -class ResourceManagerTest(utils.BaseTestCase): - - def setUp(self): - super(ResourceManagerTest, self).setUp() - self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) - self.api = client.BaseClient(self.http_client) - self.mgr = ceilometerclient.v1.meters.ResourceManager(self.api) - - def test_list_all(self): - resources = list(self.mgr.list()) - expect = [ - 'GET', '/v1/resources' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(resources), 2) - self.assertEqual(resources[0].resource_id, 'a') - self.assertEqual(resources[1].resource_id, 'b') - - def test_list_by_user(self): - resources = list(self.mgr.list(user_id='joey')) - expect = [ - 'GET', '/v1/users/joey/resources' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(resources), 1) - self.assertEqual(resources[0].resource_id, 'b') - - def test_list_by_metaquery(self): - resources = list(self.mgr.list(metaquery='metadata.zxc_id=foo')) - expect = [ - 'GET', '/v1/resources?metadata.zxc_id=foo' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(resources), 1) - self.assertEqual(resources[0].resource_id, 'b') - - def test_list_by_project(self): - resources = list(self.mgr.list(project_id='project_bla')) - expect = [ - 'GET', '/v1/projects/project_bla/resources' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(resources), 1) - self.assertEqual(resources[0].resource_id, 'a') - - def test_list_by_timestamp(self): - resources = list(self.mgr.list(start_timestamp='now', - end_timestamp='now')) - expect = [ - 'GET', '/v1/resources?start_timestamp=now&end_timestamp=now' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(resources), 1) - self.assertEqual(resources[0].resource_id, 'b') diff --git a/ceilometerclient/tests/v1/test_samples.py b/ceilometerclient/tests/v1/test_samples.py deleted file mode 100644 index 61f064e..0000000 --- a/ceilometerclient/tests/v1/test_samples.py +++ /dev/null @@ -1,196 +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 ceilometerclient.openstack.common.apiclient import client -from ceilometerclient.openstack.common.apiclient import fake_client -from ceilometerclient.tests import utils -import ceilometerclient.v1.meters - - -fixtures = { - '/v1/users/freddy/meters/balls': { - 'GET': ( - {}, - {'events': [ - { - 'resource_id': 'inst-0045', - 'project_id': 'melbourne_open', - 'user_id': 'freddy', - 'name': 'tennis', - 'type': 'counter', - 'unit': 'balls', - 'volume': 3, - 'timestamp': None, - 'resource_metadata': None, - }, - ]}, - ), - }, - '/v1/sources/openstack/meters/this': { - 'GET': ( - {}, - {'events': [ - { - 'resource_id': 'b', - 'project_id': 'dig_the_ditch', - 'user_id': 'joey', - 'name': 'this', - 'type': 'counter', - 'unit': 'b', - 'volume': 45, - 'timestamp': None, - 'resource_metadata': None, - }, - ]}, - ), - }, - '/v1/projects/dig_the_ditch/meters/meters': { - 'GET': ( - {}, - {'events': [ - { - 'resource_id': 'b', - 'project_id': 'dig_the_ditch', - 'user_id': 'joey', - 'name': 'meters', - 'type': 'counter', - 'unit': 'meters', - 'volume': 345, - 'timestamp': None, - 'resource_metadata': None, - }, - ]}, - ), - }, - '/v1/meters?metadata.zxc_id=foo': { - 'GET': ( - {}, - {'events': [ - { - 'resource_id': 'b', - 'project_id': 'dig_the_ditch', - 'user_id': 'joey', - 'name': 'this', - 'type': 'counter', - 'unit': 'meters', - 'volume': 98, - 'timestamp': None, - 'resource_metadata': {'zxc_id': 'foo'}, - }, - ]}, - ), - }, - '/v1/users/freddy/meters/balls?start_timestamp=now&end_timestamp=now': { - 'GET': ( - {}, - {'events': [ - { - 'resource_id': 'inst-0045', - 'project_id': 'melbourne_open', - 'user_id': 'freddy', - 'name': 'tennis', - 'type': 'counter', - 'unit': 'balls', - 'volume': 3, - 'timestamp': 'now', - 'resource_metadata': None, - }, - - ]}, - ), - }, - '/v1/meters': { - 'GET': ( - {}, - {'meters': []}, - ), - }, -} - - -class SampleManagerTest(utils.BaseTestCase): - - def setUp(self): - super(SampleManagerTest, self).setUp() - self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) - self.api = client.BaseClient(self.http_client) - self.mgr = ceilometerclient.v1.meters.SampleManager(self.api) - - def test_list_all(self): - samples = list(self.mgr.list(counter_name=None)) - expect = [ - 'GET', '/v1/meters' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(samples), 0) - - def test_list_by_source(self): - samples = list(self.mgr.list(source='openstack', - counter_name='this')) - expect = [ - 'GET', '/v1/sources/openstack/meters/this' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(samples), 1) - self.assertEqual(samples[0].resource_id, 'b') - - def test_list_by_user(self): - samples = list(self.mgr.list(user_id='freddy', - counter_name='balls')) - expect = [ - 'GET', '/v1/users/freddy/meters/balls' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(samples), 1) - self.assertEqual(samples[0].project_id, 'melbourne_open') - self.assertEqual(samples[0].user_id, 'freddy') - self.assertEqual(samples[0].volume, 3) - - def test_list_by_project(self): - samples = list(self.mgr.list(project_id='dig_the_ditch', - counter_name='meters')) - expect = [ - 'GET', '/v1/projects/dig_the_ditch/meters/meters' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(samples), 1) - self.assertEqual(samples[0].project_id, 'dig_the_ditch') - self.assertEqual(samples[0].volume, 345) - self.assertEqual(samples[0].unit, 'meters') - - def test_list_by_metaquery(self): - samples = list(self.mgr.list(metaquery='metadata.zxc_id=foo', - counter_name='this')) - expect = [ - 'GET', '/v1/meters?metadata.zxc_id=foo' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(samples), 1) - self.assertEqual(samples[0].resource_metadata['zxc_id'], 'foo') - - def test_list_by_timestamp(self): - samples = list(self.mgr.list(user_id='freddy', - counter_name='balls', - start_timestamp='now', - end_timestamp='now')) - expect = [ - 'GET', - '/v1/users/freddy/meters/balls?' + - 'start_timestamp=now&end_timestamp=now' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(samples), 1) - self.assertEqual(samples[0].project_id, 'melbourne_open') - self.assertEqual(samples[0].user_id, 'freddy') - self.assertEqual(samples[0].volume, 3) diff --git a/ceilometerclient/tests/v1/test_users.py b/ceilometerclient/tests/v1/test_users.py deleted file mode 100644 index 541139b..0000000 --- a/ceilometerclient/tests/v1/test_users.py +++ /dev/null @@ -1,65 +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 ceilometerclient.openstack.common.apiclient import client -from ceilometerclient.openstack.common.apiclient import fake_client -from ceilometerclient.tests import utils -import ceilometerclient.v1.meters - - -fixtures = { - '/v1/users': { - 'GET': ( - {}, - {'users': [ - 'a', - 'b', - ]}, - ), - }, - '/v1/sources/source_b/users': { - 'GET': ( - {}, - {'users': ['b']}, - ), - }, -} - - -class UserManagerTest(utils.BaseTestCase): - - def setUp(self): - super(UserManagerTest, self).setUp() - self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) - self.api = client.BaseClient(self.http_client) - self.mgr = ceilometerclient.v1.meters.UserManager(self.api) - - def test_list_all(self): - users = list(self.mgr.list()) - expect = [ - 'GET', '/v1/users' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(users), 2) - self.assertEqual(users[0].user_id, 'a') - self.assertEqual(users[1].user_id, 'b') - - def test_list_by_source(self): - users = list(self.mgr.list(source='source_b')) - expect = [ - 'GET', '/v1/sources/source_b/users' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(users), 1) - self.assertEqual(users[0].user_id, 'b') diff --git a/ceilometerclient/tests/v2/__init__.py b/ceilometerclient/tests/v2/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/ceilometerclient/tests/v2/test_alarms.py b/ceilometerclient/tests/v2/test_alarms.py deleted file mode 100644 index 4239d2f..0000000 --- a/ceilometerclient/tests/v2/test_alarms.py +++ /dev/null @@ -1,540 +0,0 @@ -# -# Copyright 2013 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 copy - -import six -from six.moves import xrange # noqa -import testtools - -from ceilometerclient import exc -from ceilometerclient.openstack.common.apiclient import client -from ceilometerclient.openstack.common.apiclient import fake_client -from ceilometerclient.v2 import alarms - -AN_ALARM = {u'alarm_actions': [u'http://site:8000/alarm'], - u'ok_actions': [u'http://site:8000/ok'], - u'description': u'An alarm', - u'type': u'threshold', - u'severity': 'low', - u'threshold_rule': { - u'meter_name': u'storage.objects', - u'query': [{u'field': u'key_name', - u'op': u'eq', - u'value': u'key_value'}], - u'evaluation_periods': 2, - u'period': 240.0, - u'statistic': u'avg', - u'threshold': 200.0, - u'comparison_operator': 'gt'}, - u'time_constraints': [ - { - u'name': u'cons1', - u'description': u'desc1', - u'start': u'0 11 * * *', - u'duration': 300, - u'timezone': u''}, - { - u'name': u'cons2', - u'description': u'desc2', - u'start': u'0 23 * * *', - u'duration': 600, - u'timezone': ''}], - u'timestamp': u'2013-05-09T13:41:23.085000', - u'enabled': True, - u'alarm_id': u'alarm-id', - u'state': u'ok', - u'insufficient_data_actions': [u'http://site:8000/nodata'], - u'user_id': u'user-id', - u'project_id': u'project-id', - u'state_timestamp': u'2013-05-09T13:41:23.085000', - u'repeat_actions': False, - u'name': 'SwiftObjectAlarm'} -CREATE_ALARM = copy.deepcopy(AN_ALARM) -del CREATE_ALARM['timestamp'] -del CREATE_ALARM['state_timestamp'] -del CREATE_ALARM['alarm_id'] -CREATE_ALARM_WITHOUT_TC = copy.deepcopy(CREATE_ALARM) -del CREATE_ALARM_WITHOUT_TC['time_constraints'] -DELTA_ALARM = {u'alarm_actions': ['url1', 'url2']} -DELTA_ALARM_RULE = {u'comparison_operator': u'lt', - u'threshold': 42.1, - u'meter_name': u'foobar', - u'query': [{u'field': u'key_name', - u'op': u'eq', - u'value': u'key_value'}]} -DELTA_ALARM_TC = [{u'name': u'cons1', - u'duration': 500}] -DELTA_ALARM['time_constraints'] = DELTA_ALARM_TC -UPDATED_ALARM = copy.deepcopy(AN_ALARM) -UPDATED_ALARM.update(DELTA_ALARM) -UPDATED_ALARM['threshold_rule'].update(DELTA_ALARM_RULE) -DELTA_ALARM['remove_time_constraints'] = 'cons2' -UPDATED_ALARM['time_constraints'] = [{u'name': u'cons1', - u'description': u'desc1', - u'start': u'0 11 * * *', - u'duration': 500, - u'timezone': u''}] -DELTA_ALARM['threshold_rule'] = DELTA_ALARM_RULE -UPDATE_ALARM = copy.deepcopy(UPDATED_ALARM) -UPDATE_ALARM['remove_time_constraints'] = 'cons2' -del UPDATE_ALARM['user_id'] -del UPDATE_ALARM['project_id'] -del UPDATE_ALARM['name'] -del UPDATE_ALARM['alarm_id'] -del UPDATE_ALARM['timestamp'] -del UPDATE_ALARM['state_timestamp'] - -AN_LEGACY_ALARM = {u'alarm_actions': [u'http://site:8000/alarm'], - u'ok_actions': [u'http://site:8000/ok'], - u'description': u'An alarm', - u'matching_metadata': {u'key_name': u'key_value'}, - u'evaluation_periods': 2, - u'timestamp': u'2013-05-09T13:41:23.085000', - u'enabled': True, - u'meter_name': u'storage.objects', - u'period': 240.0, - u'alarm_id': u'alarm-id', - u'state': u'ok', - u'severity': u'low', - u'insufficient_data_actions': [u'http://site:8000/nodata'], - u'statistic': u'avg', - u'threshold': 200.0, - u'user_id': u'user-id', - u'project_id': u'project-id', - u'state_timestamp': u'2013-05-09T13:41:23.085000', - u'comparison_operator': 'gt', - u'repeat_actions': False, - u'name': 'SwiftObjectAlarm'} -CREATE_LEGACY_ALARM = copy.deepcopy(AN_LEGACY_ALARM) -del CREATE_LEGACY_ALARM['timestamp'] -del CREATE_LEGACY_ALARM['state_timestamp'] -del CREATE_LEGACY_ALARM['alarm_id'] -DELTA_LEGACY_ALARM = {u'alarm_actions': ['url1', 'url2'], - u'comparison_operator': u'lt', - u'meter_name': u'foobar', - u'threshold': 42.1} -DELTA_LEGACY_ALARM['time_constraints'] = [{u'name': u'cons1', - u'duration': 500}] -DELTA_LEGACY_ALARM['remove_time_constraints'] = 'cons2' -UPDATED_LEGACY_ALARM = copy.deepcopy(AN_LEGACY_ALARM) -UPDATED_LEGACY_ALARM.update(DELTA_LEGACY_ALARM) -UPDATE_LEGACY_ALARM = copy.deepcopy(UPDATED_LEGACY_ALARM) -del UPDATE_LEGACY_ALARM['user_id'] -del UPDATE_LEGACY_ALARM['project_id'] -del UPDATE_LEGACY_ALARM['name'] -del UPDATE_LEGACY_ALARM['alarm_id'] -del UPDATE_LEGACY_ALARM['timestamp'] -del UPDATE_LEGACY_ALARM['state_timestamp'] - -FULL_DETAIL = ('{"alarm_actions": [], ' - '"user_id": "8185aa72421a4fd396d4122cba50e1b5", ' - '"name": "scombo", ' - '"timestamp": "2013-10-03T08:58:33.647912", ' - '"enabled": true, ' - '"state_timestamp": "2013-10-03T08:58:33.647912", ' - '"rule": {"operator": "or", "alarm_ids": ' - '["062cc907-3a9f-4867-ab3b-fa83212b39f7"]}, ' - '"alarm_id": "alarm-id, ' - '"state": "insufficient data", ' - '"insufficient_data_actions": [], ' - '"repeat_actions": false, ' - '"ok_actions": [], ' - '"project_id": "57d04f24d0824b78b1ea9bcecedbda8f", ' - '"type": "combination", ' - '"description": "Combined state of alarms ' - '062cc907-3a9f-4867-ab3b-fa83212b39f7"}') -ALARM_HISTORY = [{'on_behalf_of': '57d04f24d0824b78b1ea9bcecedbda8f', - 'user_id': '8185aa72421a4fd396d4122cba50e1b5', - 'event_id': 'c74a8611-6553-4764-a860-c15a6aabb5d0', - 'timestamp': '2013-10-03T08:59:28.326000', - 'detail': '{"state": "alarm"}', - 'alarm_id': 'alarm-id', - 'project_id': '57d04f24d0824b78b1ea9bcecedbda8f', - 'type': 'state transition'}, - {'on_behalf_of': '57d04f24d0824b78b1ea9bcecedbda8f', - 'user_id': '8185aa72421a4fd396d4122cba50e1b5', - 'event_id': 'c74a8611-6553-4764-a860-c15a6aabb5d0', - 'timestamp': '2013-10-03T08:59:28.326000', - 'detail': '{"description": "combination of one"}', - 'alarm_id': 'alarm-id', - 'project_id': '57d04f24d0824b78b1ea9bcecedbda8f', - 'type': 'rule change'}, - {'on_behalf_of': '57d04f24d0824b78b1ea9bcecedbda8f', - 'user_id': '8185aa72421a4fd396d4122cba50e1b5', - 'event_id': '4fd7df9e-190d-4471-8884-dc5a33d5d4bb', - 'timestamp': '2013-10-03T08:58:33.647000', - 'detail': FULL_DETAIL, - 'alarm_id': 'alarm-id', - 'project_id': '57d04f24d0824b78b1ea9bcecedbda8f', - 'type': 'creation'}] - -fixtures = { - '/v2/alarms': - { - 'GET': ( - {}, - [AN_ALARM], - ), - 'POST': ( - {}, - CREATE_ALARM, - ), - }, - '/v2/alarms/alarm-id': - { - 'GET': ( - {}, - AN_ALARM, - ), - 'PUT': ( - {}, - UPDATED_ALARM, - ), - 'DELETE': ( - {}, - None, - ), - }, - '/v2/alarms/unk-alarm-id': - { - 'GET': ( - {}, - None, - ), - 'PUT': ( - {}, - None, - ), - }, - '/v2/alarms/alarm-id/state': - { - 'PUT': ( - {}, - {'alarm': 'alarm'} - ), - 'GET': ( - {}, - {'alarm': 'alarm'} - ), - - }, - '/v2/alarms?q.field=project_id&q.field=name&q.op=&q.op=' - '&q.type=&q.type=&q.value=project-id&q.value=SwiftObjectAlarm': - { - 'GET': ( - {}, - [AN_ALARM], - ), - }, - '/v2/alarms/victim-id': - { - 'DELETE': ( - {}, - None, - ), - }, - '/v2/alarms/alarm-id/history': - { - 'GET': ( - {}, - ALARM_HISTORY, - ), - }, - '/v2/alarms/alarm-id/history?q.field=timestamp&q.op=&q.type=&q.value=NOW': - { - 'GET': ( - {}, - ALARM_HISTORY, - ), - }, -} - - -class AlarmManagerTest(testtools.TestCase): - - def setUp(self): - super(AlarmManagerTest, self).setUp() - self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) - self.api = client.BaseClient(self.http_client) - self.mgr = alarms.AlarmManager(self.api) - - def test_list_all(self): - alarms = list(self.mgr.list()) - expect = [ - 'GET', '/v2/alarms' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(alarms), 1) - self.assertEqual(alarms[0].alarm_id, 'alarm-id') - - def test_list_with_query(self): - alarms = list(self.mgr.list(q=[{"field": "project_id", - "value": "project-id"}, - {"field": "name", - "value": "SwiftObjectAlarm"}])) - expect = [ - 'GET', - '/v2/alarms?q.field=project_id&q.field=name&q.op=&q.op=' - '&q.type=&q.type=&q.value=project-id&q.value=SwiftObjectAlarm', - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(alarms), 1) - self.assertEqual(alarms[0].alarm_id, 'alarm-id') - - def test_get(self): - alarm = self.mgr.get(alarm_id='alarm-id') - expect = [ - 'GET', '/v2/alarms/alarm-id' - ] - self.http_client.assert_called(*expect) - self.assertIsNotNone(alarm) - self.assertEqual(alarm.alarm_id, 'alarm-id') - self.assertEqual(alarm.rule, alarm.threshold_rule) - - def test_create(self): - alarm = self.mgr.create(**CREATE_ALARM) - expect = [ - 'POST', '/v2/alarms' - ] - self.http_client.assert_called(*expect, body=CREATE_ALARM) - self.assertIsNotNone(alarm) - - def test_update(self): - alarm = self.mgr.update(alarm_id='alarm-id', **UPDATE_ALARM) - expect_get = [ - 'GET', '/v2/alarms/alarm-id' - ] - expect_put = [ - 'PUT', '/v2/alarms/alarm-id', UPDATED_ALARM - ] - self.http_client.assert_called(*expect_get, pos=0) - self.http_client.assert_called(*expect_put, pos=1) - self.assertIsNotNone(alarm) - self.assertEqual(alarm.alarm_id, 'alarm-id') - for (key, value) in six.iteritems(UPDATED_ALARM): - self.assertEqual(getattr(alarm, key), value) - - def test_update_delta(self): - alarm = self.mgr.update(alarm_id='alarm-id', **DELTA_ALARM) - expect_get = [ - 'GET', '/v2/alarms/alarm-id' - ] - expect_put = [ - 'PUT', '/v2/alarms/alarm-id', UPDATED_ALARM - ] - self.http_client.assert_called(*expect_get, pos=0) - self.http_client.assert_called(*expect_put, pos=1) - self.assertIsNotNone(alarm) - self.assertEqual(alarm.alarm_id, 'alarm-id') - for (key, value) in six.iteritems(UPDATED_ALARM): - self.assertEqual(getattr(alarm, key), value) - - def test_set_state(self): - state = self.mgr.set_state(alarm_id='alarm-id', state='alarm') - expect = [ - 'PUT', '/v2/alarms/alarm-id/state' - ] - self.http_client.assert_called(*expect, body='alarm') - self.assertEqual(state, {'alarm': 'alarm'}) - - def test_get_state(self): - state = self.mgr.get_state(alarm_id='alarm-id') - expect = [ - 'GET', '/v2/alarms/alarm-id/state' - ] - self.http_client.assert_called(*expect) - self.assertEqual(state, {'alarm': 'alarm'}) - - def test_delete(self): - deleted = self.mgr.delete(alarm_id='victim-id') - expect = [ - 'DELETE', '/v2/alarms/victim-id' - ] - self.http_client.assert_called(*expect) - self.assertIsNone(deleted) - - def test_get_from_alarm_class(self): - alarm = self.mgr.get(alarm_id='alarm-id') - self.assertIsNotNone(alarm) - alarm.get() - expect = [ - 'GET', '/v2/alarms/alarm-id' - ] - self.http_client.assert_called(*expect, pos=0) - self.http_client.assert_called(*expect, pos=1) - self.assertEqual('alarm-id', alarm.alarm_id) - self.assertEqual(alarm.threshold_rule, alarm.rule) - - def test_get_state_from_alarm_class(self): - alarm = self.mgr.get(alarm_id='alarm-id') - self.assertIsNotNone(alarm) - state = alarm.get_state() - expect_get_1 = [ - 'GET', '/v2/alarms/alarm-id' - ] - expect_get_2 = [ - 'GET', '/v2/alarms/alarm-id/state' - ] - self.http_client.assert_called(*expect_get_1, pos=0) - self.http_client.assert_called(*expect_get_2, pos=1) - self.assertEqual('alarm', state) - - def test_update_missing(self): - alarm = None - try: - alarm = self.mgr.update(alarm_id='unk-alarm-id', **UPDATE_ALARM) - except exc.CommandError: - pass - self.assertEqual(alarm, None) - - def test_delete_from_alarm_class(self): - alarm = self.mgr.get(alarm_id='alarm-id') - self.assertIsNotNone(alarm) - deleted = alarm.delete() - expect_get = [ - 'GET', '/v2/alarms/alarm-id' - ] - expect_delete = [ - 'DELETE', '/v2/alarms/alarm-id' - ] - self.http_client.assert_called(*expect_get, pos=0) - self.http_client.assert_called(*expect_delete, pos=1) - self.assertIsNone(deleted) - - def _do_test_get_history(self, q, url): - history = self.mgr.get_history(q=q, alarm_id='alarm-id') - expect = ['GET', url] - self.http_client.assert_called(*expect) - for i in xrange(len(history)): - change = history[i] - self.assertIsInstance(change, alarms.AlarmChange) - for k, v in six.iteritems(ALARM_HISTORY[i]): - self.assertEqual(getattr(change, k), v) - - def test_get_all_history(self): - url = '/v2/alarms/alarm-id/history' - self._do_test_get_history(None, url) - - def test_get_constrained_history(self): - q = [dict(field='timestamp', value='NOW')] - url = ('/v2/alarms/alarm-id/history?q.field=timestamp' - '&q.op=&q.type=&q.value=NOW') - self._do_test_get_history(q, url) - - -class AlarmLegacyManagerTest(testtools.TestCase): - - def setUp(self): - super(AlarmLegacyManagerTest, self).setUp() - self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) - self.api = client.BaseClient(self.http_client) - self.mgr = alarms.AlarmManager(self.api) - - def test_create(self): - alarm = self.mgr.create(**CREATE_LEGACY_ALARM) - expect = [ - 'POST', '/v2/alarms', CREATE_ALARM_WITHOUT_TC, - ] - self.http_client.assert_called(*expect) - self.assertIsNotNone(alarm) - - def test_create_counter_name(self): - create = {} - create.update(CREATE_LEGACY_ALARM) - create['counter_name'] = CREATE_LEGACY_ALARM['meter_name'] - del create['meter_name'] - alarm = self.mgr.create(**create) - expect = [ - 'POST', '/v2/alarms', CREATE_ALARM_WITHOUT_TC, - ] - self.http_client.assert_called(*expect) - self.assertIsNotNone(alarm) - - def test_update(self): - alarm = self.mgr.update(alarm_id='alarm-id', **DELTA_LEGACY_ALARM) - expect_put = [ - 'PUT', '/v2/alarms/alarm-id', UPDATED_ALARM - ] - self.http_client.assert_called(*expect_put) - self.assertIsNotNone(alarm) - self.assertEqual(alarm.alarm_id, 'alarm-id') - for (key, value) in six.iteritems(UPDATED_ALARM): - self.assertEqual(getattr(alarm, key), value) - - def test_update_counter_name(self): - updated = {} - updated.update(UPDATE_LEGACY_ALARM) - updated['counter_name'] = UPDATED_LEGACY_ALARM['meter_name'] - del updated['meter_name'] - alarm = self.mgr.update(alarm_id='alarm-id', **updated) - expect_put = [ - 'PUT', '/v2/alarms/alarm-id', UPDATED_ALARM - ] - self.http_client.assert_called(*expect_put) - self.assertIsNotNone(alarm) - self.assertEqual(alarm.alarm_id, 'alarm-id') - for (key, value) in six.iteritems(UPDATED_ALARM): - self.assertEqual(getattr(alarm, key), value) - - -class AlarmTimeConstraintTest(testtools.TestCase): - - def setUp(self): - super(AlarmTimeConstraintTest, self).setUp() - self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) - self.api = client.BaseClient(self.http_client) - self.mgr = alarms.AlarmManager(self.api) - - def test_add_new(self): - new_constraint = dict(name='cons3', - start='0 0 * * *', - duration=500) - kwargs = dict(time_constraints=[new_constraint]) - self.mgr.update(alarm_id='alarm-id', **kwargs) - body = copy.deepcopy(AN_ALARM) - body[u'time_constraints'] = \ - AN_ALARM[u'time_constraints'] + [new_constraint] - expect = [ - 'PUT', '/v2/alarms/alarm-id', body - ] - self.http_client.assert_called(*expect) - - def test_update_existing(self): - updated_constraint = dict(name='cons2', - duration=500) - kwargs = dict(time_constraints=[updated_constraint]) - self.mgr.update(alarm_id='alarm-id', **kwargs) - body = copy.deepcopy(AN_ALARM) - body[u'time_constraints'][1] = dict(name='cons2', - description='desc2', - start='0 23 * * *', - duration=500, - timezone='') - - expect = [ - 'PUT', '/v2/alarms/alarm-id', body - ] - self.http_client.assert_called(*expect) - - def test_remove(self): - kwargs = dict(remove_time_constraints=['cons2']) - self.mgr.update(alarm_id='alarm-id', **kwargs) - body = copy.deepcopy(AN_ALARM) - body[u'time_constraints'] = AN_ALARM[u'time_constraints'][:1] - expect = [ - 'PUT', '/v2/alarms/alarm-id', body - ] - self.http_client.assert_called(*expect) diff --git a/ceilometerclient/tests/v2/test_event_types.py b/ceilometerclient/tests/v2/test_event_types.py deleted file mode 100644 index 8d5e4a0..0000000 --- a/ceilometerclient/tests/v2/test_event_types.py +++ /dev/null @@ -1,50 +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. - - -from ceilometerclient.openstack.common.apiclient import client -from ceilometerclient.openstack.common.apiclient import fake_client -from ceilometerclient.tests import utils -import ceilometerclient.v2.event_types - - -fixtures = { - '/v2/event_types/': { - 'GET': ( - {}, - ['Foo', 'Bar', 'Sna', 'Fu'] - ), - } -} - - -class EventTypesManagerTest(utils.BaseTestCase): - - def setUp(self): - super(EventTypesManagerTest, self).setUp() - self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) - self.api = client.BaseClient(self.http_client) - self.mgr = ceilometerclient.v2.event_types.EventTypeManager(self.api) - - def test_list(self): - event_types = list(self.mgr.list()) - expect = [ - 'GET', '/v2/event_types/' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(event_types), 4) - self.assertEqual(event_types[0].event_type, "Foo") - self.assertEqual(event_types[1].event_type, "Bar") - self.assertEqual(event_types[2].event_type, "Sna") - self.assertEqual(event_types[3].event_type, "Fu") diff --git a/ceilometerclient/tests/v2/test_events.py b/ceilometerclient/tests/v2/test_events.py deleted file mode 100644 index 6b1e74b..0000000 --- a/ceilometerclient/tests/v2/test_events.py +++ /dev/null @@ -1,198 +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. -from ceilometerclient.openstack.common.apiclient import client -from ceilometerclient.openstack.common.apiclient import fake_client -from ceilometerclient.tests import utils -import ceilometerclient.v2.events - - -fixtures = { - '/v2/events': { - 'GET': ( - {}, - [ - { - 'message_id': '1', - 'event_type': 'Foo', - 'generated': '1970-01-01T00:00:00', - 'traits': {'trait_A': 'abc'}, - }, - { - 'message_id': '2', - 'event_type': 'Foo', - 'generated': '1970-01-01T00:00:00', - 'traits': {'trait_A': 'def'}, - }, - { - 'message_id': '3', - 'event_type': 'Bar', - 'generated': '1970-01-01T00:00:00', - 'traits': {'trait_B': 'bartrait'}, - }, - ] - ), - }, - '/v2/events?q.field=hostname&q.op=&q.type=string&q.value=localhost': - { - 'GET': ( - {}, - [ - { - 'message_id': '1', - 'event_type': 'Foo', - 'generated': '1970-01-01T00:00:00', - 'traits': {'trait_A': 'abc', - 'hostname': 'localhost'}, - }, - { - 'message_id': '2', - 'event_type': 'Foo', - 'generated': '1970-01-01T00:00:00', - 'traits': {'trait_A': 'def', - 'hostname': 'localhost'}, - } - ] - ), - }, - '/v2/events?q.field=hostname&q.op=&q.type=&q.value=foreignhost': - { - 'GET': ( - {}, - [ - { - 'message_id': '1', - 'event_type': 'Foo', - 'generated': '1970-01-01T00:00:00', - 'traits': {'trait_A': 'abc', - 'hostname': 'foreignhost'}, - }, - { - 'message_id': '2', - 'event_type': 'Foo', - 'generated': '1970-01-01T00:00:00', - 'traits': {'trait_A': 'def', - 'hostname': 'foreignhost'}, - } - ] - ), - }, - '/v2/events?q.field=hostname&q.field=num_cpus&q.op=&q.op=' - '&q.type=&q.type=integer&q.value=localhost&q.value=5': - { - 'GET': ( - {}, - [ - { - 'message_id': '1', - 'event_type': 'Bar', - 'generated': '1970-01-01T00:00:00', - 'traits': {'trait_A': 'abc', - 'hostname': 'localhost', - 'num_cpus': '5'}, - }, - ] - ), - }, - - '/v2/events/2': - { - 'GET': ( - {}, - { - 'message_id': '2', - 'event_type': 'Foo', - 'generated': '1970-01-01T00:00:00', - 'traits': {'trait_A': 'def', - 'intTrait': '42'}, - } - ), - }, -} - - -class EventManagerTest(utils.BaseTestCase): - - def setUp(self): - super(EventManagerTest, self).setUp() - self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) - self.api = client.BaseClient(self.http_client) - self.mgr = ceilometerclient.v2.events.EventManager(self.api) - - def test_list_all(self): - events = list(self.mgr.list()) - expect = [ - 'GET', '/v2/events' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(events), 3) - self.assertEqual(events[0].event_type, 'Foo') - self.assertEqual(events[1].event_type, 'Foo') - self.assertEqual(events[2].event_type, 'Bar') - - def test_list_one(self): - event = self.mgr.get(2) - expect = [ - 'GET', '/v2/events/2' - ] - self.http_client.assert_called(*expect) - self.assertIsNotNone(event) - self.assertEqual(event.event_type, 'Foo') - - def test_list_with_query(self): - events = list(self.mgr.list(q=[{"field": "hostname", - "value": "localhost", - "type": "string"}])) - expect = [ - 'GET', '/v2/events?q.field=hostname&q.op=&q.type=string' - '&q.value=localhost' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(events), 2) - self.assertEqual(events[0].event_type, 'Foo') - - def test_list_with_query_no_type(self): - events = list(self.mgr.list(q=[{"field": "hostname", - "value": "foreignhost"}])) - expect = [ - 'GET', '/v2/events?q.field=hostname&q.op=' - '&q.type=&q.value=foreignhost' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(events), 2) - self.assertEqual(events[0].event_type, 'Foo') - - def test_list_with_multiple_filters(self): - events = list(self.mgr.list(q=[{"field": "hostname", - "value": "localhost"}, - {"field": "num_cpus", - "value": "5", - "type": "integer"}])) - - expect = [ - 'GET', '/v2/events?q.field=hostname&q.field=num_cpus&q.op=&q.op=' - '&q.type=&q.type=integer&q.value=localhost&q.value=5' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(events), 1) - - def test_get_from_event_class(self): - event = self.mgr.get(2) - self.assertIsNotNone(event) - event.get() - expect = [ - 'GET', '/v2/events/2' - ] - self.http_client.assert_called(*expect, pos=0) - self.http_client.assert_called(*expect, pos=1) - self.assertEqual('Foo', event.event_type) diff --git a/ceilometerclient/tests/v2/test_options.py b/ceilometerclient/tests/v2/test_options.py deleted file mode 100644 index 6318d5c..0000000 --- a/ceilometerclient/tests/v2/test_options.py +++ /dev/null @@ -1,239 +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 ceilometerclient.tests import utils -from ceilometerclient.v2 import options - - -class BuildUrlTest(utils.BaseTestCase): - - def test_one(self): - url = options.build_url('/', [{'field': 'this', - 'op': 'gt', - 'value': 43}]) - self.assertEqual(url, '/?q.field=this&q.op=gt&q.type=&q.value=43') - - def test_two(self): - url = options.build_url('/', [{'field': 'this', - 'op': 'gt', - 'value': 43}, - {'field': 'that', - 'op': 'lt', - 'value': 88}]) - ops = 'q.op=gt&q.op=lt' - vals = 'q.value=43&q.value=88' - types = 'q.type=&q.type=' - fields = 'q.field=this&q.field=that' - self.assertEqual(url, '/?%s&%s&%s&%s' % (fields, ops, types, vals)) - - def test_default_op(self): - url = options.build_url('/', [{'field': 'this', - 'value': 43}]) - self.assertEqual(url, '/?q.field=this&q.op=&q.type=&q.value=43') - - def test_one_param(self): - url = options.build_url('/', None, ['period=60']) - self.assertEqual(url, '/?period=60') - - def test_two_params(self): - url = options.build_url('/', None, ['period=60', - 'others=value']) - self.assertEqual(url, '/?period=60&others=value') - - def test_with_data_type(self): - url = options.build_url('/', [{'field': 'f1', - 'value': '10', - 'type': 'integer'}]) - - self.assertEqual('/?q.field=f1&q.op=&q.type=integer&q.value=10', url) - - -class CliTest(utils.BaseTestCase): - - def test_one(self): - ar = options.cli_to_array('this<=34') - self.assertEqual(ar, [{'field': 'this', 'op': 'le', - 'value': '34', 'type': ''}]) - - def test_two(self): - ar = options.cli_to_array('this<=34;that!=foo') - self.assertEqual(ar, [{'field': 'this', 'op': 'le', - 'value': '34', 'type': ''}, - {'field': 'that', 'op': 'ne', - 'value': 'foo', 'type': ''}]) - - def test_negative(self): - ar = options.cli_to_array('this>=-783') - self.assertEqual(ar, [{'field': 'this', 'op': 'ge', - 'value': '-783', 'type': ''}]) - - def test_float(self): - ar = options.cli_to_array('this<=283.347') - self.assertEqual(ar, [{'field': 'this', - 'op': 'le', 'value': '283.347', - 'type': ''}]) - - def test_comma(self): - ar = options.cli_to_array('this=2.4,fooo=doof') - self.assertEqual([{'field': 'this', - 'op': 'eq', - 'value': '2.4,fooo=doof', - 'type': ''}], - ar) - - def test_special_character(self): - ar = options.cli_to_array('key~123=value!123') - self.assertEqual([{'field': 'key~123', - 'op': 'eq', - 'value': 'value!123', - 'type': ''}], - ar) - - def _do_test_typed_float_op(self, op, op_str): - ar = options.cli_to_array('that%sfloat::283.347' % op) - self.assertEqual([{'field': 'that', - 'type': 'float', - 'value': '283.347', - 'op': op_str}], - ar) - - def test_typed_float_eq(self): - self._do_test_typed_float_op('<', 'lt') - - def test_typed_float_le(self): - self._do_test_typed_float_op('<=', 'le') - - def test_typed_string_whitespace(self): - ar = options.cli_to_array('state=string::insufficient data') - self.assertEqual([{'field': 'state', - 'op': 'eq', - 'type': 'string', - 'value': 'insufficient data'}], - ar) - - def test_typed_string_whitespace_complex(self): - ar = options.cli_to_array( - 'that>=float::99.9999;state=string::insufficient data' - ) - self.assertEqual([{'field': 'that', - 'op': 'ge', - 'type': 'float', - 'value': '99.9999'}, - {'field': 'state', - 'op': 'eq', - 'type': 'string', - 'value': 'insufficient data'}], - ar) - - def test_invalid_operator(self): - self.assertRaises(ValueError, options.cli_to_array, - 'this=2.4;fooo-doof') - - def test_with_dot(self): - ar = options.cli_to_array('metadata.this<=34') - self.assertEqual(ar, [{'field': 'metadata.this', - 'op': 'le', 'value': '34', - 'type': ''}]) - - def test_single_char_field_or_value(self): - ar = options.cli_to_array('m<=34;large.thing>s;x!=y') - self.assertEqual([{'field': 'm', - 'op': 'le', - 'value': '34', - 'type': ''}, - {'field': 'large.thing', - 'op': 'gt', - 'value': 's', - 'type': ''}, - {'field': 'x', - 'op': 'ne', - 'value': 'y', - 'type': ''}], - ar) - - def test_without_data_type(self): - ar = options.cli_to_array('hostname=localhost') - self.assertEqual(ar, [{'field': 'hostname', - 'op': 'eq', - 'value': 'localhost', - 'type': ''}]) - - def test_with_string_data_type(self): - ar = options.cli_to_array('hostname=string::localhost') - self.assertEqual(ar, [{'field': 'hostname', - 'op': 'eq', - 'type': 'string', - 'value': 'localhost'}]) - - def test_with_int_data_type(self): - ar = options.cli_to_array('port=integer::1234') - self.assertEqual(ar, [{'field': 'port', - 'op': 'eq', - 'type': 'integer', - 'value': '1234'}]) - - def test_with_bool_data_type(self): - ar = options.cli_to_array('port=boolean::true') - self.assertEqual(ar, [{'field': 'port', - 'op': 'eq', - 'type': 'boolean', - 'value': 'true'}]) - - def test_with_float_data_type(self): - ar = options.cli_to_array('average=float::1234.5678') - self.assertEqual(ar, [{'field': 'average', - 'op': 'eq', - 'type': 'float', - 'value': '1234.5678'}]) - - def test_with_datetime_data_type(self): - ar = options.cli_to_array('timestamp=datetime::sometimestamp') - self.assertEqual(ar, [{'field': 'timestamp', - 'op': 'eq', - 'type': 'datetime', - 'value': 'sometimestamp'}]) - - def test_with_incorrect_type(self): - ar = options.cli_to_array('timestamp=invalid::sometimestamp') - self.assertEqual(ar, [{'field': 'timestamp', - 'op': 'eq', - 'type': '', - 'value': 'invalid::sometimestamp'}]) - - def test_with_single_colon(self): - ar = options.cli_to_array('timestamp=datetime:sometimestamp') - self.assertEqual(ar, [{'field': 'timestamp', - 'op': 'eq', - 'type': '', - 'value': 'datetime:sometimestamp'}]) - - def test_missing_key(self): - self.assertRaises(ValueError, options.cli_to_array, - 'average=float::1234.0;>=string::hello') - - def test_missing_value(self): - self.assertRaises(ValueError, options.cli_to_array, - 'average=float::1234.0;house>=') - - def test_timestamp_value(self): - ar = options.cli_to_array( - 'project=cow;timestamp>=datetime::2014-03-11T16:02:58' - ) - self.assertEqual([{'field': 'project', - 'op': 'eq', - 'type': '', - 'value': 'cow'}, - {'field': 'timestamp', - 'op': 'ge', - 'type': 'datetime', - 'value': '2014-03-11T16:02:58'}], - ar) diff --git a/ceilometerclient/tests/v2/test_query_alarm_history.py b/ceilometerclient/tests/v2/test_query_alarm_history.py deleted file mode 100644 index 60d437d..0000000 --- a/ceilometerclient/tests/v2/test_query_alarm_history.py +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright Ericsson AB 2014. All rights reserved -# -# Authors: Ildiko Vancsa -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from ceilometerclient.openstack.common.apiclient import client -from ceilometerclient.openstack.common.apiclient import fake_client -from ceilometerclient.tests import utils -from ceilometerclient.v2 import query - - -ALARMCHANGE = {"alarm_id": "e8ff32f772a44a478182c3fe1f7cad6a", - "event_id": "c74a8611-6553-4764-a860-c15a6aabb5d0", - "detail": "{\"threshold\": 42.0, \"evaluation_periods\": 4}", - "on_behalf_of": "92159030020611e3b26dde429e99ee8c", - "project_id": "b6f16144010811e387e4de429e99ee8c", - "timestamp": "2014-03-11T16:02:58.376261", - "type": "rule change", - "user_id": "3e5d11fda79448ac99ccefb20be187ca" - } - -QUERY = {"filter": {"and": [{">": {"timestamp": "2014-03-11T16:02:58"}}, - {"=": {"type": "rule change"}}]}, - "orderby": [{"timestamp": "desc"}], - "limit": 10} - -base_url = '/v2/query/alarms/history' -fixtures = { - base_url: - { - 'POST': ( - {}, - [ALARMCHANGE], - ), - }, -} - - -class QueryAlarmsManagerTest(utils.BaseTestCase): - - def setUp(self): - super(QueryAlarmsManagerTest, self).setUp() - self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) - self.api = client.BaseClient(self.http_client) - self.mgr = query.QueryAlarmHistoryManager(self.api) - - def test_query(self): - alarm_history = self.mgr.query(**QUERY) - expect = [ - - 'POST', '/v2/query/alarms/history', QUERY, - - ] - self.http_client.assert_called(*expect) - self.assertEqual(1, len(alarm_history)) diff --git a/ceilometerclient/tests/v2/test_query_alarms.py b/ceilometerclient/tests/v2/test_query_alarms.py deleted file mode 100644 index 7897ad1..0000000 --- a/ceilometerclient/tests/v2/test_query_alarms.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright Ericsson AB 2014. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from ceilometerclient.openstack.common.apiclient import client -from ceilometerclient.openstack.common.apiclient import fake_client -from ceilometerclient.tests import utils -from ceilometerclient.v2 import query - - -ALARM = {"alarm_actions": ["http://site:8000/alarm"], - "alarm_id": None, - "combination_rule": { - "alarm_ids": [ - "739e99cb-c2ec-4718-b900-332502355f38", - "153462d0-a9b8-4b5b-8175-9e4b05e9b856"], - "operator": "or"}, - "description": "An alarm", - "enabled": True, - "insufficient_data_actions": ["http://site:8000/nodata"], - "name": "SwiftObjectAlarm", - "ok_actions": ["http://site:8000/ok"], - "project_id": "c96c887c216949acbdfbd8b494863567", - "repeat_actions": False, - "state": "ok", - "state_timestamp": "2014-02-20T10:37:15.589860", - "threshold_rule": None, - "timestamp": "2014-02-20T10:37:15.589856", - "type": "combination", - "user_id": "c96c887c216949acbdfbd8b494863567"} - -QUERY = {"filter": {"and": [{"!=": {"state": "ok"}}, - {"=": {"type": "combination"}}]}, - "orderby": [{"state_timestamp": "desc"}], - "limit": 10} - -base_url = '/v2/query/alarms' -fixtures = { - base_url: - { - 'POST': ( - {}, - [ALARM], - ), - }, -} - - -class QueryAlarmsManagerTest(utils.BaseTestCase): - - def setUp(self): - super(QueryAlarmsManagerTest, self).setUp() - self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) - self.api = client.BaseClient(self.http_client) - self.mgr = query.QueryAlarmsManager(self.api) - - def test_query(self): - alarms = self.mgr.query(**QUERY) - expect = [ - 'POST', '/v2/query/alarms', QUERY, - ] - - self.http_client.assert_called(*expect) - self.assertEqual(1, len(alarms)) diff --git a/ceilometerclient/tests/v2/test_query_samples.py b/ceilometerclient/tests/v2/test_query_samples.py deleted file mode 100644 index e747717..0000000 --- a/ceilometerclient/tests/v2/test_query_samples.py +++ /dev/null @@ -1,67 +0,0 @@ -# Copyright Ericsson AB 2014. All rights reserved -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from ceilometerclient.openstack.common.apiclient import client -from ceilometerclient.openstack.common.apiclient import fake_client -from ceilometerclient.tests import utils -from ceilometerclient.v2 import query - - -SAMPLE = {u'id': u'b55d1526-9929-11e3-a3f6-02163e5df1e6', - u'metadata': { - u'name1': u'value1', - u'name2': u'value2'}, - u'meter': 'instance', - u'project_id': u'35b17138-b364-4e6a-a131-8f3099c5be68', - u'resource_id': u'bd9431c1-8d69-4ad3-803a-8d4a6b89fd36', - u'source': u'openstack', - u'timestamp': u'2014-02-19T05:50:16.673604', - u'type': u'gauge', - u'unit': u'instance', - u'volume': 1, - u'user_id': 'efd87807-12d2-4b38-9c70-5f5c2ac427ff'} - -QUERY = {"filter": {"and": [{"=": {"source": "openstack"}}, - {">": {"timestamp": "2014-02-19T05:50:16"}}]}, - "orderby": [{"timestamp": "desc"}, {"volume": "asc"}], - "limit": 10} - -base_url = '/v2/query/samples' -fixtures = { - base_url: - { - 'POST': ( - {}, - [SAMPLE], - ), - }, -} - - -class QuerySamplesManagerTest(utils.BaseTestCase): - - def setUp(self): - super(QuerySamplesManagerTest, self).setUp() - self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) - self.api = client.BaseClient(self.http_client) - self.mgr = query.QuerySamplesManager(self.api) - - def test_query(self): - samples = self.mgr.query(**QUERY) - expect = [ - - 'POST', '/v2/query/samples', QUERY, - ] - self.http_client.assert_called(*expect) - self.assertEqual(1, len(samples)) diff --git a/ceilometerclient/tests/v2/test_resources.py b/ceilometerclient/tests/v2/test_resources.py deleted file mode 100644 index 090ce8c..0000000 --- a/ceilometerclient/tests/v2/test_resources.py +++ /dev/null @@ -1,118 +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 ceilometerclient.openstack.common.apiclient import client -from ceilometerclient.openstack.common.apiclient import fake_client -from ceilometerclient.tests import utils -import ceilometerclient.v2.resources - - -fixtures = { - '/v2/resources': { - 'GET': ( - {}, - [ - { - 'resource_id': 'a', - 'project_id': 'project_bla', - 'user_id': 'freddy', - 'metadata': {'zxc_id': 'bla'}, - }, - { - 'resource_id': 'b', - 'project_id': 'dig_the_ditch', - 'user_id': 'joey', - 'metadata': {'zxc_id': 'foo'}, - }, - ] - ), - }, - '/v2/resources?q.field=resource_id&q.op=&q.type=&q.value=a': - { - 'GET': ( - {}, - [ - { - 'resource_id': 'a', - 'project_id': 'project_bla', - 'user_id': 'freddy', - 'metadata': {'zxc_id': 'bla'}, - }, - ] - ), - }, - '/v2/resources/a': - { - 'GET': ( - {}, - { - 'resource_id': 'a', - 'project_id': 'project_bla', - 'user_id': 'freddy', - 'metadata': {'zxc_id': 'bla'}, - }, - ), - }, -} - - -class ResourceManagerTest(utils.BaseTestCase): - - def setUp(self): - super(ResourceManagerTest, self).setUp() - self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) - self.api = client.BaseClient(self.http_client) - self.mgr = ceilometerclient.v2.resources.ResourceManager(self.api) - - def test_list_all(self): - resources = list(self.mgr.list()) - expect = [ - 'GET', '/v2/resources' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(resources), 2) - self.assertEqual(resources[0].resource_id, 'a') - self.assertEqual(resources[1].resource_id, 'b') - - def test_list_one(self): - resource = self.mgr.get(resource_id='a') - expect = [ - 'GET', '/v2/resources/a' - ] - self.http_client.assert_called(*expect) - self.assertIsNotNone(resource) - self.assertEqual(resource.resource_id, 'a') - - def test_list_by_query(self): - resources = list(self.mgr.list(q=[{"field": "resource_id", - "value": "a"}, - ])) - expect = [ - 'GET', '/v2/resources?q.field=resource_id&q.op=' - '&q.type=&q.value=a' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(resources), 1) - self.assertEqual(resources[0].resource_id, 'a') - - def test_get_from_resource_class(self): - resource = self.mgr.get(resource_id='a') - self.assertIsNotNone(resource) - resource.get() - expect = [ - 'GET', '/v2/resources/a' - ] - self.http_client.assert_called(*expect, pos=0) - self.http_client.assert_called(*expect, pos=1) - self.assertEqual('a', resource.resource_id) diff --git a/ceilometerclient/tests/v2/test_samples.py b/ceilometerclient/tests/v2/test_samples.py deleted file mode 100644 index aee2220..0000000 --- a/ceilometerclient/tests/v2/test_samples.py +++ /dev/null @@ -1,198 +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 copy - -from ceilometerclient.openstack.common.apiclient import client -from ceilometerclient.openstack.common.apiclient import fake_client -from ceilometerclient.tests import utils -import ceilometerclient.v2.samples - -GET_OLD_SAMPLE = {u'counter_name': u'instance', - u'user_id': u'user-id', - u'resource_id': u'resource-id', - u'timestamp': u'2012-07-02T10:40:00', - u'source': u'test_source', - u'message_id': u'54558a1c-6ef3-11e2-9875-5453ed1bbb5f', - u'counter_unit': u'', - u'counter_volume': 1.0, - u'project_id': u'project1', - u'resource_metadata': {u'tag': u'self.counter', - u'display_name': u'test-server'}, - u'counter_type': u'cumulative'} -CREATE_SAMPLE = copy.deepcopy(GET_OLD_SAMPLE) -del CREATE_SAMPLE['message_id'] -del CREATE_SAMPLE['source'] - -GET_SAMPLE = { - "user_id": None, - "resource_id": "9b651dfd-7d30-402b-972e-212b2c4bfb05", - "timestamp": "2014-11-03T13:37:46", - "meter": "image", - "volume": 1.0, - "source": "openstack", - "recorded_at": "2014-11-03T13:37:46.994458", - "project_id": "2cc3a7bb859b4bacbeab0aa9ca673033", - "type": "gauge", - "id": "98b5f258-635e-11e4-8bdd-0025647390c1", - "unit": "image", - "resource_metadata": {}, -} - -METER_URL = '/v2/meters/instance' -SAMPLE_URL = '/v2/samples' -QUERIES = ('q.field=resource_id&q.field=source&q.op=&q.op=' - '&q.type=&q.type=&q.value=foo&q.value=bar') -LIMIT = 'limit=1' - -OLD_SAMPLE_FIXTURES = { - METER_URL: { - 'GET': ( - {}, - [GET_OLD_SAMPLE] - ), - 'POST': ( - {}, - [CREATE_SAMPLE], - ), - }, - '%s?%s' % (METER_URL, QUERIES): { - 'GET': ( - {}, - [], - ), - }, - '%s?%s' % (METER_URL, LIMIT): { - 'GET': ( - {}, - [GET_OLD_SAMPLE] - ), - } -} -SAMPLE_FIXTURES = { - SAMPLE_URL: { - 'GET': ( - (), - [GET_SAMPLE] - ), - }, - '%s?%s' % (SAMPLE_URL, QUERIES): { - 'GET': ( - {}, - [], - ), - }, - '%s?%s' % (SAMPLE_URL, LIMIT): { - 'GET': ( - {}, - [GET_SAMPLE], - ), - }, - '%s/%s' % (SAMPLE_URL, GET_SAMPLE['id']): { - 'GET': ( - {}, - GET_SAMPLE, - ), - }, -} - - -class OldSampleManagerTest(utils.BaseTestCase): - - def setUp(self): - super(OldSampleManagerTest, self).setUp() - self.http_client = fake_client.FakeHTTPClient( - fixtures=OLD_SAMPLE_FIXTURES) - self.api = client.BaseClient(self.http_client) - self.mgr = ceilometerclient.v2.samples.OldSampleManager(self.api) - - def test_list_by_meter_name(self): - samples = list(self.mgr.list(meter_name='instance')) - expect = [ - 'GET', '/v2/meters/instance' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(samples), 1) - self.assertEqual(samples[0].resource_id, 'resource-id') - - def test_list_by_meter_name_extended(self): - samples = list(self.mgr.list(meter_name='instance', - q=[ - {"field": "resource_id", - "value": "foo"}, - {"field": "source", - "value": "bar"}, - ])) - expect = ['GET', '%s?%s' % (METER_URL, QUERIES)] - self.http_client.assert_called(*expect) - self.assertEqual(len(samples), 0) - - def test_create(self): - sample = self.mgr.create(**CREATE_SAMPLE) - expect = [ - 'POST', '/v2/meters/instance' - ] - self.http_client.assert_called(*expect, body=[CREATE_SAMPLE]) - self.assertIsNotNone(sample) - - def test_limit(self): - samples = list(self.mgr.list(meter_name='instance', limit=1)) - expect = ['GET', '/v2/meters/instance?limit=1'] - self.http_client.assert_called(*expect) - self.assertEqual(len(samples), 1) - - -class SampleManagerTest(utils.BaseTestCase): - - def setUp(self): - super(SampleManagerTest, self).setUp() - self.http_client = fake_client.FakeHTTPClient( - fixtures=SAMPLE_FIXTURES) - self.api = client.BaseClient(self.http_client) - self.mgr = ceilometerclient.v2.samples.SampleManager(self.api) - - def test_sample_list(self): - samples = list(self.mgr.list()) - expect = [ - 'GET', '/v2/samples' - ] - self.http_client.assert_called(*expect) - self.assertEqual(1, len(samples)) - self.assertEqual('9b651dfd-7d30-402b-972e-212b2c4bfb05', - samples[0].resource_id) - - def test_sample_list_with_queries(self): - queries = [ - {"field": "resource_id", - "value": "foo"}, - {"field": "source", - "value": "bar"}, - ] - samples = list(self.mgr.list(q=queries)) - expect = ['GET', '%s?%s' % (SAMPLE_URL, QUERIES)] - self.http_client.assert_called(*expect) - self.assertEqual(0, len(samples)) - - def test_sample_list_with_limit(self): - samples = list(self.mgr.list(limit=1)) - expect = ['GET', '/v2/samples?limit=1'] - self.http_client.assert_called(*expect) - self.assertEqual(1, len(samples)) - - def test_sample_get(self): - sample = self.mgr.get(GET_SAMPLE['id']) - expect = ['GET', '/v2/samples/' + GET_SAMPLE['id']] - self.http_client.assert_called(*expect) - self.assertEqual(GET_SAMPLE, sample.to_dict()) diff --git a/ceilometerclient/tests/v2/test_shell.py b/ceilometerclient/tests/v2/test_shell.py deleted file mode 100644 index 921bded..0000000 --- a/ceilometerclient/tests/v2/test_shell.py +++ /dev/null @@ -1,1175 +0,0 @@ -# Copyright Ericsson AB 2014. All rights reserved -# -# Authors: Balazs Gibizer -# Ildiko Vancsa -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# 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 sys - -import mock -import six -from testtools import matchers - -from ceilometerclient import exc -from ceilometerclient import shell as base_shell -from ceilometerclient.tests import test_shell -from ceilometerclient.tests import utils -from ceilometerclient.v2 import alarms -from ceilometerclient.v2 import events -from ceilometerclient.v2 import samples -from ceilometerclient.v2 import shell as ceilometer_shell -from ceilometerclient.v2 import statistics - - -class ShellAlarmStateCommandsTest(utils.BaseTestCase): - - ALARM_ID = 'foobar' - - def setUp(self): - super(ShellAlarmStateCommandsTest, self).setUp() - self.cc = mock.Mock() - self.cc.alarms = mock.Mock() - self.args = mock.Mock() - self.args.alarm_id = self.ALARM_ID - - def test_alarm_state_get(self): - ceilometer_shell.do_alarm_state_get(self.cc, self.args) - self.cc.alarms.get_state.assert_called_once_with(self.ALARM_ID) - self.assertFalse(self.cc.alarms.set_state.called) - - def test_alarm_state_set(self): - self.args.state = 'ok' - ceilometer_shell.do_alarm_state_set(self.cc, self.args) - self.cc.alarms.set_state.assert_called_once_with(self.ALARM_ID, 'ok') - self.assertFalse(self.cc.alarms.get_state.called) - - -class ShellAlarmHistoryCommandTest(utils.BaseTestCase): - - ALARM_ID = '768ff714-8cfb-4db9-9753-d484cb33a1cc' - FULL_DETAIL = ('{"alarm_actions": [], ' - '"user_id": "8185aa72421a4fd396d4122cba50e1b5", ' - '"name": "scombo", ' - '"timestamp": "2013-10-03T08:58:33.647912", ' - '"enabled": true, ' - '"state_timestamp": "2013-10-03T08:58:33.647912", ' - '"rule": {"operator": "or", "alarm_ids": ' - '["062cc907-3a9f-4867-ab3b-fa83212b39f7"]}, ' - '"alarm_id": "768ff714-8cfb-4db9-9753-d484cb33a1cc", ' - '"state": "insufficient data", ' - '"insufficient_data_actions": [], ' - '"repeat_actions": false, ' - '"ok_actions": [], ' - '"project_id": "57d04f24d0824b78b1ea9bcecedbda8f", ' - '"type": "combination", ' - '"description": "Combined state of alarms ' - '062cc907-3a9f-4867-ab3b-fa83212b39f7"}') - ALARM_HISTORY = [{'on_behalf_of': '57d04f24d0824b78b1ea9bcecedbda8f', - 'user_id': '8185aa72421a4fd396d4122cba50e1b5', - 'event_id': 'c74a8611-6553-4764-a860-c15a6aabb5d0', - 'timestamp': '2013-10-03T08:59:28.326000', - 'detail': '{"state": "alarm"}', - 'alarm_id': '768ff714-8cfb-4db9-9753-d484cb33a1cc', - 'project_id': '57d04f24d0824b78b1ea9bcecedbda8f', - 'type': 'state transition'}, - {'on_behalf_of': '57d04f24d0824b78b1ea9bcecedbda8f', - 'user_id': '8185aa72421a4fd396d4122cba50e1b5', - 'event_id': 'c74a8611-6553-4764-a860-c15a6aabb5d0', - 'timestamp': '2013-10-03T08:59:28.326000', - 'detail': '{"description": "combination of one"}', - 'alarm_id': '768ff714-8cfb-4db9-9753-d484cb33a1cc', - 'project_id': '57d04f24d0824b78b1ea9bcecedbda8f', - 'type': 'rule change'}, - {'on_behalf_of': '57d04f24d0824b78b1ea9bcecedbda8f', - 'user_id': '8185aa72421a4fd396d4122cba50e1b5', - 'event_id': '4fd7df9e-190d-4471-8884-dc5a33d5d4bb', - 'timestamp': '2013-10-03T08:58:33.647000', - 'detail': FULL_DETAIL, - 'alarm_id': '768ff714-8cfb-4db9-9753-d484cb33a1cc', - 'project_id': '57d04f24d0824b78b1ea9bcecedbda8f', - 'type': 'creation'}] - TIMESTAMP_RE = (' +\| (\d{4})-(\d{2})-(\d{2})T' - '(\d{2})\:(\d{2})\:(\d{2})\.(\d{6}) \| +') - - def setUp(self): - super(ShellAlarmHistoryCommandTest, self).setUp() - self.cc = mock.Mock() - self.cc.alarms = mock.Mock() - self.args = mock.Mock() - self.args.alarm_id = self.ALARM_ID - - @mock.patch('sys.stdout', new=six.StringIO()) - def _do_test_alarm_history(self, raw_query=None, parsed_query=None): - self.args.query = raw_query - history = [alarms.AlarmChange(mock.Mock(), change) - for change in self.ALARM_HISTORY] - self.cc.alarms.get_history.return_value = history - - ceilometer_shell.do_alarm_history(self.cc, self.args) - self.cc.alarms.get_history.assert_called_once_with( - q=parsed_query, - alarm_id=self.ALARM_ID - ) - out = sys.stdout.getvalue() - required = [ - '.*creation%sname: scombo.*' % self.TIMESTAMP_RE, - '.*rule change%sdescription: combination of one.*' % - self.TIMESTAMP_RE, - '.*state transition%sstate: alarm.*' % self.TIMESTAMP_RE, - ] - for r in required: - self.assertThat(out, matchers.MatchesRegex(r, re.DOTALL)) - - def test_alarm_all_history(self): - self._do_test_alarm_history() - - def test_alarm_constrained_history(self): - parsed_query = [dict(field='timestamp', - value='2013-10-03T08:59:28', - op='gt', - type='')] - self._do_test_alarm_history(raw_query='timestamp>2013-10-03T08:59:28', - parsed_query=parsed_query) - - -class ShellAlarmCommandTest(utils.BaseTestCase): - - ALARM_ID = '768ff714-8cfb-4db9-9753-d484cb33a1cc' - ALARM = {"alarm_actions": ["log://"], - "ok_actions": [], - "description": "instance running hot", - "timestamp": "2013-11-20T10:38:42.206952", - "enabled": True, - "state_timestamp": "2013-11-19T17:20:44", - "threshold_rule": {"meter_name": "cpu_util", - "evaluation_periods": 3, - "period": 600, - "statistic": "avg", - "threshold": 99.0, - "query": [{"field": "resource_id", - "value": "INSTANCE_ID", - "op": "eq"}], - "comparison_operator": "gt"}, - "time_constraints": [{"name": "cons1", - "description": "desc1", - "start": "0 11 * * *", - "duration": 300, - "timezone": ""}, - {"name": "cons2", - "description": "desc2", - "start": "0 23 * * *", - "duration": 600, - "timezone": ""}], - "alarm_id": ALARM_ID, - "state": "insufficient data", - "severity": "low", - "insufficient_data_actions": [], - "repeat_actions": True, - "user_id": "528d9b68fa774689834b5c04b4564f8a", - "project_id": "ed9d4e2be2a748bc80108053cf4598f5", - "type": "threshold", - "name": "cpu_high"} - - THRESHOLD_ALARM_CLI_ARGS = [ - '--name', 'cpu_high', - '--description', 'instance running hot', - '--meter-name', 'cpu_util', - '--threshold', '70.0', - '--comparison-operator', 'gt', - '--statistic', 'avg', - '--period', '600', - '--evaluation-periods', '3', - '--alarm-action', 'log://', - '--alarm-action', 'http://example.com/alarm/state', - '--query', 'resource_id=INSTANCE_ID' - ] - - def setUp(self): - super(ShellAlarmCommandTest, self).setUp() - self.cc = mock.Mock() - self.cc.alarms = mock.Mock() - self.args = mock.Mock() - self.args.alarm_id = self.ALARM_ID - - @mock.patch('sys.stdout', new=six.StringIO()) - def _do_test_alarm_update_repeat_actions(self, method, repeat_actions): - self.args.threshold = 42.0 - if repeat_actions is not None: - self.args.repeat_actions = repeat_actions - alarm = [alarms.Alarm(mock.Mock(), self.ALARM)] - self.cc.alarms.get.return_value = alarm - self.cc.alarms.update.return_value = alarm[0] - - method(self.cc, self.args) - args, kwargs = self.cc.alarms.update.call_args - self.assertEqual(self.ALARM_ID, args[0]) - self.assertEqual(42.0, kwargs.get('threshold')) - if repeat_actions is not None: - self.assertEqual(repeat_actions, kwargs.get('repeat_actions')) - else: - self.assertNotIn('repeat_actions', kwargs) - - def test_alarm_update_repeat_actions_untouched(self): - method = ceilometer_shell.do_alarm_update - self._do_test_alarm_update_repeat_actions(method, None) - - def test_alarm_update_repeat_actions_set(self): - method = ceilometer_shell.do_alarm_update - self._do_test_alarm_update_repeat_actions(method, True) - - def test_alarm_update_repeat_actions_clear(self): - method = ceilometer_shell.do_alarm_update - self._do_test_alarm_update_repeat_actions(method, False) - - def test_alarm_combination_update_repeat_actions_untouched(self): - method = ceilometer_shell.do_alarm_combination_update - self._do_test_alarm_update_repeat_actions(method, None) - - def test_alarm_combination_update_repeat_actions_set(self): - method = ceilometer_shell.do_alarm_combination_update - self._do_test_alarm_update_repeat_actions(method, True) - - def test_alarm_combination_update_repeat_actions_clear(self): - method = ceilometer_shell.do_alarm_combination_update - self._do_test_alarm_update_repeat_actions(method, False) - - def test_alarm_threshold_update_repeat_actions_untouched(self): - method = ceilometer_shell.do_alarm_threshold_update - self._do_test_alarm_update_repeat_actions(method, None) - - def test_alarm_threshold_update_repeat_actions_set(self): - method = ceilometer_shell.do_alarm_threshold_update - self._do_test_alarm_update_repeat_actions(method, True) - - def test_alarm_threshold_update_repeat_actions_clear(self): - method = ceilometer_shell.do_alarm_threshold_update - self._do_test_alarm_update_repeat_actions(method, False) - - @mock.patch('sys.stdout', new=six.StringIO()) - def test_alarm_threshold_create_args(self): - argv = ['alarm-threshold-create'] + self.THRESHOLD_ALARM_CLI_ARGS - self._test_alarm_threshold_action_args('create', argv) - - def test_alarm_threshold_update_args(self): - argv = ['alarm-threshold-update', 'x'] + self.THRESHOLD_ALARM_CLI_ARGS - self._test_alarm_threshold_action_args('update', argv) - - @mock.patch('sys.stdout', new=six.StringIO()) - def _test_alarm_threshold_action_args(self, action, argv): - shell = base_shell.CeilometerShell() - _, args = shell.parse_args(argv) - - alarm = alarms.Alarm(mock.Mock(), self.ALARM) - getattr(self.cc.alarms, action).return_value = alarm - - func = getattr(ceilometer_shell, 'do_alarm_threshold_' + action) - func(self.cc, args) - _, kwargs = getattr(self.cc.alarms, action).call_args - self._check_alarm_threshold_args(kwargs) - - def _check_alarm_threshold_args(self, kwargs): - self.assertEqual('cpu_high', kwargs.get('name')) - self.assertEqual('instance running hot', kwargs.get('description')) - actions = ['log://', 'http://example.com/alarm/state'] - self.assertEqual(actions, kwargs.get('alarm_actions')) - self.assertIn('threshold_rule', kwargs) - rule = kwargs['threshold_rule'] - self.assertEqual('cpu_util', rule.get('meter_name')) - self.assertEqual(70.0, rule.get('threshold')) - self.assertEqual('gt', rule.get('comparison_operator')) - self.assertEqual('avg', rule.get('statistic')) - self.assertEqual(600, rule.get('period')) - self.assertEqual(3, rule.get('evaluation_periods')) - query = dict(field='resource_id', type='', - value='INSTANCE_ID', op='eq') - self.assertEqual([query], rule['query']) - - @mock.patch('sys.stdout', new=six.StringIO()) - def test_alarm_create_time_constraints(self): - shell = base_shell.CeilometerShell() - argv = ['alarm-threshold-create', - '--name', 'cpu_high', - '--meter-name', 'cpu_util', - '--threshold', '70.0', - '--time-constraint', - 'name=cons1;start="0 11 * * *";duration=300', - '--time-constraint', - 'name=cons2;start="0 23 * * *";duration=600', - ] - _, args = shell.parse_args(argv) - - alarm = alarms.Alarm(mock.Mock(), self.ALARM) - self.cc.alarms.create.return_value = alarm - - ceilometer_shell.do_alarm_threshold_create(self.cc, args) - _, kwargs = self.cc.alarms.create.call_args - time_constraints = [dict(name='cons1', start='0 11 * * *', - duration='300'), - dict(name='cons2', start='0 23 * * *', - duration='600')] - self.assertEqual(time_constraints, kwargs['time_constraints']) - - -class ShellSampleListCommandTest(utils.BaseTestCase): - - METER = 'cpu_util' - SAMPLE_VALUES = ( - ("cpu_util", - "5dcf5537-3161-4e25-9235-407e1385bd35", - "2013-10-15T05:50:30", - "%", - 0.261666666667, - "gauge", - "86536501-b2c9-48f6-9c6a-7a5b14ba7482"), - ("cpu_util", - "87d197e9-9cf6-4c25-bc66-1b1f4cedb52f", - "2013-10-15T05:50:29", - "%", - 0.261666666667, - "gauge", - "fe2a91ec-602b-4b55-8cba-5302ce3b916e",), - ("cpu_util", - "5dcf5537-3161-4e25-9235-407e1385bd35", - "2013-10-15T05:40:30", - "%", - 0.251247920133, - "gauge", - "52768bcb-b4e9-4db9-a30c-738c758b6f43"), - ("cpu_util", - "87d197e9-9cf6-4c25-bc66-1b1f4cedb52f", - "2013-10-15T05:40:29", - "%", - 0.26, - "gauge", - "31ae614a-ac6b-4fb9-b106-4667bae03308"), - ) - - OLD_SAMPLES = [ - dict(counter_name=s[0], - resource_id=s[1], - timestamp=s[2], - counter_unit=s[3], - counter_volume=s[4], - counter_type=s[5]) - for s in SAMPLE_VALUES - ] - - SAMPLES = [ - dict(meter=s[0], - resource_id=s[1], - timestamp=s[2], - unit=s[3], - volume=s[4], - type=s[5], - id=s[6]) - for s in SAMPLE_VALUES - ] - - def setUp(self): - super(ShellSampleListCommandTest, self).setUp() - self.cc = mock.Mock() - self.cc.samples = mock.Mock() - self.cc.new_samples = mock.Mock() - self.args = mock.Mock() - self.args.query = None - self.args.limit = None - - @mock.patch('sys.stdout', new=six.StringIO()) - def test_old_sample_list(self): - self.args.meter = self.METER - sample_list = [samples.OldSample(mock.Mock(), sample) - for sample in self.OLD_SAMPLES] - self.cc.samples.list.return_value = sample_list - - ceilometer_shell.do_sample_list(self.cc, self.args) - self.cc.samples.list.assert_called_once_with( - meter_name=self.METER, - q=None, - limit=None) - - self.assertEqual('''\ -+--------------------------------------+----------+-------+----------------\ -+------+---------------------+ -| Resource ID | Name | Type | Volume \ -| Unit | Timestamp | -+--------------------------------------+----------+-------+----------------\ -+------+---------------------+ -| 5dcf5537-3161-4e25-9235-407e1385bd35 | cpu_util | gauge | 0.261666666667 \ -| % | 2013-10-15T05:50:30 | -| 87d197e9-9cf6-4c25-bc66-1b1f4cedb52f | cpu_util | gauge | 0.261666666667 \ -| % | 2013-10-15T05:50:29 | -| 5dcf5537-3161-4e25-9235-407e1385bd35 | cpu_util | gauge | 0.251247920133 \ -| % | 2013-10-15T05:40:30 | -| 87d197e9-9cf6-4c25-bc66-1b1f4cedb52f | cpu_util | gauge | 0.26 \ -| % | 2013-10-15T05:40:29 | -+--------------------------------------+----------+-------+----------------\ -+------+---------------------+ -''', sys.stdout.getvalue()) - - @mock.patch('sys.stdout', new=six.StringIO()) - def test_sample_list(self): - self.args.meter = None - sample_list = [samples.Sample(mock.Mock(), sample) - for sample in self.SAMPLES] - self.cc.new_samples.list.return_value = sample_list - - ceilometer_shell.do_sample_list(self.cc, self.args) - self.cc.new_samples.list.assert_called_once_with( - q=None, - limit=None) - - self.assertEqual('''\ -+--------------------------------------+--------------------------------------\ -+----------+-------+----------------+------+---------------------+ -| ID | Resource ID \ -| Name | Type | Volume | Unit | Timestamp | -+--------------------------------------+--------------------------------------\ -+----------+-------+----------------+------+---------------------+ -| 86536501-b2c9-48f6-9c6a-7a5b14ba7482 | 5dcf5537-3161-4e25-9235-407e1385bd35 \ -| cpu_util | gauge | 0.261666666667 | % | 2013-10-15T05:50:30 | -| fe2a91ec-602b-4b55-8cba-5302ce3b916e | 87d197e9-9cf6-4c25-bc66-1b1f4cedb52f \ -| cpu_util | gauge | 0.261666666667 | % | 2013-10-15T05:50:29 | -| 52768bcb-b4e9-4db9-a30c-738c758b6f43 | 5dcf5537-3161-4e25-9235-407e1385bd35 \ -| cpu_util | gauge | 0.251247920133 | % | 2013-10-15T05:40:30 | -| 31ae614a-ac6b-4fb9-b106-4667bae03308 | 87d197e9-9cf6-4c25-bc66-1b1f4cedb52f \ -| cpu_util | gauge | 0.26 | % | 2013-10-15T05:40:29 | -+--------------------------------------+--------------------------------------\ -+----------+-------+----------------+------+---------------------+ -''', sys.stdout.getvalue()) - - -class ShellSampleShowCommandTest(utils.BaseTestCase): - - SAMPLE = { - "user_id": None, - "resource_id": "9b651dfd-7d30-402b-972e-212b2c4bfb05", - "timestamp": "2014-11-03T13:37:46", - "meter": "image", - "volume": 1.0, - "source": "openstack", - "recorded_at": "2014-11-03T13:37:46.994458", - "project_id": "2cc3a7bb859b4bacbeab0aa9ca673033", - "type": "gauge", - "id": "98b5f258-635e-11e4-8bdd-0025647390c1", - "unit": "image", - "metadata": { - "name": "cirros-0.3.2-x86_64-uec", - } - } - - def setUp(self): - super(ShellSampleShowCommandTest, self).setUp() - self.cc = mock.Mock() - self.cc.new_samples = mock.Mock() - self.args = mock.Mock() - self.args.sample_id = "98b5f258-635e-11e4-8bdd-0025647390c1" - - @mock.patch('sys.stdout', new=six.StringIO()) - def test_sample_show(self): - sample = samples.Sample(mock.Mock(), self.SAMPLE) - self.cc.new_samples.get.return_value = sample - - ceilometer_shell.do_sample_show(self.cc, self.args) - self.cc.new_samples.get.assert_called_once_with( - "98b5f258-635e-11e4-8bdd-0025647390c1") - - self.assertEqual('''\ -+-------------+--------------------------------------+ -| Property | Value | -+-------------+--------------------------------------+ -| id | 98b5f258-635e-11e4-8bdd-0025647390c1 | -| metadata | {"name": "cirros-0.3.2-x86_64-uec"} | -| meter | image | -| project_id | 2cc3a7bb859b4bacbeab0aa9ca673033 | -| recorded_at | 2014-11-03T13:37:46.994458 | -| resource_id | 9b651dfd-7d30-402b-972e-212b2c4bfb05 | -| source | openstack | -| timestamp | 2014-11-03T13:37:46 | -| type | gauge | -| unit | image | -| user_id | None | -| volume | 1.0 | -+-------------+--------------------------------------+ -''', sys.stdout.getvalue()) - - -class ShellSampleCreateCommandTest(utils.BaseTestCase): - - METER = 'instance' - METER_TYPE = 'gauge' - RESOURCE_ID = '0564c64c-3545-4e34-abfb-9d18e5f2f2f9' - SAMPLE_VOLUME = '1' - METER_UNIT = 'instance' - SAMPLE = [{ - u'counter_name': u'instance', - u'user_id': u'21b442b8101d407d8242b6610e0ed0eb', - u'resource_id': u'0564c64c-3545-4e34-abfb-9d18e5f2f2f9', - u'timestamp': u'2014-01-10T03: 05: 33.951170', - u'message_id': u'1247cbe6-79a4-11e3-a296-000c294c58e2', - u'source': u'384260c6987b451d8290e66e1f108082: openstack', - u'counter_unit': u'instance', - u'counter_volume': 1.0, - u'project_id': u'384260c6987b451d8290e66e1f108082', - u'resource_metadata': {}, - u'counter_type': u'gauge' - }] - - def setUp(self): - super(ShellSampleCreateCommandTest, self).setUp() - self.cc = mock.Mock() - self.cc.samples = mock.Mock() - self.args = mock.Mock() - self.args.meter_name = self.METER - self.args.meter_type = self.METER_TYPE - self.args.meter_unit = self.METER_UNIT - self.args.resource_id = self.RESOURCE_ID - self.args.sample_volume = self.SAMPLE_VOLUME - - @mock.patch('sys.stdout', new=six.StringIO()) - def test_sample_create(self): - ret_sample = [samples.OldSample(mock.Mock(), sample) - for sample in self.SAMPLE] - self.cc.samples.create.return_value = ret_sample - - ceilometer_shell.do_sample_create(self.cc, self.args) - - self.assertEqual('''\ -+-------------------+---------------------------------------------+ -| Property | Value | -+-------------------+---------------------------------------------+ -| message_id | 1247cbe6-79a4-11e3-a296-000c294c58e2 | -| name | instance | -| project_id | 384260c6987b451d8290e66e1f108082 | -| resource_id | 0564c64c-3545-4e34-abfb-9d18e5f2f2f9 | -| resource_metadata | {} | -| source | 384260c6987b451d8290e66e1f108082: openstack | -| timestamp | 2014-01-10T03: 05: 33.951170 | -| type | gauge | -| unit | instance | -| user_id | 21b442b8101d407d8242b6610e0ed0eb | -| volume | 1.0 | -+-------------------+---------------------------------------------+ -''', sys.stdout.getvalue()) - - -class ShellQuerySamplesCommandTest(utils.BaseTestCase): - - SAMPLE = [{u'id': u'b55d1526-9929-11e3-a3f6-02163e5df1e6', - u'metadata': { - u'name1': u'value1', - u'name2': u'value2'}, - u'meter': 'instance', - u'project_id': u'35b17138-b364-4e6a-a131-8f3099c5be68', - u'resource_id': u'bd9431c1-8d69-4ad3-803a-8d4a6b89fd36', - u'source': u'openstack', - u'timestamp': u'2014-02-19T05:50:16.673604', - u'type': u'gauge', - u'unit': u'instance', - u'volume': 1, - u'user_id': 'efd87807-12d2-4b38-9c70-5f5c2ac427ff'}] - - QUERY = {"filter": {"and": [{"=": {"source": "openstack"}}, - {">": {"timestamp": "2014-02-19T05:50:16"}}]}, - "orderby": [{"timestamp": "desc"}, {"volume": "asc"}], - "limit": 10} - - def setUp(self): - super(ShellQuerySamplesCommandTest, self).setUp() - self.cc = mock.Mock() - self.args = mock.Mock() - self.args.filter = self.QUERY["filter"] - self.args.orderby = self.QUERY["orderby"] - self.args.limit = self.QUERY["limit"] - - @mock.patch('sys.stdout', new=six.StringIO()) - def test_query(self): - ret_sample = [samples.Sample(mock.Mock(), sample) - for sample in self.SAMPLE] - self.cc.query_samples.query.return_value = ret_sample - - ceilometer_shell.do_query_samples(self.cc, self.args) - - self.assertEqual('''\ -+--------------------------------------+----------+-------+--------+---------\ --+----------------------------+ -| Resource ID | Meter | Type | Volume | Unit \ - | Timestamp | -+--------------------------------------+----------+-------+--------+---------\ --+----------------------------+ -| bd9431c1-8d69-4ad3-803a-8d4a6b89fd36 | instance | gauge | 1 | instance\ - | 2014-02-19T05:50:16.673604 | -+--------------------------------------+----------+-------+--------+---------\ --+----------------------------+ -''', sys.stdout.getvalue()) - - -class ShellQueryAlarmsCommandTest(utils.BaseTestCase): - - ALARM = [{"alarm_actions": ["http://site:8000/alarm"], - "alarm_id": "768ff714-8cfb-4db9-9753-d484cb33a1cc", - "combination_rule": { - "alarm_ids": [ - "739e99cb-c2ec-4718-b900-332502355f38", - "153462d0-a9b8-4b5b-8175-9e4b05e9b856"], - "operator": "or"}, - "description": "An alarm", - "enabled": True, - "insufficient_data_actions": ["http://site:8000/nodata"], - "name": "SwiftObjectAlarm", - "ok_actions": ["http://site:8000/ok"], - "project_id": "c96c887c216949acbdfbd8b494863567", - "repeat_actions": False, - "state": "ok", - "severity": "critical", - "state_timestamp": "2014-02-20T10:37:15.589860", - "threshold_rule": None, - "timestamp": "2014-02-20T10:37:15.589856", - "time_constraints": [{"name": "test", "start": "0 23 * * *", - "duration": 10800}], - "type": "combination", - "user_id": "c96c887c216949acbdfbd8b494863567"}] - - QUERY = {"filter": {"and": [{"!=": {"state": "ok"}}, - {"=": {"type": "combination"}}]}, - "orderby": [{"state_timestamp": "desc"}], - "limit": 10} - - def setUp(self): - super(ShellQueryAlarmsCommandTest, self).setUp() - self.cc = mock.Mock() - self.args = mock.Mock() - self.args.filter = self.QUERY["filter"] - self.args.orderby = self.QUERY["orderby"] - self.args.limit = self.QUERY["limit"] - - @mock.patch('sys.stdout', new=six.StringIO()) - def test_query(self): - ret_alarm = [alarms.Alarm(mock.Mock(), alarm) - for alarm in self.ALARM] - self.cc.query_alarms.query.return_value = ret_alarm - - ceilometer_shell.do_query_alarms(self.cc, self.args) - - self.assertEqual('''\ -+--------------------------------------+------------------+-------+----------+\ ----------+------------+-------------------------------------------------------\ ------------------------------------------------+-------------------------------\ --+ -| Alarm ID | Name | State | Severity \ -| Enabled | Continuous | Alarm condition \ - | Time constraints \ - | -+--------------------------------------+------------------+-------+----------+\ ----------+------------+-------------------------------------------------------\ ------------------------------------------------+--------------------------------+ -| 768ff714-8cfb-4db9-9753-d484cb33a1cc | SwiftObjectAlarm | ok | critical \ -| True | False | combinated states (OR) of \ -739e99cb-c2ec-4718-b900-332502355f38, 153462d0-a9b8-4b5b-8175-9e4b05e9b856 |\ - test at 0 23 * * * for 10800s | -+--------------------------------------+------------------+-------+----------+\ ----------+------------+-------------------------------------------------------\ ------------------------------------------------+------------------------------\ ---+ -''', sys.stdout.getvalue()) - - @mock.patch('sys.stdout', new=six.StringIO()) - def test_time_constraints_compatibility(self): - # client should be backwards compatible - alarm_without_tc = dict(self.ALARM[0]) - del alarm_without_tc['time_constraints'] - - # NOTE(nsaje): Since we're accessing a nonexisting key in the resource, - # the resource is looking it up with the manager (which is a mock). - manager_mock = mock.Mock() - del manager_mock.get - ret_alarm = [alarms.Alarm(manager_mock, alarm_without_tc)] - self.cc.query_alarms.query.return_value = ret_alarm - - ceilometer_shell.do_query_alarms(self.cc, self.args) - - self.assertEqual('''\ -+--------------------------------------+------------------+-------+----------+\ ----------+------------+-------------------------------------------------------\ ------------------------------------------------+------------------+ -| Alarm ID | Name | State | Severity \ -| Enabled | Continuous | Alarm condition \ - | Time constraints | -+--------------------------------------+------------------+-------+----------+\ ----------+------------+-------------------------------------------------------\ ------------------------------------------------+------------------+ -| 768ff714-8cfb-4db9-9753-d484cb33a1cc | SwiftObjectAlarm | ok | critical \ -| True | False | combinated states (OR) of \ -739e99cb-c2ec-4718-b900-332502355f38, 153462d0-a9b8-4b5b-8175-9e4b05e9b856 \ -| None | -+--------------------------------------+------------------+-------+----------+\ ----------+------------+-------------------------------------------------------\ ------------------------------------------------+------------------+ -''', sys.stdout.getvalue()) - - -class ShellQueryAlarmHistoryCommandTest(utils.BaseTestCase): - - ALARM_HISTORY = [{"alarm_id": "e8ff32f772a44a478182c3fe1f7cad6a", - "event_id": "c74a8611-6553-4764-a860-c15a6aabb5d0", - "detail": - "{\"threshold\": 42.0, \"evaluation_periods\": 4}", - "on_behalf_of": "92159030020611e3b26dde429e99ee8c", - "project_id": "b6f16144010811e387e4de429e99ee8c", - "timestamp": "2014-03-11T16:02:58.376261", - "type": "rule change", - "user_id": "3e5d11fda79448ac99ccefb20be187ca" - }] - - QUERY = {"filter": {"and": [{">": {"timestamp": "2014-03-11T16:02:58"}}, - {"=": {"type": "rule change"}}]}, - "orderby": [{"timestamp": "desc"}], - "limit": 10} - - def setUp(self): - super(ShellQueryAlarmHistoryCommandTest, self).setUp() - self.cc = mock.Mock() - self.args = mock.Mock() - self.args.filter = self.QUERY["filter"] - self.args.orderby = self.QUERY["orderby"] - self.args.limit = self.QUERY["limit"] - - @mock.patch('sys.stdout', new=six.StringIO()) - def test_query(self): - ret_alarm_history = [alarms.AlarmChange(mock.Mock(), alarm_history) - for alarm_history in self.ALARM_HISTORY] - self.cc.query_alarm_history.query.return_value = ret_alarm_history - - ceilometer_shell.do_query_alarm_history(self.cc, self.args) - - self.assertEqual('''\ -+----------------------------------+--------------------------------------+-\ -------------+----------------------------------------------+----------------\ -------------+ -| Alarm ID | Event ID | \ -Type | Detail | Timestamp \ - | -+----------------------------------+--------------------------------------+-\ -------------+----------------------------------------------+----------------\ -------------+ -| e8ff32f772a44a478182c3fe1f7cad6a | c74a8611-6553-4764-a860-c15a6aabb5d0 | \ -rule change | {"threshold": 42.0, "evaluation_periods": 4} | 2014-03-11T16:0\ -2:58.376261 | -+----------------------------------+--------------------------------------+-\ -------------+----------------------------------------------+----------------\ -------------+ -''', sys.stdout.getvalue()) - - -class ShellStatisticsTest(utils.BaseTestCase): - def setUp(self): - super(ShellStatisticsTest, self).setUp() - self.cc = mock.Mock() - self.displays = { - 'duration': 'Duration', - 'duration_end': 'Duration End', - 'duration_start': 'Duration Start', - 'period': 'Period', - 'period_end': 'Period End', - 'period_start': 'Period Start', - 'groupby': 'Group By', - 'avg': 'Avg', - 'count': 'Count', - 'max': 'Max', - 'min': 'Min', - 'sum': 'Sum', - 'stddev': 'Standard deviation', - 'cardinality': 'Cardinality' - } - self.args = mock.Mock() - self.args.meter_name = 'instance' - self.args.aggregate = [] - self.args.groupby = None - self.args.query = None - - def test_statistics_list_simple(self): - samples = [ - {u'count': 135, - u'duration_start': u'2013-02-04T10:51:42', - u'min': 1.0, - u'max': 1.0, - u'duration_end': - u'2013-02-05T15:46:09', - u'duration': 1734.0, - u'avg': 1.0, - u'sum': 135.0}, - ] - fields = [ - 'period', - 'period_start', - 'period_end', - 'max', - 'min', - 'avg', - 'sum', - 'count', - 'duration', - 'duration_start', - 'duration_end', - ] - statistics_ret = [ - statistics.Statistics(mock.Mock(), sample) for sample in samples - ] - self.cc.statistics.list.return_value = statistics_ret - with mock.patch('ceilometerclient.v2.shell.utils.print_list') as pmock: - ceilometer_shell.do_statistics(self.cc, self.args) - pmock.assert_called_with( - statistics_ret, - fields, - [self.displays[f] for f in fields] - ) - - def test_statistics_list_groupby(self): - samples = [ - {u'count': 135, - u'duration_start': u'2013-02-04T10:51:42', - u'min': 1.0, - u'max': 1.0, - u'duration_end': - u'2013-02-05T15:46:09', - u'duration': 1734.0, - u'avg': 1.0, - u'sum': 135.0, - u'groupby': {u'resource_id': u'foo'} - }, - {u'count': 12, - u'duration_start': u'2013-02-04T10:51:42', - u'min': 1.0, - u'max': 1.0, - u'duration_end': - u'2013-02-05T15:46:09', - u'duration': 1734.0, - u'avg': 1.0, - u'sum': 12.0, - u'groupby': {u'resource_id': u'bar'} - }, - ] - fields = [ - 'period', - 'period_start', - 'period_end', - 'groupby', - 'max', - 'min', - 'avg', - 'sum', - 'count', - 'duration', - 'duration_start', - 'duration_end', - ] - self.args.groupby = 'resource_id' - statistics_ret = [ - statistics.Statistics(mock.Mock(), sample) for sample in samples - ] - self.cc.statistics.list.return_value = statistics_ret - with mock.patch('ceilometerclient.v2.shell.utils.print_list') as pmock: - ceilometer_shell.do_statistics(self.cc, self.args) - pmock.assert_called_with( - statistics_ret, - fields, - [self.displays[f] for f in fields], - ) - - def test_statistics_list_aggregates(self): - samples = [ - {u'aggregate': {u'cardinality/resource_id': 4.0, u'count': 2.0}, - u'count': 2, - u'duration': 0.442451, - u'duration_end': u'2014-03-12T14:00:21.774154', - u'duration_start': u'2014-03-12T14:00:21.331703', - u'groupby': None, - u'period': 0, - u'period_end': u'2014-03-12T14:00:21.774154', - u'period_start': u'2014-03-12T14:00:21.331703', - u'unit': u'instance', - }, - ] - fields = [ - 'period', - 'period_start', - 'period_end', - 'count', - 'cardinality/resource_id', - 'duration', - 'duration_start', - 'duration_end', - ] - self.args.aggregate = ['count', 'cardinality<-resource_id'] - statistics_ret = [ - statistics.Statistics(mock.Mock(), sample) for sample in samples - ] - self.cc.statistics.list.return_value = statistics_ret - with mock.patch('ceilometerclient.v2.shell.utils.print_list') as pmock: - ceilometer_shell.do_statistics(self.cc, self.args) - pmock.assert_called_with( - statistics_ret, - fields, - [self.displays.get(f, f) for f in fields], - ) - - -class ShellEmptyIdTest(utils.BaseTestCase): - """Test empty field which will cause calling incorrect rest uri.""" - - def _test_entity_action_with_empty_values(self, entity, - *args, **kwargs): - positional = kwargs.pop('positional', False) - for value in ('', ' ', ' ', '\t'): - self._test_entity_action_with_empty_value(entity, value, - positional, *args) - - def _test_entity_action_with_empty_value(self, entity, value, - positional, *args): - new_args = [value] if positional else ['--%s' % entity, value] - argv = list(args) + new_args - shell = base_shell.CeilometerShell() - with mock.patch('ceilometerclient.exc.CommandError') as e: - e.return_value = exc.BaseException() - self.assertRaises(exc.BaseException, shell.parse_args, argv) - entity = entity.replace('-', '_') - e.assert_called_with('%s should not be empty' % entity) - - def _test_alarm_action_with_empty_ids(self, method, *args): - args = [method] + list(args) - self._test_entity_action_with_empty_values('alarm_id', - positional=True, *args) - - def test_alarm_show_with_empty_id(self): - self._test_alarm_action_with_empty_ids('alarm-show') - - def test_alarm_update_with_empty_id(self): - self._test_alarm_action_with_empty_ids('alarm-update') - - def test_alarm_threshold_update_with_empty_id(self): - self._test_alarm_action_with_empty_ids('alarm-threshold-update') - - def test_alarm_combination_update_with_empty_id(self): - self._test_alarm_action_with_empty_ids('alarm-combination-update') - - def test_alarm_delete_with_empty_id(self): - self._test_alarm_action_with_empty_ids('alarm-delete') - - def test_alarm_state_get_with_empty_id(self): - self._test_alarm_action_with_empty_ids('alarm-state-get') - - def test_alarm_state_set_with_empty_id(self): - args = ['alarm-state-set', '--state', 'ok'] - self._test_alarm_action_with_empty_ids(*args) - - def test_alarm_history_with_empty_id(self): - self._test_alarm_action_with_empty_ids('alarm-history') - - def test_event_show_with_empty_message_id(self): - args = ['event-show'] - self._test_entity_action_with_empty_values('message_id', *args) - - def test_resource_show_with_empty_id(self): - args = ['resource-show'] - self._test_entity_action_with_empty_values('resource_id', *args) - - def test_sample_list_with_empty_meter(self): - args = ['sample-list'] - self._test_entity_action_with_empty_values('meter', *args) - - def test_sample_create_with_empty_meter(self): - args = ['sample-create', '-r', 'x', '--meter-type', 'gauge', - '--meter-unit', 'B', '--sample-volume', '1'] - self._test_entity_action_with_empty_values('meter-name', *args) - - def test_statistics_with_empty_meter(self): - args = ['statistics'] - self._test_entity_action_with_empty_values('meter', *args) - - def test_trait_description_list_with_empty_event_type(self): - args = ['trait-description-list'] - self._test_entity_action_with_empty_values('event_type', *args) - - def test_trait_list_with_empty_event_type(self): - args = ['trait-list', '--trait_name', 'x'] - self._test_entity_action_with_empty_values('event_type', *args) - - def test_trait_list_with_empty_trait_name(self): - args = ['trait-list', '--event_type', 'x'] - self._test_entity_action_with_empty_values('trait_name', *args) - - -class ShellObsoletedArgsTest(utils.BaseTestCase): - """Test arguments that have been obsoleted.""" - - def _test_entity_obsoleted(self, entity, value, positional, *args): - new_args = [value] if positional else ['--%s' % entity, value] - argv = list(args) + new_args - shell = base_shell.CeilometerShell() - with mock.patch('sys.stdout', new_callable=six.StringIO) as stdout: - shell.parse_args(argv) - self.assertIn('obsolete', stdout.getvalue()) - - def test_obsolete_alarm_id(self): - for method in ['alarm-show', 'alarm-update', 'alarm-threshold-update', - 'alarm-combination-update', 'alarm-delete', - 'alarm-state-get', 'alarm-history']: - self._test_entity_obsoleted('alarm_id', 'abcde', False, method) - - -class ShellEventListCommandTest(utils.BaseTestCase): - - EVENTS = [ - { - "traits": [], - "generated": "2015-01-12T04:03:25.741471", - "message_id": "fb2bef58-88af-4380-8698-e0f18fcf452d", - "event_type": "compute.instance.create.start", - "traits": [{ - "name": "state", - "type": "string", - "value": "building", - }], - }, - { - "traits": [], - "generated": "2015-01-12T04:03:28.452495", - "message_id": "9b20509a-576b-4995-acfa-1a24ee5cf49f", - "event_type": "compute.instance.create.end", - "traits": [{ - "name": "state", - "type": "string", - "value": "active", - }], - }, - ] - - def setUp(self): - super(ShellEventListCommandTest, self).setUp() - self.cc = mock.Mock() - self.args = mock.Mock() - self.args.query = None - self.args.no_traits = None - - @mock.patch('sys.stdout', new=six.StringIO()) - def test_event_list(self): - ret_events = [events.Event(mock.Mock(), event) - for event in self.EVENTS] - self.cc.events.list.return_value = ret_events - ceilometer_shell.do_event_list(self.cc, self.args) - self.assertEqual('''\ -+--------------------------------------+-------------------------------+\ -----------------------------+-------------------------------+ -| Message ID | Event Type |\ - Generated | Traits | -+--------------------------------------+-------------------------------+\ -----------------------------+-------------------------------+ -| fb2bef58-88af-4380-8698-e0f18fcf452d | compute.instance.create.start |\ - 2015-01-12T04:03:25.741471 | +-------+--------+----------+ | -| | |\ - | | name | type | value | | -| | |\ - | +-------+--------+----------+ | -| | |\ - | | state | string | building | | -| | |\ - | +-------+--------+----------+ | -| 9b20509a-576b-4995-acfa-1a24ee5cf49f | compute.instance.create.end |\ - 2015-01-12T04:03:28.452495 | +-------+--------+--------+ | -| | |\ - | | name | type | value | | -| | |\ - | +-------+--------+--------+ | -| | |\ - | | state | string | active | | -| | |\ - | +-------+--------+--------+ | -+--------------------------------------+-------------------------------+\ -----------------------------+-------------------------------+ -''', sys.stdout.getvalue()) - - @mock.patch('sys.stdout', new=six.StringIO()) - def test_event_list_no_traits(self): - self.args.no_traits = True - ret_events = [events.Event(mock.Mock(), event) - for event in self.EVENTS] - self.cc.events.list.return_value = ret_events - ceilometer_shell.do_event_list(self.cc, self.args) - self.assertEqual('''\ -+--------------------------------------+-------------------------------\ -+----------------------------+ -| Message ID | Event Type \ -| Generated | -+--------------------------------------+-------------------------------\ -+----------------------------+ -| fb2bef58-88af-4380-8698-e0f18fcf452d | compute.instance.create.start \ -| 2015-01-12T04:03:25.741471 | -| 9b20509a-576b-4995-acfa-1a24ee5cf49f | compute.instance.create.end \ -| 2015-01-12T04:03:28.452495 | -+--------------------------------------+-------------------------------\ -+----------------------------+ -''', sys.stdout.getvalue()) - - -class ShellShadowedArgsTest(test_shell.ShellTestBase): - - def _test_project_id_alarm(self, command, args, method): - self.make_env(test_shell.FAKE_V2_ENV) - cli_args = [ - '--os-project-id', '0ba30185ddf44834914a0b859d244c56', - '--debug', command, - '--project-id', 'the-project-id-i-want-to-set', - '--name', 'project-id-test'] + args - with mock.patch.object(alarms.AlarmManager, method) as mocked: - base_shell.main(cli_args) - args, kwargs = mocked.call_args - self.assertEqual('the-project-id-i-want-to-set', - kwargs.get('project_id')) - - def test_project_id_threshold_alarm(self): - cli_args = ['--meter-name', 'cpu', '--threshold', '90'] - self._test_project_id_alarm('alarm-create', cli_args, 'create') - self._test_project_id_alarm('alarm-threshold-create', - cli_args, 'create') - cli_args += ['--alarm_id', '437b7ed0-3733-4054-a877-e9a297b8be85'] - self._test_project_id_alarm('alarm-update', cli_args, 'update') - self._test_project_id_alarm('alarm-threshold-update', - cli_args, 'update') - - def test_project_id_combination_alarm(self): - cli_args = ['--alarm_ids', 'fb16a05a-669d-414e-8bbe-93aa381df6a8', - '--alarm_ids', 'b189bcca-0a7b-49a9-a244-a927ac291881'] - self._test_project_id_alarm('alarm-combination-create', - cli_args, 'create') - cli_args += ['--alarm_id', '437b7ed0-3733-4054-a877-e9a297b8be85'] - self._test_project_id_alarm('alarm-combination-update', - cli_args, 'update') - - @mock.patch.object(samples.OldSampleManager, 'create') - def test_project_id_sample_create(self, mocked): - self.make_env(test_shell.FAKE_V2_ENV) - cli_args = [ - '--os-project-id', '0ba30185ddf44834914a0b859d244c56', - '--debug', 'sample-create', - '--project-id', 'the-project-id-i-want-to-set', - '--resource-id', 'b666633d-9bb6-4e05-89c0-ee5a8752fb0b', - '--meter-name', 'cpu', - '--meter-type', 'cumulative', - '--meter-unit', 'ns', - '--sample-volume', '10086', - ] - base_shell.main(cli_args) - args, kwargs = mocked.call_args - self.assertEqual('the-project-id-i-want-to-set', - kwargs.get('project_id')) diff --git a/ceilometerclient/tests/v2/test_statistics.py b/ceilometerclient/tests/v2/test_statistics.py deleted file mode 100644 index 65f633e..0000000 --- a/ceilometerclient/tests/v2/test_statistics.py +++ /dev/null @@ -1,224 +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 ceilometerclient.openstack.common.apiclient import client -from ceilometerclient.openstack.common.apiclient import fake_client -from ceilometerclient.tests import utils -import ceilometerclient.v2.statistics - -base_url = '/v2/meters/instance/statistics' -qry = ('q.field=resource_id&q.field=source&q.op=&q.op=' - '&q.type=&q.type=&q.value=foo&q.value=bar') -period = '&period=60' -groupby = '&groupby=resource_id' -aggregate_query = ("aggregate.func=cardinality&aggregate.param=resource_id" - "&aggregate.func=count") -samples = [ - {u'count': 135, - u'duration_start': u'2013-02-04T10:51:42', - u'min': 1.0, - u'max': 1.0, - u'duration_end': - u'2013-02-05T15:46:09', - u'duration': 1734.0, - u'avg': 1.0, - u'sum': 135.0}, -] -groupby_samples = [ - {u'count': 135, - u'duration_start': u'2013-02-04T10:51:42', - u'min': 1.0, - u'max': 1.0, - u'duration_end': - u'2013-02-05T15:46:09', - u'duration': 1734.0, - u'avg': 1.0, - u'sum': 135.0, - u'groupby': {u'resource_id': u'foo'} - }, - {u'count': 12, - u'duration_start': u'2013-02-04T10:51:42', - u'min': 1.0, - u'max': 1.0, - u'duration_end': - u'2013-02-05T15:46:09', - u'duration': 1734.0, - u'avg': 1.0, - u'sum': 12.0, - u'groupby': {u'resource_id': u'bar'} - }, -] -aggregate_samples = [ - {u'aggregate': {u'cardinality/resource_id': 4.0, u'count': 2.0}, - u'count': 2, - u'duration': 0.442451, - u'duration_end': u'2014-03-12T14:00:21.774154', - u'duration_start': u'2014-03-12T14:00:21.331703', - u'groupby': None, - u'period': 0, - u'period_end': u'2014-03-12T14:00:21.774154', - u'period_start': u'2014-03-12T14:00:21.331703', - u'unit': u'instance', - }, -] -fixtures = { - base_url: - { - 'GET': ( - {}, - samples - ), - }, - '%s?%s' % (base_url, qry): - { - 'GET': ( - {}, - samples - ), - }, - '%s?%s%s' % (base_url, qry, period): - { - 'GET': ( - {}, - samples - ), - }, - '%s?%s%s' % (base_url, qry, groupby): - { - 'GET': ( - {}, - groupby_samples - ), - }, - '%s?%s' % (base_url, aggregate_query): - { - 'GET': ( - {}, - aggregate_samples - ), - } -} - - -class StatisticsManagerTest(utils.BaseTestCase): - - def setUp(self): - super(StatisticsManagerTest, self).setUp() - self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) - self.api = client.BaseClient(self.http_client) - self.mgr = ceilometerclient.v2.statistics.StatisticsManager(self.api) - - def test_list_by_meter_name(self): - stats = list(self.mgr.list(meter_name='instance')) - expect = [ - 'GET', '/v2/meters/instance/statistics' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(stats), 1) - self.assertEqual(stats[0].count, 135) - - def test_list_by_meter_name_extended(self): - stats = list(self.mgr.list(meter_name='instance', - q=[ - {"field": "resource_id", - "value": "foo"}, - {"field": "source", - "value": "bar"}, - ])) - expect = [ - 'GET', '%s?%s' % (base_url, qry) - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(stats), 1) - self.assertEqual(stats[0].count, 135) - - def test_list_by_meter_name_with_period(self): - stats = list(self.mgr.list(meter_name='instance', - q=[ - {"field": "resource_id", - "value": "foo"}, - {"field": "source", - "value": "bar"}, - ], - period=60)) - expect = [ - 'GET', '%s?%s%s' % (base_url, qry, period) - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(stats), 1) - self.assertEqual(stats[0].count, 135) - - def test_list_by_meter_name_with_groupby(self): - stats = list(self.mgr.list(meter_name='instance', - q=[ - {"field": "resource_id", - "value": "foo"}, - {"field": "source", - "value": "bar"}, - ], - groupby=['resource_id'])) - expect = [ - 'GET', - '%s?%s%s' % (base_url, qry, groupby) - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(stats), 2) - self.assertEqual(stats[0].count, 135) - self.assertEqual(stats[1].count, 12) - self.assertEqual(stats[0].groupby.get('resource_id'), 'foo') - self.assertEqual(stats[1].groupby.get('resource_id'), 'bar') - - def test_list_by_meter_name_with_groupby_as_str(self): - stats = list(self.mgr.list(meter_name='instance', - q=[ - {"field": "resource_id", - "value": "foo"}, - {"field": "source", - "value": "bar"}, - ], - groupby='resource_id')) - expect = [ - 'GET', - '%s?%s%s' % (base_url, qry, groupby) - ] - self.http_client.assert_called(*expect) - self.assertEqual(2, len(stats)) - self.assertEqual(135, stats[0].count) - self.assertEqual(12, stats[1].count) - self.assertEqual('foo', stats[0].groupby.get('resource_id')) - self.assertEqual('bar', stats[1].groupby.get('resource_id')) - - def test_list_by_meter_name_with_aggregates(self): - aggregates = [ - { - 'func': 'count', - }, - { - 'func': 'cardinality', - 'param': 'resource_id', - }, - ] - stats = list(self.mgr.list(meter_name='instance', - aggregates=aggregates)) - expect = [ - 'GET', - '%s?%s' % (base_url, aggregate_query) - ] - self.http_client.assert_called(*expect) - self.assertEqual(1, len(stats)) - self.assertEqual(2, stats[0].count) - self.assertEqual(2.0, stats[0].aggregate.get('count')) - self.assertEqual(4.0, stats[0].aggregate.get( - 'cardinality/resource_id', - )) diff --git a/ceilometerclient/tests/v2/test_trait_descriptions.py b/ceilometerclient/tests/v2/test_trait_descriptions.py deleted file mode 100644 index 7913124..0000000 --- a/ceilometerclient/tests/v2/test_trait_descriptions.py +++ /dev/null @@ -1,56 +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. -from ceilometerclient.openstack.common.apiclient import client -from ceilometerclient.openstack.common.apiclient import fake_client -from ceilometerclient.tests import utils -import ceilometerclient.v2.trait_descriptions - - -fixtures = { - '/v2/event_types/Foo/traits': { - 'GET': ( - {}, - [ - {'name': 'trait_1', 'type': 'string'}, - {'name': 'trait_2', 'type': 'integer'}, - {'name': 'trait_3', 'type': 'datetime'} - ] - ), - } -} - - -class TraitDescriptionManagerTest(utils.BaseTestCase): - - def setUp(self): - super(TraitDescriptionManagerTest, self).setUp() - self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) - self.api = client.BaseClient(self.http_client) - self.mgr = (ceilometerclient.v2.trait_descriptions. - TraitDescriptionManager(self.api)) - - def test_list(self): - trait_descriptions = list(self.mgr.list('Foo')) - expect = [ - 'GET', '/v2/event_types/Foo/traits' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(trait_descriptions), 3) - for i, vals in enumerate([('trait_1', 'string'), - ('trait_2', 'integer'), - ('trait_3', 'datetime')]): - - name, type = vals - self.assertEqual(trait_descriptions[i].name, name) - self.assertEqual(trait_descriptions[i].type, type) diff --git a/ceilometerclient/tests/v2/test_traits.py b/ceilometerclient/tests/v2/test_traits.py deleted file mode 100644 index 1d7dde0..0000000 --- a/ceilometerclient/tests/v2/test_traits.py +++ /dev/null @@ -1,62 +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. -from ceilometerclient.openstack.common.apiclient import client -from ceilometerclient.openstack.common.apiclient import fake_client -from ceilometerclient.tests import utils -import ceilometerclient.v2.traits - - -fixtures = { - '/v2/event_types/Foo/traits/trait_1': { - 'GET': ( - {}, - [ - {'name': 'trait_1', - 'type': 'datetime', - 'value': '2014-01-07T17:22:10.925553'}, - {'name': 'trait_1', - 'type': 'datetime', - 'value': '2014-01-07T17:23:10.925553'} - ] - ), - } -} - - -class TraitManagerTest(utils.BaseTestCase): - - def setUp(self): - super(TraitManagerTest, self).setUp() - self.http_client = fake_client.FakeHTTPClient(fixtures=fixtures) - self.api = client.BaseClient(self.http_client) - self.mgr = ceilometerclient.v2.traits.TraitManager(self.api) - - def test_list(self): - traits = list(self.mgr.list('Foo', 'trait_1')) - expect = [ - 'GET', '/v2/event_types/Foo/traits/trait_1' - ] - self.http_client.assert_called(*expect) - self.assertEqual(len(traits), 2) - for i, vals in enumerate([('trait_1', - 'datetime', - '2014-01-07T17:22:10.925553'), - ('trait_1', - 'datetime', - '2014-01-07T17:23:10.925553')]): - - name, type, value = vals - self.assertEqual(traits[i].name, name) - self.assertEqual(traits[i].type, type) - self.assertEqual(traits[i].value, value) -- cgit v1.2.1