def test_get_testprotos(test_proto): testcase = test_proto.get firestore_api = mock.Mock(spec=["batch_get_documents", "_client"]) response = firestore.BatchGetDocumentsResponse() response.read_time = Timestamp(seconds=0, nanos=0) response.found = document.Document() response.found.fields = {} response.found.create_time = Timestamp(seconds=0, nanos=0) response.found.update_time = Timestamp(seconds=0, nanos=0) firestore_api.batch_get_documents.return_value = iter([response]) firestore_api._client._database_string = "projects/projectID/databases/(default)" client, doc = _make_client_document(firestore_api, testcase) response.found.name = doc._document_path doc.get() # No '.textprotos' for errors, field_paths. expected_request = { "database": firestore_api._client._database_string, "documents": [doc._document_path], "mask": None, "transaction": None, } firestore_api.batch_get_documents.assert_called_once_with( request=expected_request, metadata=client._rpc_metadata, )
def test_client_recursive_delete(): from google.cloud.firestore_v1.types import document from google.cloud.firestore_v1.types import firestore client = _make_default_client() client._firestore_api_internal = mock.Mock(spec=["run_query"]) collection_ref = client.collection("my_collection") results = [] for index in range(10): results.append( firestore.RunQueryResponse( document=document.Document(name=f"{collection_ref.id}/{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 bulk_writer = mock.MagicMock() bulk_writer.mock_add_spec(spec=["delete", "close"]) num_deleted = client.recursive_delete( collection_ref, bulk_writer=bulk_writer, chunk_size=3 ) assert num_deleted == len(results)
def test_basewritebatch_update(): from google.cloud.firestore_v1.types import common from google.cloud.firestore_v1.types import document from google.cloud.firestore_v1.types import write client = _make_client() batch = _make_derived_write_batch(client) assert batch._write_pbs == [] reference = client.document("cats", "cradle") field_path = "head.foot" value = u"knees toes shoulders" field_updates = {field_path: value} ret_val = batch.update(reference, field_updates) assert ret_val is None map_pb = document.MapValue(fields={"foot": _value_pb(string_value=value)}) new_write_pb = write.Write( update=document.Document( name=reference._document_path, fields={"head": _value_pb(map_value=map_pb)}, ), update_mask=common.DocumentMask(field_paths=[field_path]), current_document=common.Precondition(exists=True), ) assert batch._write_pbs == [new_write_pb]
def test_found(self): from google.cloud.firestore_v1.types import document from google.cloud._helpers import _datetime_to_pb_timestamp from google.cloud.firestore_v1.document import DocumentSnapshot now = datetime.datetime.utcnow() read_time = _datetime_to_pb_timestamp(now) delta = datetime.timedelta(seconds=100) update_time = _datetime_to_pb_timestamp(now - delta) create_time = _datetime_to_pb_timestamp(now - 2 * delta) ref_string = self._dummy_ref_string() document_pb = document.Document( name=ref_string, fields={ "foo": document.Value(double_value=1.5), "bar": document.Value(string_value=u"skillz"), }, create_time=create_time, update_time=update_time, ) response_pb = _make_batch_response(found=document_pb, read_time=read_time) reference_map = {ref_string: mock.sentinel.reference} snapshot = self._call_fut(response_pb, reference_map) self.assertIsInstance(snapshot, DocumentSnapshot) self.assertIs(snapshot._reference, mock.sentinel.reference) self.assertEqual(snapshot._data, {"foo": 1.5, "bar": u"skillz"}) self.assertTrue(snapshot._exists) self.assertEqual(snapshot.read_time.timestamp_pb(), read_time) self.assertEqual(snapshot.create_time.timestamp_pb(), create_time) self.assertEqual(snapshot.update_time.timestamp_pb(), update_time)
def test__parse_batch_get_found(): from google.cloud.firestore_v1.types import document from google.cloud._helpers import _datetime_to_pb_timestamp from google.cloud.firestore_v1.document import DocumentSnapshot from google.cloud.firestore_v1.base_client import _parse_batch_get now = datetime.datetime.utcnow() read_time = _datetime_to_pb_timestamp(now) delta = datetime.timedelta(seconds=100) update_time = _datetime_to_pb_timestamp(now - delta) create_time = _datetime_to_pb_timestamp(now - 2 * delta) ref_string = _dummy_ref_string() document_pb = document.Document( name=ref_string, fields={ "foo": document.Value(double_value=1.5), "bar": document.Value(string_value=u"skillz"), }, create_time=create_time, update_time=update_time, ) response_pb = _make_batch_response(found=document_pb, read_time=read_time) reference_map = {ref_string: mock.sentinel.reference} snapshot = _parse_batch_get(response_pb, reference_map, mock.sentinel.client) assert isinstance(snapshot, DocumentSnapshot) assert snapshot._reference is mock.sentinel.reference assert snapshot._data == {"foo": 1.5, "bar": u"skillz"} assert snapshot._exists assert snapshot.read_time.timestamp_pb() == read_time assert snapshot.create_time.timestamp_pb() == create_time assert snapshot.update_time.timestamp_pb() == update_time
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()
def _write_pb_for_create(document_path, document_data): from google.cloud.firestore_v1.types import common from google.cloud.firestore_v1.types import document from google.cloud.firestore_v1.types import write from google.cloud.firestore_v1 import _helpers return write.Write( update=document.Document(name=document_path, fields=_helpers.encode_dict(document_data)), current_document=common.Precondition(exists=False), )
def _write_pb_for_update(document_path, update_values, field_paths): from google.cloud.firestore_v1.types import common from google.cloud.firestore_v1.types import document from google.cloud.firestore_v1.types import write from google.cloud.firestore_v1 import _helpers return write.Write( update=document.Document(name=document_path, fields=_helpers.encode_dict(update_values)), update_mask=common.DocumentMask(field_paths=field_paths), current_document=common.Precondition(exists=True), )
def test_get_testprotos(test_proto): testcase = test_proto.get firestore_api = mock.Mock(spec=["get_document"]) response = document.Document() firestore_api.get_document.return_value = response client, doc = _make_client_document(firestore_api, testcase) doc.get() # No '.textprotos' for errors, field_paths. firestore_api.get_document.assert_called_once_with( doc._document_path, mask=None, transaction=None, metadata=client._rpc_metadata, )
def get_update_pb( self, document_path, exists=None, allow_empty_mask=False ) -> types.write.Write: if exists is not None: current_document = common.Precondition(exists=exists) else: current_document = None update_pb = write.Write( update=document.Document( name=document_path, fields=encode_dict(self.set_fields) ), update_mask=self._get_update_mask(allow_empty_mask), current_document=current_document, ) return update_pb
def test_get_testprotos(test_proto): testcase = test_proto.get firestore_api = mock.Mock(spec=["get_document"]) response = document.Document() firestore_api.get_document.return_value = response client, doc = _make_client_document(firestore_api, testcase) doc.get() # No '.textprotos' for errors, field_paths. expected_request = { "name": doc._document_path, "mask": None, "transaction": None, } firestore_api.get_document.assert_called_once_with( request=expected_request, metadata=client._rpc_metadata, )
def test_set(self): from google.cloud.firestore_v1.types import document from google.cloud.firestore_v1.types import write client = _make_client() batch = self._make_one(client) self.assertEqual(batch._write_pbs, []) reference = client.document("another", "one") field = "zapzap" value = u"meadows and flowers" document_data = {field: value} ret_val = batch.set(reference, document_data) self.assertIsNone(ret_val) new_write_pb = write.Write(update=document.Document( name=reference._document_path, fields={field: _value_pb(string_value=value)}, )) self.assertEqual(batch._write_pbs, [new_write_pb])
def _write_pb_for_set(document_path, document_data, merge): from google.cloud.firestore_v1.types import common from google.cloud.firestore_v1.types import document from google.cloud.firestore_v1.types import write from google.cloud.firestore_v1 import _helpers write_pbs = write.Write(update=document.Document( name=document_path, fields=_helpers.encode_dict(document_data))) if merge: field_paths = [ field_path for field_path, value in _helpers.extract_fields( document_data, _helpers.FieldPath()) ] field_paths = [ field_path.to_api_repr() for field_path in sorted(field_paths) ] mask = common.DocumentMask(field_paths=sorted(field_paths)) write_pbs._pb.update_mask.CopyFrom(mask._pb) return write_pbs
def _doc_get_info(ref_string, values): from google.cloud.firestore_v1.types import document from google.cloud._helpers import _datetime_to_pb_timestamp from google.cloud.firestore_v1 import _helpers now = datetime.datetime.utcnow() read_time = _datetime_to_pb_timestamp(now) delta = datetime.timedelta(seconds=100) update_time = _datetime_to_pb_timestamp(now - delta) create_time = _datetime_to_pb_timestamp(now - 2 * delta) document_pb = document.Document( name=ref_string, fields=_helpers.encode_dict(values), create_time=create_time, update_time=update_time, ) return document_pb, read_time
def test_basewritebatch_set(): from google.cloud.firestore_v1.types import document from google.cloud.firestore_v1.types import write client = _make_client() batch = _make_derived_write_batch(client) assert batch._write_pbs == [] reference = client.document("another", "one") field = "zapzap" value = u"meadows and flowers" document_data = {field: value} ret_val = batch.set(reference, document_data) assert ret_val is None new_write_pb = write.Write( update=document.Document( name=reference._document_path, fields={field: _value_pb(string_value=value)}, ) ) assert batch._write_pbs == [new_write_pb]
async def test_asynccollectionreference_chunkify(): from google.cloud.firestore_v1.types import document from google.cloud.firestore_v1.types import firestore client = _make_client() col = client.collection("my-collection") client._firestore_api_internal = mock.Mock(spec=["run_query"]) results = [] for index in range(10): name = ( f"projects/project-project/databases/(default)/" f"documents/my-collection/{index}" ) results.append( firestore.RunQueryResponse(document=document.Document(name=name),), ) chunks = [ results[:3], results[3:6], results[6:9], results[9:], ] async def _get_chunk(*args, **kwargs): return AsyncIter(chunks.pop(0)) client._firestore_api_internal.run_query.side_effect = _get_chunk counter = 0 expected_lengths = [3, 3, 3, 1] async for chunk in col._chunkify(3): msg = f"Expected chunk of length {expected_lengths[counter]} at index {counter}. Saw {len(chunk)}." assert len(chunk) == expected_lengths[counter], msg counter += 1
def test_basewritebatch_create(): from google.cloud.firestore_v1.types import common from google.cloud.firestore_v1.types import document from google.cloud.firestore_v1.types import write client = _make_client() batch = _make_derived_write_batch(client) assert batch._write_pbs == [] reference = client.document("this", "one") document_data = {"a": 10, "b": 2.5} ret_val = batch.create(reference, document_data) assert ret_val is None new_write_pb = write.Write( update=document.Document( name=reference._document_path, fields={ "a": _value_pb(integer_value=document_data["a"]), "b": _value_pb(double_value=document_data["b"]), }, ), current_document=common.Precondition(exists=False), ) assert batch._write_pbs == [new_write_pb]
def test_create(self): from google.cloud.firestore_v1.types import common from google.cloud.firestore_v1.types import document from google.cloud.firestore_v1.types import write client = _make_client() batch = self._make_one(client) self.assertEqual(batch._write_pbs, []) reference = client.document("this", "one") document_data = {"a": 10, "b": 2.5} ret_val = batch.create(reference, document_data) self.assertIsNone(ret_val) new_write_pb = write.Write( update=document.Document( name=reference._document_path, fields={ "a": _value_pb(integer_value=document_data["a"]), "b": _value_pb(double_value=document_data["b"]), }, ), current_document=common.Precondition(exists=False), ) self.assertEqual(batch._write_pbs, [new_write_pb])
def test_client_recursive_delete_from_document(): from google.cloud.firestore_v1.types import document from google.cloud.firestore_v1.types import firestore client = _make_default_client() client._firestore_api_internal = mock.Mock( spec=["run_query", "list_collection_ids"] ) collection_ref = client.collection("my_collection") collection_1_id: str = "collection_1_id" collection_2_id: str = "collection_2_id" parent_doc = collection_ref.document("parent") collection_1_results = [] collection_2_results = [] for index in range(10): collection_1_results.append( firestore.RunQueryResponse( document=document.Document(name=f"{collection_1_id}/{index}"), ), ) collection_2_results.append( firestore.RunQueryResponse( document=document.Document(name=f"{collection_2_id}/{index}"), ), ) col_1_chunks = [ collection_1_results[:3], collection_1_results[3:6], collection_1_results[6:9], collection_1_results[9:], ] col_2_chunks = [ collection_2_results[:3], collection_2_results[3:6], collection_2_results[6:9], collection_2_results[9:], ] def _get_chunk(*args, **kwargs): start_at = ( kwargs["request"]["structured_query"].start_at.values[0].reference_value ) if collection_1_id in start_at: return iter(col_1_chunks.pop(0)) return iter(col_2_chunks.pop(0)) client._firestore_api_internal.run_query.side_effect = _get_chunk client._firestore_api_internal.list_collection_ids.return_value = [ collection_1_id, collection_2_id, ] bulk_writer = mock.MagicMock() bulk_writer.mock_add_spec(spec=["delete", "close"]) num_deleted = client.recursive_delete( parent_doc, bulk_writer=bulk_writer, chunk_size=3 ) expected_len = len(collection_1_results) + len(collection_2_results) + 1 assert num_deleted == expected_len