diff -Nru python-keystoneclient-3.17.0/AUTHORS python-keystoneclient-3.18.0/AUTHORS --- python-keystoneclient-3.17.0/AUTHORS 2018-06-20 23:17:42.000000000 +0000 +++ python-keystoneclient-3.18.0/AUTHORS 2018-10-24 17:19:40.000000000 +0000 @@ -62,6 +62,7 @@ Deepti Ramakrishna Derek Higgins DhritiShikhar +Dinesh Bhor Dirk Mueller Divyesh Khandeshi Dolph Mathews @@ -135,6 +136,7 @@ Lin Hua Cheng Lorin Hochstein M V P Nitesh +Maho Koshiya Marek Denis Mark McLoughlin MarounMaroun @@ -217,7 +219,9 @@ Victor Morales Victor Silva Victor Stinner +Vieri <15050873171@163.com> Vincent Untz +Vishakha Agarwal Vishvananda Ishaya Vu Cong Tuan Wu Wenxiang @@ -236,10 +240,10 @@ Zhongyue Luo Zhongyue Luo Ziad Sawalha -Zuul ankitagrawal chenaidong1 chenxiao +chenxing daniel-a-nguyen dineshbhor fujioka yuuichi @@ -259,6 +263,7 @@ liuqing llg8212 lrqrun +lvxianguo mathrock melissaml nachiappan-veerappan-nachiappan @@ -272,10 +277,12 @@ venkatamahesh wanghong wingwj +wu.chunyang xingzhou yuyafei zhang-jinnan zhangyanxian zheng yin zhiyuan_cai +zhubx007 zlyqqq diff -Nru python-keystoneclient-3.17.0/ChangeLog python-keystoneclient-3.18.0/ChangeLog --- python-keystoneclient-3.17.0/ChangeLog 2018-06-20 23:17:42.000000000 +0000 +++ python-keystoneclient-3.18.0/ChangeLog 2018-10-24 17:19:40.000000000 +0000 @@ -1,9 +1,27 @@ CHANGES ======= +3.18.0 +------ + +* Don't quote {posargs} in tox.ini +* Deprecate region enabled parameter +* Import legacy keystoneclient-dsvm-functional +* Use templates for cover and lower-constraints +* add lib-forward-testing-python3 test job +* add python 3.6 unit test job +* switch documentation job to new PTI +* import zuul job settings from project-config +* fix misspelling of 'default' +* Update reno for stable/rocky +* refactor the getid method in keystoneclient/base.py +* Switch to stestr +* Add release note link in README + 3.17.0 ------ +* Update IdentityProviderManager docstring * Add support for project-specific limits * Add support for registered limits * Fix python3 test compat @@ -16,6 +34,8 @@ ------ * add lower-constraints job +* Add return-request-id-to-caller function(v3) +* Add Response class to return request-id to caller * Updated from global requirements * Updated from global requirements * Update links in README diff -Nru python-keystoneclient-3.17.0/debian/changelog python-keystoneclient-3.18.0/debian/changelog --- python-keystoneclient-3.17.0/debian/changelog 2018-07-30 21:35:45.000000000 +0000 +++ python-keystoneclient-3.18.0/debian/changelog 2018-11-14 18:22:45.000000000 +0000 @@ -1,3 +1,11 @@ +python-keystoneclient (1:3.18.0-0ubuntu1) disco; urgency=medium + + * New upstream release for OpenStack Stein. + * d/control: Align (Build-)Depends with upstream. + * d/rules: Run tests with pkgos-dh_auto_test. + + -- Corey Bryant Wed, 14 Nov 2018 13:22:45 -0500 + python-keystoneclient (1:3.17.0-0ubuntu1) cosmic; urgency=medium * New upstream release for OpenStack Rocky. diff -Nru python-keystoneclient-3.17.0/debian/control python-keystoneclient-3.18.0/debian/control --- python-keystoneclient-3.17.0/debian/control 2018-07-30 21:35:45.000000000 +0000 +++ python-keystoneclient-3.18.0/debian/control 2018-11-14 18:22:45.000000000 +0000 @@ -13,9 +13,10 @@ python-all, python-pbr (>= 2.0.0), python-setuptools, - python-sphinx (>= 1.6.2) , python3-all, python3-pbr (>= 2.0.0), + python3-setuptools, + python3-sphinx (>= 1.6.2) , Build-Depends-Indep: bandit, memcached, @@ -31,7 +32,6 @@ python-mock (>= 2.0.0), python-mox3, python-oauthlib (>= 0.6.2), - python-openstackdocstheme (>= 1.18.1) , python-oslo.config (>= 1:5.2.0), python-oslo.i18n (>= 3.15.3), python-oslo.serialization (>= 2.18.0), @@ -42,6 +42,7 @@ python-requests (>= 2.14.2), python-requests-mock (>= 1.2.0), python-six (>= 1.10.0), + python-stestr, python-stevedore (>= 1:1.20.0), python-tempest (>= 1:17.1.0), python-testrepository (>= 0.0.18), @@ -68,9 +69,11 @@ python3-oslotest (>= 1:3.2.0), python3-pep8, python3-pysaml2, + python3-reno (>= 2.5.0), python3-requests (>= 2.14.2), python3-requests-mock (>= 1.2.0), python3-six (>= 1.10.0), + python3-stestr, python3-stevedore (>= 1:1.20.0), python3-tempest (>= 1:17.1.0), python3-testrepository (>= 0.0.18), diff -Nru python-keystoneclient-3.17.0/debian/rules python-keystoneclient-3.18.0/debian/rules --- python-keystoneclient-3.17.0/debian/rules 2018-07-30 21:35:45.000000000 +0000 +++ python-keystoneclient-3.18.0/debian/rules 2018-11-14 18:22:45.000000000 +0000 @@ -19,17 +19,7 @@ override_dh_auto_test: ifeq (,$(filter nocheck,$(DEB_BUILD_OPTIONS))) - set -e ; for i in 2.7 $(PYTHON3S) ; do \ - PYMAJOR=`echo $$i | cut -d'.' -f1` ; \ - echo "===> Testing with python$$i (python$$PYMAJOR)" ; \ - rm -rf .testrepository ; \ - testr-python$$PYMAJOR init ; \ - TEMP_REZ=`mktemp -t` ; \ - PYTHONPATH=$(CURDIR) PYTHON=python$$i testr-python$$PYMAJOR run --subunit 'keystoneclient\.tests\.(?!.*memcache_set_expired.*|.*test_encrypt_cache_data.*|.*test_sign_cache_data.*)' | tee $$TEMP_REZ | subunit2pyunit ; \ - cat $$TEMP_REZ | subunit-filter -s --no-passthrough | subunit-stats ; \ - rm -f $$TEMP_REZ ; \ - testr-python$$PYMAJOR slowest ; \ - done + pkgos-dh_auto_test 'keystoneclient\.tests\.(?!.*memcache_set_expired.*|.*test_encrypt_cache_data.*|.*test_sign_cache_data.*)' endif override_dh_clean: diff -Nru python-keystoneclient-3.17.0/doc/source/using-api-v3.rst python-keystoneclient-3.18.0/doc/source/using-api-v3.rst --- python-keystoneclient-3.17.0/doc/source/using-api-v3.rst 2018-06-20 23:15:51.000000000 +0000 +++ python-keystoneclient-3.18.0/doc/source/using-api-v3.rst 2018-10-24 17:18:37.000000000 +0000 @@ -102,6 +102,31 @@ .. _`Using Sessions`: using-sessions.html +Getting Metadata Responses +========================== + +Instantiating :py:class:`keystoneclient.v3.client.Client` using +`include_metadata=True` will cause manager response to return +:py:class:`keystoneclient.base.Response` instead of just the data. +The metadata property will be available directly to the +:py:class:`keystoneclient.base.Response` and the response data will +be available as property `data` to it. + + >>> from keystoneauth1.identity import v3 + >>> from keystoneauth1 import session + >>> from keystoneclient.v3 import client + >>> auth = v3.Password(auth_url='https://my.keystone.com:5000/v3', + ... user_id='myuserid', + ... password='mypassword', + ... project_id='myprojectid') + >>> sess = session.Session(auth=auth) + >>> keystone = client.Client(session=sess, include_metadata=True) + >>> resp = keystone.projects.list() + >>> resp.request_ids[0] + req-1234-5678-... + >>> resp.data + [, , ...] + Non-Session Authentication (deprecated) ======================================= diff -Nru python-keystoneclient-3.17.0/keystoneclient/base.py python-keystoneclient-3.18.0/keystoneclient/base.py --- python-keystoneclient-3.17.0/keystoneclient/base.py 2018-06-20 23:15:51.000000000 +0000 +++ python-keystoneclient-3.18.0/keystoneclient/base.py 2018-10-24 17:18:37.000000000 +0000 @@ -32,22 +32,33 @@ from keystoneclient.i18n import _ +class Response(object): + + def __init__(self, http_response, data): + self.request_ids = [] + if isinstance(http_response, list): + # http_response is a list of in case + # of pagination + for resp_obj in http_response: + # Extract 'x-openstack-request-id' from headers + self.request_ids.append(resp_obj.headers.get( + 'x-openstack-request-id')) + else: + self.request_ids.append(http_response.headers.get( + 'x-openstack-request-id')) + self.data = data + + def getid(obj): """Return id if argument is a Resource. Abstracts the common pattern of allowing both an object or an object's ID (UUID) as a parameter when dealing with relationships. """ - try: - if obj.uuid: - return obj.uuid - except AttributeError: # nosec(cjschaef): 'obj' doesn't contain attribute - # 'uuid', return attribute 'id' or the 'obj' - pass - try: - return obj.id - except AttributeError: - return obj + if getattr(obj, 'uuid', None): + return obj.uuid + else: + return getattr(obj, 'id', obj) def filter_none(**kwargs): @@ -107,6 +118,11 @@ 'may be removed in the 2.0.0 release', DeprecationWarning) return self.client + def _prepare_return_value(self, http_response, data): + if self.client.include_metadata: + return Response(http_response, data) + return data + def _list(self, url, response_key, obj_class=None, body=None, **kwargs): """List the collection. @@ -137,7 +153,8 @@ # are already returned in a list (so simply utilize that list) pass - return [obj_class(self, res, loaded=True) for res in data if res] + return self._prepare_return_value( + resp, [obj_class(self, res, loaded=True) for res in data if res]) def _get(self, url, response_key, **kwargs): """Get an object from collection. @@ -148,7 +165,8 @@ :param kwargs: Additional arguments will be passed to the request. """ resp, body = self.client.get(url, **kwargs) - return self.resource_class(self, body[response_key], loaded=True) + return self._prepare_return_value( + resp, self.resource_class(self, body[response_key], loaded=True)) def _head(self, url, **kwargs): """Retrieve request headers for an object. @@ -157,7 +175,7 @@ :param kwargs: Additional arguments will be passed to the request. """ resp, body = self.client.head(url, **kwargs) - return resp.status_code == 204 + return self._prepare_return_value(resp, resp.status_code == 204) def _post(self, url, body, response_key, return_raw=False, **kwargs): """Create an object. @@ -174,7 +192,8 @@ resp, body = self.client.post(url, body=body, **kwargs) if return_raw: return body[response_key] - return self.resource_class(self, body[response_key]) + return self._prepare_return_value( + resp, self.resource_class(self, body[response_key])) def _put(self, url, body=None, response_key=None, **kwargs): """Update an object with PUT method. @@ -190,9 +209,11 @@ # PUT requests may not return a body if body is not None: if response_key is not None: - return self.resource_class(self, body[response_key]) + return self._prepare_return_value( + resp, self.resource_class(self, body[response_key])) else: - return self.resource_class(self, body) + return self._prepare_return_value( + resp, self.resource_class(self, body)) def _patch(self, url, body=None, response_key=None, **kwargs): """Update an object with PATCH method. @@ -206,9 +227,11 @@ """ resp, body = self.client.patch(url, body=body, **kwargs) if response_key is not None: - return self.resource_class(self, body[response_key]) + return self._prepare_return_value( + resp, self.resource_class(self, body[response_key])) else: - return self.resource_class(self, body) + return self._prepare_return_value( + resp, self.resource_class(self, body)) def _delete(self, url, **kwargs): """Delete an object. @@ -216,7 +239,8 @@ :param url: a partial URL, e.g., '/servers/my-server' :param kwargs: Additional arguments will be passed to the request. """ - return self.client.delete(url, **kwargs) + resp, body = self.client.delete(url, **kwargs) + return resp, self._prepare_return_value(resp, body) def _update(self, url, body=None, response_key=None, method="PUT", **kwargs): @@ -231,7 +255,10 @@ % method) # PUT requests may not return a body if body: - return self.resource_class(self, body[response_key]) + return self._prepare_return_value( + resp, self.resource_class(self, body[response_key])) + else: + return self._prepare_return_value(resp, body) @six.add_metaclass(abc.ABCMeta) @@ -249,16 +276,20 @@ the Python side. """ rl = self.findall(**kwargs) - num = len(rl) - if num == 0: + if self.client.include_metadata: + base_response = rl + rl = rl.data + base_response.data = rl[0] + + if len(rl) == 0: msg = _("No %(name)s matching %(kwargs)s.") % { 'name': self.resource_class.__name__, 'kwargs': kwargs} raise ksa_exceptions.NotFound(404, msg) - elif num > 1: + elif len(rl) > 1: raise ksc_exceptions.NoUniqueMatch else: - return rl[0] + return base_response if self.client.include_metadata else rl[0] def findall(self, **kwargs): """Find all items with attributes matching ``**kwargs``. @@ -269,15 +300,23 @@ found = [] searches = kwargs.items() - for obj in self.list(): - try: - if all(getattr(obj, attr) == value - for (attr, value) in searches): - found.append(obj) - except AttributeError: - continue + def _extract_data(objs, response_data): + for obj in objs: + try: + if all(getattr(obj, attr) == value + for (attr, value) in searches): + response_data.append(obj) + except AttributeError: + continue + return response_data + + objs = self.list() + if self.client.include_metadata: + # 'objs' is the object of 'Response' class. + objs.data = _extract_data(objs.data, found) + return objs - return found + return _extract_data(objs, found) class CrudManager(Manager): @@ -376,6 +415,16 @@ @filter_kwargs def list(self, fallback_to_auth=False, **kwargs): + + def return_resp(resp, include_metadata=False): + base_response = None + list_data = resp + if include_metadata: + base_response = resp + list_data = resp.data + base_response.data = list_data + return base_response if include_metadata else list_data + if 'id' in kwargs.keys(): # Ensure that users are not trying to call things like # ``domains.list(id='default')`` when they should have used @@ -392,15 +441,16 @@ try: query = self._build_query(kwargs) url_query = '%(url)s%(query)s' % {'url': url, 'query': query} - return self._list( - url_query, - self.collection_key) + list_resp = self._list(url_query, self.collection_key) + return return_resp(list_resp, + include_metadata=self.client.include_metadata) except ksa_exceptions.EmptyCatalog: if fallback_to_auth: - return self._list( - url_query, - self.collection_key, - endpoint_filter={'interface': plugin.AUTH_INTERFACE}) + list_resp = self._list(url_query, self.collection_key, + endpoint_filter={ + 'interface': plugin.AUTH_INTERFACE}) + return return_resp( + list_resp, include_metadata=self.client.include_metadata) else: raise @@ -439,6 +489,11 @@ url_query, self.collection_key) + if self.client.include_metadata: + base_response = elements + elements = elements.data + base_response.data = elements[0] + if not elements: msg = _("No %(name)s matching %(kwargs)s.") % { 'name': self.resource_class.__name__, 'kwargs': kwargs} @@ -446,7 +501,8 @@ elif len(elements) > 1: raise ksc_exceptions.NoUniqueMatch else: - return elements[0] + return (base_response if self.client.include_metadata + else elements[0]) class Resource(object): diff -Nru python-keystoneclient-3.17.0/keystoneclient/httpclient.py python-keystoneclient-3.18.0/keystoneclient/httpclient.py --- python-keystoneclient-3.17.0/keystoneclient/httpclient.py 2018-06-20 23:15:51.000000000 +0000 +++ python-keystoneclient-3.18.0/keystoneclient/httpclient.py 2018-10-24 17:18:37.000000000 +0000 @@ -389,6 +389,11 @@ user_agent=user_agent, connect_retries=connect_retries) + # NOTE(dstanek): This allows me to not have to change keystoneauth or + # to write an adapter to the adapter here. Splitting thing into + # multiple project isn't always all sunshine and roses. + self._adapter.include_metadata = kwargs.pop('include_metadata', False) + # keyring setup if use_keyring and keyring is None: _logger.warning('Failed to load keyring modules.') diff -Nru python-keystoneclient-3.17.0/keystoneclient/tests/unit/test_base.py python-keystoneclient-3.18.0/keystoneclient/tests/unit/test_base.py --- python-keystoneclient-3.17.0/keystoneclient/tests/unit/test_base.py 2018-06-20 23:15:51.000000000 +0000 +++ python-keystoneclient-3.18.0/keystoneclient/tests/unit/test_base.py 2018-10-24 17:18:37.000000000 +0000 @@ -11,14 +11,29 @@ # License for the specific language governing permissions and limitations # under the License. +import uuid + import fixtures from keystoneauth1.identity import v2 from keystoneauth1 import session +import requests from keystoneclient import base +from keystoneclient import exceptions from keystoneclient.tests.unit import utils +from keystoneclient import utils as base_utils from keystoneclient.v2_0 import client from keystoneclient.v2_0 import roles +from keystoneclient.v3 import users + +TEST_REQUEST_ID = uuid.uuid4().hex +TEST_REQUEST_ID_1 = uuid.uuid4().hex + + +def create_response_with_request_id_header(): + resp = requests.Response() + resp.headers['x-openstack-request-id'] = TEST_REQUEST_ID + return resp class HumanReadable(base.Resource): @@ -202,3 +217,209 @@ management=True) put_mock.assert_called_once_with(self.url, management=True, body=None) self.assertEqual(rsrc.hi, 1) + + +class ManagerRequestIdTest(utils.TestCase): + url = "/test-url" + resp = create_response_with_request_id_header() + + def setUp(self): + super(ManagerRequestIdTest, self).setUp() + + auth = v2.Token(auth_url='http://127.0.0.1:5000', + token=self.TEST_TOKEN) + session_ = session.Session(auth=auth) + self.client = client.Client(session=session_, + include_metadata='True')._adapter + + self.mgr = base.Manager(self.client) + self.mgr.resource_class = base.Resource + + def mock_request_method(self, request_method, body): + return self.useFixture(fixtures.MockPatchObject( + self.client, request_method, autospec=True, + return_value=(self.resp, body)) + ).mock + + def test_get(self): + body = {"hello": {"hi": 1}} + get_mock = self.mock_request_method('get', body) + rsrc = self.mgr._get(self.url, "hello") + get_mock.assert_called_once_with(self.url) + self.assertEqual(rsrc.data.hi, 1) + self.assertEqual(rsrc.request_ids[0], TEST_REQUEST_ID) + + def test_list(self): + body = {"hello": [{"name": "admin"}, {"name": "admin"}]} + get_mock = self.mock_request_method('get', body) + + returned_list = self.mgr._list(self.url, "hello") + self.assertEqual(returned_list.request_ids[0], TEST_REQUEST_ID) + get_mock.assert_called_once_with(self.url) + + def test_list_with_multiple_response_objects(self): + body = {"hello": [{"name": "admin"}, {"name": "admin"}]} + resp_1 = requests.Response() + resp_1.headers['x-openstack-request-id'] = TEST_REQUEST_ID + resp_2 = requests.Response() + resp_2.headers['x-openstack-request-id'] = TEST_REQUEST_ID_1 + + resp_result = [resp_1, resp_2] + get_mock = self.useFixture(fixtures.MockPatchObject( + self.client, 'get', autospec=True, + return_value=(resp_result, body)) + ).mock + + returned_list = self.mgr._list(self.url, "hello") + self.assertIn(returned_list.request_ids[0], [ + TEST_REQUEST_ID, TEST_REQUEST_ID_1]) + self.assertIn(returned_list.request_ids[1], [ + TEST_REQUEST_ID, TEST_REQUEST_ID_1]) + get_mock.assert_called_once_with(self.url) + + def test_post(self): + body = {"hello": {"hi": 1}} + post_mock = self.mock_request_method('post', body) + rsrc = self.mgr._post(self.url, body, "hello") + post_mock.assert_called_once_with(self.url, body=body) + self.assertEqual(rsrc.data.hi, 1) + + post_mock.reset_mock() + + rsrc = self.mgr._post(self.url, body, "hello", return_raw=True) + post_mock.assert_called_once_with(self.url, body=body) + self.assertNotIsInstance(rsrc, base.Response) + self.assertEqual(rsrc["hi"], 1) + + def test_put(self): + body = {"hello": {"hi": 1}} + put_mock = self.mock_request_method('put', body) + rsrc = self.mgr._put(self.url, body, "hello") + put_mock.assert_called_once_with(self.url, body=body) + self.assertEqual(rsrc.data.hi, 1) + + put_mock.reset_mock() + + rsrc = self.mgr._put(self.url, body) + put_mock.assert_called_once_with(self.url, body=body) + self.assertEqual(rsrc.data.hello["hi"], 1) + self.assertEqual(rsrc.request_ids[0], TEST_REQUEST_ID) + + def test_head(self): + get_mock = self.mock_request_method('head', None) + rsrc = self.mgr._head(self.url) + get_mock.assert_called_once_with(self.url) + self.assertFalse(rsrc.data) + self.assertEqual(rsrc.request_ids[0], TEST_REQUEST_ID) + + def test_delete(self): + delete_mock = self.mock_request_method('delete', None) + resp, base_resp = self.mgr._delete(self.url, name="hello") + + delete_mock.assert_called_once_with('/test-url', name='hello') + self.assertEqual(base_resp.request_ids[0], TEST_REQUEST_ID) + self.assertEqual(base_resp.data, None) + self.assertTrue(isinstance(resp, requests.Response)) + + def test_patch(self): + body = {"hello": {"hi": 1}} + patch_mock = self.mock_request_method('patch', body) + rsrc = self.mgr._patch(self.url, body, "hello") + patch_mock.assert_called_once_with(self.url, body=body) + self.assertEqual(rsrc.data.hi, 1) + + patch_mock.reset_mock() + + rsrc = self.mgr._patch(self.url, body) + patch_mock.assert_called_once_with(self.url, body=body) + self.assertEqual(rsrc.data.hello["hi"], 1) + self.assertEqual(rsrc.request_ids[0], TEST_REQUEST_ID) + + def test_update(self): + body = {"hello": {"hi": 1}} + patch_mock = self.mock_request_method('patch', body) + put_mock = self.mock_request_method('put', body) + + rsrc = self.mgr._update( + self.url, body=body, response_key="hello", method="PATCH", + management=False) + patch_mock.assert_called_once_with( + self.url, management=False, body=body) + self.assertEqual(rsrc.data.hi, 1) + + rsrc = self.mgr._update( + self.url, body=None, response_key="hello", method="PUT", + management=True) + put_mock.assert_called_once_with(self.url, management=True, body=None) + self.assertEqual(rsrc.data.hi, 1) + self.assertEqual(rsrc.request_ids[0], TEST_REQUEST_ID) + + +class ManagerWithFindRequestIdTest(utils.TestCase): + url = "/fakes" + resp = create_response_with_request_id_header() + + def setUp(self): + super(ManagerWithFindRequestIdTest, self).setUp() + + auth = v2.Token(auth_url='http://127.0.0.1:5000', + token=self.TEST_TOKEN) + session_ = session.Session(auth=auth) + self.client = client.Client(session=session_, + include_metadata='True')._adapter + + def test_find_resource(self): + body = {"roles": [{"name": 'entity_one'}, {"name": 'entity_one_1'}]} + request_resp = requests.Response() + request_resp.headers['x-openstack-request-id'] = TEST_REQUEST_ID + + get_mock = self.useFixture(fixtures.MockPatchObject( + self.client, 'get', autospec=True, + side_effect=[exceptions.NotFound, (request_resp, body)]) + ).mock + + mgr = roles.RoleManager(self.client) + mgr.resource_class = roles.Role + response = base_utils.find_resource(mgr, 'entity_one') + get_mock.assert_called_with('/OS-KSADM/roles') + self.assertEqual(response.request_ids[0], TEST_REQUEST_ID) + + +class CrudManagerRequestIdTest(utils.TestCase): + resp = create_response_with_request_id_header() + request_resp = requests.Response() + request_resp.headers['x-openstack-request-id'] = TEST_REQUEST_ID + + def setUp(self): + super(CrudManagerRequestIdTest, self).setUp() + + auth = v2.Token(auth_url='http://127.0.0.1:5000', + token=self.TEST_TOKEN) + session_ = session.Session(auth=auth) + self.client = client.Client(session=session_, + include_metadata='True')._adapter + + def test_find_resource(self): + body = {"users": [{"name": 'entity_one'}]} + get_mock = self.useFixture(fixtures.MockPatchObject( + self.client, 'get', autospec=True, + side_effect=[exceptions.NotFound, (self.request_resp, body)]) + ).mock + mgr = users.UserManager(self.client) + mgr.resource_class = users.User + response = base_utils.find_resource(mgr, 'entity_one') + get_mock.assert_called_with('/users?name=entity_one') + self.assertEqual(response.request_ids[0], TEST_REQUEST_ID) + + def test_list(self): + body = {"users": [{"name": "admin"}, {"name": "admin"}]} + + get_mock = self.useFixture(fixtures.MockPatchObject( + self.client, 'get', autospec=True, + return_value=(self.request_resp, body)) + ).mock + mgr = users.UserManager(self.client) + mgr.resource_class = users.User + returned_list = mgr.list() + self.assertEqual(returned_list.request_ids[0], TEST_REQUEST_ID) + get_mock.assert_called_once_with('/users?') diff -Nru python-keystoneclient-3.17.0/keystoneclient/tests/unit/v3/test_projects.py python-keystoneclient-3.18.0/keystoneclient/tests/unit/v3/test_projects.py --- python-keystoneclient-3.17.0/keystoneclient/tests/unit/v3/test_projects.py 2018-06-20 23:15:51.000000000 +0000 +++ python-keystoneclient-3.18.0/keystoneclient/tests/unit/v3/test_projects.py 2018-10-24 17:18:38.000000000 +0000 @@ -10,12 +10,17 @@ # License for the specific language governing permissions and limitations # under the License. +import fixtures +import requests import uuid from keystoneauth1 import exceptions as ksa_exceptions +from keystoneauth1.identity import v3 +from keystoneauth1 import session from keystoneclient import exceptions as ksc_exceptions from keystoneclient.tests.unit.v3 import utils +from keystoneclient.v3 import client from keystoneclient.v3 import projects @@ -395,3 +400,71 @@ "name": project_id} ]} return ret + + +class ProjectsRequestIdTests(utils.TestCase): + + url = "/projects" + resp = requests.Response() + TEST_REQUEST_ID = uuid.uuid4().hex + resp.headers['x-openstack-request-id'] = TEST_REQUEST_ID + + def setUp(self): + super(ProjectsRequestIdTests, self).setUp() + auth = v3.Token(auth_url='http://127.0.0.1:5000', + token=self.TEST_TOKEN) + session_ = session.Session(auth=auth) + self.client = client.Client(session=session_, + include_metadata='True')._adapter + self.mgr = projects.ProjectManager(self.client) + self.mgr.resource_class = projects.Project + + def _mock_request_method(self, method=None, body=None): + return self.useFixture(fixtures.MockPatchObject( + self.client, method, autospec=True, + return_value=(self.resp, body)) + ).mock + + def test_get_project(self): + body = {"project": {"name": "admin"}} + get_mock = self._mock_request_method(method='get', body=body) + + response = self.mgr.get(project='admin') + self.assertEqual(response.request_ids[0], self.TEST_REQUEST_ID) + get_mock.assert_called_once_with(self.url + '/admin') + + def test_create_project(self): + body = {"project": {"name": "admin", "domain": "admin"}} + post_mock = self._mock_request_method(method='post', body=body) + + response = self.mgr.create('admin', 'admin') + self.assertEqual(response.request_ids[0], self.TEST_REQUEST_ID) + post_mock.assert_called_once_with(self.url, body={'project': { + 'name': 'admin', 'enabled': True, 'domain_id': 'admin'}}) + + def test_list_project(self): + body = {"projects": [{"name": "admin"}, {"name": "admin"}]} + get_mock = self._mock_request_method(method='get', body=body) + + returned_list = self.mgr.list() + self.assertEqual(returned_list.request_ids[0], self.TEST_REQUEST_ID) + get_mock.assert_called_once_with(self.url + '?') + + def test_update_project(self): + body = {"project": {"name": "admin"}} + patch_mock = self._mock_request_method(method='patch', body=body) + + put_mock = self._mock_request_method(method='put', body=body) + + response = self.mgr.update("admin", domain='demo') + self.assertEqual(response.request_ids[0], self.TEST_REQUEST_ID) + patch_mock.assert_called_once_with(self.url + '/admin', body={ + 'project': {'domain_id': 'demo'}}) + self.assertFalse(put_mock.called) + + def test_delete_project(self): + get_mock = self._mock_request_method(method='delete') + + _, resp = self.mgr.delete("admin") + self.assertEqual(resp.request_ids[0], self.TEST_REQUEST_ID) + get_mock.assert_called_once_with(self.url + '/admin') diff -Nru python-keystoneclient-3.17.0/keystoneclient/tests/unit/v3/utils.py python-keystoneclient-3.18.0/keystoneclient/tests/unit/v3/utils.py --- python-keystoneclient-3.17.0/keystoneclient/tests/unit/v3/utils.py 2018-06-20 23:15:51.000000000 +0000 +++ python-keystoneclient-3.18.0/keystoneclient/tests/unit/v3/utils.py 2018-10-24 17:18:38.000000000 +0000 @@ -221,6 +221,8 @@ self.assertRequestBodyIs(json=self.encode(entity)) def test_create(self, ref=None, req_ref=None): + deprecations = self.useFixture(client_fixtures.Deprecations()) + deprecations.expect_deprecations() ref = ref or self.new_ref() manager_ref = ref.copy() manager_ref.pop('id') @@ -343,6 +345,8 @@ self.assertQueryStringIs('') def test_update(self, ref=None, req_ref=None): + deprecations = self.useFixture(client_fixtures.Deprecations()) + deprecations.expect_deprecations() ref = ref or self.new_ref() self.stub_entity('PATCH', id=ref['id'], entity=ref) diff -Nru python-keystoneclient-3.17.0/keystoneclient/v3/contrib/federation/identity_providers.py python-keystoneclient-3.18.0/keystoneclient/v3/contrib/federation/identity_providers.py --- python-keystoneclient-3.17.0/keystoneclient/v3/contrib/federation/identity_providers.py 2018-06-20 23:15:51.000000000 +0000 +++ python-keystoneclient-3.18.0/keystoneclient/v3/contrib/federation/identity_providers.py 2018-10-24 17:18:38.000000000 +0000 @@ -45,8 +45,8 @@ PUT /OS-FEDERATION/identity_providers/$identity_provider :param id: unique id of the identity provider. - :param kwargs: optional attributes: description (str), enabled - (boolean) and remote_ids (list). + :param kwargs: optional attributes: description (str), domain_id (str), + enabled (boolean) and remote_ids (list). :returns: an IdentityProvider resource object. :rtype: :py:class:`keystoneclient.v3.federation.IdentityProvider` diff -Nru python-keystoneclient-3.17.0/keystoneclient/v3/projects.py python-keystoneclient-3.18.0/keystoneclient/v3/projects.py --- python-keystoneclient-3.17.0/keystoneclient/v3/projects.py 2018-06-20 23:15:51.000000000 +0000 +++ python-keystoneclient-3.18.0/keystoneclient/v3/projects.py 2018-10-24 17:18:38.000000000 +0000 @@ -136,9 +136,21 @@ domain_id=base.getid(domain), fallback_to_auth=True, **kwargs) - for p in projects: + + base_response = None + list_data = projects + if self.client.include_metadata: + base_response = projects + list_data = projects.data + base_response.data = list_data + + for p in list_data: p.tags = self._encode_tags(getattr(p, 'tags', [])) - return projects + + if self.client.include_metadata: + base_response.data = list_data + + return base_response if self.client.include_metadata else list_data def _check_not_parents_as_ids_and_parents_as_list(self, parents_as_ids, parents_as_list): diff -Nru python-keystoneclient-3.17.0/keystoneclient/v3/regions.py python-keystoneclient-3.18.0/keystoneclient/v3/regions.py --- python-keystoneclient-3.17.0/keystoneclient/v3/regions.py 2018-06-20 23:15:51.000000000 +0000 +++ python-keystoneclient-3.18.0/keystoneclient/v3/regions.py 2018-10-24 17:18:38.000000000 +0000 @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. +from debtcollector import removals from keystoneclient import base @@ -34,6 +35,11 @@ collection_key = 'regions' key = 'region' + @removals.removed_kwarg( + 'enabled', + message='The enabled parameter is deprecated.', + version='3.18.0', + removal_version='4.0.0') def create(self, id=None, description=None, enabled=True, parent_region=None, **kwargs): """Create a region. @@ -81,6 +87,11 @@ return super(RegionManager, self).list( **kwargs) + @removals.removed_kwarg( + 'enabled', + message='The enabled parameter is deprecated.', + version='3.18.0', + removal_version='4.0.0') def update(self, region, description=None, enabled=None, parent_region=None, **kwargs): """Update a region. diff -Nru python-keystoneclient-3.17.0/keystoneclient/v3/registered_limits.py python-keystoneclient-3.18.0/keystoneclient/v3/registered_limits.py --- python-keystoneclient-3.17.0/keystoneclient/v3/registered_limits.py 2018-06-20 23:16:07.000000000 +0000 +++ python-keystoneclient-3.18.0/keystoneclient/v3/registered_limits.py 2018-10-24 17:18:38.000000000 +0000 @@ -84,7 +84,7 @@ :param resource_name: the name of the resource to limit. :type resource_name: str :param default_limit: the default limit for projects to assume. - :type defaut slt_limit: int + :type default_limit: int :param description: a string that describes the limit :type description: str :param region: a UUID that identifies the region for the limit. diff -Nru python-keystoneclient-3.17.0/lower-constraints.txt python-keystoneclient-3.18.0/lower-constraints.txt --- python-keystoneclient-3.17.0/lower-constraints.txt 2018-06-20 23:15:51.000000000 +0000 +++ python-keystoneclient-3.18.0/lower-constraints.txt 2018-10-24 17:18:38.000000000 +0000 @@ -64,10 +64,9 @@ rfc3986==0.3.1 six==1.10.0 smmap==0.9.0 -stestr==1.0.0 stevedore==1.20.0 tempest==17.1.0 -testrepository==0.0.18 +stestr==2.0.0 testresources==2.0.0 testscenarios==0.4 testtools==2.2.0 diff -Nru python-keystoneclient-3.17.0/PKG-INFO python-keystoneclient-3.18.0/PKG-INFO --- python-keystoneclient-3.17.0/PKG-INFO 2018-06-20 23:17:43.000000000 +0000 +++ python-keystoneclient-3.18.0/PKG-INFO 2018-10-24 17:19:40.000000000 +0000 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: python-keystoneclient -Version: 3.17.0 +Version: 3.18.0 Summary: Client Library for OpenStack Identity Home-page: https://docs.openstack.org/python-keystoneclient/latest/ Author: OpenStack @@ -35,6 +35,7 @@ * `Source`_ * `Specs`_ * `How to Contribute`_ + * `Release Notes`_ .. _PyPi: https://pypi.org/project/python-keystoneclient .. _Online Documentation: https://docs.openstack.org/python-keystoneclient/latest/ @@ -45,6 +46,7 @@ .. _OpenStackClient: https://pypi.org/project/python-openstackclient .. _How to Contribute: https://docs.openstack.org/infra/manual/developers.html .. _Specs: https://specs.openstack.org/openstack/keystone-specs/ + .. _Release Notes: https://docs.openstack.org/releasenotes/python-keystoneclient .. contents:: Contents: :local: diff -Nru python-keystoneclient-3.17.0/playbooks/keystoneclient-dsvm-functional/post.yaml python-keystoneclient-3.18.0/playbooks/keystoneclient-dsvm-functional/post.yaml --- python-keystoneclient-3.17.0/playbooks/keystoneclient-dsvm-functional/post.yaml 1970-01-01 00:00:00.000000000 +0000 +++ python-keystoneclient-3.18.0/playbooks/keystoneclient-dsvm-functional/post.yaml 2018-10-24 17:18:38.000000000 +0000 @@ -0,0 +1,80 @@ +- hosts: primary + tasks: + + - name: Copy files from {{ ansible_user_dir }}/workspace/ on node + synchronize: + src: '{{ ansible_user_dir }}/workspace/' + dest: '{{ zuul.executor.log_root }}' + mode: pull + copy_links: true + verify_host: true + rsync_opts: + - --include=**/*nose_results.html + - --include=*/ + - --exclude=* + - --prune-empty-dirs + + - name: Copy files from {{ ansible_user_dir }}/workspace/ on node + synchronize: + src: '{{ ansible_user_dir }}/workspace/' + dest: '{{ zuul.executor.log_root }}' + mode: pull + copy_links: true + verify_host: true + rsync_opts: + - --include=**/*testr_results.html.gz + - --include=*/ + - --exclude=* + - --prune-empty-dirs + + - name: Copy files from {{ ansible_user_dir }}/workspace/ on node + synchronize: + src: '{{ ansible_user_dir }}/workspace/' + dest: '{{ zuul.executor.log_root }}' + mode: pull + copy_links: true + verify_host: true + rsync_opts: + - --include=/.testrepository/tmp* + - --include=*/ + - --exclude=* + - --prune-empty-dirs + + - name: Copy files from {{ ansible_user_dir }}/workspace/ on node + synchronize: + src: '{{ ansible_user_dir }}/workspace/' + dest: '{{ zuul.executor.log_root }}' + mode: pull + copy_links: true + verify_host: true + rsync_opts: + - --include=**/*testrepository.subunit.gz + - --include=*/ + - --exclude=* + - --prune-empty-dirs + + - name: Copy files from {{ ansible_user_dir }}/workspace/ on node + synchronize: + src: '{{ ansible_user_dir }}/workspace/' + dest: '{{ zuul.executor.log_root }}/tox' + mode: pull + copy_links: true + verify_host: true + rsync_opts: + - --include=/.tox/*/log/* + - --include=*/ + - --exclude=* + - --prune-empty-dirs + + - name: Copy files from {{ ansible_user_dir }}/workspace/ on node + synchronize: + src: '{{ ansible_user_dir }}/workspace/' + dest: '{{ zuul.executor.log_root }}' + mode: pull + copy_links: true + verify_host: true + rsync_opts: + - --include=/logs/** + - --include=*/ + - --exclude=* + - --prune-empty-dirs diff -Nru python-keystoneclient-3.17.0/playbooks/keystoneclient-dsvm-functional/run.yaml python-keystoneclient-3.18.0/playbooks/keystoneclient-dsvm-functional/run.yaml --- python-keystoneclient-3.17.0/playbooks/keystoneclient-dsvm-functional/run.yaml 1970-01-01 00:00:00.000000000 +0000 +++ python-keystoneclient-3.18.0/playbooks/keystoneclient-dsvm-functional/run.yaml 2018-10-24 17:18:38.000000000 +0000 @@ -0,0 +1,47 @@ +- hosts: all + name: Autoconverted job legacy-keystoneclient-dsvm-functional from old job gate-keystoneclient-dsvm-functional-ubuntu-xenial-nv + tasks: + + - name: Ensure legacy workspace directory + file: + path: '{{ ansible_user_dir }}/workspace' + state: directory + + - shell: + cmd: | + set -e + set -x + cat > clonemap.yaml << EOF + clonemap: + - name: openstack-infra/devstack-gate + dest: devstack-gate + EOF + /usr/zuul-env/bin/zuul-cloner -m clonemap.yaml --cache-dir /opt/git \ + git://git.openstack.org \ + openstack-infra/devstack-gate + executable: /bin/bash + chdir: '{{ ansible_user_dir }}/workspace' + environment: '{{ zuul | zuul_legacy_vars }}' + + - shell: + cmd: | + set -e + set -x + export PYTHONUNBUFFERED=true + export BRANCH_OVERRIDE=default + export DEVSTACK_PROJECT_FROM_GIT=python-keystoneclient + if [ "$BRANCH_OVERRIDE" != "default" ] ; then + export OVERRIDE_ZUUL_BRANCH=$BRANCH_OVERRIDE + fi + + function post_test_hook { + # Configure and run functional tests + $BASE/new/python-keystoneclient/keystoneclient/tests/functional/hooks/post_test_hook.sh + } + export -f post_test_hook + + cp devstack-gate/devstack-vm-gate-wrap.sh ./safe-devstack-vm-gate-wrap.sh + ./safe-devstack-vm-gate-wrap.sh + executable: /bin/bash + chdir: '{{ ansible_user_dir }}/workspace' + environment: '{{ zuul | zuul_legacy_vars }}' diff -Nru python-keystoneclient-3.17.0/python_keystoneclient.egg-info/pbr.json python-keystoneclient-3.18.0/python_keystoneclient.egg-info/pbr.json --- python-keystoneclient-3.17.0/python_keystoneclient.egg-info/pbr.json 2018-06-20 23:17:42.000000000 +0000 +++ python-keystoneclient-3.18.0/python_keystoneclient.egg-info/pbr.json 2018-10-24 17:19:40.000000000 +0000 @@ -1 +1 @@ -{"git_version": "234ea50", "is_release": true} \ No newline at end of file +{"git_version": "8982841", "is_release": true} \ No newline at end of file diff -Nru python-keystoneclient-3.17.0/python_keystoneclient.egg-info/PKG-INFO python-keystoneclient-3.18.0/python_keystoneclient.egg-info/PKG-INFO --- python-keystoneclient-3.17.0/python_keystoneclient.egg-info/PKG-INFO 2018-06-20 23:17:42.000000000 +0000 +++ python-keystoneclient-3.18.0/python_keystoneclient.egg-info/PKG-INFO 2018-10-24 17:19:40.000000000 +0000 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: python-keystoneclient -Version: 3.17.0 +Version: 3.18.0 Summary: Client Library for OpenStack Identity Home-page: https://docs.openstack.org/python-keystoneclient/latest/ Author: OpenStack @@ -35,6 +35,7 @@ * `Source`_ * `Specs`_ * `How to Contribute`_ + * `Release Notes`_ .. _PyPi: https://pypi.org/project/python-keystoneclient .. _Online Documentation: https://docs.openstack.org/python-keystoneclient/latest/ @@ -45,6 +46,7 @@ .. _OpenStackClient: https://pypi.org/project/python-openstackclient .. _How to Contribute: https://docs.openstack.org/infra/manual/developers.html .. _Specs: https://specs.openstack.org/openstack/keystone-specs/ + .. _Release Notes: https://docs.openstack.org/releasenotes/python-keystoneclient .. contents:: Contents: :local: diff -Nru python-keystoneclient-3.17.0/python_keystoneclient.egg-info/SOURCES.txt python-keystoneclient-3.18.0/python_keystoneclient.egg-info/SOURCES.txt --- python-keystoneclient-3.17.0/python_keystoneclient.egg-info/SOURCES.txt 2018-06-20 23:17:43.000000000 +0000 +++ python-keystoneclient-3.18.0/python_keystoneclient.egg-info/SOURCES.txt 2018-10-24 17:19:40.000000000 +0000 @@ -1,6 +1,6 @@ .coveragerc .mailmap -.testr.conf +.stestr.conf .zuul.yaml AUTHORS CONTRIBUTING.rst @@ -270,6 +270,8 @@ keystoneclient/v3/contrib/oauth1/core.py keystoneclient/v3/contrib/oauth1/request_tokens.py keystoneclient/v3/contrib/oauth1/utils.py +playbooks/keystoneclient-dsvm-functional/post.yaml +playbooks/keystoneclient-dsvm-functional/run.yaml python_keystoneclient.egg-info/PKG-INFO python_keystoneclient.egg-info/SOURCES.txt python_keystoneclient.egg-info/dependency_links.txt @@ -285,6 +287,7 @@ releasenotes/notes/bp-application-credentials-27728ded876d7d5a.yaml releasenotes/notes/bp-domain-config-9566e672a98f4e7f.yaml releasenotes/notes/bp-pci-dss-query-password-expired-users-b0c4b1bbdcf33f16.yaml +releasenotes/notes/bug-1615076-26962c85aeaf288c.yaml releasenotes/notes/bug-1616105-cc8b85eb056e99e2.yaml releasenotes/notes/bug-1641674-4862454115265e76.yaml releasenotes/notes/bug-1654847-d2e9df994c7b617f.yaml @@ -306,6 +309,7 @@ releasenotes/source/ocata.rst releasenotes/source/pike.rst releasenotes/source/queens.rst +releasenotes/source/rocky.rst releasenotes/source/unreleased.rst releasenotes/source/_static/.placeholder releasenotes/source/_templates/.placeholder diff -Nru python-keystoneclient-3.17.0/README.rst python-keystoneclient-3.18.0/README.rst --- python-keystoneclient-3.17.0/README.rst 2018-06-20 23:15:51.000000000 +0000 +++ python-keystoneclient-3.18.0/README.rst 2018-10-24 17:18:37.000000000 +0000 @@ -27,6 +27,7 @@ * `Source`_ * `Specs`_ * `How to Contribute`_ +* `Release Notes`_ .. _PyPi: https://pypi.org/project/python-keystoneclient .. _Online Documentation: https://docs.openstack.org/python-keystoneclient/latest/ @@ -37,6 +38,7 @@ .. _OpenStackClient: https://pypi.org/project/python-openstackclient .. _How to Contribute: https://docs.openstack.org/infra/manual/developers.html .. _Specs: https://specs.openstack.org/openstack/keystone-specs/ +.. _Release Notes: https://docs.openstack.org/releasenotes/python-keystoneclient .. contents:: Contents: :local: diff -Nru python-keystoneclient-3.17.0/releasenotes/notes/bug-1615076-26962c85aeaf288c.yaml python-keystoneclient-3.18.0/releasenotes/notes/bug-1615076-26962c85aeaf288c.yaml --- python-keystoneclient-3.17.0/releasenotes/notes/bug-1615076-26962c85aeaf288c.yaml 1970-01-01 00:00:00.000000000 +0000 +++ python-keystoneclient-3.18.0/releasenotes/notes/bug-1615076-26962c85aeaf288c.yaml 2018-10-24 17:18:38.000000000 +0000 @@ -0,0 +1,5 @@ +--- +deprecations: + - | + The region resource in Keystone never support or contain "enabled" property. + Thus the property is deprecated and will be removed in future versions. diff -Nru python-keystoneclient-3.17.0/releasenotes/source/index.rst python-keystoneclient-3.18.0/releasenotes/source/index.rst --- python-keystoneclient-3.17.0/releasenotes/source/index.rst 2018-06-20 23:15:51.000000000 +0000 +++ python-keystoneclient-3.18.0/releasenotes/source/index.rst 2018-10-24 17:18:38.000000000 +0000 @@ -6,6 +6,7 @@ :maxdepth: 1 unreleased + rocky queens pike ocata diff -Nru python-keystoneclient-3.17.0/releasenotes/source/rocky.rst python-keystoneclient-3.18.0/releasenotes/source/rocky.rst --- python-keystoneclient-3.17.0/releasenotes/source/rocky.rst 1970-01-01 00:00:00.000000000 +0000 +++ python-keystoneclient-3.18.0/releasenotes/source/rocky.rst 2018-10-24 17:18:38.000000000 +0000 @@ -0,0 +1,6 @@ +=================================== + Rocky Series Release Notes +=================================== + +.. release-notes:: + :branch: stable/rocky diff -Nru python-keystoneclient-3.17.0/.stestr.conf python-keystoneclient-3.18.0/.stestr.conf --- python-keystoneclient-3.17.0/.stestr.conf 1970-01-01 00:00:00.000000000 +0000 +++ python-keystoneclient-3.18.0/.stestr.conf 2018-10-24 17:18:37.000000000 +0000 @@ -0,0 +1,4 @@ +[DEFAULT] +test_path=${OS_TEST_PATH:-./keystoneclient/tests/unit} +top_dir=./ + diff -Nru python-keystoneclient-3.17.0/.testr.conf python-keystoneclient-3.18.0/.testr.conf --- python-keystoneclient-3.17.0/.testr.conf 2018-06-20 23:15:51.000000000 +0000 +++ python-keystoneclient-3.18.0/.testr.conf 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -[DEFAULT] -test_command=${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./keystoneclient/tests/unit} $LISTOPT $IDOPTION -test_id_option=--load-list $IDFILE -test_list_option=--list diff -Nru python-keystoneclient-3.17.0/test-requirements.txt python-keystoneclient-3.18.0/test-requirements.txt --- python-keystoneclient-3.17.0/test-requirements.txt 2018-06-20 23:15:51.000000000 +0000 +++ python-keystoneclient-3.18.0/test-requirements.txt 2018-10-24 17:18:38.000000000 +0000 @@ -14,7 +14,7 @@ oslotest>=3.2.0 # Apache-2.0 requests-mock>=1.2.0 # Apache-2.0 tempest>=17.1.0 # Apache-2.0 -testrepository>=0.0.18 # Apache-2.0/BSD +stestr>=2.0.0 # Apache-2.0 testresources>=2.0.0 # Apache-2.0/BSD testscenarios>=0.4 # Apache-2.0/BSD testtools>=2.2.0 # MIT diff -Nru python-keystoneclient-3.17.0/tox.ini python-keystoneclient-3.18.0/tox.ini --- python-keystoneclient-3.17.0/tox.ini 2018-06-20 23:15:51.000000000 +0000 +++ python-keystoneclient-3.18.0/tox.ini 2018-10-24 17:18:38.000000000 +0000 @@ -15,7 +15,7 @@ -r{toxinidir}/requirements.txt -r{toxinidir}/test-requirements.txt commands = find . -type f -name "*.pyc" -delete - python setup.py testr --slowest --testr-args='{posargs}' + stestr run --slowest {posargs} whitelist_externals = find [testenv:pep8] @@ -36,8 +36,14 @@ [testenv:cover] basepython = python3 -commands = python setup.py testr --coverage --testr-args='{posargs}' - coverage report +setenv = + PYTHON=coverage run --source keystoneclient --parallel-mode +commands = + stestr run {posargs} + coverage combine + coverage html -d cover + coverage xml -o cover/coverage.xml + coverage report [testenv:debug] basepython = python3 diff -Nru python-keystoneclient-3.17.0/.zuul.yaml python-keystoneclient-3.18.0/.zuul.yaml --- python-keystoneclient-3.17.0/.zuul.yaml 2018-06-20 23:15:51.000000000 +0000 +++ python-keystoneclient-3.18.0/.zuul.yaml 2018-10-24 17:18:37.000000000 +0000 @@ -1,7 +1,27 @@ +- job: + name: keystoneclient-devstack-functional + parent: legacy-dsvm-base + run: playbooks/keystoneclient-dsvm-functional/run.yaml + post-run: playbooks/keystoneclient-dsvm-functional/post.yaml + timeout: 4200 + required-projects: + - openstack-infra/devstack-gate + - openstack/keystone + - openstack/python-keystoneclient + - project: + templates: + - openstack-cover-jobs + - openstack-lower-constraints-jobs + - openstack-python-jobs + - openstack-python35-jobs + - openstack-python36-jobs + - publish-openstack-docs-pti + - check-requirements + - lib-forward-testing + - lib-forward-testing-python3 + - release-notes-jobs-python3 check: jobs: - - openstack-tox-lower-constraints - gate: - jobs: - - openstack-tox-lower-constraints + - keystoneclient-devstack-functional: + voting: false