Fixed null nextLinkName issue. Fixed paging tests to cover proper scenarios. Fixed null nextLinkName test.

This commit is contained in:
Michael Yanni 2020-04-29 10:49:43 -07:00
Родитель 7a2f6d5d48
Коммит 273870fa14
7 изменённых файлов: 55 добавлений и 154 удалений

Просмотреть файл

@ -244,7 +244,6 @@ namespace AutoRest.CSharp.V3.Generation.Writers
var pageType = pagingMethod.ItemType;
CSharpType responseType = async ? new CSharpType(typeof(AsyncPageable<>), pageType) : new CSharpType(typeof(Pageable<>), pageType);
var parameters = pagingMethod.Method.Parameters;
var nextPageParameters = pagingMethod.NextPageMethod.Parameters;
writer.WriteXmlDocumentationSummary(pagingMethod.Method.Description);
@ -286,17 +285,23 @@ namespace AutoRest.CSharp.V3.Generation.Writers
writer.Line($"return {typeof(Page)}.FromValues(response.Value.{pagingMethod.ItemName}, {continuationTokenText}, response.GetRawResponse());");
}
using (writer.Scope($"{asyncText} {funcType} NextPageFunc({typeof(string)} nextLink, {nullableInt} pageSizeHint)"))
var nextPageFunctionName = "null";
if (pagingMethod.NextPageMethod != null)
{
writer.Append($"var response = {awaitText} RestClient.{CreateMethodName(pagingMethod.NextPageMethod.Name, async)}(");
foreach (Parameter parameter in nextPageParameters)
nextPageFunctionName = "NextPageFunc";
var nextPageParameters = pagingMethod.NextPageMethod.Parameters;
using (writer.Scope($"{asyncText} {funcType} {nextPageFunctionName}({typeof(string)} nextLink, {nullableInt} pageSizeHint)"))
{
writer.Append($"{parameter.Name}, ");
writer.Append($"var response = {awaitText} RestClient.{CreateMethodName(pagingMethod.NextPageMethod.Name, async)}(");
foreach (Parameter parameter in nextPageParameters)
{
writer.Append($"{parameter.Name}, ");
}
writer.Line($"cancellationToken){configureAwaitText};");
writer.Line($"return {typeof(Page)}.FromValues(response.Value.{pagingMethod.ItemName}, {continuationTokenText}, response.GetRawResponse());");
}
writer.Line($"cancellationToken){configureAwaitText};");
writer.Line($"return {typeof(Page)}.FromValues(response.Value.{pagingMethod.ItemName}, {continuationTokenText}, response.GetRawResponse());");
}
writer.Line($"return {typeof(PageableHelpers)}.Create{(async ? "Async" : string.Empty)}Enumerable(FirstPageFunc, NextPageFunc);");
writer.Line($"return {typeof(PageableHelpers)}.Create{(async ? "Async" : string.Empty)}Enumerable(FirstPageFunc, {nextPageFunctionName});");
}
writer.Line();
}

Просмотреть файл

