Пример #1
0
def get_all(collection_name: str, last_key: str, limit: int):
    is_system = DynamoPlusService.is_system(collection_name)
    last_evaluated_key = None
    if is_system:
        logger.info("Get {} metadata from system".format(collection_name))
        if collection_name == 'collection':
            last_collection_metadata = None
            collections, last_evaluated_key = SystemService.get_all_collections(
                limit, last_key)
            documents = list(
                map(lambda c: from_collection_to_dict(c), collections))
            return documents, last_evaluated_key
        else:
            raise HandlerException(HandlerExceptionErrorCodes.BAD_REQUEST,
                                   "{} not valid", collection_name)
    else:
        logger.info("get all  {} collection limit = {} last_key = {} ".format(
            collection_name, limit, last_key))
        collection_metadata = SystemService.get_collection_by_name(
            collection_name)
        if collection_metadata is None:
            raise HandlerException(
                HandlerExceptionErrorCodes.BAD_REQUEST,
                "{} is not a valid collection".format(collection_name))
        domain_service = DomainService(collection_metadata)
        logger.info("Query all {}".format(collection_name))
        documents, last_evaluated_key = domain_service.find_all(
            limit, last_key)
        return documents, last_evaluated_key
Пример #2
0
def update(collection_name: str, document: dict, document_id: str = None):
    is_system = DynamoPlusService.is_system(collection_name)
    if is_system:
        if collection_name == "client_authorization":
            if document_id:
                document["client_id"] = document_id
            validate_client_authorization(document)
            client_authorization = from_dict_to_client_authorization(document)
            client_authorization = SystemService.update_authorization(
                client_authorization)
            logging.info("updated client_authorization {}".format(
                client_authorization.__str__))
            return from_client_authorization_to_dict(client_authorization)
        else:
            raise HandlerException(
                HandlerExceptionErrorCodes.BAD_REQUEST,
                "updating {} is not supported ".format(collection_name))
    else:
        logger.info("update {} document {}".format(collection_name, document))
        collection_metadata = SystemService.get_collection_by_name(
            collection_name)
        if collection_metadata is None:
            raise HandlerException(
                HandlerExceptionErrorCodes.BAD_REQUEST,
                "{} is not a valid collection".format(collection_name))
        if document_id:
            document[collection_metadata.id_key] = document_id
        validate_document(document, collection_metadata)
        timestamp = datetime.utcnow()
        document["update_date_time"] = timestamp.isoformat()
        d = DomainService(collection_metadata).update_document(document)
        logger.info("updated document {}".format(d))
        return d
Пример #3
0
def update_indexes(collection_name: str, new_record: dict):
    system_service = SystemService()
    collection_metadata = system_service.get_collection_by_name(
        collection_name)
    if collection_metadata:
        __indexing(lambda r: r.update(new_record), system_service,
                   collection_name, collection_metadata, new_record)
    else:
        logger.debug(
            'Skipping creating indexes on record of type {}:  collection not found'
            .format(collection_name))
Пример #4
0
def get(collection_name: str, document_id: str):
    is_system = DynamoPlusService.is_system(collection_name)
    if is_system:
        logger.info("Get {} metadata from system".format(collection_name))
        if collection_name == 'collection':
            collection_metadata = SystemService.get_collection_by_name(
                document_id)
            if collection_metadata is None:
                raise HandlerException(
                    HandlerExceptionErrorCodes.NOT_FOUND,
                    "{} not found with name {}".format(collection_name,
                                                       document_id))
            logger.info("Found collection {}".format(
                collection_metadata.__str__))
            return collection_metadata.__dict__
        elif collection_name == 'index':
            index_metadata = SystemService.get_index(document_id,
                                                     collection_name)
            if index_metadata is None:
                raise HandlerException(
                    HandlerExceptionErrorCodes.NOT_FOUND,
                    "{} not found with name {}".format(collection_name,
                                                       document_id))
            logger.info("Found index {}".format(index_metadata.__str__))
            return index_metadata.__dict__
        elif collection_name == 'client_authorization':
            client_authorization = SystemService.get_client_authorization(
                document_id)
            if client_authorization is None:
                raise HandlerException(
                    HandlerExceptionErrorCodes.NOT_FOUND,
                    "{} not found with name {}".format(collection_name,
                                                       document_id))
            logger.info("Found client_authorization {}".format(
                client_authorization.__str__))
            return from_client_authorization_to_dict(client_authorization)
        else:
            raise HandlerException(HandlerExceptionErrorCodes.BAD_REQUEST,
                                   "{} not valid", collection_name)

    else:
        logger.info("Get {} document".format(collection_name))
        collection_metadata = SystemService.get_collection_by_name(
            collection_name)
        if collection_metadata is None:
            raise HandlerException(
                HandlerExceptionErrorCodes.BAD_REQUEST,
                "{} is not a valid collection".format(collection_name))
        document = DomainService(collection_metadata).get_document(document_id)
        if document is None:
            raise HandlerException(
                HandlerExceptionErrorCodes.NOT_FOUND,
                "{} not found with id {}".format(collection_name, document_id))
        return document
