def test_fetch_all_with_negative_arg_for_limit(self): message = 'limit must be a positive integer' if sys.version_info.major < 3: with self.assertRaisesRegexp(ValueError, message): query = Query(self.client, Tour).all(limit=-1) list(query) # force the query to evaluate else: with self.assertRaisesRegex(ValueError, message): query = Query(self.client, Tour).all(limit=-1) list(query) # force the query to evaluate
def test_filtered_query_returns_new_object(self, mock_request): """ Arguments passed to .filter() are stored on new (copied) Query instance that will be different from the one it derived from. Instances should be different and filters should not stack up Every new filter returns a new object. """ query = Query(self.client, Tour).filter(tour_dossier_code='PPP') query1 = Query(self.client, Tour).filter(tour_dossier_code='DJNN') self.assertFalse(query is query1) self.assertNotEqual(query._filters, query1._filters)
def test_listing_non_listable_resource_fails(self): message = 'The Activity resource is not listable and/or is only available as a subresource' if sys.version_info.major < 3: with self.assertRaisesRegexp(ValueError, message): Query(self.client, Activity).all() with self.assertRaisesRegexp(ValueError, message): Query(self.client, Activity).count() else: with self.assertRaisesRegex(ValueError, message): Query(self.client, Activity).all() with self.assertRaisesRegex(ValueError, message): Query(self.client, Activity).count()
def test_fetch_all_with_wrong_arg_types_for_limit(self): wrong_arg_types = ['', [], {}, object()] message = 'limit must be an integer' for wrong_arg in wrong_arg_types: if sys.version_info.major < 3: with self.assertRaisesRegexp(TypeError, message): query = Query(self.client, Tour).all(limit=wrong_arg) list(query) # force the query to evaluate else: with self.assertRaisesRegex(TypeError, message): query = Query(self.client, Tour).all(limit=wrong_arg) list(query) # force the query to evaluate
def test_filtered_query(self, mock_request): """ Arguments passed to .filter() are stored on new (copied) Query instance and are not supposed to be cleared when that query is evaluated. """ # Create a basic filter query for PPP... query = Query(self.client, Tour).filter(tour_dossier_code='PPP') self.assertEqual(len(query._filters), 1) # ... then chain on another filter argument... query = query.filter(order_by__asc='departures_start_date') self.assertEqual(len(query._filters), 2) # ... and force query evaluation, before checking... list(query) # ... our request was made with the appropriate query args, and... mock_request.assert_called_once_with('/tours', 'GET', params={ 'tour_dossier_code': 'PPP', 'order_by__asc': 'departures_start_date', }) mock_request.reset_mock() # ... our stored filter args remain for the current instance. self.assertEqual(len(query._filters), 2) # .count() should remain the query filters and # respond from a new instance with the count value: query.count() self.assertEqual(len(query._filters), 2)
def test_create_extra_headers(self, mock_request): """ Test that extra HTTP headers can be passed through the `.create` method on a resource """ class MockResource(Resource): _as_is_fields = ['id', 'foo'] _resource_name = 'foo' self.gapi.foo = Query(self.gapi, MockResource) resource_data = { 'id': 1, 'foo': 'bar' } # content doesn't really matter for this test mock_request.return_value = resource_data # Create a `foo` while passing extra headers extra_headers = {'X-Bender': 'I\'m not allowed to sing. Court order.'} self.gapi.create('foo', resource_data, headers=extra_headers) # Did those headers make it all the way to the requestor? mock_request.assert_called_once_with( '/foo', 'POST', data=json.dumps(resource_data), additional_headers=extra_headers, )
def _set_resource_collection_field(self, field, value): query = Query( self._client, self._model_cls(field), parent=self._parent(), raw_data=value, ) setattr(self, field, query)
def test_get_instance_with_gone_id(self, mock_request): response = Response() response.status_code = 410 http_error = HTTPError(response=response) mock_request.side_effect = http_error query = Query(self.client, Tour) t = query.get(1234) self.assertIsNone(t)
def test_build_interface(self): class MockResource(Resource): _as_is_fields = ['id', 'foo'] _resource_name = 'foo' self.gapi.foo = Query(self.gapi, MockResource) resource = self.gapi.build('foo', {'id': 1, 'foo': 'bar'}) self.assertEqual(resource.id, 1) self.assertEqual(resource.foo, 'bar')
def test_resources_are_cached(self, mock_request): query = Query(self.client, Tour) self.assertEqual(self.cache.count(), 0) query.get(21346) self.assertEqual(self.cache.count(), 1) self.assertEqual(len(mock_request.mock_calls), 1) query.get(21346) self.assertEqual(len(mock_request.mock_calls), 1)
def test_get_instance_by_id_with_non_404_error(self, mock_request): response = Response() response.status_code = 401 http_error = HTTPError(response=response) mock_request.side_effect = http_error query = Query(self.client, Tour) with self.assertRaises(HTTPError) as cm: query.get(1234) self.assertEqual(cm.exception.response.status_code, 401)
def test_fetch_all_with_limit(self, mock_request): query = Query(self.client, TourDossier).all(limit=2) dossiers = list(query) self.assertEqual(len(dossiers), 2) for dossier in dossiers: self.assertIsInstance(dossier, TourDossier) mock_request.assert_called_once_with('/tour_dossiers', 'GET', params={})
def test_query_key_with_language(self): self.client = Client(application_key='') self.client.api_language = 'de' query = Query(self.client, self.resource) key = query.query_key(1) expected = '{}:1:de'.format(self.resource_name) self.assertEqual(key, expected) # Unsetting the language should also remove it from the key self.client.api_language = None key = query.query_key(1) expected = '{}:1'.format(self.resource_name) self.assertEqual(key, expected)
def test_create_interface(self, mock_request): class MockResource(Resource): _as_is_fields = ['id', 'foo'] _resource_name = 'foo' self.gapi.foo = Query(self.gapi, MockResource) # On create, a representation of the resource is created. mock_request.return_value = { 'id': 1, 'foo': 'bar', } # Create allows arbitrary data to be sent, even if it's not part of the # final resource. resource = self.gapi.create('foo', {'id': 1, 'foo': 'bar', 'context': 'abc'}) self.assertEqual(resource.id, 1)
def test_get_instance_with_gone_id(self, mock_request): response = Response() response.status_code = 410 http_error = HTTPError(response=response) mock_request.side_effect = http_error # default behaviour is to return None... query = Query(self.client, Tour) self.assertIsNone(query.get(1234)) # ... but if this status code is not in the list of ones to explicitly # turn into Nones, then it will get raised: with self.assertRaises(HTTPError) as context: query.get(1234, httperrors_mapped_to_none=None) self.assertEqual(context.exception.response.status_code, response.status_code)
def test_filtered_query(self, mock_request): """ Arguments passed to .filter() are stored on the Query instance but are cleared when that query is evaluated. """ # Create a basic filter query for PPP... query = Query(self.client, Tour).filter(tour_dossier_code='PPP') self.assertEqual(len(query._filters), 1) # ... then chain on another filter argument... query = query.filter(order_by__asc='departures_start_date') self.assertEqual(len(query._filters), 2) # ... and force query evaluation, before checking... list(query) # ... our request was made with the appropriate query args, and... mock_request.assert_called_once_with('/tours', 'GET', params={ 'tour_dossier_code': 'PPP', 'order_by__asc': 'departures_start_date', }) mock_request.reset_mock() # ... our stored filter args got reset. self.assertEqual(len(query._filters), 0) # Check .count() also clears stored filter args appropriately: query.filter(tour_dossier_code='PPP', order_by__desc='departures_start_date').count() mock_request.assert_called_once_with('/tours', 'GET', params={ 'tour_dossier_code': 'PPP', 'order_by__desc': 'departures_start_date', }) mock_request.reset_mock() self.assertEqual(len(query._filters), 0)
def test_get_instance_by_id_with_non_404_error(self, mock_request): response = Response() response.status_code = 401 http_error = HTTPError(response=response) mock_request.side_effect = http_error # default behaviour is to raise... query = Query(self.client, Tour) with self.assertRaises(HTTPError) as context: query.get(1234) self.assertEqual(context.exception.response.status_code, response.status_code) # ... but if we don't want that exception raised, then we can include # that status code in our `httperrors_mapped_to_none` and verify that a # `None` is returned: self.assertIsNone( query.get(1234, httperrors_mapped_to_none=[response.status_code]))
def _set_resource_collection_field(self, field, value): is_parent_resource = getattr(self, '_is_parent_resource', None) if is_parent_resource: # FIXME: variation_id is hardcoded all over the client. This should # not be the case, but is a neccessity for now. parent = ( self._uri, self.id, getattr(self, 'variation_id', None), ) else: parent = None raw_data = value query = Query(self._client, self._model_cls(field), parent=parent, raw_data=raw_data) setattr(self, field, query)
def test_cached_get_does_not_set(self): """ Regression test https://github.com/gadventures/gapipy/issues/65 We discovered that when getting a resource, even if it is a hit in our local cache we would set the data back into our cache every time. When using a cache with a TTL on keys (e.g. Redis) this has the effect of resetting the TTL each time that that key is retrieved. This is not the expected behaviour wrt cache key TTLs. """ query = Query(self.client, Tour) # act like we already have the data in our cache mock_cache_get = MagicMock(return_value=PPP_TOUR_DATA) self.cache.get = mock_cache_get mock_cache_set = MagicMock() self.cache.set = mock_cache_set query.get(21346) self.assertEqual(len(mock_cache_get.mock_calls), 1) self.assertEqual(len(mock_cache_set.mock_calls), 0)
def test_get_instance_by_id(self, mock_request): query = Query(self.client, Tour) t = query.get(1234) self.assertIsInstance(t, Tour)
def test_query_key_no_resource_id(self): query = Query(self.client, self.resource) key = query.query_key() self.assertEqual(key, self.resource_name)
def test_query_key_with_variation_id(self): query = Query(self.client, self.resource) key = query.query_key(1, 2) expected = '{}:1:2:test'.format(self.resource_name) self.assertEqual(key, expected)
def test_query_persist_filter_on_count(self, mock_request): query = Query(self.client, Tour) my_query = query.filter(tour_dossier_code='PPP') my_query.count() self.assertEqual(my_query._filters, {'tour_dossier_code': 'PPP'})
def test_query_reset_filter(self, mock_request): query = Query(self.client, Tour) query.filter(tour_dossier_code='PPP').count() self.assertEqual(query._filters, {})
def test_count(self, mock_request): query = Query(self.client, TourDossier) count = query.count() self.assertIsInstance(count, int) self.assertEqual(count, 3)
def test_can_retrieve_single_subresource_without_parent( self, mock_request): Query(self.client, Departure).get(1234) mock_request.assert_called_once_with('/departures/1234', 'GET', additional_headers=None)
def test_can_retrieve_single_non_listable_resource(self, mock_request): Query(self.client, Activity).get(1234) mock_request.assert_called_once_with('/activities/1234', 'GET', additional_headers=None)