Skip to content

Commit

Permalink
Return null if cosmos db input can't find item (#2942)
Browse files Browse the repository at this point in the history
* Fix cosmos db 404 exception

fix

* Update release_notes.md

* Update release_notes.md

* Update release_notes.md

* Update test/Worker.Extensions.Tests/Cosmos/CosmosDBConverterTests.cs

Co-authored-by: Lilian Kasem <[email protected]>

* Update release_notes.md

* add e2e tests

* Update release_notes.md

---------

Co-authored-by: Florian Lenz <[email protected]>
Co-authored-by: Lilian Kasem <[email protected]>
  • Loading branch information
3 people authored Jan 30, 2025
1 parent cc39fcf commit 9314bae
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 3 deletions.
1 change: 1 addition & 0 deletions extensions/Worker.Extensions.CosmosDB/release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
### Microsoft.Azure.Functions.Worker.Extensions.CosmosDB 4.12.0

- Updated `Microsoft.Azure.WebJobs.Extensions.CosmosDB` reference to 4.9.0
- Return a successful result with a null value when a Cosmos document cannot be found (#2942/#2545)
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,10 @@ private async ValueTask<ConversionResult> ConvertFromBindingDataAsync(ConverterC

return ConversionResult.Success(result);
}
catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
{
return ConversionResult.Success(null);
}
catch (Exception ex)
{
return ConversionResult.Failed(ex);
Expand Down
5 changes: 5 additions & 0 deletions test/E2ETests/E2EApps/E2EApp/Cosmos/CosmosFunction.cs
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@ public async Task<HttpResponseData> DocByIdFromRouteData(
Id = "{id}",
PartitionKey = "{partitionKey}")] MyDocument doc)
{
if (doc == null)
{
return req.CreateResponse(HttpStatusCode.NotFound);
}

var response = req.CreateResponse(HttpStatusCode.OK);
await response.WriteStringAsync(doc.Text);
return response;
Expand Down
22 changes: 22 additions & 0 deletions test/E2ETests/E2ETests/Cosmos/CosmosDBEndToEndTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,28 @@ public async Task CosmosInput_DocByIdFromRouteData_Succeeds()
}
}

[Fact]
public async Task CosmosInput_DocByIdFromRouteDataNotFound_Succeeds()
{
string expectedDocId = Guid.NewGuid().ToString();
string functionPath = $"docsbyroute/{expectedDocId}/{expectedDocId}";
try
{
//Trigger
HttpResponseMessage response = await HttpHelpers.InvokeHttpTrigger(functionPath);

//Verify
HttpStatusCode expectedStatusCode = HttpStatusCode.NotFound;

Assert.Equal(expectedStatusCode, response.StatusCode);
}
finally
{
//Clean up
await CosmosDBHelpers.DeleteTestDocuments(expectedDocId);
}
}

[Fact]
public async Task CosmosInput_DocByIdFromRouteDataUsingSqlQuery_Succeeds()
{
Expand Down
37 changes: 34 additions & 3 deletions test/Worker.Extensions.Tests/Cosmos/CosmosDBConverterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -359,14 +360,18 @@ public async Task ConvertAsync_CosmosContainerIsNull_ThrowsException_ReturnsFail
Assert.Equal($"Unable to create Cosmos container client for 'myContainer'.", conversionResult.Error.Message);
}

[Fact]
public async Task ConvertAsync_POCO_IdProvided_StatusNot200_ThrowsException_ReturnsFailure()
[Theory]
[InlineData(HttpStatusCode.Conflict)]
[InlineData(HttpStatusCode.Forbidden)]
[InlineData(HttpStatusCode.InternalServerError)]
[InlineData(HttpStatusCode.BadRequest)]
public async Task ConvertAsync_POCO_IdProvided_NotSuccessStatus_ThrowsException_ReturnsFailure(HttpStatusCode httpStatusCode)
{
object grpcModelBindingData = GrpcTestHelper.GetTestGrpcModelBindingData(GetTestBinaryData(id: "1", partitionKey: "1"), "CosmosDB");
var context = new TestConverterContext(typeof(ToDoItem), grpcModelBindingData);

var mockResponse = new Mock<ResponseMessage>();
var cosmosException = new CosmosException("test failure", System.Net.HttpStatusCode.NotFound, 0, "test", 0);
var cosmosException = new CosmosException("test failure", httpStatusCode, 0, "test", 0);
mockResponse.Setup(x => x.EnsureSuccessStatusCode()).Throws(cosmosException);

var mockContainer = new Mock<Container>();
Expand All @@ -384,6 +389,32 @@ public async Task ConvertAsync_POCO_IdProvided_StatusNot200_ThrowsException_Retu
Assert.Equal("test failure", conversionResult.Error.Message);
}

[Fact]
public async Task ConvertAsync_POCO_IdProvided_Status404_ReturnsSuccess()
{
object grpcModelBindingData = GrpcTestHelper.GetTestGrpcModelBindingData(GetTestBinaryData(id: "1", partitionKey: "1"), "CosmosDB");
var context = new TestConverterContext(typeof(ToDoItem), grpcModelBindingData);

var mockResponse = new Mock<ResponseMessage>();
mockResponse.Setup(x => x.IsSuccessStatusCode).Returns(false);
var cosmosException = new CosmosException("test failure", HttpStatusCode.NotFound, 0, "test", 0);
mockResponse.Setup(x => x.EnsureSuccessStatusCode()).Throws(cosmosException);

var mockContainer = new Mock<Container>();
mockContainer
.Setup(m => m.ReadItemStreamAsync(It.IsAny<string>(), It.IsAny<PartitionKey>(), null, default))
.ReturnsAsync(mockResponse.Object);

_mockCosmosClient
.Setup(m => m.GetContainer(It.IsAny<string>(), It.IsAny<string>()))
.Returns(mockContainer.Object);

var conversionResult = await _cosmosDBConverter.ConvertAsync(context);

Assert.Equal(ConversionStatus.Succeeded, conversionResult.Status);
Assert.Null(conversionResult.Value);
}

private BinaryData GetTestBinaryData(string db = "testDb", string container = "testContainer", string connection = "cosmosConnection", string id = "", string partitionKey = "", string query = "", string location = "", string queryParams = "{}")
{
string jsonData = $@"{{
Expand Down

0 comments on commit 9314bae

Please sign in to comment.