diff --git a/distilclient/common/apiclient/base.py b/distilclient/common/apiclient/base.py index 97e3d96..58c62a4 100644 --- a/distilclient/common/apiclient/base.py +++ b/distilclient/common/apiclient/base.py @@ -30,8 +30,8 @@ from oslo_utils import strutils import six from six.moves.urllib import parse -from distilclient.i18n import _ from distilclient.common.apiclient import exceptions +from distilclient.i18n import _ def getid(obj): diff --git a/distilclient/common/apiclient/client.py b/distilclient/common/apiclient/client.py index c293dc0..6df5746 100644 --- a/distilclient/common/apiclient/client.py +++ b/distilclient/common/apiclient/client.py @@ -36,8 +36,8 @@ except ImportError: from oslo_utils import importutils import requests -from distilclient.i18n import _ from distilclient.common.apiclient import exceptions +from distilclient.i18n import _ _logger = logging.getLogger(__name__) diff --git a/distilclient/common/apiclient/utils.py b/distilclient/common/apiclient/utils.py index 1be70d6..1b818a5 100644 --- a/distilclient/common/apiclient/utils.py +++ b/distilclient/common/apiclient/utils.py @@ -15,8 +15,8 @@ from oslo_utils import encodeutils from oslo_utils import uuidutils import six -from distilclient.i18n import _ from distilclient.common.apiclient import exceptions +from distilclient.i18n import _ def find_resource(manager, name_or_id, **find_args): diff --git a/distilclient/shell.py b/distilclient/shell.py index 3c1c119..1a74e03 100644 --- a/distilclient/shell.py +++ b/distilclient/shell.py @@ -12,15 +12,17 @@ # License for the specific language governing permissions and limitations # under the License. -import os -import json -import sys -from client import Client + import exc +import json +import os +import sys from keystoneauth1.identity import generic from keystoneauth1 import session +from client import Client + def main(): import argparse @@ -233,19 +235,19 @@ def main(): if args.command == 'collect-usage': response = client.collect_usage() - print json.dumps(response, indent=2) + print(json.dumps(response, indent=2)) if args.command == 'last-collected': response = client.last_collected() - print json.dumps(response, indent=2) + print(json.dumps(response, indent=2)) if args.command == 'get-usage': response = client.get_usage(args.project, args.start, args.end) - print json.dumps(response, indent=2) + print(json.dumps(response, indent=2)) if args.command == 'get-rated': response = client.get_rated(args.project, args.start, args.end) - print json.dumps(response, indent=2) + print(json.dumps(response, indent=2)) if __name__ == '__main__': diff --git a/distilclient/tests/unit/test_client.py b/distilclient/tests/unit/test_client.py index e0de8a7..663c27d 100644 --- a/distilclient/tests/unit/test_client.py +++ b/distilclient/tests/unit/test_client.py @@ -23,7 +23,7 @@ import distilclient.v2.client @ddt.ddt class ClientTest(utils.TestCase): - @mock.patch.object(distilclient.v1.client, 'Client') + @mock.patch("distilclient.v1.client.Client") def test_init_client_with_string_v1_version(self, mock_client): mock_client('1', 'foo', auth_url='quuz') mock_client.assert_called_once_with('1', 'foo', auth_url='quuz') diff --git a/distilclient/tests/unit/v1/__init__.py b/distilclient/tests/unit/v1/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/distilclient/tests/unit/v1/test_client.py b/distilclient/tests/unit/v1/test_client.py new file mode 100644 index 0000000..bf652fd --- /dev/null +++ b/distilclient/tests/unit/v1/test_client.py @@ -0,0 +1,96 @@ +# 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 mock + +from distilclient.tests.unit import utils +from distilclient.v1 import client as v1_client + + +class FakeResponse(object): + status_code = 200 + result = {} + + def __init__(self, status_code, result): + self.status_code = status_code + self.result = result + + def json(self): + return self.result + + +class ClientTest(utils.TestCase): + + def setUp(self): + super(ClientTest, self).setUp() + self.tenant = 'fake_tenant' + self.start = "2017-01-01" + self.end = "2017-02-01" + self.distil_url = "http://127.0.0.1:9999/v2" + + @mock.patch("keystoneauth1.identity.generic.Password.get_token") + @mock.patch("requests.post") + def test_collect_usage(self, mock_post, mock_get_token): + mock_get_token.return_value = 'fake_token' + mock_post.return_value = FakeResponse(200, {}) + client = v1_client.HTTPClient(distil_url=self.distil_url) + client.collect_usage() + expect_url = 'http://127.0.0.1:9999/collect_usage' + expect_headers = {'X-Auth-Token': 'fake_token', + 'Content-Type': 'application/json'} + mock_post.assert_called_once_with(expect_url, + headers=expect_headers, + verify=True) + + @mock.patch("keystoneauth1.identity.generic.Password.get_token") + @mock.patch("requests.get") + def test_last_collected(self, mock_get, mock_get_token): + mock_get_token.return_value = 'fake_token' + mock_get.return_value = FakeResponse(200, {}) + client = v1_client.HTTPClient(distil_url=self.distil_url) + client.last_collected() + expect_url = 'http://127.0.0.1:9999/last_collected' + expect_headers = {'X-Auth-Token': 'fake_token', + 'Content-Type': 'application/json'} + mock_get.assert_called_once_with(expect_url, + headers=expect_headers, + verify=True) + + @mock.patch("keystoneauth1.identity.generic.Password.get_token") + @mock.patch("requests.get") + def test_get_rated(self, mock_get, mock_get_token): + mock_get_token.return_value = 'fake_token' + mock_get.return_value = FakeResponse(200, {}) + client = v1_client.HTTPClient(distil_url=self.distil_url) + client.get_rated(self.tenant, self.start, self.end) + mock_get.assert_called_once_with('http://127.0.0.1:9999/get_rated', + headers={'X-Auth-Token': + 'fake_token'}, + params={'tenant': 'fake_tenant', + 'end': '2017-02-01', + 'start': '2017-01-01'}, + verify=True) + + @mock.patch("keystoneauth1.identity.generic.Password.get_token") + @mock.patch("requests.get") + def test_get_usage(self, mock_get, mock_get_token): + mock_get_token.return_value = 'fake_token' + mock_get.return_value = FakeResponse(200, {}) + client = v1_client.HTTPClient(distil_url=self.distil_url) + client.get_usage(self.tenant, self.start, self.end) + mock_get.assert_called_once_with('http://127.0.0.1:9999/get_usage', + headers={'X-Auth-Token': + 'fake_token'}, + params={'tenant': 'fake_tenant', + 'end': '2017-02-01', + 'start': '2017-01-01'}, + verify=True) diff --git a/distilclient/v1/client.py b/distilclient/v1/client.py index 9214839..d763d72 100644 --- a/distilclient/v1/client.py +++ b/distilclient/v1/client.py @@ -14,7 +14,8 @@ import requests from requests.exceptions import ConnectionError -from urlparse import urljoin + +import six.moves.urllib.parse as urlparse from keystoneauth1 import adapter from keystoneauth1.identity import generic @@ -138,7 +139,7 @@ class HTTPClient(object): region_name=os_region_name) def collect_usage(self): - url = urljoin(self.endpoint, "collect_usage") + url = urlparse.urljoin(self.endpoint, "collect_usage") headers = {"Content-Type": "application/json", "X-Auth-Token": self.auth_token} @@ -152,10 +153,10 @@ class HTTPClient(object): else: return response.json() except ConnectionError as e: - print e + print(e) def last_collected(self): - url = urljoin(self.endpoint, "last_collected") + url = urlparse.urljoin(self.endpoint, "last_collected") headers = {"Content-Type": "application/json", "X-Auth-Token": self.auth_token} @@ -169,7 +170,7 @@ class HTTPClient(object): else: return response.json() except ConnectionError as e: - print e + print(e) def get_usage(self, tenant, start, end): return self._query_usage(tenant, start, end, "get_usage") @@ -178,7 +179,7 @@ class HTTPClient(object): return self._query_usage(tenant, start, end, "get_rated") def _query_usage(self, tenant, start, end, endpoint): - url = urljoin(self.endpoint, endpoint) + url = urlparse.urljoin(self.endpoint, endpoint) headers = {"X-Auth-Token": self.auth_token} @@ -197,4 +198,4 @@ class HTTPClient(object): else: return response.json() except ConnectionError as e: - print e + print(e) diff --git a/distilclient/v2/measurements.py b/distilclient/v2/measurements.py index 72789e2..5b7ea2b 100644 --- a/distilclient/v2/measurements.py +++ b/distilclient/v2/measurements.py @@ -19,6 +19,7 @@ class MeasurementManager(base.Manager): def list(self, project_id, start, end): """Retrieve a list of measurements. + :returns: A list of measurements. """ url = "/v2/measurements?project_id={0}&start={1}&end={2}" diff --git a/test-requirements.txt b/test-requirements.txt index 569522e..2d1a31b 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -2,11 +2,10 @@ # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. hacking>=0.11.0,<0.12 # Apache-2.0 - coverage>=3.6 # Apache-2.0 +ddt>=1.0.1 # MIT discover # BSD fixtures>=3.0.0 # Apache-2.0/BSD -keyring>=5.5.1 # MIT/PSF mock>=2.0 # BSD requests-mock>=0.7.0 # Apache-2.0 sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 # BSD @@ -19,6 +18,4 @@ tempest>=11.0.0 # Apache-2.0 os-testr>=0.8.0 # Apache-2.0 # releasenotes -reno>=1.6.2 # Apache2 - -ddt>=1.0.1 # MIT \ No newline at end of file +reno>=1.6.2 # Apache2 \ No newline at end of file diff --git a/tox.ini b/tox.ini index 86bb33b..98984dc 100644 --- a/tox.ini +++ b/tox.ini @@ -1,19 +1,15 @@ [tox] minversion = 1.6 -envlist = py34,py27,pep8 +envlist = py35,py27,pep8 skipsdist = True [testenv] usedevelop = True -# Customize pip command, add -U to force updates. -install_command = pip install -U {opts} {packages} +install_command = pip install -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages} setenv = VIRTUAL_ENV={envdir} - NOSE_WITH_OPENSTACK=1 - NOSE_OPENSTACK_COLOR=1 - NOSE_OPENSTACK_RED=0.05 - NOSE_OPENSTACK_YELLOW=0.025 - NOSE_OPENSTACK_SHOW_ELAPSED=1 - NOSE_OPENSTACK_STDOUT=1 + OS_STDOUT_NOCAPTURE=False + OS_STDERR_NOCAPTURE=False + PYTHONHASHSEED=0 deps = -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt commands = ostestr {posargs} @@ -36,15 +32,6 @@ commands = {posargs} commands = python setup.py build_sphinx [flake8] -# Following checks should be enabled in the future. -# -# H404 multi line docstring should start without a leading new line -# H405 multi line docstring summary not separated with an empty line -# -# Following checks are ignored on purpose. -# -# Additional checks are also ignored on purpose: F811, F821 -ignore = F811,F821,H404,H405,H233,H306,E265,W291,W391,F841 show-source = True exclude=.venv,.git,.tox,dist,*lib/python*,*egg,build,doc/source/conf.py,releasenotes