Пример #5
0
def query(collection_name: str,
          query: dict = None,
          start_from: str = None,
          limit: int = None):
    is_system = DynamoPlusService.is_system(collection_name)
    documents = []
    last_evaluated_key = None
    if is_system:
        if collection_name == 'collection':
            collections, last_key = SystemService.get_all_collections(
                limit, start_from)
            documents = list(
                map(lambda c: from_collection_to_dict(c), collections))
            last_evaluated_key = last_key
        elif collection_name == 'index' and "matches" in query and "eq" in query[
                "matches"] and "value" in query["matches"]["eq"]:
            target_collection_name = query["matches"]["eq"]["value"]
            index_metadata_list, last_key = SystemService.find_indexes_from_collection_name(
                target_collection_name, limit, start_from)
            documents = list(
                map(lambda i: from_index_to_dict(i), index_metadata_list))
            last_evaluated_key = last_key
        else:
            raise HandlerException(
                HandlerExceptionErrorCodes.BAD_REQUEST,
                "{} is not a valid collection".format(collection_name))
    else:
        if "matches" in query:
            predicate: Predicate = from_dict_to_predicate(query["matches"])
        else:
            raise HandlerException(HandlerExceptionErrorCodes.BAD_REQUEST,
                                   "invalid predicate")
        logger.info("query {} collection by {} ".format(
            collection_name, predicate))
        collection_metadata = SystemService.get_collection_by_name(
            collection_name)
        if collection_metadata is None:
            raise HandlerException(
                HandlerExceptionErrorCodes.BAD_REQUEST,
                "{} is not a valid collection".format(collection_name))
        domain_service = DomainService(collection_metadata)

        query_id = "__".join(predicate.get_fields())
        index_metadata = SystemService.get_index(query_id, collection_name)
        if index_metadata is None:
            raise HandlerException(HandlerExceptionErrorCodes.BAD_REQUEST,
                                   "no index {} found".format(query_id))
        documents, last_evaluated_key = domain_service.query(
            predicate, limit, start_from)
    return documents, last_evaluated_key
Пример #6
0
def create(collection_name: str, document: dict) -> dict:
    is_system = DynamoPlusService.is_system(collection_name)
    if is_system:
        logger.info("Creating {} metadata {}".format(collection_name,
                                                     document))
        if collection_name == 'collection':
            validate_collection(document)
            collection_metadata = from_dict_to_collection(document)
            collection_metadata = SystemService.create_collection(
                collection_metadata)
            logger.info("Created collection {}".format(
                collection_metadata.__str__))
            return from_collection_to_dict(collection_metadata)
        elif collection_name == 'index':
            validate_index(document)
            index_metadata = from_dict_to_index(document)
            index_metadata = SystemService.create_index(index_metadata)
            logger.info("Created index {}".format(index_metadata.__str__))
            return from_index_to_dict(index_metadata)
        elif collection_name == 'client_authorization':
            validate_client_authorization(document)
            client_authorization = from_dict_to_client_authorization(document)
            client_authorization = SystemService.create_client_authorization(
                client_authorization)
            logging.info("created client_authorization {}".format(
                client_authorization.__str__()))
            return from_client_authorization_to_dict(client_authorization)
    else:
        logger.info("Create {} document {}".format(collection_name, document))
        collection_metadata = SystemService.get_collection_by_name(
            collection_name)
        validate_document(document, collection_metadata)
        if collection_metadata is None:
            raise HandlerException(
                HandlerExceptionErrorCodes.BAD_REQUEST,
                "{} is not a valid collection".format(collection_name))
        timestamp = datetime.utcnow()
        ## TODO: key generator
        if collection_metadata.auto_generate_id:
            document[collection_metadata.id_key] = str(uuid.uuid1())
        document["creation_date_time"] = timestamp.isoformat()
        document["order_unique"] = str(int(time.time() * 1000.0))
        d = DomainService(collection_metadata).create_document(document)
        logger.info("Created document {}".format(d))
        return d