@ -106,10 +106,11 @@ namespace AutoRest.CSharp.V3.Output.Builders
next = nextOperationMethod.Method;
}
// If there is no operationName or we didn't find an existing operation, we use the original method to construct the nextPageMethod.
RestClientMethod nextPageMethod = next ?? BuildNextPageMethod(method);
// Only add the method if it didn't previously exist
if (next == null)
RestClientMethod? nextPageMethod = next;
// Only create and add a method if it didn't previously exist and we have a NextLinkName
if (next == null && paging.NextLinkName != null)
{
nextPageMethod = BuildNextPageMethod(method);
nextPageMethods.Add(nextPageMethod);
}
@ -465,7 +466,7 @@ namespace AutoRest.CSharp.V3.Output.Builders
method.Diagnostics);
}
private PagingInfo GetPagingInfo(RestClientMethod method, RestClientMethod nextPageMethod, Paging paging, ObjectType type)
private PagingInfo GetPagingInfo(RestClientMethod method, RestClientMethod? nextPageMethod, Paging paging, ObjectType type)
{
string? nextLinkName = paging.NextLinkName;
string itemName = paging.ItemName ?? "value";

Просмотреть файл

@ -8,7 +8,7 @@ namespace AutoRest.CSharp.V3.Output.Models.Requests
{
internal class PagingInfo
{
public PagingInfo(RestClientMethod method, RestClientMethod nextPageMethod, string name, string? nextLinkName, string itemName, CSharpType itemType)
public PagingInfo(RestClientMethod method, RestClientMethod? nextPageMethod, string name, string? nextLinkName, string itemName, CSharpType itemType)
{
Method = method;
NextPageMethod = nextPageMethod;
@ -20,7 +20,7 @@ namespace AutoRest.CSharp.V3.Output.Models.Requests
public string Name { get; }
public RestClientMethod Method { get; }
public RestClientMethod NextPageMethod { get; }
public RestClientMethod? NextPageMethod { get; }
public string? NextLinkName { get; }
public string ItemName { get; }
public CSharpType ItemType { get; }

Просмотреть файл

@ -11,14 +11,18 @@ namespace Azure.Core
{
internal static class PageableHelpers
{
public static Pageable<T> CreateEnumerable<T>(Func<int?, Page<T>> firstPageFunc, Func<string?, int?, Page<T>> nextPageFunc, int? pageSize = default) where T : notnull
public static Pageable<T> CreateEnumerable<T>(Func<int?, Page<T>> firstPageFunc, Func<string?, int?, Page<T>>? nextPageFunc, int? pageSize = default) where T : notnull
{
return new FuncPageable<T>((continuationToken, pageSizeHint) => firstPageFunc(pageSizeHint), (continuationToken, pageSizeHint) => nextPageFunc(continuationToken, pageSizeHint), pageSize);
PageFunc<T> first = (continuationToken, pageSizeHint) => firstPageFunc(pageSizeHint);
PageFunc<T>? next = nextPageFunc != null ? new PageFunc<T>(nextPageFunc) : null;
return new FuncPageable<T>(first, next, pageSize);
}
public static AsyncPageable<T> CreateAsyncEnumerable<T>(Func<int?, Task<Page<T>>> firstPageFunc, Func<string?, int?, Task<Page<T>>> nextPageFunc, int? pageSize = default) where T : notnull
public static AsyncPageable<T> CreateAsyncEnumerable<T>(Func<int?, Task<Page<T>>> firstPageFunc, Func<string?, int?, Task<Page<T>>>? nextPageFunc, int? pageSize = default) where T : notnull
{
return new FuncAsyncPageable<T>((continuationToken, pageSizeHint) => firstPageFunc(pageSizeHint), (continuationToken, pageSizeHint) => nextPageFunc(continuationToken, pageSizeHint), pageSize);
AsyncPageFunc<T> first = (continuationToken, pageSizeHint) => firstPageFunc(pageSizeHint);
AsyncPageFunc<T>? next = nextPageFunc != null ? new AsyncPageFunc<T>(nextPageFunc) : null;
return new FuncAsyncPageable<T>(first, next, pageSize);
}
internal delegate Task<Page<T>> AsyncPageFunc<T>(string? continuationToken = default, int? pageSizeHint = default);
@ -27,10 +31,10 @@ namespace Azure.Core
internal class FuncAsyncPageable<T> : AsyncPageable<T> where T : notnull
{
private readonly AsyncPageFunc<T> _firstPageFunc;
private readonly AsyncPageFunc<T> _nextPageFunc;
private readonly AsyncPageFunc<T>? _nextPageFunc;
private readonly int? _defaultPageSize;
public FuncAsyncPageable(AsyncPageFunc<T> firstPageFunc, AsyncPageFunc<T> nextPageFunc, int? defaultPageSize = default)
public FuncAsyncPageable(AsyncPageFunc<T> firstPageFunc, AsyncPageFunc<T>? nextPageFunc, int? defaultPageSize = default)
{
_firstPageFunc = firstPageFunc;
_nextPageFunc = nextPageFunc;
@ -39,7 +43,7 @@ namespace Azure.Core
public override async IAsyncEnumerable<Page<T>> AsPages(string? continuationToken = default, int? pageSizeHint = default)
{
AsyncPageFunc<T> pageFunc = _firstPageFunc;
AsyncPageFunc<T>? pageFunc = _firstPageFunc;
int? pageSize = pageSizeHint ?? _defaultPageSize;
do
{
@ -47,17 +51,17 @@ namespace Azure.Core
yield return pageResponse;
continuationToken = pageResponse.ContinuationToken;
pageFunc = _nextPageFunc;
} while (!string.IsNullOrEmpty(continuationToken));
} while (!string.IsNullOrEmpty(continuationToken) && pageFunc != null);
}
}
internal class FuncPageable<T> : Pageable<T> where T : notnull
{
private readonly PageFunc<T> _firstPageFunc;
private readonly PageFunc<T> _nextPageFunc;
private readonly PageFunc<T>? _nextPageFunc;
private readonly int? _defaultPageSize;
public FuncPageable(PageFunc<T> firstPageFunc, PageFunc<T> nextPageFunc, int? defaultPageSize = default)
public FuncPageable(PageFunc<T> firstPageFunc, PageFunc<T>? nextPageFunc, int? defaultPageSize = default)
{
_firstPageFunc = firstPageFunc;
_nextPageFunc = nextPageFunc;
@ -66,7 +70,7 @@ namespace Azure.Core
public override IEnumerable<Page<T>> AsPages(string? continuationToken = default, int? pageSizeHint = default)
{
PageFunc<T> pageFunc = _firstPageFunc;
PageFunc<T>? pageFunc = _firstPageFunc;
int? pageSize = pageSizeHint ?? _defaultPageSize;
do
{
@ -74,7 +78,7 @@ namespace Azure.Core
yield return pageResponse;
continuationToken = pageResponse.ContinuationToken;
pageFunc = _nextPageFunc;
} while (!string.IsNullOrEmpty(continuationToken));
} while (!string.IsNullOrEmpty(continuationToken) && pageFunc != null);
}
}
}

Просмотреть файл

@ -75,7 +75,7 @@ namespace AutoRest.TestServer.Tests
}
}
Assert.AreEqual(2, id);
}, true);
});
[Test]
[IgnoreOnTestServer(TestServerVersion.V2, "Request not matched.")]
@ -134,7 +134,7 @@ namespace AutoRest.TestServer.Tests
}
}
Assert.AreEqual(2, id);
}, true);
});
[Test]
[IgnoreOnTestServer(TestServerVersion.V2, "Request not matched.")]
@ -193,7 +193,7 @@ namespace AutoRest.TestServer.Tests
product = "product";
}
Assert.AreEqual(10, id);
}, true);
});
[Test]
[IgnoreOnTestServer(TestServerVersion.V2, "Refused connection.")]
@ -254,7 +254,7 @@ namespace AutoRest.TestServer.Tests
product = "product";
}
Assert.AreEqual(10, id);
}, true);
});
[Test]
[IgnoreOnTestServer(TestServerVersion.V2, "Refused connection.")]
@ -313,7 +313,7 @@ namespace AutoRest.TestServer.Tests
}
}
Assert.AreEqual(2, id);
}, true);
});
[Test]
public Task PagingMultipleFailure() => Test(async (host, pipeline) =>
@ -355,7 +355,7 @@ namespace AutoRest.TestServer.Tests
}
});
Assert.AreEqual(2, id);
}, ignoreScenario: true, useSimplePipeline: true);
}, useSimplePipeline: true);
[Test]
public Task PagingMultipleFailureUri() => Test(async (host, pipeline) =>
@ -396,7 +396,7 @@ namespace AutoRest.TestServer.Tests
}
});
Assert.AreEqual(2, id);
}, true);
});
[Test]
[Ignore("Needs LRO for paging: https://github.com/Azure/autorest.csharp/issues/450")]
@ -483,7 +483,7 @@ namespace AutoRest.TestServer.Tests
id++;
}
Assert.AreEqual(10, pageNumber);
}, true);
});
[Test]
[IgnoreOnTestServer(TestServerVersion.V2, "Retry times out.")]
@ -544,7 +544,7 @@ namespace AutoRest.TestServer.Tests
product = "product";
}
Assert.AreEqual(10, id);
}, true);
});
[Test]
[IgnoreOnTestServer(TestServerVersion.V2, "Retry times out.")]
@ -611,7 +611,7 @@ namespace AutoRest.TestServer.Tests
product = "product";
}
Assert.AreEqual(10, id);
}, true);
});
[Test]
[IgnoreOnTestServer(TestServerVersion.V2, "Request not matched.")]
@ -623,7 +623,7 @@ namespace AutoRest.TestServer.Tests
Assert.AreEqual("Product", resultPage.Values.First().Properties.Name);
Assert.IsNull(resultPage.ContinuationToken);
var pageableAsync = new PagingClient(ClientDiagnostics, pipeline, host).GetNoItemNamePagesAsync();
var pageableAsync = new PagingClient(ClientDiagnostics, pipeline, host).GetNullNextLinkNamePagesAsync();
await foreach (var page in pageableAsync.AsPages())
{
Assert.AreEqual(1, page.Values.First().Properties.Id);
@ -631,14 +631,14 @@ namespace AutoRest.TestServer.Tests
Assert.IsNull(page.ContinuationToken);
}
var pageable = new PagingClient(ClientDiagnostics, pipeline, host).GetNoItemNamePages();
var pageable = new PagingClient(ClientDiagnostics, pipeline, host).GetNullNextLinkNamePages();
foreach (var page in pageable.AsPages())
{
Assert.AreEqual(1, page.Values.First().Properties.Id);
Assert.AreEqual("Product", page.Values.First().Properties.Name);
Assert.IsNull(page.ContinuationToken);
}
}, true);
});
[Test]
[IgnoreOnTestServer(TestServerVersion.V2, "Request not matched.")]
@ -665,7 +665,7 @@ namespace AutoRest.TestServer.Tests
Assert.AreEqual("Product", page.Values.First().Properties.Name);
Assert.IsNull(page.ContinuationToken);
}
}, true);
});
[Test]
[IgnoreOnTestServer(TestServerVersion.V2, "Refused connection.")]
@ -726,7 +726,7 @@ namespace AutoRest.TestServer.Tests
product = "product";
}
Assert.AreEqual(10, id);
}, true);
});
[Test]
public Task PagingSingle() => Test(async (host, pipeline) =>
@ -752,7 +752,7 @@ namespace AutoRest.TestServer.Tests
Assert.AreEqual("Product", page.Values.First().Properties.Name);
Assert.IsNull(page.ContinuationToken);
}
}, true);
});
[Test]
public Task PagingSingleFailure() => Test((host, pipeline) =>
@ -764,7 +764,6 @@ namespace AutoRest.TestServer.Tests
var pageable = new PagingClient(ClientDiagnostics, pipeline, host).GetSinglePagesFailure();
Assert.Throws<RequestFailedException>(() => { foreach (var page in pageable.AsPages()) { } });
}, true);
});
}
}

