更新
更旧
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using static Microsoft.AspNetCore.OpenApi.Tests.OpenApiOperationGeneratorTests;
namespace Microsoft.AspNetCore.OpenApi.Tests;
public class OpenApiRouteHandlerBuilderExtensionTests
{
[Fact]
public void WithOpenApi_CanSetOperationInMetadata()
{
var hostEnvironment = new HostEnvironment() { ApplicationName = nameof(OpenApiOperationGeneratorTests) };
var serviceProviderIsService = new ServiceProviderIsService();
var serviceProvider = new ServiceCollection()
.AddSingleton<IServiceProviderIsService>(serviceProviderIsService)
.AddSingleton<IHostEnvironment>(hostEnvironment)
.BuildServiceProvider();
var builder = new DefaultEndpointRouteBuilder(new ApplicationBuilder(serviceProvider));
string GetString() => "Foo";
_ = builder.MapDelete("/", GetString).WithOpenApi();
var dataSource = GetBuilderEndpointDataSource(builder);
// Trigger Endpoint build by calling getter.
var endpoint = Assert.Single(dataSource.Endpoints);
var operation = endpoint.Metadata.GetMetadata<OpenApiOperation>();
Assert.NotNull(operation);
Assert.Single(operation.Responses); // Sanity check generated operation
}
[Fact]
public void WithOpenApi_CanSetOperationInMetadataWithOverride()
{
var hostEnvironment = new HostEnvironment() { ApplicationName = nameof(OpenApiOperationGeneratorTests) };
var serviceProviderIsService = new ServiceProviderIsService();
var serviceProvider = new ServiceCollection()
.AddSingleton<IServiceProviderIsService>(serviceProviderIsService)
.AddSingleton<IHostEnvironment>(hostEnvironment)
.BuildServiceProvider();
var builder = new DefaultEndpointRouteBuilder(new ApplicationBuilder(serviceProvider));
string GetString() => "Foo";
_ = builder.MapDelete("/", GetString).WithOpenApi(generatedOperation => new OpenApiOperation());
var dataSource = GetBuilderEndpointDataSource(builder);
// Trigger Endpoint build by calling getter.
var endpoint = Assert.Single(dataSource.Endpoints);
var operation = endpoint.Metadata.GetMetadata<OpenApiOperation>();
Assert.NotNull(operation);
Assert.Empty(operation.Responses);
}
[Fact]
public void WithOpenApi_CanSetSchemaInOperationWithOverride()
{
var hostEnvironment = new HostEnvironment() { ApplicationName = nameof(OpenApiOperationGeneratorTests) };
var serviceProviderIsService = new ServiceProviderIsService();
var serviceProvider = new ServiceCollection()
.AddSingleton<IServiceProviderIsService>(serviceProviderIsService)
.AddSingleton<IHostEnvironment>(hostEnvironment)
.BuildServiceProvider();
var builder = new DefaultEndpointRouteBuilder(new ApplicationBuilder(serviceProvider));
string GetString(string id) => "Foo";
_ = builder.MapDelete("/{id}", GetString)
.WithOpenApi(operation => new(operation)
{
Parameters = new List<OpenApiParameter>() { new() { Schema = new() { Type = "number" } } }
});
var dataSource = GetBuilderEndpointDataSource(builder);
// Trigger Endpoint build by calling getter.
var endpoint = Assert.Single(dataSource.Endpoints);
var operation = endpoint.Metadata.GetMetadata<OpenApiOperation>();
Assert.NotNull(operation);
var parameter = Assert.Single(operation.Parameters);
Assert.Equal("number", parameter.Schema.Type);
}

Stephen Halter
已提交
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
[Fact]
public void WithOpenApi_WorksWithMapGroup()
{
var hostEnvironment = new HostEnvironment() { ApplicationName = nameof(OpenApiOperationGeneratorTests) };
var serviceProviderIsService = new ServiceProviderIsService();
var serviceProvider = new ServiceCollection()
.AddSingleton<IServiceProviderIsService>(serviceProviderIsService)
.AddSingleton<IHostEnvironment>(hostEnvironment)
.BuildServiceProvider();
var builder = new DefaultEndpointRouteBuilder(new ApplicationBuilder(serviceProvider));
string GetString() => "Foo";
var myGroup = builder.MapGroup("/group");
myGroup.MapDelete("/a", GetString);
// The order WithOpenApi() is relative to the MapDelete() methods does not matter.
myGroup.WithOpenApi();
myGroup.MapDelete("/b", GetString);
// The RotueGroupBuilder adds a single EndpointDataSource.
var groupDataSource = Assert.Single(builder.DataSources);
Assert.Collection(groupDataSource.Endpoints,
e => Assert.NotNull(e.Metadata.GetMetadata<OpenApiOperation>()),
e => Assert.NotNull(e.Metadata.GetMetadata<OpenApiOperation>()));
}
[Fact]
public void WithOpenApi_WorksWithMapGroupAndEndpointAnnotations()
{
var hostEnvironment = new HostEnvironment() { ApplicationName = nameof(OpenApiOperationGeneratorTests) };
var serviceProviderIsService = new ServiceProviderIsService();
var serviceProvider = new ServiceCollection()
.AddSingleton<IServiceProviderIsService>(serviceProviderIsService)
.AddSingleton<IHostEnvironment>(hostEnvironment)
.BuildServiceProvider();
var builder = new DefaultEndpointRouteBuilder(new ApplicationBuilder(serviceProvider));
string GetString() => "Foo";
var myGroup = builder.MapGroup("/group");
myGroup.WithOpenApi();
myGroup.MapDelete("/a", GetString).Produces<string>(201);
// The RotueGroupBuilder adds a single EndpointDataSource.
var groupDataSource = Assert.Single(builder.DataSources);
var endpoint = Assert.Single(groupDataSource.Endpoints);
var operation = endpoint.Metadata.GetMetadata<OpenApiOperation>();
Assert.NotNull(operation);
Assert.Equal(2, operation.Responses.Count);
var defaultOperation = operation.Responses["200"];
Assert.True(defaultOperation.Content.ContainsKey("text/plain"));
var annotatedOperation = operation.Responses["201"];
// Produces doesn't special case string??
Assert.True(annotatedOperation.Content.ContainsKey("application/json"));
}
[Fact]
public void WithOpenApi_WorksWithGroupAndSpecificEndpoint()
{
var hostEnvironment = new HostEnvironment() { ApplicationName = nameof(OpenApiOperationGeneratorTests) };
var serviceProviderIsService = new ServiceProviderIsService();
var serviceProvider = new ServiceCollection()
.AddSingleton<IServiceProviderIsService>(serviceProviderIsService)
.AddSingleton<IHostEnvironment>(hostEnvironment)
.BuildServiceProvider();
var builder = new DefaultEndpointRouteBuilder(new ApplicationBuilder(serviceProvider));
string GetString() => "Foo";
var myGroup = builder.MapGroup("/group");
myGroup.WithOpenApi(o => new(o)
{
Summary = "Set from outer group"
});
myGroup.MapDelete("/a", GetString).WithOpenApi(o => new(o)
{
Summary = "Set from endpoint"
});
// The RotueGroupBuilder adds a single EndpointDataSource.
var groupDataSource = Assert.Single(builder.DataSources);
var endpoint = Assert.Single(groupDataSource.Endpoints);
var operation = endpoint.Metadata.GetMetadata<OpenApiOperation>();
Assert.NotNull(operation);
Assert.Equal("Set from outer group", operation.Summary);
}
[Fact]
public void WithOpenApi_GroupMetadataCanExamineAndExtendMoreLocalMetadata()

Stephen Halter
已提交
{
var hostEnvironment = new HostEnvironment() { ApplicationName = nameof(OpenApiOperationGeneratorTests) };
var serviceProviderIsService = new ServiceProviderIsService();
var serviceProvider = new ServiceCollection()
.AddSingleton<IServiceProviderIsService>(serviceProviderIsService)
.AddSingleton<IHostEnvironment>(hostEnvironment)
.BuildServiceProvider();
var builder = new DefaultEndpointRouteBuilder(new ApplicationBuilder(serviceProvider));
string GetString() => "Foo";
static void WithLocalSummary(RouteHandlerBuilder builder)
{
builder.WithOpenApi(operation => new(operation)

Stephen Halter
已提交
{
Summary = $"| Local Summary | 200 Status Response Content-Type: {operation.Responses["200"].Content.Keys.Single()}"

Stephen Halter
已提交
});
}
WithLocalSummary(builder.MapDelete("/root", GetString));
var outerGroup = builder.MapGroup("/outer");
var innerGroup = outerGroup.MapGroup("/inner");
WithLocalSummary(outerGroup.MapDelete("/outer-a", GetString));
// The order WithOpenApi() is relative to the MapDelete() methods does not matter.
outerGroup.WithOpenApi(operation => new(operation)

Stephen Halter
已提交
{
Summary = $"Outer Group Summary {operation.Summary}"

Stephen Halter
已提交
});
WithLocalSummary(outerGroup.MapDelete("/outer-b", GetString));
WithLocalSummary(innerGroup.MapDelete("/inner-a", GetString));
innerGroup.WithOpenApi(operation => new(operation)

Stephen Halter
已提交
{
Summary = $"| Inner Group Summary {operation.Summary}"

Stephen Halter
已提交
});
WithLocalSummary(innerGroup.MapDelete("/inner-b", GetString));
var summaries = builder.DataSources
.SelectMany(ds => ds.Endpoints)
.ToDictionary(
e => ((RouteEndpoint)e).RoutePattern.RawText,
e => e.Metadata.GetMetadata<OpenApiOperation>().Summary);
Assert.Equal(5, summaries.Count);
Assert.Equal("| Local Summary | 200 Status Response Content-Type: text/plain",

Stephen Halter
已提交
summaries["/root"]);
Assert.Equal("Outer Group Summary | Local Summary | 200 Status Response Content-Type: text/plain",
summaries["/outer/outer-a"]);
Assert.Equal("Outer Group Summary | Local Summary | 200 Status Response Content-Type: text/plain",
summaries["/outer/outer-b"]);
Assert.Equal("Outer Group Summary | Inner Group Summary | Local Summary | 200 Status Response Content-Type: text/plain",
summaries["/outer/inner/inner-a"]);
Assert.Equal("Outer Group Summary | Inner Group Summary | Local Summary | 200 Status Response Content-Type: text/plain",
summaries["/outer/inner/inner-b"]);
}
private RouteEndpointDataSource GetBuilderEndpointDataSource(IEndpointRouteBuilder endpointRouteBuilder)

Stephen Halter
已提交
return Assert.IsType<RouteEndpointDataSource>(Assert.Single(endpointRouteBuilder.DataSources));