Main changes:
- Added Azure Functions with Swagger UI and OpenAPI spec;
- Nuget packages conflicting with Swagger and the build process were removed;
- Some small changes in tests to make the build work after duplicate packages were removed and library classes got loaded with other versions and changed API methods.

Minor changes:
- duplicate/useless Nuget packages were also cleaned up in the process;
- NUnit was removed to avoid using two testing frameworks.
This commit is contained in:
Vasily Pisar 2021-01-16 02:18:58 -08:00
Родитель f7238ba6fe
Коммит fd960cd00e
12 изменённых файлов: 148 добавлений и 72 удалений

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

@ -5,13 +5,8 @@
<UserSecretsId>e2c7f1fa-5d0c-47e5-8441-1f52ec2a4998</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.15.0" />
<PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.CosmosDB" Version="3.0.7" />
<PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Storage" Version="4.0.2" />
<PackageReference Include="Microsoft.IdentityModel.Clients.ActiveDirectory" Version="5.2.8" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.11" />
<PackageReference Include="Moq" Version="4.14.1" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">

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

@ -8,11 +8,6 @@
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="Moq" Version="4.14.1" />
<PackageReference Include="MSTest.TestAdapter" Version="2.1.0" />
<PackageReference Include="MSTest.TestFramework" Version="2.1.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
</ItemGroup>
<ItemGroup>

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

@ -17,6 +17,7 @@ namespace MultiCdnApi
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
using Swagger;
public class CacheFunctions
{
@ -33,6 +34,15 @@ namespace MultiCdnApi
this.userRequestTable = userRequestTable;
}
[PostContent("cachePurgeRequest", "Cache Purge Request: a JSON describing what urls to purge",
@"{" + "\n"
+ @" ""Description"": ""Operation Description""," + "\n"
+ @" ""Hostname"": ""Purge Hostname""," + "\n"
+ @" ""Urls"": [" + "\n"
+ @" ""url1""," + "\n"
+ @" ""url2""" + "\n"
+ @" ]" + "\n"
+ @"}")]
[FunctionName("CreateCachePurgeRequestByHostname")]
public async Task<IActionResult> CreateCachePurgeRequestByHostname(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = "{partnerId:guid}/CachePurgeByHostname")]

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

@ -3,9 +3,12 @@
* Licensed under the MIT License.
* ----------------------------------------------------------------------- */
using AzureFunctions.Extensions.Swashbuckle;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;
using MultiCdnApi;
using MultiCdnApi.Swagger;
using CachePurgeLibrary;
using CdnLibrary;
@ -16,9 +19,14 @@ namespace MultiCdnApi
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddSingleton<IRequestTable<Partner>>((s) => { return new PartnerTable(); });
builder.Services.AddSingleton<IRequestTable<UserRequest>>((s) => { return new UserRequestTable(); });
builder.Services.AddSingleton<IPartnerRequestTableManager<CDN>>((s) => { return new PartnerRequestTableManager(); });
builder.Services.AddSingleton<IRequestTable<Partner>>(s => new PartnerTable());
builder.Services.AddSingleton<IRequestTable<UserRequest>>(s => new UserRequestTable());
builder.Services.AddSingleton<IPartnerRequestTableManager<CDN>>(s => new PartnerRequestTableManager());
builder.AddSwashBuckle(Assembly.GetExecutingAssembly(),
options => {
options.ConfigureSwaggerGen = genOptions => genOptions.OperationFilter<PostContentFilter>();
});
}
}
}

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

@ -0,0 +1,35 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace MultiCdnApi
{
using System.Net.Http;
using System.Threading.Tasks;
using AzureFunctions.Extensions.Swashbuckle;
using AzureFunctions.Extensions.Swashbuckle.Attribute;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
public static class SwaggerFunctions
{
[SwaggerIgnore]
[FunctionName("SwaggerJson")]
public static Task<HttpResponseMessage> SwaggerJson(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "swagger/json")]
HttpRequestMessage req,
[SwashBuckleClient] ISwashBuckleClient swashBuckleClient)
{
return Task.FromResult(swashBuckleClient.CreateSwaggerDocumentResponse(req));
}
[SwaggerIgnore]
[FunctionName("SwaggerUi")]
public static Task<HttpResponseMessage> SwaggerUi(
[HttpTrigger(AuthorizationLevel.Function, "get", Route = "swagger/ui")]
HttpRequestMessage req,
[SwashBuckleClient] ISwashBuckleClient swashBuckleClient)
{
return Task.FromResult(swashBuckleClient.CreateSwaggerUIResponse(req, "swagger/json"));
}
}
}

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

