diff --git a/.gitignore b/.gitignore index bdb262af0bac6..19547d6a1616a 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,6 @@ hs_err_pid* doc docs +target +bin +test-output diff --git a/commons-test-utils/pom.xml b/commons-test-utils/pom.xml index 977a5a5822a00..857a9edeb3d54 100644 --- a/commons-test-utils/pom.xml +++ b/commons-test-utils/pom.xml @@ -126,6 +126,10 @@ SOFTWARE. log4j ${log4j.version} + + io.projectreactor + reactor-core + com.google.guava guava diff --git a/commons-test-utils/src/main/java/com/microsoft/azure/cosmosdb/rx/FeedResponseListValidator.java b/commons-test-utils/src/main/java/com/microsoft/azure/cosmosdb/rx/FeedResponseListValidator.java index 6356f1363fff9..ccf6bdd3df98e 100644 --- a/commons-test-utils/src/main/java/com/microsoft/azure/cosmosdb/rx/FeedResponseListValidator.java +++ b/commons-test-utils/src/main/java/com/microsoft/azure/cosmosdb/rx/FeedResponseListValidator.java @@ -32,6 +32,7 @@ import java.util.Map; import java.util.stream.Collectors; +import com.microsoft.azure.cosmos.CosmosItemSettings; import com.microsoft.azure.cosmosdb.BridgeInternal; import com.fasterxml.jackson.databind.node.ArrayNode; import com.microsoft.azure.cosmosdb.CompositePath; @@ -72,7 +73,7 @@ public void validate(List> feedList) { return this; } - public Builder containsExactly(List expectedIds) { + public Builder containsExactly(List expectedRids) { validators.add(new FeedResponseListValidator() { @Override public void validate(List> feedList) { @@ -83,6 +84,23 @@ public void validate(List> feedList) { .collect(Collectors.toList()); assertThat(actualIds) .describedAs("Resource IDs of results") + .containsExactlyElementsOf(expectedRids); + } + }); + return this; + } + + public Builder containsExactlyIds(List expectedIds) { + validators.add(new FeedResponseListValidator() { + @Override + public void validate(List> feedList) { + List actualIds = feedList + .stream() + .flatMap(f -> f.getResults().stream()) + .map(r -> r.getId()) + .collect(Collectors.toList()); + assertThat(actualIds) + .describedAs("IDs of results") .containsExactlyElementsOf(expectedIds); } }); @@ -186,11 +204,11 @@ public void validate(List> feedList) { } public Builder withAggregateValue(Object value) { - validators.add(new FeedResponseListValidator() { + validators.add(new FeedResponseListValidator() { @Override - public void validate(List> feedList) { - List list = feedList.get(0).getResults(); - Document result = list.size() > 0 ? list.get(0) : null; + public void validate(List> feedList) { + List list = feedList.get(0).getResults(); + CosmosItemSettings result = list.size() > 0 ? list.get(0) : null; if (result != null) { if (value instanceof Double) { @@ -223,13 +241,13 @@ public void validate(List> feedList) { return this; } - public Builder withOrderedResults(ArrayList expectedOrderedList, + public Builder withOrderedResults(ArrayList expectedOrderedList, ArrayList compositeIndex) { - validators.add(new FeedResponseListValidator() { + validators.add(new FeedResponseListValidator() { @Override - public void validate(List> feedList) { + public void validate(List> feedList) { - List resultOrderedList = feedList.stream() + List resultOrderedList = feedList.stream() .flatMap(f -> f.getResults().stream()) .collect(Collectors.toList()); assertThat(expectedOrderedList.size()).isEqualTo(resultOrderedList.size()); diff --git a/commons/pom.xml b/commons/pom.xml index 2db549d7278de..293faef19f94d 100644 --- a/commons/pom.xml +++ b/commons/pom.xml @@ -194,6 +194,31 @@ SOFTWARE. ${log4j.version} test + + io.projectreactor + reactor-core + + + io.projectreactor.addons + reactor-adapter + ${reactor-addons.version} + test + + + io.projectreactor + reactor-test + test + + + com.github.akarnokd + rxjava2-interop + ${rxjava2interop.verison} + + + io.reactivex.rxjava2 + rxjava + ${rxjava2.version} + com.google.guava guava diff --git a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosContainerRequestOptions.java b/commons/src/main/java/com/microsoft/azure/cosmos/CosmosContainerRequestOptions.java similarity index 99% rename from sdk/src/main/java/com/microsoft/azure/cosmos/CosmosContainerRequestOptions.java rename to commons/src/main/java/com/microsoft/azure/cosmos/CosmosContainerRequestOptions.java index 1ba2413c293bd..cbed66e3bc830 100644 --- a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosContainerRequestOptions.java +++ b/commons/src/main/java/com/microsoft/azure/cosmos/CosmosContainerRequestOptions.java @@ -127,4 +127,4 @@ protected RequestOptions toRequestOptions() { requestOptions.setConsistencyLevel(consistencyLevel); return requestOptions; } -} +} \ No newline at end of file diff --git a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosContainerSettings.java b/commons/src/main/java/com/microsoft/azure/cosmos/CosmosContainerSettings.java similarity index 87% rename from sdk/src/main/java/com/microsoft/azure/cosmos/CosmosContainerSettings.java rename to commons/src/main/java/com/microsoft/azure/cosmos/CosmosContainerSettings.java index 62989947a4f91..b5256f1915b71 100644 --- a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosContainerSettings.java +++ b/commons/src/main/java/com/microsoft/azure/cosmos/CosmosContainerSettings.java @@ -22,6 +22,7 @@ */ package com.microsoft.azure.cosmos; +import com.microsoft.azure.cosmosdb.ConflictResolutionPolicy; import com.microsoft.azure.cosmosdb.DocumentCollection; import com.microsoft.azure.cosmosdb.IndexingPolicy; import com.microsoft.azure.cosmosdb.PartitionKeyDefinition; @@ -179,6 +180,30 @@ public void setPartitionKey(PartitionKeyDefinition partitionKeyDefinition) { this.partitionKeyDefinition = partitionKeyDefinition; } + /** + * Gets the conflictResolutionPolicy that is used for resolving conflicting writes + * on documents in different regions, in a collection in the Azure Cosmos DB service. + * + * @return ConflictResolutionPolicy + */ + public ConflictResolutionPolicy getConflictResolutionPolicy() { + return super.getObject(Constants.Properties.CONFLICT_RESOLUTION_POLICY, ConflictResolutionPolicy.class); + } + + /** + * Sets the conflictResolutionPolicy that is used for resolving conflicting writes + * on documents in different regions, in a collection in the Azure Cosmos DB service. + * + * @param value ConflictResolutionPolicy to be used. + */ + public void setConflictResolutionPolicy(ConflictResolutionPolicy value) { + if (value == null) { + throw new IllegalArgumentException("CONFLICT_RESOLUTION_POLICY cannot be null."); + } + + super.set(Constants.Properties.CONFLICT_RESOLUTION_POLICY, value); + } + DocumentCollection getV2Collection(){ DocumentCollection collection = new DocumentCollection(this.toJson()); collection.setPartitionKey(this.getPartitionKey()); diff --git a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosDatabaseRequestOptions.java b/commons/src/main/java/com/microsoft/azure/cosmos/CosmosDatabaseRequestOptions.java similarity index 99% rename from sdk/src/main/java/com/microsoft/azure/cosmos/CosmosDatabaseRequestOptions.java rename to commons/src/main/java/com/microsoft/azure/cosmos/CosmosDatabaseRequestOptions.java index 77a60f70d98f0..8047375213272 100644 --- a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosDatabaseRequestOptions.java +++ b/commons/src/main/java/com/microsoft/azure/cosmos/CosmosDatabaseRequestOptions.java @@ -56,4 +56,4 @@ protected RequestOptions toRequestOptions() { requestOptions.setOfferThroughput(offerThroughput); return requestOptions; } -} +} \ No newline at end of file diff --git a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosDatabaseSettings.java b/commons/src/main/java/com/microsoft/azure/cosmos/CosmosDatabaseSettings.java similarity index 99% rename from sdk/src/main/java/com/microsoft/azure/cosmos/CosmosDatabaseSettings.java rename to commons/src/main/java/com/microsoft/azure/cosmos/CosmosDatabaseSettings.java index c53a386f7601c..6415bd16753b2 100644 --- a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosDatabaseSettings.java +++ b/commons/src/main/java/com/microsoft/azure/cosmos/CosmosDatabaseSettings.java @@ -59,4 +59,4 @@ public CosmosDatabaseSettings(String id) { static List getFromV2Results(List results){ return results.stream().map(CosmosDatabaseSettings::new).collect(Collectors.toList()); } -} +} \ No newline at end of file diff --git a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosFeedResponse.java b/commons/src/main/java/com/microsoft/azure/cosmos/CosmosFeedResponse.java similarity index 100% rename from sdk/src/main/java/com/microsoft/azure/cosmos/CosmosFeedResponse.java rename to commons/src/main/java/com/microsoft/azure/cosmos/CosmosFeedResponse.java diff --git a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosItemRequestOptions.java b/commons/src/main/java/com/microsoft/azure/cosmos/CosmosItemRequestOptions.java similarity index 99% rename from sdk/src/main/java/com/microsoft/azure/cosmos/CosmosItemRequestOptions.java rename to commons/src/main/java/com/microsoft/azure/cosmos/CosmosItemRequestOptions.java index 62f017ab337dc..bce7b56e5fcff 100644 --- a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosItemRequestOptions.java +++ b/commons/src/main/java/com/microsoft/azure/cosmos/CosmosItemRequestOptions.java @@ -179,4 +179,4 @@ protected RequestOptions toRequestOptions() { requestOptions.setPartitionKey(partitionKey); return requestOptions; } -} +} \ No newline at end of file diff --git a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosItemSettings.java b/commons/src/main/java/com/microsoft/azure/cosmos/CosmosItemSettings.java similarity index 89% rename from sdk/src/main/java/com/microsoft/azure/cosmos/CosmosItemSettings.java rename to commons/src/main/java/com/microsoft/azure/cosmos/CosmosItemSettings.java index 9000ed4ed3ca0..6bee41456d56e 100644 --- a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosItemSettings.java +++ b/commons/src/main/java/com/microsoft/azure/cosmos/CosmosItemSettings.java @@ -49,6 +49,17 @@ public CosmosItemSettings(String jsonString) { super(jsonString); } + + /** + * Initialize an CosmosItemSettings object from json string. + * + * @param jsonString the json string that represents the item object. + * @param objectMapper the custom object mapper + */ + public CosmosItemSettings(String jsonString, ObjectMapper objectMapper) { + super(jsonString, objectMapper); + } + /** * fromObject returns Document for compatibility with V2 sdk * diff --git a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosRequestOptions.java b/commons/src/main/java/com/microsoft/azure/cosmos/CosmosRequestOptions.java similarity index 99% rename from sdk/src/main/java/com/microsoft/azure/cosmos/CosmosRequestOptions.java rename to commons/src/main/java/com/microsoft/azure/cosmos/CosmosRequestOptions.java index 30a5085021ccd..fb9df401c432f 100644 --- a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosRequestOptions.java +++ b/commons/src/main/java/com/microsoft/azure/cosmos/CosmosRequestOptions.java @@ -56,4 +56,4 @@ protected RequestOptions toRequestOptions(){ requestOptions.setAccessCondition(accessCondition); return requestOptions; } -} +} \ No newline at end of file diff --git a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosResource.java b/commons/src/main/java/com/microsoft/azure/cosmos/CosmosResource.java similarity index 100% rename from sdk/src/main/java/com/microsoft/azure/cosmos/CosmosResource.java rename to commons/src/main/java/com/microsoft/azure/cosmos/CosmosResource.java diff --git a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosResponse.java b/commons/src/main/java/com/microsoft/azure/cosmos/CosmosResponse.java similarity index 84% rename from sdk/src/main/java/com/microsoft/azure/cosmos/CosmosResponse.java rename to commons/src/main/java/com/microsoft/azure/cosmos/CosmosResponse.java index 4154283e16584..8a74e286daacd 100644 --- a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosResponse.java +++ b/commons/src/main/java/com/microsoft/azure/cosmos/CosmosResponse.java @@ -22,12 +22,16 @@ */ package com.microsoft.azure.cosmos; +import com.microsoft.azure.cosmosdb.ClientSideRequestStatistics; import com.microsoft.azure.cosmosdb.Resource; import com.microsoft.azure.cosmosdb.ResourceResponse; import com.microsoft.azure.cosmosdb.StoredProcedureResponse; +import java.time.Duration; import java.util.Map; +import org.apache.commons.lang3.StringUtils; + public class CosmosResponse { private T resourceSettings; protected ResourceResponse resourceResponseWrapper; @@ -134,5 +138,21 @@ public Map getResponseHeaders() { return resourceResponseWrapper.getResponseHeaders(); } - + /** + * Gets the diagnostics information for the current request to Azure Cosmos DB service. + * + * @return diagnostics information for the current request to Azure Cosmos DB service. + */ + public String getRequestDiagnosticsString() { + return resourceResponseWrapper.getRequestDiagnosticsString(); + } + + /** + * Gets the end-to-end request latency for the current request to Azure Cosmos DB service. + * + * @return end-to-end request latency for the current request to Azure Cosmos DB service. + */ + public Duration getRequestLatency() { + return resourceResponseWrapper.getRequestLatency(); + } } diff --git a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosStoredProcedureRequestOptions.java b/commons/src/main/java/com/microsoft/azure/cosmos/CosmosStoredProcedureRequestOptions.java similarity index 100% rename from sdk/src/main/java/com/microsoft/azure/cosmos/CosmosStoredProcedureRequestOptions.java rename to commons/src/main/java/com/microsoft/azure/cosmos/CosmosStoredProcedureRequestOptions.java diff --git a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosStoredProcedureSettings.java b/commons/src/main/java/com/microsoft/azure/cosmos/CosmosStoredProcedureSettings.java similarity index 100% rename from sdk/src/main/java/com/microsoft/azure/cosmos/CosmosStoredProcedureSettings.java rename to commons/src/main/java/com/microsoft/azure/cosmos/CosmosStoredProcedureSettings.java diff --git a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosTriggerSettings.java b/commons/src/main/java/com/microsoft/azure/cosmos/CosmosTriggerSettings.java similarity index 100% rename from sdk/src/main/java/com/microsoft/azure/cosmos/CosmosTriggerSettings.java rename to commons/src/main/java/com/microsoft/azure/cosmos/CosmosTriggerSettings.java diff --git a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosUserDefinedFunctionSettings.java b/commons/src/main/java/com/microsoft/azure/cosmos/CosmosUserDefinedFunctionSettings.java similarity index 100% rename from sdk/src/main/java/com/microsoft/azure/cosmos/CosmosUserDefinedFunctionSettings.java rename to commons/src/main/java/com/microsoft/azure/cosmos/CosmosUserDefinedFunctionSettings.java diff --git a/commons/src/main/java/com/microsoft/azure/cosmos/CosmosUserSettings.java b/commons/src/main/java/com/microsoft/azure/cosmos/CosmosUserSettings.java new file mode 100644 index 0000000000000..cc81ad0d96e6d --- /dev/null +++ b/commons/src/main/java/com/microsoft/azure/cosmos/CosmosUserSettings.java @@ -0,0 +1,59 @@ +package com.microsoft.azure.cosmos; + +import java.util.List; +import java.util.stream.Collectors; + +import com.microsoft.azure.cosmosdb.DocumentCollection; +import com.microsoft.azure.cosmosdb.Resource; +import com.microsoft.azure.cosmosdb.ResourceResponse; +import com.microsoft.azure.cosmosdb.User; +import com.microsoft.azure.cosmosdb.internal.Constants; + +public class CosmosUserSettings extends Resource { + /** + * Initialize a user object. + */ + public CosmosUserSettings() { + super(); + } + + /** + * Initialize a user object from json string. + * + * @param jsonString the json string that represents the database user. + */ + public CosmosUserSettings(String jsonString) { + super(jsonString); + } + + CosmosUserSettings(ResourceResponse response) { + super(response.getResource().toJson()); + } + + // Converting document collection to CosmosContainerSettings + CosmosUserSettings(User user){ + super(user.toJson()); + } + + /** + * Gets the self-link of the permissions associated with the user. + * + * @return the permissions link. + */ + public String getPermissionsLink() { + String selfLink = this.getSelfLink(); + if (selfLink.endsWith("/")) { + return selfLink + super.getString(Constants.Properties.PERMISSIONS_LINK); + } else { + return selfLink + "/" + super.getString(Constants.Properties.PERMISSIONS_LINK); + } + } + + public User getV2User() { + return new User(this.toJson()); + } + + static List getFromV2Results(List results) { + return results.stream().map(CosmosUserSettings::new).collect(Collectors.toList()); + } +} \ No newline at end of file diff --git a/commons/src/main/java/com/microsoft/azure/cosmosdb/BridgeInternal.java b/commons/src/main/java/com/microsoft/azure/cosmosdb/BridgeInternal.java index e0bc791440772..f7c90034da6c1 100644 --- a/commons/src/main/java/com/microsoft/azure/cosmosdb/BridgeInternal.java +++ b/commons/src/main/java/com/microsoft/azure/cosmosdb/BridgeInternal.java @@ -27,6 +27,7 @@ import com.fasterxml.jackson.databind.node.ObjectNode; import com.microsoft.azure.cosmosdb.internal.HttpConstants; import com.microsoft.azure.cosmosdb.internal.query.metrics.ClientSideMetrics; +import com.microsoft.azure.cosmosdb.internal.routing.PartitionKeyInternal; import com.microsoft.azure.cosmosdb.rx.internal.RxDocumentServiceResponse; import com.microsoft.azure.cosmosdb.rx.internal.Strings; @@ -282,4 +283,12 @@ public static String getInnerErrorMessage(DocumentClientException documentClient } return documentClientException.getInnerErrorMessage(); } + + public static PartitionKeyInternal getNonePartitionKey(PartitionKeyDefinition partitionKeyDefinition) { + return partitionKeyDefinition.getNonePartitionKeyValue(); + } + + public static PartitionKey getPartitionKey(PartitionKeyInternal partitionKeyInternal) { + return new PartitionKey(partitionKeyInternal); + } } diff --git a/commons/src/main/java/com/microsoft/azure/cosmosdb/PartitionKey.java b/commons/src/main/java/com/microsoft/azure/cosmosdb/PartitionKey.java index 8defae8237b43..2f25785475d25 100644 --- a/commons/src/main/java/com/microsoft/azure/cosmosdb/PartitionKey.java +++ b/commons/src/main/java/com/microsoft/azure/cosmosdb/PartitionKey.java @@ -58,6 +58,8 @@ public static PartitionKey FromJsonString(String jsonString) { return new PartitionKey(PartitionKeyInternal.fromJsonString(jsonString)); } + public static PartitionKey None = new PartitionKey(PartitionKeyInternal.None); + /** * Serialize the PartitionKey object to a JSON string. * diff --git a/commons/src/main/java/com/microsoft/azure/cosmosdb/PartitionKeyDefinition.java b/commons/src/main/java/com/microsoft/azure/cosmosdb/PartitionKeyDefinition.java index e9f71e9928b0a..bc6fda9090410 100644 --- a/commons/src/main/java/com/microsoft/azure/cosmosdb/PartitionKeyDefinition.java +++ b/commons/src/main/java/com/microsoft/azure/cosmosdb/PartitionKeyDefinition.java @@ -24,6 +24,7 @@ package com.microsoft.azure.cosmosdb; import com.microsoft.azure.cosmosdb.internal.Constants; +import com.microsoft.azure.cosmosdb.internal.routing.PartitionKeyInternal; import com.microsoft.azure.cosmosdb.rx.internal.Strings; import java.util.ArrayList; @@ -40,6 +41,7 @@ public final class PartitionKeyDefinition extends JsonSerializable { private List paths; private PartitionKind kind; private PartitionKeyDefinitionVersion version; + private Boolean systemKey; /** * Constructor. Creates a new instance of the PartitionKeyDefinition object. @@ -134,6 +136,31 @@ public void setPaths(List paths) { this.paths = paths; } + /** + * Indicates if the partition key is generated by the system. + * + * @return the boolean indicating is it is a system key. + */ + Boolean isSystemKey() { + if (this.systemKey == null) { + if (super.has(Constants.Properties.SYSTEM_KEY)) { + this.systemKey = super.getBoolean(Constants.Properties.SYSTEM_KEY); + } else { + this.systemKey = false; + } + } + + return this.systemKey; + } + + PartitionKeyInternal getNonePartitionKeyValue() { + if (this.getPaths().size() == 0 || this.isSystemKey()) { + return PartitionKeyInternal.Empty; + } else { + return PartitionKeyInternal.UndefinedPartitionKey; + } + } + @Override void populatePropertyBag() { if (this.kind != null) { diff --git a/commons/src/main/java/com/microsoft/azure/cosmosdb/internal/Constants.java b/commons/src/main/java/com/microsoft/azure/cosmosdb/internal/Constants.java index 6ae4ca51597a2..c3d11aa753d36 100644 --- a/commons/src/main/java/com/microsoft/azure/cosmosdb/internal/Constants.java +++ b/commons/src/main/java/com/microsoft/azure/cosmosdb/internal/Constants.java @@ -157,6 +157,7 @@ public static final class Properties { public static final String PARTITION_KEY_PATHS = "paths"; public static final String PARTITION_KIND = "kind"; public static final String PARTITION_KEY_DEFINITION_VERSION = "version"; + public static final String SYSTEM_KEY = "systemKey"; public static final String RESOURCE_PARTITION_KEY = "resourcePartitionKey"; public static final String PARTITION_KEY_RANGE_ID = "partitionKeyRangeId"; diff --git a/commons/src/main/java/com/microsoft/azure/cosmosdb/internal/HttpConstants.java b/commons/src/main/java/com/microsoft/azure/cosmosdb/internal/HttpConstants.java index 2a90ef59c029c..78c0bf4e23ffa 100644 --- a/commons/src/main/java/com/microsoft/azure/cosmosdb/internal/HttpConstants.java +++ b/commons/src/main/java/com/microsoft/azure/cosmosdb/internal/HttpConstants.java @@ -265,7 +265,7 @@ public static class A_IMHeaderValues { } public static class Versions { - public static final String CURRENT_VERSION = "2018-09-17"; + public static final String CURRENT_VERSION = "2018-12-31"; // TODO: FIXME we can use maven plugin for generating a version file // @see https://stackoverflow.com/questions/2469922/generate-a-version-java-file-in-maven diff --git a/commons/src/main/java/com/microsoft/azure/cosmosdb/internal/routing/PartitionKeyInternal.java b/commons/src/main/java/com/microsoft/azure/cosmosdb/internal/routing/PartitionKeyInternal.java index 1051193584ae6..35bcc575ec2bb 100644 --- a/commons/src/main/java/com/microsoft/azure/cosmosdb/internal/routing/PartitionKeyInternal.java +++ b/commons/src/main/java/com/microsoft/azure/cosmosdb/internal/routing/PartitionKeyInternal.java @@ -62,6 +62,9 @@ public class PartitionKeyInternal implements Comparable { private static final String MAX_STRING = "MaxString"; private static final String INFINITY = "Infinity"; + public static final PartitionKeyInternal NonePartitionKey = + new PartitionKeyInternal(); + public static final PartitionKeyInternal EmptyPartitionKey = new PartitionKeyInternal(new ArrayList<>()); @@ -71,9 +74,16 @@ public class PartitionKeyInternal implements Comparable { add(new InfinityPartitionKeyComponent()); }}); + @SuppressWarnings("serial") + public static final PartitionKeyInternal UndefinedPartitionKey = + new PartitionKeyInternal(new ArrayList() {{ + add(new UndefinedPartitionKeyComponent()); + }}); + public static final PartitionKeyInternal InclusiveMinimum = PartitionKeyInternal.EmptyPartitionKey; public static final PartitionKeyInternal ExclusiveMaximum = PartitionKeyInternal.InfinityPartitionKey; public static final PartitionKeyInternal Empty = PartitionKeyInternal.EmptyPartitionKey; + public static final PartitionKeyInternal None = PartitionKeyInternal.NonePartitionKey; final List components; @@ -85,6 +95,10 @@ public PartitionKeyInternal(List values) { this.components = values; } + public PartitionKeyInternal() { + this.components = null; + } + public static PartitionKeyInternal fromJsonString(String partitionKey) { if (Strings.isNullOrEmpty(partitionKey)) { throw new IllegalArgumentException(String.format(RMResources.UnableToDeserializePartitionKeyValue, partitionKey)); @@ -178,6 +192,10 @@ public boolean equals(Object obj) { public int compareTo(PartitionKeyInternal other) { if (other == null) { throw new IllegalArgumentException("other"); + } else if (other.components == null || this.components == null) { + int otherComponentsCount = other.components == null ? 0 : other.components.size(); + int thisComponentsCount = this.components == null ? 0 : this.components.size(); + return (int) Math.signum(thisComponentsCount - otherComponentsCount); } for (int i = 0; i < Math.min(this.components.size(), other.components.size()); i++) { diff --git a/direct-impl/src/main/java/com/microsoft/azure/cosmosdb/internal/directconnectivity/AddressResolver.java b/direct-impl/src/main/java/com/microsoft/azure/cosmosdb/internal/directconnectivity/AddressResolver.java index db65feef97d5d..37527ab7d9ca0 100644 --- a/direct-impl/src/main/java/com/microsoft/azure/cosmosdb/internal/directconnectivity/AddressResolver.java +++ b/direct-impl/src/main/java/com/microsoft/azure/cosmosdb/internal/directconnectivity/AddressResolver.java @@ -655,7 +655,7 @@ private PartitionKeyRange tryResolveServerPartitionByPartitionKey( throw new InternalServerErrorException(String.format("partition key is null '%s'", partitionKeyString)); } - if (partitionKey.getComponents().size() == collection.getPartitionKey().getPaths().size()) { + if (partitionKey.equals(PartitionKeyInternal.Empty) || partitionKey.getComponents().size() == collection.getPartitionKey().getPaths().size()) { // Although we can compute effective partition key here, in general case this Gateway can have outdated // partition key definition cached - like if collection with same name but with Range partitioning is created. // In this case server will not pass x-ms-documentdb-collection-rid check and will return back InvalidPartitionException. diff --git a/direct-impl/src/main/java/com/microsoft/azure/cosmosdb/internal/routing/PartitionKeyInternalHelper.java b/direct-impl/src/main/java/com/microsoft/azure/cosmosdb/internal/routing/PartitionKeyInternalHelper.java index 316f6e87dc353..d0c81ddf8c194 100644 --- a/direct-impl/src/main/java/com/microsoft/azure/cosmosdb/internal/routing/PartitionKeyInternalHelper.java +++ b/direct-impl/src/main/java/com/microsoft/azure/cosmosdb/internal/routing/PartitionKeyInternalHelper.java @@ -140,6 +140,10 @@ public static String getEffectivePartitionKeyString(PartitionKeyInternal partiti } public static String getEffectivePartitionKeyString(PartitionKeyInternal partitionKeyInternal, PartitionKeyDefinition partitionKeyDefinition, boolean strict) { + if (partitionKeyInternal.components == null) { + throw new IllegalArgumentException(RMResources.TooFewPartitionKeyComponents); + } + if (partitionKeyInternal.equals(PartitionKeyInternal.EmptyPartitionKey)) { return MinimumInclusiveEffectivePartitionKey; } diff --git a/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/CollectionCRUDAsyncAPITest.java b/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/CollectionCRUDAsyncAPITest.java index e9d0c4d336042..4ed8e550f35ed 100644 --- a/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/CollectionCRUDAsyncAPITest.java +++ b/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/CollectionCRUDAsyncAPITest.java @@ -106,6 +106,11 @@ public void setUp() { public void before() { collectionDefinition = new DocumentCollection(); collectionDefinition.setId(UUID.randomUUID().toString()); + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.setPaths(paths); + collectionDefinition.setPartitionKey(partitionKeyDef); } @AfterClass(groups = "samples", timeOut = TIMEOUT) diff --git a/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/ConflictAPITest.java b/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/ConflictAPITest.java index 8aad1f45b8e93..d82c4aa07b9dd 100644 --- a/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/ConflictAPITest.java +++ b/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/ConflictAPITest.java @@ -32,6 +32,7 @@ import com.microsoft.azure.cosmosdb.DocumentCollection; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; +import com.microsoft.azure.cosmosdb.PartitionKeyDefinition; import com.microsoft.azure.cosmosdb.internal.HttpConstants; import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; import org.testng.annotations.AfterClass; @@ -40,6 +41,7 @@ import rx.Observable; import rx.observable.ListenableFutureObservable; +import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.UUID; @@ -77,6 +79,11 @@ public void setUp() { DocumentCollection collectionDefinition = new DocumentCollection(); collectionDefinition.setId(UUID.randomUUID().toString()); + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.setPaths(paths); + collectionDefinition.setPartitionKey(partitionKeyDef); // Create database createdDatabase = Utils.createDatabaseForTest(client); diff --git a/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/DocumentCRUDAsyncAPITest.java b/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/DocumentCRUDAsyncAPITest.java index a9df3991e84c8..c68157454ca46 100644 --- a/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/DocumentCRUDAsyncAPITest.java +++ b/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/DocumentCRUDAsyncAPITest.java @@ -221,9 +221,11 @@ public void createDocumentWithProgrammableDocumentDefinition() throws Exception .createDocument(getCollectionLink(), documentDefinition, null, false).toBlocking().single() .getResource(); + RequestOptions options = new RequestOptions(); + options.setPartitionKey(PartitionKey.None); // Read the created document Observable> readDocumentObservable = asyncClient - .readDocument(getDocumentLink(createdDocument), null); + .readDocument(getDocumentLink(createdDocument), options); final CountDownLatch completionLatch = new CountDownLatch(1); diff --git a/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/DocumentQueryAsyncAPITest.java b/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/DocumentQueryAsyncAPITest.java index 35d652c3efdf5..0cb6ec4013996 100644 --- a/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/DocumentQueryAsyncAPITest.java +++ b/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/DocumentQueryAsyncAPITest.java @@ -83,7 +83,7 @@ * {@link #transformObservableToGoogleGuavaListenableFuture()} */ public class DocumentQueryAsyncAPITest { - private final static int TIMEOUT = 60000; + private final static int TIMEOUT = 3 * 60000; private AsyncDocumentClient asyncClient; private DocumentCollection createdCollection; private Database createdDatabase; @@ -102,6 +102,11 @@ public void setUp() { DocumentCollection collectionDefinition = new DocumentCollection(); collectionDefinition.setId(UUID.randomUUID().toString()); + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.setPaths(paths); + collectionDefinition.setPartitionKey(partitionKeyDef); // Create database @@ -136,6 +141,7 @@ public void queryDocuments_Async() throws Exception { int requestPageSize = 3; FeedOptions options = new FeedOptions(); options.setMaxItemCount(requestPageSize); + options.setEnableCrossPartitionQuery(true); Observable> documentQueryObservable = asyncClient .queryDocuments(getCollectionLink(), "SELECT * FROM root", options); @@ -182,6 +188,7 @@ public void queryDocuments_Async_withoutLambda() throws Exception { int requestPageSize = 3; FeedOptions options = new FeedOptions(); options.setMaxItemCount(requestPageSize); + options.setEnableCrossPartitionQuery(true); Observable> documentQueryObservable = asyncClient .queryDocuments(getCollectionLink(), "SELECT * FROM root", options); @@ -231,6 +238,7 @@ public void queryDocuments_findTotalRequestCharge() throws Exception { int requestPageSize = 3; FeedOptions options = new FeedOptions(); options.setMaxItemCount(requestPageSize); + options.setEnableCrossPartitionQuery(true); Observable totalChargeObservable = asyncClient .queryDocuments(getCollectionLink(), "SELECT * FROM root", options) @@ -256,6 +264,7 @@ public void queryDocuments_unsubscribeAfterFirstPage() throws Exception { int requestPageSize = 3; FeedOptions options = new FeedOptions(); options.setMaxItemCount(requestPageSize); + options.setEnableCrossPartitionQuery(true); Observable> requestChargeObservable = asyncClient .queryDocuments(getCollectionLink(), "SELECT * FROM root", options); @@ -300,6 +309,7 @@ public void queryDocuments_filterFetchedResults() throws Exception { int requestPageSize = 3; FeedOptions options = new FeedOptions(); options.setMaxItemCount(requestPageSize); + options.setEnableCrossPartitionQuery(true); Func1 isPrimeNumber = new Func1() { @@ -359,6 +369,7 @@ public void queryDocuments_toBlocking_toIterator() { int requestPageSize = 3; FeedOptions options = new FeedOptions(); options.setMaxItemCount(requestPageSize); + options.setEnableCrossPartitionQuery(true); Observable> documentQueryObservable = asyncClient .queryDocuments(getCollectionLink(), "SELECT * FROM root", options); @@ -448,6 +459,7 @@ public void transformObservableToGoogleGuavaListenableFuture() throws Exception int requestPageSize = 3; FeedOptions options = new FeedOptions(); options.setMaxItemCount(requestPageSize); + options.setEnableCrossPartitionQuery(true); Observable> documentQueryObservable = asyncClient .queryDocuments(getCollectionLink(), "SELECT * FROM root", options); diff --git a/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/InMemoryGroupbyTest.java b/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/InMemoryGroupbyTest.java index baeac40b2a029..23c97a7dadba0 100644 --- a/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/InMemoryGroupbyTest.java +++ b/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/InMemoryGroupbyTest.java @@ -29,6 +29,7 @@ import com.microsoft.azure.cosmosdb.Document; import com.microsoft.azure.cosmosdb.DocumentCollection; import com.microsoft.azure.cosmosdb.FeedOptions; +import com.microsoft.azure.cosmosdb.PartitionKeyDefinition; import com.microsoft.azure.cosmosdb.SqlParameter; import com.microsoft.azure.cosmosdb.SqlParameterCollection; import com.microsoft.azure.cosmosdb.SqlQuerySpec; @@ -40,6 +41,7 @@ import rx.observables.GroupedObservable; import java.time.LocalDateTime; +import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -66,6 +68,11 @@ public static void setUp() throws Exception { DocumentCollection collectionDefinition = new DocumentCollection(); collectionDefinition.setId(UUID.randomUUID().toString()); + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.setPaths(paths); + collectionDefinition.setPartitionKey(partitionKeyDef); // Create collection createdCollection = asyncClient @@ -112,6 +119,7 @@ public void groupByInMemory() { int requestPageSize = 3; FeedOptions options = new FeedOptions(); options.setMaxItemCount(requestPageSize); + options.setEnableCrossPartitionQuery(true); Observable documentsObservable = asyncClient .queryDocuments(getCollectionLink(), @@ -144,7 +152,7 @@ public void groupByInMemory_MoreDetail() { int requestPageSize = 3; FeedOptions options = new FeedOptions(); options.setMaxItemCount(requestPageSize); - + options.setEnableCrossPartitionQuery(true); Observable documentsObservable = asyncClient .queryDocuments(getCollectionLink(), diff --git a/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/TokenResolverTest.java b/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/TokenResolverTest.java index c33f14fdc2b38..4c56170eb4972 100644 --- a/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/TokenResolverTest.java +++ b/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/TokenResolverTest.java @@ -31,6 +31,8 @@ import com.microsoft.azure.cosmosdb.Database; import com.microsoft.azure.cosmosdb.Document; import com.microsoft.azure.cosmosdb.DocumentCollection; +import com.microsoft.azure.cosmosdb.PartitionKey; +import com.microsoft.azure.cosmosdb.PartitionKeyDefinition; import com.microsoft.azure.cosmosdb.Permission; import com.microsoft.azure.cosmosdb.PermissionMode; import com.microsoft.azure.cosmosdb.RequestOptions; @@ -86,6 +88,11 @@ public void setUp() { DocumentCollection collectionDefinition = new DocumentCollection(); collectionDefinition.setId(UUID.randomUUID().toString()); + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.setPaths(paths); + collectionDefinition.setPartitionKey(partitionKeyDef); // Create database createdDatabase = Utils.createDatabaseForTest(asyncClient); @@ -163,6 +170,7 @@ public void readDocumentThroughTokenResolver() throws Exception { .build(); RequestOptions requestOptions = new RequestOptions(); requestOptions.setProperties(properties); + requestOptions.setPartitionKey(PartitionKey.None); Observable> readDocumentObservable = asyncClientWithTokenResolver .readDocument(documentLink, requestOptions); readDocumentObservable.subscribe(resourceResponse -> { @@ -204,6 +212,7 @@ public void deleteDocumentThroughTokenResolver() throws Exception { RequestOptions requestOptions = new RequestOptions(); requestOptions.setProperties(properties); + requestOptions.setPartitionKey(PartitionKey.None); Observable> readDocumentObservable = asyncClientWithTokenResolver .deleteDocument(documentLink, requestOptions); readDocumentObservable.subscribe(resourceResponse -> { diff --git a/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/UniqueIndexAsyncAPITest.java b/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/UniqueIndexAsyncAPITest.java index e253729f1ee4b..a1e8e3cdf4972 100644 --- a/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/UniqueIndexAsyncAPITest.java +++ b/examples/src/test/java/com/microsoft/azure/cosmosdb/rx/examples/UniqueIndexAsyncAPITest.java @@ -30,6 +30,7 @@ import com.microsoft.azure.cosmosdb.Document; import com.microsoft.azure.cosmosdb.DocumentClientException; import com.microsoft.azure.cosmosdb.DocumentCollection; +import com.microsoft.azure.cosmosdb.PartitionKeyDefinition; import com.microsoft.azure.cosmosdb.ResourceResponse; import com.microsoft.azure.cosmosdb.UniqueKey; import com.microsoft.azure.cosmosdb.UniqueKeyPolicy; @@ -40,6 +41,7 @@ import rx.Observable; import rx.observers.TestSubscriber; +import java.util.ArrayList; import java.util.Collections; import java.util.UUID; @@ -62,6 +64,11 @@ public void uniqueIndex() { uniqueKey.setPaths(ImmutableList.of("/name", "/field")); uniqueKeyPolicy.setUniqueKeys(Collections.singleton(uniqueKey)); collectionDefinition.setUniqueKeyPolicy(uniqueKeyPolicy); + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.setPaths(paths); + collectionDefinition.setPartitionKey(partitionKeyDef); DocumentCollection collection = client.createCollection(getDatabaseLink(), collectionDefinition, null).toBlocking().single().getResource(); diff --git a/gateway/src/main/java/com/microsoft/azure/cosmosdb/rx/internal/query/DocumentQueryExecutionContextFactory.java b/gateway/src/main/java/com/microsoft/azure/cosmosdb/rx/internal/query/DocumentQueryExecutionContextFactory.java index 4b4b2891dfe58..32a99af6e715a 100644 --- a/gateway/src/main/java/com/microsoft/azure/cosmosdb/rx/internal/query/DocumentQueryExecutionContextFactory.java +++ b/gateway/src/main/java/com/microsoft/azure/cosmosdb/rx/internal/query/DocumentQueryExecutionContextFactory.java @@ -25,8 +25,10 @@ import java.util.List; import java.util.UUID; +import com.microsoft.azure.cosmosdb.BridgeInternal; import com.microsoft.azure.cosmosdb.DocumentCollection; import com.microsoft.azure.cosmosdb.FeedOptions; +import com.microsoft.azure.cosmosdb.PartitionKey; import com.microsoft.azure.cosmosdb.PartitionKeyRange; import com.microsoft.azure.cosmosdb.Resource; import com.microsoft.azure.cosmosdb.SqlQuerySpec; @@ -86,17 +88,21 @@ public static Observable> proxyQueryExecutionContext = - collectionObs.flatMap(collection -> - ProxyDocumentQueryExecutionContext.createAsync( - client, - resourceTypeEnum, - resourceType, - query, - feedOptions, - resourceLink, - collection, - isContinuationExpected, - correlatedActivityId)); + collectionObs.flatMap(collection -> { + if (feedOptions != null && feedOptions.getPartitionKey() != null && feedOptions.getPartitionKey().equals(PartitionKey.None)) { + feedOptions.setPartitionKey(BridgeInternal.getPartitionKey(BridgeInternal.getNonePartitionKey(collection.getPartitionKey()))); + } + return ProxyDocumentQueryExecutionContext.createAsync( + client, + resourceTypeEnum, + resourceType, + query, + feedOptions, + resourceLink, + collection, + isContinuationExpected, + correlatedActivityId); + }); return proxyQueryExecutionContext; } diff --git a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosClient.java b/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosClient.java index 920df75cb493c..5ce31ded234ba 100644 --- a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosClient.java +++ b/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosClient.java @@ -26,13 +26,17 @@ import com.microsoft.azure.cosmosdb.ConnectionPolicy; import com.microsoft.azure.cosmosdb.ConsistencyLevel; import com.microsoft.azure.cosmosdb.Database; +import com.microsoft.azure.cosmosdb.DatabaseAccount; import com.microsoft.azure.cosmosdb.DocumentClientException; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; import com.microsoft.azure.cosmosdb.Permission; import com.microsoft.azure.cosmosdb.SqlQuerySpec; +import com.microsoft.azure.cosmosdb.TokenResolver; import com.microsoft.azure.cosmosdb.internal.HttpConstants; import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; +import com.microsoft.azure.cosmosdb.rx.internal.Configs; + import hu.akarnokd.rxjava.interop.RxJavaInterop; import reactor.adapter.rxjava.RxJava2Adapter; import reactor.core.publisher.Flux; @@ -48,25 +52,31 @@ public class CosmosClient { //Document client wrapper + private final Configs configs; private final AsyncDocumentClient asyncDocumentClient; private final String serviceEndpoint; private final String keyOrResourceToken; private final ConnectionPolicy connectionPolicy; private final ConsistencyLevel desiredConsistencyLevel; private final List permissions; + private final TokenResolver tokenResolver; CosmosClient(CosmosClientBuilder builder) { - this.serviceEndpoint = builder.getServiceEndpoint(); + this.configs = builder.getConfigs(); + this.serviceEndpoint = builder.getServiceEndpoint(); this.keyOrResourceToken = builder.getKeyOrResourceToken(); this.connectionPolicy = builder.getConnectionPolicy(); this.desiredConsistencyLevel = builder.getDesiredConsistencyLevel(); this.permissions = builder.getPermissions(); + this.tokenResolver = builder.getTokenResolver(); this.asyncDocumentClient = new AsyncDocumentClient.Builder() .withServiceEndpoint(this.serviceEndpoint) .withMasterKeyOrResourceToken(this.keyOrResourceToken) .withConnectionPolicy(this.connectionPolicy) .withConsistencyLevel(this.desiredConsistencyLevel) + .withConfigs(this.configs) + .withTokenResolver(this.tokenResolver) .build(); } @@ -130,6 +140,22 @@ AsyncDocumentClient getDocClientWrapper(){ return asyncDocumentClient; } + /** + * Gets the configs + * @return the configs + */ + public Configs getConfigs() { + return configs; + } + + /** + * Gets the token resolver + * @return the token resolver + */ + public TokenResolver getTokenResolver() { + return tokenResolver; + } + /** * Create a Database if it does not already exist on the service * @@ -283,6 +309,10 @@ public Flux> queryDatabases(SqlQuerySpec qu response.getResponseHeaders())))); } + Mono getDatabaseAccount() { + return RxJava2Adapter.singleToMono(RxJavaInterop.toV2Single(asyncDocumentClient.getDatabaseAccount().toSingle())); + } + /** * Gets a database object without making a service call. * diff --git a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosClientBuilder.java b/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosClientBuilder.java index eb0266bc6ecf8..34143019f2f3d 100644 --- a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosClientBuilder.java +++ b/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosClientBuilder.java @@ -25,6 +25,8 @@ import com.microsoft.azure.cosmosdb.ConnectionPolicy; import com.microsoft.azure.cosmosdb.ConsistencyLevel; import com.microsoft.azure.cosmosdb.Permission; +import com.microsoft.azure.cosmosdb.TokenResolver; +import com.microsoft.azure.cosmosdb.rx.internal.Configs; import java.util.List; @@ -47,15 +49,37 @@ */ public class CosmosClientBuilder { + private Configs configs = new Configs(); private String serviceEndpoint; private String keyOrResourceToken; private ConnectionPolicy connectionPolicy; private ConsistencyLevel desiredConsistencyLevel; private List permissions; + private TokenResolver tokenResolver; CosmosClientBuilder() { } + /** + * Configs + * @param configs + * @return current builder + */ + public CosmosClientBuilder configs(Configs configs) { + this.configs = configs; + return this; + } + + /** + * Token Resolver + * @param tokenResolver + * @return current builder + */ + public CosmosClientBuilder tokenResolver(TokenResolver tokenResolver) { + this.tokenResolver = tokenResolver; + return this; + } + /** * The service endpoint url * @param serviceEndpoint the service endpoint @@ -138,15 +162,23 @@ String getKeyOrResourceToken() { return keyOrResourceToken; } - ConnectionPolicy getConnectionPolicy() { + public ConnectionPolicy getConnectionPolicy() { return connectionPolicy; } - ConsistencyLevel getDesiredConsistencyLevel() { + public ConsistencyLevel getDesiredConsistencyLevel() { return desiredConsistencyLevel; } List getPermissions() { return permissions; } + + public Configs getConfigs() { + return configs; + } + + public TokenResolver getTokenResolver() { + return tokenResolver; + } } diff --git a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosContainer.java b/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosContainer.java index e7d31c656818d..9f168dbd83d34 100644 --- a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosContainer.java +++ b/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosContainer.java @@ -31,8 +31,11 @@ import com.microsoft.azure.cosmosdb.StoredProcedure; import com.microsoft.azure.cosmosdb.Trigger; import com.microsoft.azure.cosmosdb.UserDefinedFunction; +import com.microsoft.azure.cosmosdb.internal.Constants; import com.microsoft.azure.cosmosdb.internal.Paths; import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; +import com.microsoft.azure.cosmosdb.internal.routing.PartitionKeyInternal; + import hu.akarnokd.rxjava.interop.RxJavaInterop; import reactor.adapter.rxjava.RxJava2Adapter; import reactor.core.publisher.Flux; @@ -87,11 +90,11 @@ public static String getSelfLink(CosmosContainer cosmosContainer) { * Reads the document container * * After subscription the operation will be performed. - * The {@link Mono} upon successful completion will contain a single cossmos container response with the read + * The {@link Mono} upon successful completion will contain a single cosmos container response with the read * container. * In case of failure the {@link Mono} will error. * - * @return an {@link Mono} containing the single cossmos container response with the read container or an error. + * @return an {@link Mono} containing the single cosmos container response with the read container or an error. */ public Mono read() { return read(new CosmosContainerRequestOptions()); @@ -101,10 +104,11 @@ public Mono read() { * Reads the document container by the container link. * * After subscription the operation will be performed. - * The {@link Mono} upon successful completion will contain a single cossmos container response with the read container. + * The {@link Mono} upon successful completion will contain a single cosmos container response with the read container. * In case of failure the {@link Mono} will error. - * @param options the cosmos container request options - * @return an {@link Mono} containing the single cossmos container response with the read container or an error. + * + * @param options The cosmos container request options. + * @return an {@link Mono} containing the single cosmos container response with the read container or an error. */ public Mono read(CosmosContainerRequestOptions options) { if (options == null) { @@ -119,11 +123,11 @@ public Mono read(CosmosContainerRequestOptions options) * Deletes the item container * * After subscription the operation will be performed. - * The {@link Mono} upon successful completion will contain a single cossmos container response for the deleted database. + * The {@link Mono} upon successful completion will contain a single cosmos container response for the deleted database. * In case of failure the {@link Mono} will error. * * @param options the request options. - * @return an {@link Mono} containing the single cossmos container response for the deleted database or an error. + * @return an {@link Mono} containing the single cosmos container response for the deleted database or an error. */ public Mono delete(CosmosContainerRequestOptions options) { if (options == null) { @@ -143,7 +147,7 @@ public Mono delete(CosmosContainerRequestOptions option * The {@link Mono} upon successful completion will contain a single cosmos container response for the deleted container. * In case of failure the {@link Mono} will error. * - * @return an {@link Mono} containing the single cossmos container response for the deleted container or an error. + * @return an {@link Mono} containing the single cosmos container response for the deleted container or an error. */ public Mono delete() { return delete(new CosmosContainerRequestOptions()); @@ -153,12 +157,12 @@ public Mono delete() { * Replaces a document container. * * After subscription the operation will be performed. - * The {@link Mono} upon successful completion will contain a single cossmos container response with the replaced document container. + * The {@link Mono} upon successful completion will contain a single cosmos container response with the replaced document container. * In case of failure the {@link Mono} will error. * * @param containerSettings the item container settings * @param options the cosmos container request options. - * @return an {@link Mono} containing the single cossmos container response with the replaced document container or an error. + * @return an {@link Mono} containing the single cosmos container response with the replaced document container or an error. */ public Mono replace(CosmosContainerSettings containerSettings, CosmosContainerRequestOptions options) { @@ -186,7 +190,7 @@ public Mono replace(CosmosContainerSettings containerSe * @return an {@link Mono} containing the single resource response with the created cosmos item or an error. */ public Mono createItem(Object item){ - return createItem(item, null); + return createItem(item, new CosmosItemRequestOptions()); } /** @@ -232,6 +236,35 @@ public Mono createItem(Object item, CosmosItemRequestOptions .toSingle())); } + /** + * Upserts an item. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response with the upserted item. + * In case of failure the {@link Mono} will error. + * + * @param item the item represented as a POJO or Item object to upsert. + * @return an {@link Mono} containing the single resource response with the upserted document or an error. + */ + public Mono upsertItem(Object item) { + return upsertItem(item, new CosmosItemRequestOptions()); + } + + /** + * Upserts an item. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single resource response with the upserted item. + * In case of failure the {@link Mono} will error. + * + * @param item the item represented as a POJO or Item object to upsert. + * @param partitionKey the partitionKey to be used. + * @return an {@link Mono} containing the single resource response with the upserted document or an error. + */ + public Mono upsertItem(Object item, Object partitionKey) { + return upsertItem(item, new CosmosItemRequestOptions(partitionKey)); + } + /** * Upserts a cosmos item. * @@ -362,6 +395,21 @@ public CosmosItem getItem(String id, Object partitionKey){ /* CosmosStoredProcedure operations */ + /** + * Creates a cosmos stored procedure. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single cosmos stored procedure response with the + * created cosmos stored procedure. + * In case of failure the {@link Mono} will error. + * + * @param settings the cosmos stored procedure settings. + * @return an {@link Mono} containing the single cosmos stored procedure resource response or an error. + */ + public Mono createStoredProcedure(CosmosStoredProcedureSettings settings){ + return this.createStoredProcedure(settings, new CosmosStoredProcedureRequestOptions()); + } + /** * Creates a cosmos stored procedure. * diff --git a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosDatabase.java b/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosDatabase.java index e8306ff8bc7f0..75fb16970a13e 100644 --- a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosDatabase.java +++ b/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosDatabase.java @@ -282,15 +282,19 @@ public Flux> queryContainers(SqlQuerySpec public CosmosContainer getContainer(String id) { return new CosmosContainer(id, this); } - + /** User operations **/ + public Mono createUser(CosmosUserSettings settings) { + return this.createUser(settings, null); + } + /** * Creates a user * After subscription the operation will be performed. * The {@link Mono} upon successful completion will contain a single resource response with the created user. * In case of failure the {@link Mono} will error. - * + * * @param settings the cosmos user settings * @param options the request options * @return an {@link Mono} containing the single resource response with the created cosmos user or an error. @@ -298,7 +302,11 @@ public CosmosContainer getContainer(String id) { public Mono createUser(CosmosUserSettings settings, RequestOptions options){ return RxJava2Adapter.singleToMono(RxJavaInterop.toV2Single(getDocClientWrapper().createUser(this.getLink(), settings.getV2User(), options).map(response -> - new CosmosUserResponse(response, this)).toSingle())); + new CosmosUserResponse(response, this)).toSingle())); + } + + public Mono upsertUser(CosmosUserSettings settings) { + return this.upsertUser(settings, null); } /** @@ -306,7 +314,7 @@ public Mono createUser(CosmosUserSettings settings, RequestO * After subscription the operation will be performed. * The {@link Mono} upon successful completion will contain a single resource response with the created user. * In case of failure the {@link Mono} will error. - * + * * @param settings the cosmos user settings * @param options the request options * @return an {@link Mono} containing the single resource response with the upserted user or an error. @@ -317,6 +325,10 @@ public Mono upsertUser(CosmosUserSettings settings, RequestO new CosmosUserResponse(response, this)).toSingle())); } + public Flux> listUsers() { + return listUsers(new FeedOptions()); + } + /** * Reads all cosmos users in a database. * @@ -335,10 +347,14 @@ public Flux> listUsers(FeedOptions options){ response.getResponseHeaders())))); } + public Flux> queryUsers(String query, FeedOptions options){ + return queryUsers(new SqlQuerySpec(query), options); + } + /** * Query for cosmos users in a database. * - * After subscription the operation will be performed. + * After subscription the operation will be performed. * The {@link Flux} will contain one or several feed response of the obtained users. * In case of failure the {@link Flux} will error. * @@ -355,6 +371,10 @@ public Flux> queryUsers(SqlQuerySpec querySpec, response.getResponseHeaders(), response.getQueryMetrics())))); } + public CosmosUser getUser(String id) { + return new CosmosUser(id, this); + } + CosmosClient getClient() { return client; } diff --git a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosItem.java b/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosItem.java index fca34f5d8480c..883abecd108f8 100644 --- a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosItem.java +++ b/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosItem.java @@ -1,163 +1,162 @@ -/* - * The MIT License (MIT) - * Copyright (c) 2018 Microsoft Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.microsoft.azure.cosmos; - -import com.microsoft.azure.cosmosdb.Document; -import com.microsoft.azure.cosmosdb.RequestOptions; -import com.microsoft.azure.cosmosdb.internal.Paths; -import hu.akarnokd.rxjava.interop.RxJavaInterop; -import reactor.adapter.rxjava.RxJava2Adapter; -import reactor.core.publisher.Mono; - -public class CosmosItem extends CosmosResource{ - private Object partitionKey; - private CosmosContainer container; - - CosmosItem(String id, Object partitionKey, CosmosContainer container) { - super(id); - this.partitionKey = partitionKey; - this.container = container; - } - - /** - * Reads an item. - * - * After subscription the operation will be performed. - * The {@link Mono} upon successful completion will contain a cosmos item response with the read item - * In case of failure the {@link Mono} will error. - * - * @return an {@link Mono} containing the cosmos item response with the read item or an error - */ - public Mono read() { - return read(new CosmosItemRequestOptions(partitionKey)); - } - - /** - * Reads an item. - * - * After subscription the operation will be performed. - * The {@link Mono} upon successful completion will contain a cosmos item response with the read item - * In case of failure the {@link Mono} will error. - * - * @param options the request comosItemRequestOptions - * @return an {@link Mono} containing the cosmos item response with the read item or an error - */ - public Mono read(CosmosItemRequestOptions options) { - if (options == null) { - options = new CosmosItemRequestOptions(); - } - RequestOptions requestOptions = options.toRequestOptions(); - return RxJava2Adapter.singleToMono(RxJavaInterop.toV2Single(container.getDatabase().getDocClientWrapper() - .readDocument(getLink(), requestOptions) - .map(response -> new CosmosItemResponse(response, requestOptions.getPartitionKey(), container)) - .toSingle())); - } - - /** - * Replaces an item with the passed in item. - * - * After subscription the operation will be performed. - * The {@link Mono} upon successful completion will contain a single cosmos item response with the replaced item. - * In case of failure the {@link Mono} will error. - * - * @param item the item to replace (containing the document id). - * @return an {@link Mono} containing the cosmos item resource response with the replaced item or an error. - */ - public Mono replace(Object item){ - return replace(item, new CosmosItemRequestOptions(partitionKey)); - } - - /** - * Replaces an item with the passed in item. - * - * After subscription the operation will be performed. - * The {@link Mono} upon successful completion will contain a single cosmos item response with the replaced item. - * In case of failure the {@link Mono} will error. - * - * @param item the item to replace (containing the document id). - * @param options the request comosItemRequestOptions - * @return an {@link Mono} containing the cosmos item resource response with the replaced item or an error. - */ - public Mono replace(Object item, CosmosItemRequestOptions options){ - Document doc = CosmosItemSettings.fromObject(item); - if (options == null) { - options = new CosmosItemRequestOptions(); - } - RequestOptions requestOptions = options.toRequestOptions(); - return RxJava2Adapter.singleToMono(RxJavaInterop.toV2Single(container.getDatabase() - .getDocClientWrapper() - .replaceDocument(getLink(), doc, requestOptions) - .map(response -> new CosmosItemResponse(response, requestOptions.getPartitionKey(), container)) - .toSingle())); - } - - /** - * Deletes the item. - * - * After subscription the operation will be performed. - * The {@link Mono} upon successful completion will contain a single cosmos item response with the replaced item. - * In case of failure the {@link Mono} will error. - * @return an {@link Mono} containing the cosmos item resource response. - */ - public Mono delete() { - return delete(new CosmosItemRequestOptions(partitionKey)); - } - - /** - * Deletes the item. - * - * After subscription the operation will be performed. - * The {@link Mono} upon successful completion will contain a single cosmos item response with the replaced item. - * In case of failure the {@link Mono} will error. - * - * @param options the request options - * @return an {@link Mono} containing the cosmos item resource response. - */ - public Mono delete(CosmosItemRequestOptions options){ - if (options == null) { - options = new CosmosItemRequestOptions(); - } - RequestOptions requestOptions = options.toRequestOptions(); - return RxJava2Adapter.singleToMono( - RxJavaInterop.toV2Single(container.getDatabase() - .getDocClientWrapper() - .deleteDocument(getLink(), requestOptions) - .map(response -> new CosmosItemResponse(response, requestOptions.getPartitionKey(), container)) - .toSingle())); - } - - void setContainer(CosmosContainer container) { - this.container = container; - } - - @Override - protected String getURIPathSegment() { - return Paths.DOCUMENTS_PATH_SEGMENT; - } - - @Override - protected String getParentLink() { - return this.container.getLink(); - } - -} +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.microsoft.azure.cosmos; + +import com.microsoft.azure.cosmosdb.Document; +import com.microsoft.azure.cosmosdb.RequestOptions; +import com.microsoft.azure.cosmosdb.internal.Paths; +import hu.akarnokd.rxjava.interop.RxJavaInterop; +import reactor.adapter.rxjava.RxJava2Adapter; +import reactor.core.publisher.Mono; + +public class CosmosItem extends CosmosResource{ + private Object partitionKey; + private CosmosContainer container; + + CosmosItem(String id, Object partitionKey, CosmosContainer container) { + super(id); + this.partitionKey = partitionKey; + this.container = container; + } + + /** + * Reads an item. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a cosmos item response with the read item + * In case of failure the {@link Mono} will error. + * + * @return an {@link Mono} containing the cosmos item response with the read item or an error + */ + public Mono read() { + return read(new CosmosItemRequestOptions(partitionKey)); + } + + /** + * Reads an item. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a cosmos item response with the read item + * In case of failure the {@link Mono} will error. + * + * @param options the request comosItemRequestOptions + * @return an {@link Mono} containing the cosmos item response with the read item or an error + */ + public Mono read(CosmosItemRequestOptions options) { + if (options == null) { + options = new CosmosItemRequestOptions(); + } + RequestOptions requestOptions = options.toRequestOptions(); + return RxJava2Adapter.singleToMono(RxJavaInterop.toV2Single(container.getDatabase().getDocClientWrapper() + .readDocument(getLink(), requestOptions) + .map(response -> new CosmosItemResponse(response, requestOptions.getPartitionKey(), container)) + .toSingle())); + } + + /** + * Replaces an item with the passed in item. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single cosmos item response with the replaced item. + * In case of failure the {@link Mono} will error. + * + * @param item the item to replace (containing the document id). + * @return an {@link Mono} containing the cosmos item resource response with the replaced item or an error. + */ + public Mono replace(Object item){ + return replace(item, new CosmosItemRequestOptions(partitionKey)); + } + + /** + * Replaces an item with the passed in item. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single cosmos item response with the replaced item. + * In case of failure the {@link Mono} will error. + * + * @param item the item to replace (containing the document id). + * @param options the request comosItemRequestOptions + * @return an {@link Mono} containing the cosmos item resource response with the replaced item or an error. + */ + public Mono replace(Object item, CosmosItemRequestOptions options){ + Document doc = CosmosItemSettings.fromObject(item); + if (options == null) { + options = new CosmosItemRequestOptions(); + } + RequestOptions requestOptions = options.toRequestOptions(); + return RxJava2Adapter.singleToMono(RxJavaInterop.toV2Single(container.getDatabase() + .getDocClientWrapper() + .replaceDocument(getLink(), doc, requestOptions) + .map(response -> new CosmosItemResponse(response, requestOptions.getPartitionKey(), container)) + .toSingle())); + } + + /** + * Deletes the item. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single cosmos item response with the replaced item. + * In case of failure the {@link Mono} will error. + * @return an {@link Mono} containing the cosmos item resource response. + */ + public Mono delete() { + return delete(new CosmosItemRequestOptions(partitionKey)); + } + + /** + * Deletes the item. + * + * After subscription the operation will be performed. + * The {@link Mono} upon successful completion will contain a single cosmos item response with the replaced item. + * In case of failure the {@link Mono} will error. + * + * @param options the request options + * @return an {@link Mono} containing the cosmos item resource response. + */ + public Mono delete(CosmosItemRequestOptions options){ + if (options == null) { + options = new CosmosItemRequestOptions(); + } + RequestOptions requestOptions = options.toRequestOptions(); + return RxJava2Adapter.singleToMono( + RxJavaInterop.toV2Single(container.getDatabase() + .getDocClientWrapper() + .deleteDocument(getLink(), requestOptions) + .map(response -> new CosmosItemResponse(response, requestOptions.getPartitionKey(), container)) + .toSingle())); + } + + void setContainer(CosmosContainer container) { + this.container = container; + } + + @Override + protected String getURIPathSegment() { + return Paths.DOCUMENTS_PATH_SEGMENT; + } + + @Override + protected String getParentLink() { + return this.container.getLink(); + } +} diff --git a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosItemResponse.java b/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosItemResponse.java index f150206113cf8..5d4024d6bc004 100644 --- a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosItemResponse.java +++ b/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosItemResponse.java @@ -1,57 +1,65 @@ -/* - * The MIT License (MIT) - * Copyright (c) 2018 Microsoft Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.microsoft.azure.cosmos; - -import com.microsoft.azure.cosmosdb.Document; -import com.microsoft.azure.cosmosdb.PartitionKey; -import com.microsoft.azure.cosmosdb.ResourceResponse; - -public class CosmosItemResponse extends CosmosResponse{ - private CosmosItem itemClient; - - CosmosItemResponse(ResourceResponse response, PartitionKey partitionKey, CosmosContainer container) { - super(response); - if(response.getResource() == null){ - super.setResourceSettings(null); - }else{ - super.setResourceSettings(new CosmosItemSettings(response.getResource().toJson())); - itemClient = new CosmosItem(response.getResource().getId(),partitionKey, container); - } - } - - /** - * Gets the itemSettings - * @return the itemSettings - */ - public CosmosItemSettings getCosmosItemSettings() { - return getResourceSettings(); - } - - /** - * Gets the CosmosItem - * @return the cosmos item - */ - public CosmosItem getItem() { - return itemClient; - } -} +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.microsoft.azure.cosmos; + +import com.microsoft.azure.cosmosdb.Document; +import com.microsoft.azure.cosmosdb.PartitionKey; +import com.microsoft.azure.cosmosdb.ResourceResponse; + +public class CosmosItemResponse extends CosmosResponse{ + private CosmosItem itemClient; + + CosmosItemResponse(ResourceResponse response, PartitionKey partitionKey, CosmosContainer container) { + super(response); + if(response.getResource() == null){ + super.setResourceSettings(null); + }else{ + super.setResourceSettings(new CosmosItemSettings(response.getResource().toJson())); + itemClient = new CosmosItem(response.getResource().getId(),partitionKey, container); + } + } + + /** + * Gets the itemSettings + * @return the itemSettings + */ + public CosmosItemSettings getCosmosItemSettings() { + return getResourceSettings(); + } + + /** + * Gets the CosmosItem + * @return the cosmos item + */ + public CosmosItem getItem() { + return itemClient; + } + + /** + * Gets the CosmosItem + * @return the cosmos item + */ + public CosmosItem getCosmosItem() { + return itemClient; + } +} \ No newline at end of file diff --git a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosTriggerResponse.java b/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosTriggerResponse.java index 6dd0b4593f36c..cbdaa7130016b 100644 --- a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosTriggerResponse.java +++ b/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosTriggerResponse.java @@ -33,6 +33,7 @@ public class CosmosTriggerResponse extends CosmosResponse CosmosTriggerResponse(ResourceResponse response, CosmosContainer container) { super(response); if(response.getResource() != null) { + super.setResourceSettings(new CosmosTriggerSettings(response)); cosmosTriggerSettings = new CosmosTriggerSettings(response); cosmosTrigger = new CosmosTrigger(cosmosTriggerSettings.getId(), container); } diff --git a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosUser.java b/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosUser.java index 511f1654e5626..fc8b3cc7f8f1a 100644 --- a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosUser.java +++ b/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosUser.java @@ -15,7 +15,14 @@ public CosmosUser(String id, CosmosDatabase database) { /** * Reads a cosmos user - * + * @return an {@link Mono} containing the single cosmos user response with the read user or an error. + */ + public Mono read() { + return this.read(null); + } + + /** + * Reads a cosmos user * @param options the request options * @return a {@link Mono} containing the single resource response with the read user or an error. */ @@ -59,4 +66,4 @@ protected String getURIPathSegment() { protected String getParentLink() { return database.getLink() ; } -} +} \ No newline at end of file diff --git a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosUserDefinedFunctionResponse.java b/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosUserDefinedFunctionResponse.java index 2b4f301b9a45d..59251a9f93c12 100644 --- a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosUserDefinedFunctionResponse.java +++ b/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosUserDefinedFunctionResponse.java @@ -1,56 +1,57 @@ -/* - * The MIT License (MIT) - * Copyright (c) 2018 Microsoft Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.microsoft.azure.cosmos; - -import com.microsoft.azure.cosmosdb.ResourceResponse; -import com.microsoft.azure.cosmosdb.UserDefinedFunction; - -public class CosmosUserDefinedFunctionResponse extends CosmosResponse { - - private CosmosUserDefinedFunctionSettings cosmosUserDefinedFunctionSettings; - private CosmosUserDefinedFunction cosmosUserDefinedFunction; - - CosmosUserDefinedFunctionResponse(ResourceResponse response, CosmosContainer container) { - super(response); - if(response.getResource() != null) { - cosmosUserDefinedFunctionSettings = new CosmosUserDefinedFunctionSettings(response); - cosmosUserDefinedFunction = new CosmosUserDefinedFunction(cosmosUserDefinedFunctionSettings.getId(), container); - } - } - - /** - * Gets the cosmos user defined function settings - * @return the cosmos user defined function settings - */ - public CosmosUserDefinedFunctionSettings getCosmosUserDefinedFunctionSettings() { - return cosmosUserDefinedFunctionSettings; - } - - /** - * Gets the cosmos user defined function object - * @return the cosmos user defined function object - */ - public CosmosUserDefinedFunction getCosmosUserDefinedFunction() { - return cosmosUserDefinedFunction; - } -} +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.microsoft.azure.cosmos; + +import com.microsoft.azure.cosmosdb.ResourceResponse; +import com.microsoft.azure.cosmosdb.UserDefinedFunction; + +public class CosmosUserDefinedFunctionResponse extends CosmosResponse { + + private CosmosUserDefinedFunctionSettings cosmosUserDefinedFunctionSettings; + private CosmosUserDefinedFunction cosmosUserDefinedFunction; + + CosmosUserDefinedFunctionResponse(ResourceResponse response, CosmosContainer container) { + super(response); + if(response.getResource() != null) { + super.setResourceSettings(new CosmosUserDefinedFunctionSettings(response)); + cosmosUserDefinedFunctionSettings = new CosmosUserDefinedFunctionSettings(response); + cosmosUserDefinedFunction = new CosmosUserDefinedFunction(cosmosUserDefinedFunctionSettings.getId(), container); + } + } + + /** + * Gets the cosmos user defined function settings + * @return the cosmos user defined function settings + */ + public CosmosUserDefinedFunctionSettings getCosmosUserDefinedFunctionSettings() { + return cosmosUserDefinedFunctionSettings; + } + + /** + * Gets the cosmos user defined function object + * @return the cosmos user defined function object + */ + public CosmosUserDefinedFunction getCosmosUserDefinedFunction() { + return cosmosUserDefinedFunction; + } +} diff --git a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosUserResponse.java b/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosUserResponse.java index a4b170353c182..6b9f8b9a36ef8 100644 --- a/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosUserResponse.java +++ b/sdk/src/main/java/com/microsoft/azure/cosmos/CosmosUserResponse.java @@ -34,5 +34,5 @@ public CosmosUserSettings getCosmosUserSettings(){ return getResourceSettings(); } - + } diff --git a/sdk/src/main/java/com/microsoft/azure/cosmosdb/rx/internal/RxDocumentClientImpl.java b/sdk/src/main/java/com/microsoft/azure/cosmosdb/rx/internal/RxDocumentClientImpl.java index 40c9ba72a7fe5..e79e27b859c4a 100644 --- a/sdk/src/main/java/com/microsoft/azure/cosmosdb/rx/internal/RxDocumentClientImpl.java +++ b/sdk/src/main/java/com/microsoft/azure/cosmosdb/rx/internal/RxDocumentClientImpl.java @@ -909,10 +909,6 @@ private Map getRequestHeaders(RequestOptions options) { headers.put(HttpConstants.HttpHeaders.OFFER_TYPE, options.getOfferType()); } - if (options.getPartitionKey() != null) { - headers.put(HttpConstants.HttpHeaders.PARTITION_KEY, options.getPartitionKey().toString()); - } - if (options.isPopulateQuotaInfo()) { headers.put(HttpConstants.HttpHeaders.POPULATE_QUOTA_INFO, String.valueOf(true)); } @@ -972,7 +968,9 @@ private void addPartitionKeyInformation(RxDocumentServiceRequest request, Docume PartitionKeyDefinition partitionKeyDefinition = collection.getPartitionKey(); PartitionKeyInternal partitionKeyInternal = null; - if (options != null && options.getPartitionKey() != null) { + if (options != null && options.getPartitionKey() != null && options.getPartitionKey().equals(PartitionKey.None)){ + partitionKeyInternal = BridgeInternal.getNonePartitionKey(partitionKeyDefinition); + } else if (options != null && options.getPartitionKey() != null) { partitionKeyInternal = options.getPartitionKey().getInternalPartitionKey(); } else if (partitionKeyDefinition == null || partitionKeyDefinition.getPaths().size() == 0) { // For backward compatibility, if collection doesn't have partition key defined, we assume all documents @@ -1009,10 +1007,14 @@ private static PartitionKeyInternal extractPartitionKeyValueFromDocument( if (parts.size() >= 1) { Object value = document.getObjectByPath(parts); if (value == null || value.getClass() == ObjectNode.class) { - value = Undefined.Value(); + value = BridgeInternal.getNonePartitionKey(partitionKeyDefinition); } - return PartitionKeyInternal.fromObjectArray(Collections.singletonList(value), false); + if (value instanceof PartitionKeyInternal) { + return (PartitionKeyInternal) value; + } else { + return PartitionKeyInternal.fromObjectArray(Collections.singletonList(value), false); + } } } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ClientUnderTestBuilder.java b/sdk/src/test/java/com/microsoft/azure/cosmos/ClientUnderTestBuilder.java similarity index 50% rename from sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ClientUnderTestBuilder.java rename to sdk/src/test/java/com/microsoft/azure/cosmos/ClientUnderTestBuilder.java index 914014c2bb2c7..d7fcc8954e705 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ClientUnderTestBuilder.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmos/ClientUnderTestBuilder.java @@ -20,28 +20,39 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.microsoft.azure.cosmosdb.rx; +package com.microsoft.azure.cosmos; + +import java.net.URI; +import java.net.URISyntaxException; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; import com.microsoft.azure.cosmosdb.rx.internal.RxDocumentClientUnderTest; +import com.microsoft.azure.cosmosdb.rx.internal.directconnectivity.ReflectionUtils; -public class ClientUnderTestBuilder extends Builder { +public class ClientUnderTestBuilder extends CosmosClientBuilder { - public ClientUnderTestBuilder(Builder builder) { - this.configs = builder.configs; - this.connectionPolicy = builder.connectionPolicy; - this.desiredConsistencyLevel = builder.desiredConsistencyLevel; - this.masterKeyOrResourceToken = builder.masterKeyOrResourceToken; - this.serviceEndpoint = builder.serviceEndpoint; + public ClientUnderTestBuilder(CosmosClientBuilder builder) { + this.configs(builder.getConfigs()); + this.connectionPolicy(builder.getConnectionPolicy()); + this.consistencyLevel(builder.getDesiredConsistencyLevel()); + this.key(builder.getKeyOrResourceToken()); + this.endpoint(builder.getServiceEndpoint()); } @Override - public RxDocumentClientUnderTest build() { - return new RxDocumentClientUnderTest( - this.serviceEndpoint, - this.masterKeyOrResourceToken, - this.connectionPolicy, - this.desiredConsistencyLevel, - this.configs); + public CosmosClient build() { + RxDocumentClientUnderTest rxClient; + try { + rxClient = new RxDocumentClientUnderTest( + new URI(this.getServiceEndpoint()), + this.getKeyOrResourceToken(), + this.getConnectionPolicy(), + this.getDesiredConsistencyLevel(), + this.getConfigs()); + } catch (URISyntaxException e) { + throw new IllegalArgumentException(e.getMessage()); + } + CosmosClient cosmosClient = super.build(); + ReflectionUtils.setAsyncDocumentClient(cosmosClient, rxClient); + return cosmosClient; } } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmos/CosmosBridgeInternal.java b/sdk/src/test/java/com/microsoft/azure/cosmos/CosmosBridgeInternal.java new file mode 100644 index 0000000000000..9e12488d5a0c6 --- /dev/null +++ b/sdk/src/test/java/com/microsoft/azure/cosmos/CosmosBridgeInternal.java @@ -0,0 +1,34 @@ +package com.microsoft.azure.cosmos; + +import com.microsoft.azure.cosmosdb.DatabaseAccount; +import com.microsoft.azure.cosmosdb.DocumentCollection; +import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; + +import reactor.core.publisher.Mono; + +public class CosmosBridgeInternal { + + public static String getLink(CosmosResource resource) { + return resource.getLink(); + } + + public static DocumentCollection toDocumentCollection(CosmosContainerSettings cosmosContainerSettings) { + return new DocumentCollection(cosmosContainerSettings.toJson()); + } + + public static AsyncDocumentClient getAsyncDocumentClient(CosmosClient client) { + return client.getDocClientWrapper(); + } + + public static CosmosDatabase getCosmosDatabaseWithNewClient(CosmosDatabase cosmosDatabase, CosmosClient client) { + return new CosmosDatabase(cosmosDatabase.getId(), client); + } + + public static CosmosContainer getCosmosContainerWithNewClient(CosmosContainer cosmosContainer, CosmosDatabase cosmosDatabase, CosmosClient client) { + return new CosmosContainer(cosmosContainer.getId(), CosmosBridgeInternal.getCosmosDatabaseWithNewClient(cosmosDatabase, client)); + } + + public static Mono getDatabaseAccount(CosmosClient client) { + return client.getDatabaseAccount(); + } +} diff --git a/sdk/src/test/java/com/microsoft/azure/cosmos/CosmosDatabaseForTest.java b/sdk/src/test/java/com/microsoft/azure/cosmos/CosmosDatabaseForTest.java new file mode 100644 index 0000000000000..925f1836878f3 --- /dev/null +++ b/sdk/src/test/java/com/microsoft/azure/cosmos/CosmosDatabaseForTest.java @@ -0,0 +1,137 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.microsoft.azure.cosmos; + +import org.apache.commons.lang3.RandomStringUtils; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.microsoft.azure.cosmos.CosmosDatabaseSettings; +import com.microsoft.azure.cosmosdb.FeedResponse; +import com.microsoft.azure.cosmosdb.SqlParameter; +import com.microsoft.azure.cosmosdb.SqlParameterCollection; +import com.microsoft.azure.cosmosdb.SqlQuerySpec; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +public class CosmosDatabaseForTest { + private static Logger logger = LoggerFactory.getLogger(CosmosDatabaseForTest.class); + public static final String SHARED_DB_ID_PREFIX = "RxJava.SDKTest.SharedDatabase"; + private static final Duration CLEANUP_THRESHOLD_DURATION = Duration.ofHours(2); + private static final String DELIMITER = "_"; + private static DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss"); + + public LocalDateTime createdTime; + public CosmosDatabase createdDatabase; + + private CosmosDatabaseForTest(CosmosDatabase db, LocalDateTime createdTime) { + this.createdDatabase = db; + this.createdTime = createdTime; + } + + private boolean isStale() { + return isOlderThan(CLEANUP_THRESHOLD_DURATION); + } + + private boolean isOlderThan(Duration dur) { + return createdTime.isBefore(LocalDateTime.now().minus(dur)); + } + + public static String generateId() { + return SHARED_DB_ID_PREFIX + DELIMITER + TIME_FORMATTER.format(LocalDateTime.now()) + DELIMITER + RandomStringUtils.randomAlphabetic(3); + } + + private static CosmosDatabaseForTest from(CosmosDatabase db) { + if (db == null || db.getId() == null || db.getLink() == null) { + return null; + } + + String id = db.getId(); + if (id == null) { + return null; + } + + String[] parts = StringUtils.split(id, DELIMITER); + if (parts.length != 3) { + return null; + } + if (!StringUtils.equals(parts[0], SHARED_DB_ID_PREFIX)) { + return null; + } + + try { + LocalDateTime parsedTime = LocalDateTime.parse(parts[1], TIME_FORMATTER); + return new CosmosDatabaseForTest(db, parsedTime); + } catch (Exception e) { + return null; + } + } + + public static CosmosDatabaseForTest create(DatabaseManager client) { + CosmosDatabaseSettings dbDef = new CosmosDatabaseSettings(generateId()); + + CosmosDatabase db = client.createDatabase(dbDef).block().getDatabase(); + CosmosDatabaseForTest dbForTest = CosmosDatabaseForTest.from(db); + assertThat(dbForTest).isNotNull(); + return dbForTest; + } + + public static void cleanupStaleTestDatabases(DatabaseManager client) { + logger.info("Cleaning stale test databases ..."); + List dbs = client.queryDatabases( + new SqlQuerySpec("SELECT * FROM c WHERE STARTSWITH(c.id, @PREFIX)", + new SqlParameterCollection(new SqlParameter("@PREFIX", CosmosDatabaseForTest.SHARED_DB_ID_PREFIX)))) + .flatMap(page -> Flux.fromIterable(page.getResults())).collectList().block(); + + for (CosmosDatabaseSettings db : dbs) { + assertThat(db.getId()).startsWith(CosmosDatabaseForTest.SHARED_DB_ID_PREFIX); + + CosmosDatabaseForTest dbForTest = CosmosDatabaseForTest.from(client.getDatabase(db.getId())); + + if (db != null && dbForTest.isStale()) { + logger.info("Deleting database {}", db.getId()); + dbForTest.deleteDatabase(db.getId()); + } + } + } + + private void deleteDatabase(String id) { + this.createdDatabase.delete().block(); + } + + public interface DatabaseManager { + Flux> queryDatabases(SqlQuerySpec query); + Mono createDatabase(CosmosDatabaseSettings databaseDefinition); + CosmosDatabase getDatabase(String id); + } +} diff --git a/sdk/src/test/java/com/microsoft/azure/cosmos/CosmosPartitionKeyTests.java b/sdk/src/test/java/com/microsoft/azure/cosmos/CosmosPartitionKeyTests.java new file mode 100644 index 0000000000000..eff5aa465293d --- /dev/null +++ b/sdk/src/test/java/com/microsoft/azure/cosmos/CosmosPartitionKeyTests.java @@ -0,0 +1,331 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.microsoft.azure.cosmos; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import org.apache.commons.io.IOUtils; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; + +import com.microsoft.azure.cosmosdb.ConnectionPolicy; +import com.microsoft.azure.cosmosdb.Document; +import com.microsoft.azure.cosmosdb.DocumentCollection; +import com.microsoft.azure.cosmosdb.FeedOptions; +import com.microsoft.azure.cosmosdb.FeedResponse; +import com.microsoft.azure.cosmosdb.PartitionKey; +import com.microsoft.azure.cosmosdb.RequestOptions; +import com.microsoft.azure.cosmosdb.internal.BaseAuthorizationTokenProvider; +import com.microsoft.azure.cosmosdb.internal.HttpConstants; +import com.microsoft.azure.cosmosdb.internal.OperationType; +import com.microsoft.azure.cosmosdb.internal.Paths; +import com.microsoft.azure.cosmosdb.internal.ResourceType; +import com.microsoft.azure.cosmosdb.internal.Utils; +import com.microsoft.azure.cosmosdb.rx.FeedResponseListValidator; +import com.microsoft.azure.cosmosdb.rx.TestConfigurations; +import com.microsoft.azure.cosmosdb.rx.TestSuiteBase; +import com.microsoft.azure.cosmosdb.rx.internal.Configs; +import com.microsoft.azure.cosmosdb.rx.internal.HttpClientFactory; +import com.microsoft.azure.cosmosdb.rx.internal.RxDocumentServiceRequest; + +import io.netty.buffer.ByteBuf; +import io.netty.handler.codec.http.HttpMethod; +import io.reactivex.netty.client.RxClient; +import io.reactivex.netty.protocol.http.client.CompositeHttpClient; +import io.reactivex.netty.protocol.http.client.HttpClientRequest; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import rx.Observable; + +public class CosmosPartitionKeyTests extends TestSuiteBase { + + private final static String NON_PARTITIONED_CONTAINER_ID = "NonPartitionContainer" + UUID.randomUUID().toString(); + private final static String NON_PARTITIONED_CONTAINER_DOCUEMNT_ID = "NonPartitionContainer_Document" + UUID.randomUUID().toString(); + + private CosmosClient client; + private CosmosDatabase createdDatabase; + private CosmosClientBuilder clientBuilder; + + @Factory(dataProvider = "clientBuilders") + public CosmosPartitionKeyTests(CosmosClientBuilder clientBuilder) { + this.clientBuilder = clientBuilder; + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() throws URISyntaxException, IOException { + client = clientBuilder.build(); + createdDatabase = getSharedCosmosDatabase(client); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeDeleteDatabase(createdDatabase); + safeClose(client); + } + + private void createContainerWithoutPk() throws URISyntaxException, IOException { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + HttpClientFactory factory = new HttpClientFactory(new Configs()) + .withMaxIdleConnectionTimeoutInMillis(connectionPolicy.getIdleConnectionTimeoutInMillis()) + .withPoolSize(connectionPolicy.getMaxPoolSize()) + .withHttpProxy(connectionPolicy.getProxy()) + .withRequestTimeoutInMillis(connectionPolicy.getRequestTimeoutInMillis()); + + CompositeHttpClient httpClient = factory.toHttpClientBuilder().build(); + + // Create a non partitioned collection using the rest API and older version + String resourceId = Paths.DATABASES_PATH_SEGMENT + "/" + createdDatabase.getId(); + String path = Paths.DATABASES_PATH_SEGMENT + "/" + createdDatabase.getId() + "/" + Paths.COLLECTIONS_PATH_SEGMENT + "/"; + DocumentCollection collection = new DocumentCollection(); + collection.setId(NON_PARTITIONED_CONTAINER_ID); + + HashMap headers = new HashMap(); + headers.put(HttpConstants.HttpHeaders.X_DATE, Utils.nowAsRFC1123()); + headers.put(HttpConstants.HttpHeaders.VERSION, "2018-09-17"); + BaseAuthorizationTokenProvider base = new BaseAuthorizationTokenProvider(TestConfigurations.MASTER_KEY); + String authorization = base.generateKeyAuthorizationSignature(HttpConstants.HttpMethods.POST, resourceId, Paths.COLLECTIONS_PATH_SEGMENT, headers); + headers.put(HttpConstants.HttpHeaders.AUTHORIZATION, URLEncoder.encode(authorization, "UTF-8")); + RxDocumentServiceRequest request = RxDocumentServiceRequest.create(OperationType.Create, + ResourceType.DocumentCollection, path, collection, headers, new RequestOptions()); + + String[] baseUrlSplit = TestConfigurations.HOST.split(":"); + String resourceUri = baseUrlSplit[0] + ":" + baseUrlSplit[1] + ":" + baseUrlSplit[2].split("/")[ + 0] + "//" + Paths.DATABASES_PATH_SEGMENT + "/" + createdDatabase.getId() + "/" + Paths.COLLECTIONS_PATH_SEGMENT + "/"; + URI uri = new URI(resourceUri); + + HttpClientRequest httpRequest = HttpClientRequest.create(HttpMethod.POST, uri.toString()); + + for (Map.Entry entry : headers.entrySet()) { + httpRequest.withHeader(entry.getKey(), entry.getValue()); + } + + httpRequest.withContent(request.getContent()); + + RxClient.ServerInfo serverInfo = new RxClient.ServerInfo(uri.getHost(), uri.getPort()); + + InputStream responseStream = httpClient.submit(serverInfo, httpRequest).flatMap(clientResponse -> { + return toInputStream(clientResponse.getContent()); + }) + .toBlocking().single(); + String createdContainerAsString = IOUtils.readLines(responseStream, "UTF-8").get(0); + assertThat(createdContainerAsString).contains("\"id\":\"" + NON_PARTITIONED_CONTAINER_ID + "\""); + + // Create a document in the non partitioned collection using the rest API and older version + resourceId = Paths.DATABASES_PATH_SEGMENT + "/" + createdDatabase.getId() + "/" + Paths.COLLECTIONS_PATH_SEGMENT + "/" + collection.getId(); + path = Paths.DATABASES_PATH_SEGMENT + "/" + createdDatabase.getId() + "/" + Paths.COLLECTIONS_PATH_SEGMENT + + "/" + collection.getId() + "/" + Paths.DOCUMENTS_PATH_SEGMENT + "/"; + Document document = new Document(); + document.setId(NON_PARTITIONED_CONTAINER_DOCUEMNT_ID); + + authorization = base.generateKeyAuthorizationSignature(HttpConstants.HttpMethods.POST, resourceId, Paths.DOCUMENTS_PATH_SEGMENT, headers); + headers.put(HttpConstants.HttpHeaders.AUTHORIZATION, URLEncoder.encode(authorization, "UTF-8")); + request = RxDocumentServiceRequest.create(OperationType.Create, ResourceType.Document, path, + document, headers, new RequestOptions()); + + resourceUri = baseUrlSplit[0] + ":" + baseUrlSplit[1] + ":" + baseUrlSplit[2].split("/")[0] + "//" + Paths.DATABASES_PATH_SEGMENT + "/" + + createdDatabase.getId() + "/" + Paths.COLLECTIONS_PATH_SEGMENT + "/" + collection.getId() + "/" + Paths.DOCUMENTS_PATH_SEGMENT + "/"; + uri = new URI(resourceUri); + + httpRequest = HttpClientRequest.create(HttpMethod.POST, uri.toString()); + + for (Map.Entry entry : headers.entrySet()) { + httpRequest.withHeader(entry.getKey(), entry.getValue()); + } + + httpRequest.withContent(request.getContent()); + + serverInfo = new RxClient.ServerInfo(uri.getHost(), uri.getPort()); + + responseStream = httpClient.submit(serverInfo, httpRequest).flatMap(clientResponse -> { + return toInputStream(clientResponse.getContent()); + }).toBlocking().single(); + String createdItemAsString = IOUtils.readLines(responseStream, "UTF-8").get(0); + assertThat(createdItemAsString).contains("\"id\":\"" + NON_PARTITIONED_CONTAINER_DOCUEMNT_ID + "\""); + } + + @Test(groups = { "simple" }, timeOut = 10 * TIMEOUT) + public void testNonPartitionedCollectionOperations() throws Exception { + createContainerWithoutPk(); + CosmosContainer createdContainer = createdDatabase.getContainer(NON_PARTITIONED_CONTAINER_ID); + + Mono readMono = createdContainer.getItem(NON_PARTITIONED_CONTAINER_DOCUEMNT_ID, PartitionKey.None).read(); + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(NON_PARTITIONED_CONTAINER_DOCUEMNT_ID).build(); + validateSuccess(readMono, validator); + + String createdItemId = UUID.randomUUID().toString(); + Mono createMono = createdContainer.createItem(new CosmosItemSettings("{'id':'" + createdItemId + "'}")); + validator = new CosmosResponseValidator.Builder() + .withId(createdItemId).build(); + validateSuccess(createMono, validator); + + readMono = createdContainer.getItem(createdItemId, PartitionKey.None).read(); + validator = new CosmosResponseValidator.Builder() + .withId(createdItemId).build(); + validateSuccess(readMono, validator); + + CosmosItem itemToReplace = createdContainer.getItem(createdItemId, PartitionKey.None).read().block().getCosmosItem(); + CosmosItemSettings itemSettingsToReplace = itemToReplace.read().block().getCosmosItemSettings(); + String replacedItemId = UUID.randomUUID().toString(); + itemSettingsToReplace.setId(replacedItemId); + Mono replaceMono = itemToReplace.replace(itemSettingsToReplace); + validator = new CosmosResponseValidator.Builder() + .withId(replacedItemId).build(); + validateSuccess(replaceMono, validator); + + String upsertedItemId = UUID.randomUUID().toString(); + + Mono upsertMono = createdContainer.upsertItem(new CosmosItemSettings("{'id':'" + upsertedItemId + "'}")); + validator = new CosmosResponseValidator.Builder() + .withId(upsertedItemId).build(); + validateSuccess(upsertMono, validator); + + // one document was created during setup, one with create (which was replaced) and one with upsert + FeedOptions feedOptions = new FeedOptions(); + feedOptions.setPartitionKey(PartitionKey.None); + ArrayList expectedIds = new ArrayList(); + expectedIds.add(NON_PARTITIONED_CONTAINER_DOCUEMNT_ID); + expectedIds.add(replacedItemId); + expectedIds.add(upsertedItemId); + Flux> queryFlux = createdContainer.queryItems("SELECT * from c", feedOptions); + FeedResponseListValidator queryValidator = new FeedResponseListValidator.Builder() + .totalSize(3) + .numberOfPages(1) + .containsExactlyIds(expectedIds) + .build(); + validateQuerySuccess(queryFlux, queryValidator); + + queryFlux = createdContainer.listItems(feedOptions); + queryValidator = new FeedResponseListValidator.Builder() + .totalSize(3) + .numberOfPages(1) + .containsExactlyIds(expectedIds) + .build(); + validateQuerySuccess(queryFlux, queryValidator); + + String documentCreatedBySprocId = "testDoc"; + CosmosStoredProcedureSettings sproc = new CosmosStoredProcedureSettings( + "{" + + " 'id': '" +UUID.randomUUID().toString() + "'," + + " 'body':'" + + " function() {" + + " var client = getContext().getCollection();" + + " var doc = client.createDocument(client.getSelfLink(), { \\'id\\': \\'" + documentCreatedBySprocId + "\\'}, {}, function(err, docCreated, options) { " + + " if(err) throw new Error(\\'Error while creating document: \\' + err.message);" + + " else {" + + " getContext().getResponse().setBody(1);" + + " }" + + " });" + + "}'" + + "}"); + CosmosStoredProcedure createdSproc = createdContainer.createStoredProcedure(sproc).block().getStoredProcedure(); + + // Partiton Key value same as what is specified in the stored procedure body + RequestOptions options = new RequestOptions(); + options.setPartitionKey(PartitionKey.None); + int result = Integer.parseInt(createdSproc.execute(null, options).block().getResponseAsString()); + assertThat(result).isEqualTo(1); + + // 3 previous items + 1 created from the sproc + expectedIds.add(documentCreatedBySprocId); + queryFlux = createdContainer.listItems(feedOptions); + queryValidator = new FeedResponseListValidator.Builder() + .totalSize(4) + .numberOfPages(1) + .containsExactlyIds(expectedIds) + .build(); + validateQuerySuccess(queryFlux, queryValidator); + + Mono deleteMono = createdContainer.getItem(upsertedItemId, PartitionKey.None).delete(); + validator = new CosmosResponseValidator.Builder() + .nullResource().build(); + validateSuccess(deleteMono, validator); + + deleteMono = createdContainer.getItem(replacedItemId, PartitionKey.None).delete(); + validator = new CosmosResponseValidator.Builder() + .nullResource().build(); + validateSuccess(deleteMono, validator); + + deleteMono = createdContainer.getItem(NON_PARTITIONED_CONTAINER_DOCUEMNT_ID, PartitionKey.None).delete(); + validator = new CosmosResponseValidator.Builder() + .nullResource().build(); + validateSuccess(deleteMono, validator); + + deleteMono = createdContainer.getItem(documentCreatedBySprocId, PartitionKey.None).delete(); + validator = new CosmosResponseValidator.Builder() + .nullResource().build(); + validateSuccess(deleteMono, validator); + + queryFlux = createdContainer.listItems(feedOptions); + queryValidator = new FeedResponseListValidator.Builder() + .totalSize(0) + .numberOfPages(1) + .build(); + validateQuerySuccess(queryFlux, queryValidator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT*100) + public void testMultiPartitionCollectionReadDocumentWithNoPk() throws InterruptedException { + String partitionedCollectionId = "PartitionedCollection" + UUID.randomUUID().toString(); + String IdOfDocumentWithNoPk = UUID.randomUUID().toString(); + CosmosContainerSettings containerSettings = new CosmosContainerSettings(partitionedCollectionId, "/mypk"); + CosmosContainer createdContainer = createdDatabase.createContainer(containerSettings).block().getContainer(); + CosmosItemSettings cosmosItemSettings = new CosmosItemSettings(); + cosmosItemSettings.setId(IdOfDocumentWithNoPk); + CosmosItem createdItem = createdContainer.createItem(cosmosItemSettings).block().getCosmosItem(); + CosmosItemRequestOptions options = new CosmosItemRequestOptions(); + options.setPartitionKey(PartitionKey.None); + Mono readMono = createdItem.read(options); + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(IdOfDocumentWithNoPk).build(); + validateSuccess(readMono, validator); + } + + private Observable toInputStream(Observable contentObservable) { + return contentObservable.reduce(new ByteArrayOutputStream(), (out, bb) -> { + try { + bb.readBytes(out, bb.readableBytes()); + return out; + } catch (java.io.IOException e) { + throw new RuntimeException(e); + } + }).map(out -> { + return new ByteArrayInputStream(out.toByteArray()); + }); + } + +} diff --git a/sdk/src/test/java/com/microsoft/azure/cosmos/CosmosResponseValidator.java b/sdk/src/test/java/com/microsoft/azure/cosmos/CosmosResponseValidator.java index 1dba279227cc7..91a319718fb18 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmos/CosmosResponseValidator.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmos/CosmosResponseValidator.java @@ -1,109 +1,269 @@ -/* - * The MIT License (MIT) - * Copyright (c) 2018 Microsoft Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.microsoft.azure.cosmos; - -import com.microsoft.azure.cosmosdb.IndexingMode; -import com.microsoft.azure.cosmosdb.Resource; - -import java.util.ArrayList; -import java.util.List; - -import static org.assertj.core.api.Assertions.assertThat; - -public interface CosmosResponseValidator { - void validate(T cosmosResponse); - - class Builder { - private List> validators = new ArrayList<>(); - - public CosmosResponseValidator build() { - return new CosmosResponseValidator() { - @SuppressWarnings({"rawtypes", "unchecked"}) - @Override - public void validate(T resourceResponse) { - for (CosmosResponseValidator validator : validators) { - validator.validate(resourceResponse); - } - } - }; - } - - public Builder withId(final String resourceId) { - validators.add(new CosmosResponseValidator() { - - @Override - public void validate(T resourceResponse) { - assertThat(getResource(resourceResponse)).isNotNull(); - assertThat(getResource(resourceResponse).getId()).as("check Resource Id").isEqualTo(resourceId); - } - }); - return this; - } - - private Resource getResource(T resourceResponse) { - if(resourceResponse instanceof CosmosDatabaseResponse){ - return ((CosmosDatabaseResponse)resourceResponse).getCosmosDatabaseSettings(); - }else if(resourceResponse instanceof CosmosContainerResponse){ - return ((CosmosContainerResponse)resourceResponse).getCosmosContainerSettings(); - }else if(resourceResponse instanceof CosmosItemResponse){ - return ((CosmosItemResponse)resourceResponse).getCosmosItemSettings(); - } - return null; - } - - public Builder nullResource() { - validators.add(new CosmosResponseValidator() { - - @Override - public void validate(T resourceResponse) { - assertThat(getResource(resourceResponse)).isNull(); - } - }); - return this; - } - - public Builder indexingMode(IndexingMode mode) { - validators.add(new CosmosResponseValidator() { - - @Override - public void validate(CosmosContainerResponse resourceResponse) { - assertThat(resourceResponse.getCosmosContainerSettings()).isNotNull(); - assertThat(resourceResponse.getCosmosContainerSettings().getIndexingPolicy()).isNotNull(); - assertThat(resourceResponse.getCosmosContainerSettings().getIndexingPolicy().getIndexingMode()).isEqualTo(mode); - } - }); - return this; - } - - public Builder withProperty(String propertyName, String value) { - validators.add(new CosmosResponseValidator() { - @Override - public void validate(T cosmosResponse) { - assertThat(getResource(cosmosResponse)).isNotNull(); - assertThat(getResource(cosmosResponse).get(propertyName)).isEqualTo(value); - } - }); - return this; - } - } -} +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.microsoft.azure.cosmos; + +import com.microsoft.azure.cosmosdb.CompositePath; +import com.microsoft.azure.cosmosdb.DocumentCollection; +import com.microsoft.azure.cosmosdb.IndexingMode; +import com.microsoft.azure.cosmosdb.Resource; +import com.microsoft.azure.cosmosdb.ResourceResponse; +import com.microsoft.azure.cosmosdb.SpatialSpec; +import com.microsoft.azure.cosmosdb.SpatialType; +import com.microsoft.azure.cosmosdb.StoredProcedure; +import com.microsoft.azure.cosmosdb.Trigger; +import com.microsoft.azure.cosmosdb.TriggerOperation; +import com.microsoft.azure.cosmosdb.TriggerType; +import com.microsoft.azure.cosmosdb.UserDefinedFunction; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map.Entry; + +import static org.assertj.core.api.Assertions.assertThat; + +public interface CosmosResponseValidator { + void validate(T cosmosResponse); + + class Builder { + private List> validators = new ArrayList<>(); + + public CosmosResponseValidator build() { + return new CosmosResponseValidator() { + @SuppressWarnings({"rawtypes", "unchecked"}) + @Override + public void validate(T resourceResponse) { + for (CosmosResponseValidator validator : validators) { + validator.validate(resourceResponse); + } + } + }; + } + + public Builder withId(final String resourceId) { + validators.add(new CosmosResponseValidator() { + + @Override + public void validate(T resourceResponse) { + assertThat(getResource(resourceResponse)).isNotNull(); + assertThat(getResource(resourceResponse).getId()).as("check Resource Id").isEqualTo(resourceId); + } + }); + return this; + } + + private Resource getResource(T resourceResponse) { + if (resourceResponse instanceof CosmosDatabaseResponse) { + return ((CosmosDatabaseResponse)resourceResponse).getCosmosDatabaseSettings(); + } else if (resourceResponse instanceof CosmosContainerResponse) { + return ((CosmosContainerResponse)resourceResponse).getCosmosContainerSettings(); + } else if (resourceResponse instanceof CosmosItemResponse) { + return ((CosmosItemResponse)resourceResponse).getCosmosItemSettings(); + } else if (resourceResponse instanceof CosmosStoredProcedureResponse) { + return ((CosmosStoredProcedureResponse)resourceResponse).getStoredProcedureSettings(); + } else if (resourceResponse instanceof CosmosTriggerResponse) { + return ((CosmosTriggerResponse)resourceResponse).getCosmosTriggerSettings(); + } else if (resourceResponse instanceof CosmosUserDefinedFunctionResponse) { + return ((CosmosUserDefinedFunctionResponse)resourceResponse).getCosmosUserDefinedFunctionSettings(); + } else if (resourceResponse instanceof CosmosUserResponse) { + return ((CosmosUserResponse)resourceResponse).getCosmosUserSettings(); + } + return null; + } + + public Builder nullResource() { + validators.add(new CosmosResponseValidator() { + + @Override + public void validate(T resourceResponse) { + assertThat(getResource(resourceResponse)).isNull(); + } + }); + return this; + } + + public Builder indexingMode(IndexingMode mode) { + validators.add(new CosmosResponseValidator() { + + @Override + public void validate(CosmosContainerResponse resourceResponse) { + assertThat(resourceResponse.getCosmosContainerSettings()).isNotNull(); + assertThat(resourceResponse.getCosmosContainerSettings().getIndexingPolicy()).isNotNull(); + assertThat(resourceResponse.getCosmosContainerSettings().getIndexingPolicy().getIndexingMode()).isEqualTo(mode); + } + }); + return this; + } + + public Builder withProperty(String propertyName, String value) { + validators.add(new CosmosResponseValidator() { + @Override + public void validate(T cosmosResponse) { + assertThat(getResource(cosmosResponse)).isNotNull(); + assertThat(getResource(cosmosResponse).get(propertyName)).isEqualTo(value); + } + }); + return this; + } + + public Builder withCompositeIndexes(Collection> compositeIndexesWritten) { + validators.add(new CosmosResponseValidator() { + + @Override + public void validate(CosmosContainerResponse resourceResponse) { + Iterator> compositeIndexesReadIterator = resourceResponse.getCosmosContainerSettings() + .getIndexingPolicy().getCompositeIndexes().iterator(); + Iterator> compositeIndexesWrittenIterator = compositeIndexesWritten.iterator(); + + ArrayList readIndexesStrings = new ArrayList(); + ArrayList writtenIndexesStrings = new ArrayList(); + + while (compositeIndexesReadIterator.hasNext() && compositeIndexesWrittenIterator.hasNext()) { + Iterator compositeIndexReadIterator = compositeIndexesReadIterator.next().iterator(); + Iterator compositeIndexWrittenIterator = compositeIndexesWrittenIterator.next().iterator(); + + StringBuilder readIndexesString = new StringBuilder(); + StringBuilder writtenIndexesString = new StringBuilder(); + + while (compositeIndexReadIterator.hasNext() && compositeIndexWrittenIterator.hasNext()) { + CompositePath compositePathRead = compositeIndexReadIterator.next(); + CompositePath compositePathWritten = compositeIndexWrittenIterator.next(); + + readIndexesString.append(compositePathRead.getPath() + ":" + compositePathRead.getOrder() + ";"); + writtenIndexesString.append(compositePathWritten.getPath() + ":" + compositePathRead.getOrder() + ";"); + } + + readIndexesStrings.add(readIndexesString.toString()); + writtenIndexesStrings.add(writtenIndexesString.toString()); + } + + assertThat(readIndexesStrings).containsExactlyInAnyOrderElementsOf(writtenIndexesStrings); + } + + }); + return this; + } + + public Builder withSpatialIndexes(Collection spatialIndexes) { + validators.add(new CosmosResponseValidator() { + + @Override + public void validate(CosmosContainerResponse resourceResponse) { + Iterator spatialIndexesReadIterator = resourceResponse.getCosmosContainerSettings() + .getIndexingPolicy().getSpatialIndexes().iterator(); + Iterator spatialIndexesWrittenIterator = spatialIndexes.iterator(); + + HashMap> readIndexMap = new HashMap>(); + HashMap> writtenIndexMap = new HashMap>(); + + while (spatialIndexesReadIterator.hasNext() && spatialIndexesWrittenIterator.hasNext()) { + SpatialSpec spatialSpecRead = spatialIndexesReadIterator.next(); + SpatialSpec spatialSpecWritten = spatialIndexesWrittenIterator.next(); + + String readPath = spatialSpecRead.getPath() + ":"; + String writtenPath = spatialSpecWritten.getPath() + ":"; + + ArrayList readSpatialTypes = new ArrayList(); + ArrayList writtenSpatialTypes = new ArrayList(); + + Iterator spatialTypesReadIterator = spatialSpecRead.getSpatialTypes().iterator(); + Iterator spatialTypesWrittenIterator = spatialSpecWritten.getSpatialTypes().iterator(); + + while (spatialTypesReadIterator.hasNext() && spatialTypesWrittenIterator.hasNext()) { + readSpatialTypes.add(spatialTypesReadIterator.next()); + writtenSpatialTypes.add(spatialTypesWrittenIterator.next()); + } + + readIndexMap.put(readPath, readSpatialTypes); + writtenIndexMap.put(writtenPath, writtenSpatialTypes); + } + + for (Entry> entry : readIndexMap.entrySet()) { + assertThat(entry.getValue()) + .containsExactlyInAnyOrderElementsOf(writtenIndexMap.get(entry.getKey())); + } + } + }); + return this; + } + + public Builder withStoredProcedureBody(String storedProcedureBody) { + validators.add(new CosmosResponseValidator() { + + @Override + public void validate(CosmosStoredProcedureResponse resourceResponse) { + assertThat(resourceResponse.getStoredProcedureSettings().getBody()).isEqualTo(storedProcedureBody); + } + }); + return this; + } + + public Builder notNullEtag() { + validators.add(new CosmosResponseValidator() { + + @Override + public void validate(T resourceResponse) { + assertThat(resourceResponse.getResourceSettings()).isNotNull(); + assertThat(resourceResponse.getResourceSettings().getETag()).isNotNull(); + } + }); + return this; + } + + public Builder withTriggerBody(String functionBody) { + validators.add(new CosmosResponseValidator() { + + @Override + public void validate(CosmosTriggerResponse resourceResponse) { + assertThat(resourceResponse.getCosmosTriggerSettings().getBody()).isEqualTo(functionBody); + } + }); + return this; + } + + public Builder withTriggerInternals(TriggerType type, TriggerOperation op) { + validators.add(new CosmosResponseValidator() { + + @Override + public void validate(CosmosTriggerResponse resourceResponse) { + assertThat(resourceResponse.getCosmosTriggerSettings().getTriggerType()).isEqualTo(type); + assertThat(resourceResponse.getCosmosTriggerSettings().getTriggerOperation()).isEqualTo(op); + } + }); + return this; + } + + public Builder withUserDefinedFunctionBody(String functionBody) { + validators.add(new CosmosResponseValidator() { + + @Override + public void validate(CosmosUserDefinedFunctionResponse resourceResponse) { + assertThat(resourceResponse.getCosmosUserDefinedFunctionSettings().getBody()).isEqualTo(functionBody); + } + }); + return this; + } + } +} diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/DCDocumentCrudTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/internal/directconnectivity/DCDocumentCrudTest.java similarity index 96% rename from sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/DCDocumentCrudTest.java rename to sdk/src/test/java/com/microsoft/azure/cosmosdb/internal/directconnectivity/DCDocumentCrudTest.java index 7a73fa0e04bde..a6d5286aab9d5 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/DCDocumentCrudTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/internal/directconnectivity/DCDocumentCrudTest.java @@ -20,7 +20,7 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ -package com.microsoft.azure.cosmosdb.rx; +package com.microsoft.azure.cosmosdb.internal.directconnectivity; import com.microsoft.azure.cosmosdb.ConnectionMode; import com.microsoft.azure.cosmosdb.ConnectionPolicy; @@ -38,10 +38,15 @@ import com.microsoft.azure.cosmosdb.internal.OperationType; import com.microsoft.azure.cosmosdb.internal.ResourceType; import com.microsoft.azure.cosmosdb.internal.directconnectivity.Protocol; +import com.microsoft.azure.cosmosdb.rx.DocumentServiceRequestValidator; +import com.microsoft.azure.cosmosdb.rx.FeedResponseListValidator; +import com.microsoft.azure.cosmosdb.rx.ResourceResponseValidator; +import com.microsoft.azure.cosmosdb.rx.TestConfigurations; import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; import com.microsoft.azure.cosmosdb.rx.internal.Configs; import com.microsoft.azure.cosmosdb.rx.internal.RxDocumentServiceRequest; import com.microsoft.azure.cosmosdb.rx.internal.SpyClientUnderTestFactory; +import com.microsoft.azure.cosmosdb.rx.internal.TestSuiteBase; import org.mockito.stubbing.Answer; import org.testng.SkipException; import org.testng.annotations.AfterClass; @@ -67,6 +72,7 @@ * The tests in other test classes validate the actual behaviour and different scenarios. */ public class DCDocumentCrudTest extends TestSuiteBase { + private final static int QUERY_TIMEOUT = 40000; private final static String PARTITION_KEY_FIELD_NAME = "mypk"; @@ -249,8 +255,8 @@ public void crossPartitionQuery() { // validates only the first query for fetching query plan goes to gateway. assertThat(client.getCapturedRequests().stream().filter(r -> r.getResourceType() == ResourceType.Document)).hasSize(1); } catch (Throwable error) { - if (clientBuilder.configs.getProtocol() == Protocol.Tcp) { - String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.desiredConsistencyLevel); + if (clientBuilder.getConfigs().getProtocol() == Protocol.Tcp) { + String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.getDesiredConsistencyLevel()); logger.info(message, error); throw new SkipException(message, error); } @@ -340,4 +346,5 @@ private Document getDocumentDefinition() { doc.set("name", "Hafez"); return doc; } + } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/internal/directconnectivity/GatewayAddressCacheTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/internal/directconnectivity/GatewayAddressCacheTest.java index 54d581f42615c..9357869954706 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/internal/directconnectivity/GatewayAddressCacheTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/internal/directconnectivity/GatewayAddressCacheTest.java @@ -36,12 +36,12 @@ import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; import com.microsoft.azure.cosmosdb.rx.TestConfigurations; -import com.microsoft.azure.cosmosdb.rx.TestSuiteBase; import com.microsoft.azure.cosmosdb.rx.internal.Configs; import com.microsoft.azure.cosmosdb.rx.internal.HttpClientFactory; import com.microsoft.azure.cosmosdb.rx.internal.IAuthorizationTokenProvider; import com.microsoft.azure.cosmosdb.rx.internal.RxDocumentClientImpl; import com.microsoft.azure.cosmosdb.rx.internal.RxDocumentServiceRequest; +import com.microsoft.azure.cosmosdb.rx.internal.TestSuiteBase; import io.netty.buffer.ByteBuf; import io.reactivex.netty.protocol.http.client.CompositeHttpClient; import org.mockito.Matchers; @@ -877,4 +877,4 @@ private Document getDocumentDefinition() { , uuid, uuid)); return doc; } -} +} \ No newline at end of file diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/internal/directconnectivity/GatewayServiceConfigurationReaderTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/internal/directconnectivity/GatewayServiceConfigurationReaderTest.java index 691139545995a..0f28160d1f3da 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/internal/directconnectivity/GatewayServiceConfigurationReaderTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/internal/directconnectivity/GatewayServiceConfigurationReaderTest.java @@ -45,7 +45,7 @@ import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; import com.microsoft.azure.cosmosdb.rx.TestConfigurations; -import com.microsoft.azure.cosmosdb.rx.TestSuiteBase; +import com.microsoft.azure.cosmosdb.rx.internal.TestSuiteBase; import com.microsoft.azure.cosmosdb.rx.internal.SpyClientUnderTestFactory; import com.microsoft.azure.cosmosdb.rx.internal.SpyClientUnderTestFactory.ClientUnderTest; @@ -202,4 +202,4 @@ private HttpClientResponse getMockResponse(String databaseAccountJson) } return resp; } -} +} \ No newline at end of file diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/AggregateQueryTests.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/AggregateQueryTests.java index 3a0fb11fb207f..2a3c7696d3f69 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/AggregateQueryTests.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/AggregateQueryTests.java @@ -23,23 +23,25 @@ package com.microsoft.azure.cosmosdb.rx; import java.util.ArrayList; +import java.util.UUID; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import com.microsoft.azure.cosmosdb.internal.directconnectivity.Protocol; + +import reactor.core.publisher.Flux; + import org.testng.SkipException; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.Database; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosItemSettings; import com.microsoft.azure.cosmosdb.Document; -import com.microsoft.azure.cosmosdb.DocumentCollection; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; -import com.microsoft.azure.cosmosdb.ResourceResponse; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; - -import rx.Observable; public class AggregateQueryTests extends TestSuiteBase { @@ -67,9 +69,8 @@ public AggregateConfig(String operator, Object expected, String condition) { } } - private Database createdDatabase; - private DocumentCollection createdCollection; - private ArrayList docs = new ArrayList(); + private CosmosContainer createdCollection; + private ArrayList docs = new ArrayList(); private ArrayList queryConfigs = new ArrayList(); private String partitionKey = "mypk"; @@ -80,10 +81,10 @@ public AggregateConfig(String operator, Object expected, String condition) { private int numberOfDocumentsWithNumericId; private int numberOfDocsWithSamePartitionKey = 400; - private AsyncDocumentClient client; + private CosmosClient client; @Factory(dataProvider = "clientBuildersWithDirect") - public AggregateQueryTests(Builder clientBuilder) { + public AggregateQueryTests(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @@ -105,10 +106,9 @@ public void queryDocumentsWithAggregates(boolean qmEnabled) throws Exception { for (QueryConfig queryConfig : queryConfigs) { - Observable> queryObservable = client - .queryDocuments(createdCollection.getSelfLink(), queryConfig.query, options); + Flux> queryObservable = createdCollection.queryItems(queryConfig.query, options); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .withAggregateValue(queryConfig.expected) .numberOfPages(1) .hasValidQueryMetrics(qmEnabled) @@ -117,8 +117,8 @@ public void queryDocumentsWithAggregates(boolean qmEnabled) throws Exception { try { validateQuerySuccess(queryObservable, validator); } catch (Throwable error) { - if (this.clientBuilder.configs.getProtocol() == Protocol.Tcp) { - String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.desiredConsistencyLevel); + if (this.clientBuilder.getConfigs().getProtocol() == Protocol.Tcp) { + String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.getDesiredConsistencyLevel()); logger.info(message, error); throw new SkipException(message, error); } @@ -127,38 +127,35 @@ public void queryDocumentsWithAggregates(boolean qmEnabled) throws Exception { } } - public void bulkInsert(AsyncDocumentClient client) { + public void bulkInsert() { generateTestData(); - - ArrayList>> result = new ArrayList>>(); - for (int i = 0; i < docs.size(); i++) { - result.add(client.createDocument("dbs/" + createdDatabase.getId() + "/colls/" + createdCollection.getId(), docs.get(i), null, false)); - } - - Observable.merge(result, 100).toList().toBlocking().single(); + bulkInsertBlocking(createdCollection, docs); } public void generateTestData() { Object[] values = new Object[]{null, false, true, "abc", "cdfg", "opqrs", "ttttttt", "xyz", "oo", "ppp"}; for (int i = 0; i < values.length; i++) { - Document d = new Document(); + CosmosItemSettings d = new CosmosItemSettings(); + d.setId(UUID.randomUUID().toString()); d.set(partitionKey, values[i]); docs.add(d); } for (int i = 0; i < numberOfDocsWithSamePartitionKey; i++) { - Document d = new Document(); + CosmosItemSettings d = new CosmosItemSettings(); d.set(partitionKey, uniquePartitionKey); d.set("resourceId", Integer.toString(i)); d.set(field, i + 1); + d.setId(UUID.randomUUID().toString()); docs.add(d); } numberOfDocumentsWithNumericId = numberOfDocuments - values.length - numberOfDocsWithSamePartitionKey; for (int i = 0; i < numberOfDocumentsWithNumericId; i++) { - Document d = new Document(); + CosmosItemSettings d = new CosmosItemSettings(); d.set(partitionKey, i + 1); + d.setId(UUID.randomUUID().toString()); docs.add(d); } @@ -223,14 +220,13 @@ public void afterClass() { safeClose(client); } - @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT * 100) public void beforeClass() throws Exception { client = clientBuilder.build(); - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_MULTI_PARTITION_COLLECTION; - truncateCollection(SHARED_MULTI_PARTITION_COLLECTION); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); - bulkInsert(client); + bulkInsert(); generateTestConfigs(); waitIfNeededForReplicasToCatchUp(clientBuilder); diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/AttachmentCrudTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/AttachmentCrudTest.java deleted file mode 100644 index a229e251a2a5d..0000000000000 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/AttachmentCrudTest.java +++ /dev/null @@ -1,235 +0,0 @@ -/* - * The MIT License (MIT) - * Copyright (c) 2018 Microsoft Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.microsoft.azure.cosmosdb.rx; - -import java.util.UUID; - -import com.microsoft.azure.cosmosdb.internal.directconnectivity.Protocol; -import org.testng.SkipException; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Factory; -import org.testng.annotations.Test; - -import com.microsoft.azure.cosmosdb.Attachment; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.Document; -import com.microsoft.azure.cosmosdb.DocumentCollection; -import com.microsoft.azure.cosmosdb.PartitionKey; -import com.microsoft.azure.cosmosdb.RequestOptions; -import com.microsoft.azure.cosmosdb.ResourceResponse; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; - -import rx.Observable; - -import javax.net.ssl.SSLException; - -public class AttachmentCrudTest extends TestSuiteBase { - - private Database createdDatabase; - private DocumentCollection createdCollection; - private Document createdDocument; - - private AsyncDocumentClient client; - - @Factory(dataProvider = "clientBuildersWithDirectHttps") // Direct TCP mode does not support attachments - public AttachmentCrudTest(AsyncDocumentClient.Builder clientBuilder) { - this.clientBuilder = clientBuilder; - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT) - public void createAttachment() throws Exception { - // create an Attachment - String uuid = UUID.randomUUID().toString(); - Attachment attachment = getAttachmentDefinition(uuid, "application/text"); - - RequestOptions options = new RequestOptions(); - options.setPartitionKey(new PartitionKey(createdDocument.getId())); - Observable> createObservable = client.createAttachment(getDocumentLink(), attachment, options); - - // validate attachment creation - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() - .withId(attachment.getId()) - .withContentType("application/text") - .notNullEtag() - .build(); - validateSuccess(createObservable, validator); - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT) - public void readAttachment() throws Exception { - // create an Attachment - String uuid = UUID.randomUUID().toString(); - Attachment attachment = getAttachmentDefinition(uuid, "application/text"); - - RequestOptions options = new RequestOptions(); - options.setPartitionKey(new PartitionKey(createdDocument.getId())); - Attachment readBackAttachment = client.createAttachment(getDocumentLink(), attachment, options).toBlocking().single().getResource(); - - waitIfNeededForReplicasToCatchUp(clientBuilder); - - // read attachment - Observable> readObservable = client.readAttachment(readBackAttachment.getSelfLink(), options); - - // validate attachment read - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() - .withId(attachment.getId()) - .withContentType("application/text") - .notNullEtag() - .build(); - validateSuccess(readObservable, validator); - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT) - public void deleteAttachment() throws Exception { - // create an Attachment - String uuid = UUID.randomUUID().toString(); - Attachment attachment = getAttachmentDefinition(uuid, "application/text"); - - RequestOptions options = new RequestOptions(); - options.setPartitionKey(new PartitionKey(createdDocument.getId())); - Attachment readBackAttachment = client.createAttachment(getDocumentLink(), attachment, options).toBlocking().single().getResource(); - - // delete attachment - Observable> deleteObservable = client.deleteAttachment(readBackAttachment.getSelfLink(), options); - - // validate attachment delete - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() - .nullResource() - .build(); - validateSuccess(deleteObservable, validator); - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT) - public void upsertAttachment() throws Exception { - // create an Attachment - String uuid = UUID.randomUUID().toString(); - Attachment attachment = getAttachmentDefinition(uuid, "application/text"); - - RequestOptions options = new RequestOptions(); - options.setPartitionKey(new PartitionKey(createdDocument.getId())); - Attachment readBackAttachment = client.upsertAttachment(getDocumentLink(), attachment, options).toBlocking().single().getResource(); - - // read attachment - waitIfNeededForReplicasToCatchUp(clientBuilder); - Observable> readObservable = client.readAttachment(readBackAttachment.getSelfLink(), options); - - // validate attachment read - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() - .withId(attachment.getId()) - .withContentType("application/text") - .notNullEtag() - .build(); - validateSuccess(readObservable, validator); - - //update attachment - readBackAttachment.setContentType("application/json"); - - Observable> updateObservable = client.upsertAttachment(getDocumentLink(), readBackAttachment, options); - - // validate attachment update - ResourceResponseValidator validatorForUpdate = new ResourceResponseValidator.Builder() - .withId(readBackAttachment.getId()) - .withContentType("application/json") - .notNullEtag() - .build(); - validateSuccess(updateObservable, validatorForUpdate); - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT) - public void replaceAttachment() throws Exception { - // create an Attachment - String uuid = UUID.randomUUID().toString(); - Attachment attachment = getAttachmentDefinition(uuid, "application/text"); - - RequestOptions options = new RequestOptions(); - options.setPartitionKey(new PartitionKey(createdDocument.getId())); - Attachment readBackAttachment = client.createAttachment(getDocumentLink(), attachment, options).toBlocking().single().getResource(); - - - // read attachment - waitIfNeededForReplicasToCatchUp(clientBuilder); - Observable> readObservable = client.readAttachment(readBackAttachment.getSelfLink(), options); - - // validate attachment read - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() - .withId(attachment.getId()) - .withContentType("application/text") - .notNullEtag() - .build(); - validateSuccess(readObservable, validator); - - //update attachment - readBackAttachment.setContentType("application/json"); - - Observable> updateObservable = client.replaceAttachment(readBackAttachment, options); - - // validate attachment update - ResourceResponseValidator validatorForUpdate = new ResourceResponseValidator.Builder() - .withId(readBackAttachment.getId()) - .withContentType("application/json") - .notNullEtag() - .build(); - validateSuccess(updateObservable, validatorForUpdate); - } - - @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) - public void beforeClass() { - client = clientBuilder.build(); - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_MULTI_PARTITION_COLLECTION; - createdDocument = createDocument(client, createdDatabase.getId(), createdCollection.getId(), getDocumentDefinition()); - } - - @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) - public void afterClass() { - safeClose(client); - } - - private String getDocumentLink() { - return createdDocument.getSelfLink(); - } - - private static Document getDocumentDefinition() { - String uuid = UUID.randomUUID().toString(); - Document doc = new Document(String.format("{ " - + "\"id\": \"%s\", " - + "\"mypk\": \"%s\", " - + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" - + "}" - , uuid, uuid)); - return doc; - } - - private static Attachment getAttachmentDefinition(String uuid, String type) { - return new Attachment(String.format( - "{" + - " 'id': '%s'," + - " 'media': 'http://xstore.'," + - " 'MediaType': 'Book'," + - " 'Author': 'My Book Author'," + - " 'Title': 'My Book Title'," + - " 'contentType': '%s'" + - "}", uuid, type)); - } -} diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/AttachmentQueryTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/AttachmentQueryTest.java deleted file mode 100644 index 1a353241e4b95..0000000000000 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/AttachmentQueryTest.java +++ /dev/null @@ -1,199 +0,0 @@ -/* - * The MIT License (MIT) - * Copyright (c) 2018 Microsoft Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.microsoft.azure.cosmosdb.rx; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.stream.Collectors; - -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Factory; -import org.testng.annotations.Test; - -import com.microsoft.azure.cosmosdb.Attachment; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.Document; -import com.microsoft.azure.cosmosdb.DocumentClientException; -import com.microsoft.azure.cosmosdb.DocumentCollection; -import com.microsoft.azure.cosmosdb.FeedOptions; -import com.microsoft.azure.cosmosdb.FeedResponse; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; - -import rx.Observable; - -public class AttachmentQueryTest extends TestSuiteBase { - - private Database createdDatabase; - private DocumentCollection createdCollection; - private List createdAttachments = new ArrayList<>(); - - private Document createdDocument; - - private AsyncDocumentClient client; - - public String getCollectionLink() { - return Utils.getCollectionNameLink(createdDatabase.getId(), createdCollection.getId()); - } - - public String getDocumentLink() { - return createdDocument.getSelfLink(); - } - - @Factory(dataProvider = "clientBuilders") - public AttachmentQueryTest(Builder clientBuilder) { - this.clientBuilder = clientBuilder; - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT) - public void queryWithFilter() throws Exception { - - String filterId = createdAttachments.get(0).getId(); - String query = String.format("SELECT * from c where c.id = '%s'", filterId); - - FeedOptions options = new FeedOptions(); - options.setMaxItemCount(2); - Observable> queryObservable = client - .queryAttachments(getDocumentLink(), query, options); - - List expectedDocs = createdAttachments.stream().filter(sp -> filterId.equals(sp.getId()) ).collect(Collectors.toList()); - assertThat(expectedDocs).isNotEmpty(); - - int expectedPageSize = (expectedDocs.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() - .totalSize(expectedDocs.size()) - .exactlyContainsInAnyOrder(expectedDocs.stream().map(d -> d.getResourceId()).collect(Collectors.toList())) - .numberOfPages(expectedPageSize) - .pageSatisfy(0, new FeedResponseValidator.Builder() - .requestChargeGreaterThanOrEqualTo(1.0).build()) - .build(); - - validateQuerySuccess(queryObservable, validator, 10000); - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT) - public void query_NoResults() throws Exception { - - String query = "SELECT * from root r where r.id = '2'"; - FeedOptions options = new FeedOptions(); - Observable> queryObservable = client - .queryAttachments(getDocumentLink(), query, options); - - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() - .containsExactly(new ArrayList<>()) - .numberOfPages(1) - .pageSatisfy(0, new FeedResponseValidator.Builder() - .requestChargeGreaterThanOrEqualTo(1.0).build()) - .build(); - validateQuerySuccess(queryObservable, validator); - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT) - public void queryAll() throws Exception { - - String query = "SELECT * from root"; - FeedOptions options = new FeedOptions(); - options.setMaxItemCount(2); - options.setEnableCrossPartitionQuery(true); - Observable> queryObservable = client - .queryAttachments(getDocumentLink(), query, options); - - List expectedDocs = createdAttachments; - - int expectedPageSize = (expectedDocs.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - - FeedResponseListValidator validator = new FeedResponseListValidator - .Builder() - .exactlyContainsInAnyOrder(expectedDocs - .stream() - .map(d -> d.getResourceId()) - .collect(Collectors.toList())) - .numberOfPages(expectedPageSize) - .allPagesSatisfy(new FeedResponseValidator.Builder() - .requestChargeGreaterThanOrEqualTo(1.0).build()) - .build(); - validateQuerySuccess(queryObservable, validator); - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT) - public void invalidQuerySytax() throws Exception { - String query = "I am an invalid query"; - FeedOptions options = new FeedOptions(); - options.setEnableCrossPartitionQuery(true); - Observable> queryObservable = client - .queryDocuments(getCollectionLink(), query, options); - - FailureValidator validator = new FailureValidator.Builder() - .instanceOf(DocumentClientException.class) - .statusCode(400) - .notNullActivityId() - .build(); - validateQueryFailure(queryObservable, validator); - } - - public Attachment createAttachment(AsyncDocumentClient client) { - Attachment attachment = getAttachmentDefinition(); - return client.createAttachment(getDocumentLink(), attachment, null).toBlocking().single().getResource(); - } - - @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) - public void afterClass() { - safeClose(client); - } - - @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) - public void beforeClass() throws Exception { - client = clientBuilder.build(); - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY; - truncateCollection(SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY); - - Document docDef = new Document(); - docDef.setId(UUID.randomUUID().toString()); - - createdDocument = createDocument(client, createdDatabase.getId(), createdCollection.getId(), docDef); - - for(int i = 0; i < 5; i++) { - createdAttachments.add(createAttachment(client)); - } - - waitIfNeededForReplicasToCatchUp(clientBuilder); - } - - private static Attachment getAttachmentDefinition() { - return new Attachment(String.format( - "{" + - " 'id': '%s'," + - " 'media': 'http://xstore.'," + - " 'MediaType': 'Book'," + - " 'Author': 'My Book Author'," + - " 'Title': 'My Book Title'," + - " 'contentType': '%s'" + - "}", UUID.randomUUID().toString(), "application/text")); - } -} diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/BackPressureCrossPartitionTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/BackPressureCrossPartitionTest.java index 2a40e985d409b..a8fc9f00ab9c2 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/BackPressureCrossPartitionTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/BackPressureCrossPartitionTest.java @@ -22,21 +22,29 @@ */ package com.microsoft.azure.cosmosdb.rx; +import com.microsoft.azure.cosmos.ClientUnderTestBuilder; +import com.microsoft.azure.cosmos.CosmosBridgeInternal; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosClientBuilder; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosContainerRequestOptions; +import com.microsoft.azure.cosmos.CosmosContainerSettings; +import com.microsoft.azure.cosmos.CosmosDatabase; +import com.microsoft.azure.cosmos.CosmosItemSettings; import com.microsoft.azure.cosmosdb.DataType; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.Document; -import com.microsoft.azure.cosmosdb.DocumentCollection; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; import com.microsoft.azure.cosmosdb.IncludedPath; import com.microsoft.azure.cosmosdb.Index; import com.microsoft.azure.cosmosdb.IndexingPolicy; import com.microsoft.azure.cosmosdb.PartitionKeyDefinition; -import com.microsoft.azure.cosmosdb.RequestOptions; -import com.microsoft.azure.cosmosdb.ResourceResponse; import com.microsoft.azure.cosmosdb.internal.directconnectivity.Protocol; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; import com.microsoft.azure.cosmosdb.rx.internal.RxDocumentClientUnderTest; + +import io.reactivex.subscribers.TestSubscriber; +import reactor.core.publisher.Flux; +import reactor.core.scheduler.Schedulers; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.SkipException; @@ -45,10 +53,8 @@ import org.testng.annotations.DataProvider; import org.testng.annotations.Factory; import org.testng.annotations.Test; +import reactor.util.concurrent.Queues; import rx.Observable; -import rx.internal.util.RxRingBuffer; -import rx.observers.TestSubscriber; -import rx.schedulers.Schedulers; import java.util.ArrayList; import java.util.Collection; @@ -65,18 +71,18 @@ public class BackPressureCrossPartitionTest extends TestSuiteBase { private static final int SETUP_TIMEOUT = 60000; private int numberOfDocs = 4000; - private Database createdDatabase; - private DocumentCollection createdCollection; - private List createdDocuments; + private CosmosDatabase createdDatabase; + private CosmosContainer createdCollection; + private List createdDocuments; - private RxDocumentClientUnderTest client; + private CosmosClient client; private int numberOfPartitions; public String getCollectionLink() { return Utils.getCollectionNameLink(createdDatabase.getId(), createdCollection.getId()); } - static protected DocumentCollection getCollectionDefinition() { + static protected CosmosContainerSettings getCollectionDefinition() { PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); ArrayList paths = new ArrayList<>(); paths.add("/mypk"); @@ -98,16 +104,16 @@ static protected DocumentCollection getCollectionDefinition() { includedPaths.add(includedPath); indexingPolicy.setIncludedPaths(includedPaths); - DocumentCollection collectionDefinition = new DocumentCollection(); - collectionDefinition.setId(UUID.randomUUID().toString()); - collectionDefinition.setPartitionKey(partitionKeyDef); + CosmosContainerSettings collectionDefinition = new CosmosContainerSettings( + UUID.randomUUID().toString(), + partitionKeyDef); collectionDefinition.setIndexingPolicy(indexingPolicy); return collectionDefinition; } @Factory(dataProvider = "simpleClientBuildersWithDirectHttps") - public BackPressureCrossPartitionTest(Builder clientBuilder) { + public BackPressureCrossPartitionTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @@ -115,19 +121,19 @@ private void warmUp() { FeedOptions options = new FeedOptions(); options.setEnableCrossPartitionQuery(true); // ensure collection is cached - client.queryDocuments(getCollectionLink(), "SELECT * FROM r", options).first().toBlocking().single(); + createdCollection.queryItems("SELECT * FROM r", options).blockFirst(); } @DataProvider(name = "queryProvider") public Object[][] queryProvider() { return new Object[][] { // query, maxItemCount, max expected back pressure buffered, total number of expected query results - { "SELECT * FROM r", 1, 2 * RxRingBuffer.SIZE, numberOfDocs}, - { "SELECT * FROM r", 100, 2 * RxRingBuffer.SIZE, numberOfDocs}, - { "SELECT * FROM r ORDER BY r.prop", 100, 2 * RxRingBuffer.SIZE + 3 * numberOfPartitions, numberOfDocs}, - { "SELECT TOP 1000 * FROM r", 1, 2 * RxRingBuffer.SIZE, 1000}, - { "SELECT TOP 1000 * FROM r", 100, 2 * RxRingBuffer.SIZE, 1000}, - { "SELECT TOP 1000 * FROM r ORDER BY r.prop", 100, 2 * RxRingBuffer.SIZE + 3 * numberOfPartitions , 1000}, + { "SELECT * FROM r", 1, 2 * Queues.SMALL_BUFFER_SIZE, numberOfDocs}, + { "SELECT * FROM r", 100, 2 * Queues.SMALL_BUFFER_SIZE, numberOfDocs}, + { "SELECT * FROM r ORDER BY r.prop", 100, 2 * Queues.SMALL_BUFFER_SIZE + 3 * numberOfPartitions, numberOfDocs}, + { "SELECT TOP 1000 * FROM r", 1, 2 * Queues.SMALL_BUFFER_SIZE, 1000}, + { "SELECT TOP 1000 * FROM r", 100, 2 * Queues.SMALL_BUFFER_SIZE, 1000}, + { "SELECT TOP 1000 * FROM r ORDER BY r.prop", 100, 2 * Queues.SMALL_BUFFER_SIZE + 3 * numberOfPartitions , 1000}, }; } @@ -140,20 +146,20 @@ public void query(String query, int maxItemCount, int maxExpectedBufferedCountFo options.setEnableCrossPartitionQuery(true); options.setMaxItemCount(maxItemCount); options.setMaxDegreeOfParallelism(2); - Observable> queryObservable = client - .queryDocuments(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryItems(query, options); - client.httpRequests.clear(); + RxDocumentClientUnderTest rxClient = (RxDocumentClientUnderTest)CosmosBridgeInternal.getAsyncDocumentClient(client); + rxClient.httpRequests.clear(); log.info("instantiating subscriber ..."); - TestSubscriber> subscriber = new TestSubscriber<>(1); - queryObservable.observeOn(Schedulers.io(), 1).subscribe(subscriber); + TestSubscriber> subscriber = new TestSubscriber<>(1); + queryObservable.publishOn(Schedulers.elastic()).subscribe(subscriber); int sleepTimeInMillis = 40000; int i = 0; // use a test subscriber and request for more result and sleep in between try { - while(subscriber.getCompletions() == 0 && subscriber.getOnErrorEvents().isEmpty()) { + while(subscriber.completions() == 0 && subscriber.errorCount() == 0) { log.debug("loop " + i); TimeUnit.MILLISECONDS.sleep(sleepTimeInMillis); @@ -161,15 +167,14 @@ public void query(String query, int maxItemCount, int maxExpectedBufferedCountFo if (sleepTimeInMillis > 4000) { // validate that only one item is returned to subscriber in each iteration - assertThat(subscriber.getValueCount() - i).isEqualTo(1); + assertThat(subscriber.valueCount() - i).isEqualTo(1); } - log.debug("subscriber.getValueCount(): " + subscriber.getValueCount()); - log.debug("client.httpRequests.size(): " + client.httpRequests.size()); + log.debug("subscriber.getValueCount(): " + subscriber.valueCount()); + log.debug("client.httpRequests.size(): " + rxClient.httpRequests.size()); // validate that the difference between the number of requests to backend // and the number of returned results is always less than a fixed threshold - - assertThat(client.httpRequests.size() - subscriber.getValueCount()) + assertThat(rxClient.httpRequests.size() - subscriber.valueCount()) .isLessThanOrEqualTo(maxExpectedBufferedCountForBackPressure); log.debug("requesting more"); @@ -177,8 +182,8 @@ public void query(String query, int maxItemCount, int maxExpectedBufferedCountFo i++; } } catch (Throwable error) { - if (this.clientBuilder.configs.getProtocol() == Protocol.Tcp) { - String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.desiredConsistencyLevel); + if (this.clientBuilder.getConfigs().getProtocol() == Protocol.Tcp) { + String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.getDesiredConsistencyLevel()); logger.info(message, error); throw new SkipException(message, error); } @@ -187,11 +192,11 @@ public void query(String query, int maxItemCount, int maxExpectedBufferedCountFo try { subscriber.assertNoErrors(); - subscriber.assertCompleted(); - assertThat(subscriber.getOnNextEvents().stream().mapToInt(p -> p.getResults().size()).sum()).isEqualTo(expectedNumberOfResults); + subscriber.assertComplete(); + assertThat(subscriber.values().stream().mapToInt(p -> p.getResults().size()).sum()).isEqualTo(expectedNumberOfResults); } catch (Throwable error) { - if (this.clientBuilder.configs.getProtocol() == Protocol.Tcp) { - String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.desiredConsistencyLevel); + if (this.clientBuilder.getConfigs().getProtocol() == Protocol.Tcp) { + String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.getDesiredConsistencyLevel()); logger.info(message, error); throw new SkipException(message, error); } @@ -201,27 +206,22 @@ public void query(String query, int maxItemCount, int maxExpectedBufferedCountFo @BeforeClass(groups = { "long" }, timeOut = SETUP_TIMEOUT) public void beforeClass() { - RequestOptions options = new RequestOptions(); - options.setOfferThroughput(20000); - createdDatabase = SHARED_DATABASE; - createdCollection = createCollection(createdDatabase.getId(), getCollectionDefinition(), options); - + CosmosContainerRequestOptions options = new CosmosContainerRequestOptions(); + options.offerThroughput(20000); client = new ClientUnderTestBuilder(clientBuilder).build(); + createdDatabase = getSharedCosmosDatabase(client); + createdCollection = createCollection(createdDatabase, getCollectionDefinition(), options); - ArrayList docDefList = new ArrayList<>(); + ArrayList docDefList = new ArrayList<>(); for(int i = 0; i < numberOfDocs; i++) { docDefList.add(getDocumentDefinition(i)); } - Observable> documentBulkInsertObs = bulkInsert( - client, - getCollectionLink(), - docDefList, - 1000); - - createdDocuments = documentBulkInsertObs.map(ResourceResponse::getResource).toList().toBlocking().single(); + createdDocuments = bulkInsertBlocking( + createdCollection, + docDefList); - numberOfPartitions = client.readPartitionKeyRanges(getCollectionLink(), null) + numberOfPartitions = CosmosBridgeInternal.getAsyncDocumentClient(client).readPartitionKeyRanges(getCollectionLink(), null) .flatMap(p -> Observable.from(p.getResults())).toList().toBlocking().single().size(); waitIfNeededForReplicasToCatchUp(clientBuilder); @@ -233,13 +233,13 @@ public void beforeClass() { @AfterClass(groups = { "long" }, timeOut = 2 * SHUTDOWN_TIMEOUT, alwaysRun = true) public void afterClass() { - safeDeleteCollection(client, createdCollection); + safeDeleteCollection(createdCollection); safeClose(client); } - private static Document getDocumentDefinition(int cnt) { + private static CosmosItemSettings getDocumentDefinition(int cnt) { String uuid = UUID.randomUUID().toString(); - Document doc = new Document(String.format("{ " + CosmosItemSettings doc = new CosmosItemSettings(String.format("{ " + "\"id\": \"%s\", " + "\"prop\" : %d, " + "\"mypk\": \"%s\", " diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/BackPressureTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/BackPressureTest.java index c22fc3a4da068..2ac124487fc5d 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/BackPressureTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/BackPressureTest.java @@ -22,24 +22,30 @@ */ package com.microsoft.azure.cosmosdb.rx; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.Document; -import com.microsoft.azure.cosmosdb.DocumentCollection; +import com.microsoft.azure.cosmos.ClientUnderTestBuilder; +import com.microsoft.azure.cosmos.CosmosBridgeInternal; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosClientBuilder; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosContainerRequestOptions; +import com.microsoft.azure.cosmos.CosmosContainerSettings; +import com.microsoft.azure.cosmos.CosmosDatabase; +import com.microsoft.azure.cosmos.CosmosItemSettings; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; import com.microsoft.azure.cosmosdb.Offer; -import com.microsoft.azure.cosmosdb.RequestOptions; -import com.microsoft.azure.cosmosdb.ResourceResponse; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; +import com.microsoft.azure.cosmosdb.PartitionKeyDefinition; import com.microsoft.azure.cosmosdb.rx.internal.RxDocumentClientUnderTest; + +import io.reactivex.subscribers.TestSubscriber; +import reactor.core.publisher.Flux; +import reactor.core.scheduler.Schedulers; + import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import rx.Observable; -import rx.internal.util.RxRingBuffer; -import rx.observers.TestSubscriber; -import rx.schedulers.Schedulers; +import reactor.util.concurrent.Queues; import java.util.ArrayList; import java.util.List; @@ -53,24 +59,28 @@ public class BackPressureTest extends TestSuiteBase { private static final int TIMEOUT = 200000; private static final int SETUP_TIMEOUT = 60000; - private Database createdDatabase; - private DocumentCollection createdCollection; - private List createdDocuments; + private CosmosDatabase createdDatabase; + private CosmosContainer createdCollection; + private List createdDocuments; - private RxDocumentClientUnderTest client; + private CosmosClient client; public String getCollectionLink() { return Utils.getCollectionNameLink(createdDatabase.getId(), createdCollection.getId()); } - private static DocumentCollection getSinglePartitionCollectionDefinition() { - DocumentCollection collectionDefinition = new DocumentCollection(); - collectionDefinition.setId(UUID.randomUUID().toString()); + private static CosmosContainerSettings getSinglePartitionCollectionDefinition() { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.setPaths(paths); + + CosmosContainerSettings collectionDefinition = new CosmosContainerSettings(UUID.randomUUID().toString(), partitionKeyDef); return collectionDefinition; } @Factory(dataProvider = "simpleClientBuildersWithDirectHttps") - public BackPressureTest(Builder clientBuilder) { + public BackPressureTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @@ -78,76 +88,78 @@ public BackPressureTest(Builder clientBuilder) { public void readFeed() throws Exception { FeedOptions options = new FeedOptions(); options.setMaxItemCount(1); - Observable> queryObservable = client - .readDocuments(getCollectionLink(), options); + options.setEnableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.listItems(options); - client.httpRequests.clear(); + RxDocumentClientUnderTest rxClient = (RxDocumentClientUnderTest)CosmosBridgeInternal.getAsyncDocumentClient(client); + rxClient.httpRequests.clear(); - TestSubscriber subscriber = new TestSubscriber(1); - queryObservable.observeOn(Schedulers.io(), 1).subscribe(subscriber); + TestSubscriber> subscriber = new TestSubscriber>(1); + queryObservable.publishOn(Schedulers.elastic()).subscribe(subscriber); int sleepTimeInMillis = 10000; // 10 seconds int i = 0; // use a test subscriber and request for more result and sleep in between - while (subscriber.getCompletions() == 0 && subscriber.getOnErrorEvents().isEmpty()) { + while (subscriber.completions() == 0 && subscriber.getEvents().get(1).isEmpty()) { TimeUnit.MILLISECONDS.sleep(sleepTimeInMillis); sleepTimeInMillis /= 2; if (sleepTimeInMillis > 1000) { // validate that only one item is returned to subscriber in each iteration - assertThat(subscriber.getValueCount() - i).isEqualTo(1); + assertThat(subscriber.valueCount() - i).isEqualTo(1); } // validate that only one item is returned to subscriber in each iteration // validate that the difference between the number of requests to backend // and the number of returned results is always less than a fixed threshold - assertThat(client.httpRequests.size() - subscriber.getOnNextEvents().size()) - .isLessThanOrEqualTo(RxRingBuffer.SIZE); + assertThat(rxClient.httpRequests.size() - subscriber.getEvents().get(0).size()) + .isLessThanOrEqualTo(Queues.SMALL_BUFFER_SIZE); subscriber.requestMore(1); i++; } subscriber.assertNoErrors(); - subscriber.assertCompleted(); - assertThat(subscriber.getOnNextEvents()).hasSize(createdDocuments.size()); + subscriber.assertComplete(); + assertThat(subscriber.getEvents().get(0)).hasSize(createdDocuments.size()); } @Test(groups = { "long" }, timeOut = TIMEOUT) public void query() throws Exception { FeedOptions options = new FeedOptions(); options.setMaxItemCount(1); - Observable> queryObservable = client - .queryDocuments(getCollectionLink(), "SELECT * from r", options); + options.setEnableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.queryItems("SELECT * from r", options); - client.httpRequests.clear(); + RxDocumentClientUnderTest rxClient = (RxDocumentClientUnderTest)CosmosBridgeInternal.getAsyncDocumentClient(client); + rxClient.httpRequests.clear(); - TestSubscriber subscriber = new TestSubscriber(1); - queryObservable.observeOn(Schedulers.io(), 1).subscribe(subscriber); + TestSubscriber> subscriber = new TestSubscriber>(1); + queryObservable.publishOn(Schedulers.elastic()).subscribe(subscriber); int sleepTimeInMillis = 10000; int i = 0; // use a test subscriber and request for more result and sleep in between - while(subscriber.getCompletions() == 0 && subscriber.getOnErrorEvents().isEmpty()) { + while(subscriber.completions() == 0 && subscriber.getEvents().get(1).isEmpty()) { TimeUnit.MILLISECONDS.sleep(sleepTimeInMillis); sleepTimeInMillis /= 2; if (sleepTimeInMillis > 1000) { // validate that only one item is returned to subscriber in each iteration - assertThat(subscriber.getValueCount() - i).isEqualTo(1); + assertThat(subscriber.valueCount() - i).isEqualTo(1); } // validate that the difference between the number of requests to backend // and the number of returned results is always less than a fixed threshold - assertThat(client.httpRequests.size() - subscriber.getValueCount()) - .isLessThanOrEqualTo(RxRingBuffer.SIZE); + assertThat(rxClient.httpRequests.size() - subscriber.valueCount()) + .isLessThanOrEqualTo(Queues.SMALL_BUFFER_SIZE); subscriber.requestMore(1); i++; } subscriber.assertNoErrors(); - subscriber.assertCompleted(); + subscriber.assertComplete(); - assertThat(subscriber.getOnNextEvents()).hasSize(createdDocuments.size()); + assertThat(subscriber.getEvents().get(0)).hasSize(createdDocuments.size()); } // TODO: DANOBLE: Investigate Direct TCP performance issue @@ -157,35 +169,31 @@ public void query() throws Exception { @BeforeClass(groups = { "long" }, timeOut = 2 * SETUP_TIMEOUT) public void beforeClass() throws Exception { - RequestOptions options = new RequestOptions(); - options.setOfferThroughput(1000); - createdDatabase = SHARED_DATABASE; - createdCollection = createCollection(createdDatabase.getId(), getSinglePartitionCollectionDefinition(), options); - + CosmosContainerRequestOptions options = new CosmosContainerRequestOptions(); + options.offerThroughput(1000); client = new ClientUnderTestBuilder(clientBuilder).build(); + createdDatabase = getSharedCosmosDatabase(client); + + createdCollection = createCollection(createdDatabase, getSinglePartitionCollectionDefinition(), options); + + RxDocumentClientUnderTest rxClient = (RxDocumentClientUnderTest)CosmosBridgeInternal.getAsyncDocumentClient(client); // increase throughput to max for a single partition collection to avoid throttling // for bulk insert and later queries. - Offer offer = client.queryOffers( + Offer offer = rxClient.queryOffers( String.format("SELECT * FROM r WHERE r.offerResourceId = '%s'", - createdCollection.getResourceId()) + createdCollection.read().block().getCosmosContainerSettings().getResourceId()) , null).first().map(FeedResponse::getResults).toBlocking().single().get(0); offer.setThroughput(6000); - offer = client.replaceOffer(offer).toBlocking().single().getResource(); + offer = rxClient.replaceOffer(offer).toBlocking().single().getResource(); assertThat(offer.getThroughput()).isEqualTo(6000); - ArrayList docDefList = new ArrayList<>(); + ArrayList docDefList = new ArrayList<>(); for(int i = 0; i < 1000; i++) { docDefList.add(getDocumentDefinition(i)); } - Observable> documentBulkInsertObs = bulkInsert( - client, - getCollectionLink(), - docDefList, - 200); - - createdDocuments = documentBulkInsertObs.map(ResourceResponse::getResource).toList().toBlocking().single(); + createdDocuments = bulkInsertBlocking(createdCollection, docDefList); waitIfNeededForReplicasToCatchUp(clientBuilder); warmUp(); @@ -193,7 +201,9 @@ public void beforeClass() throws Exception { private void warmUp() { // ensure collection is cached - client.queryDocuments(getCollectionLink(), "SELECT * from r", null).first().toBlocking().single(); + FeedOptions options = new FeedOptions(); + options.setEnableCrossPartitionQuery(true); + createdCollection.queryItems("SELECT * from r", options).blockFirst(); } // TODO: DANOBLE: Investigate Direct TCP performance issue @@ -202,13 +212,13 @@ private void warmUp() { @AfterClass(groups = { "long" }, timeOut = 2 * SHUTDOWN_TIMEOUT, alwaysRun = true) public void afterClass() { - safeDeleteCollection(client, createdCollection); + safeDeleteCollection(createdCollection); safeClose(client); } - private static Document getDocumentDefinition(int cnt) { + private static CosmosItemSettings getDocumentDefinition(int cnt) { String uuid = UUID.randomUUID().toString(); - Document doc = new Document(String.format("{ " + CosmosItemSettings doc = new CosmosItemSettings(String.format("{ " + "\"id\": \"%s\", " + "\"prop\" : %d, " + "\"mypk\": \"%s\", " diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ChangeFeedTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ChangeFeedTest.java index b2446f3330198..2dadeb8bf6df6 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ChangeFeedTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ChangeFeedTest.java @@ -35,13 +35,13 @@ import com.microsoft.azure.cosmosdb.ChangeFeedOptions; import com.microsoft.azure.cosmosdb.Database; import com.microsoft.azure.cosmosdb.Document; -import com.microsoft.azure.cosmosdb.DocumentClientException; import com.microsoft.azure.cosmosdb.DocumentCollection; import com.microsoft.azure.cosmosdb.FeedResponse; import com.microsoft.azure.cosmosdb.PartitionKey; import com.microsoft.azure.cosmosdb.PartitionKeyDefinition; import com.microsoft.azure.cosmosdb.RequestOptions; import com.microsoft.azure.cosmosdb.ResourceResponse; +import com.microsoft.azure.cosmosdb.rx.internal.TestSuiteBase; import org.testng.SkipException; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; @@ -51,10 +51,10 @@ import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; import rx.Observable; +//TODO: change to use external TestSuiteBase public class ChangeFeedTest extends TestSuiteBase { private static final int SETUP_TIMEOUT = 40000; @@ -312,4 +312,4 @@ private static void waitAtleastASecond(ZonedDateTime befTime) throws Interrupted Thread.sleep(100); } } -} +} \ No newline at end of file diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/CollectionCrudTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/CollectionCrudTest.java index 7f157cf677bc3..6ed1c702cf7dc 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/CollectionCrudTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/CollectionCrudTest.java @@ -1,336 +1,333 @@ -/* - * The MIT License (MIT) - * Copyright (c) 2018 Microsoft Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.microsoft.azure.cosmosdb.rx; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.UUID; - -import com.microsoft.azure.cosmosdb.DatabaseForTest; -import com.microsoft.azure.cosmosdb.PartitionKeyDefinition; -import com.microsoft.azure.cosmosdb.RetryAnalyzer; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Factory; -import org.testng.annotations.Test; - -import com.microsoft.azure.cosmosdb.CompositePath; -import com.microsoft.azure.cosmosdb.CompositePathSortOrder; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.Document; -import com.microsoft.azure.cosmosdb.DocumentCollection; -import com.microsoft.azure.cosmosdb.IndexingMode; -import com.microsoft.azure.cosmosdb.IndexingPolicy; -import com.microsoft.azure.cosmosdb.ResourceResponse; -import com.microsoft.azure.cosmosdb.SpatialSpec; -import com.microsoft.azure.cosmosdb.SpatialType; - -import rx.Observable; - -public class CollectionCrudTest extends TestSuiteBase { - private static final int TIMEOUT = 50000; - private static final int SETUP_TIMEOUT = 20000; - private static final int SHUTDOWN_TIMEOUT = 20000; - private final String databaseId = DatabaseForTest.generateId(); - - private AsyncDocumentClient client; - private Database database; - - @Factory(dataProvider = "clientBuildersWithDirect") - public CollectionCrudTest(AsyncDocumentClient.Builder clientBuilder) { - this.clientBuilder = clientBuilder; - this.subscriberValidationTimeout = TIMEOUT; - } - - @DataProvider(name = "collectionCrudArgProvider") - public Object[][] collectionCrudArgProvider() { - return new Object[][] { - // collection name, is name base - {UUID.randomUUID().toString(), false } , - {UUID.randomUUID().toString(), true } , - - // with special characters in the name. - {"+ -_,:.|~" + UUID.randomUUID().toString() + " +-_,:.|~", true } , - }; - } - - private DocumentCollection getCollectionDefinition(String collectionName) { - PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); - ArrayList paths = new ArrayList(); - paths.add("/mypk"); - partitionKeyDef.setPaths(paths); - - DocumentCollection collectionDefinition = new DocumentCollection(); - collectionDefinition.setId(collectionName); - collectionDefinition.setPartitionKey(partitionKeyDef); - - return collectionDefinition; - } - - @Test(groups = { "emulator" }, timeOut = TIMEOUT, dataProvider = "collectionCrudArgProvider") - public void createCollection(String collectionName, boolean isNameBased) { - DocumentCollection collectionDefinition = getCollectionDefinition(collectionName); - - Observable> createObservable = client - .createCollection(getDatabaseLink(database, isNameBased), collectionDefinition, null); - - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() - .withId(collectionDefinition.getId()).build(); - - validateSuccess(createObservable, validator); - safeDeleteAllCollections(client, database); - } - - @Test(groups = { "emulator" }, timeOut = TIMEOUT) - public void createCollectionWithCompositeIndexAndSpatialSpec() { - DocumentCollection collection = new DocumentCollection(); - - IndexingPolicy indexingPolicy = new IndexingPolicy(); - CompositePath compositePath1 = new CompositePath(); - compositePath1.setPath("/path1"); - compositePath1.setOrder(CompositePathSortOrder.Ascending); - CompositePath compositePath2 = new CompositePath(); - compositePath2.setPath("/path2"); - compositePath2.setOrder(CompositePathSortOrder.Descending); - CompositePath compositePath3 = new CompositePath(); - compositePath3.setPath("/path3"); - CompositePath compositePath4 = new CompositePath(); - compositePath4.setPath("/path4"); - compositePath4.setOrder(CompositePathSortOrder.Ascending); - CompositePath compositePath5 = new CompositePath(); - compositePath5.setPath("/path5"); - compositePath5.setOrder(CompositePathSortOrder.Descending); - CompositePath compositePath6 = new CompositePath(); - compositePath6.setPath("/path6"); - - ArrayList compositeIndex1 = new ArrayList(); - compositeIndex1.add(compositePath1); - compositeIndex1.add(compositePath2); - compositeIndex1.add(compositePath3); - - ArrayList compositeIndex2 = new ArrayList(); - compositeIndex2.add(compositePath4); - compositeIndex2.add(compositePath5); - compositeIndex2.add(compositePath6); - - Collection> compositeIndexes = new ArrayList>(); - compositeIndexes.add(compositeIndex1); - compositeIndexes.add(compositeIndex2); - indexingPolicy.setCompositeIndexes(compositeIndexes); - - SpatialType[] spatialTypes = new SpatialType[] { - SpatialType.Point, - SpatialType.LineString, - SpatialType.Polygon, - SpatialType.MultiPolygon - }; - Collection spatialIndexes = new ArrayList(); - for (int index = 0; index < 2; index++) { - Collection collectionOfSpatialTypes = new ArrayList(); - - SpatialSpec spec = new SpatialSpec(); - spec.setPath("/path" + index + "/*"); - - for (int i = index; i < index + 3; i++) { - collectionOfSpatialTypes.add(spatialTypes[i]); - } - spec.setSpatialTypes(collectionOfSpatialTypes); - spatialIndexes.add(spec); - } - - indexingPolicy.setSpatialIndexes(spatialIndexes); - - collection.setId(UUID.randomUUID().toString()); - collection.setIndexingPolicy(indexingPolicy); - - Observable> createObservable = client - .createCollection(database.getSelfLink(), collection, null); - - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() - .withId(collection.getId()) - .withCompositeIndexes(compositeIndexes) - .withSpatialIndexes(spatialIndexes) - .build(); - - validateSuccess(createObservable, validator); - safeDeleteAllCollections(client, database); - } - - @Test(groups = { "emulator" }, timeOut = TIMEOUT, dataProvider = "collectionCrudArgProvider") - public void readCollection(String collectionName, boolean isNameBased) { - DocumentCollection collectionDefinition = getCollectionDefinition(collectionName); - - Observable> createObservable = client.createCollection(getDatabaseLink(database, isNameBased), collectionDefinition, - null); - DocumentCollection collection = createObservable.toBlocking().single().getResource(); - - Observable> readObservable = client.readCollection(getCollectionLink(database, collection, isNameBased), null); - - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() - .withId(collection.getId()).build(); - validateSuccess(readObservable, validator); - safeDeleteAllCollections(client, database); - } - - @Test(groups = { "emulator" }, timeOut = TIMEOUT, dataProvider = "collectionCrudArgProvider") - public void readCollection_NameBase(String collectionName, boolean isNameBased) { - DocumentCollection collectionDefinition = getCollectionDefinition(collectionName); - - Observable> createObservable = client.createCollection(getDatabaseLink(database, isNameBased), collectionDefinition, - null); - DocumentCollection collection = createObservable.toBlocking().single().getResource(); - - Observable> readObservable = client.readCollection( - getCollectionLink(database, collection, isNameBased), null); - - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() - .withId(collection.getId()).build(); - validateSuccess(readObservable, validator); - safeDeleteAllCollections(client, database); - } - - @Test(groups = { "emulator" }, timeOut = TIMEOUT, dataProvider = "collectionCrudArgProvider") - public void readCollection_DoesntExist(String collectionName, boolean isNameBased) throws Exception { - - Observable> readObservable = client - .readCollection(Utils.getCollectionNameLink(database.getId(), "I don't exist"), null); - - FailureValidator validator = new FailureValidator.Builder().resourceNotFound().build(); - validateFailure(readObservable, validator); - } - - @Test(groups = { "emulator" }, timeOut = TIMEOUT, dataProvider = "collectionCrudArgProvider") - public void deleteCollection(String collectionName, boolean isNameBased) { - DocumentCollection collectionDefinition = getCollectionDefinition(collectionName); - - Observable> createObservable = client.createCollection(getDatabaseLink(database, isNameBased), collectionDefinition, null); - DocumentCollection collection = createObservable.toBlocking().single().getResource(); - - Observable> deleteObservable = client.deleteCollection(getCollectionLink(database, collection, isNameBased), - null); - - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() - .nullResource().build(); - validateSuccess(deleteObservable, validator); - } - - @Test(groups = { "emulator" }, timeOut = TIMEOUT, dataProvider = "collectionCrudArgProvider") - public void replaceCollection(String collectionName, boolean isNameBased) { - // create a collection - DocumentCollection collectionDefinition = getCollectionDefinition(collectionName); - Observable> createObservable = client.createCollection(getDatabaseLink(database, isNameBased), collectionDefinition, null); - DocumentCollection collection = createObservable.toBlocking().single().getResource(); - // sanity check - assertThat(collection.getIndexingPolicy().getIndexingMode()).isEqualTo(IndexingMode.Consistent); - - // replace indexing mode - IndexingPolicy indexingMode = new IndexingPolicy(); - indexingMode.setIndexingMode(IndexingMode.Lazy); - collection.setIndexingPolicy(indexingMode); - Observable> readObservable = client.replaceCollection(collection, null); - - // validate - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() - .indexingMode(IndexingMode.Lazy).build(); - validateSuccess(readObservable, validator); - safeDeleteAllCollections(client, database); - } - - @Test(groups = { "emulator" }, timeOut = 10 * TIMEOUT, retryAnalyzer = RetryAnalyzer.class) - public void sessionTokenConsistencyCollectionDeleteCreateSameName() { - AsyncDocumentClient client1 = clientBuilder.build(); - AsyncDocumentClient client2 = clientBuilder.build(); - - String dbId = DatabaseForTest.generateId(); - String collectionId = "coll"; - try { - Database databaseDefinition = new Database(); - databaseDefinition.setId(dbId); - createDatabase(client1, dbId); - - DocumentCollection collectionDefinition = new DocumentCollection(); - collectionDefinition.setId(collectionId); - DocumentCollection collection = createCollection(client1, dbId, collectionDefinition); - - Document document = new Document(); - document.setId("doc"); - document.set("name", "New Document"); - createDocument(client1, dbId, collectionId, document); - ResourceResponse readDocumentResponse = client1.readDocument(Utils.getDocumentNameLink(dbId, collectionId, document.getId()), null).toBlocking().single(); - logger.info("Client 1 Read Document Client Side Request Statistics {}", readDocumentResponse.getRequestDiagnosticsString()); - logger.info("Client 1 Read Document Latency {}", readDocumentResponse.getRequestLatency()); - - document.set("name", "New Updated Document"); - ResourceResponse upsertDocumentResponse = client1.upsertDocument(collection.getSelfLink(), document, null, - true).toBlocking().single(); - logger.info("Client 1 Upsert Document Client Side Request Statistics {}", upsertDocumentResponse.getRequestDiagnosticsString()); - logger.info("Client 1 Upsert Document Latency {}", upsertDocumentResponse.getRequestLatency()); - - // Delete the existing collection - deleteCollection(client2, Utils.getCollectionNameLink(dbId, collectionId)); - // Recreate the collection with the same name but with different client - createCollection(client2, dbId, collectionDefinition); - - Document newDocument = new Document(); - newDocument.setId("doc"); - newDocument.set("name", "New Created Document"); - createDocument(client2, dbId, collectionId, newDocument); - - readDocumentResponse = client1.readDocument(Utils.getDocumentNameLink(dbId, collectionId, newDocument.getId()), null).toBlocking().single(); - logger.info("Client 2 Read Document Client Side Request Statistics {}", readDocumentResponse.getRequestDiagnosticsString()); - logger.info("Client 2 Read Document Latency {}", readDocumentResponse.getRequestLatency()); - - Document readDocument = readDocumentResponse.getResource(); - - assertThat(readDocument.getId().equals(newDocument.getId())).isTrue(); - assertThat(readDocument.get("name").equals(newDocument.get("name"))).isTrue(); - } finally { - safeDeleteDatabase(client1, dbId); - safeClose(client1); - safeClose(client2); - } - } - - @BeforeClass(groups = { "emulator" }, timeOut = SETUP_TIMEOUT) - public void beforeClass() { - client = clientBuilder.build(); - database = createDatabase(client, databaseId); - } - - @AfterClass(groups = { "emulator" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) - public void afterClass() { - safeDeleteDatabase(client, databaseId); - safeClose(client); - } - - private static String getDatabaseLink(Database db, boolean isNameLink) { - return isNameLink ? "dbs/" + db.getId() : db.getSelfLink(); - } - - private static String getCollectionLink(Database db, DocumentCollection documentCollection, boolean isNameLink) { - return isNameLink ? "dbs/" + db.getId() + "/colls/" + documentCollection.getId() : documentCollection.getSelfLink(); - } -} +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.microsoft.azure.cosmosdb.rx; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.UUID; + +import com.microsoft.azure.cosmos.CosmosClientBuilder; +import com.microsoft.azure.cosmosdb.PartitionKeyDefinition; +import com.microsoft.azure.cosmosdb.RetryAnalyzer; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; + +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosContainerRequestOptions; +import com.microsoft.azure.cosmos.CosmosContainerResponse; +import com.microsoft.azure.cosmos.CosmosContainerSettings; +import com.microsoft.azure.cosmos.CosmosDatabase; +import com.microsoft.azure.cosmos.CosmosItem; +import com.microsoft.azure.cosmos.CosmosItemRequestOptions; +import com.microsoft.azure.cosmos.CosmosItemResponse; +import com.microsoft.azure.cosmos.CosmosItemSettings; +import com.microsoft.azure.cosmos.CosmosResponseValidator; +import com.microsoft.azure.cosmos.CosmosDatabaseForTest; +import com.microsoft.azure.cosmosdb.CompositePath; +import com.microsoft.azure.cosmosdb.CompositePathSortOrder; +import com.microsoft.azure.cosmosdb.Database; +import com.microsoft.azure.cosmosdb.IndexingMode; +import com.microsoft.azure.cosmosdb.IndexingPolicy; +import com.microsoft.azure.cosmosdb.PartitionKey; +import com.microsoft.azure.cosmosdb.SpatialSpec; +import com.microsoft.azure.cosmosdb.SpatialType; + +import reactor.core.publisher.Mono; + +public class CollectionCrudTest extends TestSuiteBase { + private static final int TIMEOUT = 50000; + private static final int SETUP_TIMEOUT = 20000; + private static final int SHUTDOWN_TIMEOUT = 20000; + private final String databaseId = CosmosDatabaseForTest.generateId(); + + private CosmosClient client; + private CosmosDatabase database; + + @Factory(dataProvider = "clientBuildersWithDirect") + public CollectionCrudTest(CosmosClientBuilder clientBuilder) { + this.clientBuilder = clientBuilder; + this.subscriberValidationTimeout = TIMEOUT; + } + + @DataProvider(name = "collectionCrudArgProvider") + public Object[][] collectionCrudArgProvider() { + return new Object[][] { + // collection name, is name base + {UUID.randomUUID().toString()} , + + // with special characters in the name. + {"+ -_,:.|~" + UUID.randomUUID().toString() + " +-_,:.|~"} , + }; + } + + private CosmosContainerSettings getCollectionDefinition(String collectionName) { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.setPaths(paths); + + CosmosContainerSettings collectionDefinition = new CosmosContainerSettings( + collectionName, + partitionKeyDef); + + return collectionDefinition; + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT, dataProvider = "collectionCrudArgProvider") + public void createCollection(String collectionName) throws InterruptedException { + CosmosContainerSettings collectionDefinition = getCollectionDefinition(collectionName); + + Mono createObservable = database + .createContainer(collectionDefinition); + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(collectionDefinition.getId()).build(); + + validateSuccess(createObservable, validator); + safeDeleteAllCollections(database); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT) + public void createCollectionWithCompositeIndexAndSpatialSpec() throws InterruptedException { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.setPaths(paths); + + CosmosContainerSettings collection = new CosmosContainerSettings( + UUID.randomUUID().toString(), + partitionKeyDef); + + IndexingPolicy indexingPolicy = new IndexingPolicy(); + CompositePath compositePath1 = new CompositePath(); + compositePath1.setPath("/path1"); + compositePath1.setOrder(CompositePathSortOrder.Ascending); + CompositePath compositePath2 = new CompositePath(); + compositePath2.setPath("/path2"); + compositePath2.setOrder(CompositePathSortOrder.Descending); + CompositePath compositePath3 = new CompositePath(); + compositePath3.setPath("/path3"); + CompositePath compositePath4 = new CompositePath(); + compositePath4.setPath("/path4"); + compositePath4.setOrder(CompositePathSortOrder.Ascending); + CompositePath compositePath5 = new CompositePath(); + compositePath5.setPath("/path5"); + compositePath5.setOrder(CompositePathSortOrder.Descending); + CompositePath compositePath6 = new CompositePath(); + compositePath6.setPath("/path6"); + + ArrayList compositeIndex1 = new ArrayList(); + compositeIndex1.add(compositePath1); + compositeIndex1.add(compositePath2); + compositeIndex1.add(compositePath3); + + ArrayList compositeIndex2 = new ArrayList(); + compositeIndex2.add(compositePath4); + compositeIndex2.add(compositePath5); + compositeIndex2.add(compositePath6); + + Collection> compositeIndexes = new ArrayList>(); + compositeIndexes.add(compositeIndex1); + compositeIndexes.add(compositeIndex2); + indexingPolicy.setCompositeIndexes(compositeIndexes); + + SpatialType[] spatialTypes = new SpatialType[] { + SpatialType.Point, + SpatialType.LineString, + SpatialType.Polygon, + SpatialType.MultiPolygon + }; + Collection spatialIndexes = new ArrayList(); + for (int index = 0; index < 2; index++) { + Collection collectionOfSpatialTypes = new ArrayList(); + + SpatialSpec spec = new SpatialSpec(); + spec.setPath("/path" + index + "/*"); + + for (int i = index; i < index + 3; i++) { + collectionOfSpatialTypes.add(spatialTypes[i]); + } + spec.setSpatialTypes(collectionOfSpatialTypes); + spatialIndexes.add(spec); + } + + indexingPolicy.setSpatialIndexes(spatialIndexes); + + collection.setIndexingPolicy(indexingPolicy); + + Mono createObservable = database + .createContainer(collection, new CosmosContainerRequestOptions()); + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(collection.getId()) + .withCompositeIndexes(compositeIndexes) + .withSpatialIndexes(spatialIndexes) + .build(); + + validateSuccess(createObservable, validator); + safeDeleteAllCollections(database); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT, dataProvider = "collectionCrudArgProvider") + public void readCollection(String collectionName) throws InterruptedException { + CosmosContainerSettings collectionDefinition = getCollectionDefinition(collectionName); + + Mono createObservable = database.createContainer(collectionDefinition); + CosmosContainer collection = createObservable.block().getContainer(); + + Mono readObservable = collection.read(); + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(collection.getId()).build(); + validateSuccess(readObservable, validator); + safeDeleteAllCollections(database); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT, dataProvider = "collectionCrudArgProvider") + public void readCollection_DoesntExist(String collectionName) throws Exception { + + Mono readObservable = database + .getContainer("I don't exist").read(); + + FailureValidator validator = new FailureValidator.Builder().resourceNotFound().build(); + validateFailure(readObservable, validator); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT, dataProvider = "collectionCrudArgProvider") + public void deleteCollection(String collectionName) throws InterruptedException { + CosmosContainerSettings collectionDefinition = getCollectionDefinition(collectionName); + + Mono createObservable = database.createContainer(collectionDefinition); + CosmosContainer collection = createObservable.block().getContainer(); + + Mono deleteObservable = collection.delete(); + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .nullResource().build(); + validateSuccess(deleteObservable, validator); + } + + @Test(groups = { "emulator" }, timeOut = TIMEOUT, dataProvider = "collectionCrudArgProvider") + public void replaceCollection(String collectionName) throws InterruptedException { + // create a collection + CosmosContainerSettings collectionDefinition = getCollectionDefinition(collectionName); + Mono createObservable = database.createContainer(collectionDefinition); + CosmosContainer collection = createObservable.block().getContainer(); + CosmosContainerSettings collectionSettings = collection.read().block().getCosmosContainerSettings(); + // sanity check + assertThat(collectionSettings.getIndexingPolicy().getIndexingMode()).isEqualTo(IndexingMode.Consistent); + + // replace indexing mode + IndexingPolicy indexingMode = new IndexingPolicy(); + indexingMode.setIndexingMode(IndexingMode.Lazy); + collectionSettings.setIndexingPolicy(indexingMode); + Mono readObservable = collection.replace(collectionSettings, new CosmosContainerRequestOptions()); + + // validate + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .indexingMode(IndexingMode.Lazy).build(); + validateSuccess(readObservable, validator); + safeDeleteAllCollections(database); + } + + @Test(groups = { "emulator" }, timeOut = 10 * TIMEOUT, retryAnalyzer = RetryAnalyzer.class) + public void sessionTokenConsistencyCollectionDeleteCreateSameName() { + CosmosClient client1 = clientBuilder.build(); + CosmosClient client2 = clientBuilder.build(); + + String dbId = CosmosDatabaseForTest.generateId(); + String collectionId = "coll"; + CosmosDatabase db = null; + try { + Database databaseDefinition = new Database(); + databaseDefinition.setId(dbId); + db = createDatabase(client1, dbId); + + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.setPaths(paths); + + CosmosContainerSettings collectionDefinition = new CosmosContainerSettings(collectionId, partitionKeyDef); + CosmosContainer collection = createCollection(db, collectionDefinition, new CosmosContainerRequestOptions()); + + CosmosItemSettings document = new CosmosItemSettings(); + document.setId("doc"); + document.set("name", "New Document"); + document.set("mypk", "mypkValue"); + CosmosItem item = createDocument(collection, document); + CosmosItemRequestOptions options = new CosmosItemRequestOptions(); + options.setPartitionKey(new PartitionKey("mypkValue")); + CosmosItemResponse readDocumentResponse = item.read(options).block(); + logger.info("Client 1 Read Document Client Side Request Statistics {}", readDocumentResponse.getRequestDiagnosticsString()); + logger.info("Client 1 Read Document Latency {}", readDocumentResponse.getRequestLatency()); + + document.set("name", "New Updated Document"); + CosmosItemResponse upsertDocumentResponse = collection.upsertItem(document).block(); + logger.info("Client 1 Upsert Document Client Side Request Statistics {}", upsertDocumentResponse.getRequestDiagnosticsString()); + logger.info("Client 1 Upsert Document Latency {}", upsertDocumentResponse.getRequestLatency()); + + // Delete the existing collection + deleteCollection(client2, dbId, collectionId); + // Recreate the collection with the same name but with different client + CosmosContainer collection2 = createCollection(client2, dbId, collectionDefinition); + + CosmosItemSettings newDocument = new CosmosItemSettings(); + newDocument.setId("doc"); + newDocument.set("name", "New Created Document"); + newDocument.set("mypk", "mypk"); + createDocument(collection2, newDocument); + + readDocumentResponse = client1.getDatabase(dbId).getContainer(collectionId).getItem(newDocument.getId(), newDocument.get("mypk")).read().block(); + logger.info("Client 2 Read Document Client Side Request Statistics {}", readDocumentResponse.getRequestDiagnosticsString()); + logger.info("Client 2 Read Document Latency {}", readDocumentResponse.getRequestLatency()); + + CosmosItemSettings readDocument = readDocumentResponse.getCosmosItemSettings(); + + assertThat(readDocument.getId().equals(newDocument.getId())).isTrue(); + assertThat(readDocument.get("name").equals(newDocument.get("name"))).isTrue(); + } finally { + safeDeleteDatabase(db); + safeClose(client1); + safeClose(client2); + } + } + + @BeforeClass(groups = { "emulator" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder.build(); + database = createDatabase(client, databaseId); + } + + @AfterClass(groups = { "emulator" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeDeleteDatabase(database); + safeClose(client); + } +} diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/CollectionQueryTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/CollectionQueryTest.java index 0a4500c9d6a78..dff6d520b0dcf 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/CollectionQueryTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/CollectionQueryTest.java @@ -29,33 +29,33 @@ import java.util.UUID; import java.util.stream.Collectors; -import com.microsoft.azure.cosmosdb.DatabaseForTest; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import org.apache.commons.lang3.StringUtils; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.DocumentCollection; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosContainerSettings; +import com.microsoft.azure.cosmos.CosmosDatabase; +import com.microsoft.azure.cosmos.CosmosDatabaseForTest; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; +import com.microsoft.azure.cosmosdb.PartitionKeyDefinition; -import rx.Observable; +import reactor.core.publisher.Flux; public class CollectionQueryTest extends TestSuiteBase { private final static int TIMEOUT = 30000; - private final String databaseId = DatabaseForTest.generateId(); - private List createdCollections = new ArrayList<>(); - private AsyncDocumentClient client; + private final String databaseId = CosmosDatabaseForTest.generateId(); + private List createdCollections = new ArrayList<>(); + private CosmosClient client; + private CosmosDatabase createdDatabase; - private String getDatabaseLink() { - return Utils.getDatabaseNameLink(databaseId); - } - - @Factory(dataProvider = "clientBuilders") - public CollectionQueryTest(Builder clientBuilder) { + @Factory(dataProvider = "clientBuilders") + public CollectionQueryTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; this.subscriberValidationTimeout = TIMEOUT; } @@ -68,20 +68,20 @@ public void queryCollectionsWithFilter() throws Exception { FeedOptions options = new FeedOptions(); options.setMaxItemCount(2); - Observable> queryObservable = client.queryCollections(getDatabaseLink(), query, options); + Flux> queryObservable = createdDatabase.queryContainers(query, options); - List expectedCollections = createdCollections.stream() + List expectedCollections = createdCollections.stream() .filter(c -> StringUtils.equals(filterCollectionId, c.getId()) ).collect(Collectors.toList()); assertThat(expectedCollections).isNotEmpty(); int expectedPageSize = (expectedCollections.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .totalSize(expectedCollections.size()) - .exactlyContainsInAnyOrder(expectedCollections.stream().map(d -> d.getResourceId()).collect(Collectors.toList())) + .exactlyContainsInAnyOrder(expectedCollections.stream().map(d -> d.read().block().getCosmosContainerSettings().getResourceId()).collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .pageSatisfy(0, new FeedResponseValidator.Builder() + .pageSatisfy(0, new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); @@ -95,20 +95,19 @@ public void queryAllCollections() throws Exception { FeedOptions options = new FeedOptions(); options.setMaxItemCount(2); - String databaseLink = Utils.getDatabaseNameLink(databaseId); - Observable> queryObservable = client.queryCollections(databaseLink, query, options); + Flux> queryObservable = createdDatabase.queryContainers(query, options); - List expectedCollections = createdCollections; + List expectedCollections = createdCollections; assertThat(expectedCollections).isNotEmpty(); int expectedPageSize = (expectedCollections.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .totalSize(expectedCollections.size()) - .exactlyContainsInAnyOrder(expectedCollections.stream().map(d -> d.getResourceId()).collect(Collectors.toList())) + .exactlyContainsInAnyOrder(expectedCollections.stream().map(d -> d.read().block().getCosmosContainerSettings().getResourceId()).collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .pageSatisfy(0, new FeedResponseValidator.Builder() + .pageSatisfy(0, new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); @@ -121,12 +120,12 @@ public void queryCollections_NoResults() throws Exception { String query = "SELECT * from root r where r.id = '2'"; FeedOptions options = new FeedOptions(); options.setEnableCrossPartitionQuery(true); - Observable> queryObservable = client.queryCollections(getDatabaseLink(), query, options); + Flux> queryObservable = createdDatabase.queryContainers(query, options); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .containsExactly(new ArrayList<>()) .numberOfPages(1) - .pageSatisfy(0, new FeedResponseValidator.Builder() + .pageSatisfy(0, new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); validateQuerySuccess(queryObservable, validator); @@ -135,16 +134,20 @@ public void queryCollections_NoResults() throws Exception { @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) public void beforeClass() throws Exception { client = clientBuilder.build(); - createDatabase(client, databaseId); + createdDatabase = createDatabase(client, databaseId); + + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.setPaths(paths); - DocumentCollection collection = new DocumentCollection(); - collection.setId(UUID.randomUUID().toString()); + CosmosContainerSettings collection = new CosmosContainerSettings(UUID.randomUUID().toString(), partitionKeyDef); createdCollections.add(createCollection(client, databaseId, collection)); } @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) public void afterClass() { - safeDeleteDatabase(client, databaseId); + safeDeleteDatabase(createdDatabase); safeClose(client); } } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/DatabaseCrudTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/DatabaseCrudTest.java index 3df99491e5b24..01f4b02193868 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/DatabaseCrudTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/DatabaseCrudTest.java @@ -22,61 +22,59 @@ */ package com.microsoft.azure.cosmosdb.rx; -import com.microsoft.azure.cosmosdb.DatabaseForTest; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import org.testng.annotations.AfterClass; -import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; -import org.testng.annotations.BeforeMethod; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.ResourceResponse; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosDatabase; +import com.microsoft.azure.cosmos.CosmosDatabaseRequestOptions; +import com.microsoft.azure.cosmos.CosmosDatabaseResponse; +import com.microsoft.azure.cosmos.CosmosDatabaseSettings; +import com.microsoft.azure.cosmos.CosmosResponseValidator; +import com.microsoft.azure.cosmos.CosmosDatabaseForTest; -import rx.Observable; - -import javax.net.ssl.SSLException; +import reactor.core.publisher.Mono; import java.util.ArrayList; import java.util.List; public class DatabaseCrudTest extends TestSuiteBase { - private final String preExistingDatabaseId = DatabaseForTest.generateId(); + private final String preExistingDatabaseId = CosmosDatabaseForTest.generateId(); private final List databases = new ArrayList<>(); - private AsyncDocumentClient client; + private CosmosClient client; + private CosmosDatabase createdDatabase; @Factory(dataProvider = "clientBuilders") - public DatabaseCrudTest(Builder clientBuilder) { + public DatabaseCrudTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @Test(groups = { "emulator" }, timeOut = TIMEOUT) public void createDatabase() throws Exception { - Database databaseDefinition = new Database(); - databaseDefinition.setId(DatabaseForTest.generateId()); + CosmosDatabaseSettings databaseDefinition = new CosmosDatabaseSettings(CosmosDatabaseForTest.generateId()); databases.add(databaseDefinition.getId()); // create the database - Observable> createObservable = client.createDatabase(databaseDefinition, null); + Mono createObservable = client.createDatabase(databaseDefinition, new CosmosDatabaseRequestOptions()); // validate - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .withId(databaseDefinition.getId()).build(); validateSuccess(createObservable, validator); } @Test(groups = { "emulator" }, timeOut = TIMEOUT) public void createDatabase_AlreadyExists() throws Exception { - Database databaseDefinition = new Database(); - databaseDefinition.setId(DatabaseForTest.generateId()); + CosmosDatabaseSettings databaseDefinition = new CosmosDatabaseSettings(CosmosDatabaseForTest.generateId()); databases.add(databaseDefinition.getId()); - client.createDatabase(databaseDefinition, null).toBlocking().single(); + client.createDatabase(databaseDefinition, new CosmosDatabaseRequestOptions()).block(); // attempt to create the database - Observable> createObservable = client.createDatabase(databaseDefinition, null); + Mono createObservable = client.createDatabase(databaseDefinition, new CosmosDatabaseRequestOptions()); // validate FailureValidator validator = new FailureValidator.Builder().resourceAlreadyExists().build(); @@ -86,11 +84,10 @@ public void createDatabase_AlreadyExists() throws Exception { @Test(groups = { "emulator" }, timeOut = TIMEOUT) public void readDatabase() throws Exception { // read database - Observable> readObservable = client - .readDatabase(Utils.getDatabaseNameLink(preExistingDatabaseId), null); + Mono readObservable = client.getDatabase(preExistingDatabaseId).read(); // validate - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .withId(preExistingDatabaseId).build(); validateSuccess(readObservable, validator); } @@ -98,8 +95,7 @@ public void readDatabase() throws Exception { @Test(groups = { "emulator" }, timeOut = TIMEOUT) public void readDatabase_DoesntExist() throws Exception { // read database - Observable> readObservable = client - .readDatabase(Utils.getDatabaseNameLink("I don't exist"), null); + Mono readObservable = client.getDatabase("I don't exist").read(); // validate FailureValidator validator = new FailureValidator.Builder().resourceNotFound().build(); @@ -110,17 +106,15 @@ public void readDatabase_DoesntExist() throws Exception { @Test(groups = { "emulator" }, timeOut = TIMEOUT) public void deleteDatabase() throws Exception { // create the database - Database databaseDefinition = new Database(); - databaseDefinition.setId(DatabaseForTest.generateId()); + CosmosDatabaseSettings databaseDefinition = new CosmosDatabaseSettings(CosmosDatabaseForTest.generateId()); databases.add(databaseDefinition.getId()); - client.createDatabase(databaseDefinition, null).toCompletable().await(); + CosmosDatabase database = client.createDatabase(databaseDefinition, new CosmosDatabaseRequestOptions()).block().getDatabase(); // delete the database - Observable> deleteObservable = client - .deleteDatabase(Utils.getDatabaseNameLink(databaseDefinition.getId()), null); + Mono deleteObservable = database.delete(); // validate - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .nullResource().build(); validateSuccess(deleteObservable, validator); } @@ -128,8 +122,7 @@ public void deleteDatabase() throws Exception { @Test(groups = { "emulator" }, timeOut = TIMEOUT) public void deleteDatabase_DoesntExist() throws Exception { // delete the database - Observable> deleteObservable = client - .deleteDatabase(Utils.getDatabaseNameLink("I don't exist"), null); + Mono deleteObservable = client.getDatabase("I don't exist").delete(); // validate FailureValidator validator = new FailureValidator.Builder().resourceNotFound().build(); @@ -139,14 +132,14 @@ public void deleteDatabase_DoesntExist() throws Exception { @BeforeClass(groups = { "emulator" }, timeOut = SETUP_TIMEOUT) public void beforeClass() { client = clientBuilder.build(); - createDatabase(client, preExistingDatabaseId); + createdDatabase = createDatabase(client, preExistingDatabaseId); } @AfterClass(groups = { "emulator" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) public void afterClass() { - safeDeleteDatabase(client, preExistingDatabaseId); + safeDeleteDatabase(createdDatabase); for(String dbId: databases) { - safeDeleteDatabase(client, dbId); + safeDeleteDatabase(client.getDatabase(dbId)); } safeClose(client); } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/DatabaseQueryTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/DatabaseQueryTest.java index 832e8fe62ea83..6a399ba68206d 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/DatabaseQueryTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/DatabaseQueryTest.java @@ -28,31 +28,33 @@ import java.util.List; import java.util.stream.Collectors; -import com.microsoft.azure.cosmosdb.DatabaseForTest; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import org.apache.commons.lang3.StringUtils; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.Database; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosDatabase; +import com.microsoft.azure.cosmos.CosmosDatabaseSettings; +import com.microsoft.azure.cosmos.CosmosDatabaseForTest; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; -import rx.Observable; +import reactor.core.publisher.Flux; public class DatabaseQueryTest extends TestSuiteBase { - public final String databaseId1 = DatabaseForTest.generateId(); - public final String databaseId2 = DatabaseForTest.generateId(); + public final String databaseId1 = CosmosDatabaseForTest.generateId(); + public final String databaseId2 = CosmosDatabaseForTest.generateId(); - private List createdDatabases = new ArrayList<>(); + private List createdDatabases = new ArrayList<>(); - private AsyncDocumentClient client; + private CosmosClient client; @Factory(dataProvider = "clientBuilders") - public DatabaseQueryTest(Builder clientBuilder) { + public DatabaseQueryTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @@ -62,20 +64,20 @@ public void queryDatabaseWithFilter() throws Exception { FeedOptions options = new FeedOptions(); options.setMaxItemCount(2); - Observable> queryObservable = client.queryDatabases(query, options); + Flux> queryObservable = client.queryDatabases(query, options); - List expectedDatabases = createdDatabases.stream() - .filter(d -> StringUtils.equals(databaseId1, d.getId()) ).collect(Collectors.toList()); + List expectedDatabases = createdDatabases.stream() + .filter(d -> StringUtils.equals(databaseId1, d.getId()) ).map(d -> d.read().block().getCosmosDatabaseSettings()).collect(Collectors.toList()); assertThat(expectedDatabases).isNotEmpty(); int expectedPageSize = (expectedDatabases.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .totalSize(expectedDatabases.size()) .exactlyContainsInAnyOrder(expectedDatabases.stream().map(d -> d.getResourceId()).collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .pageSatisfy(0, new FeedResponseValidator.Builder() + .pageSatisfy(0, new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); @@ -91,19 +93,19 @@ public void queryAllDatabase() throws Exception { FeedOptions options = new FeedOptions(); options.setMaxItemCount(2); - Observable> queryObservable = client.queryDatabases(query, options); + Flux> queryObservable = client.queryDatabases(query, options); - List expectedDatabases = createdDatabases; + List expectedDatabases = createdDatabases.stream().map(d -> d.read().block().getCosmosDatabaseSettings()).collect(Collectors.toList()); assertThat(expectedDatabases).isNotEmpty(); int expectedPageSize = (expectedDatabases.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .totalSize(expectedDatabases.size()) .exactlyContainsInAnyOrder(expectedDatabases.stream().map(d -> d.getResourceId()).collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .pageSatisfy(0, new FeedResponseValidator.Builder() + .pageSatisfy(0, new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); @@ -116,12 +118,12 @@ public void queryDatabases_NoResults() throws Exception { String query = "SELECT * from root r where r.id = '2'"; FeedOptions options = new FeedOptions(); options.setEnableCrossPartitionQuery(true); - Observable> queryObservable = client.queryDatabases(query, options); + Flux> queryObservable = client.queryDatabases(query, options); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .containsExactly(new ArrayList<>()) .numberOfPages(1) - .pageSatisfy(0, new FeedResponseValidator.Builder() + .pageSatisfy(0, new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); validateQuerySuccess(queryObservable, validator); @@ -130,20 +132,14 @@ public void queryDatabases_NoResults() throws Exception { @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) public void beforeClass() throws Exception { client = clientBuilder.build(); - - Database d1 = new Database(); - d1.setId(databaseId1); - createdDatabases.add(createDatabase(client, d1)); - - Database d2 = new Database(); - d2.setId(databaseId2); - createdDatabases.add(createDatabase(client, d2)); + createdDatabases.add(createDatabase(client, databaseId1)); + createdDatabases.add(createDatabase(client, databaseId2)); } @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) public void afterClass() { - safeDeleteDatabase(client, databaseId1); - safeDeleteDatabase(client, databaseId2); + safeDeleteDatabase(createdDatabases.get(0)); + safeDeleteDatabase(createdDatabases.get(1)); safeClose(client); } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/DocumentClientResourceLeakTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/DocumentClientResourceLeakTest.java index e3a1df72d70a5..333f0c148500f 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/DocumentClientResourceLeakTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/DocumentClientResourceLeakTest.java @@ -22,11 +22,12 @@ */ package com.microsoft.azure.cosmosdb.rx; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.Document; -import com.microsoft.azure.cosmosdb.DocumentCollection; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosClientBuilder; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosDatabase; +import com.microsoft.azure.cosmos.CosmosItemSettings; import com.microsoft.azure.cosmosdb.internal.directconnectivity.Protocol; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; import org.testng.SkipException; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; @@ -39,23 +40,24 @@ import static org.assertj.core.api.Assertions.assertThat; public class DocumentClientResourceLeakTest extends TestSuiteBase { - private static final int TIMEOUT = 240000; + private static final int TIMEOUT = 2400000; private static final int MAX_NUMBER = 1000; - private Builder clientBuilder; - private AsyncDocumentClient client; + private CosmosClientBuilder clientBuilder; + private CosmosClient client; - private Database createdDatabase; - private DocumentCollection createdCollection; + private CosmosDatabase createdDatabase; + private CosmosContainer createdCollection; @Factory(dataProvider = "simpleClientBuildersWithDirect") - public DocumentClientResourceLeakTest(Builder clientBuilder) { + public DocumentClientResourceLeakTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } + //TODO : FIX tests @Test(groups = {"emulator"}, timeOut = TIMEOUT) public void resourceLeak() throws Exception { //TODO FIXME DANOBLE this test doesn't pass on RNTBD - if (clientBuilder.configs.getProtocol() == Protocol.Tcp) { + if (clientBuilder.getConfigs().getProtocol() == Protocol.Tcp) { throw new SkipException("RNTBD"); } System.gc(); @@ -64,11 +66,11 @@ public void resourceLeak() throws Exception { for (int i = 0; i < MAX_NUMBER; i++) { - logger.info("client {}", i); client = clientBuilder.build(); + logger.info("client {}", i); try { logger.info("creating doc..."); - createDocument(client, createdDatabase.getId(), createdCollection.getId(), getDocumentDefinition()); + createDocument(client.getDatabase(createdDatabase.getId()).getContainer(createdCollection.getId()), getDocumentDefinition()); } finally { logger.info("closing client..."); client.close(); @@ -83,13 +85,14 @@ public void resourceLeak() throws Exception { @BeforeClass(groups = {"emulator"}, timeOut = SETUP_TIMEOUT) public void beforeClass() { - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_MULTI_PARTITION_COLLECTION; + client = clientBuilder.build(); + createdDatabase = getSharedCosmosDatabase(client); + createdCollection = getSharedMultiPartitionCosmosContainer(client); } - private Document getDocumentDefinition() { + private CosmosItemSettings getDocumentDefinition() { String uuid = UUID.randomUUID().toString(); - Document doc = new Document(String.format("{ " + CosmosItemSettings doc = new CosmosItemSettings(String.format("{ " + "\"id\": \"%s\", " + "\"mypk\": \"%s\", " + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/DocumentCrudTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/DocumentCrudTest.java index 6c995e8682e53..7ac50af7f425b 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/DocumentCrudTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/DocumentCrudTest.java @@ -1,435 +1,395 @@ -/* - * The MIT License (MIT) - * Copyright (c) 2018 Microsoft Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.microsoft.azure.cosmosdb.rx; - -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.Document; -import com.microsoft.azure.cosmosdb.DocumentClientException; -import com.microsoft.azure.cosmosdb.DocumentCollection; -import com.microsoft.azure.cosmosdb.PartitionKey; -import com.microsoft.azure.cosmosdb.RequestOptions; -import com.microsoft.azure.cosmosdb.ResourceResponse; -import com.microsoft.azure.cosmosdb.Undefined; -import com.microsoft.azure.cosmosdb.internal.directconnectivity.Protocol; -import org.apache.commons.lang3.StringUtils; -import org.testng.SkipException; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Factory; -import org.testng.annotations.Test; -import rx.Observable; - -import java.time.OffsetDateTime; -import java.util.UUID; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -import static org.apache.commons.io.FileUtils.ONE_MB; -import static org.assertj.core.api.Assertions.assertThat; - -public class DocumentCrudTest extends TestSuiteBase { - - private Database createdDatabase; - private DocumentCollection createdCollection; - - private AsyncDocumentClient client; - - @Factory(dataProvider = "clientBuildersWithDirect") - public DocumentCrudTest(AsyncDocumentClient.Builder clientBuilder) { - this.clientBuilder = clientBuilder; - } - - @DataProvider(name = "documentCrudArgProvider") - public Object[][] documentCrudArgProvider() { - return new Object[][] { - // collection name, is name base - {UUID.randomUUID().toString(), false } , - {UUID.randomUUID().toString(), true } , - - // with special characters in the name. - {"+ -_,:.|~" + UUID.randomUUID().toString() + " +-_,:.|~", true } , - }; - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") - public void createDocument(String documentId, boolean isNameBased) { - Document docDefinition = getDocumentDefinition(documentId); - - Observable> createObservable = client - .createDocument(getCollectionLink(isNameBased), docDefinition, null, false); - - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() - .withId(docDefinition.getId()) - .build(); - - validateSuccess(createObservable, validator); - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") - public void createLargeDocument(String documentId, boolean isNameBased) { - Document docDefinition = getDocumentDefinition(documentId); - - //Keep size as ~ 1.5MB to account for size of other props - int size = (int) (ONE_MB * 1.5); - docDefinition.set("largeString", StringUtils.repeat("x", size)); - - Observable> createObservable = client - .createDocument(getCollectionLink(isNameBased), docDefinition, null, false); - - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() - .withId(docDefinition.getId()) - .build(); - - validateSuccess(createObservable, validator); - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") - public void createDocumentWithVeryLargePartitionKey(String documentId, boolean isNameBased) { - Document docDefinition = getDocumentDefinition(documentId); - StringBuilder sb = new StringBuilder(); - for(int i = 0; i < 100; i++) { - sb.append(i).append("x"); - } - docDefinition.set("mypk", sb.toString()); - - Observable> createObservable = client - .createDocument(getCollectionLink(isNameBased), docDefinition, null, false); - - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() - .withId(docDefinition.getId()) - .withProperty("mypk", sb.toString()) - .build(); - validateSuccess(createObservable, validator); - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") - public void readDocumentWithVeryLargePartitionKey(String documentId, boolean isNameBased) { - Document docDefinition = getDocumentDefinition(documentId); - StringBuilder sb = new StringBuilder(); - for(int i = 0; i < 100; i++) { - sb.append(i).append("x"); - } - docDefinition.set("mypk", sb.toString()); - - Document createdDocument = TestSuiteBase.createDocument(client, createdDatabase.getId(), createdCollection.getId(), docDefinition); - - waitIfNeededForReplicasToCatchUp(clientBuilder); - - RequestOptions options = new RequestOptions(); - options.setPartitionKey(new PartitionKey(sb.toString())); - Observable> readObservable = client.readDocument(getDocumentLink(createdDocument, isNameBased), options); - - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() - .withId(docDefinition.getId()) - .withProperty("mypk", sb.toString()) - .build(); - validateSuccess(readObservable, validator); - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") - public void createDocument_AlreadyExists(String documentId, boolean isNameBased) { - Document docDefinition = getDocumentDefinition(documentId); - - client.createDocument(getCollectionLink(isNameBased), docDefinition, null, false).toBlocking().single().getResource(); - - Observable> createObservable = client - .createDocument(getCollectionLink(isNameBased), docDefinition, null, false); - - FailureValidator validator = new FailureValidator.Builder().resourceAlreadyExists().build(); - validateFailure(createObservable, validator); - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") - public void createDocumentTimeout(String documentId, boolean isNameBased) { - Document docDefinition = getDocumentDefinition(documentId); - - Observable> createObservable = client - .createDocument(getCollectionLink(isNameBased), docDefinition, null, false) - .timeout(1, TimeUnit.MILLISECONDS); - - FailureValidator validator = new FailureValidator.Builder().instanceOf(TimeoutException.class).build(); - - validateFailure(createObservable, validator); - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") - public void readDocument(String documentId, boolean isNameBased) { - Document docDefinition = getDocumentDefinition(documentId); - - Document document = client - .createDocument(getCollectionLink(isNameBased), docDefinition, null, false).toBlocking().single().getResource(); - - waitIfNeededForReplicasToCatchUp(clientBuilder); - - RequestOptions options = new RequestOptions(); - options.setPartitionKey(new PartitionKey(document.get("mypk"))); - Observable> readObservable = client.readDocument(getDocumentLink(document, isNameBased), options); - - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() - .withId(document.getId()) - .build(); - validateSuccess(readObservable, validator); - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") - public void timestamp(String documentId, boolean isNameBased) throws Exception { - OffsetDateTime before = OffsetDateTime.now(); - Document docDefinition = getDocumentDefinition(documentId); - Thread.sleep(1000); - Document document = client - .createDocument(getCollectionLink(isNameBased), docDefinition, null, false).toBlocking().single().getResource(); - - waitIfNeededForReplicasToCatchUp(clientBuilder); - - RequestOptions options = new RequestOptions(); - options.setPartitionKey(new PartitionKey(document.get("mypk"))); - Observable> readObservable = client.readDocument(getDocumentLink(document, isNameBased), options); - Document readDocument = readObservable.toBlocking().single().getResource(); - Thread.sleep(1000); - OffsetDateTime after = OffsetDateTime.now(); - - assertThat(readDocument.getTimestamp()).isAfterOrEqualTo(before); - assertThat(readDocument.getTimestamp()).isBeforeOrEqualTo(after); - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") - public void readDocument_DoesntExist(String documentId, boolean isNameBased) { - Document docDefinition = getDocumentDefinition(documentId); - - Document document = client - .createDocument(getCollectionLink(isNameBased), docDefinition, null, false).toBlocking().single().getResource(); - - RequestOptions options = new RequestOptions(); - options.setPartitionKey(new PartitionKey(document.get("mypk"))); - client.deleteDocument(getDocumentLink(document, isNameBased), options).toBlocking().first(); - - waitIfNeededForReplicasToCatchUp(clientBuilder); - - options.setPartitionKey(new PartitionKey("looloo")); - Observable> readObservable = client.readDocument(getDocumentLink(document, isNameBased), options); - - FailureValidator validator = new FailureValidator.Builder().instanceOf(DocumentClientException.class) - .statusCode(404).build(); - validateFailure(readObservable, validator); - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") - public void deleteDocument(String documentId, boolean isNameBased) { - Document docDefinition = getDocumentDefinition(documentId); - - Document document = client - .createDocument(getCollectionLink(isNameBased), docDefinition, null, false).toBlocking().single().getResource(); - - RequestOptions options = new RequestOptions(); - options.setPartitionKey(new PartitionKey(document.get("mypk"))); - Observable> deleteObservable = client.deleteDocument(getDocumentLink(document, isNameBased), options); - - - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() - .nullResource().build(); - validateSuccess(deleteObservable, validator); - - // attempt to read document which was deleted - waitIfNeededForReplicasToCatchUp(clientBuilder); - - Observable> readObservable = client.readDocument(getDocumentLink(document, isNameBased), options); - FailureValidator notFoundValidator = new FailureValidator.Builder().resourceNotFound().build(); - validateFailure(readObservable, notFoundValidator); - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") - public void deleteDocument_undefinedPK(String documentId, boolean isNameBased) { - Document docDefinition = new Document(); - docDefinition.setId(documentId); - - Document document = client - .createDocument(getCollectionLink(isNameBased), docDefinition, null, false).toBlocking().single().getResource(); - - RequestOptions options = new RequestOptions(); - options.setPartitionKey(new PartitionKey(Undefined.Value())); - Observable> deleteObservable = client.deleteDocument(getDocumentLink(document, isNameBased), options); - - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() - .nullResource().build(); - validateSuccess(deleteObservable, validator); - - // attempt to read document which was deleted - waitIfNeededForReplicasToCatchUp(clientBuilder); - - Observable> readObservable = client.readDocument(getDocumentLink(document, isNameBased), options); - FailureValidator notFoundValidator = new FailureValidator.Builder().resourceNotFound().build(); - validateFailure(readObservable, notFoundValidator); - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") - public void deleteDocument_DoesntExist(String documentId, boolean isNameBased) { - Document docDefinition = getDocumentDefinition(documentId); - - Document document = client - .createDocument(getCollectionLink(isNameBased), docDefinition, null, false).toBlocking().single().getResource(); - - RequestOptions options = new RequestOptions(); - options.setPartitionKey(new PartitionKey(document.get("mypk"))); - client.deleteDocument(getDocumentLink(document, isNameBased), options).toBlocking().single(); - - // delete again - Observable> deleteObservable = client.deleteDocument(getDocumentLink(document, isNameBased), options); - - FailureValidator validator = new FailureValidator.Builder().resourceNotFound().build(); - validateFailure(deleteObservable, validator); - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") - public void replaceDocument(String documentId, boolean isNameBased) { - // create a document - Document docDefinition = getDocumentDefinition(documentId); - - Document document = client - .createDocument(getCollectionLink(isNameBased), docDefinition, null, false).toBlocking().single().getResource(); - - String newPropValue = UUID.randomUUID().toString(); - document.set("newProp", newPropValue); - - // replace document - Observable> readObservable = client.replaceDocument(document, null); - - // validate - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() - .withProperty("newProp", newPropValue).build(); - validateSuccess(readObservable, validator); - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") - public void replaceDocument_UsingDocumentLink(String documentId, boolean isNameBased) { - // create a document - Document docDefinition = getDocumentDefinition(documentId); - - Document document = client - .createDocument(getCollectionLink(isNameBased), docDefinition, null, false).toBlocking().single().getResource(); - - String newPropValue = UUID.randomUUID().toString(); - document.set("newProp", newPropValue); - - // replace document - Observable> readObservable = client.replaceDocument(getDocumentLink(document, isNameBased), document, null); - - // validate - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() - .withProperty("newProp", newPropValue).build(); - validateSuccess(readObservable, validator); - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") - public void upsertDocument_CreateDocument(String documentId, boolean isNameBased) { - // create a document - Document docDefinition = getDocumentDefinition(documentId); - - - // replace document - Observable> upsertObservable = client.upsertDocument(getCollectionLink(isNameBased), - docDefinition, null, false); - - // validate - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() - .withId(docDefinition.getId()).build(); - try { - validateSuccess(upsertObservable, validator); - } catch (Throwable error) { - if (this.clientBuilder.configs.getProtocol() == Protocol.Tcp) { - String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.desiredConsistencyLevel); - logger.info(message, error); - throw new SkipException(message, error); - } - throw error; - } - } - - @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") - public void upsertDocument_ReplaceDocument(String documentId, boolean isNameBased) { - // create a document - Document docDefinition = getDocumentDefinition(documentId); - - Document document = client - .createDocument(getCollectionLink(isNameBased), docDefinition, null, false).toBlocking().single().getResource(); - - String newPropValue = UUID.randomUUID().toString(); - document.set("newProp", newPropValue); - - // replace document - Observable> readObservable = client.upsertDocument - (getCollectionLink(isNameBased), document, null, true); - - // validate - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() - .withProperty("newProp", newPropValue).build(); - try { - validateSuccess(readObservable, validator); - } catch (Throwable error) { - if (this.clientBuilder.configs.getProtocol() == Protocol.Tcp) { - String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.desiredConsistencyLevel); - logger.info(message, error); - throw new SkipException(message, error); - } - throw error; - } - } - - @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) - public void beforeClass() { - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_MULTI_PARTITION_COLLECTION; - } - - @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) - public void afterClass() { - safeClose(client); - } - - @BeforeMethod(groups = { "simple" }, timeOut = SETUP_TIMEOUT) - public void beforeMethod() { - safeClose(client); - client = clientBuilder.build(); - } - - private String getCollectionLink(boolean isNameBased) { - return isNameBased ? "dbs/" + createdDatabase.getId() + "/colls/" + createdCollection.getId() : createdCollection.getSelfLink(); - } - - private String getDocumentLink(Document doc, boolean isNameBased) { - return isNameBased ? "dbs/" + createdDatabase.getId() + "/colls/" + createdCollection.getId() + "/docs/" + doc.getId() : - "dbs/" + createdDatabase.getResourceId() + "/colls/" + createdCollection.getResourceId() + "/docs/" + doc.getResourceId(); - } - - private Document getDocumentDefinition(String documentId) { - String uuid = UUID.randomUUID().toString(); - Document doc = new Document(String.format("{ " - + "\"id\": \"%s\", " - + "\"mypk\": \"%s\", " - + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" - + "}" - , documentId, uuid)); - return doc; - } -} +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.microsoft.azure.cosmosdb.rx; + +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosClientBuilder; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosItem; +import com.microsoft.azure.cosmos.CosmosItemRequestOptions; +import com.microsoft.azure.cosmos.CosmosItemResponse; +import com.microsoft.azure.cosmos.CosmosItemSettings; +import com.microsoft.azure.cosmos.CosmosResponseValidator; +import com.microsoft.azure.cosmosdb.Document; +import com.microsoft.azure.cosmosdb.DocumentClientException; +import com.microsoft.azure.cosmosdb.PartitionKey; +import com.microsoft.azure.cosmosdb.internal.directconnectivity.Protocol; + +import reactor.core.publisher.Mono; + +import org.apache.commons.lang3.StringUtils; +import org.testng.SkipException; +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.DataProvider; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; + +import java.time.Duration; +import java.time.OffsetDateTime; +import java.util.UUID; +import java.util.concurrent.TimeoutException; + +import static org.apache.commons.io.FileUtils.ONE_MB; +import static org.assertj.core.api.Assertions.assertThat; + +public class DocumentCrudTest extends TestSuiteBase { + + private CosmosContainer createdCollection; + + private CosmosClient client; + + @Factory(dataProvider = "clientBuildersWithDirect") + public DocumentCrudTest(CosmosClientBuilder clientBuilder) { + this.clientBuilder = clientBuilder; + } + + @DataProvider(name = "documentCrudArgProvider") + public Object[][] documentCrudArgProvider() { + return new Object[][] { + // collection name, is name base + {UUID.randomUUID().toString()} , + + // with special characters in the name. + {"+ -_,:.|~" + UUID.randomUUID().toString() + " +-_,:.|~"} , + }; + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void createDocument(String documentId) throws InterruptedException { + CosmosItemSettings docDefinition = getDocumentDefinition(documentId); + + Mono createObservable = createdCollection.createItem(docDefinition, new CosmosItemRequestOptions()); + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(docDefinition.getId()) + .build(); + + validateSuccess(createObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void createLargeDocument(String documentId) throws InterruptedException { + CosmosItemSettings docDefinition = getDocumentDefinition(documentId); + + //Keep size as ~ 1.5MB to account for size of other props + int size = (int) (ONE_MB * 1.5); + docDefinition.set("largeString", StringUtils.repeat("x", size)); + + Mono createObservable = createdCollection.createItem(docDefinition, new CosmosItemRequestOptions()); + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(docDefinition.getId()) + .build(); + + validateSuccess(createObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void createDocumentWithVeryLargePartitionKey(String documentId) throws InterruptedException { + CosmosItemSettings docDefinition = getDocumentDefinition(documentId); + StringBuilder sb = new StringBuilder(); + for(int i = 0; i < 100; i++) { + sb.append(i).append("x"); + } + docDefinition.set("mypk", sb.toString()); + + Mono createObservable = createdCollection.createItem(docDefinition, new CosmosItemRequestOptions()); + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(docDefinition.getId()) + .withProperty("mypk", sb.toString()) + .build(); + validateSuccess(createObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void readDocumentWithVeryLargePartitionKey(String documentId) throws InterruptedException { + CosmosItemSettings docDefinition = getDocumentDefinition(documentId); + StringBuilder sb = new StringBuilder(); + for(int i = 0; i < 100; i++) { + sb.append(i).append("x"); + } + docDefinition.set("mypk", sb.toString()); + + CosmosItem createdDocument = TestSuiteBase.createDocument(createdCollection, docDefinition); + + waitIfNeededForReplicasToCatchUp(clientBuilder); + + CosmosItemRequestOptions options = new CosmosItemRequestOptions(); + options.setPartitionKey(new PartitionKey(sb.toString())); + Mono readObservable = createdDocument.read(options); + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(docDefinition.getId()) + .withProperty("mypk", sb.toString()) + .build(); + validateSuccess(readObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void createDocument_AlreadyExists(String documentId) throws InterruptedException { + CosmosItemSettings docDefinition = getDocumentDefinition(documentId); + + createdCollection.createItem(docDefinition, new CosmosItemRequestOptions()).block(); + + Mono createObservable = createdCollection.createItem(docDefinition, new CosmosItemRequestOptions()); + + FailureValidator validator = new FailureValidator.Builder().resourceAlreadyExists().build(); + validateFailure(createObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void createDocumentTimeout(String documentId) throws InterruptedException { + CosmosItemSettings docDefinition = getDocumentDefinition(documentId); + + Mono createObservable = createdCollection.createItem(docDefinition, new CosmosItemRequestOptions()) + .timeout(Duration.ofMillis(1)); + + FailureValidator validator = new FailureValidator.Builder().instanceOf(TimeoutException.class).build(); + + validateFailure(createObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void readDocument(String documentId) throws InterruptedException { + CosmosItemSettings docDefinition = getDocumentDefinition(documentId); + + CosmosItem document = createdCollection.createItem(docDefinition, new CosmosItemRequestOptions()).block().getCosmosItem(); + waitIfNeededForReplicasToCatchUp(clientBuilder); + + CosmosItemRequestOptions options = new CosmosItemRequestOptions(); + options.setPartitionKey(new PartitionKey(docDefinition.get("mypk"))); + Mono readObservable = document.read(options); + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(document.getId()) + .build(); + validateSuccess(readObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void timestamp(String documentId, boolean isNameBased) throws Exception { + OffsetDateTime before = OffsetDateTime.now(); + CosmosItemSettings docDefinition = getDocumentDefinition(documentId); + Thread.sleep(1000); + CosmosItem document = createdCollection.createItem(docDefinition, new CosmosItemRequestOptions()).block().getCosmosItem(); + + waitIfNeededForReplicasToCatchUp(clientBuilder); + + CosmosItemRequestOptions options = new CosmosItemRequestOptions(); + options.setPartitionKey(new PartitionKey(docDefinition.get("mypk"))); + CosmosItemSettings readDocument = document.read(options).block().getCosmosItemSettings(); + Thread.sleep(1000); + OffsetDateTime after = OffsetDateTime.now(); + + assertThat(readDocument.getTimestamp()).isAfterOrEqualTo(before); + assertThat(readDocument.getTimestamp()).isBeforeOrEqualTo(after); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void readDocument_DoesntExist(String documentId) throws InterruptedException { + CosmosItemSettings docDefinition = getDocumentDefinition(documentId); + + CosmosItem document = createdCollection.createItem(docDefinition, new CosmosItemRequestOptions()).block().getCosmosItem(); + + CosmosItemRequestOptions options = new CosmosItemRequestOptions(); + options.setPartitionKey(new PartitionKey(docDefinition.get("mypk"))); + document.delete(options).block(); + + waitIfNeededForReplicasToCatchUp(clientBuilder); + + options.setPartitionKey(new PartitionKey("looloo")); + Mono readObservable = document.read(options); + + FailureValidator validator = new FailureValidator.Builder().instanceOf(DocumentClientException.class) + .statusCode(404).build(); + validateFailure(readObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void deleteDocument(String documentId) throws InterruptedException { + CosmosItemSettings docDefinition = getDocumentDefinition(documentId); + + CosmosItem document = createdCollection.createItem(docDefinition, new CosmosItemRequestOptions()).block().getCosmosItem(); + + CosmosItemRequestOptions options = new CosmosItemRequestOptions(); + options.setPartitionKey(new PartitionKey(docDefinition.get("mypk"))); + Mono deleteObservable = document.delete(options); + + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .nullResource().build(); + validateSuccess(deleteObservable, validator); + + // attempt to read document which was deleted + waitIfNeededForReplicasToCatchUp(clientBuilder); + + Mono readObservable = document.read(options); + FailureValidator notFoundValidator = new FailureValidator.Builder().resourceNotFound().build(); + validateFailure(readObservable, notFoundValidator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void deleteDocument_undefinedPK(String documentId) throws InterruptedException { + Document docDefinition = new Document(); + docDefinition.setId(documentId); + + CosmosItem document = createdCollection.createItem(docDefinition, new CosmosItemRequestOptions()).block().getCosmosItem(); + + CosmosItemRequestOptions options = new CosmosItemRequestOptions(); + options.setPartitionKey(PartitionKey.None); + Mono deleteObservable = document.delete(options); + + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .nullResource().build(); + validateSuccess(deleteObservable, validator); + + // attempt to read document which was deleted + waitIfNeededForReplicasToCatchUp(clientBuilder); + + Mono readObservable = document.read(options); + FailureValidator notFoundValidator = new FailureValidator.Builder().resourceNotFound().build(); + validateFailure(readObservable, notFoundValidator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void deleteDocument_DoesntExist(String documentId) throws InterruptedException { + CosmosItemSettings docDefinition = getDocumentDefinition(documentId); + + CosmosItem document = createdCollection.createItem(docDefinition, new CosmosItemRequestOptions()).block().getCosmosItem(); + + CosmosItemRequestOptions options = new CosmosItemRequestOptions(); + options.setPartitionKey(new PartitionKey(docDefinition.get("mypk"))); + document.delete(options).block(); + + // delete again + Mono deleteObservable = document.delete(options); + + FailureValidator validator = new FailureValidator.Builder().resourceNotFound().build(); + validateFailure(deleteObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void replaceDocument(String documentId) throws InterruptedException { + // create a document + CosmosItemSettings docDefinition = getDocumentDefinition(documentId); + + CosmosItem document = createdCollection.createItem(docDefinition, new CosmosItemRequestOptions()).block().getCosmosItem(); + + String newPropValue = UUID.randomUUID().toString(); + docDefinition.set("newProp", newPropValue); + + CosmosItemRequestOptions options = new CosmosItemRequestOptions(); + options.setPartitionKey(new PartitionKey(docDefinition.get("mypk"))); + // replace document + Mono replaceObservable = document.replace(docDefinition, options); + + // validate + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withProperty("newProp", newPropValue).build(); + validateSuccess(replaceObservable, validator); + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "documentCrudArgProvider") + public void upsertDocument_CreateDocument(String documentId) throws Throwable { + // create a document + CosmosItemSettings docDefinition = getDocumentDefinition(documentId); + + + // replace document + Mono upsertObservable = createdCollection.upsertItem(docDefinition, new CosmosItemRequestOptions()); + + // validate + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withId(docDefinition.getId()).build(); + try { + validateSuccess(upsertObservable, validator); + } catch (Throwable error) { + if (this.clientBuilder.getConfigs().getProtocol() == Protocol.Tcp) { + String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.getDesiredConsistencyLevel()); + logger.info(message, error); + throw new SkipException(message, error); + } + throw error; + } + } + + @Test(groups = { "simple" }, timeOut = TIMEOUT * 100, dataProvider = "documentCrudArgProvider") + public void upsertDocument_ReplaceDocument(String documentId) throws Throwable { + // create a document + CosmosItemSettings docDefinition = getDocumentDefinition(documentId); + + docDefinition = createdCollection.createItem(docDefinition, new CosmosItemRequestOptions()).block().getCosmosItemSettings(); + + String newPropValue = UUID.randomUUID().toString(); + docDefinition.set("newProp", newPropValue); + + // replace document + Mono readObservable = createdCollection.upsertItem(docDefinition, new CosmosItemRequestOptions()); + System.out.println(docDefinition); + + // validate + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() + .withProperty("newProp", newPropValue).build(); + try { + validateSuccess(readObservable, validator); + } catch (Throwable error) { + if (this.clientBuilder.getConfigs().getProtocol() == Protocol.Tcp) { + String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.getDesiredConsistencyLevel()); + logger.info(message, error); + throw new SkipException(message, error); + } + throw error; + } + } + + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + client = clientBuilder.build(); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + } + + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeClose(client); + } + + @BeforeMethod(groups = { "simple" }, timeOut = SETUP_TIMEOUT) + public void beforeMethod() { + safeClose(client); + client = clientBuilder.build(); + } + + private CosmosItemSettings getDocumentDefinition(String documentId) { + String uuid = UUID.randomUUID().toString(); + CosmosItemSettings doc = new CosmosItemSettings(String.format("{ " + + "\"id\": \"%s\", " + + "\"mypk\": \"%s\", " + + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" + + "}" + , documentId, uuid)); + return doc; + } +} diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/LogLevelTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/LogLevelTest.java index c2ace6ab65969..8decf192dce3b 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/LogLevelTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/LogLevelTest.java @@ -35,19 +35,18 @@ import org.apache.log4j.WriterAppender; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; -import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.Document; -import com.microsoft.azure.cosmosdb.DocumentCollection; -import com.microsoft.azure.cosmosdb.ResourceResponse; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosItemRequestOptions; +import com.microsoft.azure.cosmos.CosmosItemResponse; +import com.microsoft.azure.cosmos.CosmosItemSettings; +import com.microsoft.azure.cosmos.CosmosResponseValidator; -import rx.Observable; +import reactor.core.publisher.Mono; import static org.assertj.core.api.Assertions.assertThat; @@ -59,8 +58,8 @@ public class LogLevelTest extends TestSuiteBase { public final static String LOG_PATTERN_3 = "USER_EVENT: SslHandshakeCompletionEvent(SUCCESS)"; public final static String LOG_PATTERN_4 = "CONNECT: "; - private static Database createdDatabase; - private static DocumentCollection createdCollection; + private static CosmosContainer createdCollection; + private static CosmosClient client; public LogLevelTest() { this.clientBuilder = createGatewayRxDocumentClient(); @@ -68,8 +67,8 @@ public LogLevelTest() { @BeforeClass(groups = {"simple"}, timeOut = SETUP_TIMEOUT) public void beforeClass() { - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_MULTI_PARTITION_COLLECTION; + client = clientBuilder.build(); + createdCollection = getSharedMultiPartitionCosmosContainer(client); } /** @@ -84,12 +83,11 @@ public void createDocumentWithDebugLevel() throws Exception { WriterAppender appender = new WriterAppender(new PatternLayout(), consoleWriter); LogManager.getLogger(NETWORK_LOGGING_CATEGORY).addAppender(appender); - AsyncDocumentClient client = clientBuilder.build(); + CosmosClient client = clientBuilder.build(); try { - Document docDefinition = getDocumentDefinition(); - Observable> createObservable = client - .createDocument(getCollectionLink(), docDefinition, null, false); - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + CosmosItemSettings docDefinition = getDocumentDefinition(); + Mono createObservable = createdCollection.createItem(docDefinition, new CosmosItemRequestOptions()); + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .withId(docDefinition.getId()) .build(); validateSuccess(createObservable, validator); @@ -114,12 +112,11 @@ public void createDocumentWithWarningLevel() throws Exception { WriterAppender appender = new WriterAppender(new PatternLayout(), consoleWriter); Logger.getLogger(NETWORK_LOGGING_CATEGORY).addAppender(appender); - AsyncDocumentClient client = clientBuilder.build(); + CosmosClient client = clientBuilder.build(); try { - Document docDefinition = getDocumentDefinition(); - Observable> createObservable = client - .createDocument(getCollectionLink(), docDefinition, null, false); - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + CosmosItemSettings docDefinition = getDocumentDefinition(); + Mono createObservable = createdCollection.createItem(docDefinition, new CosmosItemRequestOptions()); + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .withId(docDefinition.getId()) .build(); validateSuccess(createObservable, validator); @@ -143,12 +140,11 @@ public void createDocumentWithTraceLevel() throws Exception { WriterAppender appender = new WriterAppender(new PatternLayout(), consoleWriter); Logger.getLogger(NETWORK_LOGGING_CATEGORY).addAppender(appender); - AsyncDocumentClient client = clientBuilder.build(); + CosmosClient client = clientBuilder.build(); try { - Document docDefinition = getDocumentDefinition(); - Observable> createObservable = client - .createDocument(getCollectionLink(), docDefinition, null, false); - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + CosmosItemSettings docDefinition = getDocumentDefinition(); + Mono createObservable = createdCollection.createItem(docDefinition, new CosmosItemRequestOptions()); + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .withId(docDefinition.getId()) .build(); validateSuccess(createObservable, validator); @@ -171,12 +167,11 @@ public void createDocumentWithTraceLevelAtRoot() throws Exception { WriterAppender appender = new WriterAppender(new PatternLayout(), consoleWriter); Logger.getLogger(NETWORK_LOGGING_CATEGORY).addAppender(appender); - AsyncDocumentClient client = clientBuilder.build(); + CosmosClient client = clientBuilder.build(); try { - Document docDefinition = getDocumentDefinition(); - Observable> createObservable = client - .createDocument(getCollectionLink(), docDefinition, null, false); - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + CosmosItemSettings docDefinition = getDocumentDefinition(); + Mono createObservable = createdCollection.createItem(docDefinition, new CosmosItemRequestOptions()); + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .withId(docDefinition.getId()) .build(); validateSuccess(createObservable, validator); @@ -198,12 +193,11 @@ public void createDocumentWithDebugLevelAtRoot() throws Exception { WriterAppender appender = new WriterAppender(new PatternLayout(), consoleWriter); Logger.getLogger(NETWORK_LOGGING_CATEGORY).addAppender(appender); - AsyncDocumentClient client = clientBuilder.build(); + CosmosClient client = clientBuilder.build(); try { - Document docDefinition = getDocumentDefinition(); - Observable> createObservable = client - .createDocument(getCollectionLink(), docDefinition, null, false); - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + CosmosItemSettings docDefinition = getDocumentDefinition(); + Mono createObservable = createdCollection.createItem(docDefinition, new CosmosItemRequestOptions()); + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .withId(docDefinition.getId()) .build(); validateSuccess(createObservable, validator); @@ -227,12 +221,11 @@ public void createDocumentWithErrorClient() throws Exception { WriterAppender appender = new WriterAppender(new PatternLayout(), consoleWriter); Logger.getLogger(NETWORK_LOGGING_CATEGORY).addAppender(appender); - AsyncDocumentClient client = clientBuilder.build(); + CosmosClient client = clientBuilder.build(); try { - Document docDefinition = getDocumentDefinition(); - Observable> createObservable = client - .createDocument(getCollectionLink(), docDefinition, null, false); - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + CosmosItemSettings docDefinition = getDocumentDefinition(); + Mono createObservable = createdCollection.createItem(docDefinition, new CosmosItemRequestOptions()); + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .withId(docDefinition.getId()) .build(); validateSuccess(createObservable, validator); @@ -256,12 +249,11 @@ public void createDocumentWithInfoLevel() throws Exception { WriterAppender appender = new WriterAppender(new PatternLayout(), consoleWriter); Logger.getLogger(NETWORK_LOGGING_CATEGORY).addAppender(appender); - AsyncDocumentClient client = clientBuilder.build(); + CosmosClient client = clientBuilder.build(); try { - Document docDefinition = getDocumentDefinition(); - Observable> createObservable = client - .createDocument(getCollectionLink(), docDefinition, null, false); - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + CosmosItemSettings docDefinition = getDocumentDefinition(); + Mono createObservable = createdCollection.createItem(docDefinition, new CosmosItemRequestOptions()); + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .withId(docDefinition.getId()) .build(); validateSuccess(createObservable, validator); @@ -272,9 +264,9 @@ public void createDocumentWithInfoLevel() throws Exception { } } - private Document getDocumentDefinition() { + private CosmosItemSettings getDocumentDefinition() { String uuid = UUID.randomUUID().toString(); - Document doc = new Document(String.format("{ " + CosmosItemSettings doc = new CosmosItemSettings(String.format("{ " + "\"id\": \"%s\", " + "\"mypk\": \"%s\", " + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" @@ -301,8 +293,4 @@ public void afterClass() { LogManager.resetConfiguration(); PropertyConfigurator.configure(this.getClass().getClassLoader().getResource("log4j.properties")); } - - private String getCollectionLink() { - return createdCollection.getSelfLink(); - } } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/MultiMasterConflictResolutionTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/MultiMasterConflictResolutionTest.java index 05ce9cee9b9fb..a9f73ec834136 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/MultiMasterConflictResolutionTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/MultiMasterConflictResolutionTest.java @@ -1,214 +1,215 @@ -/* - * The MIT License (MIT) - * Copyright (c) 2018 Microsoft Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.microsoft.azure.cosmosdb.rx; - -import com.microsoft.azure.cosmosdb.BridgeUtils; -import com.microsoft.azure.cosmosdb.ConflictResolutionMode; -import com.microsoft.azure.cosmosdb.ConflictResolutionPolicy; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.DatabaseForTest; -import com.microsoft.azure.cosmosdb.DocumentClientException; -import com.microsoft.azure.cosmosdb.DocumentCollection; -import com.microsoft.azure.cosmosdb.Resource; -import com.microsoft.azure.cosmosdb.ResourceResponse; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Factory; -import org.testng.annotations.Test; -import rx.Observable; - -import javax.net.ssl.SSLException; -import java.util.UUID; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; - -// assumes multi master is enabled in endpoint -public class MultiMasterConflictResolutionTest extends TestSuiteBase { - private static final int TIMEOUT = 40000; - - private final String databaseId = DatabaseForTest.generateId(); - - private AsyncDocumentClient client; - private Database database; - - @Factory(dataProvider = "clientBuilders") - public MultiMasterConflictResolutionTest(AsyncDocumentClient.Builder clientBuilder) { - this.clientBuilder = clientBuilder; - } - - @Test(groups = "multi-master", timeOut = TIMEOUT) - public void conflictResolutionPolicyCRUD() { - - // default last writer wins, path _ts - DocumentCollection collection = new DocumentCollection(); - collection.setId(UUID.randomUUID().toString()); - collection = getResource(client.createCollection(getDatabaseLink(database), collection, null)); - - assertThat(collection.getConflictResolutionPolicy().getConflictResolutionMode()).isEqualTo(ConflictResolutionMode.LastWriterWins); - - // LWW without path specified, should default to _ts - collection.setConflictResolutionPolicy(ConflictResolutionPolicy.createLastWriterWinsPolicy()); - collection = getResource(client.replaceCollection(collection, null)); - - - assertThat(collection.getConflictResolutionPolicy().getConflictResolutionMode()).isEqualTo(ConflictResolutionMode.LastWriterWins); - assertThat(collection.getConflictResolutionPolicy().getConflictResolutionPath()).isEqualTo("/_ts"); - - // Tests the following scenarios - // 1. LWW with valid path - // 2. LWW with null path, should default to _ts - // 3. LWW with empty path, should default to _ts - testConflictResolutionPolicyRequiringPath(ConflictResolutionMode.LastWriterWins, - new String[] { "/a", null, "" }, new String[] { "/a", "/_ts", "/_ts" }); - - // LWW invalid path - collection.setConflictResolutionPolicy(ConflictResolutionPolicy.createLastWriterWinsPolicy("/a/b")); - - try { - collection = getResource(client.replaceCollection(collection, null)); - fail("Expected exception on invalid path."); - } catch (Exception e) { - - // when (e.StatusCode == HttpStatusCode.BadRequest) - DocumentClientException dce = com.microsoft.azure.cosmosdb.rx.internal.Utils.as(e.getCause(), DocumentClientException.class); - if (dce != null && dce.getStatusCode() == 400) { - assertThat(dce.getMessage()).contains("Invalid path '\\/a\\/b' for last writer wins conflict resolution"); - } else { - throw e; - } - } - - // LWW invalid path - - collection.setConflictResolutionPolicy(ConflictResolutionPolicy.createLastWriterWinsPolicy("someText")); - - try { - collection = getResource(client.replaceCollection(collection, null)); - fail("Expected exception on invalid path."); - } catch (Exception e) { - // when (e.StatusCode == HttpStatusCode.BadRequest) - DocumentClientException dce = com.microsoft.azure.cosmosdb.rx.internal.Utils.as(e.getCause(), DocumentClientException.class); - if (dce != null && dce.getStatusCode() == 400) { - assertThat(dce.getMessage()).contains("Invalid path 'someText' for last writer wins conflict resolution"); - } else { - throw e; - } - } - - // Tests the following scenarios - // 1. Custom with valid sprocLink - // 2. Custom with null sprocLink, should default to empty string - // 3. Custom with empty sprocLink, should default to empty string - testConflictResolutionPolicyRequiringPath(ConflictResolutionMode.Custom, - new String[] { "randomSprocName", null, "" }, new String[] { "randomSprocName", "", "" }); - } - - private void testConflictResolutionPolicyRequiringPath(ConflictResolutionMode conflictResolutionMode, - String[] paths, String[] expectedPaths) { - for (int i = 0; i < paths.length; i++) { - DocumentCollection collection = new DocumentCollection(); - collection.setId(UUID.randomUUID().toString()); - - if (conflictResolutionMode == ConflictResolutionMode.LastWriterWins) { - collection.setConflictResolutionPolicy(ConflictResolutionPolicy.createLastWriterWinsPolicy(paths[i])); - } else { - collection.setConflictResolutionPolicy(ConflictResolutionPolicy.createCustomPolicy(paths[i])); - } - collection = getResource(client.createCollection("dbs/" + database.getId(), collection, null)); - assertThat(collection.getConflictResolutionPolicy().getConflictResolutionMode()).isEqualTo(conflictResolutionMode); - - if (conflictResolutionMode == ConflictResolutionMode.LastWriterWins) { - assertThat(collection.getConflictResolutionPolicy().getConflictResolutionPath()).isEqualTo(expectedPaths[i]); - } else { - assertThat(collection.getConflictResolutionPolicy().getConflictResolutionProcedure()).isEqualTo(expectedPaths[i]); - } - } - } - - @Test(groups = "multi-master", timeOut = TIMEOUT) - public void invalidConflictResolutionPolicy_LastWriterWinsWithStoredProc() throws Exception { - DocumentCollection collection = new DocumentCollection(); - collection.setId(UUID.randomUUID().toString()); - - // LWW without path specified, should default to _ts - ConflictResolutionPolicy policy = BridgeUtils.createConflictResolutionPolicy(); - BridgeUtils.setMode(policy, ConflictResolutionMode.LastWriterWins); - BridgeUtils.setStoredProc(policy,"randomSprocName"); - collection.setConflictResolutionPolicy(policy); - - Observable> createObservable = client.createCollection( - getDatabaseLink(database), - collection, - null); - - FailureValidator validator = new FailureValidator.Builder() - .instanceOf(DocumentClientException.class) - .statusCode(400) - .errorMessageContains("LastWriterWins conflict resolution mode should not have conflict resolution procedure set.") - .build(); - validateFailure(createObservable, validator); - } - - @Test(groups = "multi-master", timeOut = TIMEOUT) - public void invalidConflictResolutionPolicy_CustomWithPath() throws Exception { - DocumentCollection collection = new DocumentCollection(); - collection.setId(UUID.randomUUID().toString()); - - // LWW without path specified, should default to _ts - ConflictResolutionPolicy policy = BridgeUtils.createConflictResolutionPolicy(); - BridgeUtils.setMode(policy, ConflictResolutionMode.Custom); - BridgeUtils.setPath(policy,"/mypath"); - collection.setConflictResolutionPolicy(policy); - - Observable> createObservable = client.createCollection( - getDatabaseLink(database), - collection, - null); - - FailureValidator validator = new FailureValidator.Builder() - .instanceOf(DocumentClientException.class) - .statusCode(400) - .errorMessageContains("Custom conflict resolution mode should not have conflict resolution path set.") - .build(); - validateFailure(createObservable, validator); - } - - @BeforeClass(groups = {"multi-master"}, timeOut = SETUP_TIMEOUT) - public void beforeClass() { - // set up the client - - client = clientBuilder.build(); - database = createDatabase(client, databaseId); - } - - private T getResource(Observable> obs) { - return obs.toBlocking().single().getResource(); - } - - @AfterClass(groups = {"multi-master"}, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) - public void afterClass() { - safeDeleteDatabase(client, database); - safeClose(client); - } -} +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.microsoft.azure.cosmosdb.rx; + +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosClientBuilder; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosContainerRequestOptions; +import com.microsoft.azure.cosmos.CosmosContainerResponse; +import com.microsoft.azure.cosmos.CosmosContainerSettings; +import com.microsoft.azure.cosmos.CosmosDatabase; +import com.microsoft.azure.cosmos.CosmosDatabaseForTest; +import com.microsoft.azure.cosmosdb.BridgeUtils; +import com.microsoft.azure.cosmosdb.ConflictResolutionMode; +import com.microsoft.azure.cosmosdb.ConflictResolutionPolicy; +import com.microsoft.azure.cosmosdb.DocumentClientException; +import com.microsoft.azure.cosmosdb.PartitionKeyDefinition; + +import reactor.core.publisher.Mono; + +import org.testng.annotations.AfterClass; +import org.testng.annotations.BeforeClass; +import org.testng.annotations.Factory; +import org.testng.annotations.Test; + +import java.util.ArrayList; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.fail; + +// assumes multi master is enabled in endpoint +public class MultiMasterConflictResolutionTest extends TestSuiteBase { + private static final int TIMEOUT = 40000; + + private final String databaseId = CosmosDatabaseForTest.generateId(); + + private PartitionKeyDefinition partitionKeyDef; + private CosmosClient client; + private CosmosDatabase database; + + @Factory(dataProvider = "clientBuilders") + public MultiMasterConflictResolutionTest(CosmosClientBuilder clientBuilder) { + this.clientBuilder = clientBuilder; + } + + @Test(groups = "multi-master", timeOut = 10 * TIMEOUT) + public void conflictResolutionPolicyCRUD() { + + // default last writer wins, path _ts + CosmosContainerSettings collectionSettings = new CosmosContainerSettings(UUID.randomUUID().toString(), partitionKeyDef); + CosmosContainer collection = database.createContainer(collectionSettings, new CosmosContainerRequestOptions()).block().getContainer(); + collectionSettings = collection.read().block().getCosmosContainerSettings(); + + assertThat(collectionSettings.getConflictResolutionPolicy().getConflictResolutionMode()).isEqualTo(ConflictResolutionMode.LastWriterWins); + + // LWW without path specified, should default to _ts + collectionSettings.setConflictResolutionPolicy(ConflictResolutionPolicy.createLastWriterWinsPolicy()); + collectionSettings = collection.replace(collectionSettings, null).block().getCosmosContainerSettings(); + + assertThat(collectionSettings.getConflictResolutionPolicy().getConflictResolutionMode()).isEqualTo(ConflictResolutionMode.LastWriterWins); + assertThat(collectionSettings.getConflictResolutionPolicy().getConflictResolutionPath()).isEqualTo("/_ts"); + + // Tests the following scenarios + // 1. LWW with valid path + // 2. LWW with null path, should default to _ts + // 3. LWW with empty path, should default to _ts + testConflictResolutionPolicyRequiringPath(ConflictResolutionMode.LastWriterWins, + new String[] { "/a", null, "" }, new String[] { "/a", "/_ts", "/_ts" }); + + // LWW invalid path + collectionSettings.setConflictResolutionPolicy(ConflictResolutionPolicy.createLastWriterWinsPolicy("/a/b")); + + try { + collectionSettings = collection.replace(collectionSettings, null).block().getCosmosContainerSettings(); + fail("Expected exception on invalid path."); + } catch (Exception e) { + + // when (e.StatusCode == HttpStatusCode.BadRequest) + DocumentClientException dce = com.microsoft.azure.cosmosdb.rx.internal.Utils.as(e.getCause(), DocumentClientException.class); + if (dce != null && dce.getStatusCode() == 400) { + assertThat(dce.getMessage()).contains("Invalid path '\\/a\\/b' for last writer wins conflict resolution"); + } else { + throw e; + } + } + + // LWW invalid path + + collectionSettings.setConflictResolutionPolicy(ConflictResolutionPolicy.createLastWriterWinsPolicy("someText")); + + try { + collectionSettings = collection.replace(collectionSettings, null).block().getCosmosContainerSettings(); + fail("Expected exception on invalid path."); + } catch (Exception e) { + // when (e.StatusCode == HttpStatusCode.BadRequest) + DocumentClientException dce = com.microsoft.azure.cosmosdb.rx.internal.Utils.as(e.getCause(), DocumentClientException.class); + if (dce != null && dce.getStatusCode() == 400) { + assertThat(dce.getMessage()).contains("Invalid path 'someText' for last writer wins conflict resolution"); + } else { + throw e; + } + } + + // Tests the following scenarios + // 1. Custom with valid sprocLink + // 2. Custom with null sprocLink, should default to empty string + // 3. Custom with empty sprocLink, should default to empty string + testConflictResolutionPolicyRequiringPath(ConflictResolutionMode.Custom, + new String[] { "randomSprocName", null, "" }, new String[] { "randomSprocName", "", "" }); + } + + private void testConflictResolutionPolicyRequiringPath(ConflictResolutionMode conflictResolutionMode, + String[] paths, String[] expectedPaths) { + for (int i = 0; i < paths.length; i++) { + CosmosContainerSettings collectionSettings = new CosmosContainerSettings(UUID.randomUUID().toString(), partitionKeyDef); + + if (conflictResolutionMode == ConflictResolutionMode.LastWriterWins) { + collectionSettings.setConflictResolutionPolicy(ConflictResolutionPolicy.createLastWriterWinsPolicy(paths[i])); + } else { + collectionSettings.setConflictResolutionPolicy(ConflictResolutionPolicy.createCustomPolicy(paths[i])); + } + collectionSettings = database.createContainer(collectionSettings, new CosmosContainerRequestOptions()).block().getCosmosContainerSettings(); + assertThat(collectionSettings.getConflictResolutionPolicy().getConflictResolutionMode()).isEqualTo(conflictResolutionMode); + + if (conflictResolutionMode == ConflictResolutionMode.LastWriterWins) { + assertThat(collectionSettings.getConflictResolutionPolicy().getConflictResolutionPath()).isEqualTo(expectedPaths[i]); + } else { + assertThat(collectionSettings.getConflictResolutionPolicy().getConflictResolutionProcedure()).isEqualTo(expectedPaths[i]); + } + } + } + + @Test(groups = "multi-master", timeOut = TIMEOUT) + public void invalidConflictResolutionPolicy_LastWriterWinsWithStoredProc() throws Exception { + CosmosContainerSettings collection = new CosmosContainerSettings(UUID.randomUUID().toString(), partitionKeyDef); + + // LWW without path specified, should default to _ts + ConflictResolutionPolicy policy = BridgeUtils.createConflictResolutionPolicy(); + BridgeUtils.setMode(policy, ConflictResolutionMode.LastWriterWins); + BridgeUtils.setStoredProc(policy,"randomSprocName"); + collection.setConflictResolutionPolicy(policy); + + Mono createObservable = database.createContainer( + collection, + new CosmosContainerRequestOptions()); + + FailureValidator validator = new FailureValidator.Builder() + .instanceOf(DocumentClientException.class) + .statusCode(400) + .errorMessageContains("LastWriterWins conflict resolution mode should not have conflict resolution procedure set.") + .build(); + validateFailure(createObservable, validator); + } + + @Test(groups = "multi-master", timeOut = TIMEOUT) + public void invalidConflictResolutionPolicy_CustomWithPath() throws Exception { + CosmosContainerSettings collection = new CosmosContainerSettings(UUID.randomUUID().toString(), partitionKeyDef); + + // LWW without path specified, should default to _ts + ConflictResolutionPolicy policy = BridgeUtils.createConflictResolutionPolicy(); + BridgeUtils.setMode(policy, ConflictResolutionMode.Custom); + BridgeUtils.setPath(policy,"/mypath"); + collection.setConflictResolutionPolicy(policy); + + Mono createObservable = database.createContainer( + collection, + new CosmosContainerRequestOptions()); + + FailureValidator validator = new FailureValidator.Builder() + .instanceOf(DocumentClientException.class) + .statusCode(400) + .errorMessageContains("Custom conflict resolution mode should not have conflict resolution path set.") + .build(); + validateFailure(createObservable, validator); + } + + @BeforeClass(groups = {"multi-master"}, timeOut = SETUP_TIMEOUT) + public void beforeClass() { + // set up the client + + client = clientBuilder.build(); + database = createDatabase(client, databaseId); + partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.setPaths(paths); + } + + @AfterClass(groups = {"multi-master"}, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) + public void afterClass() { + safeDeleteDatabase(database); + safeClose(client); + } +} diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/MultiOrderByQueryTests.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/MultiOrderByQueryTests.java index 9734948d38e35..38d551d1cac8e 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/MultiOrderByQueryTests.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/MultiOrderByQueryTests.java @@ -32,22 +32,26 @@ import java.util.Random; import java.util.UUID; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import org.apache.commons.collections4.ComparatorUtils; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; - -import rx.Observable; - import com.fasterxml.jackson.databind.ObjectMapper; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosContainerSettings; +import com.microsoft.azure.cosmos.CosmosItemRequestOptions; +import com.microsoft.azure.cosmos.CosmosItemSettings; import com.microsoft.azure.cosmosdb.CompositePath; import com.microsoft.azure.cosmosdb.DocumentClientException; -import com.microsoft.azure.cosmosdb.DocumentCollection; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; + +import reactor.core.publisher.Flux; + import com.microsoft.azure.cosmosdb.CompositePathSortOrder; import com.microsoft.azure.cosmosdb.Document; @@ -66,12 +70,12 @@ public class MultiOrderByQueryTests extends TestSuiteBase { private static final String MEDIUM_STRING_FIELD = "mediumStringField"; private static final String LONG_STRING_FIELD = "longStringField"; private static final String PARTITION_KEY = "pk"; - private ArrayList documents = new ArrayList(); - private DocumentCollection documentCollection; - private Builder clientBuilder; - private AsyncDocumentClient client; + private ArrayList documents = new ArrayList(); + private CosmosContainer documentCollection; + private CosmosClientBuilder clientBuilder; + private CosmosClient client; - class CustomComparator implements Comparator { + class CustomComparator implements Comparator { String path; CompositePathSortOrder order; boolean isNumericPath = false; @@ -94,7 +98,7 @@ public CustomComparator(String path, CompositePathSortOrder order) { } @Override - public int compare(Document doc1, Document doc2) { + public int compare(CosmosItemSettings doc1, CosmosItemSettings doc2) { boolean isAsc = order == CompositePathSortOrder.Ascending; if (isNumericPath) { if (doc1.getInt(path) < doc2.getInt(path)) @@ -105,7 +109,7 @@ else if (doc1.getInt(path) > doc2.getInt(path)) return 0; } else if (isStringPath) { if (!isAsc) { - Document temp = doc1; + CosmosItemSettings temp = doc1; doc1 = doc2; doc2 = temp; } @@ -127,7 +131,7 @@ else if (doc1.getBoolean(path) == true && doc2.getBoolean(path) == false) } @Factory(dataProvider = "clientBuilders") - public MultiOrderByQueryTests(Builder clientBuilder) { + public MultiOrderByQueryTests(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @@ -139,8 +143,8 @@ public void afterClass() { @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) public void beforeClass() throws Exception { client = clientBuilder.build(); - documentCollection = SHARED_MULTI_PARTITION_COLLECTION_WITH_COMPOSITE_AND_SPATIAL_INDEXES; - truncateCollection(SHARED_MULTI_PARTITION_COLLECTION_WITH_COMPOSITE_AND_SPATIAL_INDEXES); + documentCollection = getSharedMultiPartitionCosmosContainerWithCompositeAndSpatialIndexes(client); + truncateCollection(documentCollection); int numberOfDocuments = 4; @@ -152,35 +156,35 @@ public void beforeClass() throws Exception { for (int j = 0; j < numberOfDuplicates; j++) { // Add the document itself for exact duplicates - Document initialDocument = new Document(multiOrderByDocumentString); + CosmosItemSettings initialDocument = new CosmosItemSettings(multiOrderByDocumentString); initialDocument.setId(UUID.randomUUID().toString()); this.documents.add(initialDocument); // Permute all the fields so that there are duplicates with tie breaks - Document numberClone = new Document(multiOrderByDocumentString); + CosmosItemSettings numberClone = new CosmosItemSettings(multiOrderByDocumentString); numberClone.set(NUMBER_FIELD, random.nextInt(5)); numberClone.setId(UUID.randomUUID().toString()); this.documents.add(numberClone); - Document stringClone = new Document(multiOrderByDocumentString); + CosmosItemSettings stringClone = new CosmosItemSettings(multiOrderByDocumentString); stringClone.set(STRING_FIELD, Integer.toString(random.nextInt(5))); stringClone.setId(UUID.randomUUID().toString()); this.documents.add(stringClone); - Document boolClone = new Document(multiOrderByDocumentString); + CosmosItemSettings boolClone = new CosmosItemSettings(multiOrderByDocumentString); boolClone.set(BOOL_FIELD, random.nextInt(2) % 2 == 0); boolClone.setId(UUID.randomUUID().toString()); this.documents.add(boolClone); // Also fuzz what partition it goes to - Document partitionClone = new Document(multiOrderByDocumentString); + CosmosItemSettings partitionClone = new CosmosItemSettings(multiOrderByDocumentString); partitionClone.set(PARTITION_KEY, random.nextInt(5)); partitionClone.setId(UUID.randomUUID().toString()); this.documents.add(partitionClone); } } - bulkInsertBlocking(client, documentCollection.getSelfLink(), documents); + bulkInsertBlocking(documentCollection, documents); waitIfNeededForReplicasToCatchUp(clientBuilder); } @@ -210,7 +214,8 @@ public void queryDocumentsWithMultiOrder() throws DocumentClientException, Inter feedOptions.setEnableCrossPartitionQuery(true); boolean[] booleanValues = new boolean[] {true, false}; - Iterator> compositeIndexesIterator = documentCollection.getIndexingPolicy().getCompositeIndexes().iterator(); + CosmosContainerSettings containerSettings = documentCollection.read().block().getCosmosContainerSettings(); + Iterator> compositeIndexesIterator = containerSettings.getIndexingPolicy().getCompositeIndexes().iterator(); while (compositeIndexesIterator.hasNext()) { ArrayList compositeIndex = compositeIndexesIterator.next(); // for every order @@ -260,13 +265,12 @@ public void queryDocumentsWithMultiOrder() throws DocumentClientException, Inter "FROM root " + whereString + " " + "ORDER BY " + orderByItemStringBuilder.toString(); - ArrayList expectedOrderedList = top(sort(filter(this.documents, hasFilter), compositeIndex, invert), hasTop, topCount) ; + ArrayList expectedOrderedList = top(sort(filter(this.documents, hasFilter), compositeIndex, invert), hasTop, topCount) ; - Observable> queryObservable = client - .queryDocuments(documentCollection.getSelfLink(), query, feedOptions); + Flux> queryObservable = documentCollection.queryItems(query, feedOptions); - FeedResponseListValidator validator = new FeedResponseListValidator - .Builder() + FeedResponseListValidator validator = new FeedResponseListValidator + .Builder() .withOrderedResults(expectedOrderedList, compositeIndex) .build(); @@ -280,10 +284,9 @@ public void queryDocumentsWithMultiOrder() throws DocumentClientException, Inter // This query would then be invalid. Document documentWithEmptyField = generateMultiOrderByDocument(); documentWithEmptyField.remove(NUMBER_FIELD); - client.createDocument(documentCollection.getSelfLink(), documentWithEmptyField, null, false).toBlocking().single(); + documentCollection.createItem(documentWithEmptyField, new CosmosItemRequestOptions()).block(); String query = "SELECT [root." + NUMBER_FIELD + ",root." + STRING_FIELD + "] FROM root ORDER BY root." + NUMBER_FIELD + " ASC ,root." + STRING_FIELD + " DESC"; - Observable> queryObservable = client - .queryDocuments(documentCollection.getSelfLink(), query, feedOptions); + Flux> queryObservable = documentCollection.queryItems(query, feedOptions); FailureValidator validator = new FailureValidator.Builder() .instanceOf(UnsupportedOperationException.class) @@ -292,23 +295,23 @@ public void queryDocumentsWithMultiOrder() throws DocumentClientException, Inter validateQueryFailure(queryObservable, validator); } - private ArrayList top(ArrayList documents, boolean hasTop, int topCount) { - ArrayList result = new ArrayList(); + private ArrayList top(ArrayList arrayList, boolean hasTop, int topCount) { + ArrayList result = new ArrayList(); int counter = 0; if (hasTop) { - while (counter < topCount && counter < documents.size()) { - result.add(documents.get(counter)); + while (counter < topCount && counter < arrayList.size()) { + result.add(arrayList.get(counter)); counter++; } } else { - result.addAll(documents); + result.addAll(arrayList); } return result; } - private ArrayList sort(ArrayList documents, ArrayList compositeIndex, + private ArrayList sort(ArrayList arrayList, ArrayList compositeIndex, boolean invert) { - Collection> comparators = new ArrayList>(); + Collection> comparators = new ArrayList>(); Iterator compositeIndexIterator = compositeIndex.iterator(); while (compositeIndexIterator.hasNext()) { CompositePath compositePath = compositeIndexIterator.next(); @@ -323,20 +326,20 @@ private ArrayList sort(ArrayList documents, ArrayList filter(ArrayList documents, boolean hasFilter) { - ArrayList result = new ArrayList(); + private ArrayList filter(ArrayList cosmosItemSettings, boolean hasFilter) { + ArrayList result = new ArrayList(); if (hasFilter) { - for (Document document : documents) { + for (CosmosItemSettings document : cosmosItemSettings) { if (document.getInt(NUMBER_FIELD) % 2 == 0) { result.add(document); } } } else { - result.addAll(documents); + result.addAll(cosmosItemSettings); } return result; } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/OfferQueryTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/OfferQueryTest.java index 5554c8c1ee7ad..aa9a329faaa37 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/OfferQueryTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/OfferQueryTest.java @@ -29,7 +29,6 @@ import java.util.UUID; import java.util.stream.Collectors; -import com.microsoft.azure.cosmosdb.DatabaseForTest; import org.assertj.core.util.Strings; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; @@ -37,14 +36,18 @@ import org.testng.annotations.Test; import com.microsoft.azure.cosmosdb.Database; +import com.microsoft.azure.cosmosdb.DatabaseForTest; import com.microsoft.azure.cosmosdb.DocumentCollection; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; import com.microsoft.azure.cosmosdb.Offer; +import com.microsoft.azure.cosmosdb.PartitionKeyDefinition; import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; +import com.microsoft.azure.cosmosdb.rx.internal.TestSuiteBase; import rx.Observable; +//TODO: change to use external TestSuiteBase public class OfferQueryTest extends TestSuiteBase { public final static int SETUP_TIMEOUT = 40000; @@ -147,6 +150,13 @@ public void beforeClass() throws Exception { for(int i = 0; i < 3; i++) { DocumentCollection collection = new DocumentCollection(); collection.setId(UUID.randomUUID().toString()); + + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.setPaths(paths); + collection.setPartitionKey(partitionKeyDef); + createdCollections.add(createCollection(client, databaseId, collection)); } } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/OfferReadReplaceTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/OfferReadReplaceTest.java index 6a5d9e9fdfd06..de3715f02152a 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/OfferReadReplaceTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/OfferReadReplaceTest.java @@ -24,21 +24,21 @@ import java.util.List; -import com.microsoft.azure.cosmosdb.DatabaseForTest; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; import com.microsoft.azure.cosmosdb.Database; +import com.microsoft.azure.cosmosdb.DatabaseForTest; import com.microsoft.azure.cosmosdb.DocumentCollection; import com.microsoft.azure.cosmosdb.Offer; import com.microsoft.azure.cosmosdb.ResourceResponse; +import com.microsoft.azure.cosmosdb.rx.internal.TestSuiteBase; import rx.Observable; -import javax.net.ssl.SSLException; - +//TODO: change to use external TestSuiteBase public class OfferReadReplaceTest extends TestSuiteBase { public final String databaseId = DatabaseForTest.generateId(); @@ -112,5 +112,4 @@ public void afterClass() { safeDeleteDatabase(client, createdDatabase); safeClose(client); } - } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/OrderbyDocumentQueryTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/OrderbyDocumentQueryTest.java index 21829fd366f87..d54f7ffba7d2a 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/OrderbyDocumentQueryTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/OrderbyDocumentQueryTest.java @@ -35,6 +35,7 @@ import java.util.function.Function; import java.util.stream.Collectors; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import com.microsoft.azure.cosmosdb.RetryAnalyzer; import org.apache.commons.lang3.StringUtils; @@ -46,42 +47,44 @@ import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.Document; +import com.microsoft.azure.cosmos.CosmosBridgeInternal; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosDatabase; +import com.microsoft.azure.cosmos.CosmosItemRequestOptions; +import com.microsoft.azure.cosmos.CosmosItemSettings; import com.microsoft.azure.cosmosdb.DocumentClientException; -import com.microsoft.azure.cosmosdb.DocumentCollection; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; import com.microsoft.azure.cosmosdb.PartitionKey; -import com.microsoft.azure.cosmosdb.ResourceResponse; import com.microsoft.azure.cosmosdb.internal.query.QueryItem; import com.microsoft.azure.cosmosdb.internal.routing.Range; import com.microsoft.azure.cosmosdb.rx.internal.Utils.ValueHolder; import com.microsoft.azure.cosmosdb.rx.internal.query.CompositeContinuationToken; import com.microsoft.azure.cosmosdb.rx.internal.query.OrderByContinuationToken; +import io.reactivex.subscribers.TestSubscriber; +import reactor.core.publisher.Flux; import rx.Observable; -import rx.observers.TestSubscriber; public class OrderbyDocumentQueryTest extends TestSuiteBase { private final double minQueryRequestChargePerPartition = 2.0; - private Database createdDatabase; - private DocumentCollection createdCollection; - private List createdDocuments = new ArrayList<>(); - - private AsyncDocumentClient client; + private CosmosClient client; + private CosmosContainer createdCollection; + private CosmosDatabase createdDatabase; + private List createdDocuments = new ArrayList<>(); private int numberOfPartitions; @Factory(dataProvider = "clientBuildersWithDirect") - public OrderbyDocumentQueryTest(AsyncDocumentClient.Builder clientBuilder) { + public OrderbyDocumentQueryTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "queryMetricsArgProvider") public void queryDocumentsValidateContent(boolean qmEnabled) throws Exception { - Document expectedDocument = createdDocuments.get(0); + CosmosItemSettings expectedDocument = createdDocuments.get(0); String query = String.format("SELECT * from root r where r.propStr = '%s'" + " ORDER BY r.propInt" @@ -91,22 +94,22 @@ public void queryDocumentsValidateContent(boolean qmEnabled) throws Exception { options.setEnableCrossPartitionQuery(true); options.setPopulateQueryMetrics(qmEnabled); - Observable> queryObservable = client.queryDocuments(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryItems(query, options); List expectedResourceIds = new ArrayList<>(); expectedResourceIds.add(expectedDocument.getResourceId()); - Map> resourceIDToValidator = new HashMap<>(); + Map> resourceIDToValidator = new HashMap<>(); resourceIDToValidator.put(expectedDocument.getResourceId(), - new ResourceValidator.Builder().areEqual(expectedDocument).build()); + new ResourceValidator.Builder().areEqual(expectedDocument).build()); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .numberOfPages(1) .containsExactly(expectedResourceIds) .validateAllResources(resourceIDToValidator) .totalRequestChargeIsAtLeast(numberOfPartitions * minQueryRequestChargePerPartition) - .allPagesSatisfy(new FeedResponseValidator.Builder().hasRequestChargeHeader().build()) + .allPagesSatisfy(new FeedResponseValidator.Builder().hasRequestChargeHeader().build()) .hasValidQueryMetrics(qmEnabled) .build(); @@ -116,9 +119,9 @@ public void queryDocumentsValidateContent(boolean qmEnabled) throws Exception { // TODO: DANOBLE: report this detailed information in all failures produced by TestSuiteBase classes // work item: https://msdata.visualstudio.com/CosmosDB/_workitems/edit/370015 String message = String.format("%s %s mode with %s consistency test failure", - this.clientBuilder.connectionPolicy.getConnectionMode(), - this.clientBuilder.configs.getProtocol(), - this.clientBuilder.desiredConsistencyLevel); + this.clientBuilder.getConnectionPolicy().getConnectionMode(), + this.clientBuilder.getConfigs().getProtocol(), + this.clientBuilder.getDesiredConsistencyLevel()); throw new AssertionError(message, error); } } @@ -128,14 +131,13 @@ public void queryDocuments_NoResults() throws Exception { String query = "SELECT * from root r where r.id = '2' ORDER BY r.propInt"; FeedOptions options = new FeedOptions(); options.setEnableCrossPartitionQuery(true); - Observable> queryObservable = client - .queryDocuments(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryItems(query, options); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .containsExactly(new ArrayList<>()) .numberOfPages(1) .totalRequestChargeIsAtLeast(numberOfPartitions * minQueryRequestChargePerPartition) - .allPagesSatisfy(new FeedResponseValidator.Builder() + .allPagesSatisfy(new FeedResponseValidator.Builder() .hasRequestChargeHeader().build()) .build(); @@ -154,8 +156,7 @@ public void queryOrderBy(String sortOrder) throws Exception { options.setEnableCrossPartitionQuery(true); int pageSize = 3; options.setMaxItemCount(pageSize); - Observable> queryObservable = client - .queryDocuments(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryItems(query, options); Comparator validatorComparator = Comparator.nullsFirst(Comparator.naturalOrder()); List expectedResourceIds = sortDocumentsAndCollectResourceIds("propInt", d -> d.getInt("propInt"), validatorComparator); @@ -165,10 +166,10 @@ public void queryOrderBy(String sortOrder) throws Exception { int expectedPageSize = expectedNumberOfPages(expectedResourceIds.size(), pageSize); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .containsExactly(expectedResourceIds) .numberOfPages(expectedPageSize) - .allPagesSatisfy(new FeedResponseValidator.Builder() + .allPagesSatisfy(new FeedResponseValidator.Builder() .hasRequestChargeHeader().build()) .totalRequestChargeIsAtLeast(numberOfPartitions * minQueryRequestChargePerPartition) .build(); @@ -183,17 +184,16 @@ public void queryOrderByInt() throws Exception { options.setEnableCrossPartitionQuery(true); int pageSize = 3; options.setMaxItemCount(pageSize); - Observable> queryObservable = client - .queryDocuments(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryItems(query, options); Comparator validatorComparator = Comparator.nullsFirst(Comparator.naturalOrder()); List expectedResourceIds = sortDocumentsAndCollectResourceIds("propInt", d -> d.getInt("propInt"), validatorComparator); int expectedPageSize = expectedNumberOfPages(expectedResourceIds.size(), pageSize); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .containsExactly(expectedResourceIds) .numberOfPages(expectedPageSize) - .allPagesSatisfy(new FeedResponseValidator.Builder() + .allPagesSatisfy(new FeedResponseValidator.Builder() .hasRequestChargeHeader().build()) .totalRequestChargeIsAtLeast(numberOfPartitions * minQueryRequestChargePerPartition) .build(); @@ -208,17 +208,16 @@ public void queryOrderByString() throws Exception { options.setEnableCrossPartitionQuery(true); int pageSize = 3; options.setMaxItemCount(pageSize); - Observable> queryObservable = client - .queryDocuments(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryItems(query, options); Comparator validatorComparator = Comparator.nullsFirst(Comparator.naturalOrder()); List expectedResourceIds = sortDocumentsAndCollectResourceIds("propStr", d -> d.getString("propStr"), validatorComparator); int expectedPageSize = expectedNumberOfPages(expectedResourceIds.size(), pageSize); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .containsExactly(expectedResourceIds) .numberOfPages(expectedPageSize) - .allPagesSatisfy(new FeedResponseValidator.Builder() + .allPagesSatisfy(new FeedResponseValidator.Builder() .hasRequestChargeHeader().build()) .totalRequestChargeIsAtLeast(numberOfPartitions * minQueryRequestChargePerPartition) .build(); @@ -239,8 +238,7 @@ public void queryOrderWithTop(int topValue) throws Exception { options.setEnableCrossPartitionQuery(true); int pageSize = 3; options.setMaxItemCount(pageSize); - Observable> queryObservable = client - .queryDocuments(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryItems(query, options); Comparator validatorComparator = Comparator.nullsFirst(Comparator.naturalOrder()); @@ -250,10 +248,10 @@ public void queryOrderWithTop(int topValue) throws Exception { int expectedPageSize = expectedNumberOfPages(expectedResourceIds.size(), pageSize); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .containsExactly(expectedResourceIds) .numberOfPages(expectedPageSize) - .allPagesSatisfy(new FeedResponseValidator.Builder() + .allPagesSatisfy(new FeedResponseValidator.Builder() .hasRequestChargeHeader().build()) .totalRequestChargeIsAtLeast(numberOfPartitions * (topValue > 0 ? minQueryRequestChargePerPartition : 1)) .build(); @@ -261,7 +259,7 @@ public void queryOrderWithTop(int topValue) throws Exception { validateQuerySuccess(queryObservable, validator); } - private List sortDocumentsAndCollectResourceIds(String propName, Function extractProp, Comparator comparer) { + private List sortDocumentsAndCollectResourceIds(String propName, Function extractProp, Comparator comparer) { return createdDocuments.stream() .filter(d -> d.getHashMap().containsKey(propName)) // removes undefined .sorted((d1, d2) -> comparer.compare(extractProp.apply(d1), extractProp.apply(d2))) @@ -272,8 +270,7 @@ private List sortDocumentsAndCollectResourceIds(String propName, Fun public void crossPartitionQueryNotEnabled() throws Exception { String query = "SELECT * FROM r ORDER BY r.propInt"; FeedOptions options = new FeedOptions(); - Observable> queryObservable = client - .queryDocuments(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryItems(query, options); FailureValidator validator = new FailureValidator.Builder() .instanceOf(DocumentClientException.class) @@ -288,43 +285,39 @@ public void queryScopedToSinglePartition_StartWithContinuationToken() throws Exc FeedOptions options = new FeedOptions(); options.setPartitionKey(new PartitionKey("duplicateParitionKeyValue")); options.setMaxItemCount(3); - Observable> queryObservable = client - .queryDocuments(getCollectionLink(), query, options); - + Flux> queryObservable = createdCollection.queryItems(query, options); - TestSubscriber> subscriber = new TestSubscriber<>(); - queryObservable.first().subscribe(subscriber); + TestSubscriber> subscriber = new TestSubscriber<>(); + queryObservable.take(1).subscribe(subscriber); subscriber.awaitTerminalEvent(); - subscriber.assertCompleted(); + subscriber.assertComplete(); subscriber.assertNoErrors(); - assertThat(subscriber.getValueCount()).isEqualTo(1); - FeedResponse page = subscriber.getOnNextEvents().get(0); + assertThat(subscriber.valueCount()).isEqualTo(1); + FeedResponse page = (FeedResponse) subscriber.getEvents().get(0).get(0); assertThat(page.getResults()).hasSize(3); assertThat(page.getResponseContinuation()).isNotEmpty(); options.setRequestContinuation(page.getResponseContinuation()); - queryObservable = client - .queryDocuments(getCollectionLink(), query, options); - + queryObservable = createdCollection.queryItems(query, options); - List expectedDocs = createdDocuments.stream() + List expectedDocs = createdDocuments.stream() .filter(d -> (StringUtils.equals("duplicateParitionKeyValue", d.getString("mypk")))) .filter(d -> (d.getInt("propScopedPartitionInt") > 2)).collect(Collectors.toList()); int expectedPageSize = (expectedDocs.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); assertThat(expectedDocs).hasSize(10 - 3); - FeedResponseListValidator validator = null; + FeedResponseListValidator validator = null; - validator = new FeedResponseListValidator.Builder() + validator = new FeedResponseListValidator.Builder() .containsExactly(expectedDocs.stream() .sorted((e1, e2) -> Integer.compare(e1.getInt("propScopedPartitionInt"), e2.getInt("propScopedPartitionInt"))) .map(d -> d.getResourceId()).collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .allPagesSatisfy(new FeedResponseValidator.Builder() + .allPagesSatisfy(new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); @@ -417,27 +410,22 @@ public void queryDocumentsWithInvalidOrderByContinuationTokensString(String sort this.assertInvalidContinuationToken(query, new int[] { 1, 5, 10, 100 }, expectedResourceIds); } - public Document createDocument(AsyncDocumentClient client, Map keyValueProps) + public CosmosItemSettings createDocument(CosmosContainer cosmosContainer, Map keyValueProps) throws DocumentClientException { - Document docDefinition = getDocumentDefinition(keyValueProps); - return client.createDocument(getCollectionLink(), docDefinition, null, false) - .toBlocking().single() - .getResource(); + CosmosItemSettings docDefinition = getDocumentDefinition(keyValueProps); + return cosmosContainer.createItem(docDefinition, new CosmosItemSettings()).block().getCosmosItemSettings(); } - public List bulkInsert(AsyncDocumentClient client, List> keyValuePropsList) { + public List bulkInsert(CosmosContainer cosmosContainer, List> keyValuePropsList) { - ArrayList>> result = new ArrayList>>(); + ArrayList result = new ArrayList(); for(Map keyValueProps: keyValuePropsList) { - Document docDefinition = getDocumentDefinition(keyValueProps); - Observable> obs = client.createDocument(getCollectionLink(), docDefinition, null, false); - result.add(obs); + CosmosItemSettings docDefinition = getDocumentDefinition(keyValueProps); + result.add(docDefinition); } - return Observable.merge(result, 100). - map(resp -> resp.getResource()) - .toList().toBlocking().single(); + return bulkInsertBlocking(cosmosContainer, result); } @BeforeMethod(groups = { "simple" }) @@ -449,9 +437,9 @@ public void beforeMethod() throws Exception { @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) public void beforeClass() throws Exception { client = clientBuilder.build(); - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_MULTI_PARTITION_COLLECTION; - truncateCollection(SHARED_MULTI_PARTITION_COLLECTION); + createdDatabase = getSharedCosmosDatabase(client); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); List> keyValuePropsList = new ArrayList<>(); Map props; @@ -467,17 +455,20 @@ public void beforeClass() throws Exception { props = new HashMap<>(); keyValuePropsList.add(props); - createdDocuments = bulkInsert(client, keyValuePropsList); + createdDocuments = bulkInsert(createdCollection, keyValuePropsList); for(int i = 0; i < 10; i++) { Map p = new HashMap<>(); p.put("propScopedPartitionInt", i); - Document doc = getDocumentDefinition("duplicateParitionKeyValue", UUID.randomUUID().toString(), p); - createdDocuments.add(client.createDocument(getCollectionLink(), doc, null, false).toBlocking().single().getResource()); + CosmosItemSettings doc = getDocumentDefinition("duplicateParitionKeyValue", UUID.randomUUID().toString(), p); + CosmosItemRequestOptions options = new CosmosItemRequestOptions(); + options.setPartitionKey(new PartitionKey(doc.get("mypk"))); + createdDocuments.add(createDocument(createdCollection, doc).read(options).block().getCosmosItemSettings()); } - numberOfPartitions = client - .readPartitionKeyRanges(getCollectionLink(), null) + + numberOfPartitions = CosmosBridgeInternal.getAsyncDocumentClient(client) + .readPartitionKeyRanges("dbs/" + createdDatabase.getId() + "/colls/" + createdCollection.getId(), null) .flatMap(p -> Observable.from(p.getResults())).toList().toBlocking().single().size(); waitIfNeededForReplicasToCatchUp(clientBuilder); @@ -503,12 +494,12 @@ private void assertInvalidContinuationToken(String query, int[] pageSize, List> queryObservable = client.queryDocuments(getCollectionLink(), query, + Flux> queryObservable = createdCollection.queryItems(query, options); - Observable> firstPageObservable = queryObservable.first(); - TestSubscriber> testSubscriber = new VerboseTestSubscriber<>(); - firstPageObservable.subscribe(testSubscriber); + //Observable> firstPageObservable = queryObservable.first(); + TestSubscriber> testSubscriber = new TestSubscriber<>(); + queryObservable.subscribe(testSubscriber); testSubscriber.awaitTerminalEvent(TIMEOUT, TimeUnit.MILLISECONDS); testSubscriber.assertError(DocumentClientException.class); } while (requestContinuation != null); @@ -516,9 +507,9 @@ private void assertInvalidContinuationToken(String query, int[] pageSize, List expectedIds) { for (int pageSize : pageSizes) { - List receivedDocuments = this.queryWithContinuationTokens(query, pageSize); + List receivedDocuments = this.queryWithContinuationTokens(query, pageSize); List actualIds = new ArrayList(); - for (Document document : receivedDocuments) { + for (CosmosItemSettings document : receivedDocuments) { actualIds.add(document.getResourceId()); } @@ -526,27 +517,27 @@ private void queryWithContinuationTokensAndPageSizes(String query, int[] pageSiz } } - private List queryWithContinuationTokens(String query, int pageSize) { + private List queryWithContinuationTokens(String query, int pageSize) { String requestContinuation = null; List continuationTokens = new ArrayList(); - List receivedDocuments = new ArrayList(); + List receivedDocuments = new ArrayList(); do { FeedOptions options = new FeedOptions(); options.setMaxItemCount(pageSize); options.setEnableCrossPartitionQuery(true); options.setMaxDegreeOfParallelism(2); options.setRequestContinuation(requestContinuation); - Observable> queryObservable = client.queryDocuments(getCollectionLink(), query, + Flux> queryObservable = createdCollection.queryItems(query, options); - Observable> firstPageObservable = queryObservable.first(); - TestSubscriber> testSubscriber = new VerboseTestSubscriber<>(); - firstPageObservable.subscribe(testSubscriber); + //Observable> firstPageObservable = queryObservable.first(); + TestSubscriber> testSubscriber = new TestSubscriber<>(); + queryObservable.subscribe(testSubscriber); testSubscriber.awaitTerminalEvent(TIMEOUT, TimeUnit.MILLISECONDS); testSubscriber.assertNoErrors(); - testSubscriber.assertCompleted(); + testSubscriber.assertComplete(); - FeedResponse firstPage = testSubscriber.getOnNextEvents().get(0); + FeedResponse firstPage = (FeedResponse) testSubscriber.getEvents().get(0).get(0); requestContinuation = firstPage.getResponseContinuation(); receivedDocuments.addAll(firstPage.getResults()); continuationTokens.add(requestContinuation); @@ -555,7 +546,7 @@ private List queryWithContinuationTokens(String query, int pageSize) { return receivedDocuments; } - private static Document getDocumentDefinition(String partitionKey, String id, Map keyValuePair) { + private static CosmosItemSettings getDocumentDefinition(String partitionKey, String id, Map keyValuePair) { StringBuilder sb = new StringBuilder(); sb.append("{\n"); @@ -575,18 +566,14 @@ private static Document getDocumentDefinition(String partitionKey, String id, Ma sb.append(String.format(" \"mypk\": \"%s\"\n", partitionKey)); sb.append("}"); - return new Document(sb.toString()); + return new CosmosItemSettings(sb.toString()); } - private static Document getDocumentDefinition(Map keyValuePair) { + private static CosmosItemSettings getDocumentDefinition(Map keyValuePair) { String uuid = UUID.randomUUID().toString(); return getDocumentDefinition(uuid, uuid, keyValuePair); } - public String getCollectionLink() { - return Utils.getCollectionNameLink(createdDatabase.getId(), createdCollection.getId()); - } - private static String toJson(Object object){ try { return com.microsoft.azure.cosmosdb.internal.Utils.getSimpleObjectMapper().writeValueAsString(object); diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ParallelDocumentQueryTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ParallelDocumentQueryTest.java index 14aacf69af53e..8f2a8b749c6b7 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ParallelDocumentQueryTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ParallelDocumentQueryTest.java @@ -22,6 +22,12 @@ */ package com.microsoft.azure.cosmosdb.rx; +import com.microsoft.azure.cosmos.CosmosBridgeInternal; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosClientBuilder; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosDatabase; +import com.microsoft.azure.cosmos.CosmosItemSettings; import com.microsoft.azure.cosmosdb.BridgeInternal; import static org.assertj.core.api.Assertions.assertThat; @@ -36,10 +42,7 @@ import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.Document; import com.microsoft.azure.cosmosdb.DocumentClientException; -import com.microsoft.azure.cosmosdb.DocumentCollection; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; import com.microsoft.azure.cosmosdb.QueryMetrics; @@ -48,28 +51,28 @@ import org.testng.SkipException; import org.testng.annotations.DataProvider; import com.microsoft.azure.cosmosdb.internal.routing.Range; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; import com.microsoft.azure.cosmosdb.rx.internal.Utils.ValueHolder; import com.microsoft.azure.cosmosdb.rx.internal.query.CompositeContinuationToken; +import io.reactivex.subscribers.TestSubscriber; +import reactor.core.publisher.Flux; import rx.Observable; -import rx.observers.TestSubscriber; import java.util.Map; public class ParallelDocumentQueryTest extends TestSuiteBase { - private Database createdDatabase; - private DocumentCollection createdCollection; - private List createdDocuments; + private CosmosDatabase createdDatabase; + private CosmosContainer createdCollection; + private List createdDocuments; - private AsyncDocumentClient client; + private CosmosClient client; public String getCollectionLink() { return Utils.getCollectionNameLink(createdDatabase.getId(), createdCollection.getId()); } @Factory(dataProvider = "clientBuildersWithDirect") - public ParallelDocumentQueryTest(AsyncDocumentClient.Builder clientBuilder) { + public ParallelDocumentQueryTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @@ -89,16 +92,15 @@ public void queryDocuments(boolean qmEnabled) { options.setEnableCrossPartitionQuery(true); options.setPopulateQueryMetrics(qmEnabled); options.setMaxDegreeOfParallelism(2); - Observable> queryObservable = client - .queryDocuments(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryItems(query, options); - List expectedDocs = createdDocuments.stream().filter(d -> 99 == d.getInt("prop") ).collect(Collectors.toList()); + List expectedDocs = createdDocuments.stream().filter(d -> 99 == d.getInt("prop") ).collect(Collectors.toList()); assertThat(expectedDocs).isNotEmpty(); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .totalSize(expectedDocs.size()) .exactlyContainsInAnyOrder(expectedDocs.stream().map(d -> d.getResourceId()).collect(Collectors.toList())) - .allPagesSatisfy(new FeedResponseValidator.Builder() + .allPagesSatisfy(new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .hasValidQueryMetrics(qmEnabled) .build(); @@ -106,8 +108,8 @@ public void queryDocuments(boolean qmEnabled) { try { validateQuerySuccess(queryObservable, validator, TIMEOUT); } catch (Throwable error) { - if (this.clientBuilder.configs.getProtocol() == Protocol.Tcp) { - String message = String.format(String.format("Direct TCP test failure: desiredConsistencyLevel=%s", this.clientBuilder.desiredConsistencyLevel)); + if (this.clientBuilder.getConfigs().getProtocol() == Protocol.Tcp) { + String message = String.format(String.format("Direct TCP test failure: desiredConsistencyLevel=%s", this.clientBuilder.getDesiredConsistencyLevel())); logger.info(message, error); throw new SkipException(message, error); } @@ -124,14 +126,12 @@ public void queryMetricEquality() throws Exception { options.setPopulateQueryMetrics(true); options.setMaxDegreeOfParallelism(0); - Observable> queryObservable = client - .queryDocuments(getCollectionLink(), query, options); - List> resultList1 = queryObservable.toList().toBlocking().single(); + Flux> queryObservable = createdCollection.queryItems(query, options); + List> resultList1 = queryObservable.collectList().block(); options.setMaxDegreeOfParallelism(4); - Observable> threadedQueryObs = client.queryDocuments(getCollectionLink(), query, - options); - List> resultList2 = threadedQueryObs.toList().toBlocking().single(); + Flux> threadedQueryObs = createdCollection.queryItems(query, options); + List> resultList2 = threadedQueryObs.collectList().block(); assertThat(resultList1.size()).isEqualTo(resultList2.size()); for(int i = 0; i < resultList1.size(); i++){ @@ -157,13 +157,12 @@ public void queryDocuments_NoResults() { String query = "SELECT * from root r where r.id = '2'"; FeedOptions options = new FeedOptions(); options.setEnableCrossPartitionQuery(true); - Observable> queryObservable = client - .queryDocuments(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryItems(query, options); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .containsExactly(new ArrayList<>()) .numberOfPagesIsGreaterThanOrEqualTo(1) - .allPagesSatisfy(new FeedResponseValidator.Builder() + .allPagesSatisfy(new FeedResponseValidator.Builder() .pageSizeIsLessThanOrEqualTo(0) .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); @@ -181,20 +180,19 @@ public void queryDocumentsWithPageSize() { options.setMaxItemCount(pageSize); options.setMaxDegreeOfParallelism(-1); options.setEnableCrossPartitionQuery(true); - Observable> queryObservable = client - .queryDocuments(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryItems(query, options); - List expectedDocs = createdDocuments; + List expectedDocs = createdDocuments; assertThat(expectedDocs).isNotEmpty(); - FeedResponseListValidator validator = new FeedResponseListValidator - .Builder() + FeedResponseListValidator validator = new FeedResponseListValidator + .Builder() .exactlyContainsInAnyOrder(expectedDocs .stream() .map(d -> d.getResourceId()) .collect(Collectors.toList())) .numberOfPagesIsGreaterThanOrEqualTo((expectedDocs.size() + 1) / 3) - .allPagesSatisfy(new FeedResponseValidator.Builder() + .allPagesSatisfy(new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0) .pageSizeIsLessThanOrEqualTo(pageSize) .build()) @@ -202,8 +200,8 @@ public void queryDocumentsWithPageSize() { try { validateQuerySuccess(queryObservable, validator, 2 * subscriberValidationTimeout); } catch (Throwable error) { - if (this.clientBuilder.configs.getProtocol() == Protocol.Tcp) { - String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.desiredConsistencyLevel); + if (this.clientBuilder.getConfigs().getProtocol() == Protocol.Tcp) { + String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.getDesiredConsistencyLevel()); logger.info(message, error); throw new SkipException(message, error); } @@ -216,8 +214,7 @@ public void invalidQuerySyntax() { String query = "I am an invalid query"; FeedOptions options = new FeedOptions(); options.setEnableCrossPartitionQuery(true); - Observable> queryObservable = client - .queryDocuments(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryItems(query, options); FailureValidator validator = new FailureValidator.Builder() .instanceOf(DocumentClientException.class) @@ -231,8 +228,7 @@ public void invalidQuerySyntax() { public void crossPartitionQueryNotEnabled() { String query = "SELECT * from root"; FeedOptions options = new FeedOptions(); - Observable> queryObservable = client - .queryDocuments(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryItems(query, options); FailureValidator validator = new FailureValidator.Builder() .instanceOf(DocumentClientException.class) @@ -249,22 +245,21 @@ public void crossPartitionQueryNotEnabled() { public void partitionKeyRangeId() { int sum = 0; try { - for (String partitionKeyRangeId : client.readPartitionKeyRanges(getCollectionLink(), null) + for (String partitionKeyRangeId : CosmosBridgeInternal.getAsyncDocumentClient(client).readPartitionKeyRanges(getCollectionLink(), null) .flatMap(p -> Observable.from(p.getResults())) .map(pkr -> pkr.getId()).toList().toBlocking().single()) { String query = "SELECT * from root"; FeedOptions options = new FeedOptions(); options.setPartitionKeyRangeIdInternal(partitionKeyRangeId); - int queryResultCount = client - .queryDocuments(getCollectionLink(), query, options) - .flatMap(p -> Observable.from(p.getResults())) - .toList().toBlocking().single().size(); + int queryResultCount = createdCollection.queryItems(query, options) + .flatMap(p -> Flux.fromIterable(p.getResults())) + .collectList().block().size(); sum += queryResultCount; } } catch (Throwable error) { - if (this.clientBuilder.configs.getProtocol() == Protocol.Tcp) { - String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.desiredConsistencyLevel); + if (this.clientBuilder.getConfigs().getProtocol() == Protocol.Tcp) { + String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.getDesiredConsistencyLevel()); logger.info(message, error); throw new SkipException(message, error); } @@ -315,7 +310,7 @@ public void queryDocumentsWithCompositeContinuationTokens() throws Exception { String query = "SELECT * FROM c"; // Get Expected - List expectedDocs = createdDocuments + List expectedDocs = createdDocuments .stream() .collect(Collectors.toList()); assertThat(expectedDocs).isNotEmpty(); @@ -335,10 +330,10 @@ public void queryDocumentsWithCompositeContinuationTokens() throws Exception { @BeforeClass(groups = { "simple", "non-emulator" }, timeOut = 2 * SETUP_TIMEOUT) public void beforeClass() { client = clientBuilder.build(); - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_MULTI_PARTITION_COLLECTION; - truncateCollection(SHARED_MULTI_PARTITION_COLLECTION); - List docDefList = new ArrayList<>(); + createdDatabase = getSharedCosmosDatabase(client); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); + List docDefList = new ArrayList<>(); for(int i = 0; i < 13; i++) { docDefList.add(getDocumentDefinition(i)); } @@ -347,7 +342,7 @@ public void beforeClass() { docDefList.add(getDocumentDefinition(99)); } - createdDocuments = bulkInsertBlocking(client, getCollectionLink(), docDefList); + createdDocuments = bulkInsertBlocking(createdCollection, docDefList); waitIfNeededForReplicasToCatchUp(clientBuilder); } @@ -357,9 +352,9 @@ public void afterClass() { safeClose(client); } - private static Document getDocumentDefinition(int cnt) { + private static CosmosItemSettings getDocumentDefinition(int cnt) { String uuid = UUID.randomUUID().toString(); - Document doc = new Document(String.format("{ " + CosmosItemSettings doc = new CosmosItemSettings(String.format("{ " + "\"id\": \"%s\", " + "\"prop\" : %d, " + "\"mypk\": \"%s\", " @@ -375,31 +370,30 @@ public void invalidQuerySytax() throws Exception { String query = "I am an invalid query"; FeedOptions options = new FeedOptions(); options.setEnableCrossPartitionQuery(true); - Observable> queryObservable = client.queryDocuments(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryItems(query, options); FailureValidator validator = new FailureValidator.Builder().instanceOf(DocumentClientException.class) .statusCode(400).notNullActivityId().build(); validateQueryFailure(queryObservable, validator); } - public Document createDocument(AsyncDocumentClient client, int cnt) throws DocumentClientException { + public CosmosItemSettings createDocument(CosmosContainer cosmosContainer, int cnt) throws DocumentClientException { - Document docDefinition = getDocumentDefinition(cnt); + CosmosItemSettings docDefinition = getDocumentDefinition(cnt); - return client.createDocument(getCollectionLink(), docDefinition, null, false).toBlocking().single() - .getResource(); + return cosmosContainer.createItem(docDefinition, new CosmosItemSettings()).block().getCosmosItemSettings(); } - private void queryWithContinuationTokensAndPageSizes(String query, int[] pageSizes, List expectedDocs) { + private void queryWithContinuationTokensAndPageSizes(String query, int[] pageSizes, List expectedDocs) { for (int pageSize : pageSizes) { - List receivedDocuments = this.queryWithContinuationTokens(query, pageSize); + List receivedDocuments = this.queryWithContinuationTokens(query, pageSize); List actualIds = new ArrayList(); - for (Document document : receivedDocuments) { + for (CosmosItemSettings document : receivedDocuments) { actualIds.add(document.getResourceId()); } List expectedIds = new ArrayList(); - for (Document document : expectedDocs) { + for (CosmosItemSettings document : expectedDocs) { expectedIds.add(document.getResourceId()); } @@ -407,27 +401,25 @@ private void queryWithContinuationTokensAndPageSizes(String query, int[] pageSiz } } - private List queryWithContinuationTokens(String query, int pageSize) { + private List queryWithContinuationTokens(String query, int pageSize) { String requestContinuation = null; List continuationTokens = new ArrayList(); - List receivedDocuments = new ArrayList(); + List receivedDocuments = new ArrayList(); do { FeedOptions options = new FeedOptions(); options.setMaxItemCount(pageSize); options.setEnableCrossPartitionQuery(true); options.setMaxDegreeOfParallelism(2); options.setRequestContinuation(requestContinuation); - Observable> queryObservable = client.queryDocuments(getCollectionLink(), query, - options); + Flux> queryObservable = createdCollection.queryItems(query, options); - Observable> firstPageObservable = queryObservable.first(); - TestSubscriber> testSubscriber = new TestSubscriber<>(); - firstPageObservable.subscribe(testSubscriber); + TestSubscriber> testSubscriber = new TestSubscriber<>(); + queryObservable.subscribe(testSubscriber); testSubscriber.awaitTerminalEvent(TIMEOUT, TimeUnit.MILLISECONDS); testSubscriber.assertNoErrors(); - testSubscriber.assertCompleted(); + testSubscriber.assertComplete(); - FeedResponse firstPage = testSubscriber.getOnNextEvents().get(0); + FeedResponse firstPage = (FeedResponse) testSubscriber.getEvents().get(0).get(0); requestContinuation = firstPage.getResponseContinuation(); receivedDocuments.addAll(firstPage.getResults()); continuationTokens.add(requestContinuation); diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/PermissionCrudTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/PermissionCrudTest.java index 45c5132499c7b..bbc3ad2c18494 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/PermissionCrudTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/PermissionCrudTest.java @@ -36,11 +36,13 @@ import com.microsoft.azure.cosmosdb.ResourceResponse; import com.microsoft.azure.cosmosdb.User; import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; +import com.microsoft.azure.cosmosdb.rx.internal.TestSuiteBase; import rx.Observable; import javax.net.ssl.SSLException; +//TODO: change to use external TestSuiteBase public class PermissionCrudTest extends TestSuiteBase { private Database createdDatabase; diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/PermissionQueryTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/PermissionQueryTest.java index f53e7da02edec..ea87e18cdce0a 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/PermissionQueryTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/PermissionQueryTest.java @@ -29,13 +29,13 @@ import java.util.UUID; import java.util.stream.Collectors; -import com.microsoft.azure.cosmosdb.DatabaseForTest; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; import com.microsoft.azure.cosmosdb.Database; +import com.microsoft.azure.cosmosdb.DatabaseForTest; import com.microsoft.azure.cosmosdb.DocumentClientException; import com.microsoft.azure.cosmosdb.DocumentCollection; import com.microsoft.azure.cosmosdb.FeedOptions; @@ -43,11 +43,13 @@ import com.microsoft.azure.cosmosdb.Permission; import com.microsoft.azure.cosmosdb.PermissionMode; import com.microsoft.azure.cosmosdb.User; +import com.microsoft.azure.cosmosdb.rx.internal.TestSuiteBase; import rx.Observable; import javax.net.ssl.SSLException; +//TODO: change to use external TestSuiteBase public class PermissionQueryTest extends TestSuiteBase { public final String databaseId = DatabaseForTest.generateId(); diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ProxyHostTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ProxyHostTest.java index f982df926d244..79e9a38e23252 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ProxyHostTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ProxyHostTest.java @@ -33,29 +33,25 @@ import org.apache.log4j.PatternLayout; import org.apache.log4j.PropertyConfigurator; import org.apache.log4j.WriterAppender; -import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; -import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Factory; import org.testng.annotations.Test; import com.microsoft.azure.cosmosdb.rx.proxy.HttpProxyServer; -import io.netty.handler.logging.LogLevel; -import io.netty.handler.logging.LoggingHandler; +import reactor.core.publisher.Mono; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosDatabase; +import com.microsoft.azure.cosmos.CosmosItemRequestOptions; +import com.microsoft.azure.cosmos.CosmosItemResponse; +import com.microsoft.azure.cosmos.CosmosItemSettings; +import com.microsoft.azure.cosmos.CosmosResponseValidator; import com.microsoft.azure.cosmosdb.ConnectionPolicy; import com.microsoft.azure.cosmosdb.ConsistencyLevel; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.Document; -import com.microsoft.azure.cosmosdb.DocumentCollection; -import com.microsoft.azure.cosmosdb.ResourceResponse; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; - -import rx.Observable; import static org.assertj.core.api.Assertions.assertThat; @@ -67,10 +63,10 @@ */ public class ProxyHostTest extends TestSuiteBase { - private static Database createdDatabase; - private static DocumentCollection createdCollection; + private static CosmosDatabase createdDatabase; + private static CosmosContainer createdCollection; - private AsyncDocumentClient client; + private CosmosClient client; private final String PROXY_HOST = "localhost"; private final int PROXY_PORT = 8080; private HttpProxyServer httpProxyServer; @@ -82,8 +78,8 @@ public ProxyHostTest() { @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) public void beforeClass() throws Exception { client = clientBuilder.build(); - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_SINGLE_PARTITION_COLLECTION; + createdDatabase = getSharedCosmosDatabase(client); + createdCollection = getSharedMultiPartitionCosmosContainer(client); httpProxyServer = new HttpProxyServer(); httpProxyServer.start(); // wait for proxy server to be ready @@ -97,18 +93,18 @@ public void beforeClass() throws Exception { */ @Test(groups = { "simple" }, timeOut = TIMEOUT) public void createDocumentWithValidHttpProxy() throws Exception { - AsyncDocumentClient clientWithRightProxy = null; + CosmosClient clientWithRightProxy = null; try { ConnectionPolicy connectionPolicy =new ConnectionPolicy(); connectionPolicy.setProxy(PROXY_HOST, PROXY_PORT); - clientWithRightProxy = new Builder().withServiceEndpoint(TestConfigurations.HOST) - .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) - .withConnectionPolicy(connectionPolicy) - .withConsistencyLevel(ConsistencyLevel.Session).build(); - Document docDefinition = getDocumentDefinition(); - Observable> createObservable = clientWithRightProxy - .createDocument(getCollectionLink(), docDefinition, null, false); - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + clientWithRightProxy = CosmosClient.builder().endpoint(TestConfigurations.HOST) + .key(TestConfigurations.MASTER_KEY) + .connectionPolicy(connectionPolicy) + .consistencyLevel(ConsistencyLevel.Session).build(); + CosmosItemSettings docDefinition = getDocumentDefinition(); + Mono createObservable = clientWithRightProxy.getDatabase(createdDatabase.getId()).getContainer(createdCollection.getId()) + .createItem(docDefinition, new CosmosItemRequestOptions()); + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .withId(docDefinition.getId()) .build(); validateSuccess(createObservable, validator); @@ -126,7 +122,7 @@ public void createDocumentWithValidHttpProxy() throws Exception { public void createDocumentWithValidHttpProxyWithNettyWireLogging() throws Exception { LogManager.getRootLogger().setLevel(Level.INFO); LogManager.getLogger(LogLevelTest.NETWORK_LOGGING_CATEGORY).setLevel(Level.TRACE); - AsyncDocumentClient clientWithRightProxy = null; + CosmosClient clientWithRightProxy = null; try { StringWriter consoleWriter = new StringWriter(); WriterAppender appender = new WriterAppender(new PatternLayout(), consoleWriter); @@ -134,14 +130,14 @@ public void createDocumentWithValidHttpProxyWithNettyWireLogging() throws Except ConnectionPolicy connectionPolicy =new ConnectionPolicy(); connectionPolicy.setProxy(PROXY_HOST, PROXY_PORT); - clientWithRightProxy = new Builder().withServiceEndpoint(TestConfigurations.HOST) - .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) - .withConnectionPolicy(connectionPolicy) - .withConsistencyLevel(ConsistencyLevel.Session).build(); - Document docDefinition = getDocumentDefinition(); - Observable> createObservable = clientWithRightProxy - .createDocument(getCollectionLink(), docDefinition, null, false); - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + clientWithRightProxy = CosmosClient.builder().endpoint(TestConfigurations.HOST) + .key(TestConfigurations.MASTER_KEY) + .connectionPolicy(connectionPolicy) + .consistencyLevel(ConsistencyLevel.Session).build(); + CosmosItemSettings docDefinition = getDocumentDefinition(); + Mono createObservable = clientWithRightProxy.getDatabase(createdDatabase.getId()).getContainer(createdCollection.getId()) + .createItem(docDefinition, new CosmosItemRequestOptions()); + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .withId(docDefinition.getId()) .build(); validateSuccess(createObservable, validator); @@ -178,13 +174,9 @@ public void afterMethod(Method method) { PropertyConfigurator.configure(this.getClass().getClassLoader().getResource("log4j.properties")); } - private String getCollectionLink() { - return createdCollection.getSelfLink(); - } - - private Document getDocumentDefinition() { + private CosmosItemSettings getDocumentDefinition() { String uuid = UUID.randomUUID().toString(); - Document doc = new Document(String.format("{ " + CosmosItemSettings doc = new CosmosItemSettings(String.format("{ " + "\"id\": \"%s\", " + "\"mypk\": \"%s\", " + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedAttachmentsTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedAttachmentsTest.java deleted file mode 100644 index bf61c7d7414ae..0000000000000 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedAttachmentsTest.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * The MIT License (MIT) - * Copyright (c) 2018 Microsoft Corporation - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package com.microsoft.azure.cosmosdb.rx; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; -import java.util.stream.Collectors; - -import org.apache.commons.io.IOUtils; -import org.testng.annotations.AfterClass; -import org.testng.annotations.BeforeClass; -import org.testng.annotations.Factory; -import org.testng.annotations.Test; - -import com.microsoft.azure.cosmosdb.Attachment; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.Document; -import com.microsoft.azure.cosmosdb.DocumentClientException; -import com.microsoft.azure.cosmosdb.DocumentCollection; -import com.microsoft.azure.cosmosdb.FeedOptions; -import com.microsoft.azure.cosmosdb.FeedResponse; -import com.microsoft.azure.cosmosdb.MediaOptions; -import com.microsoft.azure.cosmosdb.PartitionKey; -import com.microsoft.azure.cosmosdb.RequestOptions; -import com.microsoft.azure.cosmosdb.ResourceResponse; - -import rx.Observable; -import rx.observers.TestSubscriber; - -import javax.net.ssl.SSLException; - -public class ReadFeedAttachmentsTest extends TestSuiteBase { - - private Database createdDatabase; - private DocumentCollection createdCollection; - private Document createdDocument; - - private AsyncDocumentClient client; - - private PartitionKey pk; - @Factory(dataProvider = "clientBuildersWithDirect") - public ReadFeedAttachmentsTest(AsyncDocumentClient.Builder clientBuilder) { - this.clientBuilder = clientBuilder; - } - - @Test(groups = { "simple" }, timeOut = 30000000) - public void readExternalAttachments() throws Exception { - createdDocument = createDocument(client, createdDatabase.getId(), - createdCollection.getId(), getDocumentDefinition()); - - List createdAttachments = new ArrayList<>(); - for(int i = 0; i < 5; i++) { - createdAttachments.add(createAttachments(client)); - } - waitIfNeededForReplicasToCatchUp(clientBuilder); - - FeedOptions options = new FeedOptions(); - options.setMaxItemCount(2); - options.setPartitionKey(pk); - - Observable> feedObservable = client.readAttachments(getDocumentLink(), options); - - int expectedPageSize = (createdAttachments.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - - FeedResponseListValidator validator = new FeedResponseListValidator - .Builder() - .totalSize(createdAttachments.size()) - .exactlyContainsInAnyOrder(createdAttachments - .stream() - .map(d -> d.getResourceId()) - .collect(Collectors.toList())) - .numberOfPages(expectedPageSize) - .allPagesSatisfy(new FeedResponseValidator.Builder() - .requestChargeGreaterThanOrEqualTo(1.0).build()) - .build(); - validateQuerySuccess(feedObservable, validator, FEED_TIMEOUT); - } - - //@Test(groups = { "simple" }, timeOut = FEED_TIMEOUT) - public void readAndUpdateEmbededAttachments() throws Exception { - createdDocument = createDocument(client, createdDatabase.getId(), - createdCollection.getId(), getDocumentDefinition()); - - FeedOptions feedOptions = new FeedOptions(); - feedOptions.setMaxItemCount(1); - feedOptions.setPartitionKey(pk); - String documentLink = "dbs/" + getDatabaseId() + "/colls/" + getCollectionId() + "/docs/" + getDocumentId(); - - MediaOptions options = new MediaOptions(); - options.setContentType("application/octet-stream"); - - RequestOptions reqOptions = new RequestOptions(); - reqOptions.setPartitionKey(pk); - - - try(InputStream ipStream = getMedia1Stream()) { - TestSubscriber> subscriber = new TestSubscriber<>(); - client.createAttachment(documentLink, ipStream, options, reqOptions) - .toBlocking() - .subscribe(subscriber); - subscriber.assertNoErrors(); - } - - try(InputStream ipStream = getMedia1Stream()) { - validateReadEmbededAttachment(documentLink, ipStream, feedOptions); - } - - validateUpdateEmbededAttachment(documentLink, options, feedOptions); - } - - @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) - public void beforeClass() { - client = clientBuilder.build(); - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_SINGLE_PARTITION_COLLECTION; - } - - @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) - public void afterClass() { - safeClose(client); - } - - private void validateUpdateEmbededAttachment(String documentLink, MediaOptions mediaOptions, FeedOptions feedOptions) throws Exception { - String mediaLink = client.readAttachments(documentLink, feedOptions) - .map( response -> response.getResults().iterator().next().getMediaLink()) - .toBlocking() - .first(); - - try (InputStream ipStream = getMedia2Stream()) { - client.updateMedia(mediaLink, ipStream, mediaOptions) - .toBlocking().first(); - } - - try (InputStream ipStream = getMedia2Stream()) { - validateReadEmbededAttachment(documentLink, ipStream, feedOptions); - } - } - - private void validateReadEmbededAttachment(String documentLink, InputStream ipStream, FeedOptions feedOptions) { - TestSubscriber subscriber = new TestSubscriber<>(); - client.readAttachments(documentLink, feedOptions) - .map( response -> response.getResults().iterator().next().getMediaLink()) - .flatMap(mediaLink -> client.readMedia(mediaLink)) - .map(mediaResponse -> { - - try(InputStream responseMediaStream = mediaResponse.getMedia()) { - return IOUtils.contentEquals(ipStream, responseMediaStream); - } catch (IOException e) { - return false; - } - }) - .filter(x -> x) // Filter only right extractions back - .toBlocking() - .subscribe(subscriber); - - subscriber.assertNoErrors(); - subscriber.assertCompleted(); - subscriber.assertValueCount(1); - } - - private InputStream getMedia1Stream() - { - return this.getClass().getResourceAsStream("/cosmosdb-1.png"); - } - - private InputStream getMedia2Stream() - { - return this.getClass().getResourceAsStream("/Microsoft.jpg"); - } - - private String getCollectionId() { - return createdCollection.getId(); - } - - private String getDatabaseId() { - return createdDatabase.getId(); - } - - private String getDocumentId() { - return createdDocument.getId(); - } - - public Attachment createAttachments(AsyncDocumentClient client) { - Attachment attachment = getAttachmentDefinition(); - RequestOptions options = new RequestOptions(); - options.setPartitionKey(pk); - return client.createAttachment(getDocumentLink(), attachment, options).toBlocking().single().getResource(); - } - - public String getDocumentLink() { - return "dbs/" + getDatabaseId() + "/colls/" + getCollectionId() + "/docs/" + getDocumentId(); - } - - private Document getDocumentDefinition() { - String uuid = UUID.randomUUID().toString(); - pk = new PartitionKey(uuid); - Document doc = new Document(String.format("{ " - + "\"id\": \"%s\", " - + "\"mypk\": \"%s\", " - + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" - + "}" - , uuid, uuid)); - return doc; - } - - private static Attachment getAttachmentDefinition() { - String uuid = UUID.randomUUID().toString(); - String type = "application/text"; - return new Attachment(String.format( - "{" + - " 'id': '%s'," + - " 'media': 'http://xstore.'," + - " 'MediaType': 'Book'," + - " 'Author': 'My Book Author'," + - " 'Title': 'My Book Title'," + - " 'contentType': '%s'" + - "}", uuid, type)); - } -} diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedCollectionsTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedCollectionsTest.java index fb3c735ea8677..54982a098e6fe 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedCollectionsTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedCollectionsTest.java @@ -27,21 +27,23 @@ import java.util.UUID; import java.util.stream.Collectors; -import com.microsoft.azure.cosmosdb.DatabaseForTest; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.DocumentClientException; -import com.microsoft.azure.cosmosdb.DocumentCollection; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosContainerRequestOptions; +import com.microsoft.azure.cosmos.CosmosContainerSettings; +import com.microsoft.azure.cosmos.CosmosDatabase; +import com.microsoft.azure.cosmos.CosmosDatabaseForTest; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; +import com.microsoft.azure.cosmosdb.PartitionKeyDefinition; -import rx.Observable; - -import javax.net.ssl.SSLException; +import reactor.core.publisher.Flux; public class ReadFeedCollectionsTest extends TestSuiteBase { @@ -49,15 +51,15 @@ public class ReadFeedCollectionsTest extends TestSuiteBase { protected static final int SETUP_TIMEOUT = 60000; protected static final int SHUTDOWN_TIMEOUT = 20000; - public final String databaseId = DatabaseForTest.generateId(); + public final String databaseId = CosmosDatabaseForTest.generateId(); - private Database createdDatabase; - private List createdCollections = new ArrayList<>(); + private CosmosDatabase createdDatabase; + private List createdCollections = new ArrayList<>(); - private AsyncDocumentClient client; + private CosmosClient client; @Factory(dataProvider = "clientBuilders") - public ReadFeedCollectionsTest(AsyncDocumentClient.Builder clientBuilder) { + public ReadFeedCollectionsTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @@ -67,15 +69,15 @@ public void readCollections() throws Exception { FeedOptions options = new FeedOptions(); options.setMaxItemCount(2); - Observable> feedObservable = client.readCollections(getDatabaseLink(), options); + Flux> feedObservable = createdDatabase.listContainers(options); int expectedPageSize = (createdCollections.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .totalSize(createdCollections.size()) - .exactlyContainsInAnyOrder(createdCollections.stream().map(d -> d.getResourceId()).collect(Collectors.toList())) + .exactlyContainsInAnyOrder(createdCollections.stream().map(d -> d.read().block().getCosmosContainerSettings().getResourceId()).collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .pageSatisfy(0, new FeedResponseValidator.Builder() + .pageSatisfy(0, new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); @@ -89,23 +91,22 @@ public void beforeClass() { createdDatabase = createDatabase(client, databaseId); for(int i = 0; i < 3; i++) { - createdCollections.add(createCollections(client)); + createdCollections.add(createCollections(createdDatabase)); } } @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) public void afterClass() { - safeDeleteDatabase(client, createdDatabase); + safeDeleteDatabase(createdDatabase); safeClose(client); } - public DocumentCollection createCollections(AsyncDocumentClient client) { - DocumentCollection collection = new DocumentCollection(); - collection.setId(UUID.randomUUID().toString()); - return client.createCollection(getDatabaseLink(), collection, null).toBlocking().single().getResource(); - } - - private String getDatabaseLink() { - return "dbs/" + createdDatabase.getId(); + public CosmosContainer createCollections(CosmosDatabase database) { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.setPaths(paths); + CosmosContainerSettings collection = new CosmosContainerSettings(UUID.randomUUID().toString(), partitionKeyDef); + return database.createContainer(collection, new CosmosContainerRequestOptions()).block().getContainer(); } } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedDatabasesTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedDatabasesTest.java index 823118868ec5e..74e01f247ef94 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedDatabasesTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedDatabasesTest.java @@ -28,30 +28,29 @@ import java.util.UUID; import java.util.stream.Collectors; -import com.microsoft.azure.cosmosdb.DatabaseForTest; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.DocumentClientException; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosDatabaseRequestOptions; +import com.microsoft.azure.cosmos.CosmosDatabaseSettings; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; -import rx.Observable; - -import javax.net.ssl.SSLException; +import reactor.core.publisher.Flux; public class ReadFeedDatabasesTest extends TestSuiteBase { - private List createdDatabases = new ArrayList<>(); - private List allDatabases = new ArrayList<>(); + private List createdDatabases = new ArrayList<>(); + private List allDatabases = new ArrayList<>(); - private AsyncDocumentClient client; + private CosmosClient client; @Factory(dataProvider = "clientBuilders") - public ReadFeedDatabasesTest(AsyncDocumentClient.Builder clientBuilder) { + public ReadFeedDatabasesTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @@ -61,14 +60,14 @@ public void readDatabases() throws Exception { FeedOptions options = new FeedOptions(); options.setMaxItemCount(2); - Observable> feedObservable = client.readDatabases(options); + Flux> feedObservable = client.listDatabases(options); int expectedPageSize = (allDatabases.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .totalSize(allDatabases.size()) .exactlyContainsInAnyOrder(allDatabases.stream().map(d -> d.getResourceId()).collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .pageSatisfy(0, new FeedResponseValidator.Builder() + .pageSatisfy(0, new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); @@ -78,28 +77,26 @@ public void readDatabases() throws Exception { @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) public void beforeClass() throws URISyntaxException { client = clientBuilder.build(); - allDatabases = client.readDatabases(null) + allDatabases = client.listDatabases(null) .map(frp -> frp.getResults()) - .toList() + .collectList() .map(list -> list.stream().flatMap(x -> x.stream()).collect(Collectors.toList())) - .toBlocking() - .single(); + .block(); for(int i = 0; i < 5; i++) { createdDatabases.add(createDatabase(client)); } allDatabases.addAll(createdDatabases); } - public Database createDatabase(AsyncDocumentClient client) { - Database db = new Database(); - db.setId(UUID.randomUUID().toString()); - return client.createDatabase(db, null).toBlocking().single().getResource(); + public CosmosDatabaseSettings createDatabase(CosmosClient client) { + CosmosDatabaseSettings db = new CosmosDatabaseSettings(UUID.randomUUID().toString()); + return client.createDatabase(db, new CosmosDatabaseRequestOptions()).block().getCosmosDatabaseSettings(); } @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) public void afterClass() { for (int i = 0; i < 5; i ++) { - safeDeleteDatabase(client, createdDatabases.get(i).getId()); + safeDeleteDatabase(client.getDatabase(createdDatabases.get(i).getId())); } safeClose(client); } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedDocumentsTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedDocumentsTest.java index fd59b372ffe66..83620644114ac 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedDocumentsTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedDocumentsTest.java @@ -22,17 +22,21 @@ */ package com.microsoft.azure.cosmosdb.rx; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.Document; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosClientBuilder; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosDatabase; +import com.microsoft.azure.cosmos.CosmosItemSettings; import com.microsoft.azure.cosmosdb.DocumentClientException; -import com.microsoft.azure.cosmosdb.DocumentCollection; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; + +import reactor.core.publisher.Flux; + import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import rx.Observable; import java.util.ArrayList; import java.util.List; @@ -41,14 +45,14 @@ public class ReadFeedDocumentsTest extends TestSuiteBase { - private Database createdDatabase; - private DocumentCollection createdCollection; - private List createdDocuments; + private CosmosDatabase createdDatabase; + private CosmosContainer createdCollection; + private List createdDocuments; - private AsyncDocumentClient client; + private CosmosClient client; @Factory(dataProvider = "clientBuildersWithDirect") - public ReadFeedDocumentsTest(AsyncDocumentClient.Builder clientBuilder) { + public ReadFeedDocumentsTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @@ -58,12 +62,12 @@ public void readDocuments() { options.setEnableCrossPartitionQuery(true); options.setMaxItemCount(2); - Observable> feedObservable = client.readDocuments(getCollectionLink(), options); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + Flux> feedObservable = createdCollection.listItems(options); + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .totalSize(createdDocuments.size()) .numberOfPagesIsGreaterThanOrEqualTo(1) .exactlyContainsInAnyOrder(createdDocuments.stream().map(d -> d.getResourceId()).collect(Collectors.toList())) - .allPagesSatisfy(new FeedResponseValidator.Builder() + .allPagesSatisfy(new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0) .pageSizeIsLessThanOrEqualTo(options.getMaxItemCount()) .build()) @@ -76,7 +80,7 @@ public void readDocuments_withoutEnableCrossPartitionQuery() { FeedOptions options = new FeedOptions(); options.setMaxItemCount(2); - Observable> feedObservable = client.readDocuments(getCollectionLink(), options); + Flux> feedObservable = createdCollection.listItems(options); FailureValidator validator = FailureValidator.builder().instanceOf(DocumentClientException.class) .statusCode(400) .errorMessageContains("Cross partition query is required but disabled." + @@ -90,17 +94,16 @@ public void readDocuments_withoutEnableCrossPartitionQuery() { @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT, alwaysRun = true) public void beforeClass() { client = clientBuilder.build(); - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_MULTI_PARTITION_COLLECTION; + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); - truncateCollection(SHARED_MULTI_PARTITION_COLLECTION); - List docDefList = new ArrayList<>(); + List docDefList = new ArrayList<>(); for(int i = 0; i < 100; i++) { docDefList.add(getDocumentDefinition()); } - createdDocuments = bulkInsertBlocking(client, getCollectionLink(), docDefList); + createdDocuments = bulkInsertBlocking(createdCollection, docDefList); waitIfNeededForReplicasToCatchUp(clientBuilder); } @@ -109,9 +112,9 @@ public void afterClass() { safeClose(client); } - private Document getDocumentDefinition() { + private CosmosItemSettings getDocumentDefinition() { String uuid = UUID.randomUUID().toString(); - Document doc = new Document(String.format("{ " + CosmosItemSettings doc = new CosmosItemSettings(String.format("{ " + "\"id\": \"%s\", " + "\"mypk\": \"%s\", " + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedExceptionHandlingTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedExceptionHandlingTest.java index 044d2a6e9910c..e6e8327b81146 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedExceptionHandlingTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedExceptionHandlingTest.java @@ -25,84 +25,57 @@ import static org.assertj.core.api.Assertions.assertThat; import java.util.ArrayList; -import java.util.concurrent.CountDownLatch; -import com.microsoft.azure.cosmosdb.BridgeInternal; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import org.mockito.Mockito; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.BridgeUtils; -import com.microsoft.azure.cosmosdb.Database; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosDatabaseSettings; +import com.microsoft.azure.cosmosdb.BridgeInternal; import com.microsoft.azure.cosmosdb.DocumentClientException; import com.microsoft.azure.cosmosdb.FeedResponse; -import rx.Observable; -import rx.Subscriber; - +import io.reactivex.subscribers.TestSubscriber; +import reactor.core.publisher.Flux; public class ReadFeedExceptionHandlingTest extends TestSuiteBase { - public class ExceptionSubscriber extends Subscriber> { - - public int onNextCount; - CountDownLatch latch = new CountDownLatch(1); - public ExceptionSubscriber() { - onNextCount = 0; - } - - @Override - public void onCompleted() { - latch.countDown(); - } - - @Override - public void onError(Throwable e) { - DocumentClientException exception = (DocumentClientException) e; - assertThat(exception).isNotNull(); - assertThat(exception.getStatusCode()).isEqualTo(0); - latch.countDown(); - } - - @Override - public void onNext(FeedResponse page) { - assertThat(page.getResults().size()).isEqualTo(2); - onNextCount ++; - } - } - - private AsyncDocumentClient client; + private CosmosClient client; @Factory(dataProvider = "clientBuildersWithDirect") - public ReadFeedExceptionHandlingTest(AsyncDocumentClient.Builder clientBuilder) { + public ReadFeedExceptionHandlingTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @Test(groups = { "simple" }, timeOut = TIMEOUT) public void readFeedException() throws Exception { - ArrayList dbs = new ArrayList(); - dbs.add(new Database()); - dbs.add(new Database()); + ArrayList dbs = new ArrayList(); + dbs.add(new CosmosDatabaseSettings("db1")); + dbs.add(new CosmosDatabaseSettings("db2")); - ArrayList> frps = new ArrayList>(); + ArrayList> frps = new ArrayList>(); frps.add(BridgeInternal.createFeedResponse(dbs, null)); frps.add(BridgeInternal.createFeedResponse(dbs, null)); - Observable> response = Observable.from(frps) - .concatWith(Observable.error(new DocumentClientException(0))) - .concatWith(Observable.from(frps)); - - final AsyncDocumentClient mockClient = Mockito.spy(client); - Mockito.when(mockClient.readDatabases(null)).thenReturn(response); - ExceptionSubscriber subscriber = new ExceptionSubscriber(); - mockClient.readDatabases(null).subscribe(subscriber); - subscriber.latch.await(); - assertThat(subscriber.onNextCount).isEqualTo(2); + Flux> response = Flux.merge(Flux.fromIterable(frps)) + .mergeWith(Flux.error(new DocumentClientException(0))) + .mergeWith(Flux.fromIterable(frps)); + + final CosmosClient mockClient = Mockito.spy(client); + Mockito.when(mockClient.listDatabases(null)).thenReturn(response); + TestSubscriber> subscriber = new TestSubscriber>(); + mockClient.listDatabases(null).subscribe(subscriber); + assertThat(subscriber.valueCount()).isEqualTo(2); + assertThat(subscriber.assertNotComplete()); + assertThat(subscriber.assertTerminated()); + assertThat(subscriber.errorCount()).isEqualTo(1); } - + @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) public void beforeClass() { client = clientBuilder.build(); diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedOffersTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedOffersTest.java index 7b7e46d9dd01d..f4f54e27647a6 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedOffersTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedOffersTest.java @@ -27,23 +27,26 @@ import java.util.UUID; import java.util.stream.Collectors; -import com.microsoft.azure.cosmosdb.DatabaseForTest; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; import com.microsoft.azure.cosmosdb.Database; +import com.microsoft.azure.cosmosdb.DatabaseForTest; import com.microsoft.azure.cosmosdb.DocumentClientException; import com.microsoft.azure.cosmosdb.DocumentCollection; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; import com.microsoft.azure.cosmosdb.Offer; +import com.microsoft.azure.cosmosdb.PartitionKeyDefinition; +import com.microsoft.azure.cosmosdb.rx.internal.TestSuiteBase; import rx.Observable; import javax.net.ssl.SSLException; +//TODO: change to use external TestSuiteBase public class ReadFeedOffersTest extends TestSuiteBase { protected static final int FEED_TIMEOUT = 60000; @@ -108,6 +111,13 @@ public void afterClass() { public DocumentCollection createCollections(AsyncDocumentClient client) { DocumentCollection collection = new DocumentCollection(); collection.setId(UUID.randomUUID().toString()); + + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.setPaths(paths); + collection.setPartitionKey(partitionKeyDef); + return client.createCollection(getDatabaseLink(), collection, null).toBlocking().single().getResource(); } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedPermissionsTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedPermissionsTest.java index 6959a305bd5c0..3fcab18c1e425 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedPermissionsTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedPermissionsTest.java @@ -27,25 +27,23 @@ import java.util.UUID; import java.util.stream.Collectors; -import com.microsoft.azure.cosmosdb.DatabaseForTest; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.DocumentClientException; -import com.microsoft.azure.cosmosdb.DocumentCollection; +import com.microsoft.azure.cosmosdb.DatabaseForTest; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; import com.microsoft.azure.cosmosdb.Permission; import com.microsoft.azure.cosmosdb.PermissionMode; import com.microsoft.azure.cosmosdb.User; +import com.microsoft.azure.cosmosdb.rx.internal.TestSuiteBase; import rx.Observable; -import javax.net.ssl.SSLException; - +//TODO: change to use external TestSuiteBase public class ReadFeedPermissionsTest extends TestSuiteBase { public final String databaseId = DatabaseForTest.generateId(); @@ -109,8 +107,6 @@ private static User getUserDefinition() { } public Permission createPermissions(AsyncDocumentClient client, int index) { - DocumentCollection collection = new DocumentCollection(); - collection.setId(UUID.randomUUID().toString()); Permission permission = new Permission(); permission.setId(UUID.randomUUID().toString()); permission.setPermissionMode(PermissionMode.Read); diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedPkrTests.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedPkrTests.java index 6fbd5e74ad5a1..e9207e83b3d87 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedPkrTests.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedPkrTests.java @@ -22,15 +22,16 @@ */ package com.microsoft.azure.cosmosdb.rx; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import javax.net.ssl.SSLException; - -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.DocumentCollection; +import com.microsoft.azure.cosmos.CosmosBridgeInternal; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosContainerRequestOptions; +import com.microsoft.azure.cosmos.CosmosDatabase; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; import com.microsoft.azure.cosmosdb.PartitionKeyRange; @@ -39,13 +40,13 @@ public class ReadFeedPkrTests extends TestSuiteBase { - private Database createdDatabase; - private DocumentCollection createdCollection; + private CosmosDatabase createdDatabase; + private CosmosContainer createdCollection; private AsyncDocumentClient client; @Factory(dataProvider = "clientBuildersWithDirect") - public ReadFeedPkrTests(AsyncDocumentClient.Builder clientBuilder) { + public ReadFeedPkrTests(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @@ -66,17 +67,17 @@ public void readPartitionKeyRanges() throws Exception { @BeforeClass(groups = { "emulator" }, timeOut = SETUP_TIMEOUT) public void beforeClass() { - createdDatabase = SHARED_DATABASE; - createdCollection = createCollection(createdDatabase.getId(), + client = CosmosBridgeInternal.getAsyncDocumentClient(clientBuilder.build()); + createdDatabase = getSharedCosmosDatabase(clientBuilder.build()); + createdCollection = createCollection(createdDatabase, getCollectionDefinition(), - null); - client = clientBuilder.build(); + new CosmosContainerRequestOptions()); } @AfterClass(groups = { "emulator" }, timeOut = SETUP_TIMEOUT, alwaysRun = true) public void afterClass() { - safeDeleteCollection(client, createdCollection); - safeClose(client); + safeDeleteCollection(createdCollection); + client.close(); } private String getCollectionLink() { diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedStoredProceduresTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedStoredProceduresTest.java index 0f7d2aa156ea3..e0b46a7d8476b 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedStoredProceduresTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedStoredProceduresTest.java @@ -27,32 +27,30 @@ import java.util.UUID; import java.util.stream.Collectors; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.DocumentClientException; -import com.microsoft.azure.cosmosdb.DocumentCollection; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosStoredProcedureRequestOptions; +import com.microsoft.azure.cosmos.CosmosStoredProcedureSettings; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; -import com.microsoft.azure.cosmosdb.StoredProcedure; -import rx.Observable; - -import javax.net.ssl.SSLException; +import reactor.core.publisher.Flux; public class ReadFeedStoredProceduresTest extends TestSuiteBase { - private Database createdDatabase; - private DocumentCollection createdCollection; - private List createdStoredProcedures = new ArrayList<>(); + private CosmosContainer createdCollection; + private List createdStoredProcedures = new ArrayList<>(); - private AsyncDocumentClient client; + private CosmosClient client; @Factory(dataProvider = "clientBuildersWithDirect") - public ReadFeedStoredProceduresTest(AsyncDocumentClient.Builder clientBuilder) { + public ReadFeedStoredProceduresTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @@ -62,19 +60,19 @@ public void readStoredProcedures() throws Exception { FeedOptions options = new FeedOptions(); options.setMaxItemCount(2); - Observable> feedObservable = client.readStoredProcedures(getCollectionLink(), options); + Flux> feedObservable = createdCollection.listStoredProcedures(options); int expectedPageSize = (createdStoredProcedures.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - FeedResponseListValidator validator = new FeedResponseListValidator - .Builder() + FeedResponseListValidator validator = new FeedResponseListValidator + .Builder() .totalSize(createdStoredProcedures.size()) .exactlyContainsInAnyOrder(createdStoredProcedures .stream() .map(d -> d.getResourceId()) .collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .allPagesSatisfy(new FeedResponseValidator.Builder() + .allPagesSatisfy(new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); validateQuerySuccess(feedObservable, validator, FEED_TIMEOUT); @@ -83,12 +81,11 @@ public void readStoredProcedures() throws Exception { @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) public void beforeClass() { client = clientBuilder.build(); - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY; - truncateCollection(SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); for(int i = 0; i < 5; i++) { - createdStoredProcedures.add(createStoredProcedures(client)); + createdStoredProcedures.add(createStoredProcedures(createdCollection)); } waitIfNeededForReplicasToCatchUp(clientBuilder); @@ -99,22 +96,10 @@ public void afterClass() { safeClose(client); } - public StoredProcedure createStoredProcedures(AsyncDocumentClient client) { - StoredProcedure sproc = new StoredProcedure(); + public CosmosStoredProcedureSettings createStoredProcedures(CosmosContainer cosmosContainer) { + CosmosStoredProcedureSettings sproc = new CosmosStoredProcedureSettings(); sproc.setId(UUID.randomUUID().toString()); sproc.setBody("function() {var x = 10;}"); - return client.createStoredProcedure(getCollectionLink(), sproc, null).toBlocking().single().getResource(); - } - - private String getCollectionLink() { - return "dbs/" + getDatabaseId() + "/colls/" + getCollectionId(); - } - - private String getCollectionId() { - return createdCollection.getId(); - } - - private String getDatabaseId() { - return createdDatabase.getId(); + return cosmosContainer.createStoredProcedure(sproc, new CosmosStoredProcedureRequestOptions()).block().getStoredProcedureSettings(); } } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedTriggersTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedTriggersTest.java index 2b2c407807182..406f3033b186f 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedTriggersTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedTriggersTest.java @@ -27,32 +27,32 @@ import java.util.UUID; import java.util.stream.Collectors; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.DocumentClientException; -import com.microsoft.azure.cosmosdb.DocumentCollection; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosRequestOptions; +import com.microsoft.azure.cosmos.CosmosTriggerSettings; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; -import com.microsoft.azure.cosmosdb.Trigger; import com.microsoft.azure.cosmosdb.TriggerOperation; import com.microsoft.azure.cosmosdb.TriggerType; -import rx.Observable; +import reactor.core.publisher.Flux; public class ReadFeedTriggersTest extends TestSuiteBase { - private Database createdDatabase; - private DocumentCollection createdCollection; - private List createdTriggers = new ArrayList<>(); + private CosmosContainer createdCollection; + private List createdTriggers = new ArrayList<>(); - private AsyncDocumentClient client; + private CosmosClient client; @Factory(dataProvider = "clientBuildersWithDirect") - public ReadFeedTriggersTest(AsyncDocumentClient.Builder clientBuilder) { + public ReadFeedTriggersTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @@ -62,19 +62,19 @@ public void readTriggers() throws Exception { FeedOptions options = new FeedOptions(); options.setMaxItemCount(2); - Observable> feedObservable = client.readTriggers(getCollectionLink(), options); + Flux> feedObservable = createdCollection.listTriggers(options); int expectedPageSize = (createdTriggers.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - FeedResponseListValidator validator = new FeedResponseListValidator - .Builder() + FeedResponseListValidator validator = new FeedResponseListValidator + .Builder() .totalSize(createdTriggers.size()) .exactlyContainsInAnyOrder(createdTriggers .stream() .map(d -> d.getResourceId()) .collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .allPagesSatisfy(new FeedResponseValidator.Builder() + .allPagesSatisfy(new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); validateQuerySuccess(feedObservable, validator, FEED_TIMEOUT); @@ -82,17 +82,15 @@ public void readTriggers() throws Exception { @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) public void beforeClass() { - - this.client = clientBuilder.build(); - this.createdDatabase = SHARED_DATABASE; - this.createdCollection = SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY; - this.truncateCollection(SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY); + client = clientBuilder.build(); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); for(int i = 0; i < 5; i++) { - this.createdTriggers.add(this.createTriggers(client)); + this.createdTriggers.add(this.createTriggers(createdCollection)); } - this.waitIfNeededForReplicasToCatchUp(clientBuilder); + waitIfNeededForReplicasToCatchUp(clientBuilder); } @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) @@ -100,24 +98,12 @@ public void afterClass() { safeClose(client); } - public Trigger createTriggers(AsyncDocumentClient client) { - Trigger trigger = new Trigger(); + public CosmosTriggerSettings createTriggers(CosmosContainer cosmosContainer) { + CosmosTriggerSettings trigger = new CosmosTriggerSettings(); trigger.setId(UUID.randomUUID().toString()); trigger.setBody("function() {var x = 10;}"); trigger.setTriggerOperation(TriggerOperation.Create); trigger.setTriggerType(TriggerType.Pre); - return client.createTrigger(getCollectionLink(), trigger, null).toBlocking().single().getResource(); - } - - private String getCollectionLink() { - return "dbs/" + getDatabaseId() + "/colls/" + getCollectionId(); - } - - private String getCollectionId() { - return createdCollection.getId(); - } - - private String getDatabaseId() { - return createdDatabase.getId(); + return cosmosContainer.createTrigger(trigger, new CosmosRequestOptions()).block().getCosmosTriggerSettings(); } } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedUdfsTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedUdfsTest.java index 4bd2ccbbbfdec..9e5fe1c2a5de1 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedUdfsTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedUdfsTest.java @@ -27,32 +27,32 @@ import java.util.UUID; import java.util.stream.Collectors; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosRequestOptions; +import com.microsoft.azure.cosmos.CosmosUserDefinedFunctionSettings; import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.DocumentClientException; -import com.microsoft.azure.cosmosdb.DocumentCollection; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; -import com.microsoft.azure.cosmosdb.UserDefinedFunction; -import rx.Observable; - -import javax.net.ssl.SSLException; +import reactor.core.publisher.Flux; public class ReadFeedUdfsTest extends TestSuiteBase { private Database createdDatabase; - private DocumentCollection createdCollection; - private List createdUserDefinedFunctions = new ArrayList<>(); + private CosmosContainer createdCollection; + private List createdUserDefinedFunctions = new ArrayList<>(); - private AsyncDocumentClient client; + private CosmosClient client; @Factory(dataProvider = "clientBuildersWithDirect") - public ReadFeedUdfsTest(AsyncDocumentClient.Builder clientBuilder) { + public ReadFeedUdfsTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @@ -62,19 +62,19 @@ public void readUserDefinedFunctions() throws Exception { FeedOptions options = new FeedOptions(); options.setMaxItemCount(2); - Observable> feedObservable = client.readUserDefinedFunctions(getCollectionLink(), options); + Flux> feedObservable = createdCollection.listUserDefinedFunctions(options); int expectedPageSize = (createdUserDefinedFunctions.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - FeedResponseListValidator validator = new FeedResponseListValidator - .Builder() + FeedResponseListValidator validator = new FeedResponseListValidator + .Builder() .totalSize(createdUserDefinedFunctions.size()) .exactlyContainsInAnyOrder(createdUserDefinedFunctions .stream() .map(d -> d.getResourceId()) .collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .allPagesSatisfy(new FeedResponseValidator.Builder() + .allPagesSatisfy(new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); validateQuerySuccess(feedObservable, validator, FEED_TIMEOUT); @@ -83,12 +83,11 @@ public void readUserDefinedFunctions() throws Exception { @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) public void beforeClass() { client = clientBuilder.build(); - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY; - truncateCollection(SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); for(int i = 0; i < 5; i++) { - createdUserDefinedFunctions.add(createUserDefinedFunctions(client)); + createdUserDefinedFunctions.add(createUserDefinedFunctions(createdCollection)); } waitIfNeededForReplicasToCatchUp(clientBuilder); @@ -99,11 +98,11 @@ public void afterClass() { safeClose(client); } - public UserDefinedFunction createUserDefinedFunctions(AsyncDocumentClient client) { - UserDefinedFunction udf = new UserDefinedFunction(); + public CosmosUserDefinedFunctionSettings createUserDefinedFunctions(CosmosContainer cosmosContainer) { + CosmosUserDefinedFunctionSettings udf = new CosmosUserDefinedFunctionSettings(); udf.setId(UUID.randomUUID().toString()); udf.setBody("function() {var x = 10;}"); - return client.createUserDefinedFunction(getCollectionLink(), udf, null).toBlocking().single().getResource(); + return cosmosContainer.createUserDefinedFunction(udf, new CosmosRequestOptions()).block().getCosmosUserDefinedFunctionSettings(); } private String getCollectionLink() { diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedUsersTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedUsersTest.java index 68186ec977d5c..f7e62b47932d7 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedUsersTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ReadFeedUsersTest.java @@ -27,32 +27,32 @@ import java.util.UUID; import java.util.stream.Collectors; -import com.microsoft.azure.cosmosdb.DatabaseForTest; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.DocumentClientException; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosDatabase; +import com.microsoft.azure.cosmos.CosmosUserSettings; +import com.microsoft.azure.cosmos.CosmosDatabaseForTest; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; -import com.microsoft.azure.cosmosdb.User; +import com.microsoft.azure.cosmosdb.RequestOptions; -import rx.Observable; - -import javax.net.ssl.SSLException; +import reactor.core.publisher.Flux; public class ReadFeedUsersTest extends TestSuiteBase { - public final String databaseId = DatabaseForTest.generateId(); - private Database createdDatabase; + public final String databaseId = CosmosDatabaseForTest.generateId(); + private CosmosDatabase createdDatabase; - private AsyncDocumentClient client; - private List createdUsers = new ArrayList<>(); + private CosmosClient client; + private List createdUsers = new ArrayList<>(); @Factory(dataProvider = "clientBuilders") - public ReadFeedUsersTest(AsyncDocumentClient.Builder clientBuilder) { + public ReadFeedUsersTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @@ -62,15 +62,15 @@ public void readUsers() throws Exception { FeedOptions options = new FeedOptions(); options.setMaxItemCount(2); - Observable> feedObservable = client.readUsers(getDatabaseLink(), options); + Flux> feedObservable = createdDatabase.listUsers(options); int expectedPageSize = (createdUsers.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .totalSize(createdUsers.size()) .exactlyContainsInAnyOrder(createdUsers.stream().map(d -> d.getResourceId()).collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .pageSatisfy(0, new FeedResponseValidator.Builder() + .pageSatisfy(0, new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); validateQuerySuccess(feedObservable, validator, FEED_TIMEOUT); @@ -79,12 +79,10 @@ public void readUsers() throws Exception { @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) public void beforeClass() { client = clientBuilder.build(); - Database d = new Database(); - d.setId(databaseId); - createdDatabase = createDatabase(client, d); + createdDatabase = createDatabase(client, databaseId); for(int i = 0; i < 5; i++) { - createdUsers.add(createUsers(client)); + createdUsers.add(createUsers(createdDatabase)); } waitIfNeededForReplicasToCatchUp(clientBuilder); @@ -92,17 +90,13 @@ public void beforeClass() { @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) public void afterClass() { - safeDeleteDatabase(client, createdDatabase.getId()); + safeDeleteDatabase(createdDatabase); safeClose(client); } - public User createUsers(AsyncDocumentClient client) { - User user = new User(); + public CosmosUserSettings createUsers(CosmosDatabase cosmosDatabase) { + CosmosUserSettings user = new CosmosUserSettings(); user.setId(UUID.randomUUID().toString()); - return client.createUser(getDatabaseLink(), user, null).toBlocking().single().getResource(); - } - - private String getDatabaseLink() { - return "dbs/" + createdDatabase.getId(); + return cosmosDatabase.createUser(user, new RequestOptions()).block().getCosmosUserSettings(); } } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ResourceTokenTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ResourceTokenTest.java index c5587f7b74820..83c94f829934e 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ResourceTokenTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/ResourceTokenTest.java @@ -47,6 +47,7 @@ import com.microsoft.azure.cosmosdb.RequestOptions; import com.microsoft.azure.cosmosdb.ResourceResponse; import com.microsoft.azure.cosmosdb.User; +import com.microsoft.azure.cosmosdb.rx.internal.TestSuiteBase; import rx.Observable; @@ -55,6 +56,8 @@ * resources from resource token directly or via permission feed . * */ + +// TODO: change to use external TestSuiteBase public class ResourceTokenTest extends TestSuiteBase { public final String databaseId = DatabaseForTest.generateId(); @@ -84,7 +87,8 @@ public class ResourceTokenTest extends TestSuiteBase { private final static String DOCUMENT_DEFINITION = "{ 'id': 'doc%d', 'counter': '%d'}"; private final static String DOCUMENT_DEFINITION_WITH_PERMISSION_KEY = "{ " + "\"id\": \"%s\", " + "\"mypk\": \"%s\", " + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" + "}"; - private final static String PARTITION_KEY_PATH = "/mypk"; + private final static String PARTITION_KEY_PATH_1 = "/mypk"; + private final static String PARTITION_KEY_PATH_2 = "/mypk2"; private static final String PARTITION_KEY_VALUE = "1"; private static final String PARTITION_KEY_VALUE_2 = "2"; @@ -110,11 +114,11 @@ public void beforeClass() throws Exception { d.setId(databaseId); createdDatabase = createDatabase(client, d); // Create collection - createdCollection = createCollection(client, createdDatabase.getId(), getCollectionDefinition()); + createdCollection = createCollection(client, createdDatabase.getId(), getCollectionDefinitionWithPartitionKey(PARTITION_KEY_PATH_2)); // Create document createdDocument = createDocument(client, createdDatabase.getId(),createdCollection.getId(), getDocument()); // Create collection with partition key - createdCollectionWithPartitionKey = createCollection(client, createdDatabase.getId(), getCollectionDefinitionWithPartitionKey()); + createdCollectionWithPartitionKey = createCollection(client, createdDatabase.getId(), getCollectionDefinitionWithPartitionKey(PARTITION_KEY_PATH_1)); // Create document with partition key createdDocumentWithPartitionKey = createDocument(client, createdDatabase.getId(), createdCollectionWithPartitionKey.getId(), getDocumentDefinitionWithPartitionKey()); @@ -281,10 +285,11 @@ public void readDocumentFromPermissionFeed(String documentUrl, Permission permis asyncClientResourceToken = new AsyncDocumentClient.Builder().withServiceEndpoint(TestConfigurations.HOST) .withPermissionFeed(permissionFeed).withConnectionPolicy(ConnectionPolicy.GetDefault()) .withConsistencyLevel(ConsistencyLevel.Session).build(); - RequestOptions options = null; - if(StringUtils.isNotEmpty(partitionKey)) { - options = new RequestOptions(); - options.setPartitionKey(new PartitionKey(partitionKey)); + RequestOptions options = new RequestOptions(); + if (StringUtils.isNotEmpty(partitionKey)) { + options.setPartitionKey(new PartitionKey((String)partitionKey)); + } else { + options.setPartitionKey(PartitionKey.None); } Observable> readObservable = asyncClientResourceToken .readDocument(documentUrl, options); @@ -309,8 +314,10 @@ public void readDocumentFromResouceToken(String resourceToken) throws Exception .withMasterKeyOrResourceToken(resourceToken) .withConnectionPolicy(ConnectionPolicy.GetDefault()).withConsistencyLevel(ConsistencyLevel.Session) .build(); + RequestOptions options = new RequestOptions(); + options.setPartitionKey(PartitionKey.None); Observable> readObservable = asyncClientResourceToken - .readDocument(createdDocument.getSelfLink(), null); + .readDocument(createdDocument.getSelfLink(), options); ResourceResponseValidator validator = new ResourceResponseValidator.Builder() .withId(createdDocument.getId()).build(); validateSuccess(readObservable, validator); @@ -515,12 +522,6 @@ private String getUserLink() { return createdUser.getSelfLink(); } - static protected DocumentCollection getCollectionDefinition() { - DocumentCollection collectionDefinition = new DocumentCollection(); - collectionDefinition.setId(UUID.randomUUID().toString()); - return collectionDefinition; - } - private Document getDocumentDefinitionWithPartitionKey() { String uuid = UUID.randomUUID().toString(); Document doc = new Document(String.format(DOCUMENT_DEFINITION_WITH_PERMISSION_KEY, uuid, PARTITION_KEY_VALUE)); @@ -532,10 +533,10 @@ private Document getDocumentDefinitionWithPartitionKey2() { return doc; } - private DocumentCollection getCollectionDefinitionWithPartitionKey() { + private DocumentCollection getCollectionDefinitionWithPartitionKey(String pkDefPath) { PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); ArrayList paths = new ArrayList(); - paths.add(PARTITION_KEY_PATH); + paths.add(pkDefPath); partitionKeyDef.setPaths(paths); DocumentCollection collectionDefinition = new DocumentCollection(); diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/SimpleSerializationTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/SimpleSerializationTest.java index 338f5b7004c70..18ae2b0e59784 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/SimpleSerializationTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/SimpleSerializationTest.java @@ -24,31 +24,29 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.JsonSerializer; import com.fasterxml.jackson.databind.SerializerProvider; import com.fasterxml.jackson.databind.annotation.JsonSerialize; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.Document; -import com.microsoft.azure.cosmosdb.DocumentCollection; -import com.microsoft.azure.cosmosdb.ResourceResponse; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosClientBuilder; +import com.microsoft.azure.cosmos.CosmosContainer; + import org.apache.commons.lang3.NotImplementedException; +import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import rx.Observable; -import java.io.IOException; -import java.time.Instant; import java.util.UUID; import static org.assertj.core.api.Assertions.assertThat; public class SimpleSerializationTest extends TestSuiteBase { - private DocumentCollection createdCollection; - private AsyncDocumentClient client; + private CosmosContainer createdCollection; + private CosmosClient client; private static class TestObject { public static class BadSerializer extends JsonSerializer { @@ -70,39 +68,35 @@ public void serialize(String value, JsonGenerator gen, SerializerProvider serial } @Factory(dataProvider = "clientBuildersWithDirect") - public SimpleSerializationTest(Builder clientBuilder) { + public SimpleSerializationTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @Test(groups = {"simple"}, timeOut = TIMEOUT) - public void createDocument() { + public void createDocument() throws InterruptedException { TestObject testObject = new TestObject(); testObject.id = UUID.randomUUID().toString(); testObject.mypk = UUID.randomUUID().toString(); testObject.prop = UUID.randomUUID().toString(); - Observable> createObservable = client - .createDocument(getCollectionLink(), testObject, null, false); - - FailureValidator failureValidator = FailureValidator.builder().instanceOf(IllegalArgumentException.class) - .causeOfCauseInstanceOf(NotImplementedException.class) - .errorMessageContains("Can't serialize the object into the json string").build(); - - validateFailure(createObservable, failureValidator); + try { + createdCollection.createItem(testObject); + Assert.fail(); + } catch (IllegalArgumentException e) { + assertThat(e.getMessage()).contains("Can't serialize the object into the json string"); + assertThat(e.getCause()).isInstanceOf(JsonMappingException.class); + assertThat(e.getCause().getMessage()).contains("bad"); + } } @BeforeClass(groups = {"simple"}, timeOut = SETUP_TIMEOUT) public void beforeClass() { - createdCollection = SHARED_MULTI_PARTITION_COLLECTION; client = clientBuilder.build(); + createdCollection = getSharedMultiPartitionCosmosContainer(client); } @AfterClass(groups = {"simple"}, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) public void afterClass() { safeClose(client); } - - private String getCollectionLink() { - return createdCollection.getSelfLink(); - } } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/SinglePartitionDocumentQueryTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/SinglePartitionDocumentQueryTest.java index fdca1855021f9..e2b5e4fa43d46 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/SinglePartitionDocumentQueryTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/SinglePartitionDocumentQueryTest.java @@ -25,49 +25,48 @@ import static org.assertj.core.api.Assertions.assertThat; import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; import java.util.List; import java.util.UUID; import java.util.stream.Collectors; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import com.microsoft.azure.cosmosdb.SqlParameter; import com.microsoft.azure.cosmosdb.SqlParameterCollection; import com.microsoft.azure.cosmosdb.SqlQuerySpec; import com.microsoft.azure.cosmosdb.internal.directconnectivity.Protocol; + +import io.reactivex.subscribers.TestSubscriber; +import reactor.core.publisher.Flux; + import org.testng.SkipException; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosItemRequestOptions; +import com.microsoft.azure.cosmos.CosmosItemSettings; import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.Document; import com.microsoft.azure.cosmosdb.DocumentClientException; -import com.microsoft.azure.cosmosdb.DocumentCollection; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; - -import rx.Observable; -import rx.observers.TestSubscriber; - public class SinglePartitionDocumentQueryTest extends TestSuiteBase { private Database createdDatabase; - private DocumentCollection createdCollection; - private List createdDocuments = new ArrayList<>(); + private CosmosContainer createdCollection; + private List createdDocuments = new ArrayList<>(); - private AsyncDocumentClient client; + private CosmosClient client; public String getCollectionLink() { return Utils.getCollectionNameLink(createdDatabase.getId(), createdCollection.getId()); } @Factory(dataProvider = "clientBuildersWithDirect") - public SinglePartitionDocumentQueryTest(Builder clientBuilder) { + public SinglePartitionDocumentQueryTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @@ -78,20 +77,20 @@ public void queryDocuments(boolean queryMetricsEnabled) throws Exception { FeedOptions options = new FeedOptions(); options.setMaxItemCount(5); + options.setEnableCrossPartitionQuery(true); options.setPopulateQueryMetrics(queryMetricsEnabled); - Observable> queryObservable = client - .queryDocuments(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryItems(query, options); - List expectedDocs = createdDocuments.stream().filter(d -> 99 == d.getInt("prop") ).collect(Collectors.toList()); + List expectedDocs = createdDocuments.stream().filter(d -> 99 == d.getInt("prop") ).collect(Collectors.toList()); assertThat(expectedDocs).isNotEmpty(); int expectedPageSize = (expectedDocs.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .totalSize(expectedDocs.size()) .exactlyContainsInAnyOrder(expectedDocs.stream().map(d -> d.getResourceId()).collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .pageSatisfy(0, new FeedResponseValidator.Builder() + .pageSatisfy(0, new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .hasValidQueryMetrics(queryMetricsEnabled) .build(); @@ -99,8 +98,8 @@ public void queryDocuments(boolean queryMetricsEnabled) throws Exception { try { validateQuerySuccess(queryObservable, validator, 10000); } catch (Throwable error) { - if (this.clientBuilder.configs.getProtocol() == Protocol.Tcp) { - String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.desiredConsistencyLevel); + if (this.clientBuilder.getConfigs().getProtocol() == Protocol.Tcp) { + String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.getDesiredConsistencyLevel()); logger.info(message, error); throw new SkipException(message, error); } @@ -116,27 +115,27 @@ public void queryDocuments_ParameterizedQueryWithInClause() throws Exception { FeedOptions options = new FeedOptions(); options.setMaxItemCount(5); - Observable> queryObservable = client - .queryDocuments(getCollectionLink(), sqs, options); + options.setEnableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.queryItems(sqs, options); - List expectedDocs = createdDocuments.stream().filter(d -> (3 == d.getInt("prop") || 4 == d.getInt("prop"))).collect(Collectors.toList()); + List expectedDocs = createdDocuments.stream().filter(d -> (3 == d.getInt("prop") || 4 == d.getInt("prop"))).collect(Collectors.toList()); assertThat(expectedDocs).isNotEmpty(); int expectedPageSize = (expectedDocs.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .totalSize(expectedDocs.size()) .exactlyContainsInAnyOrder(expectedDocs.stream().map(d -> d.getResourceId()).collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .pageSatisfy(0, new FeedResponseValidator.Builder() + .pageSatisfy(0, new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); try { validateQuerySuccess(queryObservable, validator, 10000); } catch (Throwable error) { - if (this.clientBuilder.configs.getProtocol() == Protocol.Tcp) { - String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.desiredConsistencyLevel); + if (this.clientBuilder.getConfigs().getProtocol() == Protocol.Tcp) { + String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.getDesiredConsistencyLevel()); logger.info(message, error); throw new SkipException(message, error); } @@ -152,27 +151,27 @@ public void queryDocuments_ParameterizedQuery() throws Exception { FeedOptions options = new FeedOptions(); options.setMaxItemCount(5); - Observable> queryObservable = client - .queryDocuments(getCollectionLink(), sqs, options); + options.setEnableCrossPartitionQuery(true); + Flux> queryObservable = createdCollection.queryItems(sqs, options); - List expectedDocs = createdDocuments.stream().filter(d -> 3 == d.getInt("prop")).collect(Collectors.toList()); + List expectedDocs = createdDocuments.stream().filter(d -> 3 == d.getInt("prop")).collect(Collectors.toList()); assertThat(expectedDocs).isNotEmpty(); int expectedPageSize = (expectedDocs.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .totalSize(expectedDocs.size()) .exactlyContainsInAnyOrder(expectedDocs.stream().map(d -> d.getResourceId()).collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .pageSatisfy(0, new FeedResponseValidator.Builder() + .pageSatisfy(0, new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); try { validateQuerySuccess(queryObservable, validator, 10000); } catch (Throwable error) { - if (this.clientBuilder.configs.getProtocol() == Protocol.Tcp) { - String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.desiredConsistencyLevel); + if (this.clientBuilder.getConfigs().getProtocol() == Protocol.Tcp) { + String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.getDesiredConsistencyLevel()); logger.info(message, error); throw new SkipException(message, error); } @@ -186,13 +185,12 @@ public void queryDocuments_NoResults() throws Exception { String query = "SELECT * from root r where r.id = '2'"; FeedOptions options = new FeedOptions(); options.setEnableCrossPartitionQuery(true); - Observable> queryObservable = client - .queryDocuments(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryItems(query, options); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .containsExactly(new ArrayList<>()) .numberOfPages(1) - .pageSatisfy(0, new FeedResponseValidator.Builder() + .pageSatisfy(0, new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); validateQuerySuccess(queryObservable, validator); @@ -205,28 +203,27 @@ public void queryDocumentsWithPageSize() throws Exception { FeedOptions options = new FeedOptions(); options.setMaxItemCount(3); options.setEnableCrossPartitionQuery(true); - Observable> queryObservable = client - .queryDocuments(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryItems(query, options); - List expectedDocs = createdDocuments; + List expectedDocs = createdDocuments; int expectedPageSize = (expectedDocs.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - FeedResponseListValidator validator = new FeedResponseListValidator - .Builder() + FeedResponseListValidator validator = new FeedResponseListValidator + .Builder() .exactlyContainsInAnyOrder(createdDocuments .stream() .map(d -> d.getResourceId()) .collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .allPagesSatisfy(new FeedResponseValidator.Builder() + .allPagesSatisfy(new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); try { validateQuerySuccess(queryObservable, validator); } catch (Throwable error) { - if (this.clientBuilder.configs.getProtocol() == Protocol.Tcp) { - String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.desiredConsistencyLevel); + if (this.clientBuilder.getConfigs().getProtocol() == Protocol.Tcp) { + String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.getDesiredConsistencyLevel()); logger.info(message, error); throw new SkipException(message, error); } @@ -241,26 +238,25 @@ public void queryOrderBy() throws Exception { FeedOptions options = new FeedOptions(); options.setEnableCrossPartitionQuery(true); options.setMaxItemCount(3); - Observable> queryObservable = client - .queryDocuments(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryItems(query, options); - List expectedDocs = createdDocuments; + List expectedDocs = createdDocuments; int expectedPageSize = (expectedDocs.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .containsExactly(createdDocuments.stream() .sorted((e1, e2) -> Integer.compare(e1.getInt("prop"), e2.getInt("prop"))) .map(d -> d.getResourceId()).collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .allPagesSatisfy(new FeedResponseValidator.Builder() + .allPagesSatisfy(new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); try { validateQuerySuccess(queryObservable, validator); } catch (Throwable error) { - if (this.clientBuilder.configs.getProtocol() == Protocol.Tcp) { - String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.desiredConsistencyLevel); + if (this.clientBuilder.getConfigs().getProtocol() == Protocol.Tcp) { + String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.getDesiredConsistencyLevel()); logger.info(message, error); throw new SkipException(message, error); } @@ -274,39 +270,35 @@ public void continuationToken() throws Exception { FeedOptions options = new FeedOptions(); options.setEnableCrossPartitionQuery(true); options.setMaxItemCount(3); - Observable> queryObservable = client - .queryDocuments(getCollectionLink(), query, options); - + Flux> queryObservable = createdCollection.queryItems(query, options); - TestSubscriber> subscriber = new TestSubscriber<>(); - queryObservable.first().subscribe(subscriber); + TestSubscriber> subscriber = new TestSubscriber<>(); + queryObservable.take(1).subscribe(subscriber); subscriber.awaitTerminalEvent(); - subscriber.assertCompleted(); + subscriber.assertComplete(); subscriber.assertNoErrors(); - assertThat(subscriber.getValueCount()).isEqualTo(1); - FeedResponse page = subscriber.getOnNextEvents().get(0); + assertThat(subscriber.valueCount()).isEqualTo(1); + FeedResponse page = ((FeedResponse) subscriber.getEvents().get(0).get(0)); assertThat(page.getResults()).hasSize(3); assertThat(page.getResponseContinuation()).isNotEmpty(); options.setRequestContinuation(page.getResponseContinuation()); - queryObservable = client - .queryDocuments(getCollectionLink(), query, options); - + queryObservable = createdCollection.queryItems(query, options); - List expectedDocs = createdDocuments.stream().filter(d -> (d.getInt("prop") > 2)).collect(Collectors.toList()); + List expectedDocs = createdDocuments.stream().filter(d -> (d.getInt("prop") > 2)).collect(Collectors.toList()); int expectedPageSize = (expectedDocs.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); assertThat(expectedDocs).hasSize(createdDocuments.size() -3); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .containsExactly(expectedDocs.stream() .sorted((e1, e2) -> Integer.compare(e1.getInt("prop"), e2.getInt("prop"))) .map(d -> d.getResourceId()).collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .allPagesSatisfy(new FeedResponseValidator.Builder() + .allPagesSatisfy(new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); validateQuerySuccess(queryObservable, validator); @@ -317,8 +309,7 @@ public void invalidQuerySytax() throws Exception { String query = "I am an invalid query"; FeedOptions options = new FeedOptions(); options.setEnableCrossPartitionQuery(true); - Observable> queryObservable = client - .queryDocuments(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryItems(query, options); FailureValidator validator = new FailureValidator.Builder() .instanceOf(DocumentClientException.class) @@ -328,24 +319,23 @@ public void invalidQuerySytax() throws Exception { validateQueryFailure(queryObservable, validator); } - public Document createDocument(AsyncDocumentClient client, int cnt) { - Document docDefinition = getDocumentDefinition(cnt); - return client.createDocument(getCollectionLink(), docDefinition, null, false).toBlocking().single().getResource(); + public CosmosItemSettings createDocument(CosmosContainer cosmosContainer, int cnt) { + CosmosItemSettings docDefinition = getDocumentDefinition(cnt); + return cosmosContainer.createItem(docDefinition, new CosmosItemRequestOptions()).block().getCosmosItemSettings(); } @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) public void beforeClass() throws Exception { client = clientBuilder.build(); - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY; - truncateCollection(SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY); + createdCollection = getSharedSinglePartitionCosmosContainer(client); + truncateCollection(createdCollection); for(int i = 0; i < 5; i++) { - createdDocuments.add(createDocument(client, i)); + createdDocuments.add(createDocument(createdCollection, i)); } for(int i = 0; i < 8; i++) { - createdDocuments.add(createDocument(client, 99)); + createdDocuments.add(createDocument(createdCollection, 99)); } waitIfNeededForReplicasToCatchUp(clientBuilder); @@ -356,9 +346,9 @@ public void afterClass() { safeClose(client); } - private static Document getDocumentDefinition(int cnt) { + private static CosmosItemSettings getDocumentDefinition(int cnt) { String uuid = UUID.randomUUID().toString(); - Document doc = new Document(String.format("{ " + CosmosItemSettings doc = new CosmosItemSettings(String.format("{ " + "\"id\": \"%s\", " + "\"prop\" : %d, " + "\"mypk\": \"%s\", " diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/SinglePartitionReadFeedDocumentsTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/SinglePartitionReadFeedDocumentsTest.java index 6ea1db1f0c3b1..df1d077dc382f 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/SinglePartitionReadFeedDocumentsTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/SinglePartitionReadFeedDocumentsTest.java @@ -22,16 +22,19 @@ */ package com.microsoft.azure.cosmosdb.rx; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.Document; -import com.microsoft.azure.cosmosdb.DocumentCollection; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosClientBuilder; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosItemSettings; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; + +import reactor.core.publisher.Flux; + import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import rx.Observable; import java.util.ArrayList; import java.util.List; @@ -39,29 +42,30 @@ import java.util.stream.Collectors; public class SinglePartitionReadFeedDocumentsTest extends TestSuiteBase { - private Database createdDatabase; - private DocumentCollection createdCollection; - private List createdDocuments; - private AsyncDocumentClient client; + private CosmosContainer createdCollection; + private List createdDocuments; + + private CosmosClient client; @Factory(dataProvider = "clientBuildersWithDirect") - public SinglePartitionReadFeedDocumentsTest(AsyncDocumentClient.Builder clientBuilder) { + public SinglePartitionReadFeedDocumentsTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @Test(groups = { "simple" }, timeOut = FEED_TIMEOUT) public void readDocuments() { final FeedOptions options = new FeedOptions(); + options.setEnableCrossPartitionQuery(true); options.setMaxItemCount(2); - final Observable> feedObservable = client.readDocuments(getCollectionLink(), options); + final Flux> feedObservable = createdCollection.listItems(options); final int expectedPageSize = (createdDocuments.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .totalSize(createdDocuments.size()) .numberOfPages(expectedPageSize) .exactlyContainsInAnyOrder(createdDocuments.stream().map(d -> d.getResourceId()).collect(Collectors.toList())) - .allPagesSatisfy(new FeedResponseValidator.Builder() + .allPagesSatisfy(new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); validateQuerySuccess(feedObservable, validator, FEED_TIMEOUT); @@ -70,17 +74,16 @@ public void readDocuments() { @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) public void beforeClass() { client = clientBuilder.build(); - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY; - truncateCollection(SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY); + createdCollection = getSharedSinglePartitionCosmosContainer(client); + truncateCollection(createdCollection); - List docDefList = new ArrayList<>(); + List docDefList = new ArrayList<>(); for(int i = 0; i < 5; i++) { docDefList.add(getDocumentDefinition()); } - createdDocuments = bulkInsertBlocking(client, getCollectionLink(), docDefList); + createdDocuments = bulkInsertBlocking(createdCollection, docDefList); waitIfNeededForReplicasToCatchUp(clientBuilder); } @@ -89,9 +92,9 @@ public void afterClass() { safeClose(client); } - private Document getDocumentDefinition() { + private CosmosItemSettings getDocumentDefinition() { String uuid = UUID.randomUUID().toString(); - Document doc = new Document(String.format("{ " + CosmosItemSettings doc = new CosmosItemSettings(String.format("{ " + "\"id\": \"%s\", " + "\"mypk\": \"%s\", " + "\"sgmts\": [[6519456, 1471916863], [2498434, 1455671440]]" @@ -99,16 +102,4 @@ private Document getDocumentDefinition() { , uuid, uuid)); return doc; } - - public String getCollectionLink() { - return "dbs/" + getDatabaseId() + "/colls/" + getCollectionId(); - } - - private String getCollectionId() { - return createdCollection.getId(); - } - - private String getDatabaseId() { - return createdDatabase.getId(); - } } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/StoredProcedureCrudTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/StoredProcedureCrudTest.java index e963d5322d5a9..df2b779d0a066 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/StoredProcedureCrudTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/StoredProcedureCrudTest.java @@ -24,28 +24,31 @@ import java.util.UUID; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.DocumentCollection; -import com.microsoft.azure.cosmosdb.ResourceResponse; -import com.microsoft.azure.cosmosdb.StoredProcedure; - -import rx.Observable; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosResponse; +import com.microsoft.azure.cosmos.CosmosResponseValidator; +import com.microsoft.azure.cosmos.CosmosStoredProcedure; +import com.microsoft.azure.cosmos.CosmosStoredProcedureRequestOptions; +import com.microsoft.azure.cosmos.CosmosStoredProcedureResponse; +import com.microsoft.azure.cosmos.CosmosStoredProcedureSettings; +import reactor.core.publisher.Mono; public class StoredProcedureCrudTest extends TestSuiteBase { - private Database createdDatabase; - private DocumentCollection createdCollection; + private CosmosContainer createdCollection; - private AsyncDocumentClient client; + private CosmosClient client; @Factory(dataProvider = "clientBuildersWithDirect") - public StoredProcedureCrudTest(AsyncDocumentClient.Builder clientBuilder) { + public StoredProcedureCrudTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @@ -53,14 +56,14 @@ public StoredProcedureCrudTest(AsyncDocumentClient.Builder clientBuilder) { public void createStoredProcedure() throws Exception { // create a stored procedure - StoredProcedure storedProcedureDef = new StoredProcedure(); + CosmosStoredProcedureSettings storedProcedureDef = new CosmosStoredProcedureSettings(); storedProcedureDef.setId(UUID.randomUUID().toString()); storedProcedureDef.setBody("function() {var x = 10;}"); - Observable> createObservable = client.createStoredProcedure(getCollectionLink(), storedProcedureDef, null); + Mono createObservable = createdCollection.createStoredProcedure(storedProcedureDef, new CosmosStoredProcedureRequestOptions()); // validate stored procedure creation - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .withId(storedProcedureDef.getId()) .withStoredProcedureBody("function() {var x = 10;}") .notNullEtag() @@ -71,16 +74,17 @@ public void createStoredProcedure() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void readStoredProcedure() throws Exception { // create a stored procedure - StoredProcedure storedProcedureDef = new StoredProcedure(); + CosmosStoredProcedureSettings storedProcedureDef = new CosmosStoredProcedureSettings(); storedProcedureDef.setId(UUID.randomUUID().toString()); storedProcedureDef.setBody("function() {var x = 10;}"); - StoredProcedure storedProcedure = client.createStoredProcedure(getCollectionLink(), storedProcedureDef, null).toBlocking().single().getResource(); + CosmosStoredProcedure storedProcedure = createdCollection.createStoredProcedure(storedProcedureDef, new CosmosStoredProcedureRequestOptions()) + .block().getStoredProcedure(); // read stored procedure waitIfNeededForReplicasToCatchUp(clientBuilder); - Observable> readObservable = client.readStoredProcedure(storedProcedure.getSelfLink(), null); + Mono readObservable = storedProcedure.read(null); - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .withId(storedProcedureDef.getId()) .withStoredProcedureBody("function() {var x = 10;}") .notNullEtag() @@ -91,16 +95,17 @@ public void readStoredProcedure() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void deleteStoredProcedure() throws Exception { // create a stored procedure - StoredProcedure storedProcedureDef = new StoredProcedure(); + CosmosStoredProcedureSettings storedProcedureDef = new CosmosStoredProcedureSettings(); storedProcedureDef.setId(UUID.randomUUID().toString()); storedProcedureDef.setBody("function() {var x = 10;}"); - StoredProcedure storedProcedure = client.createStoredProcedure(getCollectionLink(), storedProcedureDef, null).toBlocking().single().getResource(); + CosmosStoredProcedure storedProcedure = createdCollection.createStoredProcedure(storedProcedureDef, new CosmosStoredProcedureRequestOptions()) + .block().getStoredProcedure(); // delete - Observable> deleteObservable = client.deleteStoredProcedure(storedProcedure.getSelfLink(), null); + Mono deleteObservable = storedProcedure.delete(new CosmosStoredProcedureRequestOptions()); // validate - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .nullResource() .build(); validateSuccess(deleteObservable, validator); @@ -108,7 +113,7 @@ public void deleteStoredProcedure() throws Exception { // attempt to read stored procedure which was deleted waitIfNeededForReplicasToCatchUp(clientBuilder); - Observable> readObservable = client.readStoredProcedure(storedProcedure.getSelfLink(), null); + Mono readObservable = storedProcedure.read(null); FailureValidator notFoundValidator = new FailureValidator.Builder().resourceNotFound().build(); validateFailure(readObservable, notFoundValidator); } @@ -116,16 +121,11 @@ public void deleteStoredProcedure() throws Exception { @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) public void beforeClass() { client = clientBuilder.build(); - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_SINGLE_PARTITION_COLLECTION; + createdCollection = getSharedMultiPartitionCosmosContainer(client); } @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) public void afterClass() { safeClose(client); } - - private String getCollectionLink() { - return createdCollection.getSelfLink(); - } } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/StoredProcedureQueryTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/StoredProcedureQueryTest.java index c10eb81aaf6e8..acdbdb61ebedc 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/StoredProcedureQueryTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/StoredProcedureQueryTest.java @@ -29,39 +29,33 @@ import java.util.UUID; import java.util.stream.Collectors; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import com.microsoft.azure.cosmosdb.internal.directconnectivity.Protocol; + +import reactor.core.publisher.Flux; + import org.testng.SkipException; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.Database; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosStoredProcedureSettings; import com.microsoft.azure.cosmosdb.DocumentClientException; -import com.microsoft.azure.cosmosdb.DocumentCollection; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; -import com.microsoft.azure.cosmosdb.StoredProcedure; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; - -import rx.Observable; - public class StoredProcedureQueryTest extends TestSuiteBase { - private Database createdDatabase; - private DocumentCollection createdCollection; - private List createdStoredProcs = new ArrayList<>(); - - private AsyncDocumentClient client; + private CosmosContainer createdCollection; + private List createdStoredProcs = new ArrayList<>(); - public String getCollectionLink() { - return Utils.getCollectionNameLink(createdDatabase.getId(), createdCollection.getId()); - } + private CosmosClient client; @Factory(dataProvider = "clientBuildersWithDirect") - public StoredProcedureQueryTest(Builder clientBuilder) { + public StoredProcedureQueryTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @@ -73,27 +67,26 @@ public void queryWithFilter() throws Exception { FeedOptions options = new FeedOptions(); options.setMaxItemCount(5); - Observable> queryObservable = client - .queryStoredProcedures(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryStoredProcedures(query, options); - List expectedDocs = createdStoredProcs.stream().filter(sp -> filterId.equals(sp.getId()) ).collect(Collectors.toList()); + List expectedDocs = createdStoredProcs.stream().filter(sp -> filterId.equals(sp.getId()) ).collect(Collectors.toList()); assertThat(expectedDocs).isNotEmpty(); int expectedPageSize = (expectedDocs.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .totalSize(expectedDocs.size()) .exactlyContainsInAnyOrder(expectedDocs.stream().map(d -> d.getResourceId()).collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .pageSatisfy(0, new FeedResponseValidator.Builder() + .pageSatisfy(0, new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); try { validateQuerySuccess(queryObservable, validator, 10000); } catch (Throwable error) { - if (this.clientBuilder.configs.getProtocol() == Protocol.Tcp) { - String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.desiredConsistencyLevel); + if (this.clientBuilder.getConfigs().getProtocol() == Protocol.Tcp) { + String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.getDesiredConsistencyLevel()); logger.info(message, error); throw new SkipException(message, error); } @@ -107,13 +100,12 @@ public void query_NoResults() throws Exception { String query = "SELECT * from root r where r.id = '2'"; FeedOptions options = new FeedOptions(); options.setEnableCrossPartitionQuery(true); - Observable> queryObservable = client - .queryStoredProcedures(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryStoredProcedures(query, options); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .containsExactly(new ArrayList<>()) .numberOfPages(1) - .pageSatisfy(0, new FeedResponseValidator.Builder() + .pageSatisfy(0, new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); validateQuerySuccess(queryObservable, validator); @@ -126,29 +118,28 @@ public void queryAll() throws Exception { FeedOptions options = new FeedOptions(); options.setMaxItemCount(3); options.setEnableCrossPartitionQuery(true); - Observable> queryObservable = client - .queryStoredProcedures(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryStoredProcedures(query, options); - List expectedDocs = createdStoredProcs; + List expectedDocs = createdStoredProcs; int expectedPageSize = (expectedDocs.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - FeedResponseListValidator validator = new FeedResponseListValidator - .Builder() + FeedResponseListValidator validator = new FeedResponseListValidator + .Builder() .exactlyContainsInAnyOrder(expectedDocs .stream() .map(d -> d.getResourceId()) .collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .allPagesSatisfy(new FeedResponseValidator.Builder() + .allPagesSatisfy(new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); try { validateQuerySuccess(queryObservable, validator); } catch (Throwable error) { - if (this.clientBuilder.configs.getProtocol() == Protocol.Tcp) { - String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.desiredConsistencyLevel); + if (this.clientBuilder.getConfigs().getProtocol() == Protocol.Tcp) { + String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.getDesiredConsistencyLevel()); logger.info(message, error); throw new SkipException(message, error); } @@ -161,8 +152,7 @@ public void invalidQuerySytax() throws Exception { String query = "I am an invalid query"; FeedOptions options = new FeedOptions(); options.setEnableCrossPartitionQuery(true); - Observable> queryObservable = client - .queryStoredProcedures(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryStoredProcedures(query, options); FailureValidator validator = new FailureValidator.Builder() .instanceOf(DocumentClientException.class) @@ -172,20 +162,19 @@ public void invalidQuerySytax() throws Exception { validateQueryFailure(queryObservable, validator); } - public StoredProcedure createStoredProc(AsyncDocumentClient client) { - StoredProcedure storedProcedure = getStoredProcedureDef(); - return client.createStoredProcedure(getCollectionLink(), storedProcedure, null).toBlocking().single().getResource(); + public CosmosStoredProcedureSettings createStoredProc(CosmosContainer cosmosContainer) { + CosmosStoredProcedureSettings storedProcedure = getStoredProcedureDef(); + return cosmosContainer.createStoredProcedure(storedProcedure).block().getStoredProcedureSettings(); } @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) public void beforeClass() throws Exception { client = clientBuilder.build(); - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY; - truncateCollection(SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); for(int i = 0; i < 5; i++) { - createdStoredProcs.add(createStoredProc(client)); + createdStoredProcs.add(createStoredProc(createdCollection)); } waitIfNeededForReplicasToCatchUp(clientBuilder); @@ -196,8 +185,8 @@ public void afterClass() { safeClose(client); } - private static StoredProcedure getStoredProcedureDef() { - StoredProcedure storedProcedureDef = new StoredProcedure(); + private static CosmosStoredProcedureSettings getStoredProcedureDef() { + CosmosStoredProcedureSettings storedProcedureDef = new CosmosStoredProcedureSettings(); storedProcedureDef.setId(UUID.randomUUID().toString()); storedProcedureDef.setBody("function() {var x = 10;}"); return storedProcedureDef; diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/StoredProcedureUpsertReplaceTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/StoredProcedureUpsertReplaceTest.java index 62870762d1b34..00fc53360ed12 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/StoredProcedureUpsertReplaceTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/StoredProcedureUpsertReplaceTest.java @@ -26,86 +26,53 @@ import java.util.UUID; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import com.microsoft.azure.cosmosdb.internal.directconnectivity.Protocol; + +import reactor.core.publisher.Mono; + import org.testng.SkipException; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.DocumentCollection; -import com.microsoft.azure.cosmosdb.ResourceResponse; -import com.microsoft.azure.cosmosdb.StoredProcedure; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; - -import rx.Observable; - -import javax.net.ssl.SSLException; - +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosResponseValidator; +import com.microsoft.azure.cosmos.CosmosStoredProcedure; +import com.microsoft.azure.cosmos.CosmosStoredProcedureRequestOptions; +import com.microsoft.azure.cosmos.CosmosStoredProcedureResponse; +import com.microsoft.azure.cosmos.CosmosStoredProcedureSettings; +import com.microsoft.azure.cosmosdb.PartitionKey; +import com.microsoft.azure.cosmosdb.RequestOptions; public class StoredProcedureUpsertReplaceTest extends TestSuiteBase { - private Database createdDatabase; - private DocumentCollection createdCollection; + private CosmosContainer createdCollection; - private AsyncDocumentClient client; + private CosmosClient client; @Factory(dataProvider = "clientBuildersWithDirect") - public StoredProcedureUpsertReplaceTest(AsyncDocumentClient.Builder clientBuilder) { + public StoredProcedureUpsertReplaceTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } - @Test(groups = { "simple" }, timeOut = TIMEOUT) - public void upsertStoredProcedure() throws Exception { - - // create a stored procedure - StoredProcedure storedProcedureDef = new StoredProcedure(); - storedProcedureDef.setId(UUID.randomUUID().toString()); - storedProcedureDef.setBody("function() {var x = 10;}"); - StoredProcedure readBackSp = client.upsertStoredProcedure(getCollectionLink(), storedProcedureDef, null).toBlocking().single().getResource(); - - //read back stored procedure - waitIfNeededForReplicasToCatchUp(clientBuilder); - Observable> readObservable = client.readStoredProcedure(readBackSp.getSelfLink(), null); - - // validate stored procedure creation - ResourceResponseValidator validatorForRead = new ResourceResponseValidator.Builder() - .withId(readBackSp.getId()) - .withStoredProcedureBody("function() {var x = 10;}") - .notNullEtag() - .build(); - validateSuccess(readObservable, validatorForRead); - - //update stored procedure - readBackSp.setBody("function() {var x = 11;}"); - - Observable> updateObservable = client.upsertStoredProcedure(getCollectionLink(), readBackSp, null); - - // validate stored procedure update - ResourceResponseValidator validatorForUpdate = new ResourceResponseValidator.Builder() - .withId(readBackSp.getId()) - .withStoredProcedureBody("function() {var x = 11;}") - .notNullEtag() - .build(); - validateSuccess(updateObservable, validatorForUpdate); - } - @Test(groups = { "simple" }, timeOut = TIMEOUT) public void replaceStoredProcedure() throws Exception { // create a stored procedure - StoredProcedure storedProcedureDef = new StoredProcedure(); + CosmosStoredProcedureSettings storedProcedureDef = new CosmosStoredProcedureSettings(); storedProcedureDef.setId(UUID.randomUUID().toString()); - storedProcedureDef.setBody("function() {var x = 10;}"); - StoredProcedure readBackSp = client.createStoredProcedure(getCollectionLink(), storedProcedureDef, null).toBlocking().single().getResource(); + storedProcedureDef.setBody("function() {var x = 10;}"); + CosmosStoredProcedureSettings readBackSp = createdCollection.createStoredProcedure(storedProcedureDef, new CosmosStoredProcedureRequestOptions()).block().getStoredProcedureSettings(); // read stored procedure to validate creation waitIfNeededForReplicasToCatchUp(clientBuilder); - Observable> readObservable = client.readStoredProcedure(readBackSp.getSelfLink(), null); + Mono readObservable = createdCollection.getStoredProcedure(readBackSp.getId()).read(null); // validate stored procedure creation - ResourceResponseValidator validatorForRead = new ResourceResponseValidator.Builder() + CosmosResponseValidator validatorForRead = new CosmosResponseValidator.Builder() .withId(readBackSp.getId()) .withStoredProcedureBody("function() {var x = 10;}") .notNullEtag() @@ -115,10 +82,10 @@ public void replaceStoredProcedure() throws Exception { //update stored procedure readBackSp.setBody("function() {var x = 11;}"); - Observable> replaceObservable = client.replaceStoredProcedure(readBackSp, null); + Mono replaceObservable = createdCollection.getStoredProcedure(readBackSp.getId()).replace(readBackSp, new RequestOptions()); //validate stored procedure replace - ResourceResponseValidator validatorForReplace = new ResourceResponseValidator.Builder() + CosmosResponseValidator validatorForReplace = new CosmosResponseValidator.Builder() .withId(readBackSp.getId()) .withStoredProcedureBody("function() {var x = 11;}") .notNullEtag() @@ -129,7 +96,7 @@ public void replaceStoredProcedure() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void executeStoredProcedure() throws Exception { // create a stored procedure - StoredProcedure storedProcedureDef = new StoredProcedure( + CosmosStoredProcedureSettings storedProcedureDef = new CosmosStoredProcedureSettings( "{" + " 'id': '" +UUID.randomUUID().toString() + "'," + " 'body':" + @@ -140,13 +107,13 @@ public void executeStoredProcedure() throws Exception { " }'" + "}"); - StoredProcedure storedProcedure = null; + CosmosStoredProcedure storedProcedure = null; try { - storedProcedure = client.createStoredProcedure(getCollectionLink(), storedProcedureDef, null).toBlocking().single().getResource(); + storedProcedure = createdCollection.createStoredProcedure(storedProcedureDef, new CosmosStoredProcedureRequestOptions()).block().getStoredProcedure(); } catch (Throwable error) { - if (this.clientBuilder.configs.getProtocol() == Protocol.Tcp) { - String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.desiredConsistencyLevel); + if (this.clientBuilder.getConfigs().getProtocol() == Protocol.Tcp) { + String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.getDesiredConsistencyLevel()); logger.info(message, error); throw new SkipException(message, error); } @@ -156,10 +123,12 @@ public void executeStoredProcedure() throws Exception { String result = null; try { - result = client.executeStoredProcedure(storedProcedure.getSelfLink(), null).toBlocking().single().getResponseAsString(); + RequestOptions options = new RequestOptions(); + options.setPartitionKey(PartitionKey.None); + result = storedProcedure.execute(null, options).block().getResponseAsString(); } catch (Throwable error) { - if (this.clientBuilder.configs.getProtocol() == Protocol.Tcp) { - String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.desiredConsistencyLevel); + if (this.clientBuilder.getConfigs().getProtocol() == Protocol.Tcp) { + String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.getDesiredConsistencyLevel()); logger.info(message, error); throw new SkipException(message, error); } @@ -172,17 +141,11 @@ public void executeStoredProcedure() throws Exception { @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) public void beforeClass() { client = clientBuilder.build(); - - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY; + createdCollection = getSharedMultiPartitionCosmosContainer(client); } @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) public void afterClass() { safeClose(client); } - - private String getCollectionLink() { - return createdCollection.getSelfLink(); - } } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TestSuiteBase.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TestSuiteBase.java index 546061b827855..ceb94dabf8877 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TestSuiteBase.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TestSuiteBase.java @@ -41,18 +41,23 @@ import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.ImmutableList; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import com.microsoft.azure.cosmosdb.DataType; -import com.microsoft.azure.cosmosdb.DatabaseForTest; import com.microsoft.azure.cosmosdb.DocumentClientException; import com.microsoft.azure.cosmosdb.IncludedPath; import com.microsoft.azure.cosmosdb.Index; import com.microsoft.azure.cosmosdb.IndexingPolicy; import com.microsoft.azure.cosmosdb.RetryOptions; import com.microsoft.azure.cosmosdb.SqlQuerySpec; -import com.microsoft.azure.cosmosdb.Undefined; import com.microsoft.azure.cosmosdb.internal.PathParser; import com.microsoft.azure.cosmosdb.internal.directconnectivity.Protocol; import com.microsoft.azure.cosmosdb.rx.internal.Configs; + +import io.reactivex.subscribers.TestSubscriber; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import rx.Observable; + import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.mockito.stubbing.Answer; @@ -64,27 +69,35 @@ import org.testng.annotations.BeforeSuite; import org.testng.annotations.DataProvider; +import com.microsoft.azure.cosmos.CosmosBridgeInternal; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosContainerRequestOptions; +import com.microsoft.azure.cosmos.CosmosContainerSettings; +import com.microsoft.azure.cosmos.CosmosDatabase; +import com.microsoft.azure.cosmos.CosmosDatabaseResponse; +import com.microsoft.azure.cosmos.CosmosDatabaseSettings; +import com.microsoft.azure.cosmos.CosmosItem; +import com.microsoft.azure.cosmos.CosmosItemSettings; +import com.microsoft.azure.cosmos.CosmosRequestOptions; +import com.microsoft.azure.cosmos.CosmosResponse; +import com.microsoft.azure.cosmos.CosmosResponseValidator; +import com.microsoft.azure.cosmos.CosmosUser; +import com.microsoft.azure.cosmos.CosmosUserSettings; +import com.microsoft.azure.cosmos.CosmosDatabaseForTest; import com.microsoft.azure.cosmosdb.CompositePath; import com.microsoft.azure.cosmosdb.CompositePathSortOrder; import com.microsoft.azure.cosmosdb.ConnectionMode; import com.microsoft.azure.cosmosdb.ConnectionPolicy; import com.microsoft.azure.cosmosdb.ConsistencyLevel; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.Document; -import com.microsoft.azure.cosmosdb.DocumentCollection; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; import com.microsoft.azure.cosmosdb.PartitionKey; import com.microsoft.azure.cosmosdb.PartitionKeyDefinition; -import com.microsoft.azure.cosmosdb.RequestOptions; import com.microsoft.azure.cosmosdb.Resource; import com.microsoft.azure.cosmosdb.ResourceResponse; -import com.microsoft.azure.cosmosdb.User; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; import org.testng.annotations.Test; -import rx.Observable; -import rx.observers.TestSubscriber; public class TestSuiteBase { private static final int DEFAULT_BULK_INSERT_CONCURRENCY_LEVEL = 500; @@ -106,13 +119,28 @@ public class TestSuiteBase { private static final ImmutableList protocols; protected int subscriberValidationTimeout = TIMEOUT; - protected Builder clientBuilder; + protected CosmosClientBuilder clientBuilder; - protected static Database SHARED_DATABASE; - protected static DocumentCollection SHARED_MULTI_PARTITION_COLLECTION; - protected static DocumentCollection SHARED_SINGLE_PARTITION_COLLECTION; - protected static DocumentCollection SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY; - protected static DocumentCollection SHARED_MULTI_PARTITION_COLLECTION_WITH_COMPOSITE_AND_SPATIAL_INDEXES; + private static CosmosDatabase SHARED_DATABASE; + private static CosmosContainer SHARED_MULTI_PARTITION_COLLECTION; + private static CosmosContainer SHARED_MULTI_PARTITION_COLLECTION_WITH_COMPOSITE_AND_SPATIAL_INDEXES; + private static CosmosContainer SHARED_SINGLE_PARTITION_COLLECTION; + + protected static CosmosDatabase getSharedCosmosDatabase(CosmosClient client) { + return CosmosBridgeInternal.getCosmosDatabaseWithNewClient(SHARED_DATABASE, client); + } + + protected static CosmosContainer getSharedMultiPartitionCosmosContainer(CosmosClient client) { + return CosmosBridgeInternal.getCosmosContainerWithNewClient(SHARED_MULTI_PARTITION_COLLECTION, SHARED_DATABASE, client); + } + + protected static CosmosContainer getSharedMultiPartitionCosmosContainerWithCompositeAndSpatialIndexes(CosmosClient client) { + return CosmosBridgeInternal.getCosmosContainerWithNewClient(SHARED_MULTI_PARTITION_COLLECTION_WITH_COMPOSITE_AND_SPATIAL_INDEXES, SHARED_DATABASE, client); + } + + protected static CosmosContainer getSharedSinglePartitionCosmosContainer(CosmosClient client) { + return CosmosBridgeInternal.getCosmosContainerWithNewClient(SHARED_SINGLE_PARTITION_COLLECTION, SHARED_DATABASE, client); + } static { accountConsistency = parseConsistency(TestConfigurations.CONSISTENCY); @@ -141,9 +169,9 @@ public void beforeMethod(Method method) { if (this.clientBuilder != null) { logger.info("Starting {}::{} using {} {} mode with {} consistency", method.getDeclaringClass().getSimpleName(), method.getName(), - this.clientBuilder.connectionPolicy.getConnectionMode(), - this.clientBuilder.configs.getProtocol(), - this.clientBuilder.desiredConsistencyLevel); + this.clientBuilder.getConnectionPolicy().getConnectionMode(), + this.clientBuilder.getConfigs().getProtocol(), + this.clientBuilder.getDesiredConsistencyLevel()); return; } logger.info("Starting {}::{}", method.getDeclaringClass().getSimpleName(), method.getName()); @@ -155,149 +183,142 @@ public void afterMethod(Method m) { logger.info("Finished {}:{}.", m.getDeclaringClass().getSimpleName(), m.getName()); } - private static class DatabaseManagerImpl implements DatabaseForTest.DatabaseManager { - public static DatabaseManagerImpl getInstance(AsyncDocumentClient client) { + private static class DatabaseManagerImpl implements CosmosDatabaseForTest.DatabaseManager { + public static DatabaseManagerImpl getInstance(CosmosClient client) { return new DatabaseManagerImpl(client); } - private final AsyncDocumentClient client; + private final CosmosClient client; - private DatabaseManagerImpl(AsyncDocumentClient client) { + private DatabaseManagerImpl(CosmosClient client) { this.client = client; } @Override - public Observable> queryDatabases(SqlQuerySpec query) { + public Flux> queryDatabases(SqlQuerySpec query) { return client.queryDatabases(query, null); } @Override - public Observable> createDatabase(Database databaseDefinition) { - return client.createDatabase(databaseDefinition, null); + public Mono createDatabase(CosmosDatabaseSettings databaseDefinition) { + return client.createDatabase(databaseDefinition); } @Override - public Observable> deleteDatabase(String id) { - - return client.deleteDatabase("dbs/" + id, null); + public CosmosDatabase getDatabase(String id) { + return client.getDatabase(id); } } @BeforeSuite(groups = {"simple", "long", "direct", "multi-master", "emulator", "non-emulator"}, timeOut = SUITE_SETUP_TIMEOUT) public static void beforeSuite() { logger.info("beforeSuite Started"); - AsyncDocumentClient houseKeepingClient = createGatewayHouseKeepingDocumentClient().build(); - try { - DatabaseForTest dbForTest = DatabaseForTest.create(DatabaseManagerImpl.getInstance(houseKeepingClient)); - SHARED_DATABASE = dbForTest.createdDatabase; - RequestOptions options = new RequestOptions(); - options.setOfferThroughput(10100); - SHARED_MULTI_PARTITION_COLLECTION = createCollection(houseKeepingClient, SHARED_DATABASE.getId(), getCollectionDefinitionWithRangeRangeIndex(), options); - SHARED_SINGLE_PARTITION_COLLECTION = createCollection(houseKeepingClient, SHARED_DATABASE.getId(), getCollectionDefinition(), null); - SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY = createCollection(houseKeepingClient, SHARED_DATABASE.getId(), getCollectionDefinitionSinglePartitionWithoutPartitionKey()); - SHARED_MULTI_PARTITION_COLLECTION_WITH_COMPOSITE_AND_SPATIAL_INDEXES = createCollection(houseKeepingClient, SHARED_DATABASE.getId(), getCollectionDefinitionMultiPartitionWithCompositeAndSpatialIndexes(), options); - } finally { - houseKeepingClient.close(); - } + CosmosClient houseKeepingClient = createGatewayHouseKeepingDocumentClient().build(); + CosmosDatabaseForTest dbForTest = CosmosDatabaseForTest.create(DatabaseManagerImpl.getInstance(houseKeepingClient)); + SHARED_DATABASE = dbForTest.createdDatabase; + CosmosContainerRequestOptions options = new CosmosContainerRequestOptions(); + options.offerThroughput(10100); + SHARED_MULTI_PARTITION_COLLECTION = createCollection(SHARED_DATABASE, getCollectionDefinitionWithRangeRangeIndex(), options); + SHARED_MULTI_PARTITION_COLLECTION_WITH_COMPOSITE_AND_SPATIAL_INDEXES = createCollection(SHARED_DATABASE, getCollectionDefinitionMultiPartitionWithCompositeAndSpatialIndexes(), options); + options.offerThroughput(6000); + SHARED_SINGLE_PARTITION_COLLECTION = createCollection(SHARED_DATABASE, getCollectionDefinitionWithRangeRangeIndex(), options); } @AfterSuite(groups = {"simple", "long", "direct", "multi-master", "emulator", "non-emulator"}, timeOut = SUITE_SHUTDOWN_TIMEOUT) public static void afterSuite() { logger.info("afterSuite Started"); - AsyncDocumentClient houseKeepingClient = createGatewayHouseKeepingDocumentClient().build(); + CosmosClient houseKeepingClient = createGatewayHouseKeepingDocumentClient().build(); try { - safeDeleteDatabase(houseKeepingClient, SHARED_DATABASE); - DatabaseForTest.cleanupStaleTestDatabases(DatabaseManagerImpl.getInstance(houseKeepingClient)); + safeDeleteDatabase(SHARED_DATABASE); + CosmosDatabaseForTest.cleanupStaleTestDatabases(DatabaseManagerImpl.getInstance(houseKeepingClient)); } finally { safeClose(houseKeepingClient); } } - protected static void truncateCollection(DocumentCollection collection) { - logger.info("Truncating collection {} ...", collection.getId()); - AsyncDocumentClient houseKeepingClient = createGatewayHouseKeepingDocumentClient().build(); + protected static void truncateCollection(CosmosContainer cosmosContainer) { + CosmosContainerSettings cosmosContainerSettings = cosmosContainer.read().block().getCosmosContainerSettings(); + String cosmosContainerId = cosmosContainerSettings.getId(); + logger.info("Truncating collection {} ...", cosmosContainerId); + CosmosClient houseKeepingClient = createGatewayHouseKeepingDocumentClient().build(); try { - List paths = collection.getPartitionKey().getPaths(); - + List paths = cosmosContainerSettings.getPartitionKey().getPaths(); FeedOptions options = new FeedOptions(); options.setMaxDegreeOfParallelism(-1); options.setEnableCrossPartitionQuery(true); options.setMaxItemCount(100); - logger.info("Truncating collection {} documents ...", collection.getId()); + logger.info("Truncating collection {} documents ...", cosmosContainer.getId()); - houseKeepingClient.queryDocuments(collection.getSelfLink(), "SELECT * FROM root", options) - .flatMap(page -> Observable.from(page.getResults())) + cosmosContainer.queryItems("SELECT * FROM root", options) + .flatMap(page -> Flux.fromIterable(page.getResults())) .flatMap(doc -> { - RequestOptions requestOptions = new RequestOptions(); - + + Object propertyValue = null; if (paths != null && !paths.isEmpty()) { List pkPath = PathParser.getPathParts(paths.get(0)); - Object propertyValue = doc.getObjectByPath(pkPath); + propertyValue = doc.getObjectByPath(pkPath); if (propertyValue == null) { - propertyValue = Undefined.Value(); + propertyValue = PartitionKey.None; } - requestOptions.setPartitionKey(new PartitionKey(propertyValue)); } + return cosmosContainer.getItem(doc.getId(), propertyValue).delete(); + }).collectList().block(); + logger.info("Truncating collection {} triggers ...", cosmosContainerId); - return houseKeepingClient.deleteDocument(doc.getSelfLink(), requestOptions); - }).toCompletable().await(); - - logger.info("Truncating collection {} triggers ...", collection.getId()); - - houseKeepingClient.queryTriggers(collection.getSelfLink(), "SELECT * FROM root", options) - .flatMap(page -> Observable.from(page.getResults())) + cosmosContainer.queryTriggers("SELECT * FROM root", options) + .flatMap(page -> Flux.fromIterable(page.getResults())) .flatMap(trigger -> { - RequestOptions requestOptions = new RequestOptions(); + CosmosRequestOptions requestOptions = new CosmosRequestOptions(); // if (paths != null && !paths.isEmpty()) { // Object propertyValue = trigger.getObjectByPath(PathParser.getPathParts(paths.get(0))); // requestOptions.setPartitionKey(new PartitionKey(propertyValue)); // } - return houseKeepingClient.deleteTrigger(trigger.getSelfLink(), requestOptions); - }).toCompletable().await(); + return cosmosContainer.getTrigger(trigger.getId()).delete(requestOptions); + }).collectList().block(); - logger.info("Truncating collection {} storedProcedures ...", collection.getId()); + logger.info("Truncating collection {} storedProcedures ...", cosmosContainerId); - houseKeepingClient.queryStoredProcedures(collection.getSelfLink(), "SELECT * FROM root", options) - .flatMap(page -> Observable.from(page.getResults())) + cosmosContainer.queryStoredProcedures("SELECT * FROM root", options) + .flatMap(page -> Flux.fromIterable(page.getResults())) .flatMap(storedProcedure -> { - RequestOptions requestOptions = new RequestOptions(); + CosmosRequestOptions requestOptions = new CosmosRequestOptions(); // if (paths != null && !paths.isEmpty()) { // Object propertyValue = storedProcedure.getObjectByPath(PathParser.getPathParts(paths.get(0))); // requestOptions.setPartitionKey(new PartitionKey(propertyValue)); // } - return houseKeepingClient.deleteStoredProcedure(storedProcedure.getSelfLink(), requestOptions); - }).toCompletable().await(); + return cosmosContainer.getStoredProcedure(storedProcedure.getId()).delete(requestOptions); + }).collectList().block(); - logger.info("Truncating collection {} udfs ...", collection.getId()); + logger.info("Truncating collection {} udfs ...", cosmosContainerId); - houseKeepingClient.queryUserDefinedFunctions(collection.getSelfLink(), "SELECT * FROM root", options) - .flatMap(page -> Observable.from(page.getResults())) + cosmosContainer.queryUserDefinedFunctions("SELECT * FROM root", options) + .flatMap(page -> Flux.fromIterable(page.getResults())) .flatMap(udf -> { - RequestOptions requestOptions = new RequestOptions(); + CosmosRequestOptions requestOptions = new CosmosRequestOptions(); // if (paths != null && !paths.isEmpty()) { // Object propertyValue = udf.getObjectByPath(PathParser.getPathParts(paths.get(0))); // requestOptions.setPartitionKey(new PartitionKey(propertyValue)); // } - return houseKeepingClient.deleteUserDefinedFunction(udf.getSelfLink(), requestOptions); - }).toCompletable().await(); + return cosmosContainer.getUserDefinedFunction(udf.getId()).delete(requestOptions); + }).collectList().block(); } finally { houseKeepingClient.close(); } - logger.info("Finished truncating collection {}.", collection.getId()); + logger.info("Finished truncating collection {}.", cosmosContainerId); } - protected static void waitIfNeededForReplicasToCatchUp(Builder clientBuilder) { - switch (clientBuilder.desiredConsistencyLevel) { + protected static void waitIfNeededForReplicasToCatchUp(CosmosClientBuilder clientBuilder) { + switch (clientBuilder.getDesiredConsistencyLevel()) { case Eventual: case ConsistentPrefix: logger.info(" additional wait in Eventual mode so the replica catch up"); @@ -316,36 +337,12 @@ protected static void waitIfNeededForReplicasToCatchUp(Builder clientBuilder) { } } - private static DocumentCollection getCollectionDefinitionSinglePartitionWithoutPartitionKey() { - DocumentCollection collectionDefinition = new DocumentCollection(); - collectionDefinition.setId(UUID.randomUUID().toString()); - - return collectionDefinition; + public static CosmosContainer createCollection(CosmosDatabase database, CosmosContainerSettings cosmosContainerSettings, + CosmosContainerRequestOptions options) { + return database.createContainer(cosmosContainerSettings, options).block().getContainer(); } - - public static DocumentCollection createCollection(String databaseId, - DocumentCollection collection, - RequestOptions options) { - AsyncDocumentClient client = createGatewayHouseKeepingDocumentClient().build(); - try { - return client.createCollection("dbs/" + databaseId, collection, options).toBlocking().single().getResource(); - } finally { - client.close(); - } - } - - public static DocumentCollection createCollection(AsyncDocumentClient client, String databaseId, - DocumentCollection collection, RequestOptions options) { - return client.createCollection("dbs/" + databaseId, collection, options).toBlocking().single().getResource(); - } - - public static DocumentCollection createCollection(AsyncDocumentClient client, String databaseId, - DocumentCollection collection) { - return client.createCollection("dbs/" + databaseId, collection, null).toBlocking().single().getResource(); - } - - private static DocumentCollection getCollectionDefinitionMultiPartitionWithCompositeAndSpatialIndexes() { + private static CosmosContainerSettings getCollectionDefinitionMultiPartitionWithCompositeAndSpatialIndexes() { final String NUMBER_FIELD = "numberField"; final String STRING_FIELD = "stringField"; final String NUMBER_FIELD_2 = "numberField2"; @@ -359,7 +356,12 @@ private static DocumentCollection getCollectionDefinitionMultiPartitionWithCompo final String LONG_STRING_FIELD = "longStringField"; final String PARTITION_KEY = "pk"; - DocumentCollection documentCollection = new DocumentCollection(); + PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition(); + ArrayList partitionKeyPaths = new ArrayList(); + partitionKeyPaths.add("/" + PARTITION_KEY); + partitionKeyDefinition.setPaths(partitionKeyPaths); + + CosmosContainerSettings cosmosContainerSettings = new CosmosContainerSettings(UUID.randomUUID().toString(), partitionKeyDefinition); IndexingPolicy indexingPolicy = new IndexingPolicy(); Collection> compositeIndexes = new ArrayList>(); @@ -448,91 +450,83 @@ private static DocumentCollection getCollectionDefinitionMultiPartitionWithCompo compositeIndexes.add(compositeIndexLongStrings); indexingPolicy.setCompositeIndexes(compositeIndexes); - documentCollection.setIndexingPolicy(indexingPolicy); + cosmosContainerSettings.setIndexingPolicy(indexingPolicy); - PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition(); - ArrayList partitionKeyPaths = new ArrayList(); - partitionKeyPaths.add("/" + PARTITION_KEY); - partitionKeyDefinition.setPaths(partitionKeyPaths); - documentCollection.setPartitionKey(partitionKeyDefinition); - - documentCollection.setId(UUID.randomUUID().toString()); + return cosmosContainerSettings; + } - return documentCollection; + public static CosmosContainer createCollection(CosmosClient client, String dbId, CosmosContainerSettings collectionDefinition) { + return client.getDatabase(dbId).createContainer(collectionDefinition).block().getContainer(); } - public static Document createDocument(AsyncDocumentClient client, String databaseId, String collectionId, Document document) { - return createDocument(client, databaseId, collectionId, document, null); + public static void deleteCollection(CosmosClient client, String dbId, String collectionId) { + client.getDatabase(dbId).getContainer(collectionId).delete().block(); } - public static Document createDocument(AsyncDocumentClient client, String databaseId, String collectionId, Document document, RequestOptions options) { - return client.createDocument(Utils.getCollectionNameLink(databaseId, collectionId), document, options, false).toBlocking().single().getResource(); + public static CosmosItem createDocument(CosmosContainer cosmosContainer, CosmosItemSettings item) { + return cosmosContainer.createItem(item).block().getCosmosItem(); } - public Observable> bulkInsert(AsyncDocumentClient client, - String collectionLink, - List documentDefinitionList, + /* + // TODO: respect concurrencyLevel; + public Flux bulkInsert(CosmosContainer cosmosContainer, + List documentDefinitionList, int concurrencyLevel) { - ArrayList>> result = new ArrayList>>(documentDefinitionList.size()); - for (Document docDef : documentDefinitionList) { - result.add(client.createDocument(collectionLink, docDef, null, false)); + CosmosItemSettings first = documentDefinitionList.remove(0); + Flux result = Flux.from(cosmosContainer.createItem(first)); + for (CosmosItemSettings docDef : documentDefinitionList) { + result.concatWith(cosmosContainer.createItem(docDef)); } - return Observable.merge(result, concurrencyLevel); + return result; } - - public Observable> bulkInsert(AsyncDocumentClient client, - String collectionLink, - List documentDefinitionList) { - return bulkInsert(client, collectionLink, documentDefinitionList, DEFAULT_BULK_INSERT_CONCURRENCY_LEVEL); - } - - public List bulkInsertBlocking(AsyncDocumentClient client, - String collectionLink, - List documentDefinitionList) { - return bulkInsert(client, collectionLink, documentDefinitionList, DEFAULT_BULK_INSERT_CONCURRENCY_LEVEL) - .map(ResourceResponse::getResource) - .toList() - .toBlocking() - .single(); +*/ + public List bulkInsertBlocking(CosmosContainer cosmosContainer, + List documentDefinitionList) { + /* + return bulkInsert(cosmosContainer, documentDefinitionList, DEFAULT_BULK_INSERT_CONCURRENCY_LEVEL) + .parallel() + .runOn(Schedulers.parallel()) + .map(CosmosItemResponse::getCosmosItemSettings) + .sequential() + .collectList() + .block(); + */ + return Flux.merge(documentDefinitionList.stream() + .map(d -> cosmosContainer.createItem(d).map(response -> response.getCosmosItemSettings())) + .collect(Collectors.toList())).collectList().block(); } - public static ConsistencyLevel getAccountDefaultConsistencyLevel(AsyncDocumentClient client) { - return client.getDatabaseAccount().toBlocking().single().getConsistencyPolicy().getDefaultConsistencyLevel(); + public static ConsistencyLevel getAccountDefaultConsistencyLevel(CosmosClient client) { + return CosmosBridgeInternal.getDatabaseAccount(client).block().getConsistencyPolicy().getDefaultConsistencyLevel(); } - public static User createUser(AsyncDocumentClient client, String databaseId, User user) { - return client.createUser("dbs/" + databaseId, user, null).toBlocking().single().getResource(); + public static CosmosUser createUser(CosmosClient client, String databaseId, CosmosUserSettings userSettings) { + return client.getDatabase(databaseId).read().block().getDatabase().createUser(userSettings).block().getUser(); } - public static User safeCreateUser(AsyncDocumentClient client, String databaseId, User user) { + public static CosmosUser safeCreateUser(CosmosClient client, String databaseId, CosmosUserSettings user) { deleteUserIfExists(client, databaseId, user.getId()); return createUser(client, databaseId, user); } - private static DocumentCollection safeCreateCollection(AsyncDocumentClient client, String databaseId, DocumentCollection collection, RequestOptions options) { + private static CosmosContainer safeCreateCollection(CosmosClient client, String databaseId, CosmosContainerSettings collection, CosmosContainerRequestOptions options) { deleteCollectionIfExists(client, databaseId, collection.getId()); - return createCollection(client, databaseId, collection, options); + return createCollection(client.getDatabase(databaseId), collection, options); } - public static String getCollectionLink(DocumentCollection collection) { - return collection.getSelfLink(); - } - - static protected DocumentCollection getCollectionDefinition() { + static protected CosmosContainerSettings getCollectionDefinition() { PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); ArrayList paths = new ArrayList(); paths.add("/mypk"); partitionKeyDef.setPaths(paths); - DocumentCollection collectionDefinition = new DocumentCollection(); - collectionDefinition.setId(UUID.randomUUID().toString()); - collectionDefinition.setPartitionKey(partitionKeyDef); + CosmosContainerSettings collectionDefinition = new CosmosContainerSettings(UUID.randomUUID().toString(), partitionKeyDef); return collectionDefinition; } - static protected DocumentCollection getCollectionDefinitionWithRangeRangeIndex() { + static protected CosmosContainerSettings getCollectionDefinitionWithRangeRangeIndex() { PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); ArrayList paths = new ArrayList<>(); paths.add("/mypk"); @@ -553,42 +547,50 @@ static protected DocumentCollection getCollectionDefinitionWithRangeRangeIndex() includedPaths.add(includedPath); indexingPolicy.setIncludedPaths(includedPaths); - DocumentCollection collectionDefinition = new DocumentCollection(); - collectionDefinition.setIndexingPolicy(indexingPolicy); - collectionDefinition.setId(UUID.randomUUID().toString()); - collectionDefinition.setPartitionKey(partitionKeyDef); + CosmosContainerSettings cosmosContainerSettings = new CosmosContainerSettings(UUID.randomUUID().toString(), partitionKeyDef); + cosmosContainerSettings.setIndexingPolicy(indexingPolicy); - return collectionDefinition; + return cosmosContainerSettings; } - public static void deleteCollectionIfExists(AsyncDocumentClient client, String databaseId, String collectionId) { - List res = client.queryCollections("dbs/" + databaseId, - String.format("SELECT * FROM root r where r.id = '%s'", collectionId), null).toBlocking().single() - .getResults(); + public static void deleteCollectionIfExists(CosmosClient client, String databaseId, String collectionId) { + CosmosDatabase database = client.getDatabase(databaseId).read().block().getDatabase(); + List res = database.queryContainers(String.format("SELECT * FROM root r where r.id = '%s'", collectionId), null) + .flatMap(page -> Flux.fromIterable(page.getResults())) + .collectList() + .block(); + if (!res.isEmpty()) { - deleteCollection(client, Utils.getCollectionNameLink(databaseId, collectionId)); + deleteCollection(database, collectionId); } } - public static void deleteCollection(AsyncDocumentClient client, String collectionLink) { - client.deleteCollection(collectionLink, null).toBlocking().single(); + public static void deleteCollection(CosmosDatabase cosmosDatabase, String collectionId) { + cosmosDatabase.getContainer(collectionId).delete().block(); + } + + public static void deleteCollection(CosmosContainer cosmosContainer) { + cosmosContainer.delete().block(); } - public static void deleteDocumentIfExists(AsyncDocumentClient client, String databaseId, String collectionId, String docId) { + public static void deleteDocumentIfExists(CosmosClient client, String databaseId, String collectionId, String docId) { FeedOptions options = new FeedOptions(); options.setPartitionKey(new PartitionKey(docId)); - List res = client - .queryDocuments(Utils.getCollectionNameLink(databaseId, collectionId), String.format("SELECT * FROM root r where r.id = '%s'", docId), options) - .toBlocking().single().getResults(); + CosmosContainer cosmosContainer = client.getDatabase(databaseId).read().block().getDatabase().getContainer(collectionId).read().block().getContainer(); + List res = cosmosContainer + .queryItems(String.format("SELECT * FROM root r where r.id = '%s'", docId), options) + .flatMap(page -> Flux.fromIterable(page.getResults())) + .collectList().block(); + if (!res.isEmpty()) { - deleteDocument(client, Utils.getDocumentNameLink(databaseId, collectionId, docId)); + deleteDocument(cosmosContainer, docId); } } - public static void safeDeleteDocument(AsyncDocumentClient client, String documentLink, RequestOptions options) { - if (client != null && documentLink != null) { + public static void safeDeleteDocument(CosmosContainer cosmosContainer, String documentId, Object partitionKey) { + if (cosmosContainer != null && documentId != null) { try { - client.deleteDocument(documentLink, options).toBlocking().single(); + cosmosContainer.getItem(documentId, partitionKey).read().block().getCosmosItem().delete().block(); } catch (Exception e) { DocumentClientException dce = com.microsoft.azure.cosmosdb.rx.internal.Utils.as(e, DocumentClientException.class); if (dce == null || dce.getStatusCode() != 404) { @@ -598,103 +600,89 @@ public static void safeDeleteDocument(AsyncDocumentClient client, String documen } } - public static void deleteDocument(AsyncDocumentClient client, String documentLink) { - client.deleteDocument(documentLink, null).toBlocking().single(); + public static void deleteDocument(CosmosContainer cosmosContainer, String documentId) { + cosmosContainer.getItem(documentId, PartitionKey.None).read().block().getCosmosItem().delete(); } - public static void deleteUserIfExists(AsyncDocumentClient client, String databaseId, String userId) { - List res = client - .queryUsers("dbs/" + databaseId, String.format("SELECT * FROM root r where r.id = '%s'", userId), null) - .toBlocking().single().getResults(); + public static void deleteUserIfExists(CosmosClient client, String databaseId, String userId) { + CosmosDatabase database = client.getDatabase(databaseId).read().block().getDatabase(); + List res = database + .queryUsers(String.format("SELECT * FROM root r where r.id = '%s'", userId), null) + .flatMap(page -> Flux.fromIterable(page.getResults())) + .collectList().block(); if (!res.isEmpty()) { - deleteUser(client, Utils.getUserNameLink(databaseId, userId)); + deleteUser(database, userId); } } - public static void deleteUser(AsyncDocumentClient client, String userLink) { - client.deleteUser(userLink, null).toBlocking().single(); - } - - public static String getDatabaseLink(Database database) { - return database.getSelfLink(); + public static void deleteUser(CosmosDatabase database, String userId) { + database.getUser(userId).read().block().getUser().delete(null).block(); } - static private Database safeCreateDatabase(AsyncDocumentClient client, Database database) { - safeDeleteDatabase(client, database.getId()); - return createDatabase(client, database); + static private CosmosDatabase safeCreateDatabase(CosmosClient client, CosmosDatabaseSettings databaseSettings) { + safeDeleteDatabase(client.getDatabase(databaseSettings.getId())); + return client.createDatabase(databaseSettings).block().getDatabase(); } - static protected Database createDatabase(AsyncDocumentClient client, Database database) { - Observable> databaseObservable = client.createDatabase(database, null); - return databaseObservable.toBlocking().single().getResource(); - } - - static protected Database createDatabase(AsyncDocumentClient client, String databaseId) { - Database databaseDefinition = new Database(); - databaseDefinition.setId(databaseId); - return createDatabase(client, databaseDefinition); - } - - static protected Database createDatabaseIfNotExists(AsyncDocumentClient client, String databaseId) { - return client.queryDatabases(String.format("SELECT * FROM r where r.id = '%s'", databaseId), null).flatMap(p -> Observable.from(p.getResults())).switchIfEmpty( - Observable.defer(() -> { - - Database databaseDefinition = new Database(); - databaseDefinition.setId(databaseId); - - return client.createDatabase(databaseDefinition, null).map(ResourceResponse::getResource); - }) - ).toBlocking().single(); + static protected CosmosDatabase createDatabase(CosmosClient client, String databaseId) { + CosmosDatabaseSettings databaseSettings = new CosmosDatabaseSettings(databaseId); + return client.createDatabase(databaseSettings).block().getDatabase(); } - static protected void safeDeleteDatabase(AsyncDocumentClient client, Database database) { - if (database != null) { - safeDeleteDatabase(client, database.getId()); + static protected CosmosDatabase createDatabaseIfNotExists(CosmosClient client, String databaseId) { + List res = client.queryDatabases(String.format("SELECT * FROM r where r.id = '%s'", databaseId), null) + .flatMap(p -> Flux.fromIterable(p.getResults())) + .collectList() + .block(); + if (res.size() != 0) { + return client.getDatabase(databaseId).read().block().getDatabase(); + } else { + CosmosDatabaseSettings databaseSettings = new CosmosDatabaseSettings(databaseId); + return client.createDatabase(databaseSettings).block().getDatabase(); } } - static protected void safeDeleteDatabase(AsyncDocumentClient client, String databaseId) { - if (client != null) { + static protected void safeDeleteDatabase(CosmosDatabase database) { + if (database != null) { try { - client.deleteDatabase(Utils.getDatabaseNameLink(databaseId), null).toBlocking().single(); + database.delete().block(); } catch (Exception e) { } } } - static protected void safeDeleteAllCollections(AsyncDocumentClient client, Database database) { + static protected void safeDeleteAllCollections(CosmosDatabase database) { if (database != null) { - List collections = client.readCollections(database.getSelfLink(), null) - .flatMap(p -> Observable.from(p.getResults())) - .toList() - .toBlocking() - .single(); - - for (DocumentCollection collection : collections) { - client.deleteCollection(collection.getSelfLink(), null).toBlocking().single().getResource(); + List collections = database.listContainers() + .flatMap(p -> Flux.fromIterable(p.getResults())) + .collectList() + .block(); + + for(CosmosContainerSettings collection: collections) { + database.getContainer(collection.getId()).delete().block(); } } } - static protected void safeDeleteCollection(AsyncDocumentClient client, DocumentCollection collection) { - if (client != null && collection != null) { + static protected void safeDeleteCollection(CosmosContainer collection) { + if (collection != null) { try { - client.deleteCollection(collection.getSelfLink(), null).toBlocking().single(); + collection.delete().block(); } catch (Exception e) { } } } - static protected void safeDeleteCollection(AsyncDocumentClient client, String databaseId, String collectionId) { - if (client != null && databaseId != null && collectionId != null) { + static protected void safeDeleteCollection(CosmosDatabase database, String collectionId) { + if (database != null && collectionId != null) { try { - client.deleteCollection("/dbs/" + databaseId + "/colls/" + collectionId, null).toBlocking().single(); + database.getContainer(collectionId).read().block().getContainer().delete().block(); } catch (Exception e) { } } } - static protected void safeCloseAsync(AsyncDocumentClient client) { + static protected void safeCloseAsync(CosmosClient client) { if (client != null) { new Thread(() -> { try { @@ -706,7 +694,7 @@ static protected void safeCloseAsync(AsyncDocumentClient client) { } } - static protected void safeClose(AsyncDocumentClient client) { + static protected void safeClose(CosmosClient client) { if (client != null) { try { client.close(); @@ -717,12 +705,12 @@ static protected void safeClose(AsyncDocumentClient client) { } public void validateSuccess(Observable> observable, - ResourceResponseValidator validator) { + ResourceResponseValidator validator) { validateSuccess(observable, validator, subscriberValidationTimeout); } public static void validateSuccess(Observable> observable, - ResourceResponseValidator validator, long timeout) { + ResourceResponseValidator validator, long timeout) { VerboseTestSubscriber> testSubscriber = new VerboseTestSubscriber<>(); @@ -735,12 +723,12 @@ public static void validateSuccess(Observable void validateFailure(Observable> observable, - FailureValidator validator) { + FailureValidator validator) { validateFailure(observable, validator, subscriberValidationTimeout); } public static void validateFailure(Observable> observable, - FailureValidator validator, long timeout) { + FailureValidator validator, long timeout) { VerboseTestSubscriber> testSubscriber = new VerboseTestSubscriber<>(); @@ -753,12 +741,12 @@ public static void validateFailure(Observable void validateQuerySuccess(Observable> observable, - FeedResponseListValidator validator) { + FeedResponseListValidator validator) { validateQuerySuccess(observable, validator, subscriberValidationTimeout); } public static void validateQuerySuccess(Observable> observable, - FeedResponseListValidator validator, long timeout) { + FeedResponseListValidator validator, long timeout) { VerboseTestSubscriber> testSubscriber = new VerboseTestSubscriber<>(); @@ -770,12 +758,12 @@ public static void validateQuerySuccess(Observable void validateQueryFailure(Observable> observable, - FailureValidator validator) { + FailureValidator validator) { validateQueryFailure(observable, validator, subscriberValidationTimeout); } public static void validateQueryFailure(Observable> observable, - FailureValidator validator, long timeout) { + FailureValidator validator, long timeout) { VerboseTestSubscriber> testSubscriber = new VerboseTestSubscriber<>(); @@ -787,6 +775,77 @@ public static void validateQueryFailure(Observable void validateSuccess(Mono single, CosmosResponseValidator validator) + throws InterruptedException { + validateSuccess(single.flux(), validator, subscriberValidationTimeout); + } + + public static void validateSuccess(Flux flowable, + CosmosResponseValidator validator, long timeout) throws InterruptedException { + + TestSubscriber testSubscriber = new TestSubscriber<>(); + + flowable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertComplete(); + testSubscriber.assertValueCount(1); + validator.validate(testSubscriber.values().get(0)); + } + + public void validateFailure(Mono mono, FailureValidator validator) + throws InterruptedException { + validateFailure(mono.flux(), validator, subscriberValidationTimeout); + } + + public static void validateFailure(Flux flowable, + FailureValidator validator, long timeout) throws InterruptedException { + + TestSubscriber testSubscriber = new TestSubscriber<>(); + + flowable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNotComplete(); + testSubscriber.assertTerminated(); + assertThat(testSubscriber.errors()).hasSize(1); + validator.validate((Throwable) testSubscriber.getEvents().get(1).get(0)); + } + + public void validateQuerySuccess(Flux> flowable, + FeedResponseListValidator validator) { + validateQuerySuccess(flowable, validator, subscriberValidationTimeout); + } + + public static void validateQuerySuccess(Flux> flowable, + FeedResponseListValidator validator, long timeout) { + + TestSubscriber> testSubscriber = new TestSubscriber<>(); + + flowable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertComplete(); + validator.validate(testSubscriber.getEvents().get(0).stream().map(object -> (FeedResponse) object) + .collect(Collectors.toList())); + } + + public void validateQueryFailure(Flux> flowable, FailureValidator validator) { + validateQueryFailure(flowable, validator, subscriberValidationTimeout); + } + + public static void validateQueryFailure(Flux> flowable, + FailureValidator validator, long timeout) { + + TestSubscriber> testSubscriber = new TestSubscriber<>(); + + flowable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNotComplete(); + testSubscriber.assertTerminated(); + assertThat(testSubscriber.getEvents().get(1)).hasSize(1); + validator.validate((Throwable) testSubscriber.getEvents().get(1).get(0)); + } + @DataProvider public static Object[][] clientBuilders() { return new Object[][]{{createGatewayRxDocumentClient(ConsistencyLevel.Session, false, null)}}; @@ -858,23 +917,23 @@ private static Object[][] simpleClientBuildersWithDirect(Protocol... protocols) boolean isMultiMasterEnabled = preferredLocations != null && accountConsistency == ConsistencyLevel.Session; - List builders = new ArrayList<>(); - builders.add(createGatewayRxDocumentClient(ConsistencyLevel.Session, false, null)); + List cosmosConfigurations = new ArrayList<>(); + cosmosConfigurations.add(createGatewayRxDocumentClient(ConsistencyLevel.Session, false, null)); for (Protocol protocol : protocols) { - testConsistencies.forEach(consistencyLevel -> builders.add(createDirectRxDocumentClient(consistencyLevel, + testConsistencies.forEach(consistencyLevel -> cosmosConfigurations.add(createDirectRxDocumentClient(consistencyLevel, protocol, isMultiMasterEnabled, preferredLocations))); } - builders.forEach(b -> logger.info("Will Use ConnectionMode [{}], Consistency [{}], Protocol [{}]", - b.connectionPolicy.getConnectionMode(), - b.desiredConsistencyLevel, - b.configs.getProtocol() + cosmosConfigurations.forEach(c -> logger.info("Will Use ConnectionMode [{}], Consistency [{}], Protocol [{}]", + c.getConnectionPolicy().getConnectionMode(), + c.getDesiredConsistencyLevel(), + c.getConfigs().getProtocol() )); - return builders.stream().map(b -> new Object[]{b}).collect(Collectors.toList()).toArray(new Object[0][]); + return cosmosConfigurations.stream().map(b -> new Object[]{b}).collect(Collectors.toList()).toArray(new Object[0][]); } @DataProvider @@ -924,6 +983,7 @@ static List parseDesiredConsistencies(String consistencies) { static List allEqualOrLowerConsistencies(ConsistencyLevel accountConsistency) { List testConsistencies = new ArrayList<>(); switch (accountConsistency) { + case Strong: testConsistencies.add(ConsistencyLevel.Strong); case BoundedStaleness: @@ -944,53 +1004,53 @@ static List allEqualOrLowerConsistencies(ConsistencyLevel acco private static Object[][] clientBuildersWithDirect(List testConsistencies, Protocol... protocols) { boolean isMultiMasterEnabled = preferredLocations != null && accountConsistency == ConsistencyLevel.Session; - List builders = new ArrayList<>(); - builders.add(createGatewayRxDocumentClient(ConsistencyLevel.Session, isMultiMasterEnabled, preferredLocations)); + List cosmosConfigurations = new ArrayList<>(); + cosmosConfigurations.add(createGatewayRxDocumentClient(ConsistencyLevel.Session, isMultiMasterEnabled, preferredLocations)); for (Protocol protocol : protocols) { - testConsistencies.forEach(consistencyLevel -> builders.add(createDirectRxDocumentClient(consistencyLevel, + testConsistencies.forEach(consistencyLevel -> cosmosConfigurations.add(createDirectRxDocumentClient(consistencyLevel, protocol, isMultiMasterEnabled, preferredLocations))); } - builders.forEach(b -> logger.info("Will Use ConnectionMode [{}], Consistency [{}], Protocol [{}]", - b.connectionPolicy.getConnectionMode(), - b.desiredConsistencyLevel, - b.configs.getProtocol() + cosmosConfigurations.forEach(c -> logger.info("Will Use ConnectionMode [{}], Consistency [{}], Protocol [{}]", + c.getConnectionPolicy().getConnectionMode(), + c.getDesiredConsistencyLevel(), + c.getConfigs().getProtocol() )); - return builders.stream().map(b -> new Object[]{b}).collect(Collectors.toList()).toArray(new Object[0][]); + return cosmosConfigurations.stream().map(c -> new Object[]{c}).collect(Collectors.toList()).toArray(new Object[0][]); } - static protected Builder createGatewayHouseKeepingDocumentClient() { + static protected CosmosClientBuilder createGatewayHouseKeepingDocumentClient() { ConnectionPolicy connectionPolicy = new ConnectionPolicy(); connectionPolicy.setConnectionMode(ConnectionMode.Gateway); RetryOptions options = new RetryOptions(); options.setMaxRetryWaitTimeInSeconds(SUITE_SETUP_TIMEOUT); connectionPolicy.setRetryOptions(options); - return new Builder().withServiceEndpoint(TestConfigurations.HOST) - .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) - .withConnectionPolicy(connectionPolicy) - .withConsistencyLevel(ConsistencyLevel.Session); + return CosmosClient.builder().endpoint(TestConfigurations.HOST) + .key(TestConfigurations.MASTER_KEY) + .connectionPolicy(connectionPolicy) + .consistencyLevel(ConsistencyLevel.Session); } - static protected Builder createGatewayRxDocumentClient(ConsistencyLevel consistencyLevel, boolean multiMasterEnabled, List preferredLocations) { + static protected CosmosClientBuilder createGatewayRxDocumentClient(ConsistencyLevel consistencyLevel, boolean multiMasterEnabled, List preferredLocations) { ConnectionPolicy connectionPolicy = new ConnectionPolicy(); connectionPolicy.setConnectionMode(ConnectionMode.Gateway); connectionPolicy.setUsingMultipleWriteLocations(multiMasterEnabled); connectionPolicy.setPreferredLocations(preferredLocations); - return new Builder().withServiceEndpoint(TestConfigurations.HOST) - .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) - .withConnectionPolicy(connectionPolicy) - .withConsistencyLevel(consistencyLevel); + return CosmosClient.builder().endpoint(TestConfigurations.HOST) + .key(TestConfigurations.MASTER_KEY) + .connectionPolicy(connectionPolicy) + .consistencyLevel(consistencyLevel); } - static protected Builder createGatewayRxDocumentClient() { + static protected CosmosClientBuilder createGatewayRxDocumentClient() { return createGatewayRxDocumentClient(ConsistencyLevel.Session, false, null); } - static protected Builder createDirectRxDocumentClient(ConsistencyLevel consistencyLevel, + static protected CosmosClientBuilder createDirectRxDocumentClient(ConsistencyLevel consistencyLevel, Protocol protocol, boolean multiMasterEnabled, List preferredLocations) { @@ -1008,11 +1068,11 @@ static protected Builder createDirectRxDocumentClient(ConsistencyLevel consisten Configs configs = spy(new Configs()); doAnswer((Answer)invocation -> protocol).when(configs).getProtocol(); - return new Builder().withServiceEndpoint(TestConfigurations.HOST) - .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) - .withConnectionPolicy(connectionPolicy) - .withConsistencyLevel(consistencyLevel) - .withConfigs(configs); + return CosmosClient.builder().endpoint(TestConfigurations.HOST) + .key(TestConfigurations.MASTER_KEY) + .connectionPolicy(connectionPolicy) + .consistencyLevel(consistencyLevel) + .configs(configs); } protected int expectedNumberOfPages(int totalExpectedResult, int maxPageSize) { @@ -1027,7 +1087,7 @@ public Object[][] queryMetricsArgProvider() { }; } - public static class VerboseTestSubscriber extends TestSubscriber { + public static class VerboseTestSubscriber extends rx.observers.TestSubscriber { @Override public void assertNoErrors() { List onErrorEvents = getOnErrorEvents(); diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TokenResolverTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TokenResolverTest.java index cc9ea0fef0f8b..5877d771244f4 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TokenResolverTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TokenResolverTest.java @@ -45,6 +45,7 @@ import com.microsoft.azure.cosmosdb.TokenResolver; import com.microsoft.azure.cosmosdb.User; import com.microsoft.azure.cosmosdb.internal.HttpConstants; +import com.microsoft.azure.cosmosdb.rx.internal.TestSuiteBase; import org.testng.SkipException; import org.testng.annotations.AfterClass; @@ -63,6 +64,7 @@ import java.util.UUID; import java.util.Map; +//TODO: change to use external TestSuiteBase public class TokenResolverTest extends TestSuiteBase { private class UserClass { @@ -563,4 +565,4 @@ private TokenResolver getTokenResolverWithBlockList(PermissionMode permissionMod } }; } -} +} \ No newline at end of file diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TopQueryTests.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TopQueryTests.java index b40b22609e7ea..de9569b2afe31 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TopQueryTests.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TopQueryTests.java @@ -30,6 +30,7 @@ import java.util.Set; import java.util.concurrent.TimeUnit; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import com.microsoft.azure.cosmosdb.RetryAnalyzer; import com.microsoft.azure.cosmosdb.internal.directconnectivity.Protocol; import org.testng.SkipException; @@ -38,36 +39,35 @@ import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.Document; -import com.microsoft.azure.cosmosdb.DocumentCollection; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosItemSettings; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; import com.microsoft.azure.cosmosdb.PartitionKey; import com.microsoft.azure.cosmosdb.rx.internal.Utils.ValueHolder; import com.microsoft.azure.cosmosdb.rx.internal.query.TakeContinuationToken; -import rx.Observable; +import io.reactivex.subscribers.TestSubscriber; +import reactor.core.publisher.Flux; public class TopQueryTests extends TestSuiteBase { - private Database createdDatabase; - private DocumentCollection createdCollection; - private ArrayList docs = new ArrayList(); + private CosmosContainer createdCollection; + private ArrayList docs = new ArrayList(); private String partitionKey = "mypk"; private int firstPk = 0; private int secondPk = 1; private String field = "field"; - private AsyncDocumentClient client; + private CosmosClient client; @Factory(dataProvider = "clientBuildersWithDirect") - public TopQueryTests(AsyncDocumentClient.Builder clientBuilder) { + public TopQueryTests(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } - @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "queryMetricsArgProvider", retryAnalyzer = RetryAnalyzer.class - ) + @Test(groups = { "simple" }, timeOut = TIMEOUT, dataProvider = "queryMetricsArgProvider", retryAnalyzer = RetryAnalyzer.class) public void queryDocumentsWithTop(boolean qmEnabled) throws Exception { FeedOptions options = new FeedOptions(); @@ -81,36 +81,33 @@ public void queryDocumentsWithTop(boolean qmEnabled) throws Exception { int[] expectedPageLengths = new int[] { 9, 9, 2 }; for (int i = 0; i < 2; i++) { - Observable> queryObservable1 = client.queryDocuments(createdCollection.getSelfLink(), - "SELECT TOP 0 value AVG(c.field) from c", options); + Flux> queryObservable1 = createdCollection.queryItems("SELECT TOP 0 value AVG(c.field) from c", options); - FeedResponseListValidator validator1 = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator1 = new FeedResponseListValidator.Builder() .totalSize(0).build(); try { validateQuerySuccess(queryObservable1, validator1, TIMEOUT); } catch (Throwable error) { - if (this.clientBuilder.configs.getProtocol() == Protocol.Tcp) { + if (this.clientBuilder.getConfigs().getProtocol() == Protocol.Tcp) { String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", - this.clientBuilder.desiredConsistencyLevel); + this.clientBuilder.getDesiredConsistencyLevel()); logger.info(message, error); throw new SkipException(message, error); } throw error; } - Observable> queryObservable2 = client.queryDocuments(createdCollection.getSelfLink(), - "SELECT TOP 1 value AVG(c.field) from c", options); + Flux> queryObservable2 = createdCollection.queryItems("SELECT TOP 1 value AVG(c.field) from c", options); - FeedResponseListValidator validator2 = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator2 = new FeedResponseListValidator.Builder() .totalSize(1).build(); validateQuerySuccess(queryObservable2, validator2, TIMEOUT); - Observable> queryObservable3 = client.queryDocuments(createdCollection.getSelfLink(), - "SELECT TOP 20 * from c", options); + Flux> queryObservable3 = createdCollection.queryItems("SELECT TOP 20 * from c", options); - FeedResponseListValidator validator3 = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator3 = new FeedResponseListValidator.Builder() .totalSize(expectedTotalSize).numberOfPages(expectedNumberOfPages).pageLengths(expectedPageLengths) .hasValidQueryMetrics(qmEnabled).build(); @@ -160,9 +157,9 @@ public void queryDocumentsWithTopContinuationTokens() throws Exception { private void queryWithContinuationTokensAndPageSizes(String query, int[] pageSizes, int topCount) { for (int pageSize : pageSizes) { - List receivedDocuments = this.queryWithContinuationTokens(query, pageSize); + List receivedDocuments = this.queryWithContinuationTokens(query, pageSize); Set actualIds = new HashSet(); - for (Document document : receivedDocuments) { + for (CosmosItemSettings document : receivedDocuments) { actualIds.add(document.getResourceId()); } @@ -170,10 +167,10 @@ private void queryWithContinuationTokensAndPageSizes(String query, int[] pageSiz } } - private List queryWithContinuationTokens(String query, int pageSize) { + private List queryWithContinuationTokens(String query, int pageSize) { String requestContinuation = null; List continuationTokens = new ArrayList(); - List receivedDocuments = new ArrayList(); + List receivedDocuments = new ArrayList(); do { FeedOptions options = new FeedOptions(); @@ -181,17 +178,16 @@ private List queryWithContinuationTokens(String query, int pageSize) { options.setEnableCrossPartitionQuery(true); options.setMaxDegreeOfParallelism(2); options.setRequestContinuation(requestContinuation); - Observable> queryObservable = client.queryDocuments(createdCollection.getSelfLink(), - query, options); + Flux> queryObservable = createdCollection.queryItems(query, options); - Observable> firstPageObservable = queryObservable.first(); - VerboseTestSubscriber> testSubscriber = new VerboseTestSubscriber<>(); - firstPageObservable.subscribe(testSubscriber); + //Observable> firstPageObservable = queryObservable.first(); + TestSubscriber> testSubscriber = new TestSubscriber<>(); + queryObservable.subscribe(testSubscriber); testSubscriber.awaitTerminalEvent(TIMEOUT, TimeUnit.MILLISECONDS); testSubscriber.assertNoErrors(); - testSubscriber.assertCompleted(); + testSubscriber.assertComplete(); - FeedResponse firstPage = testSubscriber.getOnNextEvents().get(0); + FeedResponse firstPage = (FeedResponse) testSubscriber.getEvents().get(0).get(0); requestContinuation = firstPage.getResponseContinuation(); receivedDocuments.addAll(firstPage.getResults()); continuationTokens.add(requestContinuation); @@ -200,18 +196,18 @@ private List queryWithContinuationTokens(String query, int pageSize) { return receivedDocuments; } - public void bulkInsert(AsyncDocumentClient client) { + public void bulkInsert(CosmosClient client) { generateTestData(); for (int i = 0; i < docs.size(); i++) { - createDocument(client, createdDatabase.getId(), createdCollection.getId(), docs.get(i)); + createDocument(createdCollection, docs.get(i)); } } public void generateTestData() { for (int i = 0; i < 10; i++) { - Document d = new Document(); + CosmosItemSettings d = new CosmosItemSettings(); d.setId(Integer.toString(i)); d.set(field, i); d.set(partitionKey, firstPk); @@ -219,7 +215,7 @@ public void generateTestData() { } for (int i = 10; i < 20; i++) { - Document d = new Document(); + CosmosItemSettings d = new CosmosItemSettings(); d.setId(Integer.toString(i)); d.set(field, i); d.set(partitionKey, secondPk); @@ -235,9 +231,8 @@ public void afterClass() { @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) public void beforeClass() throws Exception { client = clientBuilder.build(); - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_SINGLE_PARTITION_COLLECTION; - truncateCollection(SHARED_SINGLE_PARTITION_COLLECTION); + createdCollection = getSharedSinglePartitionCosmosContainer(client); + truncateCollection(createdCollection); bulkInsert(client); diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TriggerCrudTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TriggerCrudTest.java index 5a729f2ce4243..f9d4008fe70b9 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TriggerCrudTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TriggerCrudTest.java @@ -24,49 +24,50 @@ import java.util.UUID; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.DocumentCollection; -import com.microsoft.azure.cosmosdb.ResourceResponse; -import com.microsoft.azure.cosmosdb.Trigger; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosRequestOptions; +import com.microsoft.azure.cosmos.CosmosResponse; +import com.microsoft.azure.cosmos.CosmosResponseValidator; +import com.microsoft.azure.cosmos.CosmosTrigger; +import com.microsoft.azure.cosmos.CosmosTriggerResponse; +import com.microsoft.azure.cosmos.CosmosTriggerSettings; +import com.microsoft.azure.cosmosdb.RequestOptions; import com.microsoft.azure.cosmosdb.TriggerOperation; import com.microsoft.azure.cosmosdb.TriggerType; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; - -import rx.Observable; - -import javax.net.ssl.SSLException; +import reactor.core.publisher.Mono; public class TriggerCrudTest extends TestSuiteBase { - private Database createdDatabase; - private DocumentCollection createdCollection; + private CosmosContainer createdCollection; - private AsyncDocumentClient client; + private CosmosClient client; @Factory(dataProvider = "clientBuildersWithDirect") - public TriggerCrudTest(AsyncDocumentClient.Builder clientBuilder) { + public TriggerCrudTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } - @Test(groups = { "simple" }, timeOut = TIMEOUT) + @Test(groups = { "simple" }, timeOut = TIMEOUT * 100) public void createTrigger() throws Exception { // create a trigger - Trigger trigger = new Trigger(); + CosmosTriggerSettings trigger = new CosmosTriggerSettings(); trigger.setId(UUID.randomUUID().toString()); trigger.setBody("function() {var x = 10;}"); trigger.setTriggerOperation(TriggerOperation.Create); trigger.setTriggerType(TriggerType.Pre); - Observable> createObservable = client.createTrigger(getCollectionLink(), trigger, null); + Mono createObservable = createdCollection.createTrigger(trigger, new CosmosRequestOptions()); // validate trigger creation - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .withId(trigger.getId()) .withTriggerBody("function() {var x = 10;}") .withTriggerInternals(TriggerType.Pre, TriggerOperation.Create) @@ -78,19 +79,19 @@ public void createTrigger() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void readTrigger() throws Exception { // create a trigger - Trigger trigger = new Trigger(); + CosmosTriggerSettings trigger = new CosmosTriggerSettings(); trigger.setId(UUID.randomUUID().toString()); trigger.setBody("function() {var x = 10;}"); trigger.setTriggerOperation(TriggerOperation.Create); trigger.setTriggerType(TriggerType.Pre); - Trigger readBackTrigger = client.createTrigger(getCollectionLink(), trigger, null).toBlocking().single().getResource(); + CosmosTrigger readBackTrigger = createdCollection.createTrigger(trigger, new CosmosRequestOptions()).block().getCosmosTrigger(); // read trigger waitIfNeededForReplicasToCatchUp(clientBuilder); - Observable> readObservable = client.readTrigger(readBackTrigger.getSelfLink(), null); + Mono readObservable = readBackTrigger.read(new RequestOptions()); // validate read trigger - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .withId(trigger.getId()) .withTriggerBody("function() {var x = 10;}") .withTriggerInternals(TriggerType.Pre, TriggerOperation.Create) @@ -102,18 +103,18 @@ public void readTrigger() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void deleteTrigger() throws Exception { // create a trigger - Trigger trigger = new Trigger(); + CosmosTriggerSettings trigger = new CosmosTriggerSettings(); trigger.setId(UUID.randomUUID().toString()); trigger.setBody("function() {var x = 10;}"); trigger.setTriggerOperation(TriggerOperation.Create); trigger.setTriggerType(TriggerType.Pre); - Trigger readBackTrigger = client.createTrigger(getCollectionLink(), trigger, null).toBlocking().single().getResource(); + CosmosTrigger readBackTrigger = createdCollection.createTrigger(trigger, new CosmosRequestOptions()).block().getCosmosTrigger(); // delete trigger - Observable> deleteObservable = client.deleteTrigger(readBackTrigger.getSelfLink(), null); + Mono deleteObservable = readBackTrigger.delete(new CosmosRequestOptions()); // validate delete trigger - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .nullResource() .build(); validateSuccess(deleteObservable, validator); @@ -122,17 +123,11 @@ public void deleteTrigger() throws Exception { @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) public void beforeClass() { client = clientBuilder.build(); - - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_MULTI_PARTITION_COLLECTION; + createdCollection = getSharedMultiPartitionCosmosContainer(client); } @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) public void afterClass() { safeClose(client); } - - private String getCollectionLink() { - return createdCollection.getSelfLink(); - } } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TriggerQueryTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TriggerQueryTest.java index af8ea0a1bdd4f..9bb191ec70133 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TriggerQueryTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TriggerQueryTest.java @@ -29,39 +29,34 @@ import java.util.UUID; import java.util.stream.Collectors; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.Database; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosRequestOptions; +import com.microsoft.azure.cosmos.CosmosTriggerSettings; import com.microsoft.azure.cosmosdb.DocumentClientException; -import com.microsoft.azure.cosmosdb.DocumentCollection; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; import com.microsoft.azure.cosmosdb.Trigger; import com.microsoft.azure.cosmosdb.TriggerOperation; import com.microsoft.azure.cosmosdb.TriggerType; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; - -import rx.Observable; +import reactor.core.publisher.Flux; public class TriggerQueryTest extends TestSuiteBase { - private Database createdDatabase; - private DocumentCollection createdCollection; - private List createdTriggers = new ArrayList<>(); - - private AsyncDocumentClient client; + private CosmosContainer createdCollection; + private List createdTriggers = new ArrayList<>(); - public String getCollectionLink() { - return Utils.getCollectionNameLink(createdDatabase.getId(), createdCollection.getId()); - } + private CosmosClient client; @Factory(dataProvider = "clientBuildersWithDirect") - public TriggerQueryTest(Builder clientBuilder) { + public TriggerQueryTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @@ -73,19 +68,18 @@ public void queryWithFilter() throws Exception { FeedOptions options = new FeedOptions(); options.setMaxItemCount(5); - Observable> queryObservable = client - .queryTriggers(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryTriggers(query, options); List expectedDocs = createdTriggers.stream().filter(sp -> filterId.equals(sp.getId()) ).collect(Collectors.toList()); assertThat(expectedDocs).isNotEmpty(); int expectedPageSize = (expectedDocs.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .totalSize(expectedDocs.size()) .exactlyContainsInAnyOrder(expectedDocs.stream().map(d -> d.getResourceId()).collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .pageSatisfy(0, new FeedResponseValidator.Builder() + .pageSatisfy(0, new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); @@ -98,13 +92,12 @@ public void query_NoResults() throws Exception { String query = "SELECT * from root r where r.id = '2'"; FeedOptions options = new FeedOptions(); options.setEnableCrossPartitionQuery(true); - Observable> queryObservable = client - .queryTriggers(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryTriggers(query, options); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .containsExactly(new ArrayList<>()) .numberOfPages(1) - .pageSatisfy(0, new FeedResponseValidator.Builder() + .pageSatisfy(0, new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); validateQuerySuccess(queryObservable, validator); @@ -117,21 +110,20 @@ public void queryAll() throws Exception { FeedOptions options = new FeedOptions(); options.setMaxItemCount(3); options.setEnableCrossPartitionQuery(true); - Observable> queryObservable = client - .queryTriggers(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryTriggers(query, options); - List expectedDocs = createdTriggers; + List expectedDocs = createdTriggers; int expectedPageSize = (expectedDocs.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - FeedResponseListValidator validator = new FeedResponseListValidator - .Builder() + FeedResponseListValidator validator = new FeedResponseListValidator + .Builder() .exactlyContainsInAnyOrder(expectedDocs .stream() .map(d -> d.getResourceId()) .collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .allPagesSatisfy(new FeedResponseValidator.Builder() + .allPagesSatisfy(new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); validateQuerySuccess(queryObservable, validator); @@ -142,8 +134,7 @@ public void invalidQuerySytax() throws Exception { String query = "I am an invalid query"; FeedOptions options = new FeedOptions(); options.setEnableCrossPartitionQuery(true); - Observable> queryObservable = client - .queryTriggers(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryTriggers(query, options); FailureValidator validator = new FailureValidator.Builder() .instanceOf(DocumentClientException.class) @@ -153,20 +144,19 @@ public void invalidQuerySytax() throws Exception { validateQueryFailure(queryObservable, validator); } - public Trigger createTrigger(AsyncDocumentClient client) { - Trigger storedProcedure = getTriggerDef(); - return client.createTrigger(getCollectionLink(), storedProcedure, null).toBlocking().single().getResource(); + public CosmosTriggerSettings createTrigger(CosmosContainer cosmosContainer) { + CosmosTriggerSettings storedProcedure = getTriggerDef(); + return cosmosContainer.createTrigger(storedProcedure, new CosmosRequestOptions()).block().getCosmosTriggerSettings(); } @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) public void beforeClass() throws Exception { client = clientBuilder.build(); - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY; - truncateCollection(SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); for(int i = 0; i < 5; i++) { - createdTriggers.add(createTrigger(client)); + createdTriggers.add(createTrigger(createdCollection)); } waitIfNeededForReplicasToCatchUp(clientBuilder); @@ -177,8 +167,8 @@ public void afterClass() { safeClose(client); } - private static Trigger getTriggerDef() { - Trigger trigger = new Trigger(); + private static CosmosTriggerSettings getTriggerDef() { + CosmosTriggerSettings trigger = new CosmosTriggerSettings(); trigger.setId(UUID.randomUUID().toString()); trigger.setBody("function() {var x = 10;}"); trigger.setTriggerOperation(TriggerOperation.Create); diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TriggerUpsertReplaceTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TriggerUpsertReplaceTest.java index 7ef831e458eb6..fe2796bcef075 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TriggerUpsertReplaceTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/TriggerUpsertReplaceTest.java @@ -24,92 +24,52 @@ import java.util.UUID; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.DocumentCollection; -import com.microsoft.azure.cosmosdb.ResourceResponse; -import com.microsoft.azure.cosmosdb.Trigger; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosRequestOptions; +import com.microsoft.azure.cosmos.CosmosResponseValidator; +import com.microsoft.azure.cosmos.CosmosTriggerResponse; +import com.microsoft.azure.cosmos.CosmosTriggerSettings; +import com.microsoft.azure.cosmosdb.RequestOptions; import com.microsoft.azure.cosmosdb.TriggerOperation; import com.microsoft.azure.cosmosdb.TriggerType; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; - -import rx.Observable; - -import javax.net.ssl.SSLException; +import reactor.core.publisher.Mono; public class TriggerUpsertReplaceTest extends TestSuiteBase { - private Database createdDatabase; - private DocumentCollection createdCollection; + private CosmosContainer createdCollection; - private AsyncDocumentClient client; + private CosmosClient client; @Factory(dataProvider = "clientBuildersWithDirect") - public TriggerUpsertReplaceTest(AsyncDocumentClient.Builder clientBuilder) { + public TriggerUpsertReplaceTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } - @Test(groups = { "simple" }, timeOut = TIMEOUT) - public void upsertTrigger() throws Exception { - - // create a trigger - Trigger trigger = new Trigger(); - trigger.setId(UUID.randomUUID().toString()); - trigger.setBody("function() {var x = 10;}"); - trigger.setTriggerOperation(TriggerOperation.Create); - trigger.setTriggerType(TriggerType.Pre); - Trigger readBackTrigger = client.upsertTrigger(getCollectionLink(), trigger, null).toBlocking().single().getResource(); - - // read trigger to validate creation - waitIfNeededForReplicasToCatchUp(clientBuilder); - Observable> readObservable = client.readTrigger(readBackTrigger.getSelfLink(), null); - - // validate trigger creation - ResourceResponseValidator validatorForRead = new ResourceResponseValidator.Builder() - .withId(readBackTrigger.getId()) - .withTriggerBody("function() {var x = 10;}") - .withTriggerInternals(TriggerType.Pre, TriggerOperation.Create) - .notNullEtag() - .build(); - validateSuccess(readObservable, validatorForRead); - - //update trigger - readBackTrigger.setBody("function() {var x = 11;}"); - - Observable> updateObservable = client.upsertTrigger(getCollectionLink(), readBackTrigger, null); - - // validate trigger update - ResourceResponseValidator validatorForUpdate = new ResourceResponseValidator.Builder() - .withId(readBackTrigger.getId()) - .withTriggerBody("function() {var x = 11;}") - .withTriggerInternals(TriggerType.Pre, TriggerOperation.Create) - .notNullEtag() - .build(); - validateSuccess(updateObservable, validatorForUpdate); - } - @Test(groups = { "simple" }, timeOut = TIMEOUT) public void replaceTrigger() throws Exception { // create a trigger - Trigger trigger = new Trigger(); + CosmosTriggerSettings trigger = new CosmosTriggerSettings(); trigger.setId(UUID.randomUUID().toString()); trigger.setBody("function() {var x = 10;}"); trigger.setTriggerOperation(TriggerOperation.Create); trigger.setTriggerType(TriggerType.Pre); - Trigger readBackTrigger = client.createTrigger(getCollectionLink(), trigger, null).toBlocking().single().getResource(); + CosmosTriggerSettings readBackTrigger = createdCollection.createTrigger(trigger, new CosmosRequestOptions()).block().getCosmosTriggerSettings(); // read trigger to validate creation waitIfNeededForReplicasToCatchUp(clientBuilder); - Observable> readObservable = client.readTrigger(readBackTrigger.getSelfLink(), null); + Mono readObservable = createdCollection.getTrigger(readBackTrigger.getId()).read(new RequestOptions()); // validate trigger creation - ResourceResponseValidator validatorForRead = new ResourceResponseValidator.Builder() + CosmosResponseValidator validatorForRead = new CosmosResponseValidator.Builder() .withId(readBackTrigger.getId()) .withTriggerBody("function() {var x = 10;}") .withTriggerInternals(TriggerType.Pre, TriggerOperation.Create) @@ -120,10 +80,10 @@ public void replaceTrigger() throws Exception { //update trigger readBackTrigger.setBody("function() {var x = 11;}"); - Observable> updateObservable = client.replaceTrigger(readBackTrigger, null); + Mono updateObservable = createdCollection.getTrigger(readBackTrigger.getId()).replace(readBackTrigger, new RequestOptions()); // validate trigger replace - ResourceResponseValidator validatorForUpdate = new ResourceResponseValidator.Builder() + CosmosResponseValidator validatorForUpdate = new CosmosResponseValidator.Builder() .withId(readBackTrigger.getId()) .withTriggerBody("function() {var x = 11;}") .withTriggerInternals(TriggerType.Pre, TriggerOperation.Create) @@ -135,17 +95,12 @@ public void replaceTrigger() throws Exception { @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) public void beforeClass() { client = clientBuilder.build(); - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY; - truncateCollection(SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); } @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) public void afterClass() { safeClose(client); } - - private String getCollectionLink() { - return createdCollection.getSelfLink(); - } } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/UniqueIndexTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/UniqueIndexTest.java index d6bd7f40c6b21..e95adb5735ce8 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/UniqueIndexTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/UniqueIndexTest.java @@ -25,59 +25,63 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; +import java.util.ArrayList; import java.util.Collections; import java.util.UUID; -import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import javax.net.ssl.SSLException; - import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.fasterxml.jackson.databind.util.JSONPObject; -import com.microsoft.azure.cosmosdb.DatabaseForTest; + import org.testng.annotations.AfterClass; -import org.testng.annotations.AfterTest; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test; import com.google.common.collect.ImmutableList; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosContainerRequestOptions; +import com.microsoft.azure.cosmos.CosmosContainerSettings; +import com.microsoft.azure.cosmos.CosmosDatabase; +import com.microsoft.azure.cosmos.CosmosDatabaseForTest; +import com.microsoft.azure.cosmos.CosmosItem; +import com.microsoft.azure.cosmos.CosmosItemRequestOptions; +import com.microsoft.azure.cosmos.CosmosItemSettings; import com.microsoft.azure.cosmosdb.ConnectionPolicy; import com.microsoft.azure.cosmosdb.ConsistencyLevel; import com.microsoft.azure.cosmosdb.DataType; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.Document; import com.microsoft.azure.cosmosdb.DocumentClientException; -import com.microsoft.azure.cosmosdb.DocumentCollection; import com.microsoft.azure.cosmosdb.ExcludedPath; import com.microsoft.azure.cosmosdb.HashIndex; import com.microsoft.azure.cosmosdb.IncludedPath; import com.microsoft.azure.cosmosdb.IndexingMode; import com.microsoft.azure.cosmosdb.IndexingPolicy; -import com.microsoft.azure.cosmosdb.ResourceResponse; +import com.microsoft.azure.cosmosdb.PartitionKey; +import com.microsoft.azure.cosmosdb.PartitionKeyDefinition; import com.microsoft.azure.cosmosdb.UniqueKey; import com.microsoft.azure.cosmosdb.UniqueKeyPolicy; import com.microsoft.azure.cosmosdb.internal.HttpConstants; -import rx.Observable; -import rx.observers.TestSubscriber; - public class UniqueIndexTest extends TestSuiteBase { protected static final int TIMEOUT = 30000; protected static final int SETUP_TIMEOUT = 20000; protected static final int SHUTDOWN_TIMEOUT = 20000; - private final String databaseId = DatabaseForTest.generateId(); - private AsyncDocumentClient client; - private Database database; + private final String databaseId = CosmosDatabaseForTest.generateId(); + private CosmosClient client; + private CosmosDatabase database; - private DocumentCollection collection; + private CosmosContainer collection; @Test(groups = { "long" }, timeOut = TIMEOUT) public void insertWithUniqueIndex() throws Exception { - DocumentCollection collectionDefinition = new DocumentCollection(); - collectionDefinition.setId(UUID.randomUUID().toString()); + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.setPaths(paths); + + CosmosContainerSettings collectionDefinition = new CosmosContainerSettings(UUID.randomUUID().toString(), partitionKeyDef); UniqueKeyPolicy uniqueKeyPolicy = new UniqueKeyPolicy(); UniqueKey uniqueKey = new UniqueKey(); uniqueKey.setPaths(ImmutableList.of("/name", "/description")); @@ -98,59 +102,66 @@ public void insertWithUniqueIndex() throws Exception { includedPath2.setPath("/description/?"); includedPath2.setIndexes(Collections.singletonList(new HashIndex(DataType.String, 7))); indexingPolicy.setIncludedPaths(ImmutableList.of(includedPath1, includedPath2)); + collectionDefinition.setIndexingPolicy(indexingPolicy); ObjectMapper om = new ObjectMapper(); - JsonNode doc1 = om.readValue("{\"name\":\"Alexander Pushkin\",\"description\":\"poet\"}", JsonNode.class); - JsonNode doc2 = om.readValue("{\"name\":\"Alexander Pushkin\",\"description\":\"playwright\"}", JsonNode.class); - JsonNode doc3 = om.readValue("{\"name\":\"حافظ شیرازی\",\"description\":\"poet\"}", JsonNode.class); + JsonNode doc1 = om.readValue("{\"name\":\"Alexander Pushkin\",\"description\":\"poet\",\"id\": \""+ UUID.randomUUID().toString() +"\"}", JsonNode.class); + JsonNode doc2 = om.readValue("{\"name\":\"Alexander Pushkin\",\"description\":\"playwright\",\"id\": \"" + UUID.randomUUID().toString() + "\"}", JsonNode.class); + JsonNode doc3 = om.readValue("{\"name\":\"حافظ شیرازی\",\"description\":\"poet\",\"id\": \"" + UUID.randomUUID().toString() + "\"}", JsonNode.class); - collection = client.createCollection(getDatabaseLink(), collectionDefinition, null).toBlocking().single().getResource(); + collection = database.createContainer(collectionDefinition).block().getContainer(); - Document dd = client.createDocument(getCollectionLink(collection), doc1, null, false).toBlocking().single().getResource(); + CosmosItem item = collection.createItem(doc1).block().getCosmosItem(); - client.readDocument(dd.getSelfLink(), null).toBlocking().single(); + CosmosItemRequestOptions options = new CosmosItemRequestOptions(); + options.setPartitionKey(PartitionKey.None); + CosmosItemSettings itemSettings = item.read(options).block().getCosmosItemSettings(); + assertThat(itemSettings.getId()).isEqualTo(doc1.get("id").textValue()); try { - client.createDocument(getCollectionLink(collection), doc1, null, false).toBlocking().single(); + collection.createItem(doc1).block(); fail("Did not throw due to unique constraint (create)"); } catch (RuntimeException e) { assertThat(getDocumentClientException(e).getStatusCode()).isEqualTo(HttpConstants.StatusCodes.CONFLICT); } - client.createDocument(getCollectionLink(collection), doc2, null, false).toBlocking().single(); - client.createDocument(getCollectionLink(collection), doc3, null, false).toBlocking().single(); + collection.createItem(doc2).block(); + collection.createItem(doc3).block(); } - @Test(groups = { "long" }, timeOut = TIMEOUT) + @Test(groups = { "long" }, timeOut = TIMEOUT * 1000) public void replaceAndDeleteWithUniqueIndex() throws Exception { - DocumentCollection collectionDefinition = new DocumentCollection(); - collectionDefinition.setId(UUID.randomUUID().toString()); + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.setPaths(paths); + + CosmosContainerSettings collectionDefinition = new CosmosContainerSettings(UUID.randomUUID().toString(), partitionKeyDef); UniqueKeyPolicy uniqueKeyPolicy = new UniqueKeyPolicy(); UniqueKey uniqueKey = new UniqueKey(); uniqueKey.setPaths(ImmutableList.of("/name", "/description")); uniqueKeyPolicy.setUniqueKeys(Collections.singleton(uniqueKey)); collectionDefinition.setUniqueKeyPolicy(uniqueKeyPolicy); - collection = client.createCollection(getDatabaseLink(), collectionDefinition, null).toBlocking().single().getResource(); + collection = database.createContainer(collectionDefinition).block().getContainer(); ObjectMapper om = new ObjectMapper(); - ObjectNode doc1 = om.readValue("{\"name\":\"عمر خیّام\",\"description\":\"poet\"}", ObjectNode.class); - ObjectNode doc3 = om.readValue("{\"name\":\"Rabindranath Tagore\",\"description\":\"poet\"}", ObjectNode.class); - ObjectNode doc2 = om.readValue("{\"name\":\"عمر خیّام\",\"description\":\"mathematician\"}", ObjectNode.class); + ObjectNode doc1 = om.readValue("{\"name\":\"عمر خیّام\",\"description\":\"poet\",\"id\": \""+ UUID.randomUUID().toString() +"\"}", ObjectNode.class); + ObjectNode doc3 = om.readValue("{\"name\":\"Rabindranath Tagore\",\"description\":\"poet\",\"id\": \""+ UUID.randomUUID().toString() +"\"}", ObjectNode.class); + ObjectNode doc2 = om.readValue("{\"name\":\"عمر خیّام\",\"description\":\"mathematician\",\"id\": \""+ UUID.randomUUID().toString() +"\"}", ObjectNode.class); - Document doc1Inserted = client.createDocument( - getCollectionLink(collection), doc1, null, false).toBlocking().single().getResource(); + CosmosItemSettings doc1Inserted = collection.createItem(doc1, new CosmosItemRequestOptions()).block().getCosmosItemSettings(); - client.replaceDocument(doc1Inserted.getSelfLink(), doc1Inserted, null).toBlocking().single(); // Replace with same values -- OK. + collection.getItem(doc1.get("id").asText(), PartitionKey.None).replace(doc1Inserted, new CosmosItemRequestOptions()).block().getCosmosItemSettings(); // Replace with same values -- OK. - Document doc2Inserted = client.createDocument(getCollectionLink(collection), doc2, null, false).toBlocking().single().getResource(); - Document doc2Replacement = new Document(doc1Inserted.toJson()); + CosmosItemSettings doc2Inserted = collection.createItem(doc2, new CosmosItemRequestOptions()).block().getCosmosItemSettings(); + CosmosItemSettings doc2Replacement = new CosmosItemSettings(doc1Inserted.toJson()); doc2Replacement.setId( doc2Inserted.getId()); try { - client.replaceDocument(doc2Inserted.getSelfLink(), doc2Replacement, null).toBlocking().single(); // Replace doc2 with values from doc1 -- Conflict. + collection.getItem(doc2Inserted.getId(), PartitionKey.None).replace(doc2Replacement, new CosmosItemRequestOptions()).block(); // Replace doc2 with values from doc1 -- Conflict. fail("Did not throw due to unique constraint"); } catch (RuntimeException ex) { @@ -158,16 +169,20 @@ public void replaceAndDeleteWithUniqueIndex() throws Exception { } doc3.put("id", doc1Inserted.getId()); - client.replaceDocument(doc1Inserted.getSelfLink(), doc3, null).toBlocking().single(); // Replace with values from doc3 -- OK. + collection.getItem(doc1Inserted.getId(), PartitionKey.None).replace(doc3).block(); // Replace with values from doc3 -- OK. - client.deleteDocument(doc1Inserted.getSelfLink(), null).toBlocking().single(); - client.createDocument(getCollectionLink(collection), doc1, null, false).toBlocking().single(); + collection.getItem(doc1Inserted.getId(), PartitionKey.None).delete().block(); + collection.createItem(doc1, new CosmosItemRequestOptions()).block(); } @Test(groups = { "long" }, timeOut = TIMEOUT) public void uniqueKeySerializationDeserialization() { - DocumentCollection collectionDefinition = new DocumentCollection(); - collectionDefinition.setId(UUID.randomUUID().toString()); + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.setPaths(paths); + + CosmosContainerSettings collectionDefinition = new CosmosContainerSettings(UUID.randomUUID().toString(), partitionKeyDef); UniqueKeyPolicy uniqueKeyPolicy = new UniqueKeyPolicy(); UniqueKey uniqueKey = new UniqueKey(); uniqueKey.setPaths(ImmutableList.of("/name", "/description")); @@ -191,11 +206,9 @@ public void uniqueKeySerializationDeserialization() { collectionDefinition.setIndexingPolicy(indexingPolicy); - DocumentCollection createdCollection = client.createCollection(database.getSelfLink(), collectionDefinition, - null).toBlocking().single().getResource(); + CosmosContainer createdCollection = database.createContainer(collectionDefinition).block().getContainer(); - DocumentCollection collection = client.readCollection(getCollectionLink(createdCollection), null) - .toBlocking().single().getResource(); + CosmosContainerSettings collection = createdCollection.read().block().getCosmosContainerSettings(); assertThat(collection.getUniqueKeyPolicy()).isNotNull(); assertThat(collection.getUniqueKeyPolicy().getUniqueKeys()).isNotNull(); @@ -213,29 +226,21 @@ private DocumentClientException getDocumentClientException(RuntimeException e) { return dce; } - private String getDatabaseLink() { - return database.getSelfLink(); - } - - public String getCollectionLink() { - return "dbs/" + database.getId() + "/colls/" + collection.getId(); - } - @BeforeClass(groups = { "long" }, timeOut = SETUP_TIMEOUT) public void beforeClass() { // set up the client - client = new AsyncDocumentClient.Builder() - .withServiceEndpoint(TestConfigurations.HOST) - .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) - .withConnectionPolicy(ConnectionPolicy.GetDefault()) - .withConsistencyLevel(ConsistencyLevel.Session).build(); + client = CosmosClient.builder() + .endpoint(TestConfigurations.HOST) + .key(TestConfigurations.MASTER_KEY) + .connectionPolicy(ConnectionPolicy.GetDefault()) + .consistencyLevel(ConsistencyLevel.Session).build(); database = createDatabase(client, databaseId); } @AfterClass(groups = { "long" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) public void afterClass() { - safeDeleteDatabase(client, databaseId); + safeDeleteDatabase(database); safeClose(client); } } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/UserCrudTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/UserCrudTest.java index ce47630b91ad7..2159a78724cea 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/UserCrudTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/UserCrudTest.java @@ -22,49 +22,48 @@ */ package com.microsoft.azure.cosmosdb.rx; -import static org.assertj.core.api.Assertions.assertThat; import java.util.UUID; -import com.microsoft.azure.cosmosdb.DatabaseForTest; -import com.microsoft.azure.cosmosdb.Permission; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.ResourceResponse; -import com.microsoft.azure.cosmosdb.User; - -import rx.Observable; - -import javax.net.ssl.SSLException; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosDatabase; +import com.microsoft.azure.cosmos.CosmosDatabaseForTest; +import com.microsoft.azure.cosmos.CosmosResponseValidator; +import com.microsoft.azure.cosmos.CosmosUser; +import com.microsoft.azure.cosmos.CosmosUserResponse; +import com.microsoft.azure.cosmos.CosmosUserSettings; +import reactor.core.publisher.Mono; public class UserCrudTest extends TestSuiteBase { - public final String databaseId = DatabaseForTest.generateId(); + public final String databaseId = CosmosDatabaseForTest.generateId(); - private Database createdDatabase; + private CosmosDatabase createdDatabase; - private AsyncDocumentClient client; + private CosmosClient client; @Factory(dataProvider = "clientBuilders") - public UserCrudTest(AsyncDocumentClient.Builder clientBuilder) { + public UserCrudTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @Test(groups = { "emulator" }, timeOut = TIMEOUT) public void createUser() throws Exception { //create user - User user = new User(); + CosmosUserSettings user = new CosmosUserSettings(); user.setId(UUID.randomUUID().toString()); - Observable> createObservable = client.createUser(getDatabaseLink(), user, null); + Mono createObservable = createdDatabase.createUser(user, null); // validate user creation - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .withId(user.getId()) .notNullEtag() .build(); @@ -75,16 +74,16 @@ public void createUser() throws Exception { public void readUser() throws Exception { //create user - User user = new User(); + CosmosUserSettings user = new CosmosUserSettings(); user.setId(UUID.randomUUID().toString()); - User readBackUser = client.createUser(getDatabaseLink(), user, null).toBlocking().single().getResource(); + CosmosUser readBackUser = createdDatabase.createUser(user, null).block().getUser(); // read user - Observable> readObservable = client.readUser(readBackUser.getSelfLink(), null); + Mono readObservable = readBackUser.read(null); //validate user read - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .withId(readBackUser.getId()) .notNullEtag() .build(); @@ -95,22 +94,22 @@ public void readUser() throws Exception { @Test(groups = { "emulator" }, timeOut = TIMEOUT) public void deleteUser() throws Exception { //create user - User user = new User(); + CosmosUserSettings user = new CosmosUserSettings(); user.setId(UUID.randomUUID().toString()); - User readBackUser = client.createUser(getDatabaseLink(), user, null).toBlocking().single().getResource(); + CosmosUser readBackUser = createdDatabase.createUser(user, null).block().getUser(); // delete user - Observable> deleteObservable = client.deleteUser(readBackUser.getSelfLink(), null); + Mono deleteObservable = readBackUser.delete(null); // validate user delete - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .nullResource() .build(); validateSuccess(deleteObservable, validator); // attempt to read the user which was deleted - Observable> readObservable = client.readUser(readBackUser.getSelfLink(), null); + Mono readObservable = readBackUser.read(null); FailureValidator notFoundValidator = new FailureValidator.Builder().resourceNotFound().build(); validateFailure(readObservable, notFoundValidator); } @@ -119,76 +118,48 @@ public void deleteUser() throws Exception { public void upsertUser() throws Exception { //create user - User user = new User(); + CosmosUserSettings user = new CosmosUserSettings(); user.setId(UUID.randomUUID().toString()); - User readBackUser = client.upsertUser(getDatabaseLink(), user, null).toBlocking().single().getResource(); - - // read user to validate creation - Observable> readObservable = client.readUser(readBackUser.getSelfLink(), null); + Mono upsertObservable = createdDatabase.upsertUser(user, null); - //validate user read - ResourceResponseValidator validatorForRead = new ResourceResponseValidator.Builder() - .withId(readBackUser.getId()) + //validate user upsert + CosmosResponseValidator validatorForUpsert = new CosmosResponseValidator.Builder() + .withId(user.getId()) .notNullEtag() .build(); - validateSuccess(readObservable, validatorForRead); - - client.readUsers(getDatabaseLink(), null).toBlocking().subscribe(users -> { - try { - int initialNumberOfUsers = users.getResults().size(); - //update user - readBackUser.setId(UUID.randomUUID().toString()); - - Observable> updateObservable = client.upsertUser(getDatabaseLink(), readBackUser, null); - - // validate user upsert - ResourceResponseValidator validatorForUpdate = new ResourceResponseValidator.Builder() - .withId(readBackUser.getId()) - .notNullEtag() - .build(); - - validateSuccess(updateObservable, validatorForUpdate); - - //verify that new user is added due to upsert with changed id - client.readUsers(getDatabaseLink(), null).toBlocking().subscribe(newUsers ->{ - int finalNumberOfUsers = newUsers.getResults().size(); - assertThat(finalNumberOfUsers).isEqualTo(initialNumberOfUsers + 1); - }); - } catch (Exception e) { - e.printStackTrace(); - } - }); + validateSuccess(upsertObservable, validatorForUpsert); } - + @Test(groups = { "emulator" }, timeOut = TIMEOUT) public void replaceUser() throws Exception { //create user - User user = new User(); + CosmosUserSettings user = new CosmosUserSettings(); user.setId(UUID.randomUUID().toString()); - User readBackUser = client.createUser(getDatabaseLink(), user, null).toBlocking().single().getResource(); + CosmosUserSettings readBackUser = createdDatabase.createUser(user, null).block().getCosmosUserSettings(); // read user to validate creation - Observable> readObservable = client.readUser(readBackUser.getSelfLink(), null); + Mono readObservable = createdDatabase.getUser(user.getId()).read(); //validate user read - ResourceResponseValidator validatorForRead = new ResourceResponseValidator.Builder() - .withId(readBackUser.getId()) + CosmosResponseValidator validatorForRead = new CosmosResponseValidator.Builder() + .withId(readBackUser.getId()) .notNullEtag() .build(); validateSuccess(readObservable, validatorForRead); //update user + String oldId = readBackUser.getId(); readBackUser.setId(UUID.randomUUID().toString()); - Observable> updateObservable = client.replaceUser(readBackUser, null); + Mono updateObservable = createdDatabase.getUser(oldId).replace(readBackUser, null); // validate user replace - ResourceResponseValidator validatorForUpdate = new ResourceResponseValidator.Builder() + CosmosResponseValidator validatorForUpdate = new CosmosResponseValidator.Builder() .withId(readBackUser.getId()) .notNullEtag() .build(); @@ -199,18 +170,12 @@ public void replaceUser() throws Exception { @BeforeClass(groups = { "emulator" }, timeOut = SETUP_TIMEOUT) public void beforeClass() { client = clientBuilder.build(); - Database d = new Database(); - d.setId(databaseId); - createdDatabase = createDatabase(client, d); + createdDatabase = createDatabase(client, databaseId); } @AfterClass(groups = { "emulator" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) public void afterClass() { - safeDeleteDatabase(client, createdDatabase.getId()); + safeDeleteDatabase(createdDatabase); safeClose(client); } - - private String getDatabaseLink() { - return createdDatabase.getSelfLink(); - } } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/UserDefinedFunctionCrudTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/UserDefinedFunctionCrudTest.java index ed03ec2026b2a..81f6109709890 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/UserDefinedFunctionCrudTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/UserDefinedFunctionCrudTest.java @@ -24,43 +24,44 @@ import java.util.UUID; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.DocumentCollection; -import com.microsoft.azure.cosmosdb.ResourceResponse; -import com.microsoft.azure.cosmosdb.UserDefinedFunction; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; - -import rx.Observable; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosRequestOptions; +import com.microsoft.azure.cosmos.CosmosResponse; +import com.microsoft.azure.cosmos.CosmosResponseValidator; +import com.microsoft.azure.cosmos.CosmosUserDefinedFunction; +import com.microsoft.azure.cosmos.CosmosUserDefinedFunctionResponse; +import com.microsoft.azure.cosmos.CosmosUserDefinedFunctionSettings; +import reactor.core.publisher.Mono; public class UserDefinedFunctionCrudTest extends TestSuiteBase { - private Database createdDatabase; - private DocumentCollection createdCollection; - - private AsyncDocumentClient client; + private CosmosContainer createdCollection; + private CosmosClient client; @Factory(dataProvider = "clientBuildersWithDirect") - public UserDefinedFunctionCrudTest(AsyncDocumentClient.Builder clientBuilder) { + public UserDefinedFunctionCrudTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @Test(groups = { "simple" }, timeOut = TIMEOUT) public void createUserDefinedFunction() throws Exception { // create udf - UserDefinedFunction udf = new UserDefinedFunction(); + CosmosUserDefinedFunctionSettings udf = new CosmosUserDefinedFunctionSettings(); udf.setId(UUID.randomUUID().toString()); udf.setBody("function() {var x = 10;}"); - Observable> createObservable = client.createUserDefinedFunction(getCollectionLink(), udf, null); + Mono createObservable = createdCollection.createUserDefinedFunction(udf, new CosmosRequestOptions()); // validate udf creation - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .withId(udf.getId()) .withUserDefinedFunctionBody("function() {var x = 10;}") .notNullEtag() @@ -71,18 +72,17 @@ public void createUserDefinedFunction() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void readUserDefinedFunction() throws Exception { // create a udf - UserDefinedFunction udf = new UserDefinedFunction(); + CosmosUserDefinedFunctionSettings udf = new CosmosUserDefinedFunctionSettings(); udf.setId(UUID.randomUUID().toString()); udf.setBody("function() {var x = 10;}"); - UserDefinedFunction readBackUdf = client.createUserDefinedFunction(getCollectionLink(), udf, null).toBlocking().single().getResource(); - + CosmosUserDefinedFunction readBackUdf = createdCollection.createUserDefinedFunction(udf, new CosmosRequestOptions()).block().getCosmosUserDefinedFunction(); // read udf waitIfNeededForReplicasToCatchUp(clientBuilder); - Observable> readObservable = client.readUserDefinedFunction(readBackUdf.getSelfLink(), null); + Mono readObservable = readBackUdf.read(null); //validate udf read - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .withId(udf.getId()) .withUserDefinedFunctionBody("function() {var x = 10;}") .notNullEtag() @@ -93,16 +93,16 @@ public void readUserDefinedFunction() throws Exception { @Test(groups = { "simple" }, timeOut = TIMEOUT) public void deleteUserDefinedFunction() throws Exception { // create a udf - UserDefinedFunction udf = new UserDefinedFunction(); + CosmosUserDefinedFunctionSettings udf = new CosmosUserDefinedFunctionSettings(); udf.setId(UUID.randomUUID().toString()); udf.setBody("function() {var x = 10;}"); - UserDefinedFunction readBackUdf = client.createUserDefinedFunction(getCollectionLink(), udf, null).toBlocking().single().getResource(); + CosmosUserDefinedFunction readBackUdf = createdCollection.createUserDefinedFunction(udf, new CosmosRequestOptions()).block().getCosmosUserDefinedFunction(); // delete udf - Observable> deleteObservable = client.deleteUserDefinedFunction(readBackUdf.getSelfLink(), null); + Mono deleteObservable = readBackUdf.delete(new CosmosRequestOptions()); // validate udf delete - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .nullResource() .build(); validateSuccess(deleteObservable, validator); @@ -111,16 +111,12 @@ public void deleteUserDefinedFunction() throws Exception { @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) public void beforeClass() { client = clientBuilder.build(); - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_MULTI_PARTITION_COLLECTION; + createdCollection = getSharedMultiPartitionCosmosContainer(client); } - + @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) public void afterClass() { safeClose(client); } - private String getCollectionLink() { - return createdCollection.getSelfLink(); - } } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/UserDefinedFunctionQueryTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/UserDefinedFunctionQueryTest.java index b8ffbc79fe9f0..aa0449c0a7f30 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/UserDefinedFunctionQueryTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/UserDefinedFunctionQueryTest.java @@ -29,37 +29,37 @@ import java.util.UUID; import java.util.stream.Collectors; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosRequestOptions; +import com.microsoft.azure.cosmos.CosmosUserDefinedFunctionSettings; import com.microsoft.azure.cosmosdb.Database; import com.microsoft.azure.cosmosdb.DocumentClientException; -import com.microsoft.azure.cosmosdb.DocumentCollection; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; -import com.microsoft.azure.cosmosdb.UserDefinedFunction; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; - -import rx.Observable; +import reactor.core.publisher.Flux; public class UserDefinedFunctionQueryTest extends TestSuiteBase { private Database createdDatabase; - private DocumentCollection createdCollection; - private List createdUDF = new ArrayList<>(); + private CosmosContainer createdCollection; + private List createdUDF = new ArrayList<>(); - private AsyncDocumentClient client; + private CosmosClient client; public String getCollectionLink() { return Utils.getCollectionNameLink(createdDatabase.getId(), createdCollection.getId()); } @Factory(dataProvider = "clientBuildersWithDirect") - public UserDefinedFunctionQueryTest(Builder clientBuilder) { + public UserDefinedFunctionQueryTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @@ -71,19 +71,18 @@ public void queryWithFilter() throws Exception { FeedOptions options = new FeedOptions(); options.setMaxItemCount(5); - Observable> queryObservable = client - .queryUserDefinedFunctions(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryUserDefinedFunctions(query, options); - List expectedDocs = createdUDF.stream().filter(sp -> filterId.equals(sp.getId()) ).collect(Collectors.toList()); + List expectedDocs = createdUDF.stream().filter(sp -> filterId.equals(sp.getId()) ).collect(Collectors.toList()); assertThat(expectedDocs).isNotEmpty(); int expectedPageSize = (expectedDocs.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .totalSize(expectedDocs.size()) .exactlyContainsInAnyOrder(expectedDocs.stream().map(d -> d.getResourceId()).collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .pageSatisfy(0, new FeedResponseValidator.Builder() + .pageSatisfy(0, new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); @@ -96,13 +95,12 @@ public void query_NoResults() throws Exception { String query = "SELECT * from root r where r.id = '2'"; FeedOptions options = new FeedOptions(); options.setEnableCrossPartitionQuery(true); - Observable> queryObservable = client - .queryUserDefinedFunctions(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryUserDefinedFunctions(query, options); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .containsExactly(new ArrayList<>()) .numberOfPages(1) - .pageSatisfy(0, new FeedResponseValidator.Builder() + .pageSatisfy(0, new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); validateQuerySuccess(queryObservable, validator); @@ -115,21 +113,20 @@ public void queryAll() throws Exception { FeedOptions options = new FeedOptions(); options.setMaxItemCount(3); options.setEnableCrossPartitionQuery(true); - Observable> queryObservable = client - .queryUserDefinedFunctions(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryUserDefinedFunctions(query, options); - List expectedDocs = createdUDF; + List expectedDocs = createdUDF; int expectedPageSize = (expectedDocs.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - FeedResponseListValidator validator = new FeedResponseListValidator - .Builder() + FeedResponseListValidator validator = new FeedResponseListValidator + .Builder() .exactlyContainsInAnyOrder(expectedDocs .stream() .map(d -> d.getResourceId()) .collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .allPagesSatisfy(new FeedResponseValidator.Builder() + .allPagesSatisfy(new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); validateQuerySuccess(queryObservable, validator); @@ -140,8 +137,7 @@ public void invalidQuerySytax() throws Exception { String query = "I am an invalid query"; FeedOptions options = new FeedOptions(); options.setEnableCrossPartitionQuery(true); - Observable> queryObservable = client - .queryUserDefinedFunctions(getCollectionLink(), query, options); + Flux> queryObservable = createdCollection.queryUserDefinedFunctions(query, options); FailureValidator validator = new FailureValidator.Builder() .instanceOf(DocumentClientException.class) @@ -151,20 +147,19 @@ public void invalidQuerySytax() throws Exception { validateQueryFailure(queryObservable, validator); } - public UserDefinedFunction createUserDefinedFunction(AsyncDocumentClient client) { - UserDefinedFunction storedProcedure = getUserDefinedFunctionDef(); - return client.createUserDefinedFunction(getCollectionLink(), storedProcedure, null).toBlocking().single().getResource(); + public CosmosUserDefinedFunctionSettings createUserDefinedFunction(CosmosContainer cosmosContainer) { + CosmosUserDefinedFunctionSettings storedProcedure = getUserDefinedFunctionDef(); + return cosmosContainer.createUserDefinedFunction(storedProcedure, new CosmosRequestOptions()).block().getCosmosUserDefinedFunctionSettings(); } @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) public void beforeClass() throws Exception { client = clientBuilder.build(); - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY; - truncateCollection(SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); for(int i = 0; i < 5; i++) { - createdUDF.add(createUserDefinedFunction(client)); + createdUDF.add(createUserDefinedFunction(createdCollection)); } waitIfNeededForReplicasToCatchUp(clientBuilder); @@ -175,8 +170,8 @@ public void afterClass() { safeClose(client); } - private static UserDefinedFunction getUserDefinedFunctionDef() { - UserDefinedFunction udf = new UserDefinedFunction(); + private static CosmosUserDefinedFunctionSettings getUserDefinedFunctionDef() { + CosmosUserDefinedFunctionSettings udf = new CosmosUserDefinedFunctionSettings(); udf.setId(UUID.randomUUID().toString()); udf.setBody("function() {var x = 10;}"); return udf; diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/UserDefinedFunctionUpsertReplaceTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/UserDefinedFunctionUpsertReplaceTest.java index 5d35cf792b2b6..793b5ad6581bc 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/UserDefinedFunctionUpsertReplaceTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/UserDefinedFunctionUpsertReplaceTest.java @@ -24,6 +24,7 @@ import java.util.UUID; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import com.microsoft.azure.cosmosdb.internal.directconnectivity.Protocol; import org.testng.SkipException; import org.testng.annotations.AfterClass; @@ -31,91 +32,42 @@ import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.Database; -import com.microsoft.azure.cosmosdb.DocumentCollection; -import com.microsoft.azure.cosmosdb.ResourceResponse; -import com.microsoft.azure.cosmosdb.UserDefinedFunction; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; - -import rx.Observable; - -import javax.net.ssl.SSLException; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosRequestOptions; +import com.microsoft.azure.cosmos.CosmosResponseValidator; +import com.microsoft.azure.cosmos.CosmosUserDefinedFunctionResponse; +import com.microsoft.azure.cosmos.CosmosUserDefinedFunctionSettings; +import com.microsoft.azure.cosmosdb.RequestOptions; +import reactor.core.publisher.Mono; public class UserDefinedFunctionUpsertReplaceTest extends TestSuiteBase { - private Database createdDatabase; - private DocumentCollection createdCollection; + private CosmosContainer createdCollection; - private AsyncDocumentClient client; + private CosmosClient client; @Factory(dataProvider = "clientBuildersWithDirect") - public UserDefinedFunctionUpsertReplaceTest(AsyncDocumentClient.Builder clientBuilder) { + public UserDefinedFunctionUpsertReplaceTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } - @Test(groups = { "simple" }, timeOut = TIMEOUT) - public void upsertUserDefinedFunction() throws Exception { - - // create a udf - UserDefinedFunction udf = new UserDefinedFunction(); - udf.setId(UUID.randomUUID().toString()); - udf.setBody("function() {var x = 10;}"); - - UserDefinedFunction readBackUdf = null; - - try { - readBackUdf = client.upsertUserDefinedFunction(getCollectionLink(), udf, null).toBlocking().single().getResource(); - } catch (Throwable error) { - if (this.clientBuilder.configs.getProtocol() == Protocol.Tcp) { - String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.desiredConsistencyLevel); - logger.info(message, error); - throw new SkipException(message, error); - } - throw error; - } - - // read udf to validate creation - waitIfNeededForReplicasToCatchUp(clientBuilder); - Observable> readObservable = client.readUserDefinedFunction(readBackUdf.getSelfLink(), null); - - // validate udf create - ResourceResponseValidator validatorForRead = new ResourceResponseValidator.Builder() - .withId(readBackUdf.getId()) - .withUserDefinedFunctionBody("function() {var x = 10;}") - .notNullEtag() - .build(); - validateSuccess(readObservable, validatorForRead); - - //update udf - readBackUdf.setBody("function() {var x = 11;}"); - - Observable> updateObservable = client.upsertUserDefinedFunction(getCollectionLink(), readBackUdf, null); - - // validate udf update - ResourceResponseValidator validatorForUpdate = new ResourceResponseValidator.Builder() - .withId(readBackUdf.getId()) - .withUserDefinedFunctionBody("function() {var x = 11;}") - .notNullEtag() - .build(); - validateSuccess(updateObservable, validatorForUpdate); - } - @Test(groups = { "simple" }, timeOut = TIMEOUT) public void replaceUserDefinedFunction() throws Exception { // create a udf - UserDefinedFunction udf = new UserDefinedFunction(); + CosmosUserDefinedFunctionSettings udf = new CosmosUserDefinedFunctionSettings(); udf.setId(UUID.randomUUID().toString()); udf.setBody("function() {var x = 10;}"); - UserDefinedFunction readBackUdf = null; + CosmosUserDefinedFunctionSettings readBackUdf = null; try { - readBackUdf = client.createUserDefinedFunction(getCollectionLink(), udf, null).toBlocking().single().getResource(); + readBackUdf = createdCollection.createUserDefinedFunction(udf, new CosmosRequestOptions()).block().getCosmosUserDefinedFunctionSettings(); } catch (Throwable error) { - if (this.clientBuilder.configs.getProtocol() == Protocol.Tcp) { - String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.desiredConsistencyLevel); + if (this.clientBuilder.getConfigs().getProtocol() == Protocol.Tcp) { + String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.getDesiredConsistencyLevel()); logger.info(message, error); throw new SkipException(message, error); } @@ -124,10 +76,10 @@ public void replaceUserDefinedFunction() throws Exception { // read udf to validate creation waitIfNeededForReplicasToCatchUp(clientBuilder); - Observable> readObservable = client.readUserDefinedFunction(readBackUdf.getSelfLink(), null); + Mono readObservable = createdCollection.getUserDefinedFunction(readBackUdf.getId()).read(new RequestOptions()); // validate udf creation - ResourceResponseValidator validatorForRead = new ResourceResponseValidator.Builder() + CosmosResponseValidator validatorForRead = new CosmosResponseValidator.Builder() .withId(readBackUdf.getId()) .withUserDefinedFunctionBody("function() {var x = 10;}") .notNullEtag() @@ -137,10 +89,10 @@ public void replaceUserDefinedFunction() throws Exception { //update udf readBackUdf.setBody("function() {var x = 11;}"); - Observable> replaceObservable = client.replaceUserDefinedFunction(readBackUdf, null); + Mono replaceObservable = createdCollection.getUserDefinedFunction(readBackUdf.getId()).replace(readBackUdf, new RequestOptions()); //validate udf replace - ResourceResponseValidator validatorForReplace = new ResourceResponseValidator.Builder() + CosmosResponseValidator validatorForReplace = new CosmosResponseValidator.Builder() .withId(readBackUdf.getId()) .withUserDefinedFunctionBody("function() {var x = 11;}") .notNullEtag() @@ -151,16 +103,12 @@ public void replaceUserDefinedFunction() throws Exception { @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) public void beforeClass() { client = clientBuilder.build(); - createdDatabase = SHARED_DATABASE; - truncateCollection(createdCollection = SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); } @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) public void afterClass() { safeClose(client); } - - private String getCollectionLink() { - return createdCollection.getSelfLink(); - } } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/UserQueryTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/UserQueryTest.java index a1feb7046b18c..5003dd13cfe1e 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/UserQueryTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/UserQueryTest.java @@ -29,35 +29,33 @@ import java.util.UUID; import java.util.stream.Collectors; -import com.microsoft.azure.cosmosdb.DatabaseForTest; +import com.microsoft.azure.cosmos.CosmosClientBuilder; import org.apache.commons.lang3.StringUtils; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import com.microsoft.azure.cosmosdb.Database; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosDatabase; +import com.microsoft.azure.cosmos.CosmosDatabaseForTest; +import com.microsoft.azure.cosmos.CosmosUserSettings; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; -import com.microsoft.azure.cosmosdb.User; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; -import rx.Observable; +import reactor.core.publisher.Flux; public class UserQueryTest extends TestSuiteBase { - public final String databaseId = DatabaseForTest.generateId(); + public final String databaseId = CosmosDatabaseForTest.generateId(); - private List createdUsers = new ArrayList<>(); + private List createdUsers = new ArrayList<>(); - private AsyncDocumentClient client; + private CosmosClient client; + private CosmosDatabase createdDatabase; - private String getDatabaseLink() { - return Utils.getDatabaseNameLink(databaseId); - } - @Factory(dataProvider = "clientBuilders") - public UserQueryTest(Builder clientBuilder) { + public UserQueryTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @@ -69,20 +67,20 @@ public void queryUsersWithFilter() throws Exception { FeedOptions options = new FeedOptions(); options.setMaxItemCount(5); - Observable> queryObservable = client.queryUsers(getDatabaseLink(), query, options); + Flux> queryObservable = createdDatabase.queryUsers(query, options); - List expectedUsers = createdUsers.stream() + List expectedUsers = createdUsers.stream() .filter(c -> StringUtils.equals(filterUserId, c.getId()) ).collect(Collectors.toList()); assertThat(expectedUsers).isNotEmpty(); int expectedPageSize = (expectedUsers.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .totalSize(expectedUsers.size()) .exactlyContainsInAnyOrder(expectedUsers.stream().map(d -> d.getResourceId()).collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .pageSatisfy(0, new FeedResponseValidator.Builder() + .pageSatisfy(0, new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); @@ -97,19 +95,19 @@ public void queryAllUsers() throws Exception { FeedOptions options = new FeedOptions(); options.setMaxItemCount(2); String databaseLink = Utils.getDatabaseNameLink(databaseId); - Observable> queryObservable = client.queryUsers(databaseLink, query, options); + Flux> queryObservable = createdDatabase.queryUsers(query, options); - List expectedUsers = createdUsers; + List expectedUsers = createdUsers; assertThat(expectedUsers).isNotEmpty(); int expectedPageSize = (expectedUsers.size() + options.getMaxItemCount() - 1) / options.getMaxItemCount(); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .totalSize(expectedUsers.size()) .exactlyContainsInAnyOrder(expectedUsers.stream().map(d -> d.getResourceId()).collect(Collectors.toList())) .numberOfPages(expectedPageSize) - .pageSatisfy(0, new FeedResponseValidator.Builder() + .pageSatisfy(0, new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); @@ -121,12 +119,12 @@ public void queryUsers_NoResults() throws Exception { String query = "SELECT * from root r where r.id = '2'"; FeedOptions options = new FeedOptions(); - Observable> queryObservable = client.queryUsers(getDatabaseLink(), query, options); + Flux> queryObservable = createdDatabase.queryUsers(query, options); - FeedResponseListValidator validator = new FeedResponseListValidator.Builder() + FeedResponseListValidator validator = new FeedResponseListValidator.Builder() .containsExactly(new ArrayList<>()) .numberOfPages(1) - .pageSatisfy(0, new FeedResponseValidator.Builder() + .pageSatisfy(0, new FeedResponseValidator.Builder() .requestChargeGreaterThanOrEqualTo(1.0).build()) .build(); validateQuerySuccess(queryObservable, validator); @@ -136,14 +134,12 @@ public void queryUsers_NoResults() throws Exception { public void beforeClass() throws Exception { client = clientBuilder.build(); - Database d1 = new Database(); - d1.setId(databaseId); - createDatabase(client, d1); + createdDatabase = createDatabase(client, databaseId); for(int i = 0; i < 5; i++) { - User user = new User(); + CosmosUserSettings user = new CosmosUserSettings(); user.setId(UUID.randomUUID().toString()); - createdUsers.add(createUser(client, databaseId, user)); + createdUsers.add(createUser(client, databaseId, user).read().block().getCosmosUserSettings()); } waitIfNeededForReplicasToCatchUp(clientBuilder); @@ -151,7 +147,7 @@ public void beforeClass() throws Exception { @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) public void afterClass() { - safeDeleteDatabase(client, databaseId); + safeDeleteDatabase(createdDatabase); safeClose(client); } } diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/VeryLargeDocumentQueryTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/VeryLargeDocumentQueryTest.java index bbb9072868dbf..99750757ed8d0 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/VeryLargeDocumentQueryTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/VeryLargeDocumentQueryTest.java @@ -22,20 +22,26 @@ */ package com.microsoft.azure.cosmosdb.rx; +import com.microsoft.azure.cosmos.CosmosClient; +import com.microsoft.azure.cosmos.CosmosClientBuilder; +import com.microsoft.azure.cosmos.CosmosContainer; +import com.microsoft.azure.cosmos.CosmosItemRequestOptions; +import com.microsoft.azure.cosmos.CosmosItemResponse; +import com.microsoft.azure.cosmos.CosmosResponseValidator; import com.microsoft.azure.cosmosdb.Database; import com.microsoft.azure.cosmosdb.Document; -import com.microsoft.azure.cosmosdb.DocumentCollection; -import com.microsoft.azure.cosmosdb.ResourceResponse; +import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.RetryAnalyzer; import com.microsoft.azure.cosmosdb.internal.directconnectivity.Protocol; -import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; + +import reactor.core.publisher.Mono; + import org.apache.commons.lang3.StringUtils; import org.testng.SkipException; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Factory; import org.testng.annotations.Test; -import rx.Observable; import java.util.UUID; @@ -45,28 +51,30 @@ public class VeryLargeDocumentQueryTest extends TestSuiteBase { private final static int TIMEOUT = 60000; private final static int SETUP_TIMEOUT = 60000; private Database createdDatabase; - private DocumentCollection createdCollection; + private CosmosContainer createdCollection; - private AsyncDocumentClient client; + private CosmosClient client; @Factory(dataProvider = "simpleClientBuildersWithDirect") - public VeryLargeDocumentQueryTest(Builder clientBuilder) { + public VeryLargeDocumentQueryTest(CosmosClientBuilder clientBuilder) { this.clientBuilder = clientBuilder; } @Test(groups = { "emulator" }, timeOut = TIMEOUT, retryAnalyzer = RetryAnalyzer.class) - public void queryLargeDocuments() { + public void queryLargeDocuments() throws InterruptedException { int cnt = 5; for(int i = 0; i < cnt; i++) { createLargeDocument(); } try { - validateQuerySuccess(client.queryDocuments(getCollectionLink(), "SELECT * FROM r", null), + FeedOptions options = new FeedOptions(); + options.setEnableCrossPartitionQuery(true); + validateQuerySuccess(createdCollection.queryItems("SELECT * FROM r", options), new FeedResponseListValidator.Builder().totalSize(cnt).build()); } catch (Throwable error) { - if (this.clientBuilder.configs.getProtocol() == Protocol.Tcp) { - String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.desiredConsistencyLevel); + if (this.clientBuilder.getConfigs().getProtocol() == Protocol.Tcp) { + String message = String.format("Direct TCP test failure ignored: desiredConsistencyLevel=%s", this.clientBuilder.getDesiredConsistencyLevel()); logger.info(message, error); throw new SkipException(message, error); } @@ -74,17 +82,16 @@ public void queryLargeDocuments() { } } - private void createLargeDocument() { + private void createLargeDocument() throws InterruptedException { Document docDefinition = getDocumentDefinition(); //Keep size as ~ 1.999MB to account for size of other props int size = (int) (ONE_MB * 1.999); docDefinition.set("largeString", StringUtils.repeat("x", size)); - Observable> createObservable = client - .createDocument(getCollectionLink(), docDefinition, null, false); + Mono createObservable = createdCollection.createItem(docDefinition, new CosmosItemRequestOptions()); - ResourceResponseValidator validator = new ResourceResponseValidator.Builder() + CosmosResponseValidator validator = new CosmosResponseValidator.Builder() .withId(docDefinition.getId()) .build(); @@ -94,9 +101,8 @@ private void createLargeDocument() { @BeforeClass(groups = { "emulator" }, timeOut = 2 * SETUP_TIMEOUT) public void beforeClass() throws Exception { client = clientBuilder.build(); - createdDatabase = SHARED_DATABASE; - createdCollection = SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY; - truncateCollection(SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY); + createdCollection = getSharedMultiPartitionCosmosContainer(client); + truncateCollection(createdCollection); } @AfterClass(groups = { "emulator" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/ConsistencyTests1.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/ConsistencyTests1.java index a7d110a9b8c3e..4d06338211b9d 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/ConsistencyTests1.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/ConsistencyTests1.java @@ -303,4 +303,4 @@ private static User getUserDefinition() { user.setId(USER_NAME); return user; } -} +} \ No newline at end of file diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/ConsistencyTestsBase.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/ConsistencyTestsBase.java index fd2a6dba097cd..fd02c4a8989c2 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/ConsistencyTestsBase.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/ConsistencyTestsBase.java @@ -53,7 +53,6 @@ import com.microsoft.azure.cosmosdb.rx.FailureValidator; import com.microsoft.azure.cosmosdb.rx.ResourceResponseValidator; import com.microsoft.azure.cosmosdb.rx.TestConfigurations; -import com.microsoft.azure.cosmosdb.rx.TestSuiteBase; import org.apache.commons.collections4.map.UnmodifiableMap; import org.apache.commons.lang3.StringUtils; import org.testng.SkipException; @@ -858,4 +857,4 @@ private boolean isSessionEqual(SessionContainer sessionContainer1, SessionContai return true; } -} +} \ No newline at end of file diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/DocumentQuerySpyWireContentTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/DocumentQuerySpyWireContentTest.java index 79e792a5c0cfa..0e623bda8e3ff 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/DocumentQuerySpyWireContentTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/DocumentQuerySpyWireContentTest.java @@ -43,17 +43,11 @@ import com.microsoft.azure.cosmosdb.DocumentCollection; import com.microsoft.azure.cosmosdb.FeedOptions; import com.microsoft.azure.cosmosdb.FeedResponse; -import com.microsoft.azure.cosmosdb.IncludedPath; -import com.microsoft.azure.cosmosdb.Index; -import com.microsoft.azure.cosmosdb.IndexingPolicy; import com.microsoft.azure.cosmosdb.PartitionKey; -import com.microsoft.azure.cosmosdb.PartitionKeyDefinition; -import com.microsoft.azure.cosmosdb.RequestOptions; import com.microsoft.azure.cosmosdb.internal.HttpConstants; import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; import com.microsoft.azure.cosmosdb.rx.SpyClientBuilder; -import com.microsoft.azure.cosmosdb.rx.TestSuiteBase; import com.microsoft.azure.cosmosdb.rx.Utils; import io.netty.buffer.ByteBuf; @@ -219,4 +213,4 @@ private static Document getDocumentDefinition(int cnt) { , uuid, cnt, cnt)); return doc; } -} +} \ No newline at end of file diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/NetworkFailureTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/NetworkFailureTest.java index 4ce4abf58452b..81ffc4d664447 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/NetworkFailureTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/NetworkFailureTest.java @@ -28,9 +28,7 @@ import com.microsoft.azure.cosmosdb.ResourceResponse; import com.microsoft.azure.cosmosdb.internal.ResourceType; import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; -import com.microsoft.azure.cosmosdb.rx.CollectionCrudTest; import com.microsoft.azure.cosmosdb.rx.FailureValidator; -import com.microsoft.azure.cosmosdb.rx.TestSuiteBase; import org.mockito.Mockito; import org.testng.annotations.AfterClass; import org.testng.annotations.Factory; @@ -97,4 +95,4 @@ public void afterClass() { safeDeleteCollection(client, collectionDefinition); client.close(); } -} +} \ No newline at end of file diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/RetryCreateDocumentTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/RetryCreateDocumentTest.java index 536ac8e7c38bf..64fb216cc7624 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/RetryCreateDocumentTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/RetryCreateDocumentTest.java @@ -36,7 +36,6 @@ import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; import com.microsoft.azure.cosmosdb.rx.FailureValidator; import com.microsoft.azure.cosmosdb.rx.ResourceResponseValidator; -import com.microsoft.azure.cosmosdb.rx.TestSuiteBase; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; @@ -214,4 +213,4 @@ private Document getDocumentDefinition() { public void afterClass() { safeClose(client); } -} +} \ No newline at end of file diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/RetryThrottleTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/RetryThrottleTest.java index 63498109452c4..efc3b44043e54 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/RetryThrottleTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/RetryThrottleTest.java @@ -24,17 +24,14 @@ package com.microsoft.azure.cosmosdb.rx.internal; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.fail; import static org.mockito.Matchers.anyObject; import static org.mockito.Mockito.doAnswer; -import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; -import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.testng.annotations.AfterClass; @@ -48,7 +45,6 @@ import com.microsoft.azure.cosmosdb.Document; import com.microsoft.azure.cosmosdb.DocumentClientException; import com.microsoft.azure.cosmosdb.DocumentCollection; -import com.microsoft.azure.cosmosdb.RequestOptions; import com.microsoft.azure.cosmosdb.ResourceResponse; import com.microsoft.azure.cosmosdb.RetryOptions; import com.microsoft.azure.cosmosdb.internal.HttpConstants; @@ -57,7 +53,6 @@ import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; import com.microsoft.azure.cosmosdb.rx.ResourceResponseValidator; import com.microsoft.azure.cosmosdb.rx.TestConfigurations; -import com.microsoft.azure.cosmosdb.rx.TestSuiteBase; import rx.Observable; @@ -162,7 +157,7 @@ private void afterMethod() { public void beforeClass() { // set up the client database = SHARED_DATABASE; - collection = SHARED_SINGLE_PARTITION_COLLECTION_WITHOUT_PARTITION_KEY; + collection = SHARED_SINGLE_PARTITION_COLLECTION; } private Document getDocumentDefinition() { @@ -179,4 +174,4 @@ private Document getDocumentDefinition() { @AfterClass(groups = { "long" }, timeOut = SHUTDOWN_TIMEOUT, enabled = false) public void afterClass() { } -} +} \ No newline at end of file diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/RxDocumentClientUnderTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/RxDocumentClientUnderTest.java index 3cf2844149a31..a59078f224f73 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/RxDocumentClientUnderTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/RxDocumentClientUnderTest.java @@ -22,6 +22,7 @@ */ package com.microsoft.azure.cosmosdb.rx.internal; +import com.microsoft.azure.cosmos.ClientUnderTestBuilder; import com.microsoft.azure.cosmosdb.ConnectionPolicy; import com.microsoft.azure.cosmosdb.ConsistencyLevel; import com.microsoft.azure.cosmosdb.ISessionContainer; @@ -46,7 +47,7 @@ import static org.mockito.Mockito.doAnswer; /** - * This class in conjunction with {@link com.microsoft.azure.cosmosdb.rx.ClientUnderTestBuilder} + * This class in conjunction with {@link ClientUnderTestBuilder} * provides the functionality for spying the client behavior and the http requests sent. */ public class RxDocumentClientUnderTest extends RxDocumentClientImpl { diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/SessionTest.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/SessionTest.java index 209bc4e792df6..7cb4c83c7b319 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/SessionTest.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/SessionTest.java @@ -26,9 +26,11 @@ import com.microsoft.azure.cosmosdb.Database; import com.microsoft.azure.cosmosdb.Document; import com.microsoft.azure.cosmosdb.DocumentCollection; +import com.microsoft.azure.cosmosdb.PartitionKey; +import com.microsoft.azure.cosmosdb.PartitionKeyDefinition; +import com.microsoft.azure.cosmosdb.RequestOptions; import com.microsoft.azure.cosmosdb.internal.HttpConstants; import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; -import com.microsoft.azure.cosmosdb.rx.TestSuiteBase; import io.netty.buffer.ByteBuf; import io.netty.handler.codec.http.HttpMethod; @@ -46,6 +48,7 @@ import java.io.UnsupportedEncodingException; import java.lang.reflect.Method; import java.net.URLDecoder; +import java.util.ArrayList; import java.util.List; import java.util.UUID; import java.util.stream.Collectors; @@ -61,6 +64,7 @@ public class SessionTest extends TestSuiteBase { private SpyClientUnderTestFactory.SpyBaseClass> spyClient; private AsyncDocumentClient houseKeepingClient; private ConnectionMode connectionMode; + private RequestOptions options; @Factory(dataProvider = "clientBuildersWithDirectSession") public SessionTest(AsyncDocumentClient.Builder clientBuilder) { @@ -80,9 +84,16 @@ public Object[] sessionTestArgProvider() { @BeforeClass(groups = { "simple" }, timeOut = SETUP_TIMEOUT) public void beforeClass() { createdDatabase = SHARED_DATABASE; - + + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.setPaths(paths); + DocumentCollection collection = new DocumentCollection(); collection.setId(collectionId); + collection.setPartitionKey(partitionKeyDef); + createdCollection = createCollection(createGatewayHouseKeepingDocumentClient().build(), createdDatabase.getId(), collection, null); houseKeepingClient = clientBuilder.build(); @@ -93,6 +104,8 @@ public void beforeClass() { } else { spyClient = SpyClientUnderTestFactory.createClientUnderTest(clientBuilder); } + options = new RequestOptions(); + options.setPartitionKey(PartitionKey.None); } @AfterClass(groups = { "simple" }, timeOut = SHUTDOWN_TIMEOUT, alwaysRun = true) @@ -131,12 +144,12 @@ public void sessionConsistency_ReadYourWrites(boolean isNameBased) { assertThat(getSessionTokensInRequests().get(3 * i + 0)).isNotEmpty(); } - spyClient.readDocument(getDocumentLink(documentCreated, isNameBased), null).toBlocking().single(); + spyClient.readDocument(getDocumentLink(documentCreated, isNameBased), options).toBlocking().single(); assertThat(getSessionTokensInRequests()).hasSize(3 * i + 2); assertThat(getSessionTokensInRequests().get(3 * i + 1)).isNotEmpty(); - spyClient.readDocument(getDocumentLink(documentCreated, isNameBased), null).toBlocking().single(); + spyClient.readDocument(getDocumentLink(documentCreated, isNameBased), options).toBlocking().single(); assertThat(getSessionTokensInRequests()).hasSize(3 * i + 3); assertThat(getSessionTokensInRequests().get(3 * i + 2)).isNotEmpty(); @@ -152,7 +165,7 @@ public void sessionTokenInDocumentRead(boolean isNameBased) throws UnsupportedEn .getResource(); final String documentLink = getDocumentLink(document, isNameBased); - spyClient.readDocument(documentLink, null).toBlocking().single() + spyClient.readDocument(documentLink, options).toBlocking().single() .getResource(); List> documentReadHttpRequests = spyClient.getCapturedRequests().stream() diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/StoreHeaderTests.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/StoreHeaderTests.java index ecdb689b542b9..c7efac21b137d 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/StoreHeaderTests.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/StoreHeaderTests.java @@ -27,7 +27,6 @@ import com.microsoft.azure.cosmosdb.DocumentCollection; import com.microsoft.azure.cosmosdb.RequestOptions; import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; -import com.microsoft.azure.cosmosdb.rx.TestSuiteBase; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; @@ -86,4 +85,4 @@ private Document getDocumentDefinition() { , uuid, uuid)); return doc; } -} +} \ No newline at end of file diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/TestSuiteBase.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/TestSuiteBase.java new file mode 100644 index 0000000000000..6465e8ed135e8 --- /dev/null +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/TestSuiteBase.java @@ -0,0 +1,1045 @@ +/* + * The MIT License (MIT) + * Copyright (c) 2018 Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.microsoft.azure.cosmosdb.rx.internal; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.spy; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.google.common.collect.ImmutableList; +import com.microsoft.azure.cosmosdb.DataType; +import com.microsoft.azure.cosmosdb.DatabaseForTest; +import com.microsoft.azure.cosmosdb.DocumentClientException; +import com.microsoft.azure.cosmosdb.IncludedPath; +import com.microsoft.azure.cosmosdb.Index; +import com.microsoft.azure.cosmosdb.IndexingPolicy; +import com.microsoft.azure.cosmosdb.RetryOptions; +import com.microsoft.azure.cosmosdb.SqlQuerySpec; +import com.microsoft.azure.cosmosdb.Undefined; +import com.microsoft.azure.cosmosdb.internal.PathParser; +import com.microsoft.azure.cosmosdb.internal.directconnectivity.Protocol; +import com.microsoft.azure.cosmosdb.rx.internal.Configs; +import org.apache.commons.lang3.ObjectUtils; +import org.apache.commons.lang3.StringUtils; +import org.mockito.stubbing.Answer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.AfterSuite; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.BeforeSuite; +import org.testng.annotations.DataProvider; + +import com.microsoft.azure.cosmosdb.CompositePath; +import com.microsoft.azure.cosmosdb.CompositePathSortOrder; +import com.microsoft.azure.cosmosdb.ConnectionMode; +import com.microsoft.azure.cosmosdb.ConnectionPolicy; +import com.microsoft.azure.cosmosdb.ConsistencyLevel; +import com.microsoft.azure.cosmosdb.Database; +import com.microsoft.azure.cosmosdb.Document; +import com.microsoft.azure.cosmosdb.DocumentCollection; +import com.microsoft.azure.cosmosdb.FeedOptions; +import com.microsoft.azure.cosmosdb.FeedResponse; +import com.microsoft.azure.cosmosdb.PartitionKey; +import com.microsoft.azure.cosmosdb.PartitionKeyDefinition; +import com.microsoft.azure.cosmosdb.RequestOptions; +import com.microsoft.azure.cosmosdb.Resource; +import com.microsoft.azure.cosmosdb.ResourceResponse; +import com.microsoft.azure.cosmosdb.User; +import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; +import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient.Builder; +import com.microsoft.azure.cosmosdb.rx.FailureValidator; +import com.microsoft.azure.cosmosdb.rx.FeedResponseListValidator; +import com.microsoft.azure.cosmosdb.rx.ResourceResponseValidator; +import com.microsoft.azure.cosmosdb.rx.TestConfigurations; +import com.microsoft.azure.cosmosdb.rx.Utils; + +import org.testng.annotations.Test; +import rx.Observable; +import rx.observers.TestSubscriber; + +public class TestSuiteBase { + private static final int DEFAULT_BULK_INSERT_CONCURRENCY_LEVEL = 500; + private static final ObjectMapper objectMapper = new ObjectMapper(); + protected static Logger logger = LoggerFactory.getLogger(TestSuiteBase.class.getSimpleName()); + protected static final int TIMEOUT = 40000; + protected static final int FEED_TIMEOUT = 40000; + protected static final int SETUP_TIMEOUT = 60000; + protected static final int SHUTDOWN_TIMEOUT = 12000; + + protected static final int SUITE_SETUP_TIMEOUT = 120000; + protected static final int SUITE_SHUTDOWN_TIMEOUT = 60000; + + protected static final int WAIT_REPLICA_CATCH_UP_IN_MILLIS = 4000; + + protected final static ConsistencyLevel accountConsistency; + protected static final ImmutableList preferredLocations; + private static final ImmutableList desiredConsistencies; + private static final ImmutableList protocols; + + protected int subscriberValidationTimeout = TIMEOUT; + protected Builder clientBuilder; + + protected static Database SHARED_DATABASE; + protected static DocumentCollection SHARED_MULTI_PARTITION_COLLECTION; + protected static DocumentCollection SHARED_SINGLE_PARTITION_COLLECTION; + protected static DocumentCollection SHARED_MULTI_PARTITION_COLLECTION_WITH_COMPOSITE_AND_SPATIAL_INDEXES; + + static { + accountConsistency = parseConsistency(TestConfigurations.CONSISTENCY); + desiredConsistencies = immutableListOrNull( + ObjectUtils.defaultIfNull(parseDesiredConsistencies(TestConfigurations.DESIRED_CONSISTENCIES), + allEqualOrLowerConsistencies(accountConsistency))); + preferredLocations = immutableListOrNull(parsePreferredLocation(TestConfigurations.PREFERRED_LOCATIONS)); + protocols = ObjectUtils.defaultIfNull(immutableListOrNull(parseProtocols(TestConfigurations.PROTOCOLS)), + ImmutableList.of(Protocol.Https, Protocol.Tcp)); + } + + protected TestSuiteBase() { + objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true); + objectMapper.configure(JsonParser.Feature.ALLOW_TRAILING_COMMA, true); + objectMapper.configure(JsonParser.Feature.STRICT_DUPLICATE_DETECTION, true); + logger.debug("Initializing {} ...", this.getClass().getSimpleName()); + } + + private static ImmutableList immutableListOrNull(List list) { + return list != null ? ImmutableList.copyOf(list) : null; + } + + @BeforeMethod(groups = {"simple", "long", "direct", "multi-master", "emulator", "non-emulator"}) + public void beforeMethod(Method method) { + if (this.clientBuilder != null) { + logger.info("Starting {}::{} using {} {} mode with {} consistency", + method.getDeclaringClass().getSimpleName(), method.getName(), + this.clientBuilder.getConnectionPolicy().getConnectionMode(), + this.clientBuilder.getConfigs().getProtocol(), + this.clientBuilder.getDesiredConsistencyLevel()); + return; + } + logger.info("Starting {}::{}", method.getDeclaringClass().getSimpleName(), method.getName()); + } + + @AfterMethod(groups = {"simple", "long", "direct", "multi-master", "emulator", "non-emulator"}) + public void afterMethod(Method m) { + Test t = m.getAnnotation(Test.class); + logger.info("Finished {}:{}.", m.getDeclaringClass().getSimpleName(), m.getName()); + } + + private static class DatabaseManagerImpl implements DatabaseForTest.DatabaseManager { + public static DatabaseManagerImpl getInstance(AsyncDocumentClient client) { + return new DatabaseManagerImpl(client); + } + + private final AsyncDocumentClient client; + + private DatabaseManagerImpl(AsyncDocumentClient client) { + this.client = client; + } + + @Override + public Observable> queryDatabases(SqlQuerySpec query) { + return client.queryDatabases(query, null); + } + + @Override + public Observable> createDatabase(Database databaseDefinition) { + return client.createDatabase(databaseDefinition, null); + } + + @Override + public Observable> deleteDatabase(String id) { + + return client.deleteDatabase("dbs/" + id, null); + } + } + + @BeforeSuite(groups = {"simple", "long", "direct", "multi-master", "emulator", "non-emulator"}, timeOut = SUITE_SETUP_TIMEOUT) + public static void beforeSuite() { + logger.info("beforeSuite Started"); + AsyncDocumentClient houseKeepingClient = createGatewayHouseKeepingDocumentClient().build(); + try { + DatabaseForTest dbForTest = DatabaseForTest.create(DatabaseManagerImpl.getInstance(houseKeepingClient)); + SHARED_DATABASE = dbForTest.createdDatabase; + RequestOptions options = new RequestOptions(); + options.setOfferThroughput(10100); + SHARED_MULTI_PARTITION_COLLECTION = createCollection(houseKeepingClient, SHARED_DATABASE.getId(), getCollectionDefinitionWithRangeRangeIndex(), options); + SHARED_SINGLE_PARTITION_COLLECTION = createCollection(houseKeepingClient, SHARED_DATABASE.getId(), getCollectionDefinition(), null); + SHARED_MULTI_PARTITION_COLLECTION_WITH_COMPOSITE_AND_SPATIAL_INDEXES = createCollection(houseKeepingClient, SHARED_DATABASE.getId(), getCollectionDefinitionMultiPartitionWithCompositeAndSpatialIndexes(), options); + } finally { + houseKeepingClient.close(); + } + } + + @AfterSuite(groups = {"simple", "long", "direct", "multi-master", "emulator", "non-emulator"}, timeOut = SUITE_SHUTDOWN_TIMEOUT) + public static void afterSuite() { + logger.info("afterSuite Started"); + AsyncDocumentClient houseKeepingClient = createGatewayHouseKeepingDocumentClient().build(); + try { + safeDeleteDatabase(houseKeepingClient, SHARED_DATABASE); + DatabaseForTest.cleanupStaleTestDatabases(DatabaseManagerImpl.getInstance(houseKeepingClient)); + } finally { + safeClose(houseKeepingClient); + } + } + + protected static void truncateCollection(DocumentCollection collection) { + logger.info("Truncating collection {} ...", collection.getId()); + AsyncDocumentClient houseKeepingClient = createGatewayHouseKeepingDocumentClient().build(); + try { + List paths = collection.getPartitionKey().getPaths(); + + FeedOptions options = new FeedOptions(); + options.setMaxDegreeOfParallelism(-1); + options.setEnableCrossPartitionQuery(true); + options.setMaxItemCount(100); + + logger.info("Truncating collection {} documents ...", collection.getId()); + + houseKeepingClient.queryDocuments(collection.getSelfLink(), "SELECT * FROM root", options) + .flatMap(page -> Observable.from(page.getResults())) + .flatMap(doc -> { + RequestOptions requestOptions = new RequestOptions(); + + if (paths != null && !paths.isEmpty()) { + List pkPath = PathParser.getPathParts(paths.get(0)); + Object propertyValue = doc.getObjectByPath(pkPath); + if (propertyValue == null) { + propertyValue = Undefined.Value(); + } + + requestOptions.setPartitionKey(new PartitionKey(propertyValue)); + } + + return houseKeepingClient.deleteDocument(doc.getSelfLink(), requestOptions); + }).toCompletable().await(); + + logger.info("Truncating collection {} triggers ...", collection.getId()); + + houseKeepingClient.queryTriggers(collection.getSelfLink(), "SELECT * FROM root", options) + .flatMap(page -> Observable.from(page.getResults())) + .flatMap(trigger -> { + RequestOptions requestOptions = new RequestOptions(); + +// if (paths != null && !paths.isEmpty()) { +// Object propertyValue = trigger.getObjectByPath(PathParser.getPathParts(paths.get(0))); +// requestOptions.setPartitionKey(new PartitionKey(propertyValue)); +// } + + return houseKeepingClient.deleteTrigger(trigger.getSelfLink(), requestOptions); + }).toCompletable().await(); + + logger.info("Truncating collection {} storedProcedures ...", collection.getId()); + + houseKeepingClient.queryStoredProcedures(collection.getSelfLink(), "SELECT * FROM root", options) + .flatMap(page -> Observable.from(page.getResults())) + .flatMap(storedProcedure -> { + RequestOptions requestOptions = new RequestOptions(); + +// if (paths != null && !paths.isEmpty()) { +// Object propertyValue = storedProcedure.getObjectByPath(PathParser.getPathParts(paths.get(0))); +// requestOptions.setPartitionKey(new PartitionKey(propertyValue)); +// } + + return houseKeepingClient.deleteStoredProcedure(storedProcedure.getSelfLink(), requestOptions); + }).toCompletable().await(); + + logger.info("Truncating collection {} udfs ...", collection.getId()); + + houseKeepingClient.queryUserDefinedFunctions(collection.getSelfLink(), "SELECT * FROM root", options) + .flatMap(page -> Observable.from(page.getResults())) + .flatMap(udf -> { + RequestOptions requestOptions = new RequestOptions(); + +// if (paths != null && !paths.isEmpty()) { +// Object propertyValue = udf.getObjectByPath(PathParser.getPathParts(paths.get(0))); +// requestOptions.setPartitionKey(new PartitionKey(propertyValue)); +// } + + return houseKeepingClient.deleteUserDefinedFunction(udf.getSelfLink(), requestOptions); + }).toCompletable().await(); + + } finally { + houseKeepingClient.close(); + } + + logger.info("Finished truncating collection {}.", collection.getId()); + } + + protected static void waitIfNeededForReplicasToCatchUp(Builder clientBuilder) { + switch (clientBuilder.getDesiredConsistencyLevel()) { + case Eventual: + case ConsistentPrefix: + logger.info(" additional wait in Eventual mode so the replica catch up"); + // give times to replicas to catch up after a write + try { + TimeUnit.MILLISECONDS.sleep(WAIT_REPLICA_CATCH_UP_IN_MILLIS); + } catch (Exception e) { + logger.error("unexpected failure", e); + } + + case Session: + case BoundedStaleness: + case Strong: + default: + break; + } + } + + public static DocumentCollection createCollection(String databaseId, + DocumentCollection collection, + RequestOptions options) { + AsyncDocumentClient client = createGatewayHouseKeepingDocumentClient().build(); + try { + return client.createCollection("dbs/" + databaseId, collection, options).toBlocking().single().getResource(); + } finally { + client.close(); + } + } + + public static DocumentCollection createCollection(AsyncDocumentClient client, String databaseId, + DocumentCollection collection, RequestOptions options) { + return client.createCollection("dbs/" + databaseId, collection, options).toBlocking().single().getResource(); + } + + public static DocumentCollection createCollection(AsyncDocumentClient client, String databaseId, + DocumentCollection collection) { + return client.createCollection("dbs/" + databaseId, collection, null).toBlocking().single().getResource(); + } + + private static DocumentCollection getCollectionDefinitionMultiPartitionWithCompositeAndSpatialIndexes() { + final String NUMBER_FIELD = "numberField"; + final String STRING_FIELD = "stringField"; + final String NUMBER_FIELD_2 = "numberField2"; + final String STRING_FIELD_2 = "stringField2"; + final String BOOL_FIELD = "boolField"; + final String NULL_FIELD = "nullField"; + final String OBJECT_FIELD = "objectField"; + final String ARRAY_FIELD = "arrayField"; + final String SHORT_STRING_FIELD = "shortStringField"; + final String MEDIUM_STRING_FIELD = "mediumStringField"; + final String LONG_STRING_FIELD = "longStringField"; + final String PARTITION_KEY = "pk"; + + DocumentCollection documentCollection = new DocumentCollection(); + + IndexingPolicy indexingPolicy = new IndexingPolicy(); + Collection> compositeIndexes = new ArrayList>(); + + //Simple + ArrayList compositeIndexSimple = new ArrayList(); + CompositePath compositePath1 = new CompositePath(); + compositePath1.setPath("/" + NUMBER_FIELD); + compositePath1.setOrder(CompositePathSortOrder.Ascending); + + CompositePath compositePath2 = new CompositePath(); + compositePath2.setPath("/" + STRING_FIELD); + compositePath2.setOrder(CompositePathSortOrder.Descending); + + compositeIndexSimple.add(compositePath1); + compositeIndexSimple.add(compositePath2); + + //Max Columns + ArrayList compositeIndexMaxColumns = new ArrayList(); + CompositePath compositePath3 = new CompositePath(); + compositePath3.setPath("/" + NUMBER_FIELD); + compositePath3.setOrder(CompositePathSortOrder.Descending); + + CompositePath compositePath4 = new CompositePath(); + compositePath4.setPath("/" + STRING_FIELD); + compositePath4.setOrder(CompositePathSortOrder.Ascending); + + CompositePath compositePath5 = new CompositePath(); + compositePath5.setPath("/" + NUMBER_FIELD_2); + compositePath5.setOrder(CompositePathSortOrder.Descending); + + CompositePath compositePath6 = new CompositePath(); + compositePath6.setPath("/" + STRING_FIELD_2); + compositePath6.setOrder(CompositePathSortOrder.Ascending); + + compositeIndexMaxColumns.add(compositePath3); + compositeIndexMaxColumns.add(compositePath4); + compositeIndexMaxColumns.add(compositePath5); + compositeIndexMaxColumns.add(compositePath6); + + //Primitive Values + ArrayList compositeIndexPrimitiveValues = new ArrayList(); + CompositePath compositePath7 = new CompositePath(); + compositePath7.setPath("/" + NUMBER_FIELD); + compositePath7.setOrder(CompositePathSortOrder.Descending); + + CompositePath compositePath8 = new CompositePath(); + compositePath8.setPath("/" + STRING_FIELD); + compositePath8.setOrder(CompositePathSortOrder.Ascending); + + CompositePath compositePath9 = new CompositePath(); + compositePath9.setPath("/" + BOOL_FIELD); + compositePath9.setOrder(CompositePathSortOrder.Descending); + + CompositePath compositePath10 = new CompositePath(); + compositePath10.setPath("/" + NULL_FIELD); + compositePath10.setOrder(CompositePathSortOrder.Ascending); + + compositeIndexPrimitiveValues.add(compositePath7); + compositeIndexPrimitiveValues.add(compositePath8); + compositeIndexPrimitiveValues.add(compositePath9); + compositeIndexPrimitiveValues.add(compositePath10); + + //Long Strings + ArrayList compositeIndexLongStrings = new ArrayList(); + CompositePath compositePath11 = new CompositePath(); + compositePath11.setPath("/" + STRING_FIELD); + + CompositePath compositePath12 = new CompositePath(); + compositePath12.setPath("/" + SHORT_STRING_FIELD); + + CompositePath compositePath13 = new CompositePath(); + compositePath13.setPath("/" + MEDIUM_STRING_FIELD); + + CompositePath compositePath14 = new CompositePath(); + compositePath14.setPath("/" + LONG_STRING_FIELD); + + compositeIndexLongStrings.add(compositePath11); + compositeIndexLongStrings.add(compositePath12); + compositeIndexLongStrings.add(compositePath13); + compositeIndexLongStrings.add(compositePath14); + + compositeIndexes.add(compositeIndexSimple); + compositeIndexes.add(compositeIndexMaxColumns); + compositeIndexes.add(compositeIndexPrimitiveValues); + compositeIndexes.add(compositeIndexLongStrings); + + indexingPolicy.setCompositeIndexes(compositeIndexes); + documentCollection.setIndexingPolicy(indexingPolicy); + + PartitionKeyDefinition partitionKeyDefinition = new PartitionKeyDefinition(); + ArrayList partitionKeyPaths = new ArrayList(); + partitionKeyPaths.add("/" + PARTITION_KEY); + partitionKeyDefinition.setPaths(partitionKeyPaths); + documentCollection.setPartitionKey(partitionKeyDefinition); + + documentCollection.setId(UUID.randomUUID().toString()); + + return documentCollection; + } + + public static Document createDocument(AsyncDocumentClient client, String databaseId, String collectionId, Document document) { + return createDocument(client, databaseId, collectionId, document, null); + } + + public static Document createDocument(AsyncDocumentClient client, String databaseId, String collectionId, Document document, RequestOptions options) { + return client.createDocument(Utils.getCollectionNameLink(databaseId, collectionId), document, options, false).toBlocking().single().getResource(); + } + + public Observable> bulkInsert(AsyncDocumentClient client, + String collectionLink, + List documentDefinitionList, + int concurrencyLevel) { + ArrayList>> result = new ArrayList>>(documentDefinitionList.size()); + for (Document docDef : documentDefinitionList) { + result.add(client.createDocument(collectionLink, docDef, null, false)); + } + + return Observable.merge(result, concurrencyLevel); + } + + public Observable> bulkInsert(AsyncDocumentClient client, + String collectionLink, + List documentDefinitionList) { + return bulkInsert(client, collectionLink, documentDefinitionList, DEFAULT_BULK_INSERT_CONCURRENCY_LEVEL); + } + + public List bulkInsertBlocking(AsyncDocumentClient client, + String collectionLink, + List documentDefinitionList) { + return bulkInsert(client, collectionLink, documentDefinitionList, DEFAULT_BULK_INSERT_CONCURRENCY_LEVEL) + .map(ResourceResponse::getResource) + .toList() + .toBlocking() + .single(); + } + + public static ConsistencyLevel getAccountDefaultConsistencyLevel(AsyncDocumentClient client) { + return client.getDatabaseAccount().toBlocking().single().getConsistencyPolicy().getDefaultConsistencyLevel(); + } + + public static User createUser(AsyncDocumentClient client, String databaseId, User user) { + return client.createUser("dbs/" + databaseId, user, null).toBlocking().single().getResource(); + } + + public static User safeCreateUser(AsyncDocumentClient client, String databaseId, User user) { + deleteUserIfExists(client, databaseId, user.getId()); + return createUser(client, databaseId, user); + } + + private static DocumentCollection safeCreateCollection(AsyncDocumentClient client, String databaseId, DocumentCollection collection, RequestOptions options) { + deleteCollectionIfExists(client, databaseId, collection.getId()); + return createCollection(client, databaseId, collection, options); + } + + public static String getCollectionLink(DocumentCollection collection) { + return collection.getSelfLink(); + } + + static protected DocumentCollection getCollectionDefinition() { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList(); + paths.add("/mypk"); + partitionKeyDef.setPaths(paths); + + DocumentCollection collectionDefinition = new DocumentCollection(); + collectionDefinition.setId(UUID.randomUUID().toString()); + collectionDefinition.setPartitionKey(partitionKeyDef); + + return collectionDefinition; + } + + static protected DocumentCollection getCollectionDefinitionWithRangeRangeIndex() { + PartitionKeyDefinition partitionKeyDef = new PartitionKeyDefinition(); + ArrayList paths = new ArrayList<>(); + paths.add("/mypk"); + partitionKeyDef.setPaths(paths); + IndexingPolicy indexingPolicy = new IndexingPolicy(); + Collection includedPaths = new ArrayList<>(); + IncludedPath includedPath = new IncludedPath(); + includedPath.setPath("/*"); + Collection indexes = new ArrayList<>(); + Index stringIndex = Index.Range(DataType.String); + stringIndex.set("precision", -1); + indexes.add(stringIndex); + + Index numberIndex = Index.Range(DataType.Number); + numberIndex.set("precision", -1); + indexes.add(numberIndex); + includedPath.setIndexes(indexes); + includedPaths.add(includedPath); + indexingPolicy.setIncludedPaths(includedPaths); + + DocumentCollection collectionDefinition = new DocumentCollection(); + collectionDefinition.setIndexingPolicy(indexingPolicy); + collectionDefinition.setId(UUID.randomUUID().toString()); + collectionDefinition.setPartitionKey(partitionKeyDef); + + return collectionDefinition; + } + + public static void deleteCollectionIfExists(AsyncDocumentClient client, String databaseId, String collectionId) { + List res = client.queryCollections("dbs/" + databaseId, + String.format("SELECT * FROM root r where r.id = '%s'", collectionId), null).toBlocking().single() + .getResults(); + if (!res.isEmpty()) { + deleteCollection(client, Utils.getCollectionNameLink(databaseId, collectionId)); + } + } + + public static void deleteCollection(AsyncDocumentClient client, String collectionLink) { + client.deleteCollection(collectionLink, null).toBlocking().single(); + } + + public static void deleteDocumentIfExists(AsyncDocumentClient client, String databaseId, String collectionId, String docId) { + FeedOptions options = new FeedOptions(); + options.setPartitionKey(new PartitionKey(docId)); + List res = client + .queryDocuments(Utils.getCollectionNameLink(databaseId, collectionId), String.format("SELECT * FROM root r where r.id = '%s'", docId), options) + .toBlocking().single().getResults(); + if (!res.isEmpty()) { + deleteDocument(client, Utils.getDocumentNameLink(databaseId, collectionId, docId)); + } + } + + public static void safeDeleteDocument(AsyncDocumentClient client, String documentLink, RequestOptions options) { + if (client != null && documentLink != null) { + try { + client.deleteDocument(documentLink, options).toBlocking().single(); + } catch (Exception e) { + DocumentClientException dce = com.microsoft.azure.cosmosdb.rx.internal.Utils.as(e, DocumentClientException.class); + if (dce == null || dce.getStatusCode() != 404) { + throw e; + } + } + } + } + + public static void deleteDocument(AsyncDocumentClient client, String documentLink) { + client.deleteDocument(documentLink, null).toBlocking().single(); + } + + public static void deleteUserIfExists(AsyncDocumentClient client, String databaseId, String userId) { + List res = client + .queryUsers("dbs/" + databaseId, String.format("SELECT * FROM root r where r.id = '%s'", userId), null) + .toBlocking().single().getResults(); + if (!res.isEmpty()) { + deleteUser(client, Utils.getUserNameLink(databaseId, userId)); + } + } + + public static void deleteUser(AsyncDocumentClient client, String userLink) { + client.deleteUser(userLink, null).toBlocking().single(); + } + + public static String getDatabaseLink(Database database) { + return database.getSelfLink(); + } + + static private Database safeCreateDatabase(AsyncDocumentClient client, Database database) { + safeDeleteDatabase(client, database.getId()); + return createDatabase(client, database); + } + + static protected Database createDatabase(AsyncDocumentClient client, Database database) { + Observable> databaseObservable = client.createDatabase(database, null); + return databaseObservable.toBlocking().single().getResource(); + } + + static protected Database createDatabase(AsyncDocumentClient client, String databaseId) { + Database databaseDefinition = new Database(); + databaseDefinition.setId(databaseId); + return createDatabase(client, databaseDefinition); + } + + static protected Database createDatabaseIfNotExists(AsyncDocumentClient client, String databaseId) { + return client.queryDatabases(String.format("SELECT * FROM r where r.id = '%s'", databaseId), null).flatMap(p -> Observable.from(p.getResults())).switchIfEmpty( + Observable.defer(() -> { + + Database databaseDefinition = new Database(); + databaseDefinition.setId(databaseId); + + return client.createDatabase(databaseDefinition, null).map(ResourceResponse::getResource); + }) + ).toBlocking().single(); + } + + static protected void safeDeleteDatabase(AsyncDocumentClient client, Database database) { + if (database != null) { + safeDeleteDatabase(client, database.getId()); + } + } + + static protected void safeDeleteDatabase(AsyncDocumentClient client, String databaseId) { + if (client != null) { + try { + client.deleteDatabase(Utils.getDatabaseNameLink(databaseId), null).toBlocking().single(); + } catch (Exception e) { + } + } + } + + static protected void safeDeleteAllCollections(AsyncDocumentClient client, Database database) { + if (database != null) { + List collections = client.readCollections(database.getSelfLink(), null) + .flatMap(p -> Observable.from(p.getResults())) + .toList() + .toBlocking() + .single(); + + for (DocumentCollection collection : collections) { + client.deleteCollection(collection.getSelfLink(), null).toBlocking().single().getResource(); + } + } + } + + static protected void safeDeleteCollection(AsyncDocumentClient client, DocumentCollection collection) { + if (client != null && collection != null) { + try { + client.deleteCollection(collection.getSelfLink(), null).toBlocking().single(); + } catch (Exception e) { + } + } + } + + static protected void safeDeleteCollection(AsyncDocumentClient client, String databaseId, String collectionId) { + if (client != null && databaseId != null && collectionId != null) { + try { + client.deleteCollection("/dbs/" + databaseId + "/colls/" + collectionId, null).toBlocking().single(); + } catch (Exception e) { + } + } + } + + static protected void safeCloseAsync(AsyncDocumentClient client) { + if (client != null) { + new Thread(() -> { + try { + client.close(); + } catch (Exception e) { + e.printStackTrace(); + } + }).start(); + } + } + + static protected void safeClose(AsyncDocumentClient client) { + if (client != null) { + try { + client.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + + public void validateSuccess(Observable> observable, + ResourceResponseValidator validator) { + validateSuccess(observable, validator, subscriberValidationTimeout); + } + + public static void validateSuccess(Observable> observable, + ResourceResponseValidator validator, long timeout) { + + VerboseTestSubscriber> testSubscriber = new VerboseTestSubscriber<>(); + + observable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertCompleted(); + testSubscriber.assertValueCount(1); + validator.validate(testSubscriber.getOnNextEvents().get(0)); + } + + public void validateFailure(Observable> observable, + FailureValidator validator) { + validateFailure(observable, validator, subscriberValidationTimeout); + } + + public static void validateFailure(Observable> observable, + FailureValidator validator, long timeout) { + + VerboseTestSubscriber> testSubscriber = new VerboseTestSubscriber<>(); + + observable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNotCompleted(); + testSubscriber.assertTerminalEvent(); + assertThat(testSubscriber.getOnErrorEvents()).hasSize(1); + validator.validate(testSubscriber.getOnErrorEvents().get(0)); + } + + public void validateQuerySuccess(Observable> observable, + FeedResponseListValidator validator) { + validateQuerySuccess(observable, validator, subscriberValidationTimeout); + } + + public static void validateQuerySuccess(Observable> observable, + FeedResponseListValidator validator, long timeout) { + + VerboseTestSubscriber> testSubscriber = new VerboseTestSubscriber<>(); + + observable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNoErrors(); + testSubscriber.assertCompleted(); + validator.validate(testSubscriber.getOnNextEvents()); + } + + public void validateQueryFailure(Observable> observable, + FailureValidator validator) { + validateQueryFailure(observable, validator, subscriberValidationTimeout); + } + + public static void validateQueryFailure(Observable> observable, + FailureValidator validator, long timeout) { + + VerboseTestSubscriber> testSubscriber = new VerboseTestSubscriber<>(); + + observable.subscribe(testSubscriber); + testSubscriber.awaitTerminalEvent(timeout, TimeUnit.MILLISECONDS); + testSubscriber.assertNotCompleted(); + testSubscriber.assertTerminalEvent(); + assertThat(testSubscriber.getOnErrorEvents()).hasSize(1); + validator.validate(testSubscriber.getOnErrorEvents().get(0)); + } + + @DataProvider + public static Object[][] clientBuilders() { + return new Object[][]{{createGatewayRxDocumentClient(ConsistencyLevel.Session, false, null)}}; + } + + @DataProvider + public static Object[][] clientBuildersWithSessionConsistency() { + return new Object[][]{ + {createGatewayRxDocumentClient(ConsistencyLevel.Session, false, null)}, + {createDirectRxDocumentClient(ConsistencyLevel.Session, Protocol.Https, false, null)}, + {createDirectRxDocumentClient(ConsistencyLevel.Session, Protocol.Tcp, false, null)} + }; + } + + private static ConsistencyLevel parseConsistency(String consistency) { + if (consistency != null) { + for (ConsistencyLevel consistencyLevel : ConsistencyLevel.values()) { + if (consistencyLevel.name().toLowerCase().equals(consistency.toLowerCase())) { + return consistencyLevel; + } + } + } + + logger.error("Invalid configured test consistency [{}].", consistency); + throw new IllegalStateException("Invalid configured test consistency " + consistency); + } + + static List parsePreferredLocation(String preferredLocations) { + if (StringUtils.isEmpty(preferredLocations)) { + return null; + } + + try { + return objectMapper.readValue(preferredLocations, new TypeReference>() { + }); + } catch (Exception e) { + logger.error("Invalid configured test preferredLocations [{}].", preferredLocations); + throw new IllegalStateException("Invalid configured test preferredLocations " + preferredLocations); + } + } + + static List parseProtocols(String protocols) { + if (StringUtils.isEmpty(protocols)) { + return null; + } + + try { + return objectMapper.readValue(protocols, new TypeReference>() { + }); + } catch (Exception e) { + logger.error("Invalid configured test protocols [{}].", protocols); + throw new IllegalStateException("Invalid configured test protocols " + protocols); + } + } + + @DataProvider + public static Object[][] simpleClientBuildersWithDirect() { + return simpleClientBuildersWithDirect(toArray(protocols)); + } + + @DataProvider + public static Object[][] simpleClientBuildersWithDirectHttps() { + return simpleClientBuildersWithDirect(Protocol.Https); + } + + private static Object[][] simpleClientBuildersWithDirect(Protocol... protocols) { + logger.info("Max test consistency to use is [{}]", accountConsistency); + List testConsistencies = ImmutableList.of(ConsistencyLevel.Eventual); + + boolean isMultiMasterEnabled = preferredLocations != null && accountConsistency == ConsistencyLevel.Session; + + List builders = new ArrayList<>(); + builders.add(createGatewayRxDocumentClient(ConsistencyLevel.Session, false, null)); + + for (Protocol protocol : protocols) { + testConsistencies.forEach(consistencyLevel -> builders.add(createDirectRxDocumentClient(consistencyLevel, + protocol, + isMultiMasterEnabled, + preferredLocations))); + } + + builders.forEach(b -> logger.info("Will Use ConnectionMode [{}], Consistency [{}], Protocol [{}]", + b.getConnectionPolicy().getConnectionMode(), + b.getDesiredConsistencyLevel(), + b.getConfigs().getProtocol() + )); + + return builders.stream().map(b -> new Object[]{b}).collect(Collectors.toList()).toArray(new Object[0][]); + } + + @DataProvider + public static Object[][] clientBuildersWithDirect() { + return clientBuildersWithDirectAllConsistencies(toArray(protocols)); + } + + @DataProvider + public static Object[][] clientBuildersWithDirectHttps() { + return clientBuildersWithDirectAllConsistencies(Protocol.Https); + } + + @DataProvider + public static Object[][] clientBuildersWithDirectSession() { + return clientBuildersWithDirectSession(toArray(protocols)); + } + + static Protocol[] toArray(List protocols) { + return protocols.toArray(new Protocol[0]); + } + + private static Object[][] clientBuildersWithDirectSession(Protocol... protocols) { + return clientBuildersWithDirect(new ArrayList() {{ + add(ConsistencyLevel.Session); + }}, protocols); + } + + private static Object[][] clientBuildersWithDirectAllConsistencies(Protocol... protocols) { + logger.info("Max test consistency to use is [{}]", accountConsistency); + return clientBuildersWithDirect(desiredConsistencies, protocols); + } + + static List parseDesiredConsistencies(String consistencies) { + if (StringUtils.isEmpty(consistencies)) { + return null; + } + + try { + return objectMapper.readValue(consistencies, new TypeReference>() { + }); + } catch (Exception e) { + logger.error("Invalid consistency test desiredConsistencies [{}].", consistencies); + throw new IllegalStateException("Invalid configured test desiredConsistencies " + consistencies); + } + } + + static List allEqualOrLowerConsistencies(ConsistencyLevel accountConsistency) { + List testConsistencies = new ArrayList<>(); + switch (accountConsistency) { + case Strong: + testConsistencies.add(ConsistencyLevel.Strong); + case BoundedStaleness: + testConsistencies.add(ConsistencyLevel.BoundedStaleness); + case Session: + testConsistencies.add(ConsistencyLevel.Session); + case ConsistentPrefix: + testConsistencies.add(ConsistencyLevel.ConsistentPrefix); + case Eventual: + testConsistencies.add(ConsistencyLevel.Eventual); + break; + default: + throw new IllegalStateException("Invalid configured test consistency " + accountConsistency); + } + return testConsistencies; + } + + private static Object[][] clientBuildersWithDirect(List testConsistencies, Protocol... protocols) { + boolean isMultiMasterEnabled = preferredLocations != null && accountConsistency == ConsistencyLevel.Session; + + List builders = new ArrayList<>(); + builders.add(createGatewayRxDocumentClient(ConsistencyLevel.Session, isMultiMasterEnabled, preferredLocations)); + + for (Protocol protocol : protocols) { + testConsistencies.forEach(consistencyLevel -> builders.add(createDirectRxDocumentClient(consistencyLevel, + protocol, + isMultiMasterEnabled, + preferredLocations))); + } + + builders.forEach(b -> logger.info("Will Use ConnectionMode [{}], Consistency [{}], Protocol [{}]", + b.getConnectionPolicy().getConnectionMode(), + b.getDesiredConsistencyLevel(), + b.getConfigs().getProtocol() + )); + + return builders.stream().map(b -> new Object[]{b}).collect(Collectors.toList()).toArray(new Object[0][]); + } + + static protected Builder createGatewayHouseKeepingDocumentClient() { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.setConnectionMode(ConnectionMode.Gateway); + RetryOptions options = new RetryOptions(); + options.setMaxRetryWaitTimeInSeconds(SUITE_SETUP_TIMEOUT); + connectionPolicy.setRetryOptions(options); + return new Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(ConsistencyLevel.Session); + } + + static protected Builder createGatewayRxDocumentClient(ConsistencyLevel consistencyLevel, boolean multiMasterEnabled, List preferredLocations) { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.setConnectionMode(ConnectionMode.Gateway); + connectionPolicy.setUsingMultipleWriteLocations(multiMasterEnabled); + connectionPolicy.setPreferredLocations(preferredLocations); + return new Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(consistencyLevel); + } + + static protected Builder createGatewayRxDocumentClient() { + return createGatewayRxDocumentClient(ConsistencyLevel.Session, false, null); + } + + static protected Builder createDirectRxDocumentClient(ConsistencyLevel consistencyLevel, + Protocol protocol, + boolean multiMasterEnabled, + List preferredLocations) { + ConnectionPolicy connectionPolicy = new ConnectionPolicy(); + connectionPolicy.setConnectionMode(ConnectionMode.Direct); + + if (preferredLocations != null) { + connectionPolicy.setPreferredLocations(preferredLocations); + } + + if (multiMasterEnabled && consistencyLevel == ConsistencyLevel.Session) { + connectionPolicy.setUsingMultipleWriteLocations(true); + } + + Configs configs = spy(new Configs()); + doAnswer((Answer)invocation -> protocol).when(configs).getProtocol(); + + return new Builder().withServiceEndpoint(TestConfigurations.HOST) + .withMasterKeyOrResourceToken(TestConfigurations.MASTER_KEY) + .withConnectionPolicy(connectionPolicy) + .withConsistencyLevel(consistencyLevel) + .withConfigs(configs); + } + + protected int expectedNumberOfPages(int totalExpectedResult, int maxPageSize) { + return Math.max((totalExpectedResult + maxPageSize - 1 ) / maxPageSize, 1); + } + + @DataProvider(name = "queryMetricsArgProvider") + public Object[][] queryMetricsArgProvider() { + return new Object[][]{ + {true}, + {false}, + }; + } + + public static class VerboseTestSubscriber extends TestSubscriber { + @Override + public void assertNoErrors() { + List onErrorEvents = getOnErrorEvents(); + StringBuilder errorMessageBuilder = new StringBuilder(); + if (!onErrorEvents.isEmpty()) { + for(Throwable throwable : onErrorEvents) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + throwable.printStackTrace(pw); + String sStackTrace = sw.toString(); // stack trace as a string + errorMessageBuilder.append(sStackTrace); + } + + AssertionError ae = new AssertionError(errorMessageBuilder.toString()); + throw ae; + } + } + } +} \ No newline at end of file diff --git a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/directconnectivity/ReflectionUtils.java b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/directconnectivity/ReflectionUtils.java index 944089112f01c..80f31b9cc3f63 100644 --- a/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/directconnectivity/ReflectionUtils.java +++ b/sdk/src/test/java/com/microsoft/azure/cosmosdb/rx/internal/directconnectivity/ReflectionUtils.java @@ -23,10 +23,12 @@ package com.microsoft.azure.cosmosdb.rx.internal.directconnectivity; +import com.microsoft.azure.cosmos.CosmosClient; import com.microsoft.azure.cosmosdb.internal.directconnectivity.HttpTransportClient; import com.microsoft.azure.cosmosdb.internal.directconnectivity.ServerStoreModel; import com.microsoft.azure.cosmosdb.internal.directconnectivity.StoreClient; import com.microsoft.azure.cosmosdb.internal.directconnectivity.TransportClient; +import com.microsoft.azure.cosmosdb.rx.AsyncDocumentClient; import com.microsoft.azure.cosmosdb.rx.internal.RxDocumentClientImpl; import io.netty.buffer.ByteBuf; import io.reactivex.netty.protocol.http.client.CompositeHttpClient; @@ -89,4 +91,12 @@ public static void setDirectHttpsHttpClient(RxDocumentClientImpl client, Composi assert transportClient instanceof HttpTransportClient; set(transportClient, newHttpClient, "httpClient"); } + + public static AsyncDocumentClient getAsyncDocumentClient(CosmosClient client) { + return get(AsyncDocumentClient.class, client, "asyncDocumentClient"); + } + + public static void setAsyncDocumentClient(CosmosClient client, RxDocumentClientImpl rxClient) { + set(client, rxClient, "asyncDocumentClient"); + } }