Beispiel #1
0
    def test_add_document_with_different_read_times(self):
        bundle = FirestoreBundle("test")
        doc = _test_helpers.build_document_snapshot(
            client=_test_helpers.make_client(),
            data={"version": 1},
            read_time=_test_helpers.build_test_timestamp(second=1),
        )
        # Create another reference to the same document, but with new
        # data and a more recent `read_time`
        doc_refreshed = _test_helpers.build_document_snapshot(
            client=_test_helpers.make_client(),
            data={"version": 2},
            read_time=_test_helpers.build_test_timestamp(second=2),
        )

        bundle.add_document(doc)
        self.assertEqual(
            bundle.documents[self.doc_key].snapshot._data,
            {"version": 1},
        )
        bundle.add_document(doc_refreshed)
        self.assertEqual(
            bundle.documents[self.doc_key].snapshot._data,
            {"version": 2},
        )
    def test_chunkify(self):
        client = _test_helpers.make_client()
        col = client.collection("my-collection")

        client._firestore_api_internal = mock.Mock(spec=["run_query"])

        results = []
        for index in range(10):
            results.append(
                RunQueryResponse(document=Document(
                    name=
                    f"projects/project-project/databases/(default)/documents/my-collection/{index}",
                ), ), )

        chunks = [
            results[:3],
            results[3:6],
            results[6:9],
            results[9:],
        ]

        def _get_chunk(*args, **kwargs):
            return iter(chunks.pop(0))

        client._firestore_api_internal.run_query.side_effect = _get_chunk

        counter = 0
        expected_lengths = [3, 3, 3, 1]
        for chunk in col._chunkify(3):
            msg = f"Expected chunk of length {expected_lengths[counter]} at index {counter}. Saw {len(chunk)}."
            self.assertEqual(len(chunk), expected_lengths[counter], msg)
            counter += 1
Beispiel #3
0
    def test_invalid_json(self, fnc):
        from google.cloud.firestore_v1 import _helpers

        client = _test_helpers.make_client()
        fnc.return_value = iter([{}])
        with pytest.raises(ValueError):
            _helpers.deserialize_bundle("does not matter", client)
Beispiel #4
0
    def test_not_metadata_first(self, fnc):
        from google.cloud.firestore_v1 import _helpers

        client = _test_helpers.make_client()
        fnc.return_value = iter([{"document": {}}])
        with pytest.raises(ValueError):
            _helpers.deserialize_bundle("does not matter", client)
Beispiel #5
0
    def _list_documents_helper(self, page_size=None, retry=None, timeout=None):
        from google.cloud.firestore_v1 import _helpers as _fs_v1_helpers
        from google.api_core.page_iterator import Iterator
        from google.api_core.page_iterator import Page
        from google.cloud.firestore_v1.document import DocumentReference
        from google.cloud.firestore_v1.services.firestore.client import FirestoreClient
        from google.cloud.firestore_v1.types.document import Document

        class _Iterator(Iterator):
            def __init__(self, pages):
                super(_Iterator, self).__init__(client=None)
                self._pages = pages

            def _next_page(self):
                if self._pages:
                    page, self._pages = self._pages[0], self._pages[1:]
                    return Page(self, page, self.item_to_value)

        client = _test_helpers.make_client()
        template = client._database_string + "/documents/{}"
        document_ids = ["doc-1", "doc-2"]
        documents = [
            Document(name=template.format(document_id))
            for document_id in document_ids
        ]
        iterator = _Iterator(pages=[documents])
        api_client = mock.create_autospec(FirestoreClient)
        api_client.list_documents.return_value = iterator
        client._firestore_api_internal = api_client
        collection = self._make_one("collection", client=client)
        kwargs = _fs_v1_helpers.make_retry_timeout_kwargs(retry, timeout)

        if page_size is not None:
            documents = list(
                collection.list_documents(page_size=page_size, **kwargs))
        else:
            documents = list(collection.list_documents(**kwargs))

        # Verify the response and the mocks.
        self.assertEqual(len(documents), len(document_ids))
        for document, document_id in zip(documents, document_ids):
            self.assertIsInstance(document, DocumentReference)
            self.assertEqual(document.parent, collection)
            self.assertEqual(document.id, document_id)

        parent, _ = collection._parent_info()
        api_client.list_documents.assert_called_once_with(
            request={
                "parent": parent,
                "collection_id": collection.id,
                "page_size": page_size,
                "show_missing": True,
                "mask": {
                    "field_paths": None
                },
            },
            metadata=client._rpc_metadata,
            **kwargs,
        )
Beispiel #6
0
    def test_add_document(self):
        from google.cloud.firestore_bundle import FirestoreBundle

        bundle = FirestoreBundle("test")
        doc = _test_helpers.build_document_snapshot(
            client=_test_helpers.make_client())
        bundle.add_document(doc)
        assert bundle.documents[self.doc_key].snapshot == doc
Beispiel #7
0
 def test_not_actually_a_bundle_at_all(self):
     client = _test_helpers.make_client()
     self.assertRaises(
         ValueError,
         _helpers.deserialize_bundle,
         "{}",
         client,
     )
Beispiel #8
0
    def test_invalid_bundle_start(self, fnc, _):
        from google.cloud.firestore_v1 import _helpers

        client = _test_helpers.make_client()
        # invalid bc first element must be of key `metadata`
        fnc.return_value = [{"document": {}}]
        with pytest.raises(ValueError):
            _helpers.deserialize_bundle("does not matter", client)
Beispiel #9
0
    def test_invalid_bundle_element_type(self, fnc, _):
        from google.cloud.firestore_v1 import _helpers

        client = _test_helpers.make_client()
        # invalid bc `wtfisthis?` is obviously invalid
        fnc.return_value = [{"metadata": {"id": "asdf"}}, {"wtfisthis?": {}}]
        with pytest.raises(ValueError):
            _helpers.deserialize_bundle("does not matter", client)
Beispiel #10
0
    def test_invalid_bundle(self, fnc, _):
        from google.cloud.firestore_v1 import _helpers

        client = _test_helpers.make_client()
        # invalid bc `document` must follow `document_metadata`
        fnc.return_value = [{"metadata": {"id": "asdf"}}, {"document": {}}]
        with pytest.raises(ValueError):
            _helpers.deserialize_bundle("does not matter", client)
def test_add_auto_assigned():
    from google.cloud.firestore_v1.types import document
    from google.cloud.firestore_v1.document import DocumentReference
    from google.cloud.firestore_v1 import SERVER_TIMESTAMP
    from google.cloud.firestore_v1._helpers import pbs_for_create
    from tests.unit.v1 import _test_helpers

    # Create a minimal fake GAPIC add attach it to a real client.
    firestore_api = mock.Mock(spec=["create_document", "commit"])
    write_result = mock.Mock(
        update_time=mock.sentinel.update_time, spec=["update_time"]
    )

    commit_response = mock.Mock(
        write_results=[write_result],
        spec=["write_results", "commit_time"],
        commit_time=mock.sentinel.commit_time,
    )

    firestore_api.commit.return_value = commit_response
    create_doc_response = document.Document()
    firestore_api.create_document.return_value = create_doc_response
    client = _test_helpers.make_client()
    client._firestore_api_internal = firestore_api

    # Actually make a collection.
    collection = _make_collection_reference(
        "grand-parent", "parent", "child", client=client
    )

    # Actually call add() on our collection; include a transform to make
    # sure transforms during adds work.
    document_data = {"been": "here", "now": SERVER_TIMESTAMP}

    patch = mock.patch("google.cloud.firestore_v1.base_collection._auto_id")
    random_doc_id = "DEADBEEF"
    with patch as patched:
        patched.return_value = random_doc_id
        update_time, document_ref = collection.add(document_data)

    # Verify the response and the mocks.
    assert update_time is mock.sentinel.update_time
    assert isinstance(document_ref, DocumentReference)
    assert document_ref._client is client
    expected_path = collection._path + (random_doc_id,)
    assert document_ref._path == expected_path

    write_pbs = pbs_for_create(document_ref._document_path, document_data)
    firestore_api.commit.assert_called_once_with(
        request={
            "database": client._database_string,
            "writes": write_pbs,
            "transaction": None,
        },
        metadata=client._rpc_metadata,
    )
    # Since we generate the ID locally, we don't call 'create_document'.
    firestore_api.create_document.assert_not_called()
Beispiel #12
0
 def test_not_metadata_first(self, fnc):
     client = _test_helpers.make_client()
     fnc.return_value = iter([{"document": {}}])
     self.assertRaises(
         ValueError,
         _helpers.deserialize_bundle,
         "does not matter",
         client,
     )
Beispiel #13
0
 def test_invalid_json(self, fnc):
     client = _test_helpers.make_client()
     fnc.return_value = iter([{}])
     self.assertRaises(
         ValueError,
         _helpers.deserialize_bundle,
         "does not matter",
         client,
     )
Beispiel #14
0
    def test_add_invalid_bundle_element_type(self):
        from google.cloud.firestore_bundle import FirestoreBundle
        from google.cloud.firestore_bundle import BundleElement

        client = _test_helpers.make_client()
        bundle = FirestoreBundle("asdf")
        with pytest.raises(ValueError):
            bundle._add_bundle_element(BundleElement(),
                                       client=client,
                                       type="asdf")
Beispiel #15
0
 def test_invalid_bundle_element_type(self, fnc, _):
     client = _test_helpers.make_client()
     # invalid bc `wtfisthis?` is obviously invalid
     fnc.return_value = [{"metadata": {"id": "asdf"}}, {"wtfisthis?": {}}]
     self.assertRaises(
         ValueError,
         _helpers.deserialize_bundle,
         "does not matter",
         client,
     )
Beispiel #16
0
 def test_add_invalid_bundle_element_type(self):
     client = _test_helpers.make_client()
     bundle = FirestoreBundle("asdf")
     self.assertRaises(
         ValueError,
         bundle._add_bundle_element,
         BundleElement(),
         client=client,
         type="asdf",
     )
Beispiel #17
0
 def test_invalid_bundle(self, fnc, _):
     client = _test_helpers.make_client()
     # invalid bc `document` must follow `document_metadata`
     fnc.return_value = [{"metadata": {"id": "asdf"}}, {"document": {}}]
     self.assertRaises(
         ValueError,
         _helpers.deserialize_bundle,
         "does not matter",
         client,
     )
Beispiel #18
0
 def test_invalid_bundle_start(self, fnc, _):
     client = _test_helpers.make_client()
     # invalid bc first element must be of key `metadata`
     fnc.return_value = [{"document": {}}]
     self.assertRaises(
         ValueError,
         _helpers.deserialize_bundle,
         "does not matter",
         client,
     )
Beispiel #19
0
    def test_add_older_document(self):
        bundle = FirestoreBundle("test")
        new_doc = _test_helpers.build_document_snapshot(
            data={"version": 2},
            client=_test_helpers.make_client(),
            read_time=Timestamp(seconds=1, nanos=2),
        )
        bundle.add_document(new_doc)
        self.assertEqual(
            bundle.documents[self.doc_key].snapshot._data["version"], 2)

        # Builds the same ID by default
        old_doc = _test_helpers.build_document_snapshot(
            data={"version": 1},
            client=_test_helpers.make_client(),
            read_time=Timestamp(seconds=1, nanos=1),
        )
        bundle.add_document(old_doc)
        self.assertEqual(
            bundle.documents[self.doc_key].snapshot._data["version"], 2)
Beispiel #20
0
    def test_add_older_document(self):
        from google.protobuf.timestamp_pb2 import Timestamp  # type: ignore
        from google.cloud.firestore_bundle import FirestoreBundle

        bundle = FirestoreBundle("test")
        new_doc = _test_helpers.build_document_snapshot(
            data={"version": 2},
            client=_test_helpers.make_client(),
            read_time=Timestamp(seconds=1, nanos=2),
        )
        bundle.add_document(new_doc)
        assert bundle.documents[self.doc_key].snapshot._data["version"] == 2

        # Builds the same ID by default
        old_doc = _test_helpers.build_document_snapshot(
            data={"version": 1},
            client=_test_helpers.make_client(),
            read_time=Timestamp(seconds=1, nanos=1),
        )
        bundle.add_document(old_doc)
        assert bundle.documents[self.doc_key].snapshot._data["version"] == 2
Beispiel #21
0
 def test_unexpected_termination(self, fnc, _):
     client = _test_helpers.make_client()
     # invalid bc `document_metadata` must be followed by a `document`
     fnc.return_value = [{
         "metadata": {
             "id": "asdf"
         }
     }, {
         "documentMetadata": {}
     }]
     self.assertRaises(
         ValueError,
         _helpers.deserialize_bundle,
         "does not matter",
         client,
     )
Beispiel #22
0
 def test_valid_passes(self, fnc, _):
     client = _test_helpers.make_client()
     fnc.return_value = [
         {
             "metadata": {
                 "id": "asdf"
             }
         },
         {
             "documentMetadata": {}
         },
         {
             "document": {}
         },
     ]
     _helpers.deserialize_bundle("does not matter", client)
def _add_helper(retry=None, timeout=None):
    from google.cloud.firestore_v1.document import DocumentReference
    from google.cloud.firestore_v1 import _helpers as _fs_v1_helpers
    from tests.unit.v1 import _test_helpers

    # Create a minimal fake GAPIC with a dummy response.
    firestore_api = mock.Mock(spec=["commit"])
    write_result = mock.Mock(
        update_time=mock.sentinel.update_time, spec=["update_time"]
    )
    commit_response = mock.Mock(
        write_results=[write_result],
        spec=["write_results", "commit_time"],
        commit_time=mock.sentinel.commit_time,
    )
    firestore_api.commit.return_value = commit_response

    # Attach the fake GAPIC to a real client.
    client = _test_helpers.make_client()
    client._firestore_api_internal = firestore_api

    # Actually make a collection and call add().
    collection = _make_collection_reference("parent", client=client)
    document_data = {"zorp": 208.75, "i-did-not": b"know that"}
    doc_id = "child"

    kwargs = _fs_v1_helpers.make_retry_timeout_kwargs(retry, timeout)
    update_time, document_ref = collection.add(
        document_data, document_id=doc_id, **kwargs
    )

    # Verify the response and the mocks.
    assert update_time is mock.sentinel.update_time
    assert isinstance(document_ref, DocumentReference)
    assert document_ref._client is client
    assert document_ref._path == (collection.id, doc_id)

    write_pb = _write_pb_for_create(document_ref._document_path, document_data)
    firestore_api.commit.assert_called_once_with(
        request={
            "database": client._database_string,
            "writes": [write_pb],
            "transaction": None,
        },
        metadata=client._rpc_metadata,
        **kwargs,
    )
Beispiel #24
0
    def test_valid_passes(self, fnc, _):
        from google.cloud.firestore_v1 import _helpers

        client = _test_helpers.make_client()
        fnc.return_value = [
            {
                "metadata": {
                    "id": "asdf"
                }
            },
            {
                "documentMetadata": {}
            },
            {
                "document": {}
            },
        ]
        _helpers.deserialize_bundle("does not matter", client)
Beispiel #25
0
    def test_deserialize_from_seconds_nanos(self):
        """Some SDKs (Node) serialize Timestamp values to
        '{"seconds": 123, "nanos": 456}', instead of an ISO-formatted string.
        This tests deserialization from that format."""

        client = _test_helpers.make_client(project_name="fir-bundles-test")

        _serialized: str = (
            '139{"metadata":{"id":"test-bundle","createTime":' +
            '{"seconds":"1616434660","nanos":913764000},"version":1,"totalDocuments"'
            +
            ':1,"totalBytes":"829"}}224{"namedQuery":{"name":"self","bundledQuery":'
            +
            '{"parent":"projects/fir-bundles-test/databases/(default)/documents",'
            +
            '"structuredQuery":{"from":[{"collectionId":"bundles"}]}},"readTime":'
            +
            '{"seconds":"1616434660","nanos":913764000}}}194{"documentMetadata":'
            +
            '{"name":"projects/fir-bundles-test/databases/(default)/documents/'
            +
            'bundles/test-bundle","readTime":{"seconds":"1616434660","nanos":'
            +
            '913764000},"exists":true,"queries":["self"]}}402{"document":{"name":'
            +
            '"projects/fir-bundles-test/databases/(default)/documents/bundles/'
            + 'test-bundle","fields":{"clientCache":{"stringValue":"1200"},' +
            '"serverCache":{"stringValue":"600"},"queries":{"mapValue":{"fields":'
            +
            '{"self":{"mapValue":{"fields":{"collection":{"stringValue":"bundles"'
            +
            '}}}}}}}},"createTime":{"seconds":"1615488796","nanos":163327000},'
            + '"updateTime":{"seconds":"1615492486","nanos":34157000}}}')

        self.assertRaises(
            ValueError,
            _helpers.deserialize_bundle,
            _serialized,
            client=client,
        )
def test_chunkify():
    from google.cloud.firestore_v1.types.document import Document
    from google.cloud.firestore_v1.types.firestore import RunQueryResponse
    from tests.unit.v1 import _test_helpers

    client = _test_helpers.make_client()
    col = client.collection("my-collection")

    client._firestore_api_internal = mock.Mock(spec=["run_query"])

    results = []
    for index in range(10):
        results.append(
            RunQueryResponse(
                document=Document(
                    name=f"projects/project-project/databases/(default)/documents/my-collection/{index}",
                ),
            ),
        )

    chunks = [
        results[:3],
        results[3:6],
        results[6:9],
        results[9:],
    ]

    def _get_chunk(*args, **kwargs):
        return iter(chunks.pop(0))

    client._firestore_api_internal.run_query.side_effect = _get_chunk

    counter = 0
    expected_lengths = [3, 3, 3, 1]
    for chunk in col._chunkify(3):
        assert len(chunk) == expected_lengths[counter]
        counter += 1
Beispiel #27
0
 def get_client():
     return _test_helpers.make_client()
Beispiel #28
0
    def test_not_actually_a_bundle_at_all(self):
        from google.cloud.firestore_v1 import _helpers

        client = _test_helpers.make_client()
        with pytest.raises(ValueError):
            _helpers.deserialize_bundle("{}", client)
Beispiel #29
0
 def test_add_document(self):
     bundle = FirestoreBundle("test")
     doc = _test_helpers.build_document_snapshot(
         client=_test_helpers.make_client())
     bundle.add_document(doc)
     self.assertEqual(bundle.documents[self.doc_key].snapshot, doc)