Example #1
0
    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))
Example #2
0
    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))
Example #3
0
    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)
Example #4
0
    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())
Example #7
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)
Example #8
0
    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))
Example #9
0
    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)
Example #12
0
    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))
Example #13
0
    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)
Example #14
0
    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))
Example #15
0
    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)
Example #16
0
    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))
Example #17
0
    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")
Example #18
0
    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)
Example #19
0
    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)
Example #20
0
    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)
Example #21
0
    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)
Example #22
0
    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))
Example #23
0
    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]
Example #24
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)
Example #25
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)))
Example #26
0
    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)
Example #27
0
    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)        
Example #28
0
    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)
Example #29
0
    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))
Example #34
0
    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
Example #35
0
    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")
Example #36
0
 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))
Example #38
0
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)        
Example #39
0
    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