def test_get_course_catalogs_for_failure(self): """ Verify that method "get_course_catalogs" raises exception in case the Course Discovery API fails to return data. """ self.mock_course_discovery_api_for_failure() with self.assertRaises(Exception): get_course_catalogs(self.request.site)
def test_get_course_catalogs_for_failure(self): """ Verify that method "get_course_catalogs" raises exception in case the Course Discovery API fails to return data. """ exception = ConnectionError self.mock_course_discovery_api_for_catalogs_with_failure(exception) with self.assertRaises(exception): get_course_catalogs(self.request.site)
def test_get_course_catalogs_for_failure(self): """ Verify that method "get_course_catalogs" raises exception in case the Course Discovery API fails to return data. """ exception = ConnectionError self.mock_access_token_response() self.mock_discovery_api_failure(exception, self.site_configuration.discovery_api_url) with self.assertRaises(exception): get_course_catalogs(self.request.site)
def contains_product(self, product): """ Assert if the range contains the product. """ if self.course_catalog: request = get_current_request() try: course_catalog = get_course_catalogs(site=request.site, resource_id=self.course_catalog) except (ConnectionError, SlumberBaseException, Timeout): raise Exception( 'Unable to connect to Course Catalog service for catalog with id [%s].' % self.course_catalog ) response = self.run_catalog_query(product, course_catalog.get('query')) # Range can have a catalog query and 'regular' products in it, # therefor an OR is used to check for both possibilities. return ((response['course_runs'][product.course_id]) or super(Range, self).contains_product(product)) # pylint: disable=bad-super-call elif self.catalog_query and self.course_seat_types: if product.attr.certificate_type.lower() in self.course_seat_types: # pylint: disable=unsupported-membership-test response = self.run_catalog_query(product) # Range can have a catalog query and 'regular' products in it, # therefor an OR is used to check for both possibilities. return ((response['course_runs'][product.course_id]) or super(Range, self).contains_product(product)) # pylint: disable=bad-super-call elif self.catalog: return ( product.id in self.catalog.stock_records.values_list('product', flat=True) or super(Range, self).contains_product(product) # pylint: disable=bad-super-call ) return super(Range, self).contains_product(product) # pylint: disable=bad-super-call
def test_get_course_catalogs_for_single_catalog_with_id(self): """ Verify that method "get_course_catalogs" returns proper response for a single catalog by its id. """ self.mock_access_token_response() self.mock_catalog_detail_endpoint( self.site_configuration.discovery_api_url) catalog_id = 1 resource = "catalogs" cache_key = get_cache_key(site_domain=self.site.domain, resource="{}-{}".format( resource, catalog_id)) course_catalogs_cached_response = TieredCache.get_cached_response( cache_key) self.assertFalse(course_catalogs_cached_response.is_found) response = get_course_catalogs(self.request.site, catalog_id) self.assertEqual(response['name'], 'All Courses') course_cached_response = TieredCache.get_cached_response(cache_key) self.assertEqual(course_cached_response.value, response) # Verify the API was actually hit (not the cache) self._assert_num_requests(2)
def test_get_course_catalogs_for_single_catalog_with_id(self): """ Verify that method "get_course_catalogs" returns proper response for a single catalog by its id. """ self.mock_access_token_response() self.mock_catalog_detail_endpoint( self.site_configuration.discovery_api_url) catalog_id = 1 cache_key = u'{}.catalog.api.data.{}'.format(self.request.site.domain, catalog_id) cache_key = hashlib.md5(cache_key.encode('utf-8')).hexdigest() course_catalogs_cached_response = TieredCache.get_cached_response( cache_key) self.assertFalse(course_catalogs_cached_response.is_found) response = get_course_catalogs(self.request.site, catalog_id) self.assertEqual(response['name'], 'All Courses') course_cached_response = TieredCache.get_cached_response(cache_key) self.assertEqual(course_cached_response.value, response) # Verify the API was actually hit (not the cache) self._assert_num_requests(2)
def is_course_in_enterprise_catalog(site, course_id, enterprise_catalog_id): """ Verify that the provided course id exists in the site base list of course run keys from the provided enterprise course catalog. Arguments: course_id (str): The course ID. site: (django.contrib.sites.Site) site instance enterprise_catalog_id (Int): Course catalog id of enterprise Returns: Boolean """ try: enterprise_course_catalog = get_course_catalogs( site=site, resource_id=enterprise_catalog_id) except (ConnectionError, SlumberBaseException, Timeout): logger.exception( 'Unable to connect to Course Catalog service for course catalogs.') return None if is_course_in_catalog_query(site, course_id, enterprise_course_catalog.get('query')): return True return False
def test_get_course_catalogs_for_single_page_api_response(self, catalog_name_list): """ Verify that method "get_course_catalogs" returns proper response for single page Course Discovery API response and uses cache to return data in case of same API request. """ self.mock_course_discovery_api_for_catalogs(catalog_name_list) self._assert_get_course_catalogs(catalog_name_list) # Verify the API was hit once self._assert_num_requests(1) # Now fetch the catalogs again and there should be no more actual call # to Course Discovery API as the data will be fetched from the cache get_course_catalogs(self.request.site) self._assert_num_requests(1)
def test_get_course_catalogs_for_single_page_api_response( self, catalog_name_list): """ Verify that method "get_course_catalogs" returns proper response for single page Course Discovery API response and uses cache to return data in case of same API request. """ self.mock_course_discovery_api_for_catalogs(catalog_name_list) self._assert_get_course_catalogs(catalog_name_list) # Verify the API was hit once self._assert_num_requests(1) # Now fetch the catalogs again and there should be no more actual call # to Course Discovery API as the data will be fetched from the cache get_course_catalogs(self.request.site) self._assert_num_requests(1)
def course_catalogs(self, request): """ Returns response with all course catalogs in the format: ["results": {"id": 1, "name": "Dummy Catalog"}] """ try: results = get_course_catalogs(site=request.site) except: # pylint: disable=bare-except logger.exception('Failed to retrieve course catalogs data from the Course Discovery API.') results = [] # Create catalogs list with sorting by name catalogs = [{'id': catalog['id'], 'name': catalog['name']} for catalog in results] data = {'results': sorted(catalogs, key=lambda catalog: catalog.get('name', '').lower())} return Response(data=data)
def _assert_get_course_catalogs(self, catalog_name_list): """ Helper method to validate the response from the method "get_course_catalogs". """ cache_key = '{}.catalog.api.data'.format(self.request.site.domain) cache_key = hashlib.md5(cache_key).hexdigest() cached_course_catalogs = cache.get(cache_key) self.assertIsNone(cached_course_catalogs) response = get_course_catalogs(self.request.site) self.assertEqual(len(response), len(catalog_name_list)) for catalog_index, catalog in enumerate(response): self.assertEqual(catalog['name'], catalog_name_list[catalog_index]) cached_course = cache.get(cache_key) self.assertEqual(cached_course, response)
def _assert_get_course_catalogs(self, catalog_name_list): """ Helper method to validate the response from the method "get_course_catalogs". """ cache_key = u'{}.catalog.api.data'.format(self.request.site.domain) cache_key = hashlib.md5(cache_key.encode('utf-8')).hexdigest() course_catalogs_cached_response = TieredCache.get_cached_response( cache_key) self.assertFalse(course_catalogs_cached_response.is_found) response = get_course_catalogs(self.request.site) self.assertEqual(len(response), len(catalog_name_list)) for catalog_index, catalog in enumerate(response): self.assertEqual(catalog['name'], catalog_name_list[catalog_index]) course_cached_response = TieredCache.get_cached_response(cache_key) self.assertEqual(course_cached_response.value, response)
def get_course_ids_from_voucher(site, voucher): """ Get site base list of course run keys from the provided voucher object. Arguments: site: (django.contrib.sites.Site) site instance voucher (Voucher): voucher class object Returns: list of course ids """ voucher_offer = voucher.offers.first() offer_range = voucher_offer.condition.range if offer_range.course_catalog: try: course_catalog = get_course_catalogs(site=site, resource_id=offer_range.course_catalog) except (ConnectionError, SlumberBaseException, Timeout): logger.error('Unable to connect to Course Catalog service for course catalogs.') return None try: course_runs = get_catalog_course_runs(site, course_catalog.get('query'))['results'] except (ConnectionError, SlumberBaseException, Timeout, KeyError): logger.error('Unable to get course runs from Course Catalog service.') return None voucher_course_ids = [course_run.get('key') for course_run in course_runs if course_run.get('key')] elif offer_range.catalog_query: try: course_runs = get_catalog_course_runs(site, offer_range.catalog_query)['results'] except (ConnectionError, SlumberBaseException, Timeout, KeyError): logger.error('Unable to get course runs from Course Catalog service.') return None voucher_course_ids = [course_run.get('key') for course_run in course_runs if course_run.get('key')] else: stock_records = offer_range.catalog.stock_records.all() seats = Product.objects.filter(id__in=[sr.product.id for sr in stock_records]) voucher_course_ids = [seat.course_id for seat in seats] return voucher_course_ids
def _assert_get_course_catalogs(self, catalog_name_list): """ Helper method to validate the response from the method "get_course_catalogs". """ resource = "catalogs" cache_key = get_cache_key(site_domain=self.site.domain, resource=resource) course_catalogs_cached_response = TieredCache.get_cached_response( cache_key) self.assertFalse(course_catalogs_cached_response.is_found) response = get_course_catalogs(self.request.site) self.assertEqual(len(response), len(catalog_name_list)) for catalog_index, catalog in enumerate(response): self.assertEqual(catalog['name'], catalog_name_list[catalog_index]) course_cached_response = TieredCache.get_cached_response(cache_key) self.assertEqual(course_cached_response.value, response)
def test_get_course_catalogs_for_single_catalog_with_id(self): """ Verify that method "get_course_catalogs" returns proper response for a single catalog by its id. """ self.mock_course_discovery_api_for_catalog_by_resource_id() catalog_id = 1 cache_key = '{}.catalog.api.data.{}'.format(self.request.site.domain, catalog_id) cache_key = hashlib.md5(cache_key).hexdigest() cached_course_catalog = cache.get(cache_key) self.assertIsNone(cached_course_catalog) response = get_course_catalogs(self.request.site, catalog_id) self.assertEqual(response['name'], 'Catalog {}'.format(catalog_id)) cached_course = cache.get(cache_key) self.assertEqual(cached_course, response) # Verify the API was actually hit (not the cache) self._assert_num_requests(1)