@ -4,10 +4,9 @@
<AzureFunctionsVersion>v3</AzureFunctionsVersion>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Azure.Identity" Version="1.3.0" />
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.15.0" />
<PackageReference Include="Microsoft.Azure.Functions.Extensions" Version="1.1.0" />
<PackageReference Include="Microsoft.NET.Sdk.Functions" Version="3.0.11" />
<PackageReference Include="AzureExtensions.Swashbuckle" Version="3.2.2" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">

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

@ -0,0 +1,24 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace MultiCdnApi.Swagger
{
using System;
[AttributeUsage(AttributeTargets.Method)]
public class PostContentAttribute : Attribute
{
public PostContentAttribute(string name, string description, string example = "")
{
this.Name = name;
this.Description = description;
this.Example = example;
}
public string Name { get; }
public string Description { get; set; }
public string Example { get; set; }
}
}

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

@ -0,0 +1,31 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
namespace MultiCdnApi.Swagger
{
using System.Linq;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
public class PostContentFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var postContentAttribute = (PostContentAttribute) context.MethodInfo.GetCustomAttributes(true)
.SingleOrDefault(attribute => attribute is PostContentAttribute);
if (postContentAttribute != null)
{
operation.RequestBody = new OpenApiRequestBody();
operation.RequestBody.Content.Add(postContentAttribute.Name,
new OpenApiMediaType {
Schema = new OpenApiSchema {
Type = "multipart/form-data",
Description = postContentAttribute.Description,
Example = new OpenApiString(postContentAttribute.Example)
}
});
}
}
}
}

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

