diff --git a/google-cloud-firestore/pom.xml b/google-cloud-firestore/pom.xml index f2ca4fce0..5a52eceb8 100644 --- a/google-cloud-firestore/pom.xml +++ b/google-cloud-firestore/pom.xml @@ -162,7 +162,7 @@ com.google.cloud google-cloud-conformance-tests - 0.0.10 + 0.0.11 test diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentTransform.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentTransform.java index a90b0ec5e..d175919eb 100644 --- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentTransform.java +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentTransform.java @@ -17,7 +17,7 @@ package com.google.cloud.firestore; import com.google.firestore.v1.DocumentTransform.FieldTransform; -import com.google.firestore.v1.Write; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; @@ -30,12 +30,9 @@ */ final class DocumentTransform { - private DocumentReference documentReference; private final SortedMap transforms; // Sorted for testing. - private DocumentTransform( - DocumentReference documentReference, SortedMap transforms) { - this.documentReference = documentReference; + private DocumentTransform(SortedMap transforms) { this.transforms = transforms; } @@ -61,7 +58,7 @@ static DocumentTransform fromFieldPathMap( } } - return new DocumentTransform(documentReference, transforms); + return new DocumentTransform(transforms); } private static SortedMap extractFromMap( @@ -116,11 +113,7 @@ Set getFields() { return Collections.unmodifiableSet(transforms.keySet()); } - Write.Builder toPb() { - Write.Builder write = Write.newBuilder(); - com.google.firestore.v1.DocumentTransform.Builder transform = write.getTransformBuilder(); - transform.addAllFieldTransforms(transforms.values()); - transform.setDocument(documentReference.getName()); - return write; + Collection toPb() { + return transforms.values(); } } diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/UpdateBuilder.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/UpdateBuilder.java index 599c0ce53..c80916099 100644 --- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/UpdateBuilder.java +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/UpdateBuilder.java @@ -31,7 +31,6 @@ import io.opencensus.trace.Tracing; import java.util.ArrayList; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -46,19 +45,13 @@ */ public abstract class UpdateBuilder { - private static class Mutation { - Write.Builder document; - Write.Builder transform; - com.google.firestore.v1.Precondition precondition; - } - final FirestoreImpl firestore; - private final List mutations; + private final List writes; private boolean committed; UpdateBuilder(FirestoreImpl firestore) { this.firestore = firestore; - this.mutations = new ArrayList<>(); + this.writes = new ArrayList<>(); } /** @@ -116,6 +109,7 @@ public T create( private T performCreate( @Nonnull DocumentReference documentReference, @Nonnull Map fields) { + verifyNotCommitted(); DocumentSnapshot documentSnapshot = DocumentSnapshot.fromObject( firestore, documentReference, fields, UserDataConverter.NO_DELETES); @@ -123,27 +117,21 @@ private T performCreate( DocumentTransform.fromFieldPathMap( documentReference, convertToFieldPaths(fields, /* splitOnDots= */ false)); - Mutation mutation = addMutation(); - mutation.precondition = Precondition.exists(false).toPb(); - - if (!documentSnapshot.isEmpty() || documentTransform.isEmpty()) { - mutation.document = documentSnapshot.toPb(); - } + Write.Builder write = documentSnapshot.toPb(); + write.setCurrentDocument(Precondition.exists(false).toPb()); if (!documentTransform.isEmpty()) { - mutation.transform = documentTransform.toPb(); + write.addAllUpdateTransforms(documentTransform.toPb()); } + writes.add(write); + return (T) this; } - /** Adds a new mutation to the batch. */ - private Mutation addMutation() { + private void verifyNotCommitted() { Preconditions.checkState( !committed, "Cannot modify a WriteBatch that has already been committed."); - Mutation mutation = new Mutation(); - mutations.add(mutation); - return mutation; } /** @@ -233,6 +221,7 @@ private T performSet( @Nonnull DocumentReference documentReference, @Nonnull Map fields, @Nonnull SetOptions options) { + verifyNotCommitted(); Map documentData; if (options.getFieldMask() != null) { @@ -248,31 +237,25 @@ private T performSet( DocumentTransform documentTransform = DocumentTransform.fromFieldPathMap(documentReference, documentData); - if (options.isMerge()) { - if (options.getFieldMask() != null) { - List fieldMask = new ArrayList<>(options.getFieldMask()); - fieldMask.removeAll(documentTransform.getFields()); - documentMask = new FieldMask(fieldMask); - } else { - documentMask = FieldMask.fromObject(fields); - } + if (options.getFieldMask() != null) { + List fieldMask = new ArrayList<>(options.getFieldMask()); + fieldMask.removeAll(documentTransform.getFields()); + documentMask = new FieldMask(fieldMask); + } else if (options.isMerge()) { + documentMask = FieldMask.fromObject(fields); } - Mutation mutation = addMutation(); - - boolean hasDocumentData = !documentSnapshot.isEmpty() || !documentMask.isEmpty(); - - if (!options.isMerge()) { - mutation.document = documentSnapshot.toPb(); - } else if (hasDocumentData || documentTransform.isEmpty()) { - mutation.document = documentSnapshot.toPb(); - mutation.document.setUpdateMask(documentMask.toPb()); + Write.Builder write = documentSnapshot.toPb(); + if (!documentTransform.isEmpty()) { + write.addAllUpdateTransforms(documentTransform.toPb()); } - if (!documentTransform.isEmpty()) { - mutation.transform = documentTransform.toPb(); + if (options.isMerge() || options.getFieldMask() != null) { + write.setUpdateMask(documentMask.toPb()); } + writes.add(write); + return (T) this; } @@ -507,6 +490,7 @@ private T performUpdate( @Nonnull DocumentReference documentReference, @Nonnull final Map fields, @Nonnull Precondition precondition) { + verifyNotCommitted(); Preconditions.checkArgument(!fields.isEmpty(), "Data for update() cannot be empty."); Map deconstructedMap = expandObject(fields); @@ -532,17 +516,14 @@ public boolean allowTransform() { fieldPaths.removeAll(documentTransform.getFields()); FieldMask fieldMask = new FieldMask(fieldPaths); - Mutation mutation = addMutation(); - mutation.precondition = precondition.toPb(); - - if (!documentSnapshot.isEmpty() || !fieldMask.isEmpty()) { - mutation.document = documentSnapshot.toPb(); - mutation.document.setUpdateMask(fieldMask.toPb()); - } + Write.Builder write = documentSnapshot.toPb(); + write.setCurrentDocument(precondition.toPb()); + write.setUpdateMask(fieldMask.toPb()); if (!documentTransform.isEmpty()) { - mutation.transform = documentTransform.toPb(); + write.addAllUpdateTransforms(documentTransform.toPb()); } + writes.add(write); return (T) this; } @@ -573,12 +554,13 @@ public T delete(@Nonnull DocumentReference documentReference) { private T performDelete( @Nonnull DocumentReference documentReference, @Nonnull Precondition precondition) { - Mutation mutation = addMutation(); - mutation.document = Write.newBuilder().setDelete(documentReference.getName()); + verifyNotCommitted(); + Write.Builder write = Write.newBuilder().setDelete(documentReference.getName()); if (!precondition.isEmpty()) { - mutation.precondition = precondition.toPb(); + write.setCurrentDocument(precondition.toPb()); } + writes.add(write); return (T) this; } @@ -589,28 +571,13 @@ ApiFuture> commit(@Nullable ByteString transactionId) { .getCurrentSpan() .addAnnotation( "CloudFirestore.Commit", - ImmutableMap.of("numDocuments", AttributeValue.longAttributeValue(mutations.size()))); + ImmutableMap.of("numDocuments", AttributeValue.longAttributeValue(writes.size()))); final CommitRequest.Builder request = CommitRequest.newBuilder(); request.setDatabase(firestore.getDatabaseName()); - for (Mutation mutation : mutations) { - Preconditions.checkState( - mutation.document != null || mutation.transform != null, - "Either a write or transform must be set"); - - if (mutation.precondition != null) { - (mutation.document != null ? mutation.document : mutation.transform) - .setCurrentDocument(mutation.precondition); - } - - if (mutation.document != null) { - request.addWrites(mutation.document); - } - - if (mutation.transform != null) { - request.addWrites(mutation.transform); - } + for (Write.Builder write : writes) { + request.addWrites(write); } if (transactionId != null) { @@ -632,29 +599,8 @@ public List apply(CommitResponse commitResponse) { List result = new ArrayList<>(); - Preconditions.checkState( - request.getWritesCount() == writeResults.size(), - "Expected one write result per operation, but got %s results for %s operations.", - writeResults.size(), - request.getWritesCount()); - - Iterator mutationIterator = mutations.iterator(); - Iterator responseIterator = - writeResults.iterator(); - - while (mutationIterator.hasNext()) { - Mutation mutation = mutationIterator.next(); - - // Don't return both write results for a write that contains a transform, as the fact - // that we have to split one write operation into two distinct write requests is an - // implementation detail. - if (mutation.document != null && mutation.transform != null) { - // The document transform is always sent last and produces the latest update time. - responseIterator.next(); - } - - result.add( - WriteResult.fromProto(responseIterator.next(), commitResponse.getCommitTime())); + for (com.google.firestore.v1.WriteResult writeResult : writeResults) { + result.add(WriteResult.fromProto(writeResult, commitResponse.getCommitTime())); } return result; @@ -665,11 +611,11 @@ public List apply(CommitResponse commitResponse) { /** Checks whether any updates have been queued. */ boolean isEmpty() { - return mutations.isEmpty(); + return writes.isEmpty(); } - /** Get the number of mutations. */ + /** Get the number of writes. */ public int getMutationsSize() { - return mutations.size(); + return writes.size(); } } diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/DocumentReferenceTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/DocumentReferenceTest.java index 151569776..54be303b3 100644 --- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/DocumentReferenceTest.java +++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/DocumentReferenceTest.java @@ -20,7 +20,6 @@ import static com.google.cloud.firestore.LocalFirestoreHelper.ALL_SUPPORTED_TYPES_OBJECT; import static com.google.cloud.firestore.LocalFirestoreHelper.ALL_SUPPORTED_TYPES_PROTO; import static com.google.cloud.firestore.LocalFirestoreHelper.BLOB; -import static com.google.cloud.firestore.LocalFirestoreHelper.CREATE_PRECONDITION; import static com.google.cloud.firestore.LocalFirestoreHelper.DATE; import static com.google.cloud.firestore.LocalFirestoreHelper.DOCUMENT_NAME; import static com.google.cloud.firestore.LocalFirestoreHelper.DOCUMENT_PATH; @@ -28,7 +27,6 @@ import static com.google.cloud.firestore.LocalFirestoreHelper.GEO_POINT; import static com.google.cloud.firestore.LocalFirestoreHelper.NESTED_CLASS_OBJECT; import static com.google.cloud.firestore.LocalFirestoreHelper.SERVER_TIMESTAMP_PROTO; -import static com.google.cloud.firestore.LocalFirestoreHelper.SERVER_TIMESTAMP_TRANSFORM; import static com.google.cloud.firestore.LocalFirestoreHelper.SINGLE_DELETE_COMMIT_RESPONSE; import static com.google.cloud.firestore.LocalFirestoreHelper.SINGLE_FIELD_MAP; import static com.google.cloud.firestore.LocalFirestoreHelper.SINGLE_FIELD_OBJECT; @@ -406,8 +404,8 @@ public void createWithServerTimestamp() throws Exception { CommitRequest create = commit( - transform( - CREATE_PRECONDITION, "foo", serverTimestamp(), "inner.bar", serverTimestamp())); + create(Collections.emptyMap()), + transform("foo", serverTimestamp(), "inner.bar", serverTimestamp())); List commitRequests = commitCapture.getAllValues(); assertCommitEquals(create, commitRequests.get(0)); @@ -424,7 +422,10 @@ public void setWithServerTimestamp() throws Exception { documentReference.set(LocalFirestoreHelper.SERVER_TIMESTAMP_MAP).get(); documentReference.set(LocalFirestoreHelper.SERVER_TIMESTAMP_OBJECT).get(); - CommitRequest set = commit(set(SERVER_TIMESTAMP_PROTO), SERVER_TIMESTAMP_TRANSFORM); + CommitRequest set = + commit( + set(SERVER_TIMESTAMP_PROTO), + transform("foo", serverTimestamp(), "inner.bar", serverTimestamp())); List commitRequests = commitCapture.getAllValues(); assertCommitEquals(set, commitRequests.get(0)); @@ -443,7 +444,7 @@ public void updateWithServerTimestamp() throws Exception { CommitRequest update = commit( update(Collections.emptyMap(), Collections.singletonList("inner")), - SERVER_TIMESTAMP_TRANSFORM); + transform("foo", serverTimestamp(), "inner.bar", serverTimestamp())); assertCommitEquals(update, commitCapture.getValue()); @@ -452,8 +453,11 @@ public void updateWithServerTimestamp() throws Exception { update = commit( - transform( - UPDATE_PRECONDITION, "foo", serverTimestamp(), "inner.bar", serverTimestamp())); + update( + Collections.emptyMap(), + new ArrayList(), + UPDATE_PRECONDITION), + transform("foo", serverTimestamp(), "inner.bar", serverTimestamp())); assertCommitEquals(update, commitCapture.getValue()); } @@ -472,7 +476,10 @@ public void mergeWithServerTimestamps() throws Exception { .set(LocalFirestoreHelper.SERVER_TIMESTAMP_OBJECT, SetOptions.mergeFields("inner.bar")) .get(); - CommitRequest set = commit(transform("inner.bar", serverTimestamp())); + CommitRequest set = + commit( + set(SERVER_TIMESTAMP_PROTO, new ArrayList()), + transform("inner.bar", serverTimestamp())); List commitRequests = commitCapture.getAllValues(); assertCommitEquals(set, commitRequests.get(0)); diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/FirestoreTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/FirestoreTest.java index 0366f7a07..9deea1d74 100644 --- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/FirestoreTest.java +++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/FirestoreTest.java @@ -19,13 +19,13 @@ import static com.google.cloud.firestore.LocalFirestoreHelper.SINGLE_FIELD_OBJECT; import static com.google.cloud.firestore.LocalFirestoreHelper.SINGLE_FIELD_PROTO; import static com.google.cloud.firestore.LocalFirestoreHelper.SINGLE_FIELD_VALUE; -import static com.google.cloud.firestore.LocalFirestoreHelper.UPDATE_PRECONDITION; import static com.google.cloud.firestore.LocalFirestoreHelper.arrayRemove; import static com.google.cloud.firestore.LocalFirestoreHelper.arrayUnion; import static com.google.cloud.firestore.LocalFirestoreHelper.commit; import static com.google.cloud.firestore.LocalFirestoreHelper.commitResponse; import static com.google.cloud.firestore.LocalFirestoreHelper.getAllResponse; import static com.google.cloud.firestore.LocalFirestoreHelper.transform; +import static com.google.cloud.firestore.LocalFirestoreHelper.update; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.fail; @@ -40,6 +40,9 @@ import com.google.firestore.v1.CommitRequest; import com.google.firestore.v1.CommitResponse; import com.google.firestore.v1.ListCollectionIdsRequest; +import com.google.firestore.v1.Value; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.concurrent.ExecutionException; import org.junit.Test; @@ -196,7 +199,9 @@ public void arrayUnionWithPojo() throws ExecutionException, InterruptedException doc.update("array", FieldValue.arrayUnion(SINGLE_FIELD_OBJECT)).get(); CommitRequest expectedRequest = - commit(transform(UPDATE_PRECONDITION, "array", arrayUnion(SINGLE_FIELD_VALUE))); + commit( + update(Collections.emptyMap(), new ArrayList()), + transform("array", arrayUnion(SINGLE_FIELD_VALUE))); CommitRequest actualRequest = commitCapture.getValue(); assertEquals(expectedRequest, actualRequest); } @@ -212,7 +217,9 @@ public void arrayRemoveWithPojo() throws ExecutionException, InterruptedExceptio doc.update("array", FieldValue.arrayRemove(SINGLE_FIELD_OBJECT)).get(); CommitRequest expectedRequest = - commit(transform(UPDATE_PRECONDITION, "array", arrayRemove(SINGLE_FIELD_VALUE))); + commit( + update(Collections.emptyMap(), new ArrayList()), + transform("array", arrayRemove(SINGLE_FIELD_VALUE))); CommitRequest actualRequest = commitCapture.getValue(); assertEquals(expectedRequest, actualRequest); } diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java index 148ce5585..541af7034 100644 --- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java +++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java @@ -38,7 +38,6 @@ import com.google.firestore.v1.DatabaseRootName; import com.google.firestore.v1.Document; import com.google.firestore.v1.DocumentMask; -import com.google.firestore.v1.DocumentTransform; import com.google.firestore.v1.DocumentTransform.FieldTransform; import com.google.firestore.v1.MapValue; import com.google.firestore.v1.Precondition; @@ -112,7 +111,6 @@ public final class LocalFirestoreHelper { public static final Map SERVER_TIMESTAMP_MAP; public static final ServerTimestamp SERVER_TIMESTAMP_OBJECT; public static final Map SERVER_TIMESTAMP_PROTO; - public static final Write SERVER_TIMESTAMP_TRANSFORM; public static final Map ALL_SUPPORTED_TYPES_MAP; public static final AllSupportedTypes ALL_SUPPORTED_TYPES_OBJECT; @@ -131,8 +129,6 @@ public final class LocalFirestoreHelper { public static final GeoPoint GEO_POINT; public static final Blob BLOB; - public static final Precondition CREATE_PRECONDITION; - public static final Precondition UPDATE_PRECONDITION; public static class SingleField { @@ -351,33 +347,21 @@ public static FieldTransform arrayRemove(Value... values) { .build(); } - public static Write transform( + public static List transform( String fieldPath, FieldTransform fieldTransform, Object... fieldPathOrTransform) { - return transform(null, fieldPath, fieldTransform, fieldPathOrTransform); - } - public static Write transform( - @Nullable Precondition precondition, - String fieldPath, - FieldTransform fieldTransform, - Object... fieldPathOrTransform) { - Write.Builder write = Write.newBuilder(); - DocumentTransform.Builder documentTransform = write.getTransformBuilder(); - documentTransform.setDocument(DOCUMENT_NAME); + List transforms = new ArrayList<>(); + FieldTransform.Builder transformBuilder = FieldTransform.newBuilder(); + transformBuilder.setFieldPath(fieldPath).mergeFrom(fieldTransform); - documentTransform.addFieldTransformsBuilder().setFieldPath(fieldPath).mergeFrom(fieldTransform); + transforms.add(transformBuilder.build()); for (int i = 0; i < fieldPathOrTransform.length; i += 2) { String path = (String) fieldPathOrTransform[i]; FieldTransform transform = (FieldTransform) fieldPathOrTransform[i + 1]; - documentTransform.addFieldTransformsBuilder().setFieldPath(path).mergeFrom(transform); - } - - if (precondition != null) { - write.setCurrentDocument(precondition); + transforms.add(FieldTransform.newBuilder().setFieldPath(path).mergeFrom(transform).build()); } - - return write.build(); + return transforms; } public static Write create(Map fields) { @@ -456,6 +440,10 @@ public static CommitRequest commit(Write... writes) { return commit(null, writes); } + public static CommitRequest commit(Write write, List transforms) { + return commit((String) null, write.toBuilder().addAllUpdateTransforms(transforms).build()); + } + public static StructuredQuery filter(StructuredQuery.FieldFilter.Operator operator) { return filter(operator, "foo", "bar"); } @@ -644,9 +632,8 @@ private static CommitRequest sortCommit(CommitRequest commit) { writes.setUpdateMask(DocumentMask.newBuilder().addAllFieldPaths(updateMask)); } - if (writes.getTransform().getFieldTransformsCount() > 0) { - ArrayList transformList = - new ArrayList<>(writes.getTransform().getFieldTransformsList()); + if (!writes.getUpdateTransformsList().isEmpty()) { + ArrayList transformList = new ArrayList<>(writes.getUpdateTransformsList()); Collections.sort( transformList, new Comparator() { @@ -655,7 +642,7 @@ public int compare(FieldTransform t1, FieldTransform t2) { return t1.getFieldPath().compareTo(t2.getFieldPath()); } }); - writes.setTransform(DocumentTransform.newBuilder().addAllFieldTransforms(transformList)); + writes.clearUpdateTransforms().addAllUpdateTransforms(transformList); } } @@ -787,8 +774,6 @@ public boolean equals(Object o) { mapValue.getMapValueBuilder(); SERVER_TIMESTAMP_PROTO = Collections.emptyMap(); SERVER_TIMESTAMP_OBJECT = new ServerTimestamp(); - SERVER_TIMESTAMP_TRANSFORM = - transform("foo", serverTimestamp(), "inner.bar", serverTimestamp()); ALL_SUPPORTED_TYPES_MAP = new HashMap<>(); ALL_SUPPORTED_TYPES_MAP.put("foo", "bar"); @@ -867,8 +852,6 @@ public boolean equals(Object o) { NESTED_CLASS_OBJECT = new NestedClass(); - CREATE_PRECONDITION = Precondition.newBuilder().setExists(false).build(); - UPDATE_PRECONDITION = Precondition.newBuilder().setExists(true).build(); UPDATED_POJO = map("model", (Object) UPDATE_SINGLE_FIELD_OBJECT); } diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/WriteBatchTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/WriteBatchTest.java index ac992db35..3e629324f 100644 --- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/WriteBatchTest.java +++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/WriteBatchTest.java @@ -215,7 +215,7 @@ public void setDocumentWithFloat() throws Exception { @Test public void omitWriteResultForDocumentTransforms() throws Exception { - doReturn(commitResponse(2, 0)) + doReturn(commitResponse(1, 0)) .when(firestoreMock) .sendRequest( commitCapture.capture(), Matchers.>any()); diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java index 3c1bbb0e6..f50e346f1 100644 --- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java +++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITSystemTest.java @@ -231,6 +231,15 @@ public void setDocumentWithMerge() throws Exception { assertEquals(resultMap, documentSnapshot.getData()); } + @Test + public void setWithIncrementAndMerge() throws ExecutionException, InterruptedException { + DocumentReference docRef = randomColl.document(); + docRef.set(Collections.singletonMap("sum", 1L)).get(); + docRef.set(Collections.singletonMap("sum", FieldValue.increment(2)), SetOptions.merge()).get(); + DocumentSnapshot docSnap = docRef.get().get(); + assertEquals(3L, docSnap.get("sum")); + } + @Test public void mergeDocumentWithServerTimestamp() throws Exception { Map originalMap = LocalFirestoreHelper.map("a", "b");