diff --git a/.kokoro/presubmit/graalvm-c.cfg b/.kokoro/presubmit/graalvm-c.cfg index 1554918af..654995133 100644 --- a/.kokoro/presubmit/graalvm-c.cfg +++ b/.kokoro/presubmit/graalvm-c.cfg @@ -13,7 +13,7 @@ env_vars: { env_vars: { key: "INTEGRATION_TEST_ARGS" - value: "-DFIRESTORE_EDITION=standard" + value: "-DFIRESTORE_NAMED_DATABASE=enterprise -DFIRESTORE_EDITION=enterprise" } # TODO: remove this after we've migrated all tests and scripts diff --git a/.kokoro/presubmit/graalvm-native-c.cfg b/.kokoro/presubmit/graalvm-native-c.cfg index c8f9a11a8..b2fe5dc21 100644 --- a/.kokoro/presubmit/graalvm-native-c.cfg +++ b/.kokoro/presubmit/graalvm-native-c.cfg @@ -13,7 +13,7 @@ env_vars: { env_vars: { key: "INTEGRATION_TEST_ARGS" - value: "-DFIRESTORE_EDITION=standard" + value: "-DFIRESTORE_NAMED_DATABASE=enterprise -DFIRESTORE_EDITION=enterprise" } env_vars: { diff --git a/.kokoro/presubmit/integration-named-db.cfg b/.kokoro/presubmit/integration-named-db.cfg index 81bb77849..43dac3fac 100644 --- a/.kokoro/presubmit/integration-named-db.cfg +++ b/.kokoro/presubmit/integration-named-db.cfg @@ -13,7 +13,7 @@ env_vars: { env_vars: { key: "INTEGRATION_TEST_ARGS" - value: "-DFIRESTORE_NAMED_DATABASE=test-db -DFIRESTORE_EDITION=standard" + value: "-DFIRESTORE_NAMED_DATABASE=enterprise -DFIRESTORE_EDITION=enterprise" } env_vars: { diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/AggregateQuery.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/AggregateQuery.java index 830d3bc61..dc6962ff9 100644 --- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/AggregateQuery.java +++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/AggregateQuery.java @@ -16,7 +16,6 @@ package com.google.cloud.firestore; -import static com.google.cloud.firestore.pipeline.expressions.Expression.and; import static com.google.cloud.firestore.telemetry.TelemetryConstants.METHOD_NAME_RUN_AGGREGATION_QUERY; import static com.google.cloud.firestore.telemetry.TraceUtil.ATTRIBUTE_KEY_ATTEMPT; @@ -29,7 +28,6 @@ import com.google.api.gax.rpc.StreamController; import com.google.cloud.Timestamp; import com.google.cloud.firestore.pipeline.expressions.AliasedAggregate; -import com.google.cloud.firestore.pipeline.expressions.BooleanExpression; import com.google.cloud.firestore.telemetry.MetricsUtil.MetricsContext; import com.google.cloud.firestore.telemetry.TelemetryConstants; import com.google.cloud.firestore.telemetry.TelemetryConstants.MetricType; @@ -53,7 +51,6 @@ import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.stream.Collectors; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -90,22 +87,6 @@ public Query getQuery() { Pipeline pipeline() { Pipeline pipeline = getQuery().pipeline(); - - List existsExprs = - this.aggregateFieldList.stream() - .map(PipelineUtils::toPipelineExistsExpr) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - if (existsExprs.size() == 1) { - pipeline = pipeline.where(existsExprs.get(0)); - } else if (existsExprs.size() > 1) { - pipeline = - pipeline.where( - and( - existsExprs.get(0), - existsExprs.subList(1, existsExprs.size()).toArray(new BooleanExpression[0]))); - } - return pipeline.aggregate( this.aggregateFieldList.stream() .map(PipelineUtils::toPipelineAggregatorTarget) diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java index 341c73af2..00c512cb0 100644 --- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java +++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java @@ -1161,7 +1161,8 @@ public void testLogicalAndComparisonOperators() throws Exception { .pipeline() .createFrom(collection) .where( - Expression.notEqualAny("genre", Lists.newArrayList("Romance", "Dystopian", null))) + Expression.notEqualAny( + "genre", Lists.newArrayList("Science Fiction", "Romance", "Dystopian", null))) .select("genre") .distinct("genre") .execute() @@ -1169,7 +1170,11 @@ public void testLogicalAndComparisonOperators() throws Exception { .getResults(); assertThat(data(results)) .containsExactly( - map("genre", "Science Fiction"), + // This is somewhat surprising because the pipeline did ask specifically for genre not + // equal to null, + // however at the later distinct stage, UNSET is grouped as null and thus null appears + // in the result. + map("genre", null), map("genre", "Magical Realism"), map("genre", "Fantasy"), map("genre", "Psychological Thriller"), @@ -1236,10 +1241,9 @@ public void testChecks() throws Exception { .select( field("rating").equal(nullValue()).as("ratingIsNull"), field("rating").equal(Double.NaN).as("ratingIsNaN"), + // arrayGet("title", 0) evaluates to UNSET arrayGet("title", 0).isError().as("isError"), - arrayGet("title", 0) - .ifError(constant("was error"), constant("was not error")) - .as("ifError"), + arrayGet("title", 0).ifError(constant("was error")).as("ifError"), field("foo").isAbsent().as("isAbsent"), field("title").notEqual(nullValue()).as("titleIsNotNull"), field("cost").notEqual(Double.NaN).as("costIsNotNan"), @@ -1259,8 +1263,6 @@ public void testChecks() throws Exception { false, "isError", false, - "ifError", - "was not error", "isAbsent", true, "titleIsNotNull", diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITQueryAggregationsTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITQueryAggregationsTest.java index d3f13a9fb..981f4dde9 100644 --- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITQueryAggregationsTest.java +++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITQueryAggregationsTest.java @@ -33,7 +33,6 @@ import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -101,9 +100,10 @@ public void canRunCountUsingAggregationMethod() throws Exception { @Test public void allowsAliasesForLongestFieldNames() throws Exception { assumeFalse( - "Skip this test when running against the Firestore emulator because it does not support" - + " long field names.", - isRunningAgainstFirestoreEmulator(firestore)); + "Skip this test when running against the Firestore emulator or enterprise backend because" + + " they do not support long field names.", + isRunningAgainstFirestoreEmulator(firestore) + || getFirestoreEdition() == FirestoreEdition.ENTERPRISE); // The longest field name allowed is 1499 characters long. // Ensure that sum(longestField) and average(longestField) work. @@ -141,7 +141,8 @@ public void aggregateErrorMessageIfIndexIsMissing() throws Exception { assumeFalse( "Skip this test when running against the emulator because it does not require composite" + " index creation.", - isRunningAgainstFirestoreEmulator(firestore)); + isRunningAgainstFirestoreEmulator(firestore) + || getFirestoreEdition() == FirestoreEdition.ENTERPRISE); CollectionReference collection = testCollectionWithDocs(testDocs1); AggregateQuery aggregateQuery = @@ -249,8 +250,10 @@ public void getCorrectTypeForAverageNull() throws Exception { @Test public void canPerformMaxAggregations() throws Exception { assumeTrue( - "Skip this test when running against prod because it requires composite index creation.", - isRunningAgainstFirestoreEmulator(firestore)); + "Skip this test when running against standard prod because it requires composite index" + + " creation.", + isRunningAgainstFirestoreEmulator(firestore) + || getFirestoreEdition() == FirestoreEdition.ENTERPRISE); CollectionReference collection = testCollectionWithDocs(testDocs1); AggregateField f1 = sum("pages"); AggregateField f2 = average("pages"); @@ -283,9 +286,14 @@ public void cannotPerformMoreThanMaxAggregations() throws Exception { } catch (Exception e) { exception = e; } - assertThat(exception).isNotNull(); - if (!isRunningAgainstFirestoreEmulator(firestore)) { - assertThat(exception.getMessage()).contains("maximum number of aggregations"); + + if (getFirestoreEdition() == FirestoreEdition.STANDARD) { + assertThat(exception).isNotNull(); + if (!isRunningAgainstFirestoreEmulator(firestore)) { + assertThat(exception.getMessage()).contains("maximum number of aggregations"); + } + } else { + assertThat(exception).isNull(); } } @@ -293,7 +301,8 @@ public void cannotPerformMoreThanMaxAggregations() throws Exception { public void aggregateQueriesSupportCollectionGroups() throws Exception { assumeTrue( "Skip this test when running against prod because it requires composite index creation.", - isRunningAgainstFirestoreEmulator(firestore)); + isRunningAgainstFirestoreEmulator(firestore) + || getFirestoreEdition() == FirestoreEdition.ENTERPRISE); String collectionGroupId = "myColGroupId" + autoId(); Map data = map("x", 2); // Setting documents at the following paths: @@ -337,8 +346,9 @@ public void aggregateQueriesSupportCollectionGroups() throws Exception { @Test public void performsAggregationsOnDocumentsWithAllAggregatedFields() throws Exception { assumeTrue( - "Skip this test when running against prod because it requires composite index creation.", - isRunningAgainstFirestoreEmulator(firestore)); + "Skip if we are running against standard in prod", + isRunningAgainstFirestoreEmulator(firestore) + || getFirestoreEdition() == FirestoreEdition.ENTERPRISE); Map> testDocs = map( "a", @@ -354,17 +364,26 @@ public void performsAggregationsOnDocumentsWithAllAggregatedFields() throws Exce verifyPipelineReturnsSameResult( collection.aggregate( sum("pages"), average("pages"), average("year"), AggregateField.count())); - assertThat(snapshot.get(sum("pages"))).isEqualTo(300); - assertThat(snapshot.get(average("pages"))).isEqualTo(100); - assertThat(snapshot.get(average("year"))).isEqualTo(2007); - assertThat(snapshot.get(AggregateField.count())).isEqualTo(3); + if (getFirestoreEdition() == FirestoreEdition.STANDARD) { + assertThat(snapshot.get(sum("pages"))).isEqualTo(300); + assertThat(snapshot.get(average("pages"))).isEqualTo(100); + assertThat(snapshot.get(average("year"))).isEqualTo(2007); + assertThat(snapshot.get(AggregateField.count())).isEqualTo(3); + } else { + assertThat(snapshot.get(sum("pages"))).isEqualTo(350); + assertThat(snapshot.get(average("pages"))).isEqualTo(87.5); + assertThat(snapshot.get(average("year"))).isEqualTo(2007); + assertThat(snapshot.get(AggregateField.count())).isEqualTo(4); + } } @Test public void performsAggregationsWhenNaNExistsForSomeFieldValues() throws Exception { assumeTrue( - "Skip this test when running against prod because it requires composite index creation.", - isRunningAgainstFirestoreEmulator(firestore)); + "Skip this test when running against standard prod because it requires composite index" + + " creation.", + isRunningAgainstFirestoreEmulator(firestore) + || getFirestoreEdition() == FirestoreEdition.ENTERPRISE); Map> testDocs = map( "a", @@ -427,7 +446,8 @@ public void throwsAnErrorWhenGettingTheResultOfAnUnrequestedAggregation() throws public void performsAggregationWhenUsingInOperator() throws Exception { assumeTrue( "Skip this test when running against prod because it requires composite index creation.", - isRunningAgainstFirestoreEmulator(firestore)); + isRunningAgainstFirestoreEmulator(firestore) + || getFirestoreEdition() == FirestoreEdition.ENTERPRISE); Map> testDocs = map( "a", @@ -466,7 +486,8 @@ public void performsAggregationWhenUsingInOperator() throws Exception { public void performsAggregationWhenUsingArrayContainsAnyOperator() throws Exception { assumeTrue( "Skip this test when running against prod because it requires composite index creation.", - isRunningAgainstFirestoreEmulator(firestore)); + isRunningAgainstFirestoreEmulator(firestore) + || getFirestoreEdition() == FirestoreEdition.ENTERPRISE); Map> testDocs = map( "a", @@ -512,11 +533,20 @@ public void performsAggregationWhenUsingArrayContainsAnyOperator() throws Except sum("pages"), average("pages"), AggregateField.count())); - assertThat(snapshot.get(sum("rating"))).isEqualTo(0); - assertThat(snapshot.get(average("rating"))).isEqualTo(null); - assertThat(snapshot.get(sum("pages"))).isEqualTo(200); - assertThat(snapshot.get(average("pages"))).isEqualTo(100); - assertThat(snapshot.get(AggregateField.count())).isEqualTo(2); + + if (getFirestoreEdition() == FirestoreEdition.STANDARD) { + assertThat(snapshot.get(sum("rating"))).isEqualTo(0); + assertThat(snapshot.get(average("rating"))).isEqualTo(null); + assertThat(snapshot.get(sum("pages"))).isEqualTo(200); + assertThat(snapshot.get(average("pages"))).isEqualTo(100); + assertThat(snapshot.get(AggregateField.count())).isEqualTo(2); + } else { + assertThat(snapshot.get(sum("rating"))).isNull(); + assertThat(snapshot.get(average("rating"))).isNull(); + assertThat(snapshot.get(sum("pages"))).isEqualTo(200); + assertThat(snapshot.get(average("pages"))).isEqualTo(100); + assertThat(snapshot.get(AggregateField.count())).isEqualTo(2); + } } @Test @@ -586,10 +616,15 @@ public void performsSumThatOverflowsMaxLong() throws Exception { "a", map("author", "authorA", "title", "titleA", "rating", Long.MAX_VALUE), "b", map("author", "authorB", "title", "titleB", "rating", Long.MAX_VALUE)); CollectionReference collection = testCollectionWithDocs(testDocs); - AggregateQuerySnapshot snapshot = collection.aggregate(sum("rating")).get().get(); - Object sum = snapshot.get(sum("rating")); - assertThat(sum instanceof Double).isTrue(); - assertThat(sum).isEqualTo((double) Long.MAX_VALUE + (double) Long.MAX_VALUE); + if (getFirestoreEdition() == FirestoreEdition.STANDARD) { + AggregateQuerySnapshot snapshot = collection.aggregate(sum("rating")).get().get(); + Object sum = snapshot.get(sum("rating")); + assertThat(sum instanceof Double).isTrue(); + assertThat(sum).isEqualTo((double) Long.MAX_VALUE + (double) Long.MAX_VALUE); + } else { + // enterprise will fail the operation + assertThrows(ExecutionException.class, () -> collection.aggregate(sum("rating")).get().get()); + } } @Test @@ -615,9 +650,14 @@ public void performsSumThatIsNegative() throws Exception { "c", map("author", "authorC", "title", "titleC", "rating", -101), "d", map("author", "authorD", "title", "titleD", "rating", -10000)); CollectionReference collection = testCollectionWithDocs(testDocs); - AggregateQuerySnapshot snapshot = - verifyPipelineReturnsSameResult(collection.aggregate(sum("rating"))); - assertThat(snapshot.get(sum("rating"))).isEqualTo(-10101); + if (getFirestoreEdition() == FirestoreEdition.STANDARD) { + AggregateQuerySnapshot snapshot = + verifyPipelineReturnsSameResult(collection.aggregate(sum("rating"))); + assertThat(snapshot.get(sum("rating"))).isEqualTo(-10101); + } else { + // enterprise will fail the operation + assertThrows(ExecutionException.class, () -> collection.aggregate(sum("rating")).get().get()); + } } @Test @@ -691,7 +731,11 @@ public void performsSumOverResultSetOfZeroDocuments() throws Exception { AggregateQuerySnapshot snapshot = verifyPipelineReturnsSameResult( collection.whereGreaterThan("pages", 200).aggregate(sum("pages"))); - assertThat(snapshot.get(sum("pages"))).isEqualTo(0); + if (getFirestoreEdition() == FirestoreEdition.STANDARD) { + assertThat(snapshot.get(sum("pages"))).isEqualTo(0); + } else { + assertThat(snapshot.get(sum("pages"))).isNull(); + } } @Test @@ -898,10 +942,13 @@ public void performsAverageOnlyOnNumericFields() throws Exception { assertThat(snapshot.get(AggregateField.count())).isEqualTo(4); } - // Currently not allowed because it requires __name__, num index. - @Ignore @Test public void aggregatesWithDocumentReferenceCursors() throws Exception { + assumeTrue( + "Skip this test when running against standard prod because it requires composite index" + + " creation.", + isRunningAgainstFirestoreEmulator(firestore) + || getFirestoreEdition() == FirestoreEdition.ENTERPRISE); Map> testDocs = map( "a", map("num", 1), @@ -1009,10 +1056,13 @@ public void aggregateNoFilterExplicitOrderByFieldValueCursor() throws Exception assertThat(snapshot.get(sum("num"))).isEqualTo(7); } - // This is expected to fail because it requires the `__name__, num` index. - @Ignore @Test public void aggregateNoFilterExplicitOrderByDocumentReferenceCursor() throws Exception { + assumeTrue( + "Skip this test when running against standard prod because it requires composite index" + + " creation.", + isRunningAgainstFirestoreEmulator(firestore) + || getFirestoreEdition() == FirestoreEdition.ENTERPRISE); CollectionReference collection = addTwoDocsForCursorTesting(); AggregateQuery query = collection @@ -1023,20 +1073,26 @@ public void aggregateNoFilterExplicitOrderByDocumentReferenceCursor() throws Exc assertThat(snapshot.get(sum("num"))).isEqualTo(7); } - // This is expected to fail because it requires the `__name__, num` index. - @Ignore @Test public void aggregateNoFilterNoOrderByDocumentReferenceCursor() throws Exception { + assumeTrue( + "Skip this test when running against standard prod because it requires composite index" + + " creation.", + isRunningAgainstFirestoreEmulator(firestore) + || getFirestoreEdition() == FirestoreEdition.ENTERPRISE); CollectionReference collection = addTwoDocsForCursorTesting(); AggregateQuery query = collection.startAfter(collection.document("a")).aggregate(sum("num")); AggregateQuerySnapshot snapshot = verifyPipelineReturnsSameResult(query); assertThat(snapshot.get(sum("num"))).isEqualTo(7); } - // This is expected to fail because it requires the `foo, __name__, num` index. - @Ignore @Test public void aggregateNoFilterExplicitOrderByDocumentSnapshotCursor() throws Exception { + assumeTrue( + "Skip this test when running against standard prod because it requires composite index" + + " creation.", + isRunningAgainstFirestoreEmulator(firestore) + || getFirestoreEdition() == FirestoreEdition.ENTERPRISE); CollectionReference collection = addTwoDocsForCursorTesting(); DocumentSnapshot docSnapshot = collection.document("a").get().get(); AggregateQuery query = collection.orderBy("foo").startAfter(docSnapshot).aggregate(sum("num")); @@ -1072,10 +1128,13 @@ public void aggregateInequalityFilterExplicitOrderByFieldValueCursor() throws Ex assertThat(snapshot.get(sum("num"))).isEqualTo(7); } - // This is expected to fail because it requires the `__name__, num` index. - @Ignore @Test public void aggregateEqualityFilterExplicitOrderByDocumentReferenceCursor() throws Exception { + assumeTrue( + "Skip this test when running against standard prod because it requires composite index" + + " creation.", + isRunningAgainstFirestoreEmulator(firestore) + || getFirestoreEdition() == FirestoreEdition.ENTERPRISE); CollectionReference collection = addTwoDocsForCursorTesting(); AggregateQuery query = collection @@ -1102,10 +1161,13 @@ public void aggregateInequalityFilterExplicitOrderByDocumentReferenceCursor() th assertThat(snapshot.get(sum("num"))).isEqualTo(7); } - // This is expected to fail because it requires the `__name__, num` index. - @Ignore @Test public void aggregateEqualityFilterNoOrderByDocumentSnapshotReference() throws Exception { + assumeTrue( + "Skip this test when running against standard prod because it requires composite index" + + " creation.", + isRunningAgainstFirestoreEmulator(firestore) + || getFirestoreEdition() == FirestoreEdition.ENTERPRISE); CollectionReference collection = addTwoDocsForCursorTesting(); DocumentSnapshot docSnapshot = collection.document("a").get().get(); AggregateQuery query = @@ -1125,10 +1187,13 @@ public void aggregateInequalityFilterNoOrderByDocumentSnapshotReference() throws assertThat(snapshot.get(sum("num"))).isEqualTo(7); } - // This is expected to fail because it requires the `foo, __name__, num` index. - @Ignore @Test public void aggregateInequalityFilterNoOrderByDocumentSnapshotReference2() throws Exception { + assumeTrue( + "Skip this test when running against standard prod because it requires composite index" + + " creation.", + isRunningAgainstFirestoreEmulator(firestore) + || getFirestoreEdition() == FirestoreEdition.ENTERPRISE); CollectionReference collection = addTwoDocsForCursorTesting(); DocumentSnapshot docSnapshot = collection.document("a").get().get(); AggregateQuery query = @@ -1140,9 +1205,9 @@ public void aggregateInequalityFilterNoOrderByDocumentSnapshotReference2() throw @Test public void aggregateQueryShouldFailWithMessageWithConsoleLinkIfMissingIndex() { assumeFalse( - "Skip this test when running against the Firestore emulator because the Firestore emulator " - + "does not use indexes and never fails with a 'missing index' error", - isRunningAgainstFirestoreEmulator(firestore)); + "Only run this test when running against the standard backend", + isRunningAgainstFirestoreEmulator(firestore) + || getFirestoreEdition() == FirestoreEdition.ENTERPRISE); CollectionReference collection = testCollection(); Query compositeIndexQuery = collection.whereEqualTo("field1", 42).whereLessThan("field2", 99); diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITQueryCountTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITQueryCountTest.java index 438762e14..5ded283ac 100644 --- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITQueryCountTest.java +++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITQueryCountTest.java @@ -107,6 +107,10 @@ public void countShouldRespectOrderBy() throws Exception { @Test public void countShouldRespectStartAtAndEndAtWithDocumentSnapshotCursor() throws Exception { + // TODO(pipeline): Enable this test against production when adding implicitOrderBy. + assumeTrue( + "Skip this test when running against enterprise prod because it does not work yet.", + getFirestoreEdition() != FirestoreEdition.ENTERPRISE); CollectionReference collection = createCollectionWithDocuments(10).collection(); List documentSnapshots = collection.get().get().getDocuments(); AggregateQuerySnapshot snapshot = @@ -121,6 +125,10 @@ public void countShouldRespectStartAtAndEndAtWithDocumentSnapshotCursor() throws @Test public void countShouldRespectStartAtAndEndAtWithDocumentReferenceCursor() throws Exception { + // TODO: Enable this test against production when adding implicitOrderBy. + assumeTrue( + "Skip this test when running against enterprise prod because it does not work yet.", + getFirestoreEdition() != FirestoreEdition.ENTERPRISE); CollectionReference collection = createCollectionWithDocuments(10).collection(); List documentSnapshots = collection.get().get().getDocuments(); AggregateQuerySnapshot snapshot = @@ -137,6 +145,10 @@ public void countShouldRespectStartAtAndEndAtWithDocumentReferenceCursor() throw @Test public void countShouldRespectStartAfterAndEndBeforeWithDocumentSnapshotCursor() throws Exception { + // TODO(pipeline): Enable this test against production when adding implicitOrderBy. + assumeTrue( + "Skip this test when running against enterprise prod because it does not work yet.", + getFirestoreEdition() != FirestoreEdition.ENTERPRISE); CollectionReference collection = createCollectionWithDocuments(10).collection(); List documentSnapshots = collection.get().get().getDocuments(); AggregateQuerySnapshot snapshot = @@ -152,6 +164,10 @@ public void countShouldRespectStartAfterAndEndBeforeWithDocumentSnapshotCursor() @Test public void countShouldRespectStartAfterAndEndBeforeWithDocumentReferenceCursor() throws Exception { + // TODO: Enable this test against production when adding implicitOrderBy. + assumeTrue( + "Skip this test when running against enterprise prod because it does not work yet.", + getFirestoreEdition() != FirestoreEdition.ENTERPRISE); CollectionReference collection = createCollectionWithDocuments(10).collection(); List documentSnapshots = collection.get().get().getDocuments(); AggregateQuerySnapshot snapshot = @@ -374,9 +390,10 @@ public void aggregateQueryInATransactionShouldRespectReadTime() throws Exception @Test public void countQueryShouldFailWithMessageWithConsoleLinkIfMissingIndex() { assumeFalse( - "Skip this test when running against the Firestore emulator because the Firestore emulator " - + "does not use indexes and never fails with a 'missing index' error", - isRunningAgainstFirestoreEmulator(firestore)); + "Skip this test when running against the Firestore emulator or enterprise because they " + + "do not use indexes and never fails with a 'missing index' error", + isRunningAgainstFirestoreEmulator(firestore) + || getFirestoreEdition() == FirestoreEdition.ENTERPRISE); CollectionReference collection = createEmptyCollection(); Query compositeIndexQuery = collection.whereEqualTo("field1", 42).whereLessThan("field2", 99); diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITQueryFindNearestTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITQueryFindNearestTest.java index 123e9d4a9..0d40fbd77 100644 --- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITQueryFindNearestTest.java +++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITQueryFindNearestTest.java @@ -21,6 +21,7 @@ import static com.google.cloud.firestore.it.TestHelper.await; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.*; +import static org.junit.Assume.assumeTrue; import com.google.cloud.firestore.*; import java.time.Duration; @@ -826,6 +827,9 @@ public void willNotExceedLimitEvenIfThereAreMoreResultsMoreSimilarThanDistanceTh @Test public void testVectorQueryPlan() throws Exception { + assumeTrue( + "Skip this test when running against enterprise because it does not support explain yet", + getFirestoreEdition() != FirestoreEdition.ENTERPRISE); CollectionReference collection = testCollectionWithDocs( map( @@ -865,6 +869,9 @@ public void testVectorQueryPlan() throws Exception { @Test public void testVectorQueryProfile() throws Exception { + assumeTrue( + "Skip this test when running against enterprise because it does not support explain yet", + getFirestoreEdition() != FirestoreEdition.ENTERPRISE); CollectionReference collection = testCollectionWithDocs( map( diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITQueryToPipelineTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITQueryToPipelineTest.java index efdc47c88..e35677d9d 100644 --- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITQueryToPipelineTest.java +++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITQueryToPipelineTest.java @@ -609,7 +609,11 @@ public void supportsNotInWith1() throws Exception { Query query1 = collRef.whereNotIn("bar", Arrays.asList(2L)).orderBy("foo"); List snapshot = firestore.pipeline().createFrom(query1).execute().get().getResults(); - verifyResults(snapshot, map("foo", 3L, "bar", 10L)); + if (getFirestoreEdition() == FirestoreEdition.ENTERPRISE) { + verifyResults(snapshot, map("foo", 2L), map("foo", 3L, "bar", 10L)); + } else { + verifyResults(snapshot, map("foo", 3L, "bar", 10L)); + } } @Test diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITQueryWatchTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITQueryWatchTest.java index 2936c9d04..447dfa4d7 100644 --- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITQueryWatchTest.java +++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITQueryWatchTest.java @@ -668,24 +668,46 @@ public void snapshotListenerSortsQueryByDocumentIdInTheSameOrderAsServer() throw .get(); Query query = col.orderBy("__name__", Direction.ASCENDING); - List expectedOrder = - Arrays.asList( - "__id-2__", - "__id7__", - "__id12__", - "12", - "7", - "A", - "Aa", - "__id", - "__id1_", - "_id1__", - "a"); QuerySnapshot snapshot = query.get().get(); List queryOrder = snapshot.getDocuments().stream().map(doc -> doc.getId()).collect(Collectors.toList()); - assertEquals(expectedOrder, queryOrder); // Assert order from backend + if (getFirestoreEdition() == FirestoreEdition.STANDARD) { + List expectedOrder = + Arrays.asList( + "__id-2__", + "__id7__", + "__id12__", + "12", + "7", + "A", + "Aa", + "__id", + "__id1_", + "_id1__", + "a"); + assertThat(queryOrder) + .containsExactlyElementsIn(expectedOrder) + .inOrder(); // standard backend order + } else { + List expectedOrder = + Arrays.asList( + "12", + "7", + "A", + "Aa", + "__id", + "__id-2__", + "__id12__", + "__id1_", + "__id7__", + "_id1__", + "a"); + + assertThat(queryOrder) + .containsExactlyElementsIn(expectedOrder) + .inOrder(); // enterprise backend order + } CountDownLatch latch = new CountDownLatch(1); List listenerOrder = new ArrayList<>(); @@ -704,6 +726,20 @@ public void snapshotListenerSortsQueryByDocumentIdInTheSameOrderAsServer() throw latch.await(); registration.remove(); + List expectedOrder = + Arrays.asList( + "__id-2__", + "__id7__", + "__id12__", + "12", + "7", + "A", + "Aa", + "__id", + "__id1_", + "_id1__", + "a"); + // TODO: SDK now implements stardard backend order. We need to change it to Enterprise order assertEquals(expectedOrder, listenerOrder); // Assert order in the SDK } @@ -737,7 +773,11 @@ public void snapshotListenerSortsFilteredQueryByDocumentIdInTheSameOrderAsServer QuerySnapshot snapshot = query.get().get(); List queryOrder = snapshot.getDocuments().stream().map(doc -> doc.getId()).collect(Collectors.toList()); - assertEquals(expectedOrder, queryOrder); // Assert order from backend + if (getFirestoreEdition() == FirestoreEdition.STANDARD) { + assertEquals(expectedOrder, queryOrder); // Assert order from backend + } else { + assertThat(queryOrder).isEmpty(); + } CountDownLatch latch = new CountDownLatch(1); List listenerOrder = new ArrayList<>(); @@ -756,7 +796,11 @@ public void snapshotListenerSortsFilteredQueryByDocumentIdInTheSameOrderAsServer latch.await(); registration.remove(); - assertEquals(expectedOrder, listenerOrder); // Assert order in the SDK + if (getFirestoreEdition() == FirestoreEdition.STANDARD) { + assertEquals(expectedOrder, listenerOrder); // Assert order in the SDK + } else { + assertThat(listenerOrder).isEmpty(); + } } /** @@ -1123,7 +1167,8 @@ public void testInequalityIncludesAndSortsMissingFields() throws Exception { // Missing/Null sorted by __name__. // doc3 < doc4. // So: doc3, doc4, doc2. - List expectedOrder = Arrays.asList("doc3", "doc4", "doc2"); + // TODO: Watch still applies orderby normalization for now + List expectedOrder = Arrays.asList("doc2", "doc4"); assertEquals(expectedOrder, listenerAssertions.addedIds); } else { List expectedOrder = singletonList("doc2"); 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 4776ac1bb..7067bb960 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 @@ -1144,6 +1144,11 @@ public void omitWriteResultForDocumentTransforms() @Test public void listCollections() throws Exception { + assumeTrue( + "Skip this test when running against enterprise because it does not support" + + " listCollections", + getFirestoreEdition() != FirestoreEdition.ENTERPRISE); + // We test with 21 collections since 20 collections are by default returned in a single paged // response. String[] collections = @@ -1170,6 +1175,9 @@ public void listCollections() throws Exception { @Test public void listDocuments() throws Exception { + assumeTrue( + "Skip this test when running against enterprise because it does not support listDocuments", + getFirestoreEdition() != FirestoreEdition.ENTERPRISE); // We test with 21 documents since 20 documents are by default returned in a single paged // response. String[] documents = @@ -1196,6 +1204,11 @@ public void listDocuments() throws Exception { @Test public void listDocumentsListsMissingDocument() throws Exception { + assumeFalse( + "Skip this test when running against enterprise because it does not support" + + " missing documents.", + getFirestoreEdition() == FirestoreEdition.ENTERPRISE); + randomColl.document("missing/foo/bar").set(SINGLE_FIELD_MAP).get(); Iterable collectionRefs = randomColl.listDocuments(); assertEquals(randomColl.document("missing"), collectionRefs.iterator().next()); @@ -1598,6 +1611,10 @@ public void queryPaginationWithOrderByClause() throws ExecutionException, Interr @Test public void queryPaginationWithWhereClause() throws ExecutionException, InterruptedException { + // TODO(pipeline): Enable this test against production when adding implicitOrderBy. + assumeTrue( + "Skip this test when running against enterprise because it does not work yet.", + getFirestoreEdition() != FirestoreEdition.ENTERPRISE); WriteBatch batch = firestore.batch(); for (int i = 0; i < 10; ++i) { @@ -1661,9 +1678,14 @@ public void testCollectionGroupQueries() throws ExecutionException, InterruptedE batch.commit().get(); QuerySnapshot querySnapshot = firestore.collectionGroup(collectionGroup).get().get(); - assertEquals( - asList("cg-doc1", "cg-doc2", "cg-doc3", "cg-doc4", "cg-doc5"), - querySnapshotToIds(querySnapshot)); + if (getFirestoreEdition() == FirestoreEdition.STANDARD) { + assertEquals( + asList("cg-doc1", "cg-doc2", "cg-doc3", "cg-doc4", "cg-doc5"), + querySnapshotToIds(querySnapshot)); + } else { + assertThat(querySnapshotToIds(querySnapshot)) + .containsExactlyElementsIn(asList("cg-doc1", "cg-doc2", "cg-doc3", "cg-doc4", "cg-doc5")); + } } @Test @@ -1743,7 +1765,12 @@ public void collectionGroupQueriesWithWhereFiltersOnArbitraryDocumentIds() .whereLessThanOrEqualTo(FieldPath.documentId(), "a/b0") .get() .get(); - assertEquals(asList("cg-doc2", "cg-doc3", "cg-doc4"), querySnapshotToIds(querySnapshot)); + if (getFirestoreEdition() == FirestoreEdition.STANDARD) { + assertEquals(asList("cg-doc2", "cg-doc3", "cg-doc4"), querySnapshotToIds(querySnapshot)); + } else { + assertThat(querySnapshotToIds(querySnapshot)) + .containsExactlyElementsIn(asList("cg-doc2", "cg-doc3", "cg-doc4")); + } querySnapshot = firestore @@ -1767,7 +1794,11 @@ public void inQueries() throws Exception { QuerySnapshot querySnapshot = randomColl.whereIn("zip", Arrays.asList(98101, 98103)).get().get(); - assertEquals(asList("a", "c"), querySnapshotToIds(querySnapshot)); + if (getFirestoreEdition() == FirestoreEdition.STANDARD) { + assertEquals(asList("a", "c"), querySnapshotToIds(querySnapshot)); + } else { + assertThat(querySnapshotToIds(querySnapshot)).containsExactlyElementsIn(asList("a", "c")); + } } @Test @@ -1824,7 +1855,11 @@ public void notEqualQueriesWithDocumentId() throws Exception { QuerySnapshot querySnapshot = randomColl.whereNotEqualTo(FieldPath.documentId(), doc1.getId()).get().get(); - assertEquals(asList("b", "c"), querySnapshotToIds(querySnapshot)); + if (getFirestoreEdition() == FirestoreEdition.STANDARD) { + assertEquals(asList("b", "c"), querySnapshotToIds(querySnapshot)); + } else { + assertThat(querySnapshotToIds(querySnapshot)).containsExactlyElementsIn(asList("b", "c")); + } } @Test @@ -1836,7 +1871,11 @@ public void inQueriesWithDocumentId() throws Exception { QuerySnapshot querySnapshot = randomColl.whereIn(FieldPath.documentId(), Arrays.asList(doc1.getId(), doc2)).get().get(); - assertEquals(asList("a", "b"), querySnapshotToIds(querySnapshot)); + if (getFirestoreEdition() == FirestoreEdition.STANDARD) { + assertEquals(asList("a", "b"), querySnapshotToIds(querySnapshot)); + } else { + assertThat(querySnapshotToIds(querySnapshot)).containsExactlyElementsIn(asList("a", "b")); + } } @Test @@ -1850,15 +1889,31 @@ public void notInQueries() throws Exception { QuerySnapshot querySnapshot = randomColl.whereNotIn("zip", Arrays.asList(98101, 98103)).get().get(); - assertEquals(asList("b", "d", "e", "f"), querySnapshotToIds(querySnapshot)); + if (getFirestoreEdition() == FirestoreEdition.STANDARD) { + assertEquals(asList("b", "d", "e", "f"), querySnapshotToIds(querySnapshot)); + } else { + assertThat(querySnapshotToIds(querySnapshot)) + .containsExactlyElementsIn(asList("b", "d", "e", "f")); + } querySnapshot = randomColl.whereNotIn("zip", Arrays.asList(Double.NaN)).get().get(); - assertEquals(asList("b", "a", "c", "d", "e", "f"), querySnapshotToIds(querySnapshot)); + if (getFirestoreEdition() == FirestoreEdition.STANDARD) { + assertEquals(asList("b", "a", "c", "d", "e", "f"), querySnapshotToIds(querySnapshot)); + } else { + assertThat(querySnapshotToIds(querySnapshot)) + .containsExactlyElementsIn(asList("b", "a", "c", "d", "e", "f")); + } List nullArray = new ArrayList<>(); nullArray.add(null); querySnapshot = randomColl.whereNotIn("zip", nullArray).get().get(); - assertEquals(new ArrayList<>(), querySnapshotToIds(querySnapshot)); + + if (getFirestoreEdition() == FirestoreEdition.STANDARD) { + assertEquals(new ArrayList<>(), querySnapshotToIds(querySnapshot)); + } else { + assertThat(querySnapshotToIds(querySnapshot)) + .containsExactlyElementsIn(asList("a", "b", "c", "d", "e", "f")); + } } @Test @@ -1886,10 +1941,15 @@ public void arrayContainsAnyQueries() throws Exception { setDocument("f", map("array", asList(map("a", 42)))); setDocument("g", map("array", 42)); - QuerySnapshot querySnapshot = - randomColl.whereArrayContainsAny("array", Arrays.asList(42, 43)).get().get(); + Query query = randomColl.whereArrayContainsAny("array", Arrays.asList(42, 43)); - assertEquals(asList("a", "b", "d", "e"), querySnapshotToIds(querySnapshot)); + if (getFirestoreEdition() == FirestoreEdition.STANDARD) { + assertEquals(asList("a", "b", "d", "e"), querySnapshotToIds(query.get().get())); + } else { + // TODO: Currently rejected because of mixed type setup, backend will change the behavior; and + // this test will fail by then. + assertThrows(ExecutionException.class, () -> querySnapshotToIds(query.get().get())); + } } @Test @@ -2277,6 +2337,9 @@ private void setupRecursiveDeleteTest() throws Exception { @Test public void testRecursiveDeleteTopLevelCollection() throws Exception { + assumeFalse( + "Skip this test when running against enterprise because it does not support showMissing", + getFirestoreEdition() == FirestoreEdition.ENTERPRISE); setupRecursiveDeleteTest(); firestore.recursiveDelete(randomColl).get(); assertEquals(0, countCollectionChildren(randomColl)); @@ -2284,6 +2347,9 @@ public void testRecursiveDeleteTopLevelCollection() throws Exception { @Test public void testRecursiveDeleteNestedCollection() throws Exception { + assumeFalse( + "Skip this test when running against enterprise because it does not support showMissing", + getFirestoreEdition() == FirestoreEdition.ENTERPRISE); setupRecursiveDeleteTest(); firestore.recursiveDelete(randomColl.document("bob").collection("parentsCol")).get(); assertEquals(2, countCollectionChildren(randomColl)); @@ -2291,6 +2357,10 @@ public void testRecursiveDeleteNestedCollection() throws Exception { @Test public void testRecursiveDeleteNestedDocument() throws Exception { + assumeFalse( + "Skip this test when running against enterprise because it does not support showMissing", + getFirestoreEdition() == FirestoreEdition.ENTERPRISE); + setupRecursiveDeleteTest(); DocumentReference document = randomColl.document("bob/parentsCol/daniel"); firestore.recursiveDelete(document).get(); @@ -2302,6 +2372,9 @@ public void testRecursiveDeleteNestedDocument() throws Exception { @Test public void testRecursiveDeleteLeafDocument() throws Exception { + assumeFalse( + "Skip this test when running against enterprise because it does not support showMissing", + getFirestoreEdition() == FirestoreEdition.ENTERPRISE); setupRecursiveDeleteTest(); DocumentReference document = randomColl.document("bob/parentsCol/daniel/childCol/ernie"); firestore.recursiveDelete(document).get(); @@ -2312,6 +2385,9 @@ public void testRecursiveDeleteLeafDocument() throws Exception { @Test public void testRecursiveDeleteDoesNotAffectOtherCollections() throws Exception { + assumeFalse( + "Skip this test when running against enterprise because it does not support showMissing", + getFirestoreEdition() == FirestoreEdition.ENTERPRISE); setupRecursiveDeleteTest(); // Add another nested collection that shouldn't be deleted. @@ -2325,6 +2401,11 @@ public void testRecursiveDeleteDoesNotAffectOtherCollections() throws Exception @Test public void testRecursiveDeleteWithCustomBulkWriterInstance() throws Exception { + assumeFalse( + "Skip this test when running against enterprise because it does not support" + + " bulk writer.", + getFirestoreEdition() == FirestoreEdition.ENTERPRISE); + setupRecursiveDeleteTest(); BulkWriter bulkWriter = firestore.bulkWriter(); diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITTracingTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITTracingTest.java index cfc9c4784..be4ef4485 100644 --- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITTracingTest.java +++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITTracingTest.java @@ -16,12 +16,14 @@ package com.google.cloud.firestore.it; +import static com.google.cloud.firestore.it.ITBaseTest.getFirestoreEdition; import static com.google.cloud.firestore.telemetry.TelemetryConstants.*; import static com.google.cloud.firestore.telemetry.TraceUtil.*; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeFalse; +import static org.junit.Assume.assumeTrue; import com.google.cloud.firestore.BulkWriter; import com.google.cloud.firestore.BulkWriterOptions; @@ -36,6 +38,7 @@ import com.google.cloud.firestore.Query; import com.google.cloud.firestore.SetOptions; import com.google.cloud.firestore.WriteBatch; +import com.google.cloud.firestore.it.ITBaseTest.FirestoreEdition; import com.google.common.base.Preconditions; import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.common.AttributeKey; @@ -405,6 +408,11 @@ public void bulkWriterCommit() throws Exception { @Test public void partitionQuery() throws Exception { + assumeTrue( + "Skip this test when running against enterprise because it does not support partition" + + " query", + getFirestoreEdition() != FirestoreEdition.ENTERPRISE); + CollectionGroup collectionGroup = firestore.collectionGroup("col"); collectionGroup.getPartitions(3).get(); @@ -415,6 +423,10 @@ public void partitionQuery() throws Exception { @Test public void collectionListDocuments() throws Exception { + assumeTrue( + "Skip this test when running against enterprise because it does not support listDocuments", + getFirestoreEdition() != FirestoreEdition.ENTERPRISE); + firestore.collection("col").listDocuments(); List spans = prepareSpans(); @@ -606,6 +618,11 @@ public void docRefGet2() throws Exception { @Test public void docListCollections() throws Exception { + assumeTrue( + "Skip this test when running against enterprise because it does not support" + + " listCollections", + getFirestoreEdition() != FirestoreEdition.ENTERPRISE); + firestore.collection("col").document("doc0").listCollections(); List spans = prepareSpans();