@ -14,7 +14,6 @@ namespace MultiCdnApi
using CdnLibrary;
using CdnLibrary_Test;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Internal;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.VisualStudio.TestTools.UnitTesting;
@ -76,12 +75,10 @@ namespace MultiCdnApi
[TestMethod]
public async Task CreateCachePurgeRequestByHostname_Fail()
{
var defaultHttpRequest = new DefaultHttpRequest(new DefaultHttpContext())
{
Body = new MemoryStream(Encoding.UTF8.GetBytes(TestHostname))
};
var malformedCachePurgeRequest = new DefaultHttpContext().Request;
malformedCachePurgeRequest.Body = new MemoryStream(Encoding.UTF8.GetBytes(TestHostname));
var result = await cacheFunctions.CreateCachePurgeRequestByHostname(
defaultHttpRequest,
malformedCachePurgeRequest,
null,
Mock.Of<ILogger>());
Assert.IsTrue(result is JsonResult);
@ -123,17 +120,15 @@ namespace MultiCdnApi
private async Task<string> CallPurgeFunctionWithDefaultParameters()
{
var defaultHttpRequest = new DefaultHttpRequest(new DefaultHttpContext())
{
Body = new MemoryStream(Encoding.UTF8.GetBytes("{" +
$@"""Description"": ""{TestDescription}""," +
$@"""TicketId"": ""{TestTicketId}""," +
$@"""Hostname"": ""{TestHostname}""," +
$@"""Urls"": [""{TestHostname}""]" +
"}"))
};
var cachePurgeRequest = new DefaultHttpContext().Request;
cachePurgeRequest.Body = new MemoryStream(Encoding.UTF8.GetBytes("{" +
$@"""Description"": ""{TestDescription}""," +
$@"""TicketId"": ""{TestTicketId}""," +
$@"""Hostname"": ""{TestHostname}""," +
$@"""Urls"": [""{TestHostname}""]" +
"}"));
var result = await cacheFunctions.CreateCachePurgeRequestByHostname(
defaultHttpRequest,
cachePurgeRequest,
testPartnerId,
Mock.Of<ILogger>());
Assert.AreEqual(typeof(StringResult), result.GetType());
@ -143,9 +138,9 @@ namespace MultiCdnApi
private async Task<UserRequestStatusResult> CallPurgeStatus(string userRequestId)
{
var defaultHttpRequest = new DefaultHttpRequest(new DefaultHttpContext());
var emptyRequest = new DefaultHttpContext().Request;
var statusResponse = await cacheFunctions.CachePurgeRequestByHostnameStatus(
defaultHttpRequest,
emptyRequest,
testPartnerId,
userRequestId,
Mock.Of<ILogger>());

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

@ -13,7 +13,6 @@ namespace MultiCdnApi
using CdnLibrary;
using CdnLibrary_Test;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Internal;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;
@ -57,13 +56,9 @@ namespace MultiCdnApi
[TestMethod]
public void TestCreatePartner_Fail()
{
var createPartnerResponse = partnerFunctions.CreatePartner(new DefaultHttpRequest(new DefaultHttpContext())
{
Query = new QueryCollection(new Dictionary<string, StringValues>
{
["Test"] = "Bad"
}
)}, null).Result;
var malformedCreatePartnerRequest = new DefaultHttpContext().Request;
malformedCreatePartnerRequest.Query = new QueryCollection(new Dictionary<string, StringValues> {["Test"] = "Bad"});
var createPartnerResponse = partnerFunctions.CreatePartner(malformedCreatePartnerRequest, null).Result;
Assert.AreEqual(typeof(ExceptionResult), createPartnerResponse.GetType());
}
@ -109,13 +104,10 @@ namespace MultiCdnApi
Assert.AreEqual(typeof(StringResult), testPartnerResponse.GetType());
var partnerId = ((StringResult) testPartnerResponse).Value.ToString();
var partnerResult = partnerFunctions.GetPartner(new DefaultHttpRequest(new DefaultHttpContext())
{
Query = new QueryCollection(new Dictionary<string, StringValues>
{
["partnerId"] = partnerId
})
}, null).Result;
var getPartnerRequest = new DefaultHttpContext().Request;
getPartnerRequest.Query = new QueryCollection(new Dictionary<string, StringValues> {["partnerId"] = partnerId});
var partnerResult = partnerFunctions.GetPartner(getPartnerRequest, null).Result;
Assert.AreEqual(typeof(PartnerResult), partnerResult.GetType());
@ -126,10 +118,7 @@ namespace MultiCdnApi
[TestMethod]
public void TestGetPartner_Fail()
{
var partnerResult = partnerFunctions.GetPartner(new DefaultHttpRequest(new DefaultHttpContext())
{
Query = new QueryCollection()
}, null).Result;
var partnerResult = partnerFunctions.GetPartner(new DefaultHttpContext().Request, null).Result;
Assert.AreEqual(typeof(StringResult), partnerResult.GetType());
}
@ -140,7 +129,7 @@ namespace MultiCdnApi
this.partners.Clear();
CreateTestPartner();
var partnersResponse =
partnerFunctions.ListPartners(new DefaultHttpRequest(new DefaultHttpContext()), null).Result;
partnerFunctions.ListPartners(new DefaultHttpContext().Request, null).Result;
Assert.AreEqual(typeof(EnumerableResult<PartnerResult>), partnersResponse.GetType());
var partnersValue = ((EnumerableResult<PartnerResult>) partnersResponse).Value;
@ -154,16 +143,16 @@ namespace MultiCdnApi
private IActionResult CreateTestPartner()
{
var createPartnerResponse = partnerFunctions.CreatePartner(new DefaultHttpRequest(new DefaultHttpContext())
{
Body = new MemoryStream(Encoding.UTF8.GetBytes("{" +
$@"""Tenant"": ""{TenantId}""," +
$@"""Name"": ""{Name}""," +
$@"""ContactEmail"": ""{DriContact}""," +
$@"""NotifyContactEmail"": ""{NotifyContact}""," +
$@"""CdnConfiguration"": {{""Hostname"": ""{TestHostname}"", ""CdnWithCredentials"": {{""AFD"":"""", ""Akamai"":""""}}}}" +
"}"))
}, Mock.Of<ILogger>());
var createPartnerRequest = new DefaultHttpContext().Request;
createPartnerRequest.Body = new MemoryStream(Encoding.UTF8.GetBytes("{" +
$@"""Tenant"": ""{TenantId}""," +
$@"""Name"": ""{Name}""," +
$@"""ContactEmail"": ""{DriContact}""," +
$@"""NotifyContactEmail"": ""{NotifyContact}""," +
$@"""CdnConfiguration"": {{""Hostname"": ""{TestHostname}"", ""CdnWithCredentials"": {{""AFD"":"""", ""Akamai"":""""}}}}" +
"}"));
var createPartnerResponse = partnerFunctions.CreatePartner(createPartnerRequest, Mock.Of<ILogger>());
return createPartnerResponse.Result;
}
}

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

@ -10,14 +10,14 @@ namespace MultiCdnApi
using CachePurgeLibrary;
using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using NUnit.Framework;
public class FunctionsStartup_Test
{
private IFunctionsHostBuilder functionsHostBuilder;
[SetUp]
[TestInitialize]
public void Setup()
{
var multiCdnFunctionsStartup = new Startup();
@ -25,14 +25,14 @@ namespace MultiCdnApi
multiCdnFunctionsStartup.Configure(functionsHostBuilder);
}
[Test]
[TestMethod]
public void TestSetupPartnerTable()
{
var partnerTableService = FindServiceByType(functionsHostBuilder, typeof(IRequestTable<Partner>));
Assert.IsNotNull(partnerTableService);
}
[Test]
[TestMethod]
public void TestSetupUserRequestTable()
{
var userRequestTable = FindServiceByType(functionsHostBuilder, typeof(IRequestTable<UserRequest>));

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

@ -8,11 +8,6 @@
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="Moq" Version="4.14.1" />
<PackageReference Include="MSTest.TestAdapter" Version="2.1.0" />
<PackageReference Include="MSTest.TestFramework" Version="2.1.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
</ItemGroup>
<ItemGroup>