Просмотреть файл

@ -77,12 +77,7 @@ namespace paging
var response = await RestClient.GetNullNextLinkNamePagesAsync(cancellationToken).ConfigureAwait(false);
return Page.FromValues(response.Value.Values, null, response.GetRawResponse());
}
async Task<Page<Product>> NextPageFunc(string nextLink, int? pageSizeHint)
{
var response = await RestClient.GetNullNextLinkNamePagesNextPageAsync(nextLink, cancellationToken).ConfigureAwait(false);
return Page.FromValues(response.Value.Values, null, response.GetRawResponse());
}
return PageableHelpers.CreateAsyncEnumerable(FirstPageFunc, NextPageFunc);
return PageableHelpers.CreateAsyncEnumerable(FirstPageFunc, null);
}
/// <summary> A paging operation that must ignore any kind of nextLink, and stop after page 1. </summary>
@ -94,12 +89,7 @@ namespace paging
var response = RestClient.GetNullNextLinkNamePages(cancellationToken);
return Page.FromValues(response.Value.Values, null, response.GetRawResponse());
}
Page<Product> NextPageFunc(string nextLink, int? pageSizeHint)
{
var response = RestClient.GetNullNextLinkNamePagesNextPage(nextLink, cancellationToken);
return Page.FromValues(response.Value.Values, null, response.GetRawResponse());
}
return PageableHelpers.CreateEnumerable(FirstPageFunc, NextPageFunc);
return PageableHelpers.CreateEnumerable(FirstPageFunc, null);
}
/// <summary> A paging operation that finishes on the first call without a nextlink. </summary>

