81 lines
3.8 KiB
C#
81 lines
3.8 KiB
C#
//using Knoks.Api.Client;
|
|
using Knoks.Api.Controllers.Base;
|
|
using Knoks.Core.Entities;
|
|
using Knoks.Core.Entities.Args;
|
|
using Knoks.Test.Integrations.Api.Tools;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
|
using Microsoft.AspNetCore.Mvc.Routing;
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Linq;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Reflection;
|
|
using System.Threading.Tasks;
|
|
using Xunit;
|
|
|
|
namespace Knoks.Test.Integrations.Api
|
|
{
|
|
public class ApiSpecTest : ApiTestClient
|
|
{
|
|
[Fact(DisplayName = "ApiConsistenceTest")]
|
|
void ApiConsistenceTest()
|
|
{
|
|
var controllerMethods = typeof(ApiBaseController).GetTypeInfo().Assembly.GetTypes()
|
|
.Where(type => typeof(ApiBaseController).IsAssignableFrom(type))
|
|
.Select(controller => controller.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly)
|
|
.Where(m =>
|
|
{
|
|
if (m.IsSpecialName) return false; //exclude getters and setters
|
|
|
|
var apiExplorerSettingsAttribute = m.GetCustomAttribute<ApiExplorerSettingsAttribute>();
|
|
return (apiExplorerSettingsAttribute == null || !apiExplorerSettingsAttribute.IgnoreApi);
|
|
}));
|
|
|
|
var methods = new List<MethodInfo>();
|
|
foreach (var controller in controllerMethods)
|
|
foreach (var method in controller)
|
|
methods.Add(method);
|
|
|
|
foreach (var method in methods)
|
|
{
|
|
Assert.True(method.IsDefined(typeof(HttpMethodAttribute)),
|
|
$"The '{nameof(HttpMethodAttribute)}' (GET, POST, PUT) is NOT defined for public {method.DeclaringType.Name}.{method.Name} method.");
|
|
|
|
foreach (var pi in method.GetParameters())
|
|
{
|
|
var hasBinding = pi.GetCustomAttributes().Any(a => a is IBindingSourceMetadata);
|
|
Assert.True(hasBinding,
|
|
$"Paramenter '{pi.Name}' in {method.DeclaringType.Name}.{method.Name} method has NO '{nameof(IBindingSourceMetadata)}' (Form, Body, Route, Query, Header) attributre");
|
|
|
|
if ((pi.IsDefined(typeof(FromBodyAttribute)) || pi.IsDefined(typeof(FromFormAttribute))) && !typeof(IFormFile).IsAssignableFrom(pi.ParameterType))
|
|
Assert.True(typeof(IApiArgs).IsAssignableFrom(pi.ParameterType),
|
|
$"Paramenter '{pi.Name} - {pi.ParameterType.Name}' in {method.DeclaringType.Name}.{method.Name} method is NOT implement {nameof(IApiArgs)}");
|
|
}
|
|
|
|
var methodReturnType = method.ReturnType;
|
|
var methodReturnTypeInfo = methodReturnType.GetTypeInfo();
|
|
|
|
if (methodReturnTypeInfo.IsGenericType && methodReturnTypeInfo.GetGenericTypeDefinition() == typeof(Task<>))
|
|
methodReturnType = methodReturnType.GenericTypeArguments[0];
|
|
|
|
Assert.True(typeof(Core.Entities.Interfaces.IApiResult).IsAssignableFrom(methodReturnType)
|
|
|| typeof(IActionResult).IsAssignableFrom(methodReturnType),
|
|
$"'IApiResult' or 'IActionResult' is not implemented for return type '{methodReturnType.Name}' in {method.DeclaringType}.{method.Name}");
|
|
}
|
|
}
|
|
|
|
[Fact(DisplayName = "SwaggerJson")]
|
|
async void SwaggerJson()
|
|
{
|
|
var res = await ApiClient.HttpClient.GetAsync("../spec/v1/swagger.json");
|
|
Assert.Equal(HttpStatusCode.OK, res.StatusCode);
|
|
|
|
var jObject = JsonConvert.DeserializeObject<JObject>(await res.Content.ReadAsStringAsync());
|
|
Assert.Equal("2.0", jObject["swagger"].Value<string>());
|
|
}
|
|
}
|
|
}
|