diff --git a/Microsoft.Azure.Cosmos/src/Batch/BatchAsyncBatcher.cs b/Microsoft.Azure.Cosmos/src/Batch/BatchAsyncBatcher.cs index 103b31076a..75dff4f211 100644 --- a/Microsoft.Azure.Cosmos/src/Batch/BatchAsyncBatcher.cs +++ b/Microsoft.Azure.Cosmos/src/Batch/BatchAsyncBatcher.cs @@ -24,7 +24,7 @@ namespace Microsoft.Azure.Cosmos /// internal class BatchAsyncBatcher { - private readonly CosmosSerializer cosmosSerializer; + private readonly CosmosSerializerCore serializerCore; private readonly List batchOperations; private readonly BatchAsyncBatcherExecuteDelegate executor; private readonly BatchAsyncBatcherRetryDelegate retrier; @@ -39,7 +39,7 @@ internal class BatchAsyncBatcher public BatchAsyncBatcher( int maxBatchOperationCount, int maxBatchByteSize, - CosmosSerializer cosmosSerializer, + CosmosSerializerCore serializerCore, BatchAsyncBatcherExecuteDelegate executor, BatchAsyncBatcherRetryDelegate retrier) { @@ -63,9 +63,9 @@ public BatchAsyncBatcher( throw new ArgumentNullException(nameof(retrier)); } - if (cosmosSerializer == null) + if (serializerCore == null) { - throw new ArgumentNullException(nameof(cosmosSerializer)); + throw new ArgumentNullException(nameof(serializerCore)); } this.batchOperations = new List(maxBatchOperationCount); @@ -73,7 +73,7 @@ public BatchAsyncBatcher( this.retrier = retrier; this.maxBatchByteSize = maxBatchByteSize; this.maxBatchOperationCount = maxBatchOperationCount; - this.cosmosSerializer = cosmosSerializer; + this.serializerCore = serializerCore; } public virtual bool TryAdd(ItemBatchOperation operation) @@ -152,7 +152,7 @@ public virtual bool TryAdd(ItemBatchOperation operation) try { PartitionKeyRangeBatchExecutionResult result = await this.executor(serverRequest, cancellationToken); - using (PartitionKeyRangeBatchResponse batchResponse = new PartitionKeyRangeBatchResponse(serverRequest.Operations.Count, result.ServerResponse, this.cosmosSerializer)) + using (PartitionKeyRangeBatchResponse batchResponse = new PartitionKeyRangeBatchResponse(serverRequest.Operations.Count, result.ServerResponse, this.serializerCore)) { foreach (ItemBatchOperation itemBatchOperation in batchResponse.Operations) { @@ -207,7 +207,7 @@ internal virtual async Task ExecuteAsync( requestEnricher: requestMessage => BatchAsyncContainerExecutor.AddHeadersToRequestMessage(requestMessage, serverRequest.PartitionKeyRangeId), cancellationToken: cancellationToken).ConfigureAwait(false); - TransactionalBatchResponse serverResponse = await TransactionalBatchResponse.FromResponseMessageAsync(responseMessage, serverRequest, this.cosmosClientContext.CosmosSerializer).ConfigureAwait(false); + TransactionalBatchResponse serverResponse = await TransactionalBatchResponse.FromResponseMessageAsync(responseMessage, serverRequest, this.cosmosClientContext.SerializerCore).ConfigureAwait(false); return new PartitionKeyRangeBatchExecutionResult(serverRequest.PartitionKeyRangeId, serverRequest.Operations, serverResponse); } @@ -250,7 +250,7 @@ private BatchAsyncStreamer GetOrAddStreamerForPartitionKeyRange(string partition return streamer; } - BatchAsyncStreamer newStreamer = new BatchAsyncStreamer(this.maxServerRequestOperationCount, this.maxServerRequestBodyLength, this.dispatchTimerInSeconds, this.timerPool, this.cosmosClientContext.CosmosSerializer, this.ExecuteAsync, this.ReBatchAsync); + BatchAsyncStreamer newStreamer = new BatchAsyncStreamer(this.maxServerRequestOperationCount, this.maxServerRequestBodyLength, this.dispatchTimerInSeconds, this.timerPool, this.cosmosClientContext.SerializerCore, this.ExecuteAsync, this.ReBatchAsync); if (!this.streamersByPartitionKeyRange.TryAdd(partitionKeyRangeId, newStreamer)) { newStreamer.Dispose(); diff --git a/Microsoft.Azure.Cosmos/src/Batch/BatchAsyncStreamer.cs b/Microsoft.Azure.Cosmos/src/Batch/BatchAsyncStreamer.cs index 7ccb45c313..2368b2b34e 100644 --- a/Microsoft.Azure.Cosmos/src/Batch/BatchAsyncStreamer.cs +++ b/Microsoft.Azure.Cosmos/src/Batch/BatchAsyncStreamer.cs @@ -26,7 +26,7 @@ internal class BatchAsyncStreamer : IDisposable private readonly BatchAsyncBatcherExecuteDelegate executor; private readonly BatchAsyncBatcherRetryDelegate retrier; private readonly int dispatchTimerInSeconds; - private readonly CosmosSerializer cosmosSerializer; + private readonly CosmosSerializerCore serializerCore; private readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); private volatile BatchAsyncBatcher currentBatcher; private TimerPool timerPool; @@ -38,7 +38,7 @@ public BatchAsyncStreamer( int maxBatchByteSize, int dispatchTimerInSeconds, TimerPool timerPool, - CosmosSerializer cosmosSerializer, + CosmosSerializerCore serializerCore, BatchAsyncBatcherExecuteDelegate executor, BatchAsyncBatcherRetryDelegate retrier) { @@ -67,9 +67,9 @@ public BatchAsyncStreamer( throw new ArgumentNullException(nameof(retrier)); } - if (cosmosSerializer == null) + if (serializerCore == null) { - throw new ArgumentNullException(nameof(cosmosSerializer)); + throw new ArgumentNullException(nameof(serializerCore)); } this.maxBatchOperationCount = maxBatchOperationCount; @@ -78,7 +78,7 @@ public BatchAsyncStreamer( this.retrier = retrier; this.dispatchTimerInSeconds = dispatchTimerInSeconds; this.timerPool = timerPool; - this.cosmosSerializer = cosmosSerializer; + this.serializerCore = serializerCore; this.currentBatcher = this.CreateBatchAsyncBatcher(); this.ResetTimer(); @@ -157,7 +157,7 @@ private BatchAsyncBatcher GetBatchToDispatchAndCreate() private BatchAsyncBatcher CreateBatchAsyncBatcher() { - return new BatchAsyncBatcher(this.maxBatchOperationCount, this.maxBatchByteSize, this.cosmosSerializer, this.executor, this.retrier); + return new BatchAsyncBatcher(this.maxBatchOperationCount, this.maxBatchByteSize, this.serializerCore, this.executor, this.retrier); } } } diff --git a/Microsoft.Azure.Cosmos/src/Batch/BatchExecutor.cs b/Microsoft.Azure.Cosmos/src/Batch/BatchExecutor.cs index ce86787c0b..3083e5bc20 100644 --- a/Microsoft.Azure.Cosmos/src/Batch/BatchExecutor.cs +++ b/Microsoft.Azure.Cosmos/src/Batch/BatchExecutor.cs @@ -51,7 +51,7 @@ public async Task ExecuteAsync(CancellationToken can SinglePartitionKeyServerBatchRequest serverRequest = await SinglePartitionKeyServerBatchRequest.CreateAsync( serverRequestPartitionKey, new ArraySegment(this.inputOperations.ToArray()), - this.clientContext.CosmosSerializer, + this.clientContext.SerializerCore, cancellationToken); return await this.ExecuteServerRequestAsync(serverRequest, cancellationToken); @@ -89,7 +89,7 @@ private async Task ExecuteServerRequestAsync( return await TransactionalBatchResponse.FromResponseMessageAsync( responseMessage, serverRequest, - this.clientContext.CosmosSerializer); + this.clientContext.SerializerCore); } } } diff --git a/Microsoft.Azure.Cosmos/src/Batch/ItemBatchOperation.cs b/Microsoft.Azure.Cosmos/src/Batch/ItemBatchOperation.cs index 1530fbb917..b8fd2f16a5 100644 --- a/Microsoft.Azure.Cosmos/src/Batch/ItemBatchOperation.cs +++ b/Microsoft.Azure.Cosmos/src/Batch/ItemBatchOperation.cs @@ -287,9 +287,9 @@ internal int GetApproximateSerializedLength() /// /// Materializes the operation's resource into a Memory{byte} wrapping a byte array. /// - /// Serializer to serialize user provided objects to JSON. + /// Serializer to serialize user provided objects to JSON. /// for cancellation. - internal virtual async Task MaterializeResourceAsync(CosmosSerializer serializer, CancellationToken cancellationToken) + internal virtual async Task MaterializeResourceAsync(CosmosSerializerCore serializerCore, CancellationToken cancellationToken) { if (this.body.IsEmpty && this.ResourceStream != null) { @@ -361,14 +361,14 @@ public ItemBatchOperation( /// /// Materializes the operation's resource into a Memory{byte} wrapping a byte array. /// - /// Serializer to serialize user provided objects to JSON. + /// Serializer to serialize user provided objects to JSON. /// for cancellation. - internal override Task MaterializeResourceAsync(CosmosSerializer serializer, CancellationToken cancellationToken) + internal override Task MaterializeResourceAsync(CosmosSerializerCore serializerCore, CancellationToken cancellationToken) { if (this.body.IsEmpty && this.Resource != null) { - this.ResourceStream = serializer.ToStream(this.Resource); - return base.MaterializeResourceAsync(serializer, cancellationToken); + this.ResourceStream = serializerCore.ToStream(this.Resource); + return base.MaterializeResourceAsync(serializerCore, cancellationToken); } return Task.FromResult(true); diff --git a/Microsoft.Azure.Cosmos/src/Batch/PartitionKeyRangeBatchResponse.cs b/Microsoft.Azure.Cosmos/src/Batch/PartitionKeyRangeBatchResponse.cs index a6f3ce9ca8..4c90c4f361 100644 --- a/Microsoft.Azure.Cosmos/src/Batch/PartitionKeyRangeBatchResponse.cs +++ b/Microsoft.Azure.Cosmos/src/Batch/PartitionKeyRangeBatchResponse.cs @@ -25,11 +25,11 @@ internal class PartitionKeyRangeBatchResponse : TransactionalBatchResponse /// /// Original operations that generated the server responses. /// Response from the server. - /// Serializer to deserialize response resource body streams. + /// Serializer to deserialize response resource body streams. internal PartitionKeyRangeBatchResponse( int originalOperationsCount, TransactionalBatchResponse serverResponse, - CosmosSerializer serializer) + CosmosSerializerCore serializerCore) { this.StatusCode = serverResponse.StatusCode; @@ -59,7 +59,7 @@ internal PartitionKeyRangeBatchResponse( this.ErrorMessage = errorMessageBuilder.Length > 2 ? errorMessageBuilder.ToString(0, errorMessageBuilder.Length - 2) : null; this.Operations = itemBatchOperations; - this.Serializer = serializer; + this.SerializerCore = serializerCore; } /// @@ -70,7 +70,7 @@ internal PartitionKeyRangeBatchResponse( /// public override CosmosDiagnostics Diagnostics => this.serverResponse.Diagnostics; - internal override CosmosSerializer Serializer { get; } + internal override CosmosSerializerCore SerializerCore { get; } /// /// Gets the number of operation results. @@ -98,7 +98,7 @@ public override TransactionalBatchOperationResult GetOperationResultAtIndex(result.ResourceStream); + resource = this.SerializerCore.FromStream(result.ResourceStream); } return new TransactionalBatchOperationResult(result, resource); diff --git a/Microsoft.Azure.Cosmos/src/Batch/PartitionKeyRangeServerBatchRequest.cs b/Microsoft.Azure.Cosmos/src/Batch/PartitionKeyRangeServerBatchRequest.cs index 35db6ae22a..f3928ac4ca 100644 --- a/Microsoft.Azure.Cosmos/src/Batch/PartitionKeyRangeServerBatchRequest.cs +++ b/Microsoft.Azure.Cosmos/src/Batch/PartitionKeyRangeServerBatchRequest.cs @@ -18,13 +18,13 @@ internal sealed class PartitionKeyRangeServerBatchRequest : ServerBatchRequest /// The partition key range id associated with all requests. /// Maximum length allowed for the request body. /// Maximum number of operations allowed in the request. - /// Serializer to serialize user provided objects to JSON. + /// Serializer to serialize user provided objects to JSON. public PartitionKeyRangeServerBatchRequest( string partitionKeyRangeId, int maxBodyLength, int maxOperationCount, - CosmosSerializer serializer) - : base(maxBodyLength, maxOperationCount, serializer) + CosmosSerializerCore serializerCore) + : base(maxBodyLength, maxOperationCount, serializerCore) { this.PartitionKeyRangeId = partitionKeyRangeId; } @@ -44,7 +44,7 @@ public PartitionKeyRangeServerBatchRequest( /// Desired maximum length of the request body. /// Maximum number of operations allowed in the request. /// Whether to stop adding operations to the request once there is non-continuity in the operation indexes. - /// Serializer to serialize user provided objects to JSON. + /// Serializer to serialize user provided objects to JSON. /// representing request cancellation. /// A newly created instance of . public static async Task>> CreateAsync( @@ -53,10 +53,10 @@ public static async Task pendingOperations = await request.CreateBodyStreamAsync(operations, cancellationToken, ensureContinuousOperationIndexes); return new Tuple>(request, pendingOperations); } diff --git a/Microsoft.Azure.Cosmos/src/Batch/ServerBatchRequest.cs b/Microsoft.Azure.Cosmos/src/Batch/ServerBatchRequest.cs index e0bd7e7bc9..52c02ad215 100644 --- a/Microsoft.Azure.Cosmos/src/Batch/ServerBatchRequest.cs +++ b/Microsoft.Azure.Cosmos/src/Batch/ServerBatchRequest.cs @@ -21,7 +21,7 @@ internal abstract class ServerBatchRequest private readonly int maxOperationCount; - private readonly CosmosSerializer serializer; + private readonly CosmosSerializerCore serializerCore; private ArraySegment operations; @@ -40,12 +40,12 @@ internal abstract class ServerBatchRequest /// /// Maximum length allowed for the request body. /// Maximum number of operations allowed in the request. - /// Serializer to serialize user provided objects to JSON. - protected ServerBatchRequest(int maxBodyLength, int maxOperationCount, CosmosSerializer serializer) + /// Serializer to serialize user provided objects to JSON. + protected ServerBatchRequest(int maxBodyLength, int maxOperationCount, CosmosSerializerCore serializerCore) { this.maxBodyLength = maxBodyLength; this.maxOperationCount = maxOperationCount; - this.serializer = serializer; + this.serializerCore = serializerCore; } public IReadOnlyList Operations => this.operations; @@ -87,7 +87,7 @@ protected async Task> CreateBodyStreamAsync( break; } - await operation.MaterializeResourceAsync(this.serializer, cancellationToken); + await operation.MaterializeResourceAsync(this.serializerCore, cancellationToken); materializedCount++; previousOperationIndex = operation.OperationIndex; diff --git a/Microsoft.Azure.Cosmos/src/Batch/SinglePartitionKeyServerBatchRequest.cs b/Microsoft.Azure.Cosmos/src/Batch/SinglePartitionKeyServerBatchRequest.cs index 14f6e5b6fa..b1f12b25b8 100644 --- a/Microsoft.Azure.Cosmos/src/Batch/SinglePartitionKeyServerBatchRequest.cs +++ b/Microsoft.Azure.Cosmos/src/Batch/SinglePartitionKeyServerBatchRequest.cs @@ -15,11 +15,13 @@ internal sealed class SinglePartitionKeyServerBatchRequest : ServerBatchRequest /// Single partition key server request. /// /// Partition key that applies to all operations in this request. - /// Serializer to serialize user provided objects to JSON. + /// Serializer to serialize user provided objects to JSON. private SinglePartitionKeyServerBatchRequest( PartitionKey? partitionKey, - CosmosSerializer serializer) - : base(maxBodyLength: int.MaxValue, maxOperationCount: int.MaxValue, serializer: serializer) + CosmosSerializerCore serializerCore) + : base(maxBodyLength: int.MaxValue, + maxOperationCount: int.MaxValue, + serializerCore: serializerCore) { this.PartitionKey = partitionKey; } @@ -35,16 +37,16 @@ private SinglePartitionKeyServerBatchRequest( /// /// Partition key of the request. /// Operations to be added into this batch request. - /// Serializer to serialize user provided objects to JSON. + /// Serializer to serialize user provided objects to JSON. /// representing request cancellation. /// A newly created instance of . public static async Task CreateAsync( PartitionKey? partitionKey, ArraySegment operations, - CosmosSerializer serializer, + CosmosSerializerCore serializerCore, CancellationToken cancellationToken) { - SinglePartitionKeyServerBatchRequest request = new SinglePartitionKeyServerBatchRequest(partitionKey, serializer); + SinglePartitionKeyServerBatchRequest request = new SinglePartitionKeyServerBatchRequest(partitionKey, serializerCore); await request.CreateBodyStreamAsync(operations, cancellationToken); return request; } diff --git a/Microsoft.Azure.Cosmos/src/Batch/TransactionalBatchResponse.cs b/Microsoft.Azure.Cosmos/src/Batch/TransactionalBatchResponse.cs index ce28d3adaf..cbbf853c27 100644 --- a/Microsoft.Azure.Cosmos/src/Batch/TransactionalBatchResponse.cs +++ b/Microsoft.Azure.Cosmos/src/Batch/TransactionalBatchResponse.cs @@ -67,13 +67,13 @@ private TransactionalBatchResponse( string activityId, CosmosDiagnostics cosmosDiagnostics, IReadOnlyList operations, - CosmosSerializer serializer) + CosmosSerializerCore serializer) { this.StatusCode = statusCode; this.SubStatusCode = subStatusCode; this.ErrorMessage = errorMessage; this.Operations = operations; - this.Serializer = serializer; + this.SerializerCore = serializer; this.RequestCharge = requestCharge; this.RetryAfter = retryAfter; this.ActivityId = activityId; @@ -134,7 +134,7 @@ public virtual bool IsSuccessStatusCode internal virtual SubStatusCodes SubStatusCode { get; } - internal virtual CosmosSerializer Serializer { get; } + internal virtual CosmosSerializerCore SerializerCore { get; } internal IReadOnlyList Operations { get; set; } @@ -164,7 +164,7 @@ public virtual TransactionalBatchOperationResult GetOperationResultAtIndex T resource = default(T); if (result.ResourceStream != null) { - resource = this.Serializer.FromStream(result.ResourceStream); + resource = this.SerializerCore.FromStream(result.ResourceStream); } return new TransactionalBatchOperationResult(result, resource); @@ -211,7 +211,7 @@ IEnumerator IEnumerable.GetEnumerator() internal static async Task FromResponseMessageAsync( ResponseMessage responseMessage, ServerBatchRequest serverRequest, - CosmosSerializer serializer, + CosmosSerializerCore serializer, bool shouldPromoteOperationStatus = true) { using (responseMessage) @@ -325,7 +325,7 @@ private static async Task PopulateFromContentAsync( Stream content, ResponseMessage responseMessage, ServerBatchRequest serverRequest, - CosmosSerializer serializer, + CosmosSerializerCore serializer, bool shouldPromoteOperationStatus) { List results = new List(); diff --git a/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/ChangeFeedProcessorCore.cs b/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/ChangeFeedProcessorCore.cs index 1d95f0cb98..049d7bf2bd 100644 --- a/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/ChangeFeedProcessorCore.cs +++ b/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/ChangeFeedProcessorCore.cs @@ -137,7 +137,7 @@ internal PartitionManager BuildPartitionManager() PartitionSupervisorFactoryCore partitionSuperviserFactory = new PartitionSupervisorFactoryCore( factory, this.documentServiceLeaseStoreManager.LeaseManager, - new FeedProcessorFactoryCore(this.monitoredContainer, this.changeFeedProcessorOptions, this.documentServiceLeaseStoreManager.LeaseCheckpointer, this.monitoredContainer.ClientContext.CosmosSerializer), + new FeedProcessorFactoryCore(this.monitoredContainer, this.changeFeedProcessorOptions, this.documentServiceLeaseStoreManager.LeaseCheckpointer, this.monitoredContainer.ClientContext.SerializerCore), this.changeFeedLeaseOptions); EqualPartitionsBalancingStrategy loadBalancingStrategy = new EqualPartitionsBalancingStrategy( diff --git a/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/FeedManagement/RemainingWorkEstimatorCore.cs b/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/FeedManagement/RemainingWorkEstimatorCore.cs index 2aa59a836d..3d27771661 100644 --- a/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/FeedManagement/RemainingWorkEstimatorCore.cs +++ b/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/FeedManagement/RemainingWorkEstimatorCore.cs @@ -126,9 +126,9 @@ internal static string ExtractLsnFromSessionToken(string sessionToken) return segments[1]; } - private static string GetFirstItemLSN(Collection items) + private static string GetFirstItemLSN(IEnumerable items) { - JObject item = RemainingWorkEstimatorCore.GetFirstItem(items); + JObject item = items.FirstOrDefault(); if (item == null) { return null; @@ -168,14 +168,16 @@ private static long TryConvertToNumber(string number) return parsed; } - private static Collection GetItemsFromResponse(ResponseMessage response) + private static IEnumerable GetItemsFromResponse(ResponseMessage response) { if (response.Content == null) { return new Collection(); } - return CosmosContainerExtensions.DefaultJsonSerializer.FromStream>(response.Content).Data; + return CosmosContainerExtensions.DefaultJsonSerializer.FromFeedResponseStream( + response.Content, + ResourceType.Document); } private async Task GetRemainingWorkAsync(DocumentServiceLease existingLease, CancellationToken cancellationToken) @@ -196,8 +198,8 @@ private async Task GetRemainingWorkAsync(DocumentServiceLease existingLeas } long parsedLSNFromSessionToken = RemainingWorkEstimatorCore.TryConvertToNumber(ExtractLsnFromSessionToken(response.Headers[HttpConstants.HttpHeaders.SessionToken])); - Collection items = RemainingWorkEstimatorCore.GetItemsFromResponse(response); - long lastQueryLSN = items.Count > 0 + IEnumerable items = RemainingWorkEstimatorCore.GetItemsFromResponse(response); + long lastQueryLSN = items.Any() ? RemainingWorkEstimatorCore.TryConvertToNumber(RemainingWorkEstimatorCore.GetFirstItemLSN(items)) - 1 : parsedLSNFromSessionToken; if (lastQueryLSN < 0) diff --git a/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/FeedProcessing/ChangeFeedObserver.cs b/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/FeedProcessing/ChangeFeedObserver.cs index 13c6449e24..94aa0fe9a5 100644 --- a/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/FeedProcessing/ChangeFeedObserver.cs +++ b/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/FeedProcessing/ChangeFeedObserver.cs @@ -33,7 +33,7 @@ internal abstract class ChangeFeedObserver /// /// The context specifying partition for this change event, etc. /// The documents changed. - /// Token to signal that the parition processing is going to finish. + /// Token to signal that the partition processing is going to finish. /// A Task to allow asynchronous execution. public abstract Task ProcessChangesAsync(ChangeFeedObserverContext context, IReadOnlyCollection docs, CancellationToken cancellationToken); } diff --git a/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/FeedProcessing/FeedProcessorCore.cs b/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/FeedProcessing/FeedProcessorCore.cs index 3faf06666c..ee90e403c8 100644 --- a/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/FeedProcessing/FeedProcessorCore.cs +++ b/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/FeedProcessing/FeedProcessorCore.cs @@ -8,6 +8,7 @@ namespace Microsoft.Azure.Cosmos.ChangeFeed.FeedProcessing using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; + using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; @@ -24,20 +25,20 @@ internal sealed class FeedProcessorCore : FeedProcessor private readonly PartitionCheckpointer checkpointer; private readonly ChangeFeedObserver observer; private readonly FeedIterator resultSetIterator; - private readonly CosmosSerializer cosmosJsonSerializer; + private readonly CosmosSerializerCore serializerCore; public FeedProcessorCore( ChangeFeedObserver observer, FeedIterator resultSetIterator, ProcessorOptions options, PartitionCheckpointer checkpointer, - CosmosSerializer cosmosJsonSerializer) + CosmosSerializerCore serializerCore) { this.observer = observer; this.options = options; this.checkpointer = checkpointer; this.resultSetIterator = resultSetIterator; - this.cosmosJsonSerializer = cosmosJsonSerializer; + this.serializerCore = serializerCore; } public override async Task RunAsync(CancellationToken cancellationToken) @@ -114,10 +115,12 @@ private void HandleFailedRequest( private Task DispatchChangesAsync(ResponseMessage response, CancellationToken cancellationToken) { ChangeFeedObserverContext context = new ChangeFeedObserverContextCore(this.options.LeaseToken, response, this.checkpointer); - Collection asFeedResponse; + IEnumerable asFeedResponse; try { - asFeedResponse = this.cosmosJsonSerializer.FromStream>(response.Content).Data; + asFeedResponse = this.serializerCore.FromFeedResponseStream( + response.Content, + Documents.ResourceType.Document); } catch (Exception serializationException) { @@ -126,13 +129,12 @@ private Task DispatchChangesAsync(ResponseMessage response, CancellationToken ca } // When StartFromBeginning is used, the first request returns OK but no content - if (asFeedResponse.Count == 0) + if (!asFeedResponse.Any()) { return Task.CompletedTask; } - List asReadOnlyList = new List(asFeedResponse.Count); - asReadOnlyList.AddRange(asFeedResponse); + List asReadOnlyList = new List(asFeedResponse); return this.observer.ProcessChangesAsync(context, asReadOnlyList, cancellationToken); } diff --git a/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/FeedProcessing/FeedProcessorFactoryCore.cs b/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/FeedProcessing/FeedProcessorFactoryCore.cs index 7f7de722c2..9f108a7aa2 100644 --- a/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/FeedProcessing/FeedProcessorFactoryCore.cs +++ b/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/FeedProcessing/FeedProcessorFactoryCore.cs @@ -16,23 +16,23 @@ internal class FeedProcessorFactoryCore : FeedProcessorFactory private readonly ContainerCore container; private readonly ChangeFeedProcessorOptions changeFeedProcessorOptions; private readonly DocumentServiceLeaseCheckpointer leaseCheckpointer; - private readonly CosmosSerializer cosmosJsonSerializer; + private readonly CosmosSerializerCore serializerCore; public FeedProcessorFactoryCore( ContainerCore container, ChangeFeedProcessorOptions changeFeedProcessorOptions, DocumentServiceLeaseCheckpointer leaseCheckpointer, - CosmosSerializer cosmosJsonSerializer) + CosmosSerializerCore serializerCore) { if (container == null) throw new ArgumentNullException(nameof(container)); if (changeFeedProcessorOptions == null) throw new ArgumentNullException(nameof(changeFeedProcessorOptions)); if (leaseCheckpointer == null) throw new ArgumentNullException(nameof(leaseCheckpointer)); - if (cosmosJsonSerializer == null) throw new ArgumentNullException(nameof(cosmosJsonSerializer)); + if (serializerCore == null) throw new ArgumentNullException(nameof(serializerCore)); this.container = container; this.changeFeedProcessorOptions = changeFeedProcessorOptions; this.leaseCheckpointer = leaseCheckpointer; - this.cosmosJsonSerializer = cosmosJsonSerializer; + this.serializerCore = serializerCore; } public override FeedProcessor Create(DocumentServiceLease lease, ChangeFeedObserver observer) @@ -64,7 +64,7 @@ public override FeedProcessor Create(DocumentServiceLease lease, ChangeFeedObser startTime: options.StartTime, startFromBeginning: options.StartFromBeginning); - return new FeedProcessorCore(observer, iterator, options, checkpointer, this.cosmosJsonSerializer); + return new FeedProcessorCore(observer, iterator, options, checkpointer, this.serializerCore); } } } diff --git a/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/LeaseManagement/DocumentServiceLeaseContainerCosmos.cs b/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/LeaseManagement/DocumentServiceLeaseContainerCosmos.cs index a356d5037e..e46a7419a8 100644 --- a/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/LeaseManagement/DocumentServiceLeaseContainerCosmos.cs +++ b/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/LeaseManagement/DocumentServiceLeaseContainerCosmos.cs @@ -58,7 +58,9 @@ private async Task> ListDocumentsAsync(s { using (ResponseMessage responseMessage = await iterator.ReadNextAsync().ConfigureAwait(false)) { - leases.AddRange(CosmosContainerExtensions.DefaultJsonSerializer.FromStream>(responseMessage.Content).Data); + leases.AddRange(CosmosContainerExtensions.DefaultJsonSerializer.FromFeedResponseStream( + responseMessage.Content, + Documents.ResourceType.Document)); } } diff --git a/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/Utils/CosmosContainerExtensions.cs b/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/Utils/CosmosContainerExtensions.cs index 02aea42659..ae6dd1d236 100644 --- a/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/Utils/CosmosContainerExtensions.cs +++ b/Microsoft.Azure.Cosmos/src/ChangeFeedProcessor/Utils/CosmosContainerExtensions.cs @@ -14,7 +14,7 @@ namespace Microsoft.Azure.Cosmos.ChangeFeed.Utils internal static class CosmosContainerExtensions { - public static readonly CosmosSerializer DefaultJsonSerializer = new CosmosJsonDotNetSerializer(); + public static readonly CosmosSerializerCore DefaultJsonSerializer = new CosmosSerializerCore(); public static async Task TryGetItemAsync( this Container container, diff --git a/Microsoft.Azure.Cosmos/src/CosmosClient.cs b/Microsoft.Azure.Cosmos/src/CosmosClient.cs index b5bdbf25f4..6dab099528 100644 --- a/Microsoft.Azure.Cosmos/src/CosmosClient.cs +++ b/Microsoft.Azure.Cosmos/src/CosmosClient.cs @@ -481,7 +481,9 @@ public virtual FeedIterator GetDatabaseQueryIterator( return new FeedIteratorCore( databaseStreamIterator, - this.ClientContext.ResponseFactory.CreateQueryFeedResponse); + (response) => this.ClientContext.ResponseFactory.CreateQueryFeedResponse( + responseMessage: response, + resourceType: ResourceType.Database)); } /// @@ -603,7 +605,7 @@ public virtual Task CreateDatabaseStreamAsync( } this.ClientContext.ValidateResource(databaseProperties.Id); - Stream streamPayload = this.ClientContext.PropertiesSerializer.ToStream(databaseProperties); + Stream streamPayload = this.ClientContext.SerializerCore.ToStream(databaseProperties); return this.CreateDatabaseStreamInternalAsync(streamPayload, throughput, requestOptions, cancellationToken); } @@ -631,21 +633,16 @@ internal void Init( this.RequestHandler = clientPipelineBuilder.Build(); - CosmosSerializer userSerializer = this.ClientOptions.GetCosmosSerializerWithWrapperOrDefault(); - this.ResponseFactory = new CosmosResponseFactory( - defaultJsonSerializer: this.ClientOptions.PropertiesSerializer, - userJsonSerializer: userSerializer); + CosmosSerializerCore serializerCore = CosmosSerializerCore.Create( + this.ClientOptions.Serializer, + this.ClientOptions.SerializerOptions); - CosmosSerializer sqlQuerySpecSerializer = CosmosSqlQuerySpecJsonConverter.CreateSqlQuerySpecSerializer( - cosmosSerializer: userSerializer, - propertiesSerializer: this.ClientOptions.PropertiesSerializer); + this.ResponseFactory = new CosmosResponseFactory(serializerCore); this.ClientContext = new ClientContextCore( client: this, clientOptions: this.ClientOptions, - userJsonSerializer: userSerializer, - defaultJsonSerializer: this.ClientOptions.PropertiesSerializer, - sqlQuerySpecSerializer: sqlQuerySpecSerializer, + serializerCore: serializerCore, cosmosResponseFactory: this.ResponseFactory, requestHandler: this.RequestHandler, documentClient: this.DocumentClient); @@ -684,7 +681,7 @@ internal Task CreateDatabaseAsync( CancellationToken cancellationToken = default(CancellationToken)) { Task response = this.CreateDatabaseStreamInternalAsync( - streamPayload: this.ClientContext.PropertiesSerializer.ToStream(databaseProperties), + streamPayload: this.ClientContext.SerializerCore.ToStream(databaseProperties), throughput: throughput, requestOptions: requestOptions, cancellationToken: cancellationToken); @@ -710,32 +707,6 @@ private Task CreateDatabaseStreamInternalAsync( cancellationToken: cancellationToken); } - private Task> DatabaseFeedRequestExecutorAsync( - int? maxItemCount, - string continuationToken, - RequestOptions options, - object state, - CancellationToken cancellationToken) - { - Debug.Assert(state == null); - - return this.ClientContext.ProcessResourceOperationAsync>( - resourceUri: this.DatabaseRootUri, - resourceType: ResourceType.Database, - operationType: OperationType.ReadFeed, - requestOptions: options, - cosmosContainerCore: null, - partitionKey: null, - streamPayload: null, - requestEnricher: request => - { - QueryRequestOptions.FillContinuationToken(request, continuationToken); - QueryRequestOptions.FillMaxItemCount(request, maxItemCount); - }, - responseCreator: response => this.ClientContext.ResponseFactory.CreateQueryFeedResponse(response), - cancellationToken: cancellationToken); - } - private HttpClientHandler CreateHttpClientHandler(CosmosClientOptions clientOptions) { if (clientOptions == null || (clientOptions.WebProxy == null)) diff --git a/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs b/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs index 7f2a710b71..1b96a29893 100644 --- a/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs +++ b/Microsoft.Azure.Cosmos/src/CosmosClientOptions.cs @@ -54,8 +54,6 @@ public class CosmosClientOptions /// /// Default request timeout /// - private static readonly CosmosSerializer propertiesSerializer = new CosmosJsonSerializerWrapper(new CosmosJsonDotNetSerializer()); - private int gatewayModeMaxConnectionLimit; private CosmosSerializationOptions serializerOptions; private CosmosSerializer serializer; @@ -395,14 +393,6 @@ public CosmosSerializer Serializer /// public bool AllowBulkExecution { get; set; } - /// - /// A JSON serializer used by the CosmosClient to serialize or de-serialize cosmos request/responses. - /// The default serializer is always used for all system owned types like DatabaseProperties. - /// The default serializer is used for user types if no UserJsonSerializer is specified - /// - [JsonConverter(typeof(ClientOptionJsonConverter))] - internal CosmosSerializer PropertiesSerializer => CosmosClientOptions.propertiesSerializer; - /// /// Gets or sets the connection protocol when connecting to the Azure Cosmos service. /// @@ -507,22 +497,6 @@ internal Protocol ConnectionProtocol /// internal bool? EnableCpuMonitor { get; set; } - /// - /// Gets the user json serializer with the CosmosJsonSerializerWrapper or the default - /// - internal CosmosSerializer GetCosmosSerializerWithWrapperOrDefault() - { - if (this.SerializerOptions != null) - { - CosmosJsonDotNetSerializer cosmosJsonDotNetSerializer = new CosmosJsonDotNetSerializer(this.SerializerOptions); - return new CosmosJsonSerializerWrapper(cosmosJsonDotNetSerializer); - } - else - { - return this.Serializer == null ? this.PropertiesSerializer : new CosmosJsonSerializerWrapper(this.Serializer); - } - } - internal CosmosClientOptions Clone() { CosmosClientOptions cloneConfiguration = (CosmosClientOptions)this.MemberwiseClone(); diff --git a/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElementSerializer.cs b/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElementSerializer.cs index a6b29b6585..bcaf594471 100644 --- a/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElementSerializer.cs +++ b/Microsoft.Azure.Cosmos/src/CosmosElements/CosmosElementSerializer.cs @@ -7,6 +7,7 @@ namespace Microsoft.Azure.Cosmos.CosmosElements using System.Collections.Generic; using System.IO; using System.Linq; + using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using Microsoft.Azure.Cosmos.Json; using Microsoft.Azure.Cosmos.Query.Core; @@ -21,6 +22,30 @@ namespace Microsoft.Azure.Cosmos.CosmosElements #endif static class CosmosElementSerializer { + /// + /// Converts a list of CosmosElements into a memory stream. + /// + /// The stream response from Azure Cosmos + /// The resource type + /// The custom serialization options. This allows custom serialization types like BSON, JSON, or other formats + /// Returns a memory stream of cosmos elements. By default the memory stream will contain JSON. + internal static CosmosArray ToCosmosElements( + Stream stream, + ResourceType resourceType, + CosmosSerializationFormatOptions cosmosSerializationOptions = null) + { + MemoryStream memoryStream = stream as MemoryStream; + if (memoryStream == null) + { + memoryStream = new MemoryStream(); + stream.CopyTo(memoryStream); + } + + return CosmosElementSerializer.ToCosmosElements( + memoryStream, + resourceType, + cosmosSerializationOptions); + } /// /// Converts a list of CosmosElements into a memory stream. /// @@ -220,6 +245,39 @@ internal static MemoryStream ToStream( return new MemoryStream(resultAsArray.Array, resultAsArray.Offset, resultAsArray.Count); } + internal static IEnumerable GetResources( + IReadOnlyList cosmosArray, + CosmosSerializerCore serializerCore) + { + if (cosmosArray == null) + { + return new List(); + } + + if (typeof(T) == typeof(CosmosElement)) + { + return cosmosArray.Cast(); + } + + return CosmosElementSerializer.GetResourcesHelper( + cosmosArray, + serializerCore); + } + + private static IEnumerable GetResourcesHelper( + IReadOnlyList cosmosArray, + CosmosSerializerCore serializerCore) + { + List result = new List(); + foreach (CosmosElement element in cosmosArray) + { + MemoryStream memory = CosmosElementSerializer.ElementToMemoryStream(element, null); + result.Add(serializerCore.FromStream(memory)); + } + + return result; + } + /// /// Converts a list of CosmosElements into a list of objects. /// @@ -233,7 +291,7 @@ internal static IEnumerable Deserialize( string containerRid, IEnumerable cosmosElements, ResourceType resourceType, - CosmosSerializer jsonSerializer, + CosmosSerializerCore jsonSerializer, CosmosSerializationFormatOptions cosmosSerializationOptions = null) { if (!cosmosElements.Any()) @@ -247,11 +305,44 @@ internal static IEnumerable Deserialize( resourceType, cosmosSerializationOptions); - IEnumerable typedResults = jsonSerializer.FromStream>(stream).Data; + IEnumerable typedResults = jsonSerializer.FromFeedResponseStream( + stream, + resourceType); return typedResults; } + /// + /// Converts a list of CosmosElements into a memory stream. + /// + /// The cosmos elements + /// The custom serialization options. This allows custom serialization types like BSON, JSON, or other formats + /// Returns a memory stream of cosmos elements. By default the memory stream will contain JSON. + private static MemoryStream ElementToMemoryStream( + CosmosElement cosmosElement, + CosmosSerializationFormatOptions cosmosSerializationOptions = null) + { + IJsonWriter jsonWriter; + if (cosmosSerializationOptions != null) + { + jsonWriter = cosmosSerializationOptions.CreateCustomWriterCallback(); + } + else + { + jsonWriter = JsonWriter.Create(JsonSerializationFormat.Text); + } + + cosmosElement.WriteTo(jsonWriter); + + ReadOnlyMemory result = jsonWriter.GetResult(); + if (!MemoryMarshal.TryGetArray(result, out ArraySegment resultAsArray)) + { + resultAsArray = new ArraySegment(result.ToArray()); + } + + return new MemoryStream(resultAsArray.Array, resultAsArray.Offset, resultAsArray.Count); + } + private static string GetRootNodeName(ResourceType resourceType) { switch (resourceType) diff --git a/Microsoft.Azure.Cosmos/src/FeedIteratorCore.cs b/Microsoft.Azure.Cosmos/src/FeedIteratorCore.cs index 4f1a78e605..d8552a5c9e 100644 --- a/Microsoft.Azure.Cosmos/src/FeedIteratorCore.cs +++ b/Microsoft.Azure.Cosmos/src/FeedIteratorCore.cs @@ -68,13 +68,7 @@ public override async Task ReadNextAsync(CancellationToken canc OperationType operation = OperationType.ReadFeed; if (this.querySpec != null) { - // Use property serializer is for internal query operations like throughput - // that should not use custom serializer - CosmosSerializer serializer = this.usePropertySerializer ? - this.clientContext.PropertiesSerializer : - this.clientContext.SqlQuerySpecSerializer; - - stream = serializer.ToStream(this.querySpec); + stream = this.clientContext.SerializerCore.ToStreamSqlQuerySpec(this.querySpec, this.resourceType); operation = OperationType.Query; } diff --git a/Microsoft.Azure.Cosmos/src/Linq/CosmosLinqQuery.cs b/Microsoft.Azure.Cosmos/src/Linq/CosmosLinqQuery.cs index 43d7f3622f..a332e6df5b 100644 --- a/Microsoft.Azure.Cosmos/src/Linq/CosmosLinqQuery.cs +++ b/Microsoft.Azure.Cosmos/src/Linq/CosmosLinqQuery.cs @@ -210,7 +210,7 @@ private FeedIterator CreateFeedIterator(bool isContinuationExcpected) FeedIteratorInternal streamIterator = this.CreateStreamIterator(isContinuationExcpected); return new FeedIteratorCore( streamIterator, - this.responseFactory.CreateQueryFeedResponse); + this.responseFactory.CreateQueryFeedUserTypeResponse); } } } diff --git a/Microsoft.Azure.Cosmos/src/Query/v3Query/CosmosQueryClientCore.cs b/Microsoft.Azure.Cosmos/src/Query/v3Query/CosmosQueryClientCore.cs index 8d5d31e4d5..0cf9ce795b 100644 --- a/Microsoft.Azure.Cosmos/src/Query/v3Query/CosmosQueryClientCore.cs +++ b/Microsoft.Azure.Cosmos/src/Query/v3Query/CosmosQueryClientCore.cs @@ -139,7 +139,7 @@ internal override async Task ExecuteItemQueryAsync { this.PopulatePartitionKeyRangeInfo(cosmosRequestMessage, partitionKeyRange); @@ -180,7 +180,7 @@ internal override async Task ExecuteQueryPlanRequ requestOptions: null, partitionKey: null, cosmosContainerCore: this.cosmosContainerCore, - streamPayload: this.clientContext.SqlQuerySpecSerializer.ToStream(sqlQuerySpec), + streamPayload: this.clientContext.SerializerCore.ToStreamSqlQuerySpec(sqlQuerySpec, resourceType), requestEnricher: (requestMessage) => { requestMessage.Headers.Add(HttpConstants.HttpHeaders.ContentType, RuntimeConstants.MediaTypes.QueryJson); @@ -193,7 +193,7 @@ internal override async Task ExecuteQueryPlanRequ { // Syntax exception are argument exceptions and thrown to the user. message.EnsureSuccessStatusCode(); - partitionedQueryExecutionInfo = this.clientContext.CosmosSerializer.FromStream(message.Content); + partitionedQueryExecutionInfo = this.clientContext.SerializerCore.FromStream(message.Content); } return partitionedQueryExecutionInfo; diff --git a/Microsoft.Azure.Cosmos/src/Query/v3Query/QueryResponse.cs b/Microsoft.Azure.Cosmos/src/Query/v3Query/QueryResponse.cs index 8d84ebca2b..d9552a79f0 100644 --- a/Microsoft.Azure.Cosmos/src/Query/v3Query/QueryResponse.cs +++ b/Microsoft.Azure.Cosmos/src/Query/v3Query/QueryResponse.cs @@ -27,7 +27,7 @@ internal QueryResponse() } private QueryResponse( - IEnumerable result, + IReadOnlyList result, int count, long responseLengthBytes, CosmosQueryResponseMessageHeaders responseHeaders, @@ -63,7 +63,7 @@ public override Stream Content } } - internal virtual IEnumerable CosmosElements { get; } + internal virtual IReadOnlyList CosmosElements { get; } internal virtual CosmosQueryResponseMessageHeaders QueryHeaders => (CosmosQueryResponseMessageHeaders)this.Headers; @@ -83,7 +83,7 @@ internal bool GetHasMoreResults() } internal static QueryResponse CreateSuccess( - IEnumerable result, + IReadOnlyList result, int count, long responseLengthBytes, CosmosQueryResponseMessageHeaders responseHeaders, @@ -131,7 +131,7 @@ internal static QueryResponse CreateFailure( CosmosDiagnostics diagnostics) { QueryResponse cosmosQueryResponse = new QueryResponse( - result: Enumerable.Empty(), + result: new List(), count: 0, responseLengthBytes: 0, responseHeaders: responseHeaders, @@ -153,25 +153,26 @@ internal static QueryResponse CreateFailure( /// The type for the query response. internal class QueryResponse : FeedResponse { - private readonly IEnumerable cosmosElements; - private readonly CosmosSerializer jsonSerializer; + private readonly CosmosSerializerCore serializerCore; private readonly CosmosSerializationFormatOptions serializationOptions; - private IEnumerable resources; private QueryResponse( HttpStatusCode httpStatusCode, - IEnumerable cosmosElements, + IReadOnlyList cosmosElements, CosmosQueryResponseMessageHeaders responseMessageHeaders, CosmosDiagnostics diagnostics, - CosmosSerializer jsonSerializer, + CosmosSerializerCore serializerCore, CosmosSerializationFormatOptions serializationOptions) { - this.cosmosElements = cosmosElements; this.QueryHeaders = responseMessageHeaders; this.Diagnostics = diagnostics; - this.jsonSerializer = jsonSerializer; + this.serializerCore = serializerCore; this.serializationOptions = serializationOptions; this.StatusCode = httpStatusCode; + this.Count = cosmosElements.Count; + this.Resource = CosmosElementSerializer.GetResources( + cosmosArray: cosmosElements, + serializerCore: serializerCore); } public override string ContinuationToken => this.Headers.ContinuationToken; @@ -184,7 +185,7 @@ private QueryResponse( public override CosmosDiagnostics Diagnostics { get; } - public override int Count => this.cosmosElements?.Count() ?? 0; + public override int Count { get; } internal CosmosQueryResponseMessageHeaders QueryHeaders { get; } @@ -193,45 +194,23 @@ public override IEnumerator GetEnumerator() return this.Resource.GetEnumerator(); } - public override IEnumerable Resource - { - get - { - if (this.resources == null) - { - if (typeof(T) == typeof(CosmosElement)) - { - this.resources = this.cosmosElements.Cast(); - } - else - { - this.resources = CosmosElementSerializer.Deserialize( - this.QueryHeaders.ContainerRid, - this.cosmosElements, - this.QueryHeaders.ResourceType, - this.jsonSerializer, - this.serializationOptions); - } - } - - return this.resources; - } - } + public override IEnumerable Resource { get; } internal static QueryResponse CreateResponse( QueryResponse cosmosQueryResponse, - CosmosSerializer jsonSerializer) + CosmosSerializerCore serializerCore) { QueryResponse queryResponse; using (cosmosQueryResponse) { cosmosQueryResponse.EnsureSuccessStatusCode(); + queryResponse = new QueryResponse( httpStatusCode: cosmosQueryResponse.StatusCode, cosmosElements: cosmosQueryResponse.CosmosElements, responseMessageHeaders: cosmosQueryResponse.QueryHeaders, diagnostics: cosmosQueryResponse.Diagnostics, - jsonSerializer: jsonSerializer, + serializerCore: serializerCore, serializationOptions: cosmosQueryResponse.CosmosSerializationOptions); } return queryResponse; diff --git a/Microsoft.Azure.Cosmos/src/Query/v3Query/ReadFeedResponse.cs b/Microsoft.Azure.Cosmos/src/Query/v3Query/ReadFeedResponse.cs index 9ec20eea82..69de91eec8 100644 --- a/Microsoft.Azure.Cosmos/src/Query/v3Query/ReadFeedResponse.cs +++ b/Microsoft.Azure.Cosmos/src/Query/v3Query/ReadFeedResponse.cs @@ -4,22 +4,27 @@ namespace Microsoft.Azure.Cosmos { using System.Collections.Generic; + using System.IO; using System.Net; - using Microsoft.Azure.Cosmos.Query.Core; + using Microsoft.Azure.Cosmos.CosmosElements; + using Microsoft.Azure.Cosmos.Json; internal class ReadFeedResponse : FeedResponse { protected ReadFeedResponse( HttpStatusCode httpStatusCode, - ICollection resource, + CosmosArray cosmosArray, + CosmosSerializerCore serializerCore, Headers responseMessageHeaders, CosmosDiagnostics diagnostics) { - this.Count = resource.Count; + this.Count = cosmosArray.Count; this.Headers = responseMessageHeaders; - this.Resource = resource; this.StatusCode = httpStatusCode; this.Diagnostics = diagnostics; + this.Resource = CosmosElementSerializer.GetResources( + cosmosArray: cosmosArray, + serializerCore: serializerCore); } public override int Count { get; } @@ -41,20 +46,26 @@ public override IEnumerator GetEnumerator() internal static ReadFeedResponse CreateResponse( ResponseMessage responseMessage, - CosmosSerializer jsonSerializer) + CosmosSerializerCore serializerCore, + Documents.ResourceType resourceType) { using (responseMessage) { - ICollection resources = default; + responseMessage.EnsureSuccessStatusCode(); + + CosmosArray cosmosArray = null; if (responseMessage.Content != null) { - CosmosFeedResponseUtil response = jsonSerializer.FromStream>(responseMessage.Content); - resources = response.Data; + cosmosArray = CosmosElementSerializer.ToCosmosElements( + responseMessage.Content, + resourceType, + null); } ReadFeedResponse readFeedResponse = new ReadFeedResponse( httpStatusCode: responseMessage.StatusCode, - resource: resources, + cosmosArray: cosmosArray, + serializerCore: serializerCore, responseMessageHeaders: responseMessage.Headers, diagnostics: responseMessage.Diagnostics); diff --git a/Microsoft.Azure.Cosmos/src/Resource/ClientContextCore.cs b/Microsoft.Azure.Cosmos/src/Resource/ClientContextCore.cs index 1f879021fc..aee5a975b2 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/ClientContextCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/ClientContextCore.cs @@ -19,18 +19,14 @@ internal class ClientContextCore : CosmosClientContext internal ClientContextCore( CosmosClient client, CosmosClientOptions clientOptions, - CosmosSerializer userJsonSerializer, - CosmosSerializer defaultJsonSerializer, - CosmosSerializer sqlQuerySpecSerializer, + CosmosSerializerCore serializerCore, CosmosResponseFactory cosmosResponseFactory, RequestInvokerHandler requestHandler, DocumentClient documentClient) { this.Client = client; this.ClientOptions = clientOptions; - this.CosmosSerializer = userJsonSerializer; - this.PropertiesSerializer = defaultJsonSerializer; - this.SqlQuerySpecSerializer = sqlQuerySpecSerializer; + this.SerializerCore = serializerCore; this.ResponseFactory = cosmosResponseFactory; this.RequestHandler = requestHandler; this.DocumentClient = documentClient; @@ -43,11 +39,7 @@ internal ClientContextCore( internal override DocumentClient DocumentClient { get; } - internal override CosmosSerializer CosmosSerializer { get; } - - internal override CosmosSerializer PropertiesSerializer { get; } - - internal override CosmosSerializer SqlQuerySpecSerializer { get; } + internal override CosmosSerializerCore SerializerCore { get; } internal override CosmosResponseFactory ResponseFactory { get; } diff --git a/Microsoft.Azure.Cosmos/src/Resource/Conflict/ConflictsCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Conflict/ConflictsCore.cs index 52090721b0..8619943ec4 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Conflict/ConflictsCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Conflict/ConflictsCore.cs @@ -124,7 +124,9 @@ public override FeedIterator GetConflictQueryIterator( return new FeedIteratorCore( databaseStreamIterator, - this.clientContext.ResponseFactory.CreateQueryFeedResponseWithPropertySerializer); + (response) => this.clientContext.ResponseFactory.CreateQueryFeedResponse( + responseMessage: response, + resourceType: ResourceType.Conflict)); } public override async Task> ReadCurrentAsync( @@ -188,7 +190,7 @@ public override T ReadConflictContent(ConflictProperties cosmosConflict) writer.Write(cosmosConflict.Content); writer.Flush(); stream.Position = 0; - return this.clientContext.CosmosSerializer.FromStream(stream); + return this.clientContext.SerializerCore.FromStream(stream); } } } diff --git a/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerCore.Items.cs b/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerCore.Items.cs index baa0e793af..e0e369cbab 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerCore.Items.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerCore.Items.cs @@ -365,7 +365,7 @@ public override FeedIterator GetItemQueryIterator( return new FeedIteratorCore( feedIterator: feedIterator, - responseCreator: this.ClientContext.ResponseFactory.CreateQueryFeedResponse); + responseCreator: this.ClientContext.ResponseFactory.CreateQueryFeedUserTypeResponse); } public override IOrderedQueryable GetItemLinqQueryable( @@ -519,7 +519,7 @@ internal async Task ExtractPartitionKeyAndProcessItemStreamAsyn RequestOptions requestOptions, CancellationToken cancellationToken) { - Stream streamPayload = this.ClientContext.CosmosSerializer.ToStream(item); + Stream streamPayload = this.ClientContext.SerializerCore.ToStream(item); // User specified PK value, no need to extract it if (partitionKey.HasValue) diff --git a/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerCore.cs index 5187d8fe71..e425eaba19 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Container/ContainerCore.cs @@ -87,7 +87,7 @@ public override Task ReplaceContainerAsync( this.ClientContext.ValidateResource(containerProperties.Id); Task response = this.ReplaceStreamInternalAsync( - streamPayload: this.ClientContext.PropertiesSerializer.ToStream(containerProperties), + streamPayload: this.ClientContext.SerializerCore.ToStream(containerProperties), requestOptions: requestOptions, cancellationToken: cancellationToken); @@ -194,7 +194,7 @@ public override Task ReplaceContainerStreamAsync( this.ClientContext.ValidateResource(containerProperties.Id); return this.ReplaceStreamInternalAsync( - streamPayload: this.ClientContext.PropertiesSerializer.ToStream(containerProperties), + streamPayload: this.ClientContext.SerializerCore.ToStream(containerProperties), requestOptions: requestOptions, cancellationToken: cancellationToken); } diff --git a/Microsoft.Azure.Cosmos/src/Resource/CosmosClientContext.cs b/Microsoft.Azure.Cosmos/src/Resource/CosmosClientContext.cs index f9c567194c..e2f0ff6def 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/CosmosClientContext.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/CosmosClientContext.cs @@ -27,11 +27,7 @@ internal abstract class CosmosClientContext internal abstract DocumentClient DocumentClient { get; } - internal abstract CosmosSerializer CosmosSerializer { get; } - - internal abstract CosmosSerializer PropertiesSerializer { get; } - - internal abstract CosmosSerializer SqlQuerySpecSerializer { get; } + internal abstract CosmosSerializerCore SerializerCore { get; } internal abstract CosmosResponseFactory ResponseFactory { get; } diff --git a/Microsoft.Azure.Cosmos/src/Resource/CosmosResponseFactory.cs b/Microsoft.Azure.Cosmos/src/Resource/CosmosResponseFactory.cs index 34a565bb76..315e27b179 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/CosmosResponseFactory.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/CosmosResponseFactory.cs @@ -5,67 +5,59 @@ namespace Microsoft.Azure.Cosmos { using System; + using System.IO; using System.Threading.Tasks; using Microsoft.Azure.Cosmos.Scripts; internal class CosmosResponseFactory { - /// - /// Cosmos JSON converter. This allows custom JSON parsers. - /// - private readonly CosmosSerializer cosmosSerializer; - /// /// This is used for all meta data types /// - private readonly CosmosSerializer propertiesSerializer; + private readonly CosmosSerializerCore serializerCore; internal CosmosResponseFactory( - CosmosSerializer defaultJsonSerializer, - CosmosSerializer userJsonSerializer) + CosmosSerializerCore jsonSerializerCore) { - this.propertiesSerializer = defaultJsonSerializer; - this.cosmosSerializer = userJsonSerializer; + this.serializerCore = jsonSerializerCore; } - internal FeedResponse CreateQueryFeedResponseWithPropertySerializer( - ResponseMessage cosmosResponseMessage) + internal FeedResponse CreateQueryFeedUserTypeResponse( + ResponseMessage responseMessage) { return this.CreateQueryFeedResponseHelper( - cosmosResponseMessage, - true); + responseMessage, + Documents.ResourceType.Document); } internal FeedResponse CreateQueryFeedResponse( - ResponseMessage cosmosResponseMessage) + ResponseMessage responseMessage, + Documents.ResourceType resourceType) { return this.CreateQueryFeedResponseHelper( - cosmosResponseMessage, - false); + responseMessage, + resourceType); } private FeedResponse CreateQueryFeedResponseHelper( ResponseMessage cosmosResponseMessage, - bool usePropertySerializer) + Documents.ResourceType resourceType) { //Throw the exception cosmosResponseMessage.EnsureSuccessStatusCode(); - // The property serializer should be used for internal - // query operations like throughput since user serializer can break the logic - CosmosSerializer serializer = usePropertySerializer ? this.propertiesSerializer : this.cosmosSerializer; - QueryResponse queryResponse = cosmosResponseMessage as QueryResponse; if (queryResponse != null) { return QueryResponse.CreateResponse( cosmosQueryResponse: queryResponse, - jsonSerializer: serializer); + serializerCore: this.serializerCore); } return ReadFeedResponse.CreateResponse( cosmosResponseMessage, - serializer); + this.serializerCore, + resourceType); } internal Task> CreateItemResponseAsync( @@ -73,7 +65,7 @@ internal Task> CreateItemResponseAsync( { return this.ProcessMessageAsync(cosmosResponseMessageTask, (cosmosResponseMessage) => { - T item = this.ToObjectInternal(cosmosResponseMessage, this.cosmosSerializer); + T item = this.ToObjectInternal(cosmosResponseMessage); return new ItemResponse( cosmosResponseMessage.StatusCode, cosmosResponseMessage.Headers, @@ -88,7 +80,7 @@ internal Task CreateContainerResponseAsync( { return this.ProcessMessageAsync(cosmosResponseMessageTask, (cosmosResponseMessage) => { - ContainerProperties containerProperties = this.ToObjectInternal(cosmosResponseMessage, this.propertiesSerializer); + ContainerProperties containerProperties = this.ToObjectInternal(cosmosResponseMessage); return new ContainerResponse( cosmosResponseMessage.StatusCode, cosmosResponseMessage.Headers, @@ -104,7 +96,7 @@ internal Task CreateUserResponseAsync( { return this.ProcessMessageAsync(cosmosResponseMessageTask, (cosmosResponseMessage) => { - UserProperties userProperties = this.ToObjectInternal(cosmosResponseMessage, this.propertiesSerializer); + UserProperties userProperties = this.ToObjectInternal(cosmosResponseMessage); return new UserResponse( cosmosResponseMessage.StatusCode, cosmosResponseMessage.Headers, @@ -120,7 +112,7 @@ internal Task CreatePermissionResponseAsync( { return this.ProcessMessageAsync(cosmosResponseMessageTask, (cosmosResponseMessage) => { - PermissionProperties permissionProperties = this.ToObjectInternal(cosmosResponseMessage, this.propertiesSerializer); + PermissionProperties permissionProperties = this.ToObjectInternal(cosmosResponseMessage); return new PermissionResponse( cosmosResponseMessage.StatusCode, cosmosResponseMessage.Headers, @@ -136,9 +128,7 @@ internal Task CreateDatabaseResponseAsync( { return this.ProcessMessageAsync(cosmosResponseMessageTask, (cosmosResponseMessage) => { - DatabaseProperties databaseProperties = this.ToObjectInternal( - cosmosResponseMessage, - this.propertiesSerializer); + DatabaseProperties databaseProperties = this.ToObjectInternal(cosmosResponseMessage); return new DatabaseResponse( cosmosResponseMessage.StatusCode, @@ -154,7 +144,7 @@ internal Task CreateThroughputResponseAsync( { return this.ProcessMessageAsync(cosmosResponseMessageTask, (cosmosResponseMessage) => { - ThroughputProperties throughputProperties = this.ToObjectInternal(cosmosResponseMessage, this.propertiesSerializer); + ThroughputProperties throughputProperties = this.ToObjectInternal(cosmosResponseMessage); return new ThroughputResponse( cosmosResponseMessage.StatusCode, cosmosResponseMessage.Headers, @@ -167,7 +157,7 @@ internal Task> CreateStoredProcedureExecuteRes { return this.ProcessMessageAsync(cosmosResponseMessageTask, (cosmosResponseMessage) => { - T item = this.ToObjectInternal(cosmosResponseMessage, this.cosmosSerializer); + T item = this.ToObjectInternal(cosmosResponseMessage); return new StoredProcedureExecuteResponse( cosmosResponseMessage.StatusCode, cosmosResponseMessage.Headers, @@ -180,7 +170,7 @@ internal Task CreateStoredProcedureResponseAsync(Task { - StoredProcedureProperties cosmosStoredProcedure = this.ToObjectInternal(cosmosResponseMessage, this.propertiesSerializer); + StoredProcedureProperties cosmosStoredProcedure = this.ToObjectInternal(cosmosResponseMessage); return new StoredProcedureResponse( cosmosResponseMessage.StatusCode, cosmosResponseMessage.Headers, @@ -193,7 +183,7 @@ internal Task CreateTriggerResponseAsync(Task { return this.ProcessMessageAsync(cosmosResponseMessageTask, (cosmosResponseMessage) => { - TriggerProperties triggerProperties = this.ToObjectInternal(cosmosResponseMessage, this.propertiesSerializer); + TriggerProperties triggerProperties = this.ToObjectInternal(cosmosResponseMessage); return new TriggerResponse( cosmosResponseMessage.StatusCode, cosmosResponseMessage.Headers, @@ -206,7 +196,7 @@ internal Task CreateUserDefinedFunctionResponseAsyn { return this.ProcessMessageAsync(cosmosResponseMessageTask, (cosmosResponseMessage) => { - UserDefinedFunctionProperties settings = this.ToObjectInternal(cosmosResponseMessage, this.propertiesSerializer); + UserDefinedFunctionProperties settings = this.ToObjectInternal(cosmosResponseMessage); return new UserDefinedFunctionResponse( cosmosResponseMessage.StatusCode, cosmosResponseMessage.Headers, @@ -219,21 +209,21 @@ internal async Task ProcessMessageAsync(Task cosmosRespon { using (ResponseMessage message = await cosmosResponseTask) { + //Throw the exception + message.EnsureSuccessStatusCode(); + return createResponse(message); } } - internal T ToObjectInternal(ResponseMessage cosmosResponseMessage, CosmosSerializer jsonSerializer) + internal T ToObjectInternal(ResponseMessage responseMessage) { - //Throw the exception - cosmosResponseMessage.EnsureSuccessStatusCode(); - - if (cosmosResponseMessage.Content == null) + if (responseMessage.Content == null) { return default(T); } - return jsonSerializer.FromStream(cosmosResponseMessage.Content); + return this.serializerCore.FromStream(responseMessage.Content); } } } \ No newline at end of file diff --git a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs index 23bae398cc..737986b018 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Database/DatabaseCore.cs @@ -156,7 +156,7 @@ public override Task CreateContainerAsync( this.ValidateContainerProperties(containerProperties); Task response = this.CreateContainerStreamInternalAsync( - streamPayload: this.ClientContext.PropertiesSerializer.ToStream(containerProperties), + streamPayload: this.ClientContext.SerializerCore.ToStream(containerProperties), throughput: throughput, requestOptions: requestOptions, cancellationToken: cancellationToken); @@ -281,7 +281,7 @@ public override Task CreateContainerStreamAsync( this.ValidateContainerProperties(containerProperties); - Stream streamPayload = this.ClientContext.PropertiesSerializer.ToStream(containerProperties); + Stream streamPayload = this.ClientContext.SerializerCore.ToStream(containerProperties); return this.CreateContainerStreamInternalAsync(streamPayload, throughput, requestOptions, @@ -333,7 +333,7 @@ public Task CreateUserStreamAsync( this.ClientContext.ValidateResource(userProperties.Id); - Stream streamPayload = this.ClientContext.PropertiesSerializer.ToStream(userProperties); + Stream streamPayload = this.ClientContext.SerializerCore.ToStream(userProperties); return this.ProcessUserCreateAsync( streamPayload: streamPayload, requestOptions: requestOptions, @@ -352,7 +352,7 @@ public override Task UpsertUserAsync(string id, this.ClientContext.ValidateResource(id); Task response = this.ProcessUserUpsertAsync( - streamPayload: this.ClientContext.PropertiesSerializer.ToStream(new UserProperties(id)), + streamPayload: this.ClientContext.SerializerCore.ToStream(new UserProperties(id)), requestOptions: requestOptions, cancellationToken: cancellationToken); @@ -423,7 +423,9 @@ public override FeedIterator GetContainerQueryIterator( return new FeedIteratorCore( containerStreamIterator, - this.ClientContext.ResponseFactory.CreateQueryFeedResponse); + (response) => this.ClientContext.ResponseFactory.CreateQueryFeedResponse( + responseMessage: response, + resourceType: ResourceType.Collection)); } public override FeedIterator GetUserQueryIterator(QueryDefinition queryDefinition, @@ -441,7 +443,9 @@ public override FeedIterator GetUserQueryIterator(QueryDefinition queryDef return new FeedIteratorCore( userStreamIterator, - this.ClientContext.ResponseFactory.CreateQueryFeedResponse); + (response) => this.ClientContext.ResponseFactory.CreateQueryFeedResponse( + responseMessage: response, + resourceType: ResourceType.User)); } public FeedIterator GetUserQueryStreamIterator(QueryDefinition queryDefinition, diff --git a/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs b/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs index 9673b9c860..fcd4d6cfd4 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Offer/CosmosOffers.cs @@ -75,7 +75,7 @@ internal async Task ReplaceThroughputAsync( OfferV2 newOffer = new OfferV2(offerV2, throughput); return await this.GetThroughputResponseAsync( - streamPayload: this.ClientContext.PropertiesSerializer.ToStream(newOffer), + streamPayload: this.ClientContext.SerializerCore.ToStream(newOffer), operationType: OperationType.Replace, linkUri: new Uri(offerV2.SelfLink, UriKind.Relative), resourceType: ResourceType.Offer, @@ -95,7 +95,7 @@ internal async Task ReplaceThroughputIfExistsAsync( OfferV2 newOffer = new OfferV2(offerV2, throughput); return await this.GetThroughputResponseAsync( - streamPayload: this.ClientContext.PropertiesSerializer.ToStream(newOffer), + streamPayload: this.ClientContext.SerializerCore.ToStream(newOffer), operationType: OperationType.Replace, linkUri: new Uri(offerV2.SelfLink, UriKind.Relative), resourceType: ResourceType.Offer, @@ -168,7 +168,9 @@ internal virtual FeedIterator GetOfferQueryIterator( return new FeedIteratorCore( databaseStreamIterator, - this.ClientContext.ResponseFactory.CreateQueryFeedResponseWithPropertySerializer); + (response) => this.ClientContext.ResponseFactory.CreateQueryFeedResponse( + responseMessage: response, + resourceType: ResourceType.Offer)); } internal virtual FeedIterator GetOfferQueryStreamIterator( diff --git a/Microsoft.Azure.Cosmos/src/Resource/Permission/PermissionCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Permission/PermissionCore.cs index cb9902a065..55c98cd673 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Permission/PermissionCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Permission/PermissionCore.cs @@ -110,7 +110,7 @@ public override Task ReplaceAsync(PermissionProperties permi this.ClientContext.ValidateResource(permissionProperties.Id); Task response = this.ReplaceStreamInternalAsync( - streamPayload: this.ClientContext.PropertiesSerializer.ToStream(permissionProperties), + streamPayload: this.ClientContext.SerializerCore.ToStream(permissionProperties), tokenExpiryInSeconds: tokenExpiryInSeconds, requestOptions: requestOptions, cancellationToken: cancellationToken); @@ -129,7 +129,7 @@ public Task ReplacePermissionStreamAsync(PermissionProperties p this.ClientContext.ValidateResource(permissionProperties.Id); return this.ReplaceStreamInternalAsync( - streamPayload: this.ClientContext.PropertiesSerializer.ToStream(permissionProperties), + streamPayload: this.ClientContext.SerializerCore.ToStream(permissionProperties), requestOptions: requestOptions, cancellationToken: cancellationToken); } diff --git a/Microsoft.Azure.Cosmos/src/Resource/Scripts/ScriptsCore.cs b/Microsoft.Azure.Cosmos/src/Resource/Scripts/ScriptsCore.cs index 21a72e0b49..c91d95955a 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Scripts/ScriptsCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Scripts/ScriptsCore.cs @@ -31,7 +31,7 @@ public override Task CreateStoredProcedureAsync( return this.ProcessStoredProcedureOperationAsync( linkUri: this.container.LinkUri, operationType: OperationType.Create, - streamPayload: this.clientContext.PropertiesSerializer.ToStream(storedProcedureProperties), + streamPayload: this.clientContext.SerializerCore.ToStream(storedProcedureProperties), requestOptions: requestOptions, cancellationToken: cancellationToken); } @@ -99,7 +99,9 @@ public override FeedIterator GetStoredProcedureQueryIterator( return new FeedIteratorCore( databaseStreamIterator, - this.clientContext.ResponseFactory.CreateQueryFeedResponseWithPropertySerializer); + (response) => this.clientContext.ResponseFactory.CreateQueryFeedResponse( + responseMessage: response, + resourceType: ResourceType.StoredProcedure)); } public override Task ReadStoredProcedureAsync( @@ -128,7 +130,7 @@ public override Task ReplaceStoredProcedureAsync( return this.ProcessStoredProcedureOperationAsync( id: storedProcedureProperties.Id, operationType: OperationType.Replace, - streamPayload: this.clientContext.PropertiesSerializer.ToStream(storedProcedureProperties), + streamPayload: this.clientContext.SerializerCore.ToStream(storedProcedureProperties), requestOptions: requestOptions, cancellationToken: cancellationToken); } @@ -178,7 +180,7 @@ public override Task ExecuteStoredProcedureStreamAsync( Stream streamPayload = null; if (parameters != null) { - streamPayload = this.clientContext.CosmosSerializer.ToStream(parameters); + streamPayload = this.clientContext.SerializerCore.ToStream(parameters); } return this.ExecuteStoredProcedureStreamAsync( @@ -241,7 +243,7 @@ public override Task CreateTriggerAsync( return this.ProcessTriggerOperationAsync( linkUri: this.container.LinkUri, operationType: OperationType.Create, - streamPayload: this.clientContext.PropertiesSerializer.ToStream(triggerProperties), + streamPayload: this.clientContext.SerializerCore.ToStream(triggerProperties), requestOptions: requestOptions, cancellationToken: cancellationToken); } @@ -309,7 +311,9 @@ public override FeedIterator GetTriggerQueryIterator( return new FeedIteratorCore( databaseStreamIterator, - this.clientContext.ResponseFactory.CreateQueryFeedResponseWithPropertySerializer); + (response) => this.clientContext.ResponseFactory.CreateQueryFeedResponse( + responseMessage: response, + resourceType: ResourceType.Trigger)); } public override Task ReadTriggerAsync( @@ -353,7 +357,7 @@ public override Task ReplaceTriggerAsync( return this.ProcessTriggerOperationAsync( id: triggerProperties.Id, operationType: OperationType.Replace, - streamPayload: this.clientContext.PropertiesSerializer.ToStream(triggerProperties), + streamPayload: this.clientContext.SerializerCore.ToStream(triggerProperties), requestOptions: requestOptions, cancellationToken: cancellationToken); } @@ -399,7 +403,7 @@ public override Task CreateUserDefinedFunctionAsync return this.ProcessUserDefinedFunctionOperationAsync( linkUri: this.container.LinkUri, operationType: OperationType.Create, - streamPayload: this.clientContext.PropertiesSerializer.ToStream(userDefinedFunctionProperties), + streamPayload: this.clientContext.SerializerCore.ToStream(userDefinedFunctionProperties), requestOptions: requestOptions, cancellationToken: cancellationToken); } @@ -467,7 +471,9 @@ public override FeedIterator GetUserDefinedFunctionQueryIterator( return new FeedIteratorCore( databaseStreamIterator, - this.clientContext.ResponseFactory.CreateQueryFeedResponseWithPropertySerializer); + (response) => this.clientContext.ResponseFactory.CreateQueryFeedResponse( + responseMessage: response, + resourceType: ResourceType.UserDefinedFunction)); } public override Task ReadUserDefinedFunctionAsync( @@ -511,7 +517,7 @@ public override Task ReplaceUserDefinedFunctionAsyn return this.ProcessUserDefinedFunctionOperationAsync( id: userDefinedFunctionProperties.Id, operationType: OperationType.Replace, - streamPayload: this.clientContext.PropertiesSerializer.ToStream(userDefinedFunctionProperties), + streamPayload: this.clientContext.SerializerCore.ToStream(userDefinedFunctionProperties), requestOptions: requestOptions, cancellationToken: cancellationToken); } diff --git a/Microsoft.Azure.Cosmos/src/Resource/Settings/ThroughputProperties.cs b/Microsoft.Azure.Cosmos/src/Resource/Settings/ThroughputProperties.cs index af0e47f672..6373ca8db4 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/Settings/ThroughputProperties.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/Settings/ThroughputProperties.cs @@ -51,7 +51,7 @@ public class ThroughputProperties /// public int? Throughput { - get => this.Content.OfferThroughput; + get => this.Content?.OfferThroughput; private set => this.Content = new OfferContentV2(value.Value); } diff --git a/Microsoft.Azure.Cosmos/src/Resource/User/UserCore.cs b/Microsoft.Azure.Cosmos/src/Resource/User/UserCore.cs index 2ee1f4d2ce..d59845985f 100644 --- a/Microsoft.Azure.Cosmos/src/Resource/User/UserCore.cs +++ b/Microsoft.Azure.Cosmos/src/Resource/User/UserCore.cs @@ -84,7 +84,7 @@ public override Task ReplaceAsync(UserProperties userProperties, this.ClientContext.ValidateResource(userProperties.Id); Task response = this.ReplaceStreamInternalAsync( - streamPayload: this.ClientContext.PropertiesSerializer.ToStream(userProperties), + streamPayload: this.ClientContext.SerializerCore.ToStream(userProperties), requestOptions: requestOptions, cancellationToken: cancellationToken); @@ -102,7 +102,7 @@ public Task ReplaceStreamAsync(UserProperties userProperties, this.ClientContext.ValidateResource(userProperties.Id); return this.ReplaceStreamInternalAsync( - streamPayload: this.ClientContext.PropertiesSerializer.ToStream(userProperties), + streamPayload: this.ClientContext.SerializerCore.ToStream(userProperties), requestOptions: requestOptions, cancellationToken: cancellationToken); } @@ -156,7 +156,7 @@ public override Task CreatePermissionAsync(PermissionPropert this.ClientContext.ValidateResource(permissionProperties.Id); Task response = this.CreatePermissionStreamInternalAsync( - streamPayload: this.ClientContext.PropertiesSerializer.ToStream(permissionProperties), + streamPayload: this.ClientContext.SerializerCore.ToStream(permissionProperties), tokenExpiryInSeconds: tokenExpiryInSeconds, requestOptions: requestOptions, cancellationToken: cancellationToken); @@ -176,7 +176,7 @@ public Task CreatePermissionStreamAsync(PermissionProperties pe this.ClientContext.ValidateResource(permissionProperties.Id); - Stream streamPayload = this.ClientContext.PropertiesSerializer.ToStream(permissionProperties); + Stream streamPayload = this.ClientContext.SerializerCore.ToStream(permissionProperties); return this.CreatePermissionStreamInternalAsync(streamPayload, tokenExpiryInSeconds, requestOptions, @@ -196,7 +196,7 @@ public override Task UpsertPermissionAsync(PermissionPropert this.ClientContext.ValidateResource(permissionProperties.Id); Task response = this.UpsertPermissionStreamInternalAsync( - streamPayload: this.ClientContext.PropertiesSerializer.ToStream(permissionProperties), + streamPayload: this.ClientContext.SerializerCore.ToStream(permissionProperties), tokenExpiryInSeconds: tokenExpiryInSeconds, requestOptions: requestOptions, cancellationToken: cancellationToken); @@ -219,7 +219,9 @@ public override FeedIterator GetPermissionQueryIterator(QueryDefinition qu return new FeedIteratorCore( permissionStreamIterator, - this.ClientContext.ResponseFactory.CreateQueryFeedResponseWithPropertySerializer); + (response) => this.ClientContext.ResponseFactory.CreateQueryFeedResponse( + responseMessage: response, + resourceType: ResourceType.Permission)); } public FeedIterator GetPermissionQueryStreamIterator(QueryDefinition queryDefinition, diff --git a/Microsoft.Azure.Cosmos/src/Serializer/CosmosSerializerCore.cs b/Microsoft.Azure.Cosmos/src/Serializer/CosmosSerializerCore.cs new file mode 100644 index 0000000000..52fe3ddff1 --- /dev/null +++ b/Microsoft.Azure.Cosmos/src/Serializer/CosmosSerializerCore.cs @@ -0,0 +1,142 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.IO; + using Microsoft.Azure.Cosmos.CosmosElements; + using Microsoft.Azure.Cosmos.Query.Core; + using Microsoft.Azure.Cosmos.Query.Core.QueryPlan; + using Microsoft.Azure.Cosmos.Scripts; + using Microsoft.Azure.Documents; + + /// + /// This is an interface to allow a custom serializer to be used by the CosmosClient + /// + internal class CosmosSerializerCore + { + private static readonly CosmosSerializer propertiesSerializer = new CosmosJsonSerializerWrapper(new CosmosJsonDotNetSerializer()); + private readonly CosmosSerializer customSerializer; + private readonly CosmosSerializer sqlQuerySpecSerializer; + + internal CosmosSerializerCore( + CosmosSerializer customSerializer = null) + { + if (customSerializer == null) + { + this.customSerializer = null; + this.sqlQuerySpecSerializer = null; + } + else + { + this.customSerializer = new CosmosJsonSerializerWrapper(customSerializer); + this.sqlQuerySpecSerializer = CosmosSqlQuerySpecJsonConverter.CreateSqlQuerySpecSerializer( + cosmosSerializer: this.customSerializer, + propertiesSerializer: CosmosSerializerCore.propertiesSerializer); + } + } + + internal static CosmosSerializerCore Create( + CosmosSerializer customSerializer, + CosmosSerializationOptions serializationOptions) + { + if (customSerializer != null && serializationOptions != null) + { + throw new ArgumentException("Customer serializer and serialization options can not be set at the same time."); + } + + if (serializationOptions != null) + { + customSerializer = new CosmosJsonSerializerWrapper(new CosmosJsonDotNetSerializer(serializationOptions)); + } + + return new CosmosSerializerCore(customSerializer); + } + + internal T FromStream(Stream stream) + { + CosmosSerializer serializer = this.GetSerializer(); + return serializer.FromStream(stream); + } + + internal Stream ToStream(T input) + { + CosmosSerializer serializer = this.GetSerializer(); + return serializer.ToStream(input); + } + + internal Stream ToStreamSqlQuerySpec(SqlQuerySpec input, ResourceType resourceType) + { + CosmosSerializer serializer = CosmosSerializerCore.propertiesSerializer; + + // All the public types that support query use the custom serializer + // Internal types like offers will use the default serializer. + if (this.customSerializer != null && + (resourceType == ResourceType.Database || + resourceType == ResourceType.Collection || + resourceType == ResourceType.Document || + resourceType == ResourceType.Trigger || + resourceType == ResourceType.UserDefinedFunction || + resourceType == ResourceType.StoredProcedure || + resourceType == ResourceType.Permission || + resourceType == ResourceType.User || + resourceType == ResourceType.Conflict)) + { + serializer = this.sqlQuerySpecSerializer; + } + + return serializer.ToStream(input); + } + + internal IEnumerable FromFeedResponseStream( + Stream stream, + ResourceType resourceType) + { + CosmosArray cosmosArray = CosmosElementSerializer.ToCosmosElements( + stream, + resourceType); + + return CosmosElementSerializer.GetResources( + cosmosArray: cosmosArray, + serializerCore: this); + } + + private CosmosSerializer GetSerializer() + { + if (this.customSerializer == null) + { + return CosmosSerializerCore.propertiesSerializer; + } + + Type inputType = typeof(T); + if (inputType == typeof(AccountProperties) || + inputType == typeof(DatabaseProperties) || + inputType == typeof(ContainerProperties) || + inputType == typeof(PermissionProperties) || + inputType == typeof(StoredProcedureProperties) || + inputType == typeof(TriggerProperties) || + inputType == typeof(UserDefinedFunctionProperties) || + inputType == typeof(UserProperties) || + inputType == typeof(ConflictProperties) || + inputType == typeof(ThroughputProperties) || + inputType == typeof(OfferV2) || + inputType == typeof(PartitionedQueryExecutionInfo)) + { + return CosmosSerializerCore.propertiesSerializer; + } + + if (inputType == typeof(SqlQuerySpec)) + { + throw new ArgumentException("SqlQuerySpec to stream must use the SqlQuerySpec override"); + } + + Debug.Assert(inputType.IsPublic || inputType.IsNested, $"User serializer is being used for internal type:{inputType.FullName}."); + + return this.customSerializer; + } + } +} diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Batch/BatchTestBase.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Batch/BatchTestBase.cs index 25fab2c7e8..815699b8a2 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Batch/BatchTestBase.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Batch/BatchTestBase.cs @@ -233,7 +233,7 @@ protected static Stream TestDocToStream(TestDoc testDoc, bool isSchematized) else { - return TestCommon.Serializer.ToStream(testDoc); + return TestCommon.SerializerCore.ToStream(testDoc); } } @@ -245,7 +245,7 @@ protected static TestDoc StreamToTestDoc(Stream stream, bool isSchematized) } else { - return TestCommon.Serializer.FromStream(stream); + return TestCommon.SerializerCore.FromStream(stream); } } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Batch/CosmosItemBulkTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Batch/CosmosItemBulkTests.cs index 09c91a4cf8..8a005f6bc1 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Batch/CosmosItemBulkTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Batch/CosmosItemBulkTests.cs @@ -14,8 +14,6 @@ namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests [TestClass] public class CosmosItemBulkTests { - private static CosmosSerializer cosmosDefaultJsonSerializer = new CosmosJsonDotNetSerializer(); - private Container container; private Database database; @@ -57,7 +55,7 @@ public async Task CreateItemStream_WithBulk() Assert.AreEqual(HttpStatusCode.Created, result.StatusCode); Assert.IsTrue(result.Headers.RequestCharge > 0); Assert.IsFalse(string.IsNullOrEmpty(result.Diagnostics.ToString())); - MyDocument document = cosmosDefaultJsonSerializer.FromStream(result.Content); + MyDocument document = TestCommon.SerializerCore.FromStream(result.Content); Assert.AreEqual(i.ToString(), document.id); } } @@ -122,7 +120,7 @@ public async Task UpsertItemStream_WithBulk() Assert.AreEqual(HttpStatusCode.Created, result.StatusCode); Assert.IsTrue(result.Headers.RequestCharge > 0); Assert.IsFalse(string.IsNullOrEmpty(result.Diagnostics.ToString())); - MyDocument document = cosmosDefaultJsonSerializer.FromStream(result.Content); + MyDocument document = TestCommon.SerializerCore.FromStream(result.Content); Assert.AreEqual(i.ToString(), document.id); } } @@ -423,17 +421,17 @@ private static Task> ExecuteReadAsync(Container contain private static Task ExecuteCreateStreamAsync(Container container, MyDocument item) { - return container.CreateItemStreamAsync(cosmosDefaultJsonSerializer.ToStream(item), new PartitionKey(item.Status)); + return container.CreateItemStreamAsync(TestCommon.SerializerCore.ToStream(item), new PartitionKey(item.Status)); } private static Task ExecuteUpsertStreamAsync(Container container, MyDocument item) { - return container.UpsertItemStreamAsync(cosmosDefaultJsonSerializer.ToStream(item), new PartitionKey(item.Status)); + return container.UpsertItemStreamAsync(TestCommon.SerializerCore.ToStream(item), new PartitionKey(item.Status)); } private static Task ExecuteReplaceStreamAsync(Container container, MyDocument item) { - return container.ReplaceItemStreamAsync(cosmosDefaultJsonSerializer.ToStream(item), item.id, new PartitionKey(item.Status)); + return container.ReplaceItemStreamAsync(TestCommon.SerializerCore.ToStream(item), item.id, new PartitionKey(item.Status)); } private static Task ExecuteDeleteStreamAsync(Container container, MyDocument item) diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ChangeFeed/SmokeTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ChangeFeed/SmokeTests.cs index 186b563f71..a9b63559f1 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ChangeFeed/SmokeTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/ChangeFeed/SmokeTests.cs @@ -212,7 +212,7 @@ private class FailedUserSerializer : CosmosSerializer public override T FromStream(Stream stream) { // Only let changes serialization pass through - if (typeof(T) == typeof(CosmosFeedResponseUtil)) + if (typeof(T) == typeof(TestClass)) { return this.cosmosSerializer.FromStream(stream); } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosBasicQueryTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosBasicQueryTests.cs index 1133d8ed2b..9d88f39811 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosBasicQueryTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosBasicQueryTests.cs @@ -555,8 +555,8 @@ private async Task> ToListAsync( response.EnsureSuccessStatusCode(); Assert.AreEqual(expectedStatus, response.StatusCode); - ICollection responseResults = TestCommon.Serializer.FromStream>(response.Content).Data; - Assert.IsTrue(responseResults.Count <= 1); + IEnumerable responseResults = TestCommon.SerializerCore.FromStream>(response.Content).Data; + Assert.IsTrue(responseResults.Count() <= 1); pagedStreamResults.AddRange(responseResults); continuationToken = response.Headers.ContinuationToken; diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosDiagnosticsTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosDiagnosticsTests.cs index 36337cf29f..6802b662d5 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosDiagnosticsTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosDiagnosticsTests.cs @@ -63,7 +63,7 @@ public async Task PointOperationDiagnostic() //Checking point operation diagnostics on stream operations ResponseMessage createStreamResponse = await this.Container.CreateItemStreamAsync( partitionKey: new PartitionKey(testItem.status), - streamPayload: TestCommon.Serializer.ToStream(testItem)); + streamPayload: TestCommon.SerializerCore.ToStream(testItem)); CosmosDiagnosticsTests.VerifyPointDiagnostics(createStreamResponse.Diagnostics); ResponseMessage readStreamResponse = await this.Container.ReadItemStreamAsync( @@ -72,7 +72,7 @@ public async Task PointOperationDiagnostic() CosmosDiagnosticsTests.VerifyPointDiagnostics(readStreamResponse.Diagnostics); ResponseMessage replaceStreamResponse = await this.Container.ReplaceItemStreamAsync( - streamPayload: TestCommon.Serializer.ToStream(testItem), + streamPayload: TestCommon.SerializerCore.ToStream(testItem), id: testItem.id, partitionKey: new PartitionKey(testItem.status)); CosmosDiagnosticsTests.VerifyPointDiagnostics(replaceStreamResponse.Diagnostics); @@ -86,7 +86,7 @@ public async Task PointOperationDiagnostic() testItem.description = new string('x', Microsoft.Azure.Documents.Constants.MaxResourceSizeInBytes + 1); ResponseMessage createTooBigStreamResponse = await this.Container.CreateItemStreamAsync( partitionKey: new PartitionKey(testItem.status), - streamPayload: TestCommon.Serializer.ToStream(testItem)); + streamPayload: TestCommon.SerializerCore.ToStream(testItem)); Assert.IsFalse(createTooBigStreamResponse.IsSuccessStatusCode); CosmosDiagnosticsTests.VerifyPointDiagnostics(createTooBigStreamResponse.Diagnostics); } @@ -222,7 +222,7 @@ private async Task ExecuteQueryAndReturnOutputDocumentCount(string queryTe while (streamIterator.HasMoreResults) { ResponseMessage response = await streamIterator.ReadNextAsync(); - Collection result = TestCommon.Serializer.FromStream>(response.Content).Data; + Collection result = TestCommon.SerializerCore.FromStream>(response.Content).Data; streamResults.AddRange(result); VerifyQueryDiagnostics(response.Diagnostics); } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosHandlersTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosHandlersTests.cs index 88ec42dc76..8db9a6186d 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosHandlersTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosHandlersTests.cs @@ -51,7 +51,7 @@ public async Task TestCustomPropertyWithHandler() ToDoActivity testItem = CreateRandomToDoActivity(); using (ResponseMessage response = await customClient.GetContainer(this.database.Id, this.Container.Id).CreateItemStreamAsync( partitionKey: new Cosmos.PartitionKey(testItem.status), - streamPayload: TestCommon.Serializer.ToStream(testItem))) + streamPayload: TestCommon.SerializerCore.ToStream(testItem))) { Assert.IsNotNull(response); Assert.IsNotNull(response.RequestMessage); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemChangeFeedTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemChangeFeedTests.cs index 66d4346cdf..8476ceac3c 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemChangeFeedTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemChangeFeedTests.cs @@ -83,7 +83,7 @@ await feedIterator.ReadNextAsync(this.cancellationToken)) Assert.AreEqual(pkRangesCount, deserializedToken.Count); if (responseMessage.IsSuccessStatusCode) { - Collection response = TestCommon.Serializer.FromStream>(responseMessage.Content).Data; + Collection response = TestCommon.SerializerCore.FromStream>(responseMessage.Content).Data; totalCount += response.Count; } @@ -124,7 +124,7 @@ await setIteratorNew.ReadNextAsync(this.cancellationToken)) if (responseMessage.IsSuccessStatusCode) { - Collection response = TestCommon.Serializer.FromStream>(responseMessage.Content).Data; + Collection response = TestCommon.SerializerCore.FromStream>(responseMessage.Content).Data; totalCount += response.Count; } @@ -176,7 +176,7 @@ await feedIterator.ReadNextAsync(this.cancellationToken)) currentRange = deserializedToken[0].Range; if (responseMessage.IsSuccessStatusCode) { - Collection response = TestCommon.Serializer.FromStream>(responseMessage.Content).Data; + Collection response = TestCommon.SerializerCore.FromStream>(responseMessage.Content).Data; totalCount += response.Count; } else @@ -251,7 +251,7 @@ await feedIterator.ReadNextAsync(this.cancellationToken)) { if (responseMessage.IsSuccessStatusCode) { - Collection response = TestCommon.Serializer.FromStream>(responseMessage.Content).Data; + Collection response = TestCommon.SerializerCore.FromStream>(responseMessage.Content).Data; if (response.Count > 0) { Assert.AreEqual(1, response.Count); @@ -291,7 +291,7 @@ await feedIterator.ReadNextAsync(this.cancellationToken)) Assert.AreEqual(responseMessage.ContinuationToken, responseMessage.Headers.ContinuationToken); if (responseMessage.IsSuccessStatusCode) { - Collection response = TestCommon.Serializer.FromStream>(responseMessage.Content).Data; + Collection response = TestCommon.SerializerCore.FromStream>(responseMessage.Content).Data; count += response.Count; } } @@ -364,7 +364,7 @@ await iteratorForToken.ReadNextAsync(this.cancellationToken)) break; } - Collection response = TestCommon.Serializer.FromStream>(responseMessage.Content).Data; + Collection response = TestCommon.SerializerCore.FromStream>(responseMessage.Content).Data; count += response.Count; } } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs index ca4d06fea4..ea1a515fb1 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemLinqTests.cs @@ -108,7 +108,7 @@ public async Task ItemLinqReadFeedTest(bool useStatelessIterator) { lastContinuationToken = responseMessage.Headers.ContinuationToken; - Collection items = TestCommon.Serializer.FromStream>(responseMessage.Content).Data; + Collection items = TestCommon.SerializerCore.FromStream>(responseMessage.Content).Data; foreach (ToDoActivity toDoActivity in items) { if (itemIds.Contains(toDoActivity.id)) @@ -384,7 +384,7 @@ public async Task ItemLINQWithCamelCaseSerializerOptions(bool isGatewayMode) action.WithConnectionModeGateway(); } }; - CosmosClient camelCaseCosmosClient = TestCommon.CreateCosmosClient(builder); + CosmosClient camelCaseCosmosClient = TestCommon.CreateCosmosClient(builder, false); Cosmos.Database database = camelCaseCosmosClient.GetDatabase(this.database.Id); Container containerFromCamelCaseClient = database.GetContainer(this.Container.Id); IList itemList = await ToDoActivity.CreateRandomItems(container: containerFromCamelCaseClient, pkCount: 2, perPKItemCount: 1, randomPartitionKey: true); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs index 11984bc6de..c1cb95c217 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosItemTests.cs @@ -73,7 +73,7 @@ public async Task CreateDropItemTest() public async Task NegativeCreateDropItemTest() { ToDoActivity testItem = ToDoActivity.CreateRandomToDoActivity(); - ResponseMessage response = await this.Container.CreateItemStreamAsync(streamPayload: TestCommon.Serializer.ToStream(testItem), partitionKey: new Cosmos.PartitionKey("BadKey")); + ResponseMessage response = await this.Container.CreateItemStreamAsync(streamPayload: TestCommon.SerializerCore.ToStream(testItem), partitionKey: new Cosmos.PartitionKey("BadKey")); Assert.IsNotNull(response); Assert.IsNull(response.Content); Assert.AreEqual(HttpStatusCode.BadRequest, response.StatusCode); @@ -324,7 +324,7 @@ public async Task NonPartitionKeyLookupCacheTest() public async Task CreateDropItemStreamTest() { ToDoActivity testItem = ToDoActivity.CreateRandomToDoActivity(); - using (Stream stream = TestCommon.Serializer.ToStream(testItem)) + using (Stream stream = TestCommon.SerializerCore.ToStream(testItem)) { using (ResponseMessage response = await this.Container.CreateItemStreamAsync(partitionKey: new Cosmos.PartitionKey(testItem.status), streamPayload: stream)) { @@ -349,7 +349,7 @@ public async Task CreateDropItemStreamTest() public async Task UpsertItemStreamTest() { ToDoActivity testItem = ToDoActivity.CreateRandomToDoActivity(); - using (Stream stream = TestCommon.Serializer.ToStream(testItem)) + using (Stream stream = TestCommon.SerializerCore.ToStream(testItem)) { //Create the object using (ResponseMessage response = await this.Container.UpsertItemStreamAsync(partitionKey: new Cosmos.PartitionKey(testItem.status), streamPayload: stream)) @@ -365,7 +365,7 @@ public async Task UpsertItemStreamTest() //Updated the taskNum field testItem.taskNum = 9001; - using (Stream stream = TestCommon.Serializer.ToStream(testItem)) + using (Stream stream = TestCommon.SerializerCore.ToStream(testItem)) { using (ResponseMessage response = await this.Container.UpsertItemStreamAsync(partitionKey: new Cosmos.PartitionKey(testItem.status), streamPayload: stream)) { @@ -384,7 +384,7 @@ public async Task UpsertItemStreamTest() public async Task ReplaceItemStreamTest() { ToDoActivity testItem = ToDoActivity.CreateRandomToDoActivity(); - using (Stream stream = TestCommon.Serializer.ToStream(testItem)) + using (Stream stream = TestCommon.SerializerCore.ToStream(testItem)) { //Replace a non-existing item. It should fail, and not throw an exception. using (ResponseMessage response = await this.Container.ReplaceItemStreamAsync( @@ -398,7 +398,7 @@ public async Task ReplaceItemStreamTest() } } - using (Stream stream = TestCommon.Serializer.ToStream(testItem)) + using (Stream stream = TestCommon.SerializerCore.ToStream(testItem)) { //Create the item using (ResponseMessage response = await this.Container.CreateItemStreamAsync(partitionKey: new Cosmos.PartitionKey(testItem.status), streamPayload: stream)) @@ -410,7 +410,7 @@ public async Task ReplaceItemStreamTest() //Updated the taskNum field testItem.taskNum = 9001; - using (Stream stream = TestCommon.Serializer.ToStream(testItem)) + using (Stream stream = TestCommon.SerializerCore.ToStream(testItem)) { using (ResponseMessage response = await this.Container.ReplaceItemStreamAsync(partitionKey: new Cosmos.PartitionKey(testItem.status), id: testItem.id, streamPayload: stream)) { @@ -458,7 +458,7 @@ await feedIterator.ReadNextAsync(this.cancellationToken)) { lastContinuationToken = responseMessage.Headers.ContinuationToken; Assert.AreEqual(responseMessage.ContinuationToken, responseMessage.Headers.ContinuationToken); - Collection response = TestCommon.Serializer.FromStream>(responseMessage.Content).Data; + Collection response = TestCommon.SerializerCore.FromStream>(responseMessage.Content).Data; foreach (ToDoActivity toDoActivity in response) { if (itemIds.Contains(toDoActivity.id)) @@ -600,7 +600,7 @@ public async Task ItemCustomSerialzierTest() // Each parameter in query spec should be a call to the custom serializer int parameterCount = queryDefinition.ToSqlQuerySpec().Parameters.Count; Assert.AreEqual(parameterCount, toStreamCount, $"missing to stream call. Expected: {parameterCount}, Actual: {toStreamCount} for query:{queryDefinition.ToSqlQuerySpec().QueryText}"); - Assert.AreEqual(1, fromStreamCount); + Assert.AreEqual(allItems.Count, fromStreamCount); } } @@ -866,7 +866,7 @@ public async Task ItemMultiplePartitionOrderByQueryStream() Assert.IsNull(iter.ErrorMessage); totalRequstCharge += iter.Headers.RequestCharge; - ToDoActivity[] activities = TestCommon.Serializer.FromStream>(iter.Content).Data.ToArray(); + ToDoActivity[] activities = TestCommon.SerializerCore.FromStream>(iter.Content).Data.ToArray(); Assert.AreEqual(1, activities.Length); ToDoActivity response = activities.First(); resultList.Add(response); @@ -913,7 +913,7 @@ public async Task ItemMultiplePartitionQueryStream() Assert.IsTrue(iter.IsSuccessStatusCode); Assert.IsNull(iter.ErrorMessage); totalRequstCharge += iter.Headers.RequestCharge; - ToDoActivity[] response = TestCommon.Serializer.FromStream>(iter.Content).Data.ToArray(); + ToDoActivity[] response = TestCommon.SerializerCore.FromStream>(iter.Content).Data.ToArray(); Assert.IsTrue(response.Length <= 5); resultList.AddRange(response); } @@ -962,7 +962,7 @@ public async Task ItemSinglePartitionQueryStream() Assert.IsTrue(iter.IsSuccessStatusCode); Assert.IsNull(iter.ErrorMessage); totalRequstCharge += iter.Headers.RequestCharge; - Collection response = TestCommon.Serializer.FromStream>(iter.Content).Data; + Collection response = TestCommon.SerializerCore.FromStream>(iter.Content).Data; foundItems.AddRange(response); } @@ -1521,7 +1521,7 @@ public async Task VerifyToManyRequestTest(bool isQuery) ToDoActivity temp = ToDoActivity.CreateRandomToDoActivity(); createItems[i] = container.CreateItemStreamAsync( partitionKey: new Cosmos.PartitionKey(temp.status), - streamPayload: TestCommon.Serializer.ToStream(temp)); + streamPayload: TestCommon.SerializerCore.ToStream(temp)); } Task.WaitAll(createItems); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosJsonSerializerTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosJsonSerializerTests.cs index ec58924dc5..e280d1cfae 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosJsonSerializerTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosJsonSerializerTests.cs @@ -5,11 +5,16 @@ namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests { using System; + using System.Collections.Generic; + using System.Globalization; using System.IO; using System.Net; using System.Threading.Tasks; + using Microsoft.Azure.Cosmos.Query; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; + using Newtonsoft.Json; + using Newtonsoft.Json.Serialization; [TestClass] public class CosmosJsonSerializerTests : BaseCosmosClientHelper @@ -34,6 +39,102 @@ public async Task Cleanup() await base.TestCleanup(); } + [TestMethod] + public async Task TestQueryWithCustomJsonSerializer() + { + int toStreamCount = 0; + int fromStreamCount = 0; + CosmosSerializer serializer = new CosmosSerializerHelper(new Newtonsoft.Json.JsonSerializerSettings() + { + NullValueHandling = NullValueHandling.Ignore + }, + (item) => fromStreamCount++, + (item) => toStreamCount++); + + CosmosClient client = TestCommon.CreateCosmosClient(builder => builder.WithCustomSerializer(serializer)); + Database database = await client.CreateDatabaseAsync(Guid.NewGuid().ToString()); + try + { + Container container = await database.CreateContainerAsync(Guid.NewGuid().ToString(), "/id"); + Assert.AreEqual(0, toStreamCount); + Assert.AreEqual(0, fromStreamCount); + + double cost = 9001.42; + for (int i = 0; i < 5; i++) + { + ToDoActivity toDoActivity = new ToDoActivity() + { + id = "TestId" + i, + cost = cost + }; + + await container.CreateItemAsync(toDoActivity, new PartitionKey(toDoActivity.id)); + } + + Assert.AreEqual(5, toStreamCount); + Assert.AreEqual(5, fromStreamCount); + + toStreamCount = 0; + fromStreamCount = 0; + + QueryDefinition query = new QueryDefinition("select * from T where T.id != @id"). + WithParameter("@id", Guid.NewGuid()); + + FeedIterator feedIterator = client.GetDatabaseQueryIterator( + query); + List databases = new List(); + while (feedIterator.HasMoreResults) + { + databases.AddRange(await feedIterator.ReadNextAsync()); + } + + Assert.AreEqual(1, toStreamCount, "parameter should use custom serializer"); + Assert.AreEqual(0, fromStreamCount); + + toStreamCount = 0; + fromStreamCount = 0; + + FeedIterator itemIterator = container.GetItemQueryIterator( + query); + List items = new List(); + while (itemIterator.HasMoreResults) + { + items.AddRange(await itemIterator.ReadNextAsync()); + } + + Assert.AreEqual(1, toStreamCount); + Assert.AreEqual(5, fromStreamCount); + + toStreamCount = 0; + fromStreamCount = 0; + + // Verify that the custom serializer is actually being used via stream + FeedIterator itemStreamIterator = container.GetItemQueryStreamIterator( + query); + while (itemStreamIterator.HasMoreResults) + { + ResponseMessage response = await itemStreamIterator.ReadNextAsync(); + using (StreamReader reader = new StreamReader(response.Content)) + { + string content = await reader.ReadToEndAsync(); + Assert.IsTrue(content.Contains("9001.42")); + Assert.IsFalse(content.Contains("description"), "Description should be ignored and not in the JSON"); + } + } + + Assert.AreEqual(1, toStreamCount); + Assert.AreEqual(0, fromStreamCount); + + } + finally + { + if(database != null) + { + using (await database.DeleteStreamAsync()) { } + } + } + } + [TestMethod] public async Task TestCustomJsonSerializer() { @@ -46,7 +147,7 @@ public async Task TestCustomJsonSerializer() ToDoActivity testItem = this.CreateRandomToDoActivity(); mockJsonSerializer.Setup(x => x.ToStream(It.IsAny())) .Callback(() => toStreamCount++) - .Returns(TestCommon.Serializer.ToStream(testItem)); + .Returns(TestCommon.SerializerCore.ToStream(testItem)); mockJsonSerializer.Setup(x => x.FromStream(It.IsAny())) .Callback(x => { x.Dispose(); fromStreamCount++; }) @@ -111,6 +212,7 @@ private ToDoActivity CreateRandomToDoActivity(string pk = null) public class ToDoActivity { + [JsonProperty(PropertyName = "id")] public string id { get; set; } public int taskNum { get; set; } public double cost { get; set; } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosNotFoundTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosNotFoundTests.cs index 1874d0d0d8..2d1999fe77 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosNotFoundTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosNotFoundTests.cs @@ -131,7 +131,7 @@ private async Task ItemOperations(Container container, bool containerNotExist) if (containerNotExist) { dynamic randomItem = new { id = "test", pk = "doesnotexist" }; - Stream create = TestCommon.Serializer.ToStream(randomItem); + Stream create = TestCommon.SerializerCore.ToStream(randomItem); this.VerifyNotFoundResponse(await container.CreateItemStreamAsync(create, new PartitionKey(randomItem.pk))); FeedIterator queryIterator = container.GetItemQueryStreamIterator( @@ -144,7 +144,7 @@ private async Task ItemOperations(Container container, bool containerNotExist) this.VerifyNotFoundResponse(await feedIterator.ReadNextAsync()); dynamic randomUpsertItem = new { id = DoesNotExist, pk = DoesNotExist, status = 42 }; - Stream upsert = TestCommon.Serializer.ToStream(randomUpsertItem); + Stream upsert = TestCommon.SerializerCore.ToStream(randomUpsertItem); this.VerifyNotFoundResponse(await container.UpsertItemStreamAsync( partitionKey: new Cosmos.PartitionKey(randomUpsertItem.pk), streamPayload: upsert)); @@ -154,7 +154,7 @@ private async Task ItemOperations(Container container, bool containerNotExist) this.VerifyNotFoundResponse(await container.DeleteItemStreamAsync(partitionKey: new Cosmos.PartitionKey(DoesNotExist), id: DoesNotExist)); dynamic randomReplaceItem = new { id = "test", pk = "doesnotexist", status = 42 }; - Stream replace = TestCommon.Serializer.ToStream(randomReplaceItem); + Stream replace = TestCommon.SerializerCore.ToStream(randomReplaceItem); this.VerifyNotFoundResponse(await container.ReplaceItemStreamAsync( partitionKey: new Cosmos.PartitionKey(randomReplaceItem.pk), id: randomReplaceItem.id, diff --git a/Microsoft.Azure.Cosmos/src/Query/Core/CosmosFeedResponseUtil.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Utils/CosmosFeedResponseUtil.cs similarity index 64% rename from Microsoft.Azure.Cosmos/src/Query/Core/CosmosFeedResponseUtil.cs rename to Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Utils/CosmosFeedResponseUtil.cs index 005d556f7c..9aa117c6af 100644 --- a/Microsoft.Azure.Cosmos/src/Query/Core/CosmosFeedResponseUtil.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Utils/CosmosFeedResponseUtil.cs @@ -1,9 +1,11 @@ //------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ -namespace Microsoft.Azure.Cosmos.Query.Core +namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests { + using System; using System.Collections.ObjectModel; + using Newtonsoft.Json; /// /// This is a helper class that is used to get the query response collection. @@ -13,80 +15,94 @@ namespace Microsoft.Azure.Cosmos.Query.Core /// store the collection. Then the response object will use the Data property to /// access the collection. This prevents having a class for each different property. /// - internal sealed class CosmosFeedResponseUtil + public sealed class CosmosFeedResponseUtil { /// /// All the properties use this to store the collection. /// - public Collection Data { get; set; } + public Collection Data { get; private set; } - public Collection Attachments + internal Type InnerType { get; } = typeof(T); + + [JsonProperty] + internal Collection Attachments { get => this.Data; set => this.Data = value; } - public Collection DocumentCollections + [JsonProperty] + internal Collection DocumentCollections { get => this.Data; set => this.Data = value; } - public Collection Databases + [JsonProperty] + internal Collection Databases { get => this.Data; set => this.Data = value; } - public Collection Documents + [JsonProperty] + internal Collection Documents { get => this.Data; set => this.Data = value; } - public Collection Offers + [JsonProperty] + internal Collection Offers { get => this.Data; set => this.Data = value; } - public Collection Triggers + [JsonProperty] + internal Collection Triggers { get => this.Data; set => this.Data = value; } - public Collection UserDefinedFunctions + [JsonProperty] + internal Collection UserDefinedFunctions { get => this.Data; set => this.Data = value; } - public Collection UserDefinedTypes + [JsonProperty] + internal Collection UserDefinedTypes { get => this.Data; set => this.Data = value; } - public Collection StoredProcedures + [JsonProperty] + internal Collection StoredProcedures { get => this.Data; set => this.Data = value; } - public Collection Conflicts + [JsonProperty] + internal Collection Conflicts { get => this.Data; set => this.Data = value; } - public Collection Users + [JsonProperty] + internal Collection Users { get => this.Data; set => this.Data = value; } - public Collection Permissions + [JsonProperty] + internal Collection Permissions { get => this.Data; set => this.Data = value; diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Utils/CosmosSerializerHelper.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Utils/CosmosSerializerHelper.cs index 0fa9067d41..70c573560e 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Utils/CosmosSerializerHelper.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Utils/CosmosSerializerHelper.cs @@ -14,7 +14,7 @@ namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests /// internal class CosmosSerializerHelper : CosmosSerializer { - private readonly CosmosSerializer cosmosSerializer = TestCommon.Serializer; + private readonly CosmosSerializer cosmosSerializer; private readonly Action fromStreamCallback; private readonly Action toStreamCallBack; @@ -25,7 +25,7 @@ public CosmosSerializerHelper( { if (jsonSerializerSettings == null) { - this.cosmosSerializer = TestCommon.Serializer; + this.cosmosSerializer = new CosmosJsonDotNetSerializer(); } else { diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Utils/TestCommon.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Utils/TestCommon.cs index 875b88a32f..657add2548 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Utils/TestCommon.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/Utils/TestCommon.cs @@ -43,7 +43,9 @@ internal static class TestCommon private static readonly int serverStalenessIntervalInSeconds; private static readonly int masterStalenessIntervalInSeconds; - public static readonly CosmosSerializer Serializer = new CosmosJsonDotNetSerializer(); + + // Passing in the a custom serializer instance will cause all the checks for internal types to validated. + public static readonly CosmosSerializerCore SerializerCore = new CosmosSerializerCore(new CosmosJsonDotNetSerializer()); static TestCommon() { @@ -59,16 +61,21 @@ internal static (string endpoint, string authKey) GetAccountInfo() return (endpoint, authKey); } - internal static CosmosClientBuilder GetDefaultConfiguration() + internal static CosmosClientBuilder GetDefaultConfiguration(bool useCustomSeralizer = true) { (string endpoint, string authKey) accountInfo = TestCommon.GetAccountInfo(); + CosmosClientBuilder clientBuilder = new CosmosClientBuilder(accountEndpoint: accountInfo.endpoint, authKeyOrResourceToken: accountInfo.authKey); + if (useCustomSeralizer) + { + clientBuilder.WithCustomSerializer(new CosmosJsonDotNetSerializer()); + } - return new CosmosClientBuilder(accountEndpoint: accountInfo.endpoint, authKeyOrResourceToken: accountInfo.authKey); + return clientBuilder; } - internal static CosmosClient CreateCosmosClient(Action customizeClientBuilder = null) + internal static CosmosClient CreateCosmosClient(Action customizeClientBuilder = null, bool useCustomSeralizer = true) { - CosmosClientBuilder cosmosClientBuilder = GetDefaultConfiguration(); + CosmosClientBuilder cosmosClientBuilder = GetDefaultConfiguration(useCustomSeralizer); if (customizeClientBuilder != null) { customizeClientBuilder(cosmosClientBuilder); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/Benchmarks/ItemBenchmark.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/Benchmarks/ItemBenchmark.cs index 1d9475b406..6b84631294 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/Benchmarks/ItemBenchmark.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Performance.Tests/Benchmarks/ItemBenchmark.cs @@ -6,12 +6,9 @@ namespace Microsoft.Azure.Cosmos.Performance.Tests.Benchmarks { using System; using System.IO; - using System.Text; using System.Threading.Tasks; using BenchmarkDotNet.Attributes; using Microsoft.Azure.Cosmos; - using Microsoft.Azure.Documents.Collections; - using Newtonsoft.Json; using Newtonsoft.Json.Linq; /// @@ -20,13 +17,11 @@ namespace Microsoft.Azure.Cosmos.Performance.Tests.Benchmarks [MemoryDiagnoser] public class ItemBenchmark { - private static readonly Encoding DefaultEncoding = new UTF8Encoding(false, true); private readonly CosmosClient clientForTests; private readonly Container container; - private readonly JsonSerializer jsonSerializer = new JsonSerializer(); private JObject baseItem; private byte[] payloadBytes; - private dynamic TestItem; + /// /// Initializes a new instance of the class. /// @@ -43,51 +38,6 @@ public ItemBenchmark() this.payloadBytes = ms.ToArray(); } } - - this.TestItem = new - { - id = "test", - pk = "what", - value = 1245, - stop = true, - }; - } - - [Benchmark] - public void SingletonJsonSerializeItem() - { - using (MemoryStream streamPayload = new MemoryStream()) - { - using (StreamWriter streamWriter = new StreamWriter(streamPayload, encoding: ItemBenchmark.DefaultEncoding, bufferSize: 1024, leaveOpen: true)) - { - using (JsonWriter writer = new JsonTextWriter(streamWriter)) - { - writer.Formatting = Newtonsoft.Json.Formatting.None; - this.jsonSerializer.Serialize(writer, this.TestItem); - writer.Flush(); - streamWriter.Flush(); - } - } - } - } - - [Benchmark] - public void InstanceJsonSerializeItem() - { - using (MemoryStream streamPayload = new MemoryStream()) - { - using (StreamWriter streamWriter = new StreamWriter(streamPayload, encoding: ItemBenchmark.DefaultEncoding, bufferSize: 1024, leaveOpen: true)) - { - using (JsonWriter writer = new JsonTextWriter(streamWriter)) - { - writer.Formatting = Newtonsoft.Json.Formatting.None; - JsonSerializer jsonSerializer = new JsonSerializer(); - jsonSerializer.Serialize(writer, this.TestItem); - writer.Flush(); - streamWriter.Flush(); - } - } - } } /// diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncBatcherTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncBatcherTests.cs index d5df23058d..8108f47d43 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncBatcherTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncBatcherTests.cs @@ -54,7 +54,7 @@ private BatchAsyncBatcherExecuteDelegate Executor SinglePartitionKeyServerBatchRequest batchRequest = await SinglePartitionKeyServerBatchRequest.CreateAsync( partitionKey: null, operations: new ArraySegment(arrayOperations), - serializer: new CosmosJsonDotNetSerializer(), + serializerCore: MockCosmosUtil.Serializer, cancellationToken: cancellationToken); TransactionalBatchResponse batchresponse = await TransactionalBatchResponse.FromResponseMessageAsync( @@ -74,7 +74,7 @@ private BatchAsyncBatcherExecuteDelegate Executor clientSideRequestStatistics: new CosmosClientSideRequestStatistics()) }, batchRequest, - new CosmosJsonDotNetSerializer()); + MockCosmosUtil.Serializer); return new PartitionKeyRangeBatchExecutionResult(request.PartitionKeyRangeId, request.Operations, batchresponse); }; @@ -102,7 +102,7 @@ private BatchAsyncBatcherExecuteDelegate ExecutorWithSplit SinglePartitionKeyServerBatchRequest batchRequest = await SinglePartitionKeyServerBatchRequest.CreateAsync( partitionKey: null, operations: new ArraySegment(arrayOperations), - serializer: new CosmosJsonDotNetSerializer(), + serializerCore: MockCosmosUtil.Serializer, cancellationToken: cancellationToken); ResponseMessage responseMessage = new ResponseMessage(HttpStatusCode.Gone) @@ -125,7 +125,7 @@ private BatchAsyncBatcherExecuteDelegate ExecutorWithSplit TransactionalBatchResponse batchresponse = await TransactionalBatchResponse.FromResponseMessageAsync( responseMessage, batchRequest, - new CosmosJsonDotNetSerializer()); + MockCosmosUtil.Serializer); return new PartitionKeyRangeBatchExecutionResult(request.PartitionKeyRangeId, request.Operations, batchresponse); }; @@ -155,13 +155,13 @@ private BatchAsyncBatcherExecuteDelegate ExecutorWithLessResponses SinglePartitionKeyServerBatchRequest batchRequest = await SinglePartitionKeyServerBatchRequest.CreateAsync( partitionKey: null, operations: new ArraySegment(arrayOperations), - serializer: new CosmosJsonDotNetSerializer(), + serializerCore: MockCosmosUtil.Serializer, cancellationToken: cancellationToken); TransactionalBatchResponse batchresponse = await TransactionalBatchResponse.FromResponseMessageAsync( new ResponseMessage(HttpStatusCode.OK) { Content = responseContent }, batchRequest, - new CosmosJsonDotNetSerializer()); + MockCosmosUtil.Serializer); return new PartitionKeyRangeBatchExecutionResult(request.PartitionKeyRangeId, request.Operations, batchresponse); }; @@ -183,7 +183,7 @@ private BatchAsyncBatcherExecuteDelegate ExecutorWithFailure [DataRow(-1)] public void ValidatesSize(int size) { - BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(size, 1, new CosmosJsonDotNetSerializer(), this.Executor, this.Retrier); + BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(size, 1, MockCosmosUtil.Serializer, this.Executor, this.Retrier); } [DataTestMethod] @@ -192,21 +192,21 @@ public void ValidatesSize(int size) [DataRow(-1)] public void ValidatesByteSize(int size) { - BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(1, size, new CosmosJsonDotNetSerializer(), this.Executor, this.Retrier); + BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(1, size, MockCosmosUtil.Serializer, this.Executor, this.Retrier); } [TestMethod] [ExpectedException(typeof(ArgumentNullException))] public void ValidatesExecutor() { - BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(1, 1, new CosmosJsonDotNetSerializer(), null, this.Retrier); + BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(1, 1, MockCosmosUtil.Serializer, null, this.Retrier); } [TestMethod] [ExpectedException(typeof(ArgumentNullException))] public void ValidatesRetrier() { - BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(1, 1, new CosmosJsonDotNetSerializer(), this.Executor, null); + BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(1, 1, MockCosmosUtil.Serializer, this.Executor, null); } [TestMethod] @@ -219,7 +219,7 @@ public void ValidatesSerializer() [TestMethod] public void HasFixedSize() { - BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(2, 1000, new CosmosJsonDotNetSerializer(), this.Executor, this.Retrier); + BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(2, 1000, MockCosmosUtil.Serializer, this.Executor, this.Retrier); Assert.IsTrue(batchAsyncBatcher.TryAdd(this.CreateItemBatchOperation(true))); Assert.IsTrue(batchAsyncBatcher.TryAdd(this.CreateItemBatchOperation(true))); Assert.IsFalse(batchAsyncBatcher.TryAdd(this.CreateItemBatchOperation(true))); @@ -229,9 +229,9 @@ public void HasFixedSize() public async Task HasFixedByteSize() { ItemBatchOperation itemBatchOperation = this.CreateItemBatchOperation(true); - await itemBatchOperation.MaterializeResourceAsync(new CosmosJsonDotNetSerializer(), default(CancellationToken)); + await itemBatchOperation.MaterializeResourceAsync(MockCosmosUtil.Serializer, default(CancellationToken)); // Each operation is 2 bytes - BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(3, 4, new CosmosJsonDotNetSerializer(), this.Executor, this.Retrier); + BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(3, 4, MockCosmosUtil.Serializer, this.Executor, this.Retrier); Assert.IsTrue(batchAsyncBatcher.TryAdd(itemBatchOperation)); Assert.IsTrue(batchAsyncBatcher.TryAdd(itemBatchOperation)); Assert.IsFalse(batchAsyncBatcher.TryAdd(itemBatchOperation)); @@ -240,7 +240,7 @@ public async Task HasFixedByteSize() [TestMethod] public async Task ExceptionsFailOperationsAsync() { - BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(2, 1000, new CosmosJsonDotNetSerializer(), this.ExecutorWithFailure, this.Retrier); + BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(2, 1000, MockCosmosUtil.Serializer, this.ExecutorWithFailure, this.Retrier); ItemBatchOperation operation1 = this.CreateItemBatchOperation(); ItemBatchOperation operation2 = this.CreateItemBatchOperation(); ItemBatchOperationContext context1 = new ItemBatchOperationContext(string.Empty); @@ -260,7 +260,7 @@ public async Task ExceptionsFailOperationsAsync() [TestMethod] public async Task DispatchProcessInOrderAsync() { - BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(10, 1000, new CosmosJsonDotNetSerializer(), this.Executor, this.Retrier); + BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(10, 1000, MockCosmosUtil.Serializer, this.Executor, this.Retrier); List operations = new List(10); for (int i = 0; i < 10; i++) { @@ -289,8 +289,8 @@ public async Task DispatchProcessInOrderAsync() [TestMethod] public async Task DispatchWithLessResponses() { - BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(10, 1000, new CosmosJsonDotNetSerializer(), this.ExecutorWithLessResponses, this.Retrier); - BatchAsyncBatcher secondAsyncBatcher = new BatchAsyncBatcher(10, 1000, new CosmosJsonDotNetSerializer(), this.Executor, this.Retrier); + BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(10, 1000, MockCosmosUtil.Serializer, this.ExecutorWithLessResponses, this.Retrier); + BatchAsyncBatcher secondAsyncBatcher = new BatchAsyncBatcher(10, 1000, MockCosmosUtil.Serializer, this.Executor, this.Retrier); List operations = new List(10); for (int i = 0; i < 10; i++) { @@ -342,14 +342,14 @@ public async Task DispatchWithLessResponses() [TestMethod] public void IsEmptyWithNoOperations() { - BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(10, 1000, new CosmosJsonDotNetSerializer(), this.Executor, this.Retrier); + BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(10, 1000, MockCosmosUtil.Serializer, this.Executor, this.Retrier); Assert.IsTrue(batchAsyncBatcher.IsEmpty); } [TestMethod] public void IsNotEmptyWithOperations() { - BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(1, 1000, new CosmosJsonDotNetSerializer(), this.Executor, this.Retrier); + BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(1, 1000, MockCosmosUtil.Serializer, this.Executor, this.Retrier); Assert.IsTrue(batchAsyncBatcher.TryAdd(this.CreateItemBatchOperation(true))); Assert.IsFalse(batchAsyncBatcher.IsEmpty); } @@ -357,7 +357,7 @@ public void IsNotEmptyWithOperations() [TestMethod] public async Task CannotAddToDispatchedBatch() { - BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(1, 1000, new CosmosJsonDotNetSerializer(), this.Executor, this.Retrier); + BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(1, 1000, MockCosmosUtil.Serializer, this.Executor, this.Retrier); ItemBatchOperation operation = this.CreateItemBatchOperation(); operation.AttachContext(new ItemBatchOperationContext(string.Empty)); Assert.IsTrue(batchAsyncBatcher.TryAdd(operation)); @@ -381,7 +381,7 @@ public async Task RetrierGetsCalledOnSplit() Mock retryDelegate = new Mock(); - BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(2, 1000, new CosmosJsonDotNetSerializer(), this.ExecutorWithSplit, retryDelegate.Object); + BatchAsyncBatcher batchAsyncBatcher = new BatchAsyncBatcher(2, 1000, MockCosmosUtil.Serializer, this.ExecutorWithSplit, retryDelegate.Object); Assert.IsTrue(batchAsyncBatcher.TryAdd(operation1)); Assert.IsTrue(batchAsyncBatcher.TryAdd(operation2)); await batchAsyncBatcher.DispatchAsync(); @@ -405,7 +405,7 @@ public async Task RetrierGetsCalledOnOverFlow() Mock retryDelegate = new Mock(); Mock executeDelegate = new Mock(); - BatchAsyncBatcherThatOverflows batchAsyncBatcher = new BatchAsyncBatcherThatOverflows(2, 1000, new CosmosJsonDotNetSerializer(), executeDelegate.Object, retryDelegate.Object); + BatchAsyncBatcherThatOverflows batchAsyncBatcher = new BatchAsyncBatcherThatOverflows(2, 1000, MockCosmosUtil.Serializer, executeDelegate.Object, retryDelegate.Object); Assert.IsTrue(batchAsyncBatcher.TryAdd(operation1)); Assert.IsTrue(batchAsyncBatcher.TryAdd(operation2)); await batchAsyncBatcher.DispatchAsync(); @@ -419,9 +419,9 @@ private class BatchAsyncBatcherThatOverflows : BatchAsyncBatcher public BatchAsyncBatcherThatOverflows( int maxBatchOperationCount, int maxBatchByteSize, - CosmosSerializer cosmosSerializer, + CosmosSerializerCore serializerCore, BatchAsyncBatcherExecuteDelegate executor, - BatchAsyncBatcherRetryDelegate retrier) : base (maxBatchOperationCount, maxBatchByteSize, cosmosSerializer, executor, retrier) + BatchAsyncBatcherRetryDelegate retrier) : base (maxBatchOperationCount, maxBatchByteSize, serializerCore, executor, retrier) { } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncContainerExecutorCacheTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncContainerExecutorCacheTests.cs index a14f8baae1..8b164ea480 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncContainerExecutorCacheTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncContainerExecutorCacheTests.cs @@ -25,9 +25,7 @@ public async Task ConcurrentGet_ReturnsSameExecutorInstance() CosmosClientContext context = new ClientContextCore( client: mockClient.Object, clientOptions: new CosmosClientOptions() { AllowBulkExecution = true }, - userJsonSerializer: null, - defaultJsonSerializer: null, - sqlQuerySpecSerializer: null, + serializerCore: null, cosmosResponseFactory: null, requestHandler: null, documentClient: null); @@ -61,9 +59,7 @@ public async Task SingleTaskScheduler_ExecutorTest() CosmosClientContext context = new ClientContextCore( client: mockClient.Object, clientOptions: new CosmosClientOptions() { AllowBulkExecution = true }, - userJsonSerializer: null, - defaultJsonSerializer: null, - sqlQuerySpecSerializer: null, + serializerCore: null, cosmosResponseFactory: null, requestHandler: null, documentClient: null); @@ -100,9 +96,7 @@ public void Null_When_OptionsOff() CosmosClientContext context = new ClientContextCore( client: mockClient.Object, clientOptions: new CosmosClientOptions() { }, - userJsonSerializer: null, - defaultJsonSerializer: null, - sqlQuerySpecSerializer: null, + serializerCore: null, cosmosResponseFactory: null, requestHandler: null, documentClient: null); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncContainerExecutorTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncContainerExecutorTests.cs index 979d5600c1..bc3b9c0501 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncContainerExecutorTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncContainerExecutorTests.cs @@ -20,8 +20,6 @@ namespace Microsoft.Azure.Cosmos.Tests [TestClass] public class BatchAsyncContainerExecutorTests { - private static CosmosSerializer cosmosDefaultJsonSerializer = new CosmosJsonDotNetSerializer(); - [TestMethod] public async Task RetryOnSplit() { @@ -43,7 +41,7 @@ public async Task RetryOnSplit() .Returns(this.GenerateSplitResponseAsync(itemBatchOperation)) .Returns(this.GenerateOkResponseAsync(itemBatchOperation)); - mockedContext.Setup(c => c.CosmosSerializer).Returns(new CosmosJsonDotNetSerializer()); + mockedContext.Setup(c => c.SerializerCore).Returns(MockCosmosUtil.Serializer); Uri link = new Uri($"/dbs/db/colls/colls", UriKind.Relative); Mock mockContainer = new Mock(); @@ -109,7 +107,7 @@ public async Task RetryOnNameStale() .Returns(this.GenerateCacheStaleResponseAsync(itemBatchOperation)) .Returns(this.GenerateOkResponseAsync(itemBatchOperation)); - mockedContext.Setup(c => c.CosmosSerializer).Returns(new CosmosJsonDotNetSerializer()); + mockedContext.Setup(c => c.SerializerCore).Returns(MockCosmosUtil.Serializer); Uri link = new Uri($"/dbs/db/colls/colls", UriKind.Relative); Mock mockContainer = new Mock(); @@ -175,7 +173,7 @@ public async Task RetryOn429() .Returns(this.Generate429ResponseAsync(itemBatchOperation)) .Returns(this.GenerateOkResponseAsync(itemBatchOperation)); - mockedContext.Setup(c => c.CosmosSerializer).Returns(new CosmosJsonDotNetSerializer()); + mockedContext.Setup(c => c.SerializerCore).Returns(MockCosmosUtil.Serializer); Uri link = new Uri($"/dbs/db/colls/colls", UriKind.Relative); Mock mockContainer = new Mock(); @@ -240,7 +238,7 @@ public async Task DoesNotRecalculatePartitionKeyRangeOnNoSplits() It.IsAny())) .Returns(this.GenerateOkResponseAsync(itemBatchOperation)); - mockedContext.Setup(c => c.CosmosSerializer).Returns(new CosmosJsonDotNetSerializer()); + mockedContext.Setup(c => c.SerializerCore).Returns(MockCosmosUtil.Serializer); Uri link = new Uri($"/dbs/db/colls/colls", UriKind.Relative); Mock mockContainer = new Mock(); @@ -291,7 +289,7 @@ private async Task GenerateSplitResponseAsync(ItemBatchOperatio SinglePartitionKeyServerBatchRequest batchRequest = await SinglePartitionKeyServerBatchRequest.CreateAsync( partitionKey: null, operations: new ArraySegment(arrayOperations), - serializer: new CosmosJsonDotNetSerializer(), + serializerCore: MockCosmosUtil.Serializer, cancellationToken: CancellationToken.None); ResponseMessage responseMessage = new ResponseMessage(HttpStatusCode.Gone) @@ -331,7 +329,7 @@ private async Task GenerateCacheStaleResponseAsync(ItemBatchOpe SinglePartitionKeyServerBatchRequest batchRequest = await SinglePartitionKeyServerBatchRequest.CreateAsync( partitionKey: null, operations: new ArraySegment(arrayOperations), - serializer: new CosmosJsonDotNetSerializer(), + serializerCore: MockCosmosUtil.Serializer, cancellationToken: CancellationToken.None); ResponseMessage responseMessage = new ResponseMessage(HttpStatusCode.Gone) @@ -370,7 +368,7 @@ private async Task Generate429ResponseAsync(ItemBatchOperation SinglePartitionKeyServerBatchRequest batchRequest = await SinglePartitionKeyServerBatchRequest.CreateAsync( partitionKey: null, operations: new ArraySegment(arrayOperations), - serializer: new CosmosJsonDotNetSerializer(), + serializerCore: MockCosmosUtil.Serializer, cancellationToken: CancellationToken.None); ResponseMessage responseMessage = new ResponseMessage((HttpStatusCode)StatusCodes.TooManyRequests) @@ -408,7 +406,7 @@ private async Task GenerateOkResponseAsync(ItemBatchOperation i SinglePartitionKeyServerBatchRequest batchRequest = await SinglePartitionKeyServerBatchRequest.CreateAsync( partitionKey: null, operations: new ArraySegment(arrayOperations), - serializer: new CosmosJsonDotNetSerializer(), + serializerCore: MockCosmosUtil.Serializer, cancellationToken: CancellationToken.None); ResponseMessage responseMessage = new ResponseMessage(HttpStatusCode.OK) @@ -432,7 +430,7 @@ private async Task GenerateOkResponseAsync(ItemBatchOperation i private static ItemBatchOperation CreateItem(string id) { MyDocument myDocument = new MyDocument() { id = id, Status = id }; - return new ItemBatchOperation(OperationType.Create, 0, new Cosmos.PartitionKey(id), id, cosmosDefaultJsonSerializer.ToStream(myDocument)); + return new ItemBatchOperation(OperationType.Create, 0, new Cosmos.PartitionKey(id), id, MockCosmosUtil.Serializer.ToStream(myDocument)); } private class MyDocument diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncStreamerTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncStreamerTests.cs index 5406bd2699..70684f97c8 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncStreamerTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchAsyncStreamerTests.cs @@ -46,13 +46,13 @@ private BatchAsyncBatcherExecuteDelegate Executor SinglePartitionKeyServerBatchRequest batchRequest = await SinglePartitionKeyServerBatchRequest.CreateAsync( partitionKey: null, operations: new ArraySegment(arrayOperations), - serializer: new CosmosJsonDotNetSerializer(), + serializerCore: MockCosmosUtil.Serializer, cancellationToken: cancellationToken); TransactionalBatchResponse batchresponse = await TransactionalBatchResponse.FromResponseMessageAsync( new ResponseMessage(HttpStatusCode.OK) { Content = responseContent }, batchRequest, - new CosmosJsonDotNetSerializer()); + MockCosmosUtil.Serializer); return new PartitionKeyRangeBatchExecutionResult(request.PartitionKeyRangeId, request.Operations, batchresponse); }; @@ -73,7 +73,7 @@ private BatchAsyncBatcherExecuteDelegate Executor [DataRow(-1)] public void ValidatesSize(int size) { - BatchAsyncStreamer batchAsyncStreamer = new BatchAsyncStreamer(size, MaxBatchByteSize, DispatchTimerInSeconds, this.TimerPool, new CosmosJsonDotNetSerializer(), this.Executor, this.Retrier); + BatchAsyncStreamer batchAsyncStreamer = new BatchAsyncStreamer(size, MaxBatchByteSize, DispatchTimerInSeconds, this.TimerPool, MockCosmosUtil.Serializer, this.Executor, this.Retrier); } [DataTestMethod] @@ -82,21 +82,21 @@ public void ValidatesSize(int size) [DataRow(-1)] public void ValidatesDispatchTimer(int dispatchTimerInSeconds) { - BatchAsyncStreamer batchAsyncStreamer = new BatchAsyncStreamer(1, MaxBatchByteSize, dispatchTimerInSeconds, this.TimerPool, new CosmosJsonDotNetSerializer(), this.Executor, this.Retrier); + BatchAsyncStreamer batchAsyncStreamer = new BatchAsyncStreamer(1, MaxBatchByteSize, dispatchTimerInSeconds, this.TimerPool, MockCosmosUtil.Serializer, this.Executor, this.Retrier); } [TestMethod] [ExpectedException(typeof(ArgumentNullException))] public void ValidatesExecutor() { - BatchAsyncStreamer batchAsyncStreamer = new BatchAsyncStreamer(1, MaxBatchByteSize, DispatchTimerInSeconds, this.TimerPool, new CosmosJsonDotNetSerializer(), null, this.Retrier); + BatchAsyncStreamer batchAsyncStreamer = new BatchAsyncStreamer(1, MaxBatchByteSize, DispatchTimerInSeconds, this.TimerPool, MockCosmosUtil.Serializer, null, this.Retrier); } [TestMethod] [ExpectedException(typeof(ArgumentNullException))] public void ValidatesRetrier() { - BatchAsyncStreamer batchAsyncStreamer = new BatchAsyncStreamer(1, MaxBatchByteSize, DispatchTimerInSeconds, this.TimerPool, new CosmosJsonDotNetSerializer(), this.Executor, null); + BatchAsyncStreamer batchAsyncStreamer = new BatchAsyncStreamer(1, MaxBatchByteSize, DispatchTimerInSeconds, this.TimerPool, MockCosmosUtil.Serializer, this.Executor, null); } [TestMethod] @@ -109,7 +109,7 @@ public void ValidatesSerializer() [TestMethod] public async Task ExceptionsOnBatchBubbleUpAsync() { - BatchAsyncStreamer batchAsyncStreamer = new BatchAsyncStreamer(2, MaxBatchByteSize, DispatchTimerInSeconds, this.TimerPool, new CosmosJsonDotNetSerializer(), this.ExecutorWithFailure, this.Retrier); + BatchAsyncStreamer batchAsyncStreamer = new BatchAsyncStreamer(2, MaxBatchByteSize, DispatchTimerInSeconds, this.TimerPool, MockCosmosUtil.Serializer, this.ExecutorWithFailure, this.Retrier); ItemBatchOperationContext context = AttachContext(this.ItemBatchOperation); batchAsyncStreamer.Add(this.ItemBatchOperation); Exception capturedException = await Assert.ThrowsExceptionAsync(() => context.OperationTask); @@ -120,7 +120,7 @@ public async Task ExceptionsOnBatchBubbleUpAsync() public async Task TimerDispatchesAsync() { // Bigger batch size than the amount of operations, timer should dispatch - BatchAsyncStreamer batchAsyncStreamer = new BatchAsyncStreamer(2, MaxBatchByteSize, DispatchTimerInSeconds, this.TimerPool, new CosmosJsonDotNetSerializer(), this.Executor, this.Retrier); + BatchAsyncStreamer batchAsyncStreamer = new BatchAsyncStreamer(2, MaxBatchByteSize, DispatchTimerInSeconds, this.TimerPool, MockCosmosUtil.Serializer, this.Executor, this.Retrier); ItemBatchOperationContext context = AttachContext(this.ItemBatchOperation); batchAsyncStreamer.Add(this.ItemBatchOperation); TransactionalBatchOperationResult result = await context.OperationTask; @@ -132,7 +132,14 @@ public async Task TimerDispatchesAsync() public async Task DispatchesAsync() { // Expect all operations to complete as their batches get dispached - BatchAsyncStreamer batchAsyncStreamer = new BatchAsyncStreamer(2, MaxBatchByteSize, DispatchTimerInSeconds, this.TimerPool, new CosmosJsonDotNetSerializer(), this.Executor, this.Retrier); + BatchAsyncStreamer batchAsyncStreamer = new BatchAsyncStreamer( + 2, + MaxBatchByteSize, + DispatchTimerInSeconds, + this.TimerPool, + MockCosmosUtil.Serializer, + this.Executor, + this.Retrier); List> contexts = new List>(10); for (int i = 0; i < 10; i++) { diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchSchemaTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchSchemaTests.cs index f371c43b2b..6bffe33447 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchSchemaTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchSchemaTests.cs @@ -45,7 +45,7 @@ public async Task BatchRequestSerializationAsync() ServerBatchRequest batchRequest = await SinglePartitionKeyServerBatchRequest.CreateAsync( new Cosmos.PartitionKey(partitionKey1), new ArraySegment(operations), - serializer: new CosmosJsonDotNetSerializer(), + serializerCore: MockCosmosUtil.Serializer, cancellationToken: CancellationToken.None); Assert.AreEqual(2, batchRequest.Operations.Count); @@ -90,12 +90,12 @@ public async Task BatchResponseDeserializationAsync() new ItemBatchOperation(OperationType.Read, operationIndex: 0, id: "someId"), new ItemBatchOperation(OperationType.Read, operationIndex: 0, id: "someId") }), - serializer: serializer, + serializerCore: MockCosmosUtil.Serializer, cancellationToken: CancellationToken.None); TransactionalBatchResponse batchResponse = await TransactionalBatchResponse.FromResponseMessageAsync( new ResponseMessage((HttpStatusCode)StatusCodes.MultiStatus) { Content = responseContent }, batchRequest, - serializer); + MockCosmosUtil.Serializer); Assert.IsNotNull(batchRequest); Assert.AreEqual(HttpStatusCode.Conflict, batchResponse.StatusCode); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchUnitTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchUnitTests.cs index 92fb330821..1b94fad8e7 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchUnitTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/BatchUnitTests.cs @@ -12,7 +12,6 @@ namespace Microsoft.Azure.Cosmos.Tests using System.Text; using System.Threading; using System.Threading.Tasks; - using Microsoft.Azure.Cosmos.Client.Core.Tests; using Microsoft.Azure.Documents; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/PartitionKeyBatchResponseTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/PartitionKeyBatchResponseTests.cs index 6462cb4748..931bd22fb3 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/PartitionKeyBatchResponseTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/PartitionKeyBatchResponseTests.cs @@ -39,15 +39,15 @@ public async Task StatusCodesAreSetThroughResponseAsync() SinglePartitionKeyServerBatchRequest batchRequest = await SinglePartitionKeyServerBatchRequest.CreateAsync( partitionKey: null, operations: new ArraySegment(arrayOperations), - serializer: new CosmosJsonDotNetSerializer(), + serializerCore: MockCosmosUtil.Serializer, cancellationToken: default(CancellationToken)); TransactionalBatchResponse batchresponse = await TransactionalBatchResponse.FromResponseMessageAsync( new ResponseMessage(HttpStatusCode.OK) { Content = responseContent }, batchRequest, - new CosmosJsonDotNetSerializer()); + MockCosmosUtil.Serializer); - PartitionKeyRangeBatchResponse response = new PartitionKeyRangeBatchResponse(arrayOperations.Length, batchresponse, new CosmosJsonDotNetSerializer()); + PartitionKeyRangeBatchResponse response = new PartitionKeyRangeBatchResponse(arrayOperations.Length, batchresponse, MockCosmosUtil.Serializer); Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); } @@ -73,7 +73,7 @@ public async Task DiagnosticsAreSetThroughResponseAsync() SinglePartitionKeyServerBatchRequest batchRequest = await SinglePartitionKeyServerBatchRequest.CreateAsync( partitionKey: null, operations: new ArraySegment(arrayOperations), - serializer: new CosmosJsonDotNetSerializer(), + serializerCore: MockCosmosUtil.Serializer, cancellationToken: default(CancellationToken)); CosmosDiagnostics diagnostics = new PointOperationStatistics( @@ -91,9 +91,9 @@ public async Task DiagnosticsAreSetThroughResponseAsync() TransactionalBatchResponse batchresponse = await TransactionalBatchResponse.FromResponseMessageAsync( new ResponseMessage(HttpStatusCode.OK) { Content = responseContent, Diagnostics = diagnostics }, batchRequest, - new CosmosJsonDotNetSerializer()); + MockCosmosUtil.Serializer); - PartitionKeyRangeBatchResponse response = new PartitionKeyRangeBatchResponse(arrayOperations.Length, batchresponse, new CosmosJsonDotNetSerializer()); + PartitionKeyRangeBatchResponse response = new PartitionKeyRangeBatchResponse(arrayOperations.Length, batchresponse, MockCosmosUtil.Serializer); Assert.AreEqual(diagnostics, response.Diagnostics); } } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/PartitionKeyRangeBatchExecutionResultTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/PartitionKeyRangeBatchExecutionResultTests.cs index ad07f62c68..48c957421f 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/PartitionKeyRangeBatchExecutionResultTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/PartitionKeyRangeBatchExecutionResultTests.cs @@ -54,15 +54,18 @@ public async Task StatusCodesAreSetThroughResponseAsync() SinglePartitionKeyServerBatchRequest batchRequest = await SinglePartitionKeyServerBatchRequest.CreateAsync( partitionKey: null, operations: new ArraySegment(arrayOperations), - serializer: new CosmosJsonDotNetSerializer(), + serializerCore: MockCosmosUtil.Serializer, cancellationToken: default(CancellationToken)); TransactionalBatchResponse batchresponse = await TransactionalBatchResponse.FromResponseMessageAsync( new ResponseMessage(HttpStatusCode.OK) { Content = responseContent }, batchRequest, - new CosmosJsonDotNetSerializer()); + MockCosmosUtil.Serializer); - PartitionKeyRangeBatchResponse response = new PartitionKeyRangeBatchResponse(arrayOperations.Length, batchresponse, new CosmosJsonDotNetSerializer()); + PartitionKeyRangeBatchResponse response = new PartitionKeyRangeBatchResponse( + arrayOperations.Length, + batchresponse, + MockCosmosUtil.Serializer); Assert.AreEqual(HttpStatusCode.OK, response.StatusCode); } @@ -120,7 +123,7 @@ private async Task ConstainsSplitIsTrueInternal(HttpStatusCode statusCode, SinglePartitionKeyServerBatchRequest batchRequest = await SinglePartitionKeyServerBatchRequest.CreateAsync( partitionKey: null, operations: new ArraySegment(arrayOperations), - serializer: new CosmosJsonDotNetSerializer(), + serializerCore: MockCosmosUtil.Serializer, cancellationToken: default(CancellationToken)); ResponseMessage response = new ResponseMessage(statusCode) { Content = responseContent }; @@ -129,7 +132,7 @@ private async Task ConstainsSplitIsTrueInternal(HttpStatusCode statusCode, TransactionalBatchResponse batchresponse = await TransactionalBatchResponse.FromResponseMessageAsync( response, batchRequest, - new CosmosJsonDotNetSerializer()); + MockCosmosUtil.Serializer); PartitionKeyRangeBatchExecutionResult result = new PartitionKeyRangeBatchExecutionResult("0", arrayOperations, batchresponse); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/PartitionKeyRangeServerBatchRequestTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/PartitionKeyRangeServerBatchRequestTests.cs index cffe8d072e..0f90f294ca 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/PartitionKeyRangeServerBatchRequestTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Batch/PartitionKeyRangeServerBatchRequestTests.cs @@ -30,7 +30,14 @@ public async Task FitsAllOperations() CreateItemBatchOperation() }; - (PartitionKeyRangeServerBatchRequest request , ArraySegment pendingOperations) = await PartitionKeyRangeServerBatchRequest.CreateAsync("0", new ArraySegment(operations.ToArray()), 200000, 2, false, new CosmosJsonDotNetSerializer(), default(CancellationToken)); + (PartitionKeyRangeServerBatchRequest request , ArraySegment pendingOperations) = await PartitionKeyRangeServerBatchRequest.CreateAsync( + "0", + new ArraySegment(operations.ToArray()), + 200000, + 2, + false, + MockCosmosUtil.Serializer, + default(CancellationToken)); Assert.AreEqual(operations.Count, request.Operations.Count); CollectionAssert.AreEqual(operations, request.Operations.ToArray()); @@ -51,7 +58,14 @@ public async Task OverflowsBasedOnCount() }; // Setting max count to 1 - (PartitionKeyRangeServerBatchRequest request, ArraySegment pendingOperations) = await PartitionKeyRangeServerBatchRequest.CreateAsync("0", new ArraySegment(operations.ToArray()), 200000, 1, false, new CosmosJsonDotNetSerializer(), default(CancellationToken)); + (PartitionKeyRangeServerBatchRequest request, ArraySegment pendingOperations) = await PartitionKeyRangeServerBatchRequest.CreateAsync( + "0", + new ArraySegment(operations.ToArray()), + 200000, + 1, + false, + MockCosmosUtil.Serializer, + default(CancellationToken)); Assert.AreEqual(1, request.Operations.Count); Assert.AreEqual(operations[0].Id, request.Operations[0].Id); @@ -75,7 +89,14 @@ public async Task OverflowsBasedOnCount_WithOffset() }; // Setting max count to 1 - (PartitionKeyRangeServerBatchRequest request, ArraySegment pendingOperations) = await PartitionKeyRangeServerBatchRequest.CreateAsync("0", new ArraySegment(operations.ToArray(), 1, 2), 200000, 1, false, new CosmosJsonDotNetSerializer(), default(CancellationToken)); + (PartitionKeyRangeServerBatchRequest request, ArraySegment pendingOperations) = await PartitionKeyRangeServerBatchRequest.CreateAsync( + "0", + new ArraySegment(operations.ToArray(), 1, 2), + 200000, + 1, + false, + MockCosmosUtil.Serializer, + default(CancellationToken)); Assert.AreEqual(1, request.Operations.Count); // The first element is not taken into account due to an Offset of 1 @@ -148,7 +169,7 @@ private static async Task mockContext = new Mock(); mockContext.Setup(x => x.ClientOptions).Returns(MockCosmosUtil.GetDefaultConfiguration()); mockContext.Setup(x => x.DocumentClient).Returns(new MockDocumentClient()); - mockContext.Setup(x => x.CosmosSerializer).Returns(new CosmosJsonDotNetSerializer()); + mockContext.Setup(x => x.SerializerCore).Returns(MockCosmosUtil.Serializer); mockContext.Setup(x => x.Client).Returns(mockClient.Object); return mockContext.Object; } diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeed/DocumentServiceLeaseContainerCosmosTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeed/DocumentServiceLeaseContainerCosmosTests.cs index 1d007929aa..a4cd761958 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeed/DocumentServiceLeaseContainerCosmosTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeed/DocumentServiceLeaseContainerCosmosTests.cs @@ -10,7 +10,7 @@ namespace Microsoft.Azure.Cosmos.ChangeFeed.Tests using System.Threading; using System.Threading.Tasks; using Microsoft.Azure.Cosmos.ChangeFeed.LeaseManagement; - using Microsoft.Azure.Cosmos.Client.Core.Tests; + using Microsoft.Azure.Cosmos.Tests; using Microsoft.Azure.Cosmos.Fluent; using Microsoft.Azure.Documents; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeed/DocumentServiceLeaseUpdaterCosmosTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeed/DocumentServiceLeaseUpdaterCosmosTests.cs index 128035e8aa..07fba06bd1 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeed/DocumentServiceLeaseUpdaterCosmosTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeed/DocumentServiceLeaseUpdaterCosmosTests.cs @@ -11,7 +11,7 @@ namespace Microsoft.Azure.Cosmos.ChangeFeed.Tests using System.Threading.Tasks; using Microsoft.Azure.Cosmos.ChangeFeed.Exceptions; using Microsoft.Azure.Cosmos.ChangeFeed.LeaseManagement; - using Microsoft.Azure.Cosmos.Client.Core.Tests; + using Microsoft.Azure.Cosmos.Tests; using Microsoft.Azure.Cosmos.Fluent; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeed/FeedProcessorCoreTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeed/FeedProcessorCoreTests.cs index d7e7439543..36c0a1d2c4 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeed/FeedProcessorCoreTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeed/FeedProcessorCoreTests.cs @@ -14,6 +14,7 @@ namespace Microsoft.Azure.Cosmos.ChangeFeed.Tests using Microsoft.Azure.Cosmos.ChangeFeed.FeedManagement; using Microsoft.Azure.Cosmos.ChangeFeed.FeedProcessing; using Microsoft.Azure.Cosmos.Query.Core; + using Microsoft.Azure.Cosmos.Tests; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; @@ -41,7 +42,12 @@ public async Task UsesCustomSerializer() mockIterator.SetupSequence(i => i.HasMoreResults).Returns(true).Returns(false); CustomSerializer serializer = new CustomSerializer(); - FeedProcessorCore processor = new FeedProcessorCore(mockObserver.Object, mockIterator.Object, FeedProcessorCoreTests.DefaultSettings, mockCheckpointer.Object, serializer); + FeedProcessorCore processor = new FeedProcessorCore( + mockObserver.Object, + mockIterator.Object, + FeedProcessorCoreTests.DefaultSettings, + mockCheckpointer.Object, + new CosmosSerializerCore(serializer)); try { @@ -74,7 +80,12 @@ public async Task ThrowsOnFailedCustomSerializer() mockIterator.SetupSequence(i => i.HasMoreResults).Returns(true).Returns(false); CustomSerializerFails serializer = new CustomSerializerFails(); - FeedProcessorCore processor = new FeedProcessorCore(mockObserver.Object, mockIterator.Object, FeedProcessorCoreTests.DefaultSettings, mockCheckpointer.Object, serializer); + FeedProcessorCore processor = new FeedProcessorCore( + mockObserver.Object, + mockIterator.Object, + FeedProcessorCoreTests.DefaultSettings, + mockCheckpointer.Object, + new CosmosSerializerCore(serializer)); ObserverException caughtException = await Assert.ThrowsExceptionAsync(() => processor.RunAsync(cancellationTokenSource.Token)); Assert.IsInstanceOfType(caughtException.InnerException, typeof(CustomException)); @@ -94,7 +105,12 @@ public async Task ThrowOnPartitionSplit(HttpStatusCode statusCode, int subStatus mockIterator.Setup(i => i.ReadNextAsync(It.IsAny())) .ReturnsAsync(GetResponse(statusCode, false, subStatusCode)); - FeedProcessorCore processor = new FeedProcessorCore(mockObserver.Object, mockIterator.Object, FeedProcessorCoreTests.DefaultSettings, mockCheckpointer.Object, new CosmosJsonDotNetSerializer()); + FeedProcessorCore processor = new FeedProcessorCore( + mockObserver.Object, + mockIterator.Object, + FeedProcessorCoreTests.DefaultSettings, + mockCheckpointer.Object, + MockCosmosUtil.Serializer); await Assert.ThrowsExceptionAsync(() => processor.RunAsync(cancellationTokenSource.Token)); } @@ -112,13 +128,8 @@ private static ResponseMessage GetResponse(HttpStatusCode statusCode, bool inclu { MyDocument document = new MyDocument(); document.id = "test"; - CosmosFeedResponseUtil cosmosFeedResponse = new CosmosFeedResponseUtil(); - cosmosFeedResponse.Data = new System.Collections.ObjectModel.Collection() - { - document - }; - message.Content = new CosmosJsonDotNetSerializer().ToStream(cosmosFeedResponse); + message.Content = new CosmosJsonDotNetSerializer().ToStream(new { Documents = new List() { document } }); } return message; diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeed/RemainingWorkEstimatorTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeed/RemainingWorkEstimatorTests.cs index c75b65e4c3..3450f37b20 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeed/RemainingWorkEstimatorTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeed/RemainingWorkEstimatorTests.cs @@ -212,13 +212,8 @@ private static ResponseMessage GetResponse(HttpStatusCode statusCode, string loc { JObject firstDocument = new JObject(); firstDocument["_lsn"] = itemLsn; - CosmosFeedResponseUtil cosmosFeedResponse = new CosmosFeedResponseUtil(); - cosmosFeedResponse.Data = new System.Collections.ObjectModel.Collection() - { - firstDocument - }; - message.Content = new CosmosJsonDotNetSerializer().ToStream(cosmosFeedResponse); + message.Content = new CosmosJsonDotNetSerializer().ToStream( new { Documents = new List() { firstDocument } }); } return message; diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeedResultSetIteratorTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeedResultSetIteratorTests.cs index cc42ff8363..d16bce104a 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeedResultSetIteratorTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ChangeFeedResultSetIteratorTests.cs @@ -11,7 +11,6 @@ namespace Microsoft.Azure.Cosmos.Tests using System.Net; using System.Threading; using System.Threading.Tasks; - using Microsoft.Azure.Cosmos.Client.Core.Tests; using Microsoft.Azure.Cosmos.Query; using Microsoft.Azure.Cosmos.Query.Core.ContinuationTokens; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -29,7 +28,7 @@ public async Task ContinuationTokenIsNotUpdatedOnFails() Mock mockContext = new Mock(); mockContext.Setup(x => x.ClientOptions).Returns(MockCosmosUtil.GetDefaultConfiguration()); mockContext.Setup(x => x.DocumentClient).Returns(documentClient); - mockContext.Setup(x => x.CosmosSerializer).Returns(MockCosmosUtil.Serializer); + mockContext.Setup(x => x.SerializerCore).Returns(MockCosmosUtil.Serializer); mockContext.Setup(x => x.Client).Returns(client); mockContext.Setup(x => x.CreateLink(It.IsAny(), It.IsAny(), It.IsAny())).Returns(new Uri("/dbs/test/colls/test", UriKind.Relative)); @@ -84,7 +83,7 @@ public async Task ShouldContinueUntilResponseOk() Mock mockContext = new Mock(); mockContext.Setup(x => x.ClientOptions).Returns(MockCosmosUtil.GetDefaultConfiguration()); mockContext.Setup(x => x.DocumentClient).Returns(documentClient); - mockContext.Setup(x => x.CosmosSerializer).Returns(MockCosmosUtil.Serializer); + mockContext.Setup(x => x.SerializerCore).Returns(MockCosmosUtil.Serializer); mockContext.Setup(x => x.Client).Returns(client); mockContext.Setup(x => x.CreateLink(It.IsAny(), It.IsAny(), It.IsAny())).Returns(new Uri("/dbs/test/colls/test", UriKind.Relative)); @@ -138,7 +137,7 @@ public async Task ShouldReturnNotModifiedAfterCyclingOnAllRanges() Mock mockContext = new Mock(); mockContext.Setup(x => x.ClientOptions).Returns(MockCosmosUtil.GetDefaultConfiguration()); mockContext.Setup(x => x.DocumentClient).Returns(documentClient); - mockContext.Setup(x => x.CosmosSerializer).Returns(MockCosmosUtil.Serializer); + mockContext.Setup(x => x.SerializerCore).Returns(MockCosmosUtil.Serializer); mockContext.Setup(x => x.Client).Returns(client); mockContext.Setup(x => x.CreateLink(It.IsAny(), It.IsAny(), It.IsAny())).Returns(new Uri("/dbs/test/colls/test", UriKind.Relative)); @@ -196,7 +195,7 @@ public async Task ShouldReturnNotModifiedOnSingleRange() Mock mockContext = new Mock(); mockContext.Setup(x => x.ClientOptions).Returns(MockCosmosUtil.GetDefaultConfiguration()); mockContext.Setup(x => x.DocumentClient).Returns(new MockDocumentClient()); - mockContext.Setup(x => x.CosmosSerializer).Returns(MockCosmosUtil.Serializer); + mockContext.Setup(x => x.SerializerCore).Returns(MockCosmosUtil.Serializer); mockContext.Setup(x => x.Client).Returns(client); mockContext.Setup(x => x.CreateLink(It.IsAny(), It.IsAny(), It.IsAny())).Returns(new Uri("/dbs/test/colls/test", UriKind.Relative)); @@ -246,7 +245,7 @@ public async Task GetChangeFeedTokensAsyncReturnsOnePerPartitionKeyRange() Mock mockContext = new Mock(); mockContext.Setup(x => x.ClientOptions).Returns(MockCosmosUtil.GetDefaultConfiguration()); mockContext.Setup(x => x.DocumentClient).Returns(documentClient); - mockContext.Setup(x => x.CosmosSerializer).Returns(MockCosmosUtil.Serializer); + mockContext.Setup(x => x.SerializerCore).Returns(MockCosmosUtil.Serializer); mockContext.Setup(x => x.Client).Returns(client); mockContext.Setup(x => x.CreateLink(It.IsAny(), It.IsAny(), It.IsAny())).Returns(UriFactory.CreateDocumentCollectionUri("test", "test")); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs index 1a99366d34..f5b2d1063b 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientOptionsUnitTests.cs @@ -9,7 +9,6 @@ namespace Microsoft.Azure.Cosmos.Tests using System.Linq; using System.Net; using System.Net.Http; - using Microsoft.Azure.Cosmos.Client.Core.Tests; using Microsoft.Azure.Cosmos.Fluent; using Microsoft.Azure.Documents; using Microsoft.Azure.Documents.Client; @@ -210,62 +209,6 @@ public void UserAgentContainsEnvironmentInformation() Assert.IsTrue(connectionPolicy.UserAgentContainer.UserAgent.EndsWith(userAgentSuffix)); } - [TestMethod] - public void GetCosmosSerializerWithWrapperOrDefaultTest() - { - CosmosJsonDotNetSerializer serializer = new CosmosJsonDotNetSerializer(); - CosmosClientOptions options = new CosmosClientOptions() - { - Serializer = serializer - }; - - CosmosSerializer cosmosSerializer = options.GetCosmosSerializerWithWrapperOrDefault(); - Assert.AreNotEqual(cosmosSerializer, options.PropertiesSerializer, "Serializer should be custom not the default"); - Assert.AreNotEqual(cosmosSerializer, serializer, "Serializer should be in the CosmosJsonSerializerWrapper"); - - CosmosJsonSerializerWrapper cosmosJsonSerializerWrapper = cosmosSerializer as CosmosJsonSerializerWrapper; - Assert.IsNotNull(cosmosJsonSerializerWrapper); - Assert.AreEqual(cosmosJsonSerializerWrapper.InternalJsonSerializer, serializer); - } - - [TestMethod] - public void GetCosmosSerializerWithWrapperOrDefaultWithOptionsTest() - { - CosmosSerializationOptions serializerOptions = new CosmosSerializationOptions(); - Assert.IsFalse(serializerOptions.IgnoreNullValues); - Assert.IsFalse(serializerOptions.Indented); - Assert.AreEqual(CosmosPropertyNamingPolicy.Default, serializerOptions.PropertyNamingPolicy); - - CosmosClientOptions options = new CosmosClientOptions() - { - SerializerOptions = new CosmosSerializationOptions() - { - IgnoreNullValues = true, - Indented = true, - PropertyNamingPolicy = CosmosPropertyNamingPolicy.CamelCase - } - }; - - CosmosSerializer cosmosSerializer = options.GetCosmosSerializerWithWrapperOrDefault(); - Assert.AreNotEqual(cosmosSerializer, options.PropertiesSerializer, "Serializer should be custom not the default"); - - CosmosJsonSerializerWrapper cosmosJsonSerializerWrapper = cosmosSerializer as CosmosJsonSerializerWrapper; - Assert.IsNotNull(cosmosJsonSerializerWrapper); - - // Verify the custom settings are being honored - dynamic testItem = new { id = "testid", description = (string)null, CamelCaseProperty = "TestCamelCase" }; - using (Stream stream = cosmosSerializer.ToStream(testItem)) - { - using (StreamReader sr = new StreamReader(stream)) - { - string jsonString = sr.ReadToEnd(); - // Notice description is not included, camelCaseProperty starts lower case, the white space shows the indents - string expectedJsonString = $"{{{Environment.NewLine} \"id\": \"testid\",{Environment.NewLine} \"camelCaseProperty\": \"TestCamelCase\"{Environment.NewLine}}}"; - Assert.AreEqual(expectedJsonString, jsonString); - } - } - } - [TestMethod] [ExpectedException(typeof(ArgumentException))] public void ThrowOnSerializerOptionsWithCustomSerializer() @@ -313,25 +256,6 @@ public void ThrowOnMissingAccountEndpointInConnectionString() new CosmosClientBuilder(invalidConnectionString); } - [TestMethod] - public void AssertJsonSerializer() - { - string connectionString = "AccountEndpoint=https://localtestcosmos.documents.azure.com:443/;AccountKey=425Mcv8CXQqzRNCgFNjIhT424GK99CKJvASowTnq15Vt8LeahXTcN5wt3342vQ==;"; - CosmosClientBuilder cosmosClientBuilder = new CosmosClientBuilder(connectionString); - CosmosClient cosmosClient = cosmosClientBuilder.Build(new MockDocumentClient()); - Assert.IsInstanceOfType(cosmosClient.ClientOptions.GetCosmosSerializerWithWrapperOrDefault(), typeof(CosmosJsonSerializerWrapper)); - Assert.AreEqual(cosmosClient.ClientOptions.GetCosmosSerializerWithWrapperOrDefault(), cosmosClient.ClientOptions.PropertiesSerializer); - - CosmosSerializer defaultSerializer = cosmosClient.ClientOptions.PropertiesSerializer; - CosmosSerializer mockJsonSerializer = new Mock().Object; - cosmosClientBuilder.WithCustomSerializer(mockJsonSerializer); - CosmosClient cosmosClientCustom = cosmosClientBuilder.Build(new MockDocumentClient()); - Assert.AreEqual(defaultSerializer, cosmosClientCustom.ClientOptions.PropertiesSerializer); - Assert.AreEqual(mockJsonSerializer, cosmosClientCustom.ClientOptions.Serializer); - Assert.IsInstanceOfType(cosmosClientCustom.ClientOptions.GetCosmosSerializerWithWrapperOrDefault(), typeof(CosmosJsonSerializerWrapper)); - Assert.AreEqual(mockJsonSerializer, ((CosmosJsonSerializerWrapper)cosmosClientCustom.ClientOptions.GetCosmosSerializerWithWrapperOrDefault()).InternalJsonSerializer); - } - [TestMethod] public void VerifyGetConnectionPolicyThrowIfDirectTcpSettingAreUsedInGatewayMode() { diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientResourceUnitTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientResourceUnitTests.cs index 2c78de337e..1297cded35 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientResourceUnitTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosClientResourceUnitTests.cs @@ -26,9 +26,7 @@ public void ValidateUriGenerationForResources() CosmosClientContext context = new ClientContextCore( client: mockClient.Object, clientOptions: new CosmosClientOptions(), - userJsonSerializer: null, - defaultJsonSerializer: null, - sqlQuerySpecSerializer: null, + serializerCore: null, cosmosResponseFactory: null, requestHandler: null, documentClient: null); @@ -130,9 +128,7 @@ public void InitializeBatchExecutorForContainer_Null_WhenAllowBulk_False() CosmosClientContext context = new ClientContextCore( client: mockClient.Object, clientOptions: new CosmosClientOptions(), - userJsonSerializer: null, - defaultJsonSerializer: null, - sqlQuerySpecSerializer: null, + serializerCore: null, cosmosResponseFactory: null, requestHandler: null, documentClient: null); @@ -154,9 +150,7 @@ public void InitializeBatchExecutorForContainer_NotNull_WhenAllowBulk_True() CosmosClientContext context = new ClientContextCore( client: mockClient.Object, clientOptions: new CosmosClientOptions() { AllowBulkExecution = true }, - userJsonSerializer: null, - defaultJsonSerializer: null, - sqlQuerySpecSerializer: null, + serializerCore: null, cosmosResponseFactory: null, requestHandler: null, documentClient: null); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosConflictTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosConflictTests.cs index 0e3071055f..f81e4d7f5d 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosConflictTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosConflictTests.cs @@ -7,7 +7,6 @@ namespace Microsoft.Azure.Cosmos.Tests using System; using System.Threading; using System.Threading.Tasks; - using Microsoft.Azure.Cosmos.Client.Core.Tests; using Microsoft.Azure.Documents; using Microsoft.Azure.Cosmos.Handlers; using Microsoft.Azure.Cosmos.Routing; @@ -118,14 +117,12 @@ private static CosmosClientContext GetMockedClientContext( handler = handler.InnerHandler; } - CosmosResponseFactory responseFactory = new CosmosResponseFactory(MockCosmosUtil.Serializer, MockCosmosUtil.Serializer); + CosmosResponseFactory responseFactory = new CosmosResponseFactory(MockCosmosUtil.Serializer); return new ClientContextCore( client: client, clientOptions: new CosmosClientOptions(), - userJsonSerializer: MockCosmosUtil.Serializer, - defaultJsonSerializer: MockCosmosUtil.Serializer, - sqlQuerySpecSerializer: MockCosmosUtil.Serializer, + serializerCore: MockCosmosUtil.Serializer, cosmosResponseFactory: responseFactory, requestHandler: client.RequestHandler, documentClient: new MockDocumentClient()); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosContainerSettingsTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosContainerSettingsTests.cs index f6ce1fb478..2a93213e0f 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosContainerSettingsTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosContainerSettingsTests.cs @@ -2,12 +2,11 @@ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ -namespace Microsoft.Azure.Cosmos +namespace Microsoft.Azure.Cosmos.Tests { using System.Collections.ObjectModel; using System.IO; using System.Linq; - using Microsoft.Azure.Cosmos.Client.Core.Tests; using Microsoft.Azure.Documents; using Microsoft.VisualStudio.TestTools.UnitTesting; using Newtonsoft.Json; @@ -22,15 +21,15 @@ public void DefaultIncludesPopulated() ContainerProperties containerSettings = new ContainerProperties("TestContainer", "/partitionKey"); Assert.IsNotNull(containerSettings.IndexingPolicy); - containerSettings.IndexingPolicy = new IndexingPolicy(); + containerSettings.IndexingPolicy = new Cosmos.IndexingPolicy(); Assert.AreEqual(0, containerSettings.IndexingPolicy.IncludedPaths.Count); - // HAKC: Work-around till BE fixes defautls + // HAKC: Work-around till BE fixes defaults containerSettings.ValidateRequiredProperties(); Assert.AreEqual(1, containerSettings.IndexingPolicy.IncludedPaths.Count); - IncludedPath defaultEntry = containerSettings.IndexingPolicy.IncludedPaths[0]; - Assert.AreEqual(IndexingPolicy.DefaultPath, defaultEntry.Path); + Cosmos.IncludedPath defaultEntry = containerSettings.IndexingPolicy.IncludedPaths[0]; + Assert.AreEqual(Cosmos.IndexingPolicy.DefaultPath, defaultEntry.Path); Assert.AreEqual(0, defaultEntry.Indexes.Count); } @@ -51,17 +50,17 @@ public void DefaultIncludesShouldNotBePopulated() Assert.IsNotNull(containerSettings.IndexingPolicy); // Any exclude path should not auto-generate default indexing - containerSettings.IndexingPolicy = new IndexingPolicy(); - containerSettings.IndexingPolicy.ExcludedPaths.Add(new ExcludedPath() { Path = "/some" }); + containerSettings.IndexingPolicy = new Cosmos.IndexingPolicy(); + containerSettings.IndexingPolicy.ExcludedPaths.Add(new Cosmos.ExcludedPath() { Path = "/some" }); Assert.AreEqual(0, containerSettings.IndexingPolicy.IncludedPaths.Count); containerSettings.ValidateRequiredProperties(); Assert.AreEqual(0, containerSettings.IndexingPolicy.IncludedPaths.Count); // None indexing mode should not auto-generate the default indexing - containerSettings.IndexingPolicy = new IndexingPolicy + containerSettings.IndexingPolicy = new Cosmos.IndexingPolicy { - IndexingMode = IndexingMode.None + IndexingMode = Cosmos.IndexingMode.None }; Assert.AreEqual(0, containerSettings.IndexingPolicy.IncludedPaths.Count); @@ -93,7 +92,7 @@ public void DefaultIndexingPolicySameAsDocumentCollection() { ContainerProperties containerSettings = new ContainerProperties("TestContainer", "/partitionKey") { - IndexingPolicy = new IndexingPolicy() + IndexingPolicy = new Cosmos.IndexingPolicy() }; DocumentCollection dc = new DocumentCollection() @@ -133,7 +132,7 @@ private static void AssertSerializedPayloads(ContainerProperties settings, Docum NullValueHandling = NullValueHandling.Ignore }; - // HAKC: Work-around till BE fixes defautls + // HAKC: Work-around till BE fixes defaults settings.ValidateRequiredProperties(); string containerSerialized = JsonConvert.SerializeObject(settings, jsonSettings); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosItemUnitTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosItemUnitTests.cs index 84807d770c..d45a1205c0 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosItemUnitTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosItemUnitTests.cs @@ -10,7 +10,6 @@ namespace Microsoft.Azure.Cosmos.Tests using System.Net; using System.Threading; using System.Threading.Tasks; - using Microsoft.Azure.Cosmos.Client.Core.Tests; using Microsoft.Azure.Cosmos.Query; using Microsoft.Azure.Documents; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -168,16 +167,7 @@ await Assert.ThrowsExceptionAsync(async () => { [TestMethod] public async Task AllowBatchingRequestsSendsToExecutor_CreateStream() { - ClientContextCore clientContextCore = new ClientContextCore( - MockCosmosUtil.CreateMockCosmosClient(), - new CosmosClientOptions() { AllowBulkExecution = true }, - new CosmosJsonDotNetSerializer(), - new CosmosJsonDotNetSerializer(), - new CosmosJsonDotNetSerializer(), - null, - null, - new MockDocumentClient() - ); + ClientContextCore clientContextCore = this.CreateMockBulkClientContextCore(); DatabaseCore db = new DatabaseCore(clientContextCore, "test"); ExecutorContainerCore container = new ExecutorContainerCore(clientContextCore, db, "test"); @@ -204,16 +194,7 @@ public async Task AllowBatchingRequestsSendsToExecutor_CreateStream() [TestMethod] public async Task AllowBatchingRequestsSendsToExecutor_UpsertStream() { - ClientContextCore clientContextCore = new ClientContextCore( - MockCosmosUtil.CreateMockCosmosClient(), - new CosmosClientOptions() { AllowBulkExecution = true }, - new CosmosJsonDotNetSerializer(), - new CosmosJsonDotNetSerializer(), - new CosmosJsonDotNetSerializer(), - null, - null, - new MockDocumentClient() - ); + ClientContextCore clientContextCore = this.CreateMockBulkClientContextCore(); DatabaseCore db = new DatabaseCore(clientContextCore, "test"); ExecutorContainerCore container = new ExecutorContainerCore(clientContextCore, db, "test"); @@ -240,16 +221,7 @@ public async Task AllowBatchingRequestsSendsToExecutor_UpsertStream() [TestMethod] public async Task AllowBatchingRequestsSendsToExecutor_ReplaceStream() { - ClientContextCore clientContextCore = new ClientContextCore( - MockCosmosUtil.CreateMockCosmosClient(), - new CosmosClientOptions() { AllowBulkExecution = true }, - new CosmosJsonDotNetSerializer(), - new CosmosJsonDotNetSerializer(), - new CosmosJsonDotNetSerializer(), - null, - null, - new MockDocumentClient() - ); + ClientContextCore clientContextCore = this.CreateMockBulkClientContextCore(); DatabaseCore db = new DatabaseCore(clientContextCore, "test"); ExecutorContainerCore container = new ExecutorContainerCore(clientContextCore, db, "test"); @@ -277,16 +249,7 @@ public async Task AllowBatchingRequestsSendsToExecutor_ReplaceStream() [TestMethod] public async Task AllowBatchingRequestsSendsToExecutor_ReadStream() { - ClientContextCore clientContextCore = new ClientContextCore( - MockCosmosUtil.CreateMockCosmosClient(), - new CosmosClientOptions() { AllowBulkExecution = true }, - new CosmosJsonDotNetSerializer(), - new CosmosJsonDotNetSerializer(), - new CosmosJsonDotNetSerializer(), - null, - null, - new MockDocumentClient() - ); + ClientContextCore clientContextCore = this.CreateMockBulkClientContextCore(); DatabaseCore db = new DatabaseCore(clientContextCore, "test"); ExecutorContainerCore container = new ExecutorContainerCore(clientContextCore, db, "test"); @@ -313,16 +276,7 @@ public async Task AllowBatchingRequestsSendsToExecutor_ReadStream() [TestMethod] public async Task AllowBatchingRequestsSendsToExecutor_DeleteStream() { - ClientContextCore clientContextCore = new ClientContextCore( - MockCosmosUtil.CreateMockCosmosClient(), - new CosmosClientOptions() { AllowBulkExecution = true }, - new CosmosJsonDotNetSerializer(), - new CosmosJsonDotNetSerializer(), - new CosmosJsonDotNetSerializer(), - null, - null, - new MockDocumentClient() - ); + ClientContextCore clientContextCore = this.CreateMockBulkClientContextCore(); DatabaseCore db = new DatabaseCore(clientContextCore, "test"); ExecutorContainerCore container = new ExecutorContainerCore(clientContextCore, db, "test"); @@ -346,17 +300,7 @@ public async Task AllowBatchingRequestsSendsToExecutor_DeleteStream() [TestMethod] public async Task AllowBatchingRequestsSendsToExecutor_Create() { - CosmosClient cosmosClient = MockCosmosUtil.CreateMockCosmosClient(); - ClientContextCore clientContextCore = new ClientContextCore( - cosmosClient, - new CosmosClientOptions() { AllowBulkExecution = true }, - new CosmosJsonDotNetSerializer(), - new CosmosJsonDotNetSerializer(), - null, - cosmosClient.ResponseFactory, - null, - new MockDocumentClient() - ); + ClientContextCore clientContextCore = this.CreateMockBulkClientContextCore(); DatabaseCore db = new DatabaseCore(clientContextCore, "test"); ExecutorContainerCore container = new ExecutorContainerCore(clientContextCore, db, "test"); @@ -377,17 +321,7 @@ public async Task AllowBatchingRequestsSendsToExecutor_Create() [TestMethod] public async Task AllowBatchingRequestsSendsToExecutor_Upsert() { - CosmosClient cosmosClient = MockCosmosUtil.CreateMockCosmosClient(); - ClientContextCore clientContextCore = new ClientContextCore( - cosmosClient, - new CosmosClientOptions() { AllowBulkExecution = true }, - new CosmosJsonDotNetSerializer(), - new CosmosJsonDotNetSerializer(), - null, - cosmosClient.ResponseFactory, - null, - new MockDocumentClient() - ); + ClientContextCore clientContextCore = this.CreateMockBulkClientContextCore(); DatabaseCore db = new DatabaseCore(clientContextCore, "test"); ExecutorContainerCore container = new ExecutorContainerCore(clientContextCore, db, "test"); @@ -408,17 +342,7 @@ public async Task AllowBatchingRequestsSendsToExecutor_Upsert() [TestMethod] public async Task AllowBatchingRequestsSendsToExecutor_Replace() { - CosmosClient cosmosClient = MockCosmosUtil.CreateMockCosmosClient(); - ClientContextCore clientContextCore = new ClientContextCore( - cosmosClient, - new CosmosClientOptions() { AllowBulkExecution = true }, - new CosmosJsonDotNetSerializer(), - new CosmosJsonDotNetSerializer(), - null, - cosmosClient.ResponseFactory, - null, - new MockDocumentClient() - ); + ClientContextCore clientContextCore = this.CreateMockBulkClientContextCore(); DatabaseCore db = new DatabaseCore(clientContextCore, "test"); ExecutorContainerCore container = new ExecutorContainerCore(clientContextCore, db, "test"); @@ -439,17 +363,7 @@ public async Task AllowBatchingRequestsSendsToExecutor_Replace() [TestMethod] public async Task AllowBatchingRequestsSendsToExecutor_Read() { - CosmosClient cosmosClient = MockCosmosUtil.CreateMockCosmosClient(); - ClientContextCore clientContextCore = new ClientContextCore( - cosmosClient, - new CosmosClientOptions() { AllowBulkExecution = true }, - new CosmosJsonDotNetSerializer(), - new CosmosJsonDotNetSerializer(), - null, - cosmosClient.ResponseFactory, - null, - new MockDocumentClient() - ); + ClientContextCore clientContextCore = this.CreateMockBulkClientContextCore(); DatabaseCore db = new DatabaseCore(clientContextCore, "test"); ExecutorContainerCore container = new ExecutorContainerCore(clientContextCore, db, "test"); @@ -470,17 +384,7 @@ public async Task AllowBatchingRequestsSendsToExecutor_Read() [TestMethod] public async Task AllowBatchingRequestsSendsToExecutor_Delete() { - CosmosClient cosmosClient = MockCosmosUtil.CreateMockCosmosClient(); - ClientContextCore clientContextCore = new ClientContextCore( - cosmosClient, - new CosmosClientOptions() { AllowBulkExecution = true }, - new CosmosJsonDotNetSerializer(), - new CosmosJsonDotNetSerializer(), - null, - cosmosClient.ResponseFactory, - null, - new MockDocumentClient() - ); + ClientContextCore clientContextCore = this.CreateMockBulkClientContextCore(); DatabaseCore db = new DatabaseCore(clientContextCore, "test"); ExecutorContainerCore container = new ExecutorContainerCore(clientContextCore, db, "test"); @@ -572,6 +476,21 @@ public async Task TestNestedPartitionKeyValueFromStreamAsync() } } + private ClientContextCore CreateMockBulkClientContextCore() + { + CosmosClient cosmosClient = MockCosmosUtil.CreateMockCosmosClient(); + ClientContextCore clientContextCore = new ClientContextCore( + cosmosClient, + new CosmosClientOptions() { AllowBulkExecution = true }, + MockCosmosUtil.Serializer, + cosmosClient.ResponseFactory, + null, + new MockDocumentClient() + ); + + return clientContextCore; + } + private async Task VerifyItemNullPartitionKeyExpectations( dynamic testItem, ItemRequestOptions requestOptions = null) @@ -671,7 +590,6 @@ private async Task VerifyItemOperations( Assert.AreEqual(5, testHandlerHitCount, "An operation did not make it to the handler"); - CosmosSerializer jsonSerializer = MockCosmosUtil.Serializer; using (Stream itemStream = MockCosmosUtil.Serializer.ToStream(testItem)) { using (ResponseMessage streamResponse = await container.CreateItemStreamAsync( @@ -684,7 +602,7 @@ private async Task VerifyItemOperations( } } - using (Stream itemStream = jsonSerializer.ToStream(testItem)) + using (Stream itemStream = MockCosmosUtil.Serializer.ToStream(testItem)) { using (ResponseMessage streamResponse = await container.ReadItemStreamAsync( partitionKey: partitionKey, @@ -696,7 +614,7 @@ private async Task VerifyItemOperations( } } - using (Stream itemStream = jsonSerializer.ToStream(testItem)) + using (Stream itemStream = MockCosmosUtil.Serializer.ToStream(testItem)) { using (ResponseMessage streamResponse = await container.UpsertItemStreamAsync( partitionKey: partitionKey, @@ -708,7 +626,7 @@ private async Task VerifyItemOperations( } } - using (Stream itemStream = jsonSerializer.ToStream(testItem)) + using (Stream itemStream = MockCosmosUtil.Serializer.ToStream(testItem)) { using (ResponseMessage streamResponse = await container.ReplaceItemStreamAsync( partitionKey: partitionKey, @@ -721,7 +639,7 @@ private async Task VerifyItemOperations( } } - using (Stream itemStream = jsonSerializer.ToStream(testItem)) + using (Stream itemStream = MockCosmosUtil.Serializer.ToStream(testItem)) { using (ResponseMessage streamResponse = await container.DeleteItemStreamAsync( partitionKey: partitionKey, diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosJsonSeriliazerUnitTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosJsonSeriliazerUnitTests.cs index d7d5ac4e2b..c564ec852d 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosJsonSeriliazerUnitTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosJsonSeriliazerUnitTests.cs @@ -108,23 +108,19 @@ public async Task ValidateResponseFactoryJsonSerializer() ResponseMessage triggerResponse = this.CreateResponse(); ResponseMessage udfResponse = this.CreateResponse(); ResponseMessage itemResponse = this.CreateResponse(); - ResponseMessage feedResponse = this.CreateResponse(); Mock mockUserJsonSerializer = new Mock(); - Mock mockDefaultJsonSerializer = new Mock(); + CosmosSerializerCore serializerCore = new CosmosSerializerCore(mockUserJsonSerializer.Object); CosmosResponseFactory cosmosResponseFactory = new CosmosResponseFactory( - defaultJsonSerializer: mockDefaultJsonSerializer.Object, - userJsonSerializer: mockUserJsonSerializer.Object); + serializerCore); // Test the user specified response - mockUserJsonSerializer.Setup(x => x.FromStream(itemResponse.Content)).Returns(new ToDoActivity()); - mockUserJsonSerializer.Setup(x => x.FromStream(storedProcedureExecuteResponse.Content)).Returns(new ToDoActivity()); - mockUserJsonSerializer.Setup(x => x.FromStream>(feedResponse.Content)).Returns(new CosmosFeedResponseUtil() { Data = new Collection() }); + mockUserJsonSerializer.Setup(x => x.FromStream(itemResponse.Content)).Callback(input => input.Dispose()).Returns(new ToDoActivity()); + mockUserJsonSerializer.Setup(x => x.FromStream(storedProcedureExecuteResponse.Content)).Callback(input => input.Dispose()).Returns(new ToDoActivity()); // Verify all the user types use the user specified version await cosmosResponseFactory.CreateItemResponseAsync(Task.FromResult(itemResponse)); await cosmosResponseFactory.CreateStoredProcedureExecuteResponseAsync(Task.FromResult(storedProcedureExecuteResponse)); - cosmosResponseFactory.CreateQueryFeedResponse(feedResponse); // Throw if the setups were not called mockUserJsonSerializer.VerifyAll(); @@ -151,12 +147,6 @@ public async Task ValidateResponseFactoryJsonSerializer() Id = "mock" }; - mockDefaultJsonSerializer.Setup(x => x.FromStream(databaseResponse.Content)).Returns(databaseSettings); - mockDefaultJsonSerializer.Setup(x => x.FromStream(containerResponse.Content)).Returns(containerSettings); - mockDefaultJsonSerializer.Setup(x => x.FromStream(storedProcedureResponse.Content)).Returns(cosmosStoredProcedureSettings); - mockDefaultJsonSerializer.Setup(x => x.FromStream(triggerResponse.Content)).Returns(cosmosTriggerSettings); - mockDefaultJsonSerializer.Setup(x => x.FromStream(udfResponse.Content)).Returns(cosmosUserDefinedFunctionSettings); - Mock mockContainer = new Mock(); Mock mockDatabase = new Mock(); @@ -166,9 +156,6 @@ public async Task ValidateResponseFactoryJsonSerializer() await cosmosResponseFactory.CreateStoredProcedureResponseAsync(Task.FromResult(storedProcedureResponse)); await cosmosResponseFactory.CreateTriggerResponseAsync(Task.FromResult(triggerResponse)); await cosmosResponseFactory.CreateUserDefinedFunctionResponseAsync(Task.FromResult(udfResponse)); - - // Throw if the setups were not called - mockDefaultJsonSerializer.VerifyAll(); } [TestMethod] diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosPermissionUnitTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosPermissionUnitTests.cs index dacacfc888..e6cb8fede4 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosPermissionUnitTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosPermissionUnitTests.cs @@ -4,7 +4,6 @@ namespace Microsoft.Azure.Cosmos.Tests { - using Microsoft.Azure.Cosmos.Client.Core.Tests; using Microsoft.VisualStudio.TestTools.UnitTesting; using System.Net; using System.Threading.Tasks; diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosSerializerCoreTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosSerializerCoreTests.cs new file mode 100644 index 0000000000..4ebe93caed --- /dev/null +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/CosmosSerializerCoreTests.cs @@ -0,0 +1,173 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Tests +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Text; + using Microsoft.Azure.Cosmos.Query.Core; + using Microsoft.Azure.Cosmos.Query.Core.QueryPlan; + using Microsoft.Azure.Cosmos.Scripts; + using Microsoft.Azure.Documents; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using Newtonsoft.Json; + + [TestClass] + public class CosmosSerializerCoreTests + { + [TestMethod] + public void ValidateSqlQuerySpecSerialization() + { + int toCount = 0; + int fromCount = 0; + + CosmosSerializerHelper serializerHelper = new CosmosSerializerHelper( + null, + (input) => fromCount++, + (input) => toCount++); + + CosmosSerializerCore serializerCore = new CosmosSerializerCore(serializerHelper); + SqlQuerySpec querySpec = new SqlQuerySpec("select * from T where T.id = @id"); + querySpec.Parameters = new SqlParameterCollection() + { + new SqlParameter("@id", "testValue") + }; + + try + { + serializerCore.ToStream(querySpec); + Assert.Fail("ToStream should throw exception"); + } + catch (ArgumentException e) + { + Assert.IsNotNull(e); + } + + try + { + serializerCore.FromStream(new MemoryStream()); + Assert.Fail("FromStream should throw exception"); + } + catch (ArgumentException e) + { + Assert.IsNotNull(e); + } + + Assert.AreEqual(0, toCount); + Assert.AreEqual(0, fromCount); + + using (Stream stream = serializerCore.ToStreamSqlQuerySpec(querySpec, ResourceType.Offer)) { } + + Assert.AreEqual(0, toCount); + Assert.AreEqual(0, fromCount); + + List publicQuerySupportedTypes = new List() + { + ResourceType.Database, + ResourceType.Collection, + ResourceType.Document, + ResourceType.Trigger, + ResourceType.UserDefinedFunction, + ResourceType.StoredProcedure, + ResourceType.Permission, + ResourceType.User, + ResourceType.Conflict + }; + + foreach (ResourceType resourceType in publicQuerySupportedTypes) + { + toCount = 0; + + using (Stream stream = serializerCore.ToStreamSqlQuerySpec(querySpec, resourceType)) + { + Assert.AreEqual(1, toCount); + Assert.AreEqual(0, fromCount); + } + } + } + + [TestMethod] + public void ValidateCustomSerializerNotUsedForInternalTypes() + { + CosmosSerializerHelper serializerHelper = new CosmosSerializerHelper( + null, + (item) => throw new ArgumentException("Should be using internal serializer"), + (item) => throw new ArgumentException("Should be using internal serializer")); + + CosmosSerializerCore serializerCore = new CosmosSerializerCore(serializerHelper); + + string id = "testId"; + this.TestProperty( + serializerCore, + id, + $@"{{""id"":""{id}"",""_etag"":null,""_rid"":null,""writableLocations"":[],""readableLocations"":[],""userConsistencyPolicy"":null,""addresses"":null,""userReplicationPolicy"":null,""systemReplicationPolicy"":null,""readPolicy"":null,""queryEngineConfiguration"":null,""enableMultipleWriteLocations"":false}}"); + + this.TestProperty( + serializerCore, + id, + $@"{{""id"":""{id}"",""_etag"":null,""_ts"":1576767176,""_rid"":null}}"); + + this.TestProperty( + serializerCore, + id, + $@"{{""id"":""{id}"",""partitionKey"":{{""paths"":[],""kind"":""Hash""}}}}"); + + this.TestProperty( + serializerCore, + id, + $@"{{""body"":""bodyCantBeNull"",""id"":""{id}"",""_etag"":null,""_ts"":1576767176,""_rid"":null}}"); + + this.TestProperty( + serializerCore, + id, + $@"{{""body"":null,""triggerType"":""Pre"",""triggerOperation"":""All"",""id"":""{id}"",""_etag"":null}}"); + + this.TestProperty( + serializerCore, + id, + $@"{{""body"":null,""id"":""{id}"",""_etag"":null}}"); + + this.TestProperty( + serializerCore, + id, + $@"{{""id"":""{id}"",""_etag"":null,""_ts"":1576767176,""_rid"":null,""_permissions"":null}}"); + + this.TestProperty( + serializerCore, + id, + $@"{{""id"":""{id}"",""resource"":null,""permissionMode"":0}}"); + + this.TestProperty( + serializerCore, + id, + $@"{{""id"":""{id}"",""operationType"":""Invalid"",""resourceType"":null,""resourceId"":null,""content"":null,""conflict_lsn"":0}}"); + + // Throughput doesn't have an id. + string defaultThroughputJson = @"{""_etag"":null,""_ts"":1576767176,""Throughput"":null,""_rid"":null,""offerResourceId"":null}"; + ThroughputProperties property = JsonConvert.DeserializeObject(defaultThroughputJson); + Assert.IsNull(property.Throughput); + string propertyJson = JsonConvert.SerializeObject(property); + Assert.AreEqual(defaultThroughputJson, propertyJson); + } + + private void TestProperty( + CosmosSerializerCore serializerCore, + string id, + string defaultJson) + { + dynamic property = serializerCore.FromStream(new MemoryStream(Encoding.UTF8.GetBytes(defaultJson))); + Assert.AreEqual(id, property.Id); + using (Stream stream = serializerCore.ToStream(property)) + { + using (StreamReader sr = new StreamReader(stream)) + { + string propertyJson = sr.ReadToEnd(); + Assert.AreEqual(defaultJson, propertyJson); + } + } + } + } +} diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ExceptionlessTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ExceptionlessTests.cs index 7fe3d56b90..ad1523f241 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ExceptionlessTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ExceptionlessTests.cs @@ -2,7 +2,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ -namespace Microsoft.Azure.Cosmos +namespace Microsoft.Azure.Cosmos.Tests { using System; using System.Globalization; @@ -12,7 +12,6 @@ namespace Microsoft.Azure.Cosmos using System.Text; using System.Threading; using System.Threading.Tasks; - using Microsoft.Azure.Cosmos.Client.Core.Tests; using Microsoft.Azure.Cosmos.Collections; using Microsoft.Azure.Cosmos.Common; using Microsoft.Azure.Cosmos.Handlers; @@ -310,10 +309,10 @@ private static GatewayStoreModel MockGatewayStoreModel(Func items) Create( @@ -34,7 +33,7 @@ public static (QueryResponseCore queryResponse, IList items) Create( } IList items = ToDoItem.CreateItems(itemCount, itemIdPrefix); - MemoryStream memoryStream = (MemoryStream)cosmosSerializer.ToStream>(items); + MemoryStream memoryStream = (MemoryStream)MockCosmosUtil.Serializer.ToStream>(items); long responseLengthBytes = memoryStream.Length; IJsonNavigator jsonNavigator = JsonNavigator.Create(memoryStream.ToArray()); @@ -92,7 +91,7 @@ public static QueryResponseCore CreateQueryResponse( } else { - memoryStream = (MemoryStream)cosmosSerializer.ToStream>(items); + memoryStream = (MemoryStream)MockCosmosUtil.Serializer.ToStream>(items); } long responseLengthBytes = memoryStream.Length; @@ -134,7 +133,7 @@ public static QueryResponseCore CreateQueryResponse( public static QueryResponse CreateQueryResponse( QueryResponse queryResponse) { - return QueryResponse.CreateResponse(queryResponse, cosmosSerializer); + return QueryResponse.CreateResponse(queryResponse, MockCosmosUtil.Serializer); } public static QueryResponseCore CreateFailureResponse( @@ -198,7 +197,7 @@ private static MemoryStream SerializeForOrderByQuery(IList items) orderByItems = new OrderbyItems[] { new OrderbyItems(item.id) } }).ToArray(); - return (MemoryStream)cosmosSerializer.ToStream(payload); + return (MemoryStream)MockCosmosUtil.Serializer.ToStream(payload); } private class OrderByReturnStructure diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ResultSetIteratorTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ResultSetIteratorTests.cs index d307c92a27..6ca4fcfd09 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ResultSetIteratorTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/ResultSetIteratorTests.cs @@ -5,17 +5,19 @@ namespace Microsoft.Azure.Cosmos.Tests { using System; + using System.Collections; + using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; - using Microsoft.Azure.Cosmos.Client.Core.Tests; using Microsoft.Azure.Cosmos.Query.Core; using Microsoft.Azure.Cosmos.Scripts; using Microsoft.Azure.Documents; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; + using Newtonsoft.Json.Linq; [TestClass] public class ResultSetIteratorTests @@ -50,10 +52,10 @@ public void ValidateFillQueryRequestOptions() [TestMethod] public async Task CosmosConflictsIteratorBuildsSettings() { - string conflictResponsePayload = @"{ 'Data':[{ - id: 'Conflict1', - operationType: 'Replace', - resourceType: 'trigger' + string conflictResponsePayload = @"{ ""Conflicts"":[{ + ""id"": ""Conflict1"", + ""operationType"": ""Replace"", + ""resourceType"": ""trigger"" }]}"; CosmosClient mockClient = MockCosmosUtil.CreateMockCosmosClient( @@ -94,12 +96,13 @@ public async Task CosmosConflictsIteratorBuildsSettings() [TestMethod] public async Task CosmosConflictsStreamIteratorBuildsSettings() { - string conflictResponsePayload = @"{ 'Data':[{ - id: 'Conflict1', - operationType: 'Replace', - resourceType: 'trigger' + string conflictResponsePayload = @"{ ""Conflicts"":[{ + ""id"": ""Conflict1"", + ""operationType"": ""Replace"", + ""resourceType"": ""trigger"" }]}"; + JObject jObject = JObject.Parse(conflictResponsePayload); CosmosClient mockClient = MockCosmosUtil.CreateMockCosmosClient( (cosmosClientBuilder) => cosmosClientBuilder.WithConnectionModeDirect()); @@ -124,7 +127,9 @@ public async Task CosmosConflictsStreamIteratorBuildsSettings() mockClient.RequestHandler.InnerHandler = testHandler; ResponseMessage streamResponse = await feedIterator.ReadNextAsync(); - Collection response = MockCosmosUtil.Serializer.FromStream>(streamResponse.Content).Data; + IEnumerable response = MockCosmosUtil.Serializer.FromFeedResponseStream( + streamResponse.Content, + ResourceType.Conflict); Assert.AreEqual(1, response.Count()); diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/RetryHandlerTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/RetryHandlerTests.cs index 69560cef9f..29caef2520 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/RetryHandlerTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/RetryHandlerTests.cs @@ -9,7 +9,6 @@ namespace Microsoft.Azure.Cosmos.Tests using System.Net.Http; using System.Threading; using System.Threading.Tasks; - using Microsoft.Azure.Cosmos.Client.Core.Tests; using Microsoft.Azure.Cosmos.Handlers; using Microsoft.Azure.Documents; using Microsoft.VisualStudio.TestTools.UnitTesting; diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Scenarios/GremlinScenarioTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Scenarios/GremlinScenarioTests.cs index 89816781d9..ad4b73ac17 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Scenarios/GremlinScenarioTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Scenarios/GremlinScenarioTests.cs @@ -12,6 +12,7 @@ namespace Microsoft.Azure.Cosmos.Scenarios using System.Text; using Microsoft.Azure.Cosmos.CosmosElements; using Microsoft.Azure.Cosmos.Json; + using Microsoft.Azure.Cosmos.Tests; using Microsoft.Azure.Documents; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -651,7 +652,7 @@ internal void GetCosmosElementsFromQueryResponseTest(JsonSerializationFormat jso QueryResponse cosmosElementQueryResponse = QueryResponse.CreateResponse( queryResponse, - new CosmosJsonSerializerWrapper(new CosmosJsonDotNetSerializer())); + MockCosmosUtil.Serializer); // Assert that we are directly returned the lazy CosmosElements that we created earlier List responseCosmosElements = new List(cosmosElementQueryResponse.Resource); @@ -733,7 +734,7 @@ internal void GetDeserializedObjectsFromQueryResponseTest(JsonSerializationForma QueryResponse cosmosElementQueryResponse = QueryResponse.CreateResponse( queryResponse, - new CosmosJsonSerializerWrapper(new CosmosJsonDotNetSerializer())); + MockCosmosUtil.Serializer); // Assert that other objects (anything besides the lazy CosmosElements that we created earlier) are deserialized // from the backing CosmosElement contents rather than being directly returned as CosmosElements diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/SettingsContractTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/SettingsContractTests.cs index 6175525301..cc0bc9e95a 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/SettingsContractTests.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/SettingsContractTests.cs @@ -395,18 +395,18 @@ public async Task ContainerSettingsIndexTest() { string containerJsonString = "{\"indexingPolicy\":{\"automatic\":true,\"indexingMode\":\"Consistent\",\"includedPaths\":[{\"path\":\"/*\",\"indexes\":[{\"dataType\":\"Number\",\"precision\":-1,\"kind\":\"Range\"},{\"dataType\":\"String\",\"precision\":-1,\"kind\":\"Range\"}]}],\"excludedPaths\":[{\"path\":\"/\\\"_etag\\\"/?\"}],\"compositeIndexes\":[],\"spatialIndexes\":[]},\"id\":\"MigrationTest\",\"partitionKey\":{\"paths\":[\"/id\"],\"kind\":\"Hash\"}}"; - CosmosJsonDotNetSerializer cosmosSerializer = new CosmosJsonDotNetSerializer(); + CosmosJsonDotNetSerializer serializerCore = new CosmosJsonDotNetSerializer(); ContainerProperties containerProperties = null; using (MemoryStream memory = new MemoryStream(Encoding.UTF8.GetBytes(containerJsonString))) { - containerProperties = cosmosSerializer.FromStream(memory); + containerProperties = serializerCore.FromStream(memory); } Assert.IsNotNull(containerProperties); Assert.AreEqual("MigrationTest", containerProperties.Id); string containerJsonAfterConversion = null; - using (Stream stream = cosmosSerializer.ToStream(containerProperties)) + using (Stream stream = serializerCore.ToStream(containerProperties)) { using (StreamReader sr = new StreamReader(stream)) { @@ -502,13 +502,13 @@ public async Task ContainerV2CompatTest() documentCollection.SaveTo(memoryStream); memoryStream.Position = 0; - CosmosJsonDotNetSerializer cosmosSerializer = new CosmosJsonDotNetSerializer(); - ContainerProperties containerProperties = cosmosSerializer.FromStream(memoryStream); + CosmosJsonDotNetSerializer serializerCore = new CosmosJsonDotNetSerializer(); + ContainerProperties containerProperties = serializerCore.FromStream(memoryStream); Assert.IsNotNull(containerProperties); Assert.AreEqual(containerId, containerProperties.Id); - using (Stream stream = cosmosSerializer.ToStream(containerProperties)) + using (Stream stream = serializerCore.ToStream(containerProperties)) { using (StreamReader sr = new StreamReader(stream)) { diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/CosmosSerializerHelper.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/CosmosSerializerHelper.cs new file mode 100644 index 0000000000..9fda712426 --- /dev/null +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/CosmosSerializerHelper.cs @@ -0,0 +1,90 @@ +//------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +//------------------------------------------------------------ + +namespace Microsoft.Azure.Cosmos.Tests +{ + using System; + using System.Globalization; + using System.IO; + using Newtonsoft.Json; + + /// + /// Placeholder for VST Logger. + /// + internal class CosmosSerializerHelper : CosmosSerializer + { + private readonly CosmosSerializer cosmosSerializer; + private readonly Action fromStreamCallback; + private readonly Action toStreamCallBack; + + public CosmosSerializerHelper( + JsonSerializerSettings jsonSerializerSettings, + Action fromStreamCallback, + Action toStreamCallBack) + { + if (jsonSerializerSettings == null) + { + this.cosmosSerializer = new CosmosJsonDotNetSerializer(); + } + else + { + this.cosmosSerializer = new CosmosJsonDotNetSerializer(jsonSerializerSettings); + } + + this.fromStreamCallback = fromStreamCallback; + this.toStreamCallBack = toStreamCallBack; + } + + public override T FromStream(Stream stream) + { + T item = this.cosmosSerializer.FromStream(stream); + this.fromStreamCallback?.Invoke(item); + + return item; + } + + public override Stream ToStream(T input) + { + this.toStreamCallBack?.Invoke(input); + return this.cosmosSerializer.ToStream(input); + } + + public sealed class FormatNumbersAsTextConverter : JsonConverter + { + public override bool CanRead => false; + public override bool CanWrite => true; + public override bool CanConvert(Type type) + { + return type == typeof(int) || type == typeof(double); + } + + public override void WriteJson( + JsonWriter writer, + object value, + JsonSerializer serializer) + { + if (value.GetType() == typeof(int)) + { + int number = (int)value; + writer.WriteValue(number.ToString(CultureInfo.InvariantCulture)); + } + else + { + double number = (double)value; + writer.WriteValue(number.ToString(CultureInfo.InvariantCulture)); + } + + } + + public override object ReadJson( + JsonReader reader, + Type type, + object existingValue, + JsonSerializer serializer) + { + throw new NotSupportedException(); + } + } + } +} diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/MockCosmosUtil.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/MockCosmosUtil.cs similarity index 96% rename from Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/MockCosmosUtil.cs rename to Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/MockCosmosUtil.cs index 0fd8d94fad..2ee446c9e5 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/MockCosmosUtil.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/MockCosmosUtil.cs @@ -2,7 +2,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ -namespace Microsoft.Azure.Cosmos.Client.Core.Tests +namespace Microsoft.Azure.Cosmos.Tests { using System; using System.Collections.Generic; @@ -21,7 +21,7 @@ namespace Microsoft.Azure.Cosmos.Client.Core.Tests internal class MockCosmosUtil { - public static readonly CosmosSerializer Serializer = new CosmosJsonDotNetSerializer(); + public static readonly CosmosSerializerCore Serializer = new CosmosSerializerCore(); public static CosmosClient CreateMockCosmosClient( Action customizeClientBuilder = null, diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/MockDocumentClient.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/MockDocumentClient.cs similarity index 99% rename from Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/MockDocumentClient.cs rename to Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/MockDocumentClient.cs index c139955c75..8362e05f52 100644 --- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/MockDocumentClient.cs +++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Utils/MockDocumentClient.cs @@ -2,7 +2,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. //------------------------------------------------------------ -namespace Microsoft.Azure.Cosmos.Client.Core.Tests +namespace Microsoft.Azure.Cosmos.Tests { using System; using System.Collections.Generic; diff --git a/changelog.md b/changelog.md index b3fa58f702..f3ea71f4ce 100644 --- a/changelog.md +++ b/changelog.md @@ -12,10 +12,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - [#1097](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/1097) Add GeospatialConfig to ContainerProperties, BoundingBoxProperties to SpatialPath - [#1061](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/1061) Add Stream payload to ExecuteStoredProcedureStreamAsync -### Added - ### Fixed +- [#1105](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/1105) Custom serializer no longer calls SDK owned types that would cause serialization exceptions ## [3.5.1](https://www.nuget.org/packages/Microsoft.Azure.Cosmos/3.5.1) - 2019-12-11