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_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_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_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_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_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 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 _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_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 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 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_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 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_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_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 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_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_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_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 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 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 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_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_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))
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