From 577fa3847c5e9dbb9a83d83bb8faf2de1ccdd9ea Mon Sep 17 00:00:00 2001 From: Jose Manuel Castano Date: Fri, 7 Feb 2025 11:11:26 +0100 Subject: [PATCH 01/19] Add test for testing response headers --- tests/test_response_headers.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/test_response_headers.py diff --git a/tests/test_response_headers.py b/tests/test_response_headers.py new file mode 100644 index 0000000..728896b --- /dev/null +++ b/tests/test_response_headers.py @@ -0,0 +1,18 @@ +import threescale_api +import os +import pytest + +@pytest.fixture(scope="module") +def client(): + return threescale_api.ThreeScaleClient(url=os.environ['THREESCALE_PROVIDER_URL'], + token=os.environ['THREESCALE_PROVIDER_TOKEN'], ssl_verify=False) + +def test_x_served_by_ga(client): + response = client._rest.get(url=client.url + "/accounts.json") + assert response.status_code == 200 + assert "X-Served-By" not in response.headers + +def test_x_served_by_mas(client): + response = client._rest.get(url=client.url + "/accounts.json") + assert response.status_code == 200 + assert "X-Served-By" in response.headers \ No newline at end of file From 9065b956a51812b5253c0cd92844c96a19727409 Mon Sep 17 00:00:00 2001 From: Jose Manuel Castano Date: Mon, 10 Feb 2025 11:08:15 +0100 Subject: [PATCH 02/19] Adding test for response headers --- tests/test_response_headers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_response_headers.py b/tests/test_response_headers.py index 728896b..f6c45bf 100644 --- a/tests/test_response_headers.py +++ b/tests/test_response_headers.py @@ -8,11 +8,11 @@ def client(): token=os.environ['THREESCALE_PROVIDER_TOKEN'], ssl_verify=False) def test_x_served_by_ga(client): - response = client._rest.get(url=client.url + "/accounts.json") + response = client._rest.get(url=client.url + "/accounts") assert response.status_code == 200 assert "X-Served-By" not in response.headers def test_x_served_by_mas(client): - response = client._rest.get(url=client.url + "/accounts.json") + response = client._rest.get(url=client.url + "/accounts") assert response.status_code == 200 assert "X-Served-By" in response.headers \ No newline at end of file From 08e367a2e85026ef04e7b61c2eaff7ebad34bef5 Mon Sep 17 00:00:00 2001 From: Jose Manuel Castano Date: Mon, 10 Feb 2025 11:08:15 +0100 Subject: [PATCH 03/19] Adding test for response headers --- tests/test_response_headers.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_response_headers.py b/tests/test_response_headers.py index 728896b..f6c45bf 100644 --- a/tests/test_response_headers.py +++ b/tests/test_response_headers.py @@ -8,11 +8,11 @@ def client(): token=os.environ['THREESCALE_PROVIDER_TOKEN'], ssl_verify=False) def test_x_served_by_ga(client): - response = client._rest.get(url=client.url + "/accounts.json") + response = client._rest.get(url=client.url + "/accounts") assert response.status_code == 200 assert "X-Served-By" not in response.headers def test_x_served_by_mas(client): - response = client._rest.get(url=client.url + "/accounts.json") + response = client._rest.get(url=client.url + "/accounts") assert response.status_code == 200 assert "X-Served-By" in response.headers \ No newline at end of file From c34d833bbbe21fe68268fd6151f89092a875bb89 Mon Sep 17 00:00:00 2001 From: Jose Manuel Castano Date: Fri, 7 Feb 2025 11:11:26 +0100 Subject: [PATCH 04/19] Add test for testing response headers --- tests/test_response_headers.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/test_response_headers.py diff --git a/tests/test_response_headers.py b/tests/test_response_headers.py new file mode 100644 index 0000000..728896b --- /dev/null +++ b/tests/test_response_headers.py @@ -0,0 +1,18 @@ +import threescale_api +import os +import pytest + +@pytest.fixture(scope="module") +def client(): + return threescale_api.ThreeScaleClient(url=os.environ['THREESCALE_PROVIDER_URL'], + token=os.environ['THREESCALE_PROVIDER_TOKEN'], ssl_verify=False) + +def test_x_served_by_ga(client): + response = client._rest.get(url=client.url + "/accounts.json") + assert response.status_code == 200 + assert "X-Served-By" not in response.headers + +def test_x_served_by_mas(client): + response = client._rest.get(url=client.url + "/accounts.json") + assert response.status_code == 200 + assert "X-Served-By" in response.headers \ No newline at end of file From 85d0e94df9a435fdc8b0e6fda29fff629a865708 Mon Sep 17 00:00:00 2001 From: Jose Manuel Castano Date: Fri, 14 Feb 2025 15:18:42 +0100 Subject: [PATCH 05/19] Add test for response headers, modify ServiceSubscription unit test --- .../test_integration_service_subscriptions.py | 19 ++++++++++++++++ tests/test_response_headers.py | 22 ++++++++++--------- threescale_api/resources.py | 9 ++++---- 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/tests/integration/test_integration_service_subscriptions.py b/tests/integration/test_integration_service_subscriptions.py index e2c9a5a..3139978 100644 --- a/tests/integration/test_integration_service_subscriptions.py +++ b/tests/integration/test_integration_service_subscriptions.py @@ -2,6 +2,7 @@ from tests.integration import asserts + def test_list_service_subscriptions(account): resource = account.service_subscriptions.list() assert len(resource) >= 1 @@ -14,3 +15,21 @@ def test_read_service_subscription(account, service_subscription, service_subscr resource = account.service_subscriptions.read(service_subscription.entity_id) asserts.assert_resource(resource) asserts.assert_resource_params(service_subscription,service_subscription_params) + +def test_change_plan_service_subscription(account, account_plan, service_subscription): + asserts.assert_resource(account) + asserts.assert_resource(account_plan) + resource = account.service_subscriptions.change_plan(service_subscription.entity_id, + account_plan.entity_id) + asserts.assert_resource(resource) + + +# TODO: https://issues.redhat.com/browse/THREESCALE-11693 +def test_approve_service_subscription(account, service_subscription,service_subscription_params): + asserts.assert_resource(service_subscription) + service_subscription['state'] = 'pending' + account.service_subscriptions.update(service_subscription.entity_id, + service_subscription_params) + resource = account.service_subscriptions.approve(service_subscription.entity_id) + asserts.assert_resource(resource) + asserts.assert_resource_params(service_subscription, service_subscription_params) diff --git a/tests/test_response_headers.py b/tests/test_response_headers.py index f6c45bf..2274aff 100644 --- a/tests/test_response_headers.py +++ b/tests/test_response_headers.py @@ -1,18 +1,20 @@ -import threescale_api import os import pytest +import threescale_api + @pytest.fixture(scope="module") -def client(): +def cl(): return threescale_api.ThreeScaleClient(url=os.environ['THREESCALE_PROVIDER_URL'], - token=os.environ['THREESCALE_PROVIDER_TOKEN'], ssl_verify=False) + token=os.environ['THREESCALE_PROVIDER_TOKEN'], + ssl_verify=False) -def test_x_served_by_ga(client): - response = client._rest.get(url=client.url + "/accounts") - assert response.status_code == 200 - assert "X-Served-By" not in response.headers -def test_x_served_by_mas(client): - response = client._rest.get(url=client.url + "/accounts") +def test_x_served_by(cl): + + response = cl._rest.get(url=cl.url + '/admin/api/accounts') assert response.status_code == 200 - assert "X-Served-By" in response.headers \ No newline at end of file + if "X-Served-By" in response.headers: + assert True + else: + assert "X-Served-By" not in response.headers diff --git a/threescale_api/resources.py b/threescale_api/resources.py index 8306e0e..6a050d8 100644 --- a/threescale_api/resources.py +++ b/threescale_api/resources.py @@ -286,16 +286,17 @@ def url(self) -> str: return self.parent.url + '/service_subscriptions' def approve(self, entity_id: int, **kwargs): - url = self.url + f"/{entity_id}/approve.json" + url = self.url + f"/{entity_id}/approve" response = self.rest.put(url=url, **kwargs) instance = utils.extract_response(response=response) return instance def change_plan(self, entity_id: int, plan_id: int, **kwargs): - params = {"plan_id": plan_id} - url = self.url + f"/{entity_id}/change_plan.json" - response = self.rest.put(url=url, json=params, **kwargs) + #params = {"plan_id": plan_id} + url = self.url + f"/{entity_id}/change_plan" + response = self.rest.put(url=url,params={"plan_id": plan_id}) instance = utils.extract_response(response=response) + #instance = self._create_instance(response=response) return instance From 5f6f1fc4904f799ff2f41c22a6b3b0ff95b95339 Mon Sep 17 00:00:00 2001 From: Jose Manuel Castano Date: Fri, 14 Feb 2025 15:34:53 +0100 Subject: [PATCH 06/19] Resolve conflicts of lint in PR --- threescale_api/resources.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/threescale_api/resources.py b/threescale_api/resources.py index 6a050d8..8e8d946 100644 --- a/threescale_api/resources.py +++ b/threescale_api/resources.py @@ -292,11 +292,10 @@ def approve(self, entity_id: int, **kwargs): return instance def change_plan(self, entity_id: int, plan_id: int, **kwargs): - #params = {"plan_id": plan_id} + params = {"plan_id": plan_id} url = self.url + f"/{entity_id}/change_plan" - response = self.rest.put(url=url,params={"plan_id": plan_id}) + response = self.rest.put(url=url, params=params) instance = utils.extract_response(response=response) - #instance = self._create_instance(response=response) return instance From 1dfdd236e0cfd271d6c30dc38c5321e5bd071758 Mon Sep 17 00:00:00 2001 From: Jose Manuel Castano Date: Mon, 17 Feb 2025 09:42:28 +0100 Subject: [PATCH 07/19] Add test for response headers --- tests/test_response_headers.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/tests/test_response_headers.py b/tests/test_response_headers.py index 728896b..e8db578 100644 --- a/tests/test_response_headers.py +++ b/tests/test_response_headers.py @@ -1,18 +1,22 @@ -import threescale_api import os import pytest +import threescale_api + @pytest.fixture(scope="module") -def client(): +def cl(): return threescale_api.ThreeScaleClient(url=os.environ['THREESCALE_PROVIDER_URL'], - token=os.environ['THREESCALE_PROVIDER_TOKEN'], ssl_verify=False) + token=os.environ['THREESCALE_PROVIDER_TOKEN'], + ssl_verify=False) -def test_x_served_by_ga(client): - response = client._rest.get(url=client.url + "/accounts.json") - assert response.status_code == 200 - assert "X-Served-By" not in response.headers -def test_x_served_by_mas(client): - response = client._rest.get(url=client.url + "/accounts.json") +def test_x_served_by(cl): + + + response = cl._rest.get(url=cl.url + '/admin/api/accounts') assert response.status_code == 200 - assert "X-Served-By" in response.headers \ No newline at end of file + + if "X-Served-By" in response.headers: + assert True + else: + assert "X-Served-By" not in response.headers From c76479f3d0a0cf7a2e245a8bf01a0657a3603692 Mon Sep 17 00:00:00 2001 From: Martin Pentrak Date: Wed, 13 Nov 2024 16:38:31 +0100 Subject: [PATCH 08/19] admin/api/accounts/{id}/users done Get admin/api/accounts/find Get admin/api/accounts/plan --- tests/integration/conftest.py | 27 ++++++++++- .../test_integration_account_users.py | 46 +++++++++++++++++++ .../integration/test_integration_accounts.py | 12 +++++ threescale_api/defaults.py | 14 +++++- threescale_api/resources.py | 19 ++++++++ 5 files changed, 115 insertions(+), 3 deletions(-) create mode 100644 tests/integration/test_integration_account_users.py diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index c79850a..d16a882 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -13,7 +13,7 @@ Proxy, Backend, Metric, MappingRule, BackendMappingRule, BackendUsage, ActiveDoc, Webhooks, InvoiceState, - ApplicationKey, ApplicationPlans) + ApplicationKey, ApplicationPlans, AccountUser, AccountUsers) load_dotenv() @@ -109,6 +109,11 @@ def update_account_params(): return dict(org_name=name) +@pytest.fixture(scope='module') +def account_get_plan_params(): + return dict(name="Default") + + @pytest.fixture(scope='module') def account_params(): suffix = get_suffix() @@ -123,6 +128,26 @@ def account(account_params, api): cleanup(entity) +@pytest.fixture(scope='module') +def account_user_update_params(): + suffix = get_suffix() + name = f"test-update-{suffix}" + return dict(username=name, email=f"{name}@email.com") + + +@pytest.fixture(scope='module') +def account_user_params(): + suffix = get_suffix() + name = f"test-{suffix}" + return dict(username=name, email=f"{name}@email.com") + + +@pytest.fixture(scope='module') +def account_user(account,account_user_params) -> AccountUser: + user = account.users.create(account_user_params) + yield user + cleanup(user) + @pytest.fixture(scope='module') def application_plan_params() -> dict: suffix = get_suffix() diff --git a/tests/integration/test_integration_account_users.py b/tests/integration/test_integration_account_users.py new file mode 100644 index 0000000..d5792e2 --- /dev/null +++ b/tests/integration/test_integration_account_users.py @@ -0,0 +1,46 @@ +from tests.integration import asserts +from tests.integration.conftest import account + + +def test_account_user_can_be_created(account_user, account_user_params): + asserts.assert_resource(account_user) + asserts.assert_resource_params(account_user, account_user_params) + + +def test_account_users_list(api,account, account_user): + users = account.users.list() + assert len(users) > 1 + + +def test_account_users_get_by_id(account, account_user, account_user_params): + account_user = account.users.read(account_user['id']) + asserts.assert_resource(account_user) + asserts.assert_resource_params(account_user, account_user_params) + + +def test_account_user_can_be_updated(account_user, account_user_update_params): + updated_user = account_user.update(account_user_update_params) + asserts.assert_resource(updated_user) + asserts.assert_resource_params(updated_user, account_user_update_params) + + +def test_account_user_change_status(account_user): + assert account_user['state'] == 'pending' + updated_account_user = account_user.activate() + assert updated_account_user['state'] == 'active' + + updated_account_user = account_user.suspend() + assert updated_account_user['state'] == 'suspended' + + updated_account_user = account_user.un_suspend() + assert updated_account_user['state'] == 'active' + + +def test_account_user_change_role(account_user): + assert account_user['role'] == 'member' + + updated_account_user = account_user.set_as_admin() + assert updated_account_user['role'] == 'admin' + + updated_account_user = account_user.set_as_member() + assert updated_account_user['role'] == 'member' diff --git a/tests/integration/test_integration_accounts.py b/tests/integration/test_integration_accounts.py index 8f96492..e796ed3 100644 --- a/tests/integration/test_integration_accounts.py +++ b/tests/integration/test_integration_accounts.py @@ -24,11 +24,23 @@ def test_account_can_be_read_by_name(api, account, account_params): asserts.assert_resource_params(read, account_params, ['org_name']) +def test_account_can_be_find_by_name(api, account_user, account_params): + account2 = api.accounts.find(dict(username=account_user['username'])) + asserts.assert_resource(account2) + asserts.assert_resource_params(account2, account_params, ['org_name']) + + def test_account_update(api,account, update_account_params): updated_account = account.update(params=update_account_params) asserts.assert_resource(updated_account) asserts.assert_resource_params(updated_account, update_account_params) +def test_get_account_plan(account, account_get_plan_params): + plan = account.get_account_plan() + asserts.assert_resource(plan) + asserts.assert_resource_params(plan,account_get_plan_params, ['name']) + + def test_users_list(api, account): assert len(account.users.list()) >= 1 diff --git a/threescale_api/defaults.py b/threescale_api/defaults.py index 500f1a5..833316b 100644 --- a/threescale_api/defaults.py +++ b/threescale_api/defaults.py @@ -516,6 +516,16 @@ def suspend(self, **kwargs) -> 'DefaultUserResource': """ return self.set_state(state='suspend', **kwargs) + def un_suspend(self, **kwargs) -> 'DefaultUserResource': + """Un suspends the user + Args: + **kwargs: + Optional arguments + Returns(DefaultUserResource): User instance + + """ + return self.set_state(state='unsuspend', **kwargs) + def resume(self, **kwargs): """Resumes the user Args: @@ -541,7 +551,7 @@ def set_as_admin(self, **kwargs): Returns(DefaultUserResource): User instance """ - return self.set_state(state='set_as_admin', **kwargs) + return self.set_state(state='admin', **kwargs) def set_as_member(self, **kwargs): """Demotes the user to s member @@ -550,4 +560,4 @@ def set_as_member(self, **kwargs): Returns(DefaultUserResource): User instance """ - return self.set_state(state='set_as_member', **kwargs) + return self.set_state(state='member', **kwargs) diff --git a/threescale_api/resources.py b/threescale_api/resources.py index b63cd34..1a9f015 100644 --- a/threescale_api/resources.py +++ b/threescale_api/resources.py @@ -188,6 +188,19 @@ def create(self, params: dict = None, **kwargs) -> 'Account': """ return self.signup(params=params, **kwargs) + def find(self, params: dict, **kwargs) -> 'Account': + """Find an account + Args: + params(dict): Parameters to used to find account (name, email, etc) + **kwargs: Optional args + Returns(Account): Account instance + """ + log.info("[FIND] Find accout: paramas:%s, kwarfs=%s", params, kwargs) + find_url = self.url + "/find" + response = self.rest.get(path=find_url, json=params, **kwargs) + instance = self._create_instance(response=response) + return instance + def signup(self, params: dict, **kwargs) -> 'Account': """Sign Up for an account Args: @@ -1470,6 +1483,12 @@ def credit_card_delete(self, params: dict = None, **kwargs): response = self.client.rest.delete(url=url, json=params, **kwargs) return response + def get_account_plan(self, params: dict = None, **kwargs): + account_plans = AccountPlans(self, ApplicationPlan) + url = self.url + "/plan" + response = self.client.rest.get(url=url, json=params, **kwargs) + return account_plans._create_instance(response=response) + class UserPermissions(DefaultResource): pass From 5ecfd7df8e324e8fc1ed9c35696e70ea72c475e5 Mon Sep 17 00:00:00 2001 From: joscasta Date: Mon, 27 Jan 2025 16:55:47 +0100 Subject: [PATCH 09/19] Adding Service Subscription and Service Plan resources and tests for Service Subscription --- tests/integration/conftest.py | 14 ++- .../test_integration_service_subscriptions.py | 39 ++++++++ threescale_api/resources.py | 89 +++++++++++++++++++ 3 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 tests/integration/test_integration_service_subscriptions.py diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index d16a882..04ad00e 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -11,9 +11,9 @@ import threescale_api from threescale_api.resources import (Service, ApplicationPlan, Application, Proxy, Backend, Metric, MappingRule, - BackendMappingRule, BackendUsage, + BackendMappingRule, Account, BackendUsage, ActiveDoc, Webhooks, InvoiceState, - ApplicationKey, ApplicationPlans, AccountUser, AccountUsers) + ApplicationKey, ApplicationPlans, AccountUser, AccountUsers, ServiceSubscription) load_dotenv() @@ -148,6 +148,16 @@ def account_user(account,account_user_params) -> AccountUser: yield user cleanup(user) +@pytest.fixture(scope='module') +def service_subscription_params(account) -> dict: + #suffix = get_suffix() + return dict(plan_id=account['id']) + +@pytest.fixture(scope='module') +def service_subscription(account, service_subscription_params) -> ServiceSubscription: + resource = account.service_subscriptions.create(params=service_subscription_params) + yield resource + @pytest.fixture(scope='module') def application_plan_params() -> dict: suffix = get_suffix() diff --git a/tests/integration/test_integration_service_subscriptions.py b/tests/integration/test_integration_service_subscriptions.py new file mode 100644 index 0000000..25252ec --- /dev/null +++ b/tests/integration/test_integration_service_subscriptions.py @@ -0,0 +1,39 @@ +import pytest +import backoff + +from tests.integration.conftest import account +from threescale_api.errors import ApiClientError + +from tests.integration import asserts + +def test_should_create_service_subscription(account, service_subscription, service_subscription_params): + + account.service_subscriptions.create(params=service_subscription_params) + resource = service_subscription.get(service_subscription_params) + asserts.assert_resource(resource) + asserts.assert_resource_params(account, service_subscription_params, [param for param in service_subscription_params.keys() if param != 'id']) + +def test_should_read_service_subscription(account, service_subscription, service_subscription_params): + resource = account.service_subscriptions.get(params=service_subscription_params) + asserts.assert_resource(resource) + asserts.assert_resource_params(resource, service_subscription_params, [param for param in service_subscription_params.keys() if param != 'id']) + +#def test_should_update_service_subscription(account, service_subscription, service_subscription_params): +# service_subscription_params['plan_id'] = 100 +# resource = account.service_subscriptions.update(service_subscription.entity_id, service_subscription_params) +# asserts.assert_resource(resource) +# asserts.assert_resource_params(resource, service_subscription_params, [param for param in service_subscription_params.keys() if param != 'id']) +# resource_updated = account.service_subscription.read(params=service_subscription_params) +# asserts.assert_resource(resource_updated) +# asserts.assert_resource_params(resource_updated, service_subscription_params, [param for param in service_subscription_params.keys() if param != 'id']) + +#def test_should_approve_service_subscription(account, service_subscription, service_subscription_params): +# resource = account.service_subscriptions.approve_service_subscription(params=service_subscription_params) +# asserts.assert_resource(resource) +# read = account.service_subscriptions.read(service_subscription.entity_id) +# asserts.assert_resource(read) + +def test_list_service_subscriptions(account): + resource = account.service_subscriptions.list() + assert len(resource) >= 1 + diff --git a/threescale_api/resources.py b/threescale_api/resources.py index 1a9f015..5657a2d 100644 --- a/threescale_api/resources.py +++ b/threescale_api/resources.py @@ -3,6 +3,8 @@ from typing import Dict, Union, List, Iterable from urllib.parse import quote_plus +from dill.pointers import parent + from threescale_api import auth from threescale_api import utils from threescale_api import errors @@ -273,6 +275,59 @@ def pending(self, entity_id, **kwargs) -> 'Account': """ return self.set_state(entity_id=entity_id, state='make_pending', **kwargs) +class ServiceSubscriptions(DefaultClient): + def __init__(self, *args, entity_name='service_subscription', entity_collection='service_subscriptions', + per_page=None, **kwargs): + super().__init__(*args, entity_name=entity_name, + entity_collection=entity_collection, **kwargs) + + @property + def url(self) -> str: + return self.parent.url + '/service_subscriptions' + + def approve_service_subscription(self, entity_id: int, **kwargs): + url = self.url + f"/{entity_id}/approve.json" + response = self.rest.put(url=url, **kwargs) + instance = utils.extract_response(response=response) + return instance + + def change_plan_service_subscription(self, entity_id: int, plan_id: int, **kwargs): + params = dict(plan_id=plan_id) + url = self.url + f"/{entity_id}/change_plan.json" + response = self.rest.put(url=url, json=params, **kwargs) + instance = utils.extract_response(response=response) + return instance + +class ServicePlans(DefaultClient): + def __init__(self, *args, entity_name='service_plan', entity_collection='service_plans', per_page=None, **kwargs): + super().__init__(*args, entity_name=entity_name, + entity_collection=entity_collection, **kwargs) + + def url(self) -> str: + if type(self.parent) is Service: + return self.parent.url + '/service_plans' + return self.threescale_client.admin_api_url + '/service_plans' + + def service_plans_features_list(self, entity_id: int, **kwargs): + url = self.url + f"/{entity_id}/features.xml" + response = self.rest.get(url=url) + instance = utils.extract_response(response) + return instance + + def service_plan_add_feature(self, entity_id: int, feature_id: int, **kwargs): + params = dict(feature_id=feature_id) + url = self.url + f"/{entity_id}/features.xml" + response = self.rest.post(url=url, json=params, **kwargs) + instance = utils.extract_response(response=response) + return instance + + def service_plan_delete_feature(self, entity_id: int, id: int, **kwargs): + params = dict(id=id) + url = self.url + f"/{entity_id}/features/{id}.xml" + response = self.rest.delete(url=url, json=params, **kwargs) + instance = utils.extract_response(response=response) + return instance + class Applications(DefaultStateClient): def __init__(self, *args, entity_name='application', entity_collection='applications', @@ -1138,6 +1193,16 @@ def service(self) -> 'Service': def backend(self) -> 'Backend': return self.metric.parent +class ServiceSubscription(DefaultResource): + def __init__(self, **kwargs): + super().__init__(**kwargs) + + def approve_service_subscription(self, entity_id: int, **kwargs): + return self.client.approve_service_subscription(entity_id=self.entity_id, **kwargs) + + def change_plan_service_subscription(self, entity_id: int, **kwargs): + return self.client.change_plan_service_subscription(entity_id=self.entity_id, **kwargs) + class Metric(DefaultResource): def __init__(self, entity_name='system_name', **kwargs): @@ -1249,6 +1314,10 @@ def app_plans(self) -> ApplicationPlans: def metrics(self) -> Metrics: return Metrics(parent=self, instance_klass=Metric) + @property + def service_plans(self) -> ServicePlans: + return ServicePlans(parent=self, instance_klass=ServicePlan) + @property def proxy(self) -> 'Proxies': return Proxies(parent=self, instance_klass=Proxy) @@ -1455,6 +1524,22 @@ def test_request(self, relpath=None, verify: bool = None): return client.get(relpath) +class ServicePlan(DefaultResource): + def __init__(self, **kwargs): + super().__init__(**kwargs) + + def service_plan_list(self, **kwargs): + return self.client.service_plan_list(self, **kwargs) + + def service_plan_features_list(self, entity_id: int, **kwargs): + return self.client.service_plan_features_list(entity_id=self.entity_id, **kwargs) + + def service_plan_add_feature(self, entity_id: int, id: int, **kwargs): + return self.client.service_plan_add_feature(entity_id=id, id=id, **kwargs) + + def service_plan_delete_feature(self, entity_id: int, id: int, **kwargs): + return self.client.service_plan_delete_feature(entity_id=entity_id, id=id, **kwargs) + class ApplicationKey(DefaultResource): def __init__(self, entity_name='', **kwargs): @@ -1473,6 +1558,10 @@ def applications(self) -> Applications: def users(self) -> AccountUsers: return AccountUsers(parent=self, instance_klass=AccountUser) + @property + def service_subscriptions(self) -> ServiceSubscriptions: + return ServiceSubscriptions(parent=self, instance_klass=ServiceSubscription) + def credit_card_set(self, params: dict = None, **kwargs): url = self.url + "/credit_card" response = self.client.rest.put(url=url, json=params, **kwargs) From b1e1838d05e0f0da4d51ffcebc75a4adfb3d74c2 Mon Sep 17 00:00:00 2001 From: Jose Manuel Castano Date: Mon, 27 Jan 2025 17:25:19 +0100 Subject: [PATCH 10/19] Changes made in response to PR comments. --- threescale_api/resources.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/threescale_api/resources.py b/threescale_api/resources.py index 5657a2d..5fef004 100644 --- a/threescale_api/resources.py +++ b/threescale_api/resources.py @@ -3,8 +3,6 @@ from typing import Dict, Union, List, Iterable from urllib.parse import quote_plus -from dill.pointers import parent - from threescale_api import auth from threescale_api import utils from threescale_api import errors @@ -276,7 +274,9 @@ def pending(self, entity_id, **kwargs) -> 'Account': return self.set_state(entity_id=entity_id, state='make_pending', **kwargs) class ServiceSubscriptions(DefaultClient): - def __init__(self, *args, entity_name='service_subscription', entity_collection='service_subscriptions', + + def __init__(self, *args, entity_name='service_subscription', + entity_collection='service_subscriptions', per_page=None, **kwargs): super().__init__(*args, entity_name=entity_name, entity_collection=entity_collection, **kwargs) @@ -299,7 +299,9 @@ def change_plan_service_subscription(self, entity_id: int, plan_id: int, **kwarg return instance class ServicePlans(DefaultClient): - def __init__(self, *args, entity_name='service_plan', entity_collection='service_plans', per_page=None, **kwargs): + + def __init__(self, *args, entity_name='service_plan', + entity_collection='service_plans', per_page=None, **kwargs): super().__init__(*args, entity_name=entity_name, entity_collection=entity_collection, **kwargs) @@ -1194,6 +1196,7 @@ def backend(self) -> 'Backend': return self.metric.parent class ServiceSubscription(DefaultResource): + def __init__(self, **kwargs): super().__init__(**kwargs) @@ -1525,6 +1528,7 @@ def test_request(self, relpath=None, verify: bool = None): return client.get(relpath) class ServicePlan(DefaultResource): + def __init__(self, **kwargs): super().__init__(**kwargs) From 5f8e2e5c796d7a8c3422b3f4d4ecc770833e1f60 Mon Sep 17 00:00:00 2001 From: Jose Manuel Castano Date: Tue, 28 Jan 2025 17:05:29 +0100 Subject: [PATCH 11/19] Update tests for test_integration_service_subscriptions. Add Service Plan resources. --- tests/integration/conftest.py | 20 ++++++++-- .../test_integration_service_subscriptions.py | 19 +++++----- threescale_api/resources.py | 37 +------------------ 3 files changed, 28 insertions(+), 48 deletions(-) diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 04ad00e..afe0e5b 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -13,7 +13,8 @@ Proxy, Backend, Metric, MappingRule, BackendMappingRule, Account, BackendUsage, ActiveDoc, Webhooks, InvoiceState, - ApplicationKey, ApplicationPlans, AccountUser, AccountUsers, ServiceSubscription) + ApplicationKey, ApplicationPlans, AccountUser, AccountUsers, ServiceSubscription, + ServicePlan) load_dotenv() @@ -149,9 +150,20 @@ def account_user(account,account_user_params) -> AccountUser: cleanup(user) @pytest.fixture(scope='module') -def service_subscription_params(account) -> dict: - #suffix = get_suffix() - return dict(plan_id=account['id']) +def service_plan_params() -> dict: + suffix = get_suffix() + return dict(name=f"test-{suffix}") + +@pytest.fixture(scope='module') +def service_plan(service, service_plan_params) -> ServicePlan: + + resource = service.service_plans.create(params=service_plan_params) + yield resource + +@pytest.fixture(scope='module') +def service_subscription_params(service_plan) -> dict: + suffix = get_suffix() + return dict(plan_id=service_plan['id']) @pytest.fixture(scope='module') def service_subscription(account, service_subscription_params) -> ServiceSubscription: diff --git a/tests/integration/test_integration_service_subscriptions.py b/tests/integration/test_integration_service_subscriptions.py index 25252ec..02d8cf6 100644 --- a/tests/integration/test_integration_service_subscriptions.py +++ b/tests/integration/test_integration_service_subscriptions.py @@ -6,17 +6,21 @@ from tests.integration import asserts +def test_list_service_subscriptions(account, service_subscription): + resource = account.service_subscriptions.list() + assert len(resource) >= 1 + def test_should_create_service_subscription(account, service_subscription, service_subscription_params): - account.service_subscriptions.create(params=service_subscription_params) - resource = service_subscription.get(service_subscription_params) - asserts.assert_resource(resource) - asserts.assert_resource_params(account, service_subscription_params, [param for param in service_subscription_params.keys() if param != 'id']) + asserts.assert_resource(service_subscription) + asserts.assert_resource_params(service_subscription, service_subscription_params) def test_should_read_service_subscription(account, service_subscription, service_subscription_params): - resource = account.service_subscriptions.get(params=service_subscription_params) + + + resource = account.service_subscriptions.read(service_subscription.entity_id) asserts.assert_resource(resource) - asserts.assert_resource_params(resource, service_subscription_params, [param for param in service_subscription_params.keys() if param != 'id']) + asserts.assert_resource_params(service_subscription,service_subscription_params) #def test_should_update_service_subscription(account, service_subscription, service_subscription_params): # service_subscription_params['plan_id'] = 100 @@ -33,7 +37,4 @@ def test_should_read_service_subscription(account, service_subscription, service # read = account.service_subscriptions.read(service_subscription.entity_id) # asserts.assert_resource(read) -def test_list_service_subscriptions(account): - resource = account.service_subscriptions.list() - assert len(resource) >= 1 diff --git a/threescale_api/resources.py b/threescale_api/resources.py index 5fef004..594864e 100644 --- a/threescale_api/resources.py +++ b/threescale_api/resources.py @@ -305,30 +305,10 @@ def __init__(self, *args, entity_name='service_plan', super().__init__(*args, entity_name=entity_name, entity_collection=entity_collection, **kwargs) + @property def url(self) -> str: - if type(self.parent) is Service: - return self.parent.url + '/service_plans' - return self.threescale_client.admin_api_url + '/service_plans' - - def service_plans_features_list(self, entity_id: int, **kwargs): - url = self.url + f"/{entity_id}/features.xml" - response = self.rest.get(url=url) - instance = utils.extract_response(response) - return instance - - def service_plan_add_feature(self, entity_id: int, feature_id: int, **kwargs): - params = dict(feature_id=feature_id) - url = self.url + f"/{entity_id}/features.xml" - response = self.rest.post(url=url, json=params, **kwargs) - instance = utils.extract_response(response=response) - return instance + return self.parent.url + '/service_plans' - def service_plan_delete_feature(self, entity_id: int, id: int, **kwargs): - params = dict(id=id) - url = self.url + f"/{entity_id}/features/{id}.xml" - response = self.rest.delete(url=url, json=params, **kwargs) - instance = utils.extract_response(response=response) - return instance class Applications(DefaultStateClient): @@ -1532,19 +1512,6 @@ class ServicePlan(DefaultResource): def __init__(self, **kwargs): super().__init__(**kwargs) - def service_plan_list(self, **kwargs): - return self.client.service_plan_list(self, **kwargs) - - def service_plan_features_list(self, entity_id: int, **kwargs): - return self.client.service_plan_features_list(entity_id=self.entity_id, **kwargs) - - def service_plan_add_feature(self, entity_id: int, id: int, **kwargs): - return self.client.service_plan_add_feature(entity_id=id, id=id, **kwargs) - - def service_plan_delete_feature(self, entity_id: int, id: int, **kwargs): - return self.client.service_plan_delete_feature(entity_id=entity_id, id=id, **kwargs) - - class ApplicationKey(DefaultResource): def __init__(self, entity_name='', **kwargs): super().__init__(entity_name=entity_name, **kwargs) From 833729744473ce18746805ca7f6e0b8c78c2589a Mon Sep 17 00:00:00 2001 From: Jose Manuel Castano Date: Thu, 30 Jan 2025 15:29:09 +0100 Subject: [PATCH 12/19] Adding resources for Service Plan and the equivalent unit tests --- tests/integration/conftest.py | 2 +- .../test_integration_service_plans.py | 36 +++++++++++++++++++ .../test_integration_service_subscriptions.py | 17 --------- threescale_api/resources.py | 13 +++++++ 4 files changed, 50 insertions(+), 18 deletions(-) create mode 100644 tests/integration/test_integration_service_plans.py diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index afe0e5b..c07d8a3 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -150,7 +150,7 @@ def account_user(account,account_user_params) -> AccountUser: cleanup(user) @pytest.fixture(scope='module') -def service_plan_params() -> dict: +def service_plan_params(service) -> dict: suffix = get_suffix() return dict(name=f"test-{suffix}") diff --git a/tests/integration/test_integration_service_plans.py b/tests/integration/test_integration_service_plans.py new file mode 100644 index 0000000..8ff6015 --- /dev/null +++ b/tests/integration/test_integration_service_plans.py @@ -0,0 +1,36 @@ +import pytest + + +from tests.integration.conftest import service +from threescale_api.errors import ApiClientError + +from tests.integration import asserts + +def test_list_service_plans(service, service_plan): + resource = service.service_plans.list() + assert len(resource) >= 1 + +def test_check_service_plan_creation(service, service_plan, service_plan_params): + asserts.assert_resource(service_plan) + asserts.assert_resource_params(service_plan, service_plan_params) + assert service_plan.exists() + +def test_read_service_plans(service, service_plan, service_plan_params): + asserts.assert_resource(service_plan) + resource = service.service_plans.read(service_plan.entity_id) + asserts.assert_resource(resource) + asserts.assert_resource_params(service_plan,service_plan_params) + +def test_update_service_plans(service, service_plan, service_plan_params): + asserts.assert_resource(service_plan) + service_plan['state'] = 'publish' + service_plan['approval_required'] = True + resource = service.service_plans.update(service_plan.entity_id, service_plan_params) + asserts.assert_resource(resource) + asserts.assert_resource_params(service_plan, service_plan_params) + +def test_set_default_service_plan(service, service_plan, service_plan_params): + asserts.assert_resource(service_plan) + resource = service_plan.set_default() + asserts.assert_resource(resource) + asserts.assert_resource_params(service_plan, service_plan_params) diff --git a/tests/integration/test_integration_service_subscriptions.py b/tests/integration/test_integration_service_subscriptions.py index 02d8cf6..e1d81de 100644 --- a/tests/integration/test_integration_service_subscriptions.py +++ b/tests/integration/test_integration_service_subscriptions.py @@ -11,30 +11,13 @@ def test_list_service_subscriptions(account, service_subscription): assert len(resource) >= 1 def test_should_create_service_subscription(account, service_subscription, service_subscription_params): - asserts.assert_resource(service_subscription) asserts.assert_resource_params(service_subscription, service_subscription_params) def test_should_read_service_subscription(account, service_subscription, service_subscription_params): - - resource = account.service_subscriptions.read(service_subscription.entity_id) asserts.assert_resource(resource) asserts.assert_resource_params(service_subscription,service_subscription_params) -#def test_should_update_service_subscription(account, service_subscription, service_subscription_params): -# service_subscription_params['plan_id'] = 100 -# resource = account.service_subscriptions.update(service_subscription.entity_id, service_subscription_params) -# asserts.assert_resource(resource) -# asserts.assert_resource_params(resource, service_subscription_params, [param for param in service_subscription_params.keys() if param != 'id']) -# resource_updated = account.service_subscription.read(params=service_subscription_params) -# asserts.assert_resource(resource_updated) -# asserts.assert_resource_params(resource_updated, service_subscription_params, [param for param in service_subscription_params.keys() if param != 'id']) - -#def test_should_approve_service_subscription(account, service_subscription, service_subscription_params): -# resource = account.service_subscriptions.approve_service_subscription(params=service_subscription_params) -# asserts.assert_resource(resource) -# read = account.service_subscriptions.read(service_subscription.entity_id) -# asserts.assert_resource(read) diff --git a/threescale_api/resources.py b/threescale_api/resources.py index 594864e..ea10692 100644 --- a/threescale_api/resources.py +++ b/threescale_api/resources.py @@ -273,6 +273,7 @@ def pending(self, entity_id, **kwargs) -> 'Account': """ return self.set_state(entity_id=entity_id, state='make_pending', **kwargs) + class ServiceSubscriptions(DefaultClient): def __init__(self, *args, entity_name='service_subscription', @@ -298,6 +299,7 @@ def change_plan_service_subscription(self, entity_id: int, plan_id: int, **kwarg instance = utils.extract_response(response=response) return instance + class ServicePlans(DefaultClient): def __init__(self, *args, entity_name='service_plan', @@ -309,6 +311,11 @@ def __init__(self, *args, entity_name='service_plan', def url(self) -> str: return self.parent.url + '/service_plans' + def service_plan_set_default(self, entity_id: int, **kwargs): + url = self.url + f"/{entity_id}/default" + response = self.rest.put(url=url, **kwargs) + instance = self._create_instance(response=response) + return instance class Applications(DefaultStateClient): @@ -1175,6 +1182,7 @@ def service(self) -> 'Service': def backend(self) -> 'Backend': return self.metric.parent + class ServiceSubscription(DefaultResource): def __init__(self, **kwargs): @@ -1507,11 +1515,16 @@ def test_request(self, relpath=None, verify: bool = None): return client.get(relpath) + class ServicePlan(DefaultResource): def __init__(self, **kwargs): super().__init__(**kwargs) + def set_default(self, **kwargs): + return self.client.service_plan_set_default(entity_id=self.entity_id, **kwargs) + + class ApplicationKey(DefaultResource): def __init__(self, entity_name='', **kwargs): super().__init__(entity_name=entity_name, **kwargs) From bdc138c2772c8cfd96667c11f3dcf7c08a657ba8 Mon Sep 17 00:00:00 2001 From: Jose Manuel Castano Date: Wed, 5 Feb 2025 15:27:24 +0100 Subject: [PATCH 13/19] Implement suggested changes from PR review. --- tests/integration/conftest.py | 3 ++- tests/integration/test_integration_service_plans.py | 10 +++------- .../test_integration_service_subscriptions.py | 13 +++---------- threescale_api/resources.py | 8 ++++---- 4 files changed, 12 insertions(+), 22 deletions(-) diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index c07d8a3..5faa692 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -156,9 +156,9 @@ def service_plan_params(service) -> dict: @pytest.fixture(scope='module') def service_plan(service, service_plan_params) -> ServicePlan: - resource = service.service_plans.create(params=service_plan_params) yield resource + cleanup(resource) @pytest.fixture(scope='module') def service_subscription_params(service_plan) -> dict: @@ -169,6 +169,7 @@ def service_subscription_params(service_plan) -> dict: def service_subscription(account, service_subscription_params) -> ServiceSubscription: resource = account.service_subscriptions.create(params=service_subscription_params) yield resource + cleanup(resource) @pytest.fixture(scope='module') def application_plan_params() -> dict: diff --git a/tests/integration/test_integration_service_plans.py b/tests/integration/test_integration_service_plans.py index 8ff6015..7277061 100644 --- a/tests/integration/test_integration_service_plans.py +++ b/tests/integration/test_integration_service_plans.py @@ -1,16 +1,12 @@ -import pytest -from tests.integration.conftest import service -from threescale_api.errors import ApiClientError - from tests.integration import asserts -def test_list_service_plans(service, service_plan): +def test_list_service_plans(service): resource = service.service_plans.list() assert len(resource) >= 1 -def test_check_service_plan_creation(service, service_plan, service_plan_params): +def test_check_service_plan_creation(service_plan, service_plan_params): asserts.assert_resource(service_plan) asserts.assert_resource_params(service_plan, service_plan_params) assert service_plan.exists() @@ -29,7 +25,7 @@ def test_update_service_plans(service, service_plan, service_plan_params): asserts.assert_resource(resource) asserts.assert_resource_params(service_plan, service_plan_params) -def test_set_default_service_plan(service, service_plan, service_plan_params): +def test_set_default_service_plan(service_plan, service_plan_params): asserts.assert_resource(service_plan) resource = service_plan.set_default() asserts.assert_resource(resource) diff --git a/tests/integration/test_integration_service_subscriptions.py b/tests/integration/test_integration_service_subscriptions.py index e1d81de..e2c9a5a 100644 --- a/tests/integration/test_integration_service_subscriptions.py +++ b/tests/integration/test_integration_service_subscriptions.py @@ -1,23 +1,16 @@ -import pytest -import backoff -from tests.integration.conftest import account -from threescale_api.errors import ApiClientError from tests.integration import asserts -def test_list_service_subscriptions(account, service_subscription): +def test_list_service_subscriptions(account): resource = account.service_subscriptions.list() assert len(resource) >= 1 -def test_should_create_service_subscription(account, service_subscription, service_subscription_params): +def test_create_service_subscription(service_subscription, service_subscription_params): asserts.assert_resource(service_subscription) asserts.assert_resource_params(service_subscription, service_subscription_params) -def test_should_read_service_subscription(account, service_subscription, service_subscription_params): +def test_read_service_subscription(account, service_subscription, service_subscription_params): resource = account.service_subscriptions.read(service_subscription.entity_id) asserts.assert_resource(resource) asserts.assert_resource_params(service_subscription,service_subscription_params) - - - diff --git a/threescale_api/resources.py b/threescale_api/resources.py index ea10692..5e63eb1 100644 --- a/threescale_api/resources.py +++ b/threescale_api/resources.py @@ -286,13 +286,13 @@ def __init__(self, *args, entity_name='service_subscription', def url(self) -> str: return self.parent.url + '/service_subscriptions' - def approve_service_subscription(self, entity_id: int, **kwargs): + def approve(self, entity_id: int, **kwargs): url = self.url + f"/{entity_id}/approve.json" response = self.rest.put(url=url, **kwargs) instance = utils.extract_response(response=response) return instance - def change_plan_service_subscription(self, entity_id: int, plan_id: int, **kwargs): + def change_plan(self, entity_id: int, plan_id: int, **kwargs): params = dict(plan_id=plan_id) url = self.url + f"/{entity_id}/change_plan.json" response = self.rest.put(url=url, json=params, **kwargs) @@ -1188,10 +1188,10 @@ class ServiceSubscription(DefaultResource): def __init__(self, **kwargs): super().__init__(**kwargs) - def approve_service_subscription(self, entity_id: int, **kwargs): + def approve(self, entity_id: int, **kwargs): return self.client.approve_service_subscription(entity_id=self.entity_id, **kwargs) - def change_plan_service_subscription(self, entity_id: int, **kwargs): + def change_plan(self, entity_id: int, **kwargs): return self.client.change_plan_service_subscription(entity_id=self.entity_id, **kwargs) From 8d8c1e1ecd5d4d0684bf994b9d4bf40e72275ee4 Mon Sep 17 00:00:00 2001 From: Jose Manuel Castano Date: Wed, 5 Feb 2025 15:30:52 +0100 Subject: [PATCH 14/19] Fix missing correct nammes in DefaultResoruce ServiceSubscription --- threescale_api/resources.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/threescale_api/resources.py b/threescale_api/resources.py index 5e63eb1..cc9bca4 100644 --- a/threescale_api/resources.py +++ b/threescale_api/resources.py @@ -1189,10 +1189,10 @@ def __init__(self, **kwargs): super().__init__(**kwargs) def approve(self, entity_id: int, **kwargs): - return self.client.approve_service_subscription(entity_id=self.entity_id, **kwargs) + return self.client.approve(entity_id=self.entity_id, **kwargs) def change_plan(self, entity_id: int, **kwargs): - return self.client.change_plan_service_subscription(entity_id=self.entity_id, **kwargs) + return self.client.change_plan(entity_id=self.entity_id, **kwargs) class Metric(DefaultResource): From b6057922856a6c1c0a9c9c154c876fe6cba4c2c8 Mon Sep 17 00:00:00 2001 From: Jose Manuel Castano Date: Thu, 6 Feb 2025 09:49:46 +0100 Subject: [PATCH 15/19] Fix minor bugs in PR after review. --- tests/integration/conftest.py | 7 +++---- threescale_api/resources.py | 11 +++++------ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/tests/integration/conftest.py b/tests/integration/conftest.py index 5faa692..ebc2147 100644 --- a/tests/integration/conftest.py +++ b/tests/integration/conftest.py @@ -150,9 +150,9 @@ def account_user(account,account_user_params) -> AccountUser: cleanup(user) @pytest.fixture(scope='module') -def service_plan_params(service) -> dict: +def service_plan_params() -> dict: suffix = get_suffix() - return dict(name=f"test-{suffix}") + return {"name":f'test-{suffix}'} @pytest.fixture(scope='module') def service_plan(service, service_plan_params) -> ServicePlan: @@ -162,8 +162,7 @@ def service_plan(service, service_plan_params) -> ServicePlan: @pytest.fixture(scope='module') def service_subscription_params(service_plan) -> dict: - suffix = get_suffix() - return dict(plan_id=service_plan['id']) + return {"plan_id":service_plan['id']} @pytest.fixture(scope='module') def service_subscription(account, service_subscription_params) -> ServiceSubscription: diff --git a/threescale_api/resources.py b/threescale_api/resources.py index cc9bca4..d73cdf2 100644 --- a/threescale_api/resources.py +++ b/threescale_api/resources.py @@ -277,8 +277,7 @@ def pending(self, entity_id, **kwargs) -> 'Account': class ServiceSubscriptions(DefaultClient): def __init__(self, *args, entity_name='service_subscription', - entity_collection='service_subscriptions', - per_page=None, **kwargs): + entity_collection='service_subscriptions', **kwargs): super().__init__(*args, entity_name=entity_name, entity_collection=entity_collection, **kwargs) @@ -293,7 +292,7 @@ def approve(self, entity_id: int, **kwargs): return instance def change_plan(self, entity_id: int, plan_id: int, **kwargs): - params = dict(plan_id=plan_id) + params = {"plan_id":plan_id} url = self.url + f"/{entity_id}/change_plan.json" response = self.rest.put(url=url, json=params, **kwargs) instance = utils.extract_response(response=response) @@ -303,7 +302,7 @@ def change_plan(self, entity_id: int, plan_id: int, **kwargs): class ServicePlans(DefaultClient): def __init__(self, *args, entity_name='service_plan', - entity_collection='service_plans', per_page=None, **kwargs): + entity_collection='service_plans', **kwargs): super().__init__(*args, entity_name=entity_name, entity_collection=entity_collection, **kwargs) @@ -1188,10 +1187,10 @@ class ServiceSubscription(DefaultResource): def __init__(self, **kwargs): super().__init__(**kwargs) - def approve(self, entity_id: int, **kwargs): + def approve(self, **kwargs): return self.client.approve(entity_id=self.entity_id, **kwargs) - def change_plan(self, entity_id: int, **kwargs): + def change_plan(self, **kwargs): return self.client.change_plan(entity_id=self.entity_id, **kwargs) From d8b8f203d1dec848c319935007165b1291027595 Mon Sep 17 00:00:00 2001 From: Jose Manuel Castano Date: Thu, 6 Feb 2025 10:51:45 +0100 Subject: [PATCH 16/19] Fix typo in resources.py Add test for testing response headers Add test for response headers Adding test for response headers Add test for response headers, modify ServiceSubscription unit test Adding test for response headers Resolve conflicts of lint in PR --- .../test_integration_service_subscriptions.py | 19 +++++++++++++++++ tests/test_response_headers.py | 21 +++++++++++++++++++ threescale_api/resources.py | 8 +++---- 3 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 tests/test_response_headers.py diff --git a/tests/integration/test_integration_service_subscriptions.py b/tests/integration/test_integration_service_subscriptions.py index e2c9a5a..3139978 100644 --- a/tests/integration/test_integration_service_subscriptions.py +++ b/tests/integration/test_integration_service_subscriptions.py @@ -2,6 +2,7 @@ from tests.integration import asserts + def test_list_service_subscriptions(account): resource = account.service_subscriptions.list() assert len(resource) >= 1 @@ -14,3 +15,21 @@ def test_read_service_subscription(account, service_subscription, service_subscr resource = account.service_subscriptions.read(service_subscription.entity_id) asserts.assert_resource(resource) asserts.assert_resource_params(service_subscription,service_subscription_params) + +def test_change_plan_service_subscription(account, account_plan, service_subscription): + asserts.assert_resource(account) + asserts.assert_resource(account_plan) + resource = account.service_subscriptions.change_plan(service_subscription.entity_id, + account_plan.entity_id) + asserts.assert_resource(resource) + + +# TODO: https://issues.redhat.com/browse/THREESCALE-11693 +def test_approve_service_subscription(account, service_subscription,service_subscription_params): + asserts.assert_resource(service_subscription) + service_subscription['state'] = 'pending' + account.service_subscriptions.update(service_subscription.entity_id, + service_subscription_params) + resource = account.service_subscriptions.approve(service_subscription.entity_id) + asserts.assert_resource(resource) + asserts.assert_resource_params(service_subscription, service_subscription_params) diff --git a/tests/test_response_headers.py b/tests/test_response_headers.py new file mode 100644 index 0000000..e0a6cc0 --- /dev/null +++ b/tests/test_response_headers.py @@ -0,0 +1,21 @@ +import os +import pytest +import threescale_api + + +@pytest.fixture(scope="module") +def cl(): + return threescale_api.ThreeScaleClient(url=os.environ['THREESCALE_PROVIDER_URL'], + token=os.environ['THREESCALE_PROVIDER_TOKEN'], + ssl_verify=False) + + +def test_x_served_by(cl): + + response = cl._rest.get(url=cl.url + '/admin/api/accounts') + assert response.status_code == 200 + + if "X-Served-By" in response.headers: + assert True + else: + assert "X-Served-By" not in response.headers diff --git a/threescale_api/resources.py b/threescale_api/resources.py index d73cdf2..8e8d946 100644 --- a/threescale_api/resources.py +++ b/threescale_api/resources.py @@ -286,15 +286,15 @@ def url(self) -> str: return self.parent.url + '/service_subscriptions' def approve(self, entity_id: int, **kwargs): - url = self.url + f"/{entity_id}/approve.json" + url = self.url + f"/{entity_id}/approve" response = self.rest.put(url=url, **kwargs) instance = utils.extract_response(response=response) return instance def change_plan(self, entity_id: int, plan_id: int, **kwargs): - params = {"plan_id":plan_id} - url = self.url + f"/{entity_id}/change_plan.json" - response = self.rest.put(url=url, json=params, **kwargs) + params = {"plan_id": plan_id} + url = self.url + f"/{entity_id}/change_plan" + response = self.rest.put(url=url, params=params) instance = utils.extract_response(response=response) return instance From fb92d78dec86f3d63ab86c8d83253b4bf3fafe32 Mon Sep 17 00:00:00 2001 From: Jose Manuel Castano Date: Tue, 18 Feb 2025 14:56:27 +0100 Subject: [PATCH 17/19] Modify test for response headers. --- .../test_integration_service_subscriptions.py | 1 + tests/integration/test_response_headers.py | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 tests/integration/test_response_headers.py diff --git a/tests/integration/test_integration_service_subscriptions.py b/tests/integration/test_integration_service_subscriptions.py index e2c9a5a..8efa978 100644 --- a/tests/integration/test_integration_service_subscriptions.py +++ b/tests/integration/test_integration_service_subscriptions.py @@ -14,3 +14,4 @@ def test_read_service_subscription(account, service_subscription, service_subscr resource = account.service_subscriptions.read(service_subscription.entity_id) asserts.assert_resource(resource) asserts.assert_resource_params(service_subscription,service_subscription_params) + diff --git a/tests/integration/test_response_headers.py b/tests/integration/test_response_headers.py new file mode 100644 index 0000000..ddb96ba --- /dev/null +++ b/tests/integration/test_response_headers.py @@ -0,0 +1,9 @@ + +def test_x_served_by(api): + response = api._rest.get(url=api.admin_api_url + '/accounts') + assert response.status_code == 200 + + if "X-Served-By" in response.headers: + assert True + else: + assert "X-Served-By" not in response.headers From 4296106ed6700d70aa2b61d061900bfee6ea9b9f Mon Sep 17 00:00:00 2001 From: Jose Manuel Castano Date: Tue, 18 Feb 2025 14:59:32 +0100 Subject: [PATCH 18/19] Remove replicated test test_response_headers.py --- tests/test_response_headers.py | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 tests/test_response_headers.py diff --git a/tests/test_response_headers.py b/tests/test_response_headers.py deleted file mode 100644 index e0a6cc0..0000000 --- a/tests/test_response_headers.py +++ /dev/null @@ -1,21 +0,0 @@ -import os -import pytest -import threescale_api - - -@pytest.fixture(scope="module") -def cl(): - return threescale_api.ThreeScaleClient(url=os.environ['THREESCALE_PROVIDER_URL'], - token=os.environ['THREESCALE_PROVIDER_TOKEN'], - ssl_verify=False) - - -def test_x_served_by(cl): - - response = cl._rest.get(url=cl.url + '/admin/api/accounts') - assert response.status_code == 200 - - if "X-Served-By" in response.headers: - assert True - else: - assert "X-Served-By" not in response.headers From 5ba28168ebb290c835750c929f980a211dadfe7e Mon Sep 17 00:00:00 2001 From: Jose Manuel Castano Date: Thu, 20 Feb 2025 08:56:50 +0100 Subject: [PATCH 19/19] Fix suggestions after PR review. --- tests/integration/test_response_headers.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/integration/test_response_headers.py b/tests/integration/test_response_headers.py index ddb96ba..7bef6ed 100644 --- a/tests/integration/test_response_headers.py +++ b/tests/integration/test_response_headers.py @@ -2,8 +2,4 @@ def test_x_served_by(api): response = api._rest.get(url=api.admin_api_url + '/accounts') assert response.status_code == 200 - - if "X-Served-By" in response.headers: - assert True - else: - assert "X-Served-By" not in response.headers + assert "X-Served-By" not in response.headers