Пример #7
0
 def get_client_authorization_by_api_key(headers: dict):
     authorization_value = AuthorizationService.get_authorization_value(
         headers, API_KEY_PREFIX)
     logger.info("authorization value = {}".format(authorization_value))
     if authorization_value and CLIENT_ID_HEADER in headers:
         client_id = headers[CLIENT_ID_HEADER]
         logger.info("client_id = {}".format(client_id))
         client_authorization = SystemService.get_client_authorization(
             client_id)
         logger.info(
             "found client authorization {}".format(client_authorization))
         if client_authorization.api_key == authorization_value:
             return client_authorization
Пример #8
0
    def get_client_authorization_using_http_signature_authorized(
            headers: dict, method: str, path: str):
        headers = dict((k.lower(), v) for k, v in headers.items())
        if "authorization" in headers:
            authorization_header = headers["authorization"]
            if authorization_header.startswith("Signature"):
                authorization_value = authorization_header.replace(
                    "Signature", "")
                signature_components = {}
                if authorization_value:
                    for v in authorization_value.split(","):
                        key, value = v.split("=", 1)
                        signature_components[key.strip()] = value.replace(
                            "\"", "")
                    if "keyId" in signature_components:
                        key_id = signature_components["keyId"]
                        logging.info("client {}".format(key_id))
                        client_authorization = SystemService.get_client_authorization(
                            key_id)
                        if client_authorization:
                            signatory_message = "(request-target): {} {}".format(
                                method, path)
                            for h in filter(
                                    lambda header: header.lower() !=
                                    'authorization', headers):
                                signatory_message += "\n{}: {}".format(
                                    h.lower(), headers[h])

                            rsakey = RSA.importKey(
                                client_authorization.client_public_key)
                            signer = PKCS1_v1_5.new(rsakey)
                            ## digest = SHA256.new()
                            signature = signature_components[
                                "signature"].replace("\"", "")
                            ## digest.update(b64decode(signatory_message))
                            hash = SHA256.new(
                                signatory_message.encode("utf-8"))
                            if signer.verify(hash, b64decode(signature)):
                                return client_authorization
                            else:
                                logging.error(
                                    "signature not verified for key id {}".
                                    format(key_id))
                        else:
                            logging.error(
                                "client authorization not found for key {}".
                                format(key_id))
                    else:
                        logging.error("missing key id")
                else:
                    logging.error("missing authorization value ")
Пример #9
0
def __indexing(repository_action: Callable[[DynamoPlusRepository], None],
               system_service: SystemService, collection_name: str,
               collection_metadata: Collection, new_record: dict):
    #logger.info("indexing {} record {}", collection_name, str(new_record))
    is_system = DynamoPlusService.is_system(collection_name)
    if not is_system:
        logger.debug("{} is not system".format(collection_name))
        indexes_by_collection_name, last_evaluated_key = system_service.find_indexes_from_collection_name(
            collection_name)
        for index in indexes_by_collection_name:
            logger.debug("found index {}".format(str(index)))
            repository = IndexDynamoPlusRepository(collection_metadata, index,
                                                   False)
            index_model = IndexModel(collection_metadata, new_record, index)
            if index_model.data():
                repository_action(repository)
Пример #10
0
def delete(collection_name: str, id: str):
    is_system = DynamoPlusService.is_system(collection_name)
    if is_system:
        logger.info("delete {} metadata from system".format(collection_name))
        if collection_name == 'collection':
            SystemService.delete_collection(id)
        elif collection_name == 'index':
            index_metadata = SystemService.delete_index(id)
        elif collection_name == 'client_authorization':
            SystemService.delete_authorization(id)
        else:
            raise NotImplementedError(
                "collection_name {} not handled".format(collection_name))
    else:
        logger.info("delete {} document {}".format(collection_name, id))
        collection_metadata = SystemService.get_collection_by_name(
            collection_name)
        if collection_metadata is None:
            raise HandlerException(
                HandlerExceptionErrorCodes.BAD_REQUEST,
                "{} is not a valid collection".format(collection_name))
        DomainService(collection_metadata).delete_document(id)
Пример #11
0
 def setUp(self):
     self.systemService = SystemService()
Пример #12
0
class TestSystemService(unittest.TestCase):
    def setUp(self):
        self.systemService = SystemService()

    @patch.object(DynamoPlusRepository, "update")
    @patch.object(DynamoPlusRepository, "__init__")
    def test_update_authorization_http_signature(self, mock_repository,
                                                 mock_update):
        expected_client_id = "test"
        client_authorization = ClientAuthorizationHttpSignature(
            expected_client_id, [Scope("example", ScopesType.CREATE)],
            "my-public-key")
        client_authorization_metadata = Collection("client_authorization",
                                                   "client_id")
        mock_repository.return_value = None
        document = {
            "type":
            "http_signature",
            "client_id":
            expected_client_id,
            "client_scopes": [{
                "collection_name": "example",
                "scope_type": "CREATE"
            }],
            "public_key":
            "my-public-key"
        }
        mock_update.return_value = Model(client_authorization_metadata,
                                         document)
        result = self.systemService.update_authorization(client_authorization)
        self.assertEqual(result.client_id, client_authorization.client_id)
        self.assertTrue(isinstance(result, ClientAuthorizationHttpSignature))
        self.assertEqual(call(document), mock_update.call_args_list[0])

    @patch.object(DynamoPlusRepository, "delete")
    @patch.object(DynamoPlusRepository, "__init__")
    def test_delete_authorization_http_signature(self, mock_repository,
                                                 mock_delete):
        expected_client_id = "test"
        client_authorization_metadata = Collection("client_authorization",
                                                   "client_id")
        mock_repository.return_value = None
        document = {
            "type":
            "http_signature",
            "client_id":
            expected_client_id,
            "client_scopes": [{
                "collection_name": "example",
                "scope_type": "CREATE"
            }],
            "public_key":
            "my-public-key"
        }
        mock_delete.return_value = Model(client_authorization_metadata,
                                         document)
        self.systemService.delete_authorization(expected_client_id)
        self.assertEqual(call(expected_client_id),
                         mock_delete.call_args_list[0])

    @patch.object(DynamoPlusRepository, "create")
    @patch.object(DynamoPlusRepository, "__init__")
    def test_create_authorization_http_signature(self, mock_repository,
                                                 mock_create):
        expected_client_id = "test"
        client_authorization = ClientAuthorizationHttpSignature(
            expected_client_id, [Scope("example", ScopesType.CREATE)],
            "my-public-key")
        client_authorization_metadata = Collection("client_authorization",
                                                   "client_id")
        mock_repository.return_value = None
        document = {
            "type":
            "http_signature",
            "client_id":
            expected_client_id,
            "client_scopes": [{
                "collection_name": "example",
                "scope_type": "CREATE"
            }],
            "public_key":
            "my-public-key"
        }
        mock_create.return_value = Model(client_authorization_metadata,
                                         document)
        result = self.systemService.create_client_authorization(
            client_authorization)
        self.assertEqual(result.client_id, client_authorization.client_id)
        self.assertTrue(isinstance(result, ClientAuthorizationHttpSignature))
        self.assertEqual(call(document), mock_create.call_args_list[0])

    @patch.object(DynamoPlusRepository, "create")
    @patch.object(DynamoPlusRepository, "__init__")
    def test_create_authorization_api_key(self, mock_repository, mock_create):
        expected_client_id = "test"
        client_authorization = ClientAuthorizationApiKey(
            expected_client_id, [Scope("example", ScopesType.CREATE)],
            "my-api-key", [])
        client_authorization_metadata = Collection("client_authorization",
                                                   "client_id")
        mock_repository.return_value = None
        document = {
            "type":
            "api_key",
            "client_id":
            expected_client_id,
            "client_scopes": [{
                "collection_name": "example",
                "scope_type": "CREATE"
            }],
            "api_key":
            "my-api-key"
        }
        mock_create.return_value = Model(client_authorization_metadata,
                                         document)
        result = self.systemService.create_client_authorization(
            client_authorization)
        self.assertEqual(result.client_id, client_authorization.client_id)
        self.assertTrue(isinstance(result, ClientAuthorizationApiKey))
        self.assertEqual(call(document), mock_create.call_args_list[0])

    @patch.object(DynamoPlusRepository, "get")
    @patch.object(DynamoPlusRepository, "__init__")
    def test_get_client_authorization_http_signature(self, mock_repository,
                                                     mock_get):
        expected_client_id = 'my-client-id'
        mock_repository.return_value = None
        client_authorization_metadata = Collection("client_authorization",
                                                   "client_id")
        document = {
            "client_id": expected_client_id,
            "type": "http_signature",
            "public_key": "my-public-key",
            "client_scopes": [{
                "collection_name": "example",
                "scope_type": "GET"
            }]
        }
        expected_model = Model(client_authorization_metadata, document)
        mock_get.return_value = expected_model
        result = self.systemService.get_client_authorization(
            expected_client_id)
        self.assertTrue(mock_get.called_with(expected_client_id))
        self.assertEqual(expected_client_id, result.client_id)
        self.assertIsInstance(result, ClientAuthorizationHttpSignature)
        self.assertEqual("my-public-key", result.client_public_key)
        self.assertEqual(1, len(result.client_scopes))
        self.assertEqual("example", result.client_scopes[0].collection_name)
        self.assertEqual("GET", result.client_scopes[0].scope_type.name)

    @patch.object(DynamoPlusRepository, "get")
    @patch.object(DynamoPlusRepository, "__init__")
    def test_get_client_authorization_api_key(self, mock_repository, mock_get):
        expected_client_id = 'my-client-id'
        mock_repository.return_value = None
        client_authorization_metadata = Collection("client_authorization",
                                                   "client_id")
        document = {
            "client_id": expected_client_id,
            "type": "api_key",
            "api_key": "my_api_key",
            "whitelist_hosts": ["*"],
            "client_scopes": [{
                "collection_name": "example",
                "scope_type": "GET"
            }]
        }
        expected_model = Model(client_authorization_metadata, document)
        mock_get.return_value = expected_model
        result = self.systemService.get_client_authorization(
            expected_client_id)
        self.assertTrue(mock_get.called_with(expected_client_id))
        self.assertEqual(expected_client_id, result.client_id)
        self.assertIsInstance(result, ClientAuthorizationApiKey)

    @patch.object(DynamoPlusRepository, "create")
    @patch.object(DynamoPlusRepository, "__init__")
    def test_createCollection(self, mock_repository, mock_create):
        expected_id = 'example'
        target_collection = {
            "name": "example",
            "id_key": "id",
            "ordering": None,
            "auto_generate_id": False
        }
        document = {"name": expected_id, "id_key": "id"}
        collection_metadata = Collection("collection", "name")
        expected_model = Model(collection_metadata, document)
        mock_repository.return_value = None
        mock_create.return_value = expected_model
        target_metadata = Collection("example", "id")
        created_collection = self.systemService.create_collection(
            target_metadata)
        collection_id = created_collection.name
        self.assertEqual(collection_id, expected_id)
        self.assertEqual(call(target_collection),
                         mock_create.call_args_list[0])

    @patch.object(DynamoPlusRepository, "delete")
    @patch.object(DynamoPlusRepository, "__init__")
    def test_deleteCollection(self, mock_repository, mock_delete):
        expected_id = 'example'
        mock_repository.return_value = None
        self.systemService.delete_collection(expected_id)
        self.assertTrue(mock_delete.called_with(expected_id))

    @patch.object(DynamoPlusRepository, "get")
    @patch.object(DynamoPlusRepository, "__init__")
    def test_getCollection(self, mock_repository, mock_get):
        expected_id = 'example'
        mock_repository.return_value = None
        collection_metadata = Collection("collection", "name")
        document = {
            "name": expected_id,
            "id_key": expected_id,
            "fields": [{
                "field1": "string"
            }]
        }
        expected_model = Model(collection_metadata, document)
        mock_get.return_value = expected_model
        result = self.systemService.get_collection_by_name(expected_id)
        # self.assertIn("fields",result)
        self.assertTrue(mock_get.called_with(expected_id))

    @patch.object(DynamoPlusRepository, "create")
    @patch.object(DynamoPlusRepository, "__init__")
    def test_createIndexWithOrdering(self, mock_repository, mock_create):
        expected_id = 'field1__field2.field21__ORDER_BY__field2.field21'
        expected_conditions = ["field1", "field2.field21"]
        target_index = {
            "uid": "1",
            "name": expected_id,
            "collection": {
                "name": "example"
            },
            "conditions": expected_conditions,
            "ordering_key": "field2.field21"
        }
        index_metadata = Collection("index", "name")
        expected_model = Model(index_metadata, target_index)
        mock_repository.return_value = None
        mock_create.return_value = expected_model
        index = Index("1", "example", expected_conditions, "field2.field21")
        created_index = self.systemService.create_index(index)
        index_name = created_index.index_name
        self.assertEqual(index_name, expected_id)
        self.assertEqual(call(target_index), mock_create.call_args_list[0])

    @patch.object(DynamoPlusRepository, "create")
    @patch.object(DynamoPlusRepository, "__init__")
    def test_createIndexWithNoOrdering(self, mock_repository, mock_create):
        expected_id = 'field1__field2.field21'
        expected_conditions = ["field1", "field2.field21"]
        target_index = {
            "uid": "1",
            "name": expected_id,
            "collection": {
                "name": "example"
            },
            "conditions": expected_conditions,
            "ordering_key": None
        }
        index_metadata = Collection("index", "name")
        expected_model = Model(index_metadata, target_index)
        mock_repository.return_value = None
        mock_create.return_value = expected_model
        index = Index("1", "example", expected_conditions)
        created_index = self.systemService.create_index(index)
        index_name = created_index.index_name
        self.assertEqual(index_name, expected_id)
        self.assertEqual(call(target_index), mock_create.call_args_list[0])

    @patch.object(DynamoPlusRepository, "query_v2")
    @patch.object(DynamoPlusRepository, "__init__")
    def test_queryCollectionByName(self, mock_index_dynamoplus_repository,
                                   mock_find):
        collection_metadata = Collection("example", "name")
        expected_query = Query(Eq("name", "example"), collection_metadata)
        mock_index_dynamoplus_repository.return_value = None
        mock_find.return_value = QueryResult([
            Model(Collection("example", "id"), {
                "name": "example",
                "id_key": "id"
            })
        ])
        collections = self.systemService.find_collections_by_example(
            collection_metadata)
        self.assertTrue(len(collections) == 1)
        self.assertEqual(collections[0].name, "example")
        self.assertEqual(call(expected_query), mock_find.call_args_list[0])

    @patch.object(DynamoPlusRepository, "query_v2")
    @patch.object(DynamoPlusRepository, "__init__")
    def test_queryIndex_by_CollectionByName(self,
                                            mock_index_dynamoplus_repository,
                                            mock_find):
        expected_query = Query(Eq("collection.name", "example"),
                               Collection("index", "uid"))
        mock_index_dynamoplus_repository.return_value = None
        mock_find.return_value = QueryResult([
            Model(
                Collection("index", "name"), {
                    "uid": "1",
                    "name": "collection.name",
                    "collection": {
                        "name": "example"
                    },
                    "conditions": ["collection.name"]
                })
        ])
        indexes, last_key = self.systemService.find_indexes_from_collection_name(
            "example")
        self.assertEqual(1, len(indexes))
        self.assertEqual(indexes[0].uid, "1")
        self.assertEqual(indexes[0].index_name, "collection.name")
        self.assertEqual(call(expected_query), mock_find.call_args_list[0])

    @patch.object(DynamoPlusRepository, "query_v2")
    @patch.object(DynamoPlusRepository, "__init__")
    def test_queryIndex_by_CollectionByName_generator(
            self, mock_index_dynamoplus_repository, mock_find):
        expected_query = Query(Eq("collection.name", "example"),
                               Collection("index", "uid"), 2)
        mock_index_dynamoplus_repository.return_value = None
        mock_find.side_effect = [
            self.fake_query_result("1", "2"),
            self.fake_query_result("2", "3"),
            self.fake_query_result("3", "4"),
            self.fake_query_result("4", "5"),
            self.fake_query_result("5"),
        ]
        indexes = self.systemService.get_indexes_from_collection_name_generator(
            "example", 2)
        uids = list(map(lambda i: i.uid, indexes))
        self.assertEqual(5, len(uids))
        self.assertEqual(["1", "2", "3", "4", "5"], uids)
        self.assertEqual(call(expected_query), mock_find.call_args_list[0])

    def fake_query_result(self, uid, next=None):
        return QueryResult([
            Model(
                Collection("index", "name"), {
                    "uid": uid,
                    "name": "collection.name",
                    "collection": {
                        "name": "example" + uid
                    },
                    "conditions": ["collection.name"]
                })
        ], next)