Skip to content

Commit

Permalink
Fix async wrapper over sync API in reading nested property info (#2995)
Browse files Browse the repository at this point in the history
  • Loading branch information
gathogojr committed Jun 10, 2024
1 parent a81e113 commit 4b956cb
Show file tree
Hide file tree
Showing 2 changed files with 170 additions and 2 deletions.
59 changes: 59 additions & 0 deletions src/Microsoft.OData.Core/Json/ODataJsonReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,17 @@ protected override bool ReadAtNestedPropertyInfoImplementation()
return this.ReadAtNestedPropertyInfoSynchronously();
}

/// <summary>
/// Asynchronous implementation of the reader logic when in state 'PropertyInfo'.
/// </summary>
/// A task that represents the asynchronous read operation.
/// The value of the TResult parameter contains true if more items can be read from the reader; otherwise false
/// </returns>
protected override Task<bool> ReadAtNestedPropertyInfoImplementationAsync()
{
return this.ReadAtNestedPropertyInfoAsynchronously();
}

#endregion

#region Stream
Expand Down Expand Up @@ -1537,6 +1548,54 @@ private bool ReadAtNestedPropertyInfoSynchronously()
return true;
}

/// <summary>
/// Asynchronous implementation of the reader logic when in state 'PropertyInfo'.
/// </summary>
/// <returns>
/// A task that represents the asynchronous read operation.
/// The value of the TResult parameter contains true if more items can be read from the reader; otherwise false
/// </returns>
/// <remarks>
/// Pre-Condition: JsonNodeType.Property: there are more properties after the nested resource info in the owning resource
/// Post-Condition: JsonNodeType.StartObject start of the expanded resource nested resource info to read next
/// JsonNodeType.StartArray start of the expanded resource set nested resource info to read next
/// JsonNoteType.Primitive (null) expanded null resource nested resource info to read next
/// JsonNoteType.Property property after deferred link or entity reference link
/// JsonNodeType.EndObject end of the parent resource
/// </remarks>
private async Task<bool> ReadAtNestedPropertyInfoAsynchronously()
{
Debug.Assert(this.CurrentScope.State == ODataReaderState.NestedProperty, "Must be on 'NestedProperty' scope.");
JsonLightNestedPropertyInfoScope nestedPropertyInfoScope = (JsonLightNestedPropertyInfoScope)this.CurrentScope;
ODataJsonLightReaderNestedPropertyInfo nestedPropertyInfo = nestedPropertyInfoScope.ReaderNestedPropertyInfo;
Debug.Assert(nestedPropertyInfo != null);

ODataPropertyInfo propertyInfo = this.CurrentScope.Item as ODataPropertyInfo;
Debug.Assert(propertyInfo != null, "Reading Nested Property Without an ODataPropertyInfo");

ODataStreamPropertyInfo streamPropertyInfo = propertyInfo as ODataStreamPropertyInfo;
if (streamPropertyInfo != null && !String.IsNullOrEmpty(streamPropertyInfo.ContentType))
{
this.StartNestedStreamInfo(new ODataJsonLightReaderStreamInfo(streamPropertyInfo.PrimitiveTypeKind, streamPropertyInfo.ContentType));
}
else if (!nestedPropertyInfo.WithValue)
{
// It's a nested non-stream property
this.PopScope(ODataReaderState.NestedProperty);

// We are reading a next nested info.
return await this.ReadNextNestedInfoAsync()
.ConfigureAwait(false);
}
else
{
this.StartNestedStreamInfo(
new ODataJsonLightReaderStreamInfo(propertyInfo.PrimitiveTypeKind));
}

return true;
}

/// <summary>
/// Implementation of the reader logic when in state 'Stream'.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1641,6 +1641,112 @@ await SetupJsonReaderAndRunTestAsync(
Assert.Empty(verifyResourceActionStack);
}

[Fact]
public async Task ReadResourceWithNestedPropertyInfoAsync()
{
var payload = "{\"@odata.context\":\"http://tempuri.org/$metadata#Orders/$entity\"," +
"\"Id\":1," +
"\"Amount\":130," +
"\"ShippingAddress@odata.type\":\"#NS.Address\"}";

ODataResource orderResource = null;
ODataPropertyInfo shippingAddressPropertyInfo = null;

await SetupJsonReaderAndRunTestAsync(
payload,
this.orderEntitySet,
this.orderEntityType,
(jsonReader) => DoReadAsync(
jsonReader,
verifyResourceAction: (resource) =>
{
orderResource = resource;
},
verifyNestedPropertyInfoAction: (nestedPropertyInfo) =>
{
shippingAddressPropertyInfo = nestedPropertyInfo;
}));

Assert.NotNull(orderResource);
Assert.Equal("NS.Order", orderResource.TypeName);
Assert.Equal(2, orderResource.Properties.Count());

var idProperty = orderResource.Properties.ElementAt(0);
var amountProperty = orderResource.Properties.ElementAt(1);

Assert.Equal("Id", idProperty.Name);
Assert.Equal(1, idProperty.Value);
Assert.Equal("Amount", amountProperty.Name);
Assert.Equal(130M, amountProperty.Value);

Assert.NotNull(shippingAddressPropertyInfo);
Assert.Equal("ShippingAddress", shippingAddressPropertyInfo.Name);
}

[Fact]
public async Task ReadResourceWithStreamPropertyContentTypeUnspecifiedAsync()
{
var payload = "{\"@odata.context\":\"http://tempuri.org/$metadata#Customers/$entity\"," +
"\"Id\":1," +
"\"Name\":\"Sue\"," +
"\"Photo@odata.mediaEditLink\":\"http://tempuri.org/Customers(1)/Photo/Edit\"," +
"\"Photo@odata.mediaReadLink\":\"http://tempuri.org/Customers(1)/Photo\"," +
"\"Photo@odata.mediaEtag\":\"media-etag\"," +
"\"Photo\":\"AQIDBAUGBwgJAA==\"}";

ODataResource customerResource = null;
ODataPropertyInfo photoPropertyInfo = null;
byte[] photoBuffer = null;
int bytesRead = 0;

await SetupJsonReaderAndRunTestAsync(
payload,
this.customerEntitySet,
this.customerEntityType,
(jsonReader) => DoReadAsync(
jsonReader,
verifyResourceAction: (resource) =>
{
customerResource = resource;
},
verifyNestedPropertyInfoAction: (nestedPropertyInfo) =>
{
photoPropertyInfo = nestedPropertyInfo;
},
verifyBinaryStreamAction: async (binaryStream) =>
{
var maxLength = 10;
photoBuffer = new byte[maxLength];
bytesRead = await binaryStream.ReadAsync(photoBuffer, 0, maxLength);
}));

Assert.NotNull(customerResource);
Assert.Equal("NS.Customer", customerResource.TypeName);
Assert.Equal(3, customerResource.Properties.Count());

var idProperty = customerResource.Properties.ElementAt(0);
var nameProperty = customerResource.Properties.ElementAt(1);
var photoProperty = customerResource.Properties.ElementAt(2);

Assert.Equal("Id", idProperty.Name);
Assert.Equal(1, idProperty.Value);
Assert.Equal("Name", nameProperty.Name);
Assert.Equal("Sue", nameProperty.Value);
Assert.Equal("Photo", photoProperty.Name);

Assert.Equal(10, bytesRead);
Assert.NotNull(photoBuffer);
Assert.Equal(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }, photoBuffer);

Assert.NotNull(photoPropertyInfo);
var photoStreamInfoProperty = Assert.IsType<ODataStreamPropertyInfo>(photoPropertyInfo);
Assert.Equal("Photo", photoStreamInfoProperty.Name);
Assert.Equal("http://tempuri.org/Customers(1)/Photo", photoStreamInfoProperty.ReadLink.OriginalString);
Assert.Equal("http://tempuri.org/Customers(1)/Photo/Edit", photoStreamInfoProperty.EditLink.OriginalString);
Assert.Null(photoStreamInfoProperty.ContentType);
Assert.Equal("media-etag", photoStreamInfoProperty.ETag);
}

[Fact]
public async Task ReadNestedResourceSetAsync_ThrowsExceptionForInvalidItemsInResourceSet()
{
Expand Down Expand Up @@ -1714,7 +1820,7 @@ private async Task DoReadAsync(
Action<ODataDeletedResource> verifyDeletedResourceAction = null,
Action<ODataDeltaLinkBase> verifyDeltaLinkAction = null,
Action<ODataEntityReferenceLink> verifyEntityReferenceLinkAction = null,
Action<ODataItem> verifyNestedPropertyInfoAction = null,
Action<ODataPropertyInfo> verifyNestedPropertyInfoAction = null,
Action<Stream> verifyBinaryStreamAction = null,
Action<TextReader> verifyTextStreamAction = null,
Action<ODataPrimitiveValue> verifyPrimitiveAction = null)
Expand Down Expand Up @@ -1823,9 +1929,12 @@ private async Task DoReadAsync(

break;
case ODataReaderState.NestedProperty:
var nestedPropertyInfo = jsonReader.Item as ODataPropertyInfo;
Assert.NotNull(nestedPropertyInfo);

if (verifyNestedPropertyInfoAction != null)
{
verifyNestedPropertyInfoAction(jsonReader.Item);
verifyNestedPropertyInfoAction(nestedPropertyInfo);
}

break;
Expand Down

0 comments on commit 4b956cb

Please sign in to comment.