diff --git a/membersuite_api_client/memberships/services.py b/membersuite_api_client/memberships/services.py index 030eea3..81cbb56 100644 --- a/membersuite_api_client/memberships/services.py +++ b/membersuite_api_client/memberships/services.py @@ -6,12 +6,13 @@ """ from zeep.exceptions import TransportError +from ..mixins import ChunkQueryMixin from .models import Membership, MembershipProduct from ..utils import convert_ms_object import datetime -class MembershipService(object): +class MembershipService(ChunkQueryMixin, object): def __init__(self, client): """ @@ -19,7 +20,7 @@ def __init__(self, client): """ self.client = client - def get_memberships_for_org(self, account_num): + def get_memberships_for_org(self, account_num, verbose=False): """ Retrieve all memberships associated with an organization """ @@ -28,18 +29,13 @@ def get_memberships_for_org(self, account_num): query = "SELECT Objects() FROM Membership " \ "WHERE Owner = '%s'" % account_num - result = self.client.runSQL(query) - msql_result = result["body"]["ExecuteMSQLResult"] - obj_result = msql_result["ResultValue"]["ObjectSearchResult"] - if obj_result['Objects']: - objects = obj_result['Objects']['MemberSuiteObject'] - if not msql_result["Errors"] and len(objects): - return self.package_memberships(objects) - return None - - def get_all_memberships(self, since_when=None, results=None, - start_record=0, limit_to=200, - depth=1, max_depth=None): + + membership_list = self.get_long_query(query, verbose=verbose) + return membership_list + + def get_all_memberships( + self, limit_to=100, max_calls=None, parameters=None, + since_when=None, start_record=0, verbose=False): """ Retrieve all memberships updated since "since_when" @@ -51,59 +47,52 @@ def get_all_memberships(self, since_when=None, results=None, self.client.request_session() query = "SELECT Objects() FROM Membership" + + # collect all where parameters into a list of + # (key, operator, value) tuples + where_params = [] + + if parameters: + for k, v in parameters.items(): + where_params.append((k, "=", v)) + if since_when: - query += " WHERE LastModifiedDate > '{since_when} 00:00:00'" \ - " ORDER BY LocalID".format( - since_when=datetime.date.today() - - datetime.timedelta(days=since_when)) - else: - query += " ORDER BY LocalID" - - try: - result = self.client.runSQL( - query=query, - start_record=start_record, - limit_to=limit_to, - ) - - except TransportError: - # API Intermittently fails and kicks a 504, - # this is a way to retry if that happens. - result = self.get_all_memberships( - since_when=since_when, - results=results, - start_record=start_record, - limit_to=limit_to, - depth=depth, - max_depth=max_depth, - ) - - msql_result = result['body']["ExecuteMSQLResult"] - if (not msql_result['Errors'] and msql_result["ResultValue"] - ["ObjectSearchResult"]["Objects"]): - new_results = self.package_memberships(msql_result - ["ResultValue"] - ["ObjectSearchResult"] - ["Objects"] - ["MemberSuiteObject"] - ) + (results or []) - - # Check if the queryset was completely full. If so, there may be - # More results we need to query - if len(new_results) >= limit_to and not depth == max_depth: - new_results = self.get_all_memberships( - since_when=since_when, - results=new_results, - start_record=start_record + limit_to, - limit_to=limit_to, - depth=depth+1, - max_depth=max_depth - ) - return new_results - else: - return results - - def get_all_membership_products(self): + d = datetime.date.today() - datetime.timedelta(days=since_when) + where_params.append( + ('LastModifiedDate', ">", "'%s 00:00:00'" % d)) + + if where_params: + query += " WHERE " + query += " AND ".join( + ["%s %s %s" % (p[0], p[1], p[2]) for p in where_params]) + + query += " ORDER BY LocalID" + + # note, get_long_query is overkill when just looking at + # one org, but it still only executes once + # `get_long_query` uses `ms_object_to_model` to return Organizations + membership_list = self.get_long_query( + query, limit_to=limit_to, max_calls=max_calls, + start_record=start_record, verbose=verbose) + + return membership_list + + def ms_object_to_model(self, ms_obj): + " Converts an individual result to a Subscription Model " + sane_obj = convert_ms_object( + ms_obj['Fields']['KeyValueOfstringanyType']) + return Membership(sane_obj) + + +class MembershipProductService(ChunkQueryMixin, object): + + def __init__(self, client): + """ + Accepts a ConciergeClient to connect with MemberSuite + """ + self.client = client + + def get_all_membership_products(self, verbose=False): """ Retrieves membership product objects """ @@ -111,40 +100,12 @@ def get_all_membership_products(self): self.client.request_session() query = "SELECT Objects() FROM MembershipDuesProduct" - result = self.client.runSQL(query) - msql_result = result['body']['ExecuteMSQLResult'] - if not msql_result['Errors']: - return self.package_membership_products(msql_result) - else: - return None - - def package_memberships(self, object_list): - """ - Loops through MS objects returned from queries to turn them into - Membership objects and pack them into a list for later use. - """ - membership_list = [] - for obj in object_list: - if type(obj) != str: - sane_obj = convert_ms_object( - obj['Fields']['KeyValueOfstringanyType']) - membership = Membership(sane_obj) - membership_list.append(membership) - return membership_list + membership_product_list = self.get_long_query(query, verbose=verbose) + return membership_product_list - def package_membership_products(self, msql_result): - """ - Loops through MS objects returned from queries to turn them into - MembershipProduct objects and pack them into a list for later use. - """ - obj_result = msql_result['ResultValue']['ObjectSearchResult'] - objects = obj_result['Objects']['MemberSuiteObject'] - product_list = [] - for obj in objects: - sane_obj = convert_ms_object( - obj['Fields']['KeyValueOfstringanyType'] - ) - product = MembershipProduct(sane_obj) - product_list.append(product) - return product_list + def ms_object_to_model(self, ms_obj): + " Converts an individual result to a Subscription Model " + sane_obj = convert_ms_object( + ms_obj['Fields']['KeyValueOfstringanyType']) + return MembershipProduct(sane_obj) diff --git a/membersuite_api_client/mixins.py b/membersuite_api_client/mixins.py index b16f8a2..11ef8b8 100644 --- a/membersuite_api_client/mixins.py +++ b/membersuite_api_client/mixins.py @@ -1,4 +1,9 @@ from retrying import retry +import datetime + +from .exceptions import ExecuteMSQLError + +RETRY_ATTEMPTS = 10 class ChunkQueryMixin(): @@ -15,28 +20,41 @@ class ChunkQueryMixin(): """ def get_long_query( - self, base_query, retry_attempts=2, limit_to=200, max_calls=None): + self, base_query, limit_to=100, max_calls=None, + start_record=0, verbose=False): """ Takes a base query for all objects and recursively requests them - @base_query - the base query to be executed - @retry_attempts - the number of times to retry a query when it fails - @limit_to - how many rows to query for in each chunk - @max_recursion_depth - None is infinite + :param str base_query: the base query to be executed + :param int limit_to: how many rows to query for in each chunk + :param int max_calls: the max calls(chunks to request) None is infinite + :param int start_record: the first record to return from the query + :param bool verbose: print progress to stdout + :return: a list of Organization objects """ - @retry(stop_max_attempt_number=retry_attempts) - def run_query(base_query, start_record, limit_to): + @retry(stop_max_attempt_number=RETRY_ATTEMPTS, wait_fixed=2000) + def run_query(base_query, start_record, limit_to, verbose): # inline method to take advantage of retry + + if verbose: + print("[start: %d limit: %d]" % (start_record, limit_to)) + start = datetime.datetime.now() result = self.client.runSQL( query=base_query, start_record=start_record, limit_to=limit_to, ) + end = datetime.datetime.now() + if verbose: + print("[%s - %s]" % (start, end)) return self.result_to_models(result) - record_index = 0 - result = run_query(base_query, record_index, limit_to) + if verbose: + print(base_query) + + record_index = start_record + result = run_query(base_query, record_index, limit_to, verbose) all_objects = result call_count = 1 """ @@ -49,7 +67,32 @@ def run_query(base_query, start_record, limit_to): len(result) >= limit_to): record_index += len(result) # should be `limit_to` - all_objects += run_query(base_query, record_index, limit_to) + result = run_query( + base_query, record_index, limit_to, verbose) + all_objects += result call_count += 1 return all_objects + + def result_to_models(self, result): + """ + this is the 'transorm' part of ETL: + converts the result of the SQL to Models + """ + mysql_result = result['body']['ExecuteMSQLResult'] + + if not mysql_result['Errors']: + obj_result = mysql_result['ResultValue']['ObjectSearchResult'] + if not obj_result['Objects']: + return [] + objects = obj_result['Objects']['MemberSuiteObject'] + + model_list = [] + for obj in objects: + model = self.ms_object_to_model(obj) + model_list.append(model) + + return model_list + + else: + raise ExecuteMSQLError(result) diff --git a/membersuite_api_client/organizations/services.py b/membersuite_api_client/organizations/services.py index b3ad571..4f454ff 100644 --- a/membersuite_api_client/organizations/services.py +++ b/membersuite_api_client/organizations/services.py @@ -5,13 +5,14 @@ """ +from ..mixins import ChunkQueryMixin from .models import Organization, OrganizationType from ..utils import convert_ms_object from zeep.exceptions import TransportError import datetime -class OrganizationService(object): +class OrganizationService(ChunkQueryMixin, object): def __init__(self, client): """ @@ -19,80 +20,61 @@ def __init__(self, client): """ self.client = client - def get_orgs(self, parameters=None, get_all=False, since_when=None, - results=None, start_record=0, limit_to=200, depth=1, - max_depth=None): + def get_orgs( + self, limit_to=100, max_calls=None, parameters=None, + since_when=None, start_record=0, verbose=False): """ - Constructs request to MemberSuite to query organization objects - based on parameters provided. - - Loop over queries of size limit_to until either a non-full queryset - is returned, or max_depth is reached (used in tests). Then the - recursion collapses to return a single concatenated list. + Constructs request to MemberSuite to query organization objects. + + :param int limit_to: number of records to fetch with each chunk + :param int max_calls: the maximum number of calls (chunks) to request + :param str parameters: additional query parameter dictionary + :param date since_when: fetch records modified after this date + :param int start_record: the first record to return from the query + :param bool verbose: print progress to stdout + :return: a list of Organization objects """ + if not self.client.session_id: self.client.request_session() - query = "SELECT Objects() FROM Organization " - if parameters and not get_all: - query += "WHERE" - for key in parameters: - query += " %s = '%s' AND" % (key, parameters[key]) - query = query[:-4] - - if since_when: - query += " AND LastModifiedDate > '{since_when} 00:00:00'" \ - .format(since_when=datetime.date.today() - - datetime.timedelta(days=since_when)) - elif since_when and not get_all: - query += "WHERE LastModifiedDate > '{since_when} 00:00:00'".format( - since_when=datetime.date.today() - - datetime.timedelta(days=since_when)) - try: - result = self.client.runSQL( - query=query, - start_record=start_record, - limit_to=limit_to, - ) + query = "SELECT Objects() FROM Organization" - except TransportError: - # API Intermittently fails and kicks a 504, - # this is a way to retry if that happens. - result = self.get_orgs( - parameters=parameters, - get_all=get_all, - since_when=since_when, - results=results, - start_record=start_record, - limit_to=limit_to, - depth=depth, - max_depth=max_depth, - ) + # collect all where parameters into a list of + # (key, operator, value) tuples + where_params = [] - msql_result = result['body']["ExecuteMSQLResult"] - if not msql_result['Errors'] and \ - msql_result["ResultValue"]["ObjectSearchResult"]["Objects"]: - new_results = self.package_organizations(msql_result["ResultValue"] - ["ObjectSearchResult"] - ["Objects"] - ["MemberSuiteObject"] - ) + (results or []) - # Check if the queryset was completely full. If so, there may be - # More results we need to query - if len(new_results) >= limit_to and not depth == max_depth: - new_results = self.get_orgs( - parameters=parameters, - get_all=get_all, - since_when=since_when, - results=new_results, - start_record=start_record + limit_to, - limit_to=limit_to, - depth=depth + 1, - max_depth=max_depth - ) - return new_results - else: - return results + if parameters: + for k, v in parameters.items(): + where_params.append((k, "=", v)) + + if since_when: + d = datetime.date.today() - datetime.timedelta(days=since_when) + where_params.append( + ('LastModifiedDate', ">", "'%s 00:00:00'" % d)) + + if where_params: + query += " WHERE " + query += " AND ".join( + ["%s %s %s" % (p[0], p[1], p[2]) for p in where_params]) + + if verbose: + print("Fetching Organizations...") + + # note, get_long_query is overkill when just looking at + # one org, but it still only executes once + # `get_long_query` uses `ms_object_to_model` to return Organizations + org_list = self.get_long_query( + query, limit_to=limit_to, max_calls=max_calls, + start_record=start_record, verbose=verbose) + + return org_list + + def ms_object_to_model(self, ms_obj): + " Converts an individual result to an Organization Model " + sane_obj = convert_ms_object( + ms_obj['Fields']['KeyValueOfstringanyType']) + return Organization(sane_obj) def get_org_types(self): """ @@ -109,20 +91,6 @@ def get_org_types(self): ["Objects"]["MemberSuiteObject"] ) - def package_organizations(self, obj_list): - """ - Loops through MS objects returned from queries to turn them into - Organization objects and pack them into a list for later use. - """ - org_list = [] - for obj in obj_list: - sane_obj = convert_ms_object( - obj['Fields']['KeyValueOfstringanyType'] - ) - org = Organization(sane_obj) - org_list.append(org) - return org_list - def package_org_types(self, obj_list): """ Loops through MS objects returned from queries to turn them into diff --git a/membersuite_api_client/subscriptions/services.py b/membersuite_api_client/subscriptions/services.py index a0c7189..9952752 100644 --- a/membersuite_api_client/subscriptions/services.py +++ b/membersuite_api_client/subscriptions/services.py @@ -27,53 +27,40 @@ def __init__(self, client): def get_subscriptions( self, publication_id=None, org_id=None, since_when=None, - retry_attempts=2, limit_to=200, max_calls=None): + limit_to=200, max_calls=None, start_record=0, verbose=False): """ Fetches all subscriptions from Membersuite of a particular `publication_id` if set. """ query = "SELECT Objects() FROM Subscription" + + # collect all where parameters into a list of + # (key, operator, value) tuples + where_params = [] + if org_id: - query += " WHERE owner = '%s'" % org_id + where_params.append(('owner', '=', "'%s'" % org_id)) if publication_id: - query += " AND publication = '%s'" % publication_id + where_params.append(('publication', '=', "'%s'" % publication_id)) if since_when: - query += " AND LastModifiedDate > '{since_when} 00:00:00'" \ - .format(since_when=datetime.date.today() - - datetime.timedelta(days=since_when)) + d = datetime.date.today() - datetime.timedelta(days=since_when) + where_params.append( + ('LastModifiedDate', ">", "'%s 00:00:00'" % d)) + + if where_params: + query += " WHERE " + query += " AND ".join( + ["%s %s %s" % (p[0], p[1], p[2]) for p in where_params]) # note, get_long_query is overkill when just looking at # one org, but it still only executes once - # `get_long_query` uses `result_to_models` to return Subscriptions + # `get_long_query` uses `ms_object_to_model` to return Subscriptions subscription_list = self.get_long_query( - query, retry_attempts=retry_attempts, limit_to=limit_to, - max_calls=max_calls) + query, limit_to=limit_to, max_calls=max_calls, + start_record=start_record, verbose=verbose) return subscription_list - def result_to_models(self, result): - """ - this is the 'transorm' part of ETL: - converts the result of the SQL to Subscription objects - """ - mysql_result = result['body']['ExecuteMSQLResult'] - - if not mysql_result['Errors']: - obj_result = mysql_result['ResultValue']['ObjectSearchResult'] - if not obj_result['Objects']: - return [] - objects = obj_result['Objects']['MemberSuiteObject'] - - subscription_list = [] - for obj in objects: - subscription = self.ms_object_to_model(obj) - subscription_list.append(subscription) - - return subscription_list - - else: - raise ExecuteMSQLError(result) - def ms_object_to_model(self, ms_obj): " Converts an individual result to a Subscription Model " sane_obj = convert_ms_object( @@ -82,6 +69,6 @@ def ms_object_to_model(self, ms_obj): id=sane_obj['ID'], org_id=sane_obj['Owner'], start=sane_obj['StartDate'], - end=sane_obj['TerminationDate'], + end=sane_obj['ExpirationDate'], extra_data=sane_obj) return subscription diff --git a/membersuite_api_client/tests/README.md b/membersuite_api_client/tests/README.md new file mode 100644 index 0000000..906b10b --- /dev/null +++ b/membersuite_api_client/tests/README.md @@ -0,0 +1,35 @@ +# Testing membersuite_api_client + +## Configuration + +You will need to define the following environment variables: + +## General vars: + + - `MS_ACCESS_KEY` - your API key + - `MS_SECRET_KEY` - your API secret + - `MS_ASSOCIATION_ID` - your membersuite association id + +Until we set up a mechanism for fixtures, you'll need to set up the following: + +## Organization vars: + + - `TEST_ORG_NAME` - an existing org's name + +## Membership vars: + + - `ORG_ID_WITH_MEMBERSHIPS` - an existing org with a membership or two + - `ORG_ID_WITHOUT_MEMBERSHIPS` - and w/out + +## Security vars: + +- `TEST_MS_PORTAL_MEMBER_ID` - member user with portal access +- `TEST_MS_PORTAL_MEMBER_PASS` - password +- `TEST_MS_PORTAL_NONMEMBER_ID` - nonmember with portal access +- `TEST_MS_PORTAL_NONMEMBER_PASS` - password +- `TEST_MS_MEMBER_ORG_NAME` - the name of the member organization + +## Subscription vars: + + - `TEST_ORG_ID_SUBSCRIBER` - org that has subscriptions + - `TEST_PUBLICATION_ID` - a publication for the subscription above diff --git a/membersuite_api_client/tests/test_memberships.py b/membersuite_api_client/tests/test_memberships.py index 76edb85..97af5a0 100644 --- a/membersuite_api_client/tests/test_memberships.py +++ b/membersuite_api_client/tests/test_memberships.py @@ -1,15 +1,21 @@ import unittest +import os from .base import BaseTestCase -from ..memberships.services import MembershipService +from ..memberships.services import MembershipService, MembershipProductService from ..memberships.models import Membership, MembershipProduct +# might eventually have to come from fixtures +MEMBER_ORG_ID = os.environ.get('TEST_ORG_ID_MEMBER') +NONMEMBER_ORG_ID = os.environ.get('TEST_ORG_ID_NONMEMBER') + class MembershipServiceTestCase(BaseTestCase): def setUp(self): super(MembershipServiceTestCase, self).setUp() self.service = MembershipService(self.client) + self.product_service = MembershipProductService(self.client) @unittest.skip("Need an Organization ID for a non-member org") def test_get_membership_for_org(self): @@ -17,15 +23,13 @@ def test_get_membership_for_org(self): Get membership info for a test org """ # Test org with a membership - test_org_id = "6faf90e4-0007-c578-8310-0b3c53985743" - membership_list = self.service.get_memberships_for_org(test_org_id) + membership_list = self.service.get_memberships_for_org( + MEMBER_ORG_ID, verbose=True) self.assertEqual(type(membership_list[0]), Membership) - self.assertEqual(membership_list[0].id, - '6faf90e4-0074-cbb5-c1d2-0b3c539859ef') # Test org without a membership - test_org_id = "6faf90e4-0007-c92e-8d16-0b3c53985743" - membership_list = self.service.get_memberships_for_org(test_org_id) + membership_list = self.service.get_memberships_for_org( + NONMEMBER_ORG_ID, verbose=True) self.assertFalse(membership_list) def test_get_all_memberships(self): @@ -33,17 +37,20 @@ def test_get_all_memberships(self): Does the get_all_memberships() method work? """ membership_list = self.service.get_all_memberships( - limit_to=1, max_depth=2 + limit_to=1, max_calls=2, verbose=True ) self.assertEqual(len(membership_list), 2) self.assertEqual(type(membership_list[0]), Membership) def test_get_all_membership_products(self): """ - Test if we can retrieve all 103 MembershipProduct objects + Test if we can retrieve all MembershipProduct objects + 103 at the time of testing """ - membership_product_list = self.service.get_all_membership_products() - self.assertTrue(len(membership_product_list) == 103) + service = self.product_service + membership_product_list = service.get_all_membership_products( + verbose=True) + self.assertTrue(len(membership_product_list) > 0) self.assertEqual(type(membership_product_list[0]), MembershipProduct) diff --git a/membersuite_api_client/tests/test_organizations.py b/membersuite_api_client/tests/test_organizations.py index 6652fb9..7c85f93 100644 --- a/membersuite_api_client/tests/test_organizations.py +++ b/membersuite_api_client/tests/test_organizations.py @@ -1,9 +1,13 @@ import unittest +import os from .base import BaseTestCase from ..organizations.services import OrganizationService from ..organizations.models import Organization, OrganizationType +# @todo - this should come from the env for portability +TEST_ORG_NAME = os.environ.get('TEST_ORG_NAME') + class OrganizationServiceTestCase(BaseTestCase): @@ -17,25 +21,25 @@ def test_get_orgs(self): """ # Fetch just one org by name parameters = { - 'Name': 'AASHE Test Campus', + 'Name': "'%s'" % TEST_ORG_NAME, } - org_list = self.service.get_orgs(parameters) + org_list = self.service.get_orgs(parameters=parameters, verbose=True) self.assertEqual(len(org_list), 1) self.assertEqual(type(org_list[0]), Organization) + # @todo - test since_when parameter + # Fetch all orgs using get_all=True # But limit to 1 result per iteration, 2 iterations - org_list = self.service.get_orgs(get_all=True, - limit_to=1, - max_depth=2) + org_list = self.service.get_orgs(limit_to=1, max_calls=2, verbose=True) self.assertEqual(len(org_list), 2) self.assertEqual(type(org_list[0]), Organization) # How does recursion handle the end? # 8055 records at the time of this test org_list = self.service.get_orgs( - get_all=True, start_record=8000, limit_to=10) - self.assertGreater(len(org_list), 50) + start_record=8000, limit_to=10, verbose=True) + self.assertGreater(len(org_list), 1) self.assertEqual(type(org_list[0]), Organization) def test_get_org_types(self): diff --git a/membersuite_api_client/tests/test_security.py b/membersuite_api_client/tests/test_security.py index 847f882..6571964 100644 --- a/membersuite_api_client/tests/test_security.py +++ b/membersuite_api_client/tests/test_security.py @@ -9,6 +9,13 @@ LOGIN_TO_PORTAL_RETRIES = 5 LOGIN_TO_PORTAL_DELAY = 1 +MEMBER_ID = os.environ.get('TEST_MS_PORTAL_MEMBER_ID') +MEMBER_PASSWORD = os.environ.get('TEST_MS_PORTAL_MEMBER_PASS') +NONMEMBER_ID = os.environ.get('TEST_MS_PORTAL_NONMEMBER_ID') +NONMEMBER_PASSWORD = os.environ.get('TEST_MS_PORTAL_NONMEMBER_PASS') +MEMBER_ORG_NAME = os.environ.get('TEST_MS_MEMBER_ORG_NAME') +print("**************") +print("MEMBER_ORG_NAME: %s" % MEMBER_ORG_NAME) def get_portal_user(client, member=True): @@ -16,15 +23,15 @@ def get_portal_user(client, member=True): client.request_session() if member: return login_to_portal( - username=os.environ["TEST_MS_PORTAL_USER_ID"], - password=os.environ["TEST_MS_PORTAL_USER_PASS"], + username=MEMBER_ID, + password=MEMBER_PASSWORD, client=client, retries=LOGIN_TO_PORTAL_RETRIES, delay=LOGIN_TO_PORTAL_DELAY) else: return login_to_portal( - username=os.environ["TEST_NON_MEMBER_MS_PORTAL_USER_ID"], - password=os.environ["TEST_NON_MEMBER_MS_PORTAL_USER_PASS"], + username=NONMEMBER_ID, + password=NONMEMBER_PASSWORD, client=client, retries=LOGIN_TO_PORTAL_RETRIES, delay=LOGIN_TO_PORTAL_DELAY) @@ -38,12 +45,7 @@ def setUpClass(cls): def test_login_to_portal(self): """Can we log in to the portal?""" - portal_user = login_to_portal( - username=os.environ["TEST_MS_PORTAL_USER_ID"], - password=os.environ["TEST_MS_PORTAL_USER_PASS"], - client=self.client, - retries=LOGIN_TO_PORTAL_RETRIES, - delay=LOGIN_TO_PORTAL_DELAY) + portal_user = get_portal_user(client=self.client) self.assertIsInstance(portal_user, models.PortalUser) def test_login_to_portal_failure(self): @@ -144,12 +146,12 @@ def test_get_primary_organization(self): Assumptions: - self.individual_member has as its primary organization, one - named "AASHE Test Campus". + named MEMBER_ORG_NAME """ organization = self.individual_member.get_primary_organization( client=self.client) - self.assertEqual("AASHE Test Campus", organization.name) + self.assertEqual(MEMBER_ORG_NAME, organization.name) def test_get_primary_organization_fails(self): """What happens when get_primary_organization() fails? diff --git a/membersuite_api_client/tests/test_subscriptions.py b/membersuite_api_client/tests/test_subscriptions.py index fd7ff7a..d418498 100644 --- a/membersuite_api_client/tests/test_subscriptions.py +++ b/membersuite_api_client/tests/test_subscriptions.py @@ -1,7 +1,13 @@ import unittest +import os from .base import BaseTestCase from ..subscriptions.services import SubscriptionService +from ..subscriptions.models import Subscription + +# @todo - these should go in the env to be portable across associations +TEST_SUBSCRIPTION_OWNER = os.environ.get('TEST_ORG_ID_SUBSCRIBER') +TEST_PUBLICATION_ID = os.environ.get('TEST_PUBLICATION_ID') class SubscriptionTestCase(BaseTestCase): @@ -14,27 +20,32 @@ def test_get_org_subscriptions(self): """ Get the all subscriptions for an organization """ - - test_org_id = "6faf90e4-0007-cbaa-6232-0b3c7fa70db7" - subscription_list = self.service.get_subscriptions(org_id=test_org_id) + subscription_list = self.service.get_subscriptions( + org_id=TEST_SUBSCRIPTION_OWNER, verbose=True) self.assertGreaterEqual(len(subscription_list), 2) + self.assertEqual(type(subscription_list[0]), Subscription) # with publication_id - STARS_PUBLICATION_ID = '6faf90e4-009e-cb9b-7c9e-0b3bcd6dff6a' subscription_list = self.service.get_subscriptions( - org_id=test_org_id, publication_id=STARS_PUBLICATION_ID) + org_id=TEST_SUBSCRIPTION_OWNER, + publication_id=TEST_PUBLICATION_ID, + verbose=True) self.assertGreaterEqual(len(subscription_list), 2) + self.assertEqual(type(subscription_list[0]), Subscription) # now for a "long query" - querying ALL subscriptions subscription_list = self.service.get_subscriptions( - retry_attempts=2, limit_to=3, max_calls=3) + limit_to=3, max_calls=3, verbose=True) self.assertEqual(len(subscription_list), 9) + self.assertEqual(type(subscription_list[0]), Subscription) # test a long query that's longer than the number we have # to ensure that edge case stops the queries + # ~1500 subscriptions at the time of these tests subscription_list = self.service.get_subscriptions( - retry_attempts=5, limit_to=200, max_calls=6) - self.assertLess(len(subscription_list), 1500) + limit_to=100, start_record=1300, verbose=True) + self.assertGreater(len(subscription_list), 0) + self.assertEqual(type(subscription_list[0]), Subscription) # @todo: test the modified date