Просмотреть файл

@ -1837,104 +1837,6 @@ namespace paging
}
}
internal HttpMessage CreateGetNullNextLinkNamePagesNextPageRequest(string nextLink)
{
var message = _pipeline.CreateMessage();
var request = message.Request;
request.Method = RequestMethod.Get;
var uri = new RawRequestUriBuilder();
uri.AppendRaw(host, false);
uri.AppendRawNextLink(nextLink, false);
request.Uri = uri;
return message;
}
/// <summary> A paging operation that must ignore any kind of nextLink, and stop after page 1. </summary>
/// <param name="nextLink"> The URL to the next page of results. </param>
/// <param name="cancellationToken"> The cancellation token to use. </param>
public async ValueTask<Response<ProductResult>> GetNullNextLinkNamePagesNextPageAsync(string nextLink, CancellationToken cancellationToken = default)
{
if (nextLink == null)
{
throw new ArgumentNullException(nameof(nextLink));
}
using var scope = _clientDiagnostics.CreateScope("PagingClient.GetNullNextLinkNamePages");
scope.Start();
try
{
using var message = CreateGetNullNextLinkNamePagesNextPageRequest(nextLink);
await _pipeline.SendAsync(message, cancellationToken).ConfigureAwait(false);
switch (message.Response.Status)
{
case 200:
{
ProductResult value = default;
using var document = await JsonDocument.ParseAsync(message.Response.ContentStream, default, cancellationToken).ConfigureAwait(false);
if (document.RootElement.ValueKind == JsonValueKind.Null)
{
value = null;
}
else
{
value = ProductResult.DeserializeProductResult(document.RootElement);
}
return Response.FromValue(value, message.Response);
}
default:
throw await _clientDiagnostics.CreateRequestFailedExceptionAsync(message.Response).ConfigureAwait(false);
}
}
catch (Exception e)
{
scope.Failed(e);
throw;
}
}
/// <summary> A paging operation that must ignore any kind of nextLink, and stop after page 1. </summary>
/// <param name="nextLink"> The URL to the next page of results. </param>
/// <param name="cancellationToken"> The cancellation token to use. </param>
public Response<ProductResult> GetNullNextLinkNamePagesNextPage(string nextLink, CancellationToken cancellationToken = default)
{
if (nextLink == null)
{
throw new ArgumentNullException(nameof(nextLink));
}
using var scope = _clientDiagnostics.CreateScope("PagingClient.GetNullNextLinkNamePages");
scope.Start();
try
{
using var message = CreateGetNullNextLinkNamePagesNextPageRequest(nextLink);
_pipeline.Send(message, cancellationToken);
switch (message.Response.Status)
{
case 200:
{
ProductResult value = default;
using var document = JsonDocument.Parse(message.Response.ContentStream);
if (document.RootElement.ValueKind == JsonValueKind.Null)
{
value = null;
}
else
{
value = ProductResult.DeserializeProductResult(document.RootElement);
}
return Response.FromValue(value, message.Response);
}
default:
throw _clientDiagnostics.CreateRequestFailedException(message.Response);
}
}
catch (Exception e)
{
scope.Failed(e);
throw;
}
}
internal HttpMessage CreateGetSinglePagesNextPageRequest(string nextLink)
{
var message = _pipeline.CreateMessage();