From 791bd5aefc49ab93383006e3e17cf923249866d6 Mon Sep 17 00:00:00 2001 From: alecmerdler Date: Tue, 27 Jun 2017 14:00:23 -0700 Subject: [PATCH] refactored endpoints.api.subscribe to use abstracted data interface --- endpoints/api/subscribe.py | 18 +++----- endpoints/api/subscribe_models_interface.py | 26 +++++++++++ endpoints/api/subscribe_models_pre_oci.py | 23 ++++++++++ .../api/test/test_subscribe_models_pre_oci.py | 43 +++++++++++++++++++ 4 files changed, 99 insertions(+), 11 deletions(-) create mode 100644 endpoints/api/subscribe_models_interface.py create mode 100644 endpoints/api/subscribe_models_pre_oci.py create mode 100644 endpoints/api/test/test_subscribe_models_pre_oci.py diff --git a/endpoints/api/subscribe.py b/endpoints/api/subscribe.py index a0be987eb..e3644fde1 100644 --- a/endpoints/api/subscribe.py +++ b/endpoints/api/subscribe.py @@ -1,32 +1,28 @@ """ Subscribe to plans. """ - import logging import stripe - +import features from app import billing from endpoints.api import request_error, log_action -from endpoints.exception import NotFound -from data import model from data.billing import PLANS - -import features +from endpoints.api.subscribe_models_pre_oci import data_model as model +from endpoints.exception import NotFound logger = logging.getLogger(__name__) def check_repository_usage(user_or_org, plan_found): - private_repos = model.user.get_private_repo_count(user_or_org.username) + private_repos = model.get_private_repo_count(user_or_org.username) if plan_found is None: repos_allowed = 0 else: repos_allowed = plan_found['privateRepos'] if private_repos > repos_allowed: - model.notification.create_unique_notification('over_private_usage', user_or_org, - {'namespace': user_or_org.username}) + model.create_unique_notification('over_private_usage', user_or_org.username, {'namespace': user_or_org.username}) else: - model.notification.delete_notifications_by_kind(user_or_org, 'over_private_usage') + model.delete_notifications_by_kind(user_or_org.username, 'over_private_usage') def carderror_response(exc): @@ -70,7 +66,7 @@ def subscribe(user, plan, token, require_business_plan): user.username) raise request_error(message='No matching plan found') - private_repos = model.user.get_private_repo_count(user.username) + private_repos = model.get_private_repo_count(user.username) # This is the default response response_json = { diff --git a/endpoints/api/subscribe_models_interface.py b/endpoints/api/subscribe_models_interface.py new file mode 100644 index 000000000..fbc7a8a70 --- /dev/null +++ b/endpoints/api/subscribe_models_interface.py @@ -0,0 +1,26 @@ +from abc import ABCMeta, abstractmethod +from six import add_metaclass + + +@add_metaclass(ABCMeta) +class SubscribeInterface(object): + """ + Interface that represents all data store interactions required by the subscribe API endpoint. + """ + @abstractmethod + def get_private_repo_count(self, username): + """ + Returns the number of private repositories for a given username or namespace. + """ + + @abstractmethod + def create_unique_notification(self, kind_name, target_username, metadata={}): + """ + Creates a notification using the given parameters. + """ + + @abstractmethod + def delete_notifications_by_kind(self, target_username, kind_name): + """ + Remove notifications for a target based on given kind. + """ diff --git a/endpoints/api/subscribe_models_pre_oci.py b/endpoints/api/subscribe_models_pre_oci.py new file mode 100644 index 000000000..a5ca83149 --- /dev/null +++ b/endpoints/api/subscribe_models_pre_oci.py @@ -0,0 +1,23 @@ +from data.model.notification import create_unique_notification, delete_notifications_by_kind +from data.model.user import get_private_repo_count, get_user_or_org +from endpoints.api.subscribe_models_interface import SubscribeInterface + + +class PreOCIModel(SubscribeInterface): + """ + PreOCIModel implements the data model for build triggers using a database schema + before it was changed to support the OCI specification. + """ + def get_private_repo_count(self, username): + return get_private_repo_count(username) + + def create_unique_notification(self, kind_name, target_username, metadata={}): + target = get_user_or_org(target_username) + create_unique_notification(kind_name, target, metadata) + + def delete_notifications_by_kind(self, target_username, kind_name): + target = get_user_or_org(target_username) + delete_notifications_by_kind(target, kind_name) + + +data_model = PreOCIModel() diff --git a/endpoints/api/test/test_subscribe_models_pre_oci.py b/endpoints/api/test/test_subscribe_models_pre_oci.py new file mode 100644 index 000000000..8810e36f5 --- /dev/null +++ b/endpoints/api/test/test_subscribe_models_pre_oci.py @@ -0,0 +1,43 @@ +import pytest +from mock import patch + +from endpoints.api.subscribe_models_pre_oci import data_model + + +@pytest.mark.parametrize('username,repo_count', [ + ('devtable', 3) +]) +def test_get_private_repo_count(username, repo_count): + with patch('endpoints.api.subscribe_models_pre_oci.get_private_repo_count') as mock_get_private_reop_count: + mock_get_private_reop_count.return_value = repo_count + count = data_model.get_private_repo_count(username) + + mock_get_private_reop_count.assert_called_once_with(username) + assert count == repo_count + + +@pytest.mark.parametrize('kind_name,target_username,metadata', [ + ('over_private_usage', 'devtable', {'namespace': 'devtable'}) +]) +def test_create_unique_notification(kind_name, target_username, metadata): + with patch('endpoints.api.subscribe_models_pre_oci.get_user_or_org') as mock_get_user_or_org: + mock_get_user_or_org.return_value = {'username': target_username} + with patch('endpoints.api.subscribe_models_pre_oci.create_unique_notification') as mock_create_unique_notification: + data_model.create_unique_notification(kind_name, target_username, metadata) + + mock_get_user_or_org.assert_called_once_with(target_username) + mock_create_unique_notification.assert_called_once_with(kind_name, mock_get_user_or_org.return_value, metadata) + + +@pytest.mark.parametrize('target_username,kind_name', [ + ('devtable', 'over_private_usage') +]) +def test_delete_notifications_by_kind(target_username, kind_name): + with patch('endpoints.api.subscribe_models_pre_oci.get_user_or_org') as mock_get_user_or_org: + mock_get_user_or_org.return_value = {'username': target_username} + with patch('endpoints.api.subscribe_models_pre_oci.delete_notifications_by_kind') as mock_delete_notifications_by_kind: + data_model.delete_notifications_by_kind(target_username, kind_name) + + mock_get_user_or_org.assert_called_once_with(target_username) + mock_delete_notifications_by_kind.assert_called_once_with(mock_get_user_or_org.return_value, kind_name) +