diff --git a/Microsoft.Azure.Cosmos/src/Resource/QueryResponses/FeedResponse.cs b/Microsoft.Azure.Cosmos/src/Resource/QueryResponses/FeedResponse.cs
index 370a647076..9c32b12c49 100644
--- a/Microsoft.Azure.Cosmos/src/Resource/QueryResponses/FeedResponse.cs
+++ b/Microsoft.Azure.Cosmos/src/Resource/QueryResponses/FeedResponse.cs
@@ -21,31 +21,6 @@ protected FeedResponse()
{
}
- ///
- /// Create a FeedResponse object with the default properties set
- ///
- /// The status code of the response
- /// The headers of the response
- /// The object from the response
- internal FeedResponse(
- HttpStatusCode httpStatusCode,
- Headers headers,
- IEnumerable resource)
- {
- this.StatusCode = httpStatusCode;
- this.Headers = headers;
- this.Resource = resource;
- }
-
- ///
- public override Headers Headers { get; }
-
- ///
- public override IEnumerable Resource { get; }
-
- ///
- public override HttpStatusCode StatusCode { get; }
-
///
public override double RequestCharge => this.Headers?.RequestCharge ?? 0;
diff --git a/Microsoft.Azure.Cosmos/src/Resource/QueryResponses/QueryResponse.cs b/Microsoft.Azure.Cosmos/src/Resource/QueryResponses/QueryResponse.cs
index d7e441a401..c581a1107e 100644
--- a/Microsoft.Azure.Cosmos/src/Resource/QueryResponses/QueryResponse.cs
+++ b/Microsoft.Azure.Cosmos/src/Resource/QueryResponses/QueryResponse.cs
@@ -140,10 +140,8 @@ internal class QueryResponse : FeedResponse
private readonly CosmosSerializationOptions serializationOptions;
private IEnumerable resources;
- ///
- /// Create a
- ///
private QueryResponse(
+ HttpStatusCode httpStatusCode,
IEnumerable cosmosElements,
CosmosQueryResponseMessageHeaders responseMessageHeaders,
CosmosSerializer jsonSerializer,
@@ -153,46 +151,26 @@ private QueryResponse(
this.QueryHeaders = responseMessageHeaders;
this.jsonSerializer = jsonSerializer;
this.serializationOptions = serializationOptions;
+ this.StatusCode = httpStatusCode;
}
- ///
- /// Gets the continuation token
- ///
public override string ContinuationToken => this.Headers.ContinuationToken;
- ///
- /// Gets the request charge for this request from the Azure Cosmos DB service.
- ///
- ///
- /// The request charge measured in request units.
- ///
public override double RequestCharge => this.Headers.RequestCharge;
- ///
- /// The headers of the response
- ///
public override Headers Headers => this.QueryHeaders;
- ///
- /// The number of items in the stream.
- ///
+ public override HttpStatusCode StatusCode { get; }
+
public override int Count => this.cosmosElements?.Count() ?? 0;
internal CosmosQueryResponseMessageHeaders QueryHeaders { get; }
- ///
- /// Get the enumerators to iterate through the results
- ///
- /// An enumerator of the response objects
public override IEnumerator GetEnumerator()
{
return this.Resource.GetEnumerator();
}
- ///
- /// Get the enumerators to iterate through the results
- ///
- /// An enumerator of the response objects
public override IEnumerable Resource
{
get
@@ -235,6 +213,7 @@ internal static QueryResponse CreateResponse(
{
cosmosQueryResponse.EnsureSuccessStatusCode();
queryResponse = new QueryResponse(
+ httpStatusCode: cosmosQueryResponse.StatusCode,
cosmosElements: cosmosQueryResponse.CosmosElements,
responseMessageHeaders: cosmosQueryResponse.QueryHeaders,
jsonSerializer: jsonSerializer,
diff --git a/Microsoft.Azure.Cosmos/src/Resource/QueryResponses/ReadFeedResponse.cs b/Microsoft.Azure.Cosmos/src/Resource/QueryResponses/ReadFeedResponse.cs
index e5a54b8f2e..ad2b5ccac4 100644
--- a/Microsoft.Azure.Cosmos/src/Resource/QueryResponses/ReadFeedResponse.cs
+++ b/Microsoft.Azure.Cosmos/src/Resource/QueryResponses/ReadFeedResponse.cs
@@ -10,20 +10,26 @@ namespace Microsoft.Azure.Cosmos
internal class ReadFeedResponse : FeedResponse
{
protected ReadFeedResponse(
+ HttpStatusCode httpStatusCode,
ICollection resource,
Headers responseMessageHeaders)
- : base(
- httpStatusCode: HttpStatusCode.Accepted,
- headers: responseMessageHeaders,
- resource: resource)
{
this.Count = resource.Count;
+ this.Headers = responseMessageHeaders;
+ this.Resource = resource;
+ this.StatusCode = httpStatusCode;
}
public override int Count { get; }
public override string ContinuationToken => this.Headers?.ContinuationToken;
+ public override Headers Headers { get; }
+
+ public override IEnumerable Resource { get; }
+
+ public override HttpStatusCode StatusCode { get; }
+
public override IEnumerator GetEnumerator()
{
return this.Resource.GetEnumerator();
@@ -43,23 +49,12 @@ internal static ReadFeedResponse CreateResponse(
}
ReadFeedResponse readFeedResponse = new ReadFeedResponse(
+ httpStatusCode: responseMessage.StatusCode,
resource: resources,
responseMessageHeaders: responseMessage.Headers);
return readFeedResponse;
}
}
-
- internal static ReadFeedResponse CreateResponse(
- Headers responseMessageHeaders,
- ICollection resources,
- bool hasMoreResults)
- {
- ReadFeedResponse readFeedResponse = new ReadFeedResponse(
- resource: resources,
- responseMessageHeaders: responseMessageHeaders);
-
- return readFeedResponse;
- }
}
}
\ No newline at end of file
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 d375aee714..8e947eded1 100644
--- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosBasicQueryTests.cs
+++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.EmulatorTests/CosmosBasicQueryTests.cs
@@ -10,6 +10,7 @@ namespace Microsoft.Azure.Cosmos.SDK.EmulatorTests
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
+ using System.Net;
using System.Threading.Tasks;
using Cosmos.Scripts;
using Microsoft.Azure.Cosmos.Linq;
@@ -409,12 +410,14 @@ private async Task> ToListAsync(
string queryText,
QueryRequestOptions requestOptions)
{
+ HttpStatusCode expectedStatus = HttpStatusCode.OK;
FeedIterator feedStreamIterator = createStreamQuery(queryText, null, requestOptions);
List streamResults = new List();
while (feedStreamIterator.HasMoreResults)
{
ResponseMessage response = await feedStreamIterator.ReadNextAsync();
response.EnsureSuccessStatusCode();
+ Assert.AreEqual(expectedStatus, response.StatusCode);
StreamReader sr = new StreamReader(response.Content);
string result = await sr.ReadToEndAsync();
@@ -431,6 +434,7 @@ private async Task> ToListAsync(
FeedIterator pagedFeedIterator = createStreamQuery(queryText, continuationToken, requestOptions);
ResponseMessage response = await pagedFeedIterator.ReadNextAsync();
response.EnsureSuccessStatusCode();
+ Assert.AreEqual(expectedStatus, response.StatusCode);
ICollection responseResults = TestCommon.Serializer.FromStream>(response.Content).Data;
Assert.IsTrue(responseResults.Count <= 1);
@@ -451,11 +455,12 @@ private async Task> ToListAsync(
List results = new List();
while (feedIterator.HasMoreResults)
{
- FeedResponse iterator = await feedIterator.ReadNextAsync();
- Assert.IsTrue(iterator.Count <= 1);
- Assert.IsTrue(iterator.Resource.Count() <= 1);
+ FeedResponse response = await feedIterator.ReadNextAsync();
+ Assert.AreEqual(expectedStatus, response.StatusCode);
+ Assert.IsTrue(response.Count <= 1);
+ Assert.IsTrue(response.Resource.Count() <= 1);
- results.AddRange(iterator);
+ results.AddRange(response);
}
continuationToken = null;
@@ -463,11 +468,12 @@ private async Task> ToListAsync(
do
{
FeedIterator pagedFeedIterator = createQuery(queryText, continuationToken, requestOptions);
- FeedResponse iterator = await pagedFeedIterator.ReadNextAsync();
- Assert.IsTrue(iterator.Count <= 1);
- Assert.IsTrue(iterator.Resource.Count() <= 1);
- pagedResults.AddRange(iterator);
- continuationToken = iterator.ContinuationToken;
+ FeedResponse response = await pagedFeedIterator.ReadNextAsync();
+ Assert.AreEqual(expectedStatus, response.StatusCode);
+ Assert.IsTrue(response.Count <= 1);
+ Assert.IsTrue(response.Resource.Count() <= 1);
+ pagedResults.AddRange(response);
+ continuationToken = response.ContinuationToken;
} while (continuationToken != null);
Assert.AreEqual(pagedResults.Count, results.Count);
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 35d255942f..0a7907783a 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
@@ -67,12 +67,16 @@ private static Container GetMockedContainer(string containerName = "myColl")
Headers headers = new Headers();
headers.ContinuationToken = string.Empty;
+ Mock> mockFeedResponse = new Mock>();
+ mockFeedResponse.Setup(x => x.ContinuationToken).Returns(string.Empty);
+ mockFeedResponse.Setup(x => x.Headers).Returns(headers);
+ mockFeedResponse.Setup(x => x.Resource).Returns(DocumentServiceLeaseContainerCosmosTests.allLeases);
+ mockFeedResponse.Setup(x => x.Headers).Returns(headers);
+ mockFeedResponse.Setup(x => x.GetEnumerator()).Returns(DocumentServiceLeaseContainerCosmosTests.allLeases.GetEnumerator());
+
Mock> mockedQuery = new Mock>();
mockedQuery.Setup(q => q.ReadNextAsync(It.IsAny()))
- .ReturnsAsync(() => ReadFeedResponse.CreateResponse(
- responseMessageHeaders: headers,
- resources: DocumentServiceLeaseContainerCosmosTests.allLeases,
- hasMoreResults: false));
+ .ReturnsAsync(() => mockFeedResponse.Object);
mockedQuery.SetupSequence(q => q.HasMoreResults)
.Returns(true)
.Returns(false);
diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DotNetSDKAPI.json b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DotNetSDKAPI.json
index 4fec6023fa..57b123c6dd 100644
--- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DotNetSDKAPI.json
+++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/DotNetSDKAPI.json
@@ -1968,47 +1968,11 @@
"Attributes": [],
"MethodInfo": "Int32 get_Count()"
},
- "Microsoft.Azure.Cosmos.Headers get_Headers()[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]": {
- "Type": "Method",
- "Attributes": [
- "CompilerGeneratedAttribute"
- ],
- "MethodInfo": "Microsoft.Azure.Cosmos.Headers get_Headers()"
- },
- "Microsoft.Azure.Cosmos.Headers Headers": {
- "Type": "Property",
- "Attributes": [],
- "MethodInfo": null
- },
- "System.Collections.Generic.IEnumerable`1[T] get_Resource()[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]": {
- "Type": "Method",
- "Attributes": [
- "CompilerGeneratedAttribute"
- ],
- "MethodInfo": "System.Collections.Generic.IEnumerable`1[T] get_Resource()"
- },
- "System.Collections.Generic.IEnumerable`1[T] Resource": {
- "Type": "Property",
- "Attributes": [],
- "MethodInfo": null
- },
"System.Collections.Generic.IEnumerator`1[T] GetEnumerator()": {
"Type": "Method",
"Attributes": [],
"MethodInfo": "System.Collections.Generic.IEnumerator`1[T] GetEnumerator()"
},
- "System.Net.HttpStatusCode get_StatusCode()[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]": {
- "Type": "Method",
- "Attributes": [
- "CompilerGeneratedAttribute"
- ],
- "MethodInfo": "System.Net.HttpStatusCode get_StatusCode()"
- },
- "System.Net.HttpStatusCode StatusCode": {
- "Type": "Property",
- "Attributes": [],
- "MethodInfo": null
- },
"System.String ActivityId": {
"Type": "Property",
"Attributes": [],
diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/ItemProducerTests.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/ItemProducerTests.cs
index a812bf0a27..e9c67fb16f 100644
--- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/ItemProducerTests.cs
+++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/ItemProducerTests.cs
@@ -127,11 +127,31 @@ public async Task BufferMore(int maxPageSize, int[] pageSizes)
[TestMethod]
public async Task ConcurrentMoveNextAndBufferMore()
{
+ bool blockExecute = true;
+ int callBackCount = 0;
+ Action callbackBlock = () =>
+ {
+ int callBackWaitCount = 0;
+ callBackCount++;
+ while (blockExecute)
+ {
+ if (callBackWaitCount++ > 200)
+ {
+ Assert.Fail("The task never started to buffer the items. The callback was never called");
+ }
+
+ Thread.Sleep(TimeSpan.FromSeconds(.1));
+ }
+
+ // Reset the block for the next call
+ blockExecute = true;
+ };
+
int[] pageSizes = new int[] { 2, 3, 1, 4 };
(ItemProducer itemProducer, ReadOnlyCollection allItems) itemFactory = MockItemProducerFactory.Create(
responseMessagesPageSize: pageSizes,
maxPageSize: 10,
- responseDelay: TimeSpan.FromSeconds(1),
+ executeCallback: callbackBlock,
cancellationToken: this.cancellationToken);
ItemProducer itemProducer = itemFactory.itemProducer;
@@ -139,8 +159,19 @@ public async Task ConcurrentMoveNextAndBufferMore()
// BufferMore
// Fire and Forget this task.
#pragma warning disable 4014
- Task.Run(() => itemProducer.BufferMoreDocumentsAsync(this.cancellationToken));
-#pragma warning restore 4014
+ Task bufferTask = Task.Run(()=> itemProducer.BufferMoreDocumentsAsync(this.cancellationToken));
+
+ // Verify the task started
+ int waitCount = 0;
+ while(callBackCount == 0)
+ {
+ if(waitCount++ > 100)
+ {
+ Assert.Fail("The task never started to buffer the items. The callback was never called");
+ }
+
+ Thread.Sleep(TimeSpan.FromSeconds(.1));
+ }
List itemsRead = new List();
Assert.AreEqual(0, itemProducer.BufferedItemCount, "Mocked response should be delayed until after move next is called.");
@@ -148,18 +179,59 @@ public async Task ConcurrentMoveNextAndBufferMore()
int itemsToRead = pageSizes[0] + pageSizes[1];
// Call move next while buffer more is waiting for response.
// Move next should wait for buffer more to complete then use the results of the buffer more.
- List currentPage = await this.ReadItemProducer(itemProducer, itemsToRead);
- itemsRead.AddRange(currentPage);
+#pragma warning disable 4014
+ bool readTaskRunning = false;
+ Task readTask = Task.Run(async () =>
+ {
+ readTaskRunning = true;
+ List currentPage = await this.ReadItemProducer(itemProducer, itemsToRead);
+ itemsRead.AddRange(currentPage);
+ });
+#pragma warning restore 4014
+
+ // Verify the task started
+ while (readTaskRunning == false)
+ {
+ Thread.Sleep(TimeSpan.FromSeconds(.1));
+ }
+
+ Assert.AreEqual(0, itemProducer.BufferedItemCount, "The call back block will prevent any item from being buffered");
+ Assert.AreEqual(1, callBackCount, "Buffer more should have a lock which prevents multiple executes.");
+ // Unblock the buffer task
+ blockExecute = false;
+ await bufferTask;
+ Assert.AreEqual(2, itemProducer.BufferedItemCount, "Buffer should be completed and have 2 items from first page");
+
+ // Unblock the read task
+ blockExecute = false;
+ await readTask;
Assert.AreEqual(itemsToRead, itemsRead.Count, "All of the first and 2nd page should be read.");
Assert.AreEqual(1, itemProducer.BufferedItemCount, "The last element should still be buffered. Moving next will cause another buffer.");
itemsToRead = pageSizes[2] + pageSizes[3];
#pragma warning disable 4014
- Task.Run(() => itemProducer.MoveNextAsync(this.cancellationToken));
+ Task moveNext = Task.Run(() => itemProducer.MoveNextAsync(this.cancellationToken));
#pragma warning restore 4014
+ while (callBackCount == 2)
+ {
+ if (waitCount++ > 100)
+ {
+ Assert.Fail("The task never started to buffer the items. The callback was never called");
+ }
+
+ Thread.Sleep(TimeSpan.FromSeconds(.1));
+ }
+
+ bufferTask = Task.Run(() => itemProducer.BufferMoreDocumentsAsync(this.cancellationToken));
+
+ Assert.AreEqual(3, callBackCount, "Buffer more should have a lock which prevents multiple executes.");
+
+ blockExecute = false;
+ await moveNext;
- await itemProducer.BufferMoreDocumentsAsync(this.cancellationToken);
+ blockExecute = false;
+ await bufferTask;
Assert.AreEqual(itemsToRead, itemProducer.BufferedItemCount, "2nd Page should be loaded.");
}
diff --git a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/MockItemProducerFactory.cs b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/MockItemProducerFactory.cs
index 385ad654ee..35f981450b 100644
--- a/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/MockItemProducerFactory.cs
+++ b/Microsoft.Azure.Cosmos/tests/Microsoft.Azure.Cosmos.Tests/Query/MockItemProducerFactory.cs
@@ -46,7 +46,7 @@ public static (ItemProducer itemProducer, ReadOnlyCollection allItems)
string continuationToken = null,
int maxPageSize = 50,
ItemProducer.ProduceAsyncCompleteDelegate completeDelegate = null,
- TimeSpan? responseDelay = null,
+ Action executeCallback = null,
CancellationToken cancellationToken = default(CancellationToken))
{
if (responseMessagesPageSize == null)
@@ -81,7 +81,7 @@ public static (ItemProducer itemProducer, ReadOnlyCollection allItems)
continuationToken,
maxPageSize,
DefaultCollectionRid,
- responseDelay,
+ executeCallback,
cancellationToken);
ItemProducer itemProducer = new ItemProducer(
@@ -117,7 +117,7 @@ public static (ItemProducerTree itemProducerTree, ReadOnlyCollection a
string collectionRid = null,
IComparer itemProducerTreeComparer = null,
ItemProducerTree.ProduceAsyncCompleteDelegate completeDelegate = null,
- TimeSpan? responseDelay = null,
+ Action executeCallback = null,
CancellationToken cancellationToken = default(CancellationToken))
{
if (responseMessagesPageSize == null)
@@ -161,7 +161,7 @@ public static (ItemProducerTree itemProducerTree, ReadOnlyCollection a
continuationToken,
maxPageSize,
collectionRid,
- responseDelay,
+ executeCallback,
cancellationToken);
ItemProducerTree itemProducerTree = new ItemProducerTree(
@@ -198,7 +198,7 @@ public static List MockSinglePartitionKeyRangeContext(
string continuationToken,
int maxPageSize,
string collectionRid,
- TimeSpan? responseDelay,
+ Action executeCallback,
CancellationToken cancellationToken)
{
// Setup a list of query responses. It generates a new continuation token for each response. This allows the mock to return the messages in the correct order.
@@ -235,13 +235,7 @@ public static List MockSinglePartitionKeyRangeContext(
It.IsAny(),
maxPageSize,
cancellationToken))
- .Callback(() =>
- {
- if (responseDelay.HasValue)
- {
- Thread.Sleep(responseDelay.Value);
- }
- })
+ .Callback(() => executeCallback?.Invoke())
.Returns(Task.FromResult(queryResponse.response));
@@ -262,7 +256,7 @@ public static List MockSinglePartitionKeyRangeContext(
string continuationToken,
int maxPageSize,
string collectionRid,
- TimeSpan? responseDelay,
+ Action executeCallback,
CancellationToken cancellationToken)
{
// Setup a list of query responses. It generates a new continuation token for each response. This allows the mock to return the messages in the correct order.
@@ -294,13 +288,7 @@ public static List MockSinglePartitionKeyRangeContext(
It.IsAny(),
maxPageSize,
cancellationToken))
- .Callback(() =>
- {
- if (responseDelay.HasValue)
- {
- Thread.Sleep(responseDelay.Value);
- }
- })
+ .Callback(() =>executeCallback?.Invoke())
.Returns(Task.FromResult(queryResponse.response));
previousContinuationToken = newContinuationToken;
}
diff --git a/changelog.md b/changelog.md
index c6451dd26a..2e765f146d 100644
--- a/changelog.md
+++ b/changelog.md
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [#612](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/612) Bug fix for ReadFeed with partition-key
- [#614](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/614) Fixed SpatialPath serialization and compatibility with older index versions
+- [#626](https://github.com/Azure/azure-cosmos-dotnet-v3/pull/626) FeedResponse status code now return OK for success instead of the invalid status code 0 or Accepted
## [3.1.0](https://www.nuget.org/packages/Microsoft.Azure.Cosmos/3.1.0) - 2019-07-26