def test_model_filter_noquery(self): '''This test case ensures no exception occurs if the underlining query is None.''' model = Mock() model_filter = ModelFilter(model.id, 1, "gt") self.assertIsNone(model_filter.build(None))
def test_model_filter_ok(self): '''This test case ensures model filter can correctly enrich a given query with the right filters for all supported operations.''' expected_result = Mock() model = Mock() model.id = Column("id", Integer) model.id.like = Mock(return_value=expected_result) model.id.in_ = Mock(return_value=expected_result) query = Mock() model.id.table = Mock() query._primary_entity = query query.selectable = model.id.table query.filter = lambda *args, **kwargs: expected_result for operation in ModelFilter.get_supported_operations(): ref_value = 1 if operation == ModelFilter.IN: ref_value = [ref_value] model_filter = ModelFilter(model.id, ref_value, operation) new_query = model_filter.build(query) self.assertEqual(model.id, model_filter.column) self.assertEqual(operation, model_filter.operation) self.assertEqual(expected_result, new_query)
def test_modelfilteror_ok(self): '''This test case ensures compound **or** filter correctly transform the filter into sql alchemy and_ statement.''' self._or_invoked = False model_filter = ModelFilterOr( ModelFilter(self._model.id, 1, ModelFilter.EQ), ModelFilter(self._model.id, 1, ModelFilter.EQ), ModelFilter(self._model.id, 1, ModelFilter.EQ)) query = Mock() def filter_fn(expr): self._or_invoked = True return Mock() self._model.id.table = Mock() query._primary_entity = query query.selectable = self._model.id.table query.filter = filter_fn query_new = model_filter.build(query) self.assertTrue(self._or_invoked) self.assertIsInstance(query_new, Mock)
def test_modelfiteror_unhandled_exception(self): '''This test case ensures unhandled exceptions raised from ModelFilter are gracefully handled by ModelFilterOr build.''' model_filter = ModelFilter(self._model.id, 1, ModelFilter.EQ) model_filter.get_expression = Mock(side_effect=Exception("Unhandled exception")) model_filter_or = ModelFilterOr(model_filter, model_filter, model_filter) with self.assertRaises(FantasticoError): model_filter_or.build(Mock())
def test_get_paged_records_ok(self): '''This test case ensures records can be retrieved correctly from a facade.''' expected_model = Mock() self._model_filter = ModelFilter(PersonModelTest.id, 1, ModelFilter.GT) self._model_sort = ModelSort(PersonModelTest.first_name) def query_mock(cls_obj): self.assertEqual(PersonModelTest, cls_obj) return self._session def filter_mock(expr): self.assertEqual(self._model_filter.get_expression(), expr) return self._session def sort_mock(expr): self.assertEqual(self._model_sort.get_expression(), expr) return self._session def offset_mock(offset): self.assertEqual(0, offset) return self._session def limit_mock(limit_count): self.assertEqual(4, limit_count) return self._session self._session.query = query_mock self._session._primary_entity = self._session self._session.selectable = PersonModelTest.id.table self._session.filter = filter_mock self._session.order_by = sort_mock self._session.offset = offset_mock self._session.limit = limit_mock self._session.all = Mock( return_value=[expected_model, expected_model, expected_model]) records = self._facade.get_records_paged( start_record=0, end_record=4, sort_expr=self._model_sort, filter_expr=self._model_filter) self.assertIsNotNone(records) self.assertEqual(3, len(records)) for model in records: self.assertEqual(expected_model, model)
def test_model_filter_eq(self): '''This test case ensures model filters equality evaluation works as expected.''' model = Mock() model.id = Column("id", Integer) filter1 = ModelFilter(model.id, 1, ModelFilter.EQ) filter2 = ModelFilter(model.id, 1, ModelFilter.EQ) self.assertEqual(filter1, filter2) self.assertEqual(hash(filter1), hash(filter2))
def test_modelfilterand_eq_differenttype(self): '''This test case ensures compound model filter and can not be equal with a simple model filter.''' id_col = Column("id", Integer) name_col = Column("name", String(100)) filter1 = ModelFilter(id_col, 1, ModelFilter.EQ) filter2 = ModelFilterAnd(filter1, ModelFilter(name_col, "john", ModelFilter.EQ)) self.assertNotEqual(filter2, filter1) self.assertNotEqual(hash(filter2), hash(filter1))
def test_modelfiteror_unhandled_exception(self): '''This test case ensures unhandled exceptions raised from ModelFilter are gracefully handled by ModelFilterOr build.''' model_filter = ModelFilter(self._model.id, 1, ModelFilter.EQ) model_filter.get_expression = Mock( side_effect=Exception("Unhandled exception")) model_filter_or = ModelFilterOr(model_filter, model_filter, model_filter) with self.assertRaises(FantasticoError): model_filter_or.build(Mock())
def test_retrieve_message_byfilter_and(self): '''This test case ensures filtering message using compound **and** works as expected.''' model_filter_gt = ModelFilter(ModelFacadeMessage.id, 1, ModelFilter.GT) model_filter_like = ModelFilter(ModelFacadeMessage.message, "%%world 4%%", ModelFilter.LIKE) model_filter_and = ModelFilterAnd(model_filter_gt, model_filter_like) records = self.model_facade.get_records_paged( 0, 100, filter_expr=model_filter_and) self.assertEqual(1, len(records)) self.assertEqual(self.last_generated_pk, records[0].id) self.assertEqual(self.MESSAGES[-1], records[0].message)
def test_modelfilterand_eq_different(self): '''This test case ensures compound model filter and is not always equal with another compound model filter and.''' id_col = Column("id", Integer) name_col = Column("name", String(100)) filter1 = ModelFilterAnd(ModelFilter(id_col, 1, ModelFilter.EQ), ModelFilter(id_col, 1, ModelFilter.EQ)) filter2 = ModelFilterAnd(ModelFilter(id_col, 1, ModelFilter.EQ), ModelFilter(name_col, "john", ModelFilter.EQ)) self.assertNotEqual(filter1, filter2) self.assertNotEqual(hash(filter1), hash(filter2))
def test_model_filter_in_notsupported(self): '''This test case ensures in filter raises an exception if ref_value is not a list.''' model = Mock() model.id = Column("id", Integer) model_filter = ModelFilter(model.id, "invalid list", ModelFilter.IN) query = Mock() query._primary_entity = query query.selectable = model.id.table with self.assertRaises(FantasticoNotSupportedError): model_filter.build(query)
def test_modelfilterand_eq_ok(self): '''This test case ensures two model filters and equality works as expected.''' id_col = Column("id", Integer) name_col = Column("name", String(100)) filter1 = ModelFilterAnd(ModelFilter(id_col, 1, ModelFilter.EQ), ModelFilter(name_col, "john", ModelFilter.EQ)) filter2 = ModelFilterAnd(ModelFilter(id_col, 1, ModelFilter.EQ), ModelFilter(name_col, "john", ModelFilter.EQ)) self.assertEqual(filter1, filter2) self.assertEqual(hash(filter1), hash(filter2))
def test_model_filter_noteq_sametype(self): '''This test case ensures model filter equality fails if one of attributes (column, ref_value, operation) varies.''' model = Mock() model.id = Column("id", Integer) model.name = Column("name", String(100)) filter1 = ModelFilter(model.id, 1, ModelFilter.EQ) self.assertFalse(filter1 == ModelFilter(model.name, 1, ModelFilter.EQ)) self.assertFalse( hash(filter1) == hash(ModelFilter(model.name, 1, ModelFilter.EQ))) self.assertFalse( hash(filter1) == hash(ModelFilter(model.id, 2, ModelFilter.EQ))) self.assertFalse(filter1 == ModelFilter(model.id, 1, ModelFilter.GT))
def test_model_filter_operation_notsupported(self): '''This test case ensures an exception is raised when the requested operation is not supported.''' model = Mock() with self.assertRaises(FantasticoNotSupportedError): ModelFilter(model.id, 1, "xx")
def _validate_return_url(self, clienturls_facade, return_url): '''This test case checks the existence of return url in the list of supported return urls for idp.''' qmark_pos = return_url.find("?") if qmark_pos > -1: return_url = return_url[:qmark_pos] client_urls = clienturls_facade.get_records_paged( start_record=0, end_record=1, filter_expr=ModelFilterAnd( ModelFilter(ClientReturnUrl.client_id, self._idp_client_id, ModelFilter.EQ), ModelFilter(ClientReturnUrl.return_url, return_url, ModelFilter.EQ))) if len(client_urls) != 1: raise OAuth2MissingQueryParamError(self.REDIRECT_PARAM)
def test_count_records_unhandled_exception(self): '''This test case ensures count method gracefully handles unexpected exceptions.''' self._model_filter = ModelFilter(PersonModelTest.id, 1, ModelFilter.GT) self._model_filter.build = Mock( side_effect=Exception("Unhandled exception")) def rollback(): self._rollbacked = True self._session.rollback = rollback with self.assertRaises(FantasticoDbError): self._facade.count_records(self._model_filter) self.assertTrue(self._rollbacked)
def test_get_records_paged_unhandled_exception(self): '''This test case ensures that any unhandled exception from filters / sql alchemy is gracefully handled.''' self._model_filter = ModelFilter(PersonModelTest.id, 1, ModelFilter.GT) self._model_filter.build = Mock( side_effect=Exception("Unhandled exception")) def rollback(): self._rollbacked = True self._session.rollback = rollback with self.assertRaises(FantasticoDbError): self._facade.get_records_paged(start_record=0, end_record=4, filter_expr=self._model_filter) self.assertTrue(self._rollbacked)
def build_filter(self, model): '''This method builds a binary filter.''' try: self._value = json.loads(self._value) except ValueError: pass return ModelFilter(column=self._column, ref_value=self._value, operation=self._operation)
def test_model_filter_noteq_differenttype(self): '''This test case ensures model filter equality fails when compared with a different object type.''' model = Mock() model.id = Column("id", Integer) filter1 = ModelFilter(model.id, 1, ModelFilter.EQ) filter2 = object() self.assertFalse(filter1 == filter2) self.assertFalse(hash(filter1) == hash(filter2))
def load_by_username(self, username): '''This method tries to load a user by username. If it does not exist a FantasticoDbNotFoundError is raised.''' users = self._user_facade.get_records_paged( start_record=0, end_record=1, filter_expr=ModelFilter(User.username, username, ModelFilter.EQ)) if not users: raise FantasticoDbNotFoundError("User %s does not exist." % username) return users[0]
def test_get_paged_records_ok(self): '''This test case ensures records can be retrieved correctly from a facade.''' expected_model = Mock() self._model_filter = ModelFilter(PersonModelTest.id, 1, ModelFilter.GT) self._model_sort = ModelSort(PersonModelTest.first_name) def query_mock(cls_obj): self.assertEqual(PersonModelTest, cls_obj) return self._session def filter_mock(expr): self.assertEqual(self._model_filter.get_expression(), expr) return self._session def sort_mock(expr): self.assertEqual(self._model_sort.get_expression(), expr) return self._session def offset_mock(offset): self.assertEqual(0, offset) return self._session def limit_mock(limit_count): self.assertEqual(4, limit_count) return self._session self._session.query = query_mock self._session._primary_entity = self._session self._session.selectable = PersonModelTest.id.table self._session.filter = filter_mock self._session.order_by = sort_mock self._session.offset = offset_mock self._session.limit = limit_mock self._session.all = Mock(return_value=[expected_model, expected_model, expected_model]) records = self._facade.get_records_paged(start_record=0, end_record=4, sort_expr=self._model_sort, filter_expr=self._model_filter) self.assertIsNotNone(records) self.assertEqual(3, len(records)) for model in records: self.assertEqual(expected_model, model)
def test_authenticate_invalid_redirecturi(self): '''This test case ensures an exception is raised when the return url query parameter is not accepted by idp.''' creation_time, expiration_time = self._mock_creationexpiration_time() user = User(username="******", password="******") user.session = Mock() return_url = "/test/url?state=xyz" token = Token({ "client_id": self._IDP_CLIENTID, "type": "login", "user_id": user.user_id, "creation_time": creation_time, "expiration_time": expiration_time }) request, user_repo_cls, user_repo, tokens_service_cls, \ tokens_service, clienturl_facade = self._mock_authenticate_dependencies(token, user, return_url) clienturl_facade.get_records_paged = Mock(return_value=[]) with self.assertRaises(OAuth2MissingQueryParamError): self._idp_controller.authenticate( request, tokens_service_cls=tokens_service_cls, user_repo_cls=user_repo_cls) return_url = return_url[:return_url.find("?")] clienturl_facade.get_records_paged.assert_called_once_with( start_record=0, end_record=1, filter_expr=ModelFilterAnd( ModelFilter(ClientReturnUrl.client_id, self._IDP_CLIENTID, ModelFilter.EQ), ModelFilter(ClientReturnUrl.return_url, return_url, ModelFilter.EQ)))
def serve_dynamic_page(self, request, page_url, os_provider=os): '''This method is used to route all /dynamic/... requests to database pages. It renders the configured template into database binded to :py:class:`fantastico.contrib.models.pages.DynamicPageModel` values.''' page_facade = request.models.DynamicPage page_attr_facade = request.models.DynamicPageModel page_url = "/%s" % page_url page = page_facade.get_records_paged( 0, 1, ModelFilter(DynamicPage.url, page_url, ModelFilter.EQ)) if len(page) == 0: msg_not_found = "Page %s does not exist." % page_url return Response(msg_not_found.encode(), content_type="text/html", status=404) page = page[0] page_attrs = page_attr_facade.get_records_paged( 0, self.MAX_PAGE_ATTRS, ModelFilter(DynamicPageModel.page_id, page.id, ModelFilter.EQ)) return self._load_page(page, page_attrs, os_provider)
def test_count_records_unhandled_exception(self): '''This test case ensures count method gracefully handles unexpected exceptions.''' self._model_filter = ModelFilter(PersonModelTest.id, 1, ModelFilter.GT) self._model_filter.build = Mock(side_effect=Exception("Unhandled exception")) def rollback(): self._rollbacked = True self._session.rollback = rollback with self.assertRaises(FantasticoDbError): self._facade.count_records(self._model_filter) self.assertTrue(self._rollbacked)
def test_count_records_filtered_ok(self): '''This test case ensures count method works correctly when a filter is given.''' self._model_filter = ModelFilter(PersonModelTest.id, 1, ModelFilter.GT) def query_mock(cls_obj): self.assertEqual(PersonModelTest, cls_obj) return self._session def filter_mock(expr): self.assertEqual(self._model_filter.get_expression(), expr) return self._session self._session.query = query_mock self._session._primary_entity = self._session self._session.selectable = PersonModelTest.id.table self._session.filter = filter_mock self._session.count = Mock(return_value=20) records_count = self._facade.count_records(self._model_filter) self.assertEqual(20, records_count)
def test_get_records_paged_unhandled_exception(self): '''This test case ensures that any unhandled exception from filters / sql alchemy is gracefully handled.''' self._model_filter = ModelFilter(PersonModelTest.id, 1, ModelFilter.GT) self._model_filter.build = Mock(side_effect=Exception("Unhandled exception")) def rollback(): self._rollbacked = True self._session.rollback = rollback with self.assertRaises(FantasticoDbError): self._facade.get_records_paged(start_record=0, end_record=4, filter_expr=self._model_filter) self.assertTrue(self._rollbacked)
def test_retrieve_subset_ordered_asc(self): '''This test case ensures subset records retrieval work as expected for asc order.''' model_filter_like = ModelFilter(ModelFacadeMessage.message, "%%world%%", ModelFilter.LIKE) model_sort = ModelSort(ModelFacadeMessage.message, ModelSort.ASC) records = self.model_facade.get_records_paged( 1, 3, filter_expr=model_filter_like, sort_expr=model_sort) self.assertIsNotNone(records) self.assertEqual(2, len(records)) self.assertEqual(self.MESSAGES[1], records[0].message) self.assertEqual(self.MESSAGES[2], records[1].message) self.assertLess(records[0].id, records[1].id)
def test_retrieve_subset_ordered_asc_in(self): '''This test case ensures a subset of records is retrieved correctly when order expression and in filter are specified.''' model_filter_in = ModelFilter(ModelFacadeMessage.message, ["Hello world 2", "Hello world 3"], ModelFilter.IN) model_sort = ModelSort(ModelFacadeMessage.message, ModelSort.ASC) records = self.model_facade.get_records_paged( 1, 2, filter_expr=model_filter_in, sort_expr=model_sort) self.assertIsNotNone(records) self.assertEqual(1, len(records)) self.assertEqual(self.MESSAGES[-2], records[0].message)
def init(self): '''This method creates a number of messages before each test case.''' for message in ModelFacadeIntegration.MESSAGES: message_entity = self.model_facade.new_model(message=message) message_id = self.model_facade.create(message_entity) assert message_id[0] == message_entity.id assert message_id[0] > 0 self.last_generated_pk = message_id[0] self.entities_created.append(message_entity) records_count = self.model_facade.count_records( ModelFilter(ModelFacadeMessage.id, 0, ModelFilter.GT)) self.assertEqual(len(self.MESSAGES), records_count)
def test_load_by_username(self): '''This test case ensures a user can be loaded by username.''' user = User(username="******", password="******", person_id=1) self._user_facade.get_records_paged = Mock(return_value=[user]) result = self._repo.load_by_username(user.username) self.assertEqual(user, result) self._user_facade.get_records_paged.assert_called_once_with( start_record=0, end_record=1, filter_expr=ModelFilter(User.username, user.username, ModelFilter.EQ))
def load_client_by_returnurl(self, return_url): '''This method load the first available client descriptor which has the specified return url. Please make sure return url is decoded before invoking this method or it will not work otherwise.''' qmark_pos = return_url.find("?") if qmark_pos == -1: qmark_pos = len(return_url) return_url = return_url[:qmark_pos] results = self._url_facade.get_records_paged( start_record=0, end_record=1, filter_expr=ModelFilter(ClientReturnUrl.return_url, return_url, ModelFilter.EQ)) if not results: return None return results[0].client
def retrieve_menu_items(self, request, menu_id): '''This method is used to retrieve all items associated with a specified menu. :param request: Http request being processed. :type request: HTTP request :param menu_id: Menu unique identifier we want to retrieve information for. :type menu_id: int :returns: A JSON array containing all available menu items. :raises fantastico.contrib.dynamic_menu.menu_exceptions.FantasticoMenuNotFoundException: Whenever the requested menu does not exist. ''' menu_id = int(menu_id) menus_facade = request.models.Menus if not menus_facade.find_by_pk({DynamicMenu.id: menu_id}): raise FantasticoMenuNotFoundException("Menu %s does not exist." % menu_id) items_facade = request.models.Items items = items_facade.get_records_paged(start_record=0, end_record=self.max_items, filter_expr=[ ModelFilter( DynamicMenuItem.menu_id, menu_id, ModelFilter.EQ) ]) items = [{ "url": item.url, "target": item.target, "title": item.title, "label": item.label } for item in items or []] body = json.dumps({"items": items}) return Response(body, content_type="application/json")
def _test_load_clienturl_template(self, return_url, base_url=None, client_id="abc"): '''This method provides a template for testing load_client_by_returnurl success scenarios.''' base_url = base_url or return_url client = Client(client_id=client_id) url = ClientReturnUrl() url.client = client self._url_facade.get_records_paged = Mock(return_value=[url]) result = self._repo.load_client_by_returnurl(return_url) self.assertEqual(client, result) self._url_facade.get_records_paged.assert_called_once_with( start_record=0, end_record=1, filter_expr=ModelFilter(ClientReturnUrl.return_url, base_url, ModelFilter.EQ))
class ModelFacadeTests(FantasticoUnitTestsCase): '''This class provides test suite for generating a model facade for BaseModel classes.''' def init(self): self._session = Mock() self._facade = ModelFacade(PersonModelTest, self._session) self._rollbacked = False self._model_filter = None self._model_sort = None def test_new_model_ok(self): '''This test case ensures a model facade can obtain an instance of a given class.''' for model in [self._facade.new_model("John", **{"last_name": "Doe"}), self._facade.new_model("John", last_name="Doe")]: self.assertEqual(PersonModelTest, self._facade.model_cls) self.assertIsInstance(model, BASEMODEL) self.assertEqual("John", model.first_name) self.assertEqual("Doe", model.last_name) def test_new_model_incompatible(self): '''This test case makes sure a model facade instance raises an exception if given model class does not extend **BASEMODEL**.''' with self.assertRaises(FantasticoIncompatibleClassError): ModelFacade(Mock(), Mock()) def test_create_ok(self): '''This test case makes sure a model can be correctly saved using a facade.''' model = PersonModelTest(first_name="John", last_name="Doe") def add(model): model.id = 1 return self._session self._session.add = add model_id = self._facade.create(model) self.assertFalse(self._rollbacked) self.assertEqual(1, len(model_id)) self.assertEqual(1, model_id[0]) self.assertEqual(1, model.id) def test_create_exception_unhandled(self): '''This test case makes sure a model creation exception is wrapped correctly into a concrete fantastico exception.''' model = PersonModelTest(first_name="John", last_name="Doe") self._session.add = Mock(side_effect=Exception("Unhandled exception")) def rollback(): self._rollbacked = True self._session.rollback = rollback self.assertRaises(FantasticoDbError, self._facade.create, *[model]) self.assertTrue(self._rollbacked) def test_update_ok(self): '''This test case ensures a model can be updated correctly using model facade.''' model = PersonModelTest(first_name="John", last_name="Doe") model.id = 1 self._session.query = Mock(return_value=self._session) self._session.filter = Mock(return_value=self._session) self._session.all = Mock(return_value=[model]) def merge(model): model.first_name = "John Changed" self._session.merge = merge self._facade.update(model) self.assertFalse(self._rollbacked) self.assertEqual("John Changed", model.first_name) def test_update_exception_unhandled(self): '''This test case ensures a model update gracefully handles all unhandled exceptions.''' model = PersonModelTest(first_name="John", last_name="Doe") model.id = 1 self._session.query = Mock(return_value=self._session) self._session.filter = Mock(return_value=self._session) self._session.all = Mock(return_value=[model]) self._session.merge = Mock(side_effect=Exception("Unhandled exception")) def rollback(): self._rollbacked = True self._session.rollback = rollback self.assertRaises(FantasticoDbError, self._facade.update, *[model]) self.assertTrue(self._rollbacked) def test_update_exception_notfound(self): '''This test case ensures a model update exception is raised when the given model does not exist.''' model = PersonModelTest(first_name="John", last_name="Doe") model.id = 1 self._session.query = Mock(return_value=self._session) self._session.filter = Mock(return_value=self._session) self._session.all = Mock(return_value=[]) def rollback(): self._rollbacked = True self._session.rollback = rollback self.assertRaises(FantasticoDbNotFoundError, self._facade.update, *[model]) self.assertTrue(self._rollbacked) def test_find_by_pk_ok(self): '''This test case ensures find_by_pk method retrieves a model instance when a record is found by id.''' model = PersonModelTest(first_name="John", last_name="Doe") model.id = 1 self._session.query = Mock(return_value=self._session) self._session.filter = Mock(return_value=self._session) self._session.all = Mock(return_value=[model]) response = self._facade.find_by_pk({PersonModelTest.id: 1}) self.assertFalse(self._rollbacked) self.assertEqual(model, response) def test_find_by_pk_notfound(self): '''This test case ensures find_by_pk method raises an exception when a matching record is not found.''' model = PersonModelTest(first_name="John", last_name="Doe") model.id = 1 self._session.query = Mock(return_value=self._session) self._session.filter = Mock(return_value=self._session) self._session.all = Mock(return_value=[]) def rollback(): self._rollbacked = True self._session.rollback = rollback with self.assertRaises(FantasticoDbNotFoundError): self._facade.find_by_pk({PersonModelTest.id: 1}) self.assertTrue(self._rollbacked) def test_delete_ok(self): '''This test case ensures a model can be deleted successfully if no exception occurs.''' model = PersonModelTest(first_name="John", last_name="Doe") model.id = 1 self._facade.delete(model) self.assertFalse(self._rollbacked) def test_delete_exception_unhandled(self): '''This test case ensures unhandled exceptions are gracefully handled by delete method.''' model = PersonModelTest(first_name="John", last_name="Doe") model.id = 1 self._session.delete = Mock(side_effect=Exception("Unhandled exception")) def rollback(): self._rollbacked = True self._session.rollback = rollback with self.assertRaises(FantasticoDbError): self._facade.delete(model) self.assertTrue(self._rollbacked) def test_get_paged_records_ok(self): '''This test case ensures records can be retrieved correctly from a facade.''' expected_model = Mock() self._model_filter = ModelFilter(PersonModelTest.id, 1, ModelFilter.GT) self._model_sort = ModelSort(PersonModelTest.first_name) def query_mock(cls_obj): self.assertEqual(PersonModelTest, cls_obj) return self._session def filter_mock(expr): self.assertEqual(self._model_filter.get_expression(), expr) return self._session def sort_mock(expr): self.assertEqual(self._model_sort.get_expression(), expr) return self._session def offset_mock(offset): self.assertEqual(0, offset) return self._session def limit_mock(limit_count): self.assertEqual(4, limit_count) return self._session self._session.query = query_mock self._session._primary_entity = self._session self._session.selectable = PersonModelTest.id.table self._session.filter = filter_mock self._session.order_by = sort_mock self._session.offset = offset_mock self._session.limit = limit_mock self._session.all = Mock(return_value=[expected_model, expected_model, expected_model]) records = self._facade.get_records_paged(start_record=0, end_record=4, sort_expr=self._model_sort, filter_expr=self._model_filter) self.assertIsNotNone(records) self.assertEqual(3, len(records)) for model in records: self.assertEqual(expected_model, model) def test_get_records_paged_default(self): '''This test case ensure records are retrieved when no filter / sort_expr are specified.''' def query_mock(cls_obj): self.assertEqual(PersonModelTest, cls_obj) return self._session def offset_mock(offset): self.assertEqual(0, offset) return self._session def limit_mock(limit_count): self.assertEqual(4, limit_count) return self._session self._session.query = query_mock self._session.offset = offset_mock self._session.limit = limit_mock self._session.all = Mock(return_value=[]) records = self._facade.get_records_paged(start_record=0, end_record=4) self.assertIsNotNone(records) self.assertEqual(0, len(records)) def test_get_records_paged_unhandled_exception(self): '''This test case ensures that any unhandled exception from filters / sql alchemy is gracefully handled.''' self._model_filter = ModelFilter(PersonModelTest.id, 1, ModelFilter.GT) self._model_filter.build = Mock(side_effect=Exception("Unhandled exception")) def rollback(): self._rollbacked = True self._session.rollback = rollback with self.assertRaises(FantasticoDbError): self._facade.get_records_paged(start_record=0, end_record=4, filter_expr=self._model_filter) self.assertTrue(self._rollbacked) def test_count_records_default_ok(self): '''This test case ensures count method works correctly.''' def query_mock(cls_obj): self.assertEqual(PersonModelTest, cls_obj) return self._session self._session.query = query_mock self._session.count = Mock(return_value=20) records_count = self._facade.count_records() self.assertEqual(20, records_count) def test_count_records_filtered_ok(self): '''This test case ensures count method works correctly when a filter is given.''' self._model_filter = ModelFilter(PersonModelTest.id, 1, ModelFilter.GT) def query_mock(cls_obj): self.assertEqual(PersonModelTest, cls_obj) return self._session def filter_mock(expr): self.assertEqual(self._model_filter.get_expression(), expr) return self._session self._session.query = query_mock self._session._primary_entity = self._session self._session.selectable = PersonModelTest.id.table self._session.filter = filter_mock self._session.count = Mock(return_value=20) records_count = self._facade.count_records(self._model_filter) self.assertEqual(20, records_count) def test_count_records_unhandled_exception(self): '''This test case ensures count method gracefully handles unexpected exceptions.''' self._model_filter = ModelFilter(PersonModelTest.id, 1, ModelFilter.GT) self._model_filter.build = Mock(side_effect=Exception("Unhandled exception")) def rollback(): self._rollbacked = True self._session.rollback = rollback with self.assertRaises(FantasticoDbError): self._facade.count_records(self._model_filter) self.assertTrue(self._rollbacked)
def get_collection(self, request, version, resource_url): '''This method provides the route for accessing a resource collection. :doc:`/features/roa/rest_standard` for collections are enabled by this method. The typical response format is presented below: .. code-block:: javascript var response = {"items": [ // resources represented as json objects. ], "totalItems": 100} If a resource is not found or the resource version does not exist the following response is returned: .. code-block:: javascript {"error_code": 10000, "error_description": "Resource %s version %s does not exist.", "error_details": "http://rcosnita.github.io/fantastico/html/features/roa/errors/error_10000.html"} ''' if version != "latest": version = float(version) params = CollectionParams(request, RoaController.OFFSET_DEFAULT, RoaController.LIMIT_DEFAULT) resource = self._resources_registry.find_by_url(resource_url, version) if not resource: return self._handle_resource_notfound(version, resource_url) self._inject_security_context(request, resource.model) access_token = self.validate_security_context(request, "read") json_serializer = self._json_serializer_cls(resource) filter_expr = self._parse_filter(params.filter_expr, resource.model) if resource.user_dependent: if filter_expr: filter_expr = ModelFilterAnd( filter_expr, ModelFilter(resource.model.user_id, access_token.user_id, ModelFilter.EQ)) else: filter_expr = ModelFilter(resource.model.user_id, access_token.user_id, ModelFilter.EQ) sort_expr = self._parse_sort(params.order_expr, resource.model) model_facade = self._model_facade_cls( resource.model, self._get_current_connection(request)) models = model_facade.get_records_paged(start_record=params.offset, end_record=params.offset + params.limit, filter_expr=filter_expr, sort_expr=sort_expr) items = [ json_serializer.serialize(model, params.fields) for model in models ] if resource.validator: resource.validator().format_collection(items, request) models_count = model_facade.count_records(filter_expr=filter_expr) body = {"items": items, "totalItems": models_count} response = Response(text=json.dumps(body), content_type="application/json", status_code=200) self._add_cors_headers(response) return response