Skip to content

Commit

Permalink
Merge pull request #116 from SedativeEffect/feature/C-SHARP-196-all-e…
Browse files Browse the repository at this point in the history
…ndpoints

feat(autodoc): show all endpoints
  • Loading branch information
Rast1234 authored Aug 27, 2024
2 parents 2c0dc73 + 64acd86 commit a7e1827
Show file tree
Hide file tree
Showing 2 changed files with 110 additions and 10 deletions.
40 changes: 36 additions & 4 deletions src/Tochka.JsonRpc.OpenRpc/Services/OpenRpcDocumentGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public Models.OpenRpc Generate(OpenRpcInfo info, string documentName, Uri host)
var tags = GetControllersTags();
return new(info)
{
Servers = GetServers(host, serverOptions.RoutePrefix.Value),
Servers = GetServers(host),
Methods = GetMethods(documentName, host, tags),
Components = new()
{
Expand All @@ -60,6 +60,33 @@ public Models.OpenRpc Generate(OpenRpcInfo info, string documentName, Uri host)
};
}

// internal virtual for mocking in tests
internal virtual List<OpenRpcServer> GetServers(Uri host)
{
var apiDescriptions = apiDescriptionsProvider.ApiDescriptionGroups.Items
.SelectMany(static g => g.Items)
.Where(d => !openRpcOptions.IgnoreObsoleteActions || !IsObsoleteTransitive(d))
.Where(static d => d.ActionDescriptor.EndpointMetadata.Any(static m => m is JsonRpcControllerAttribute))
.ToArray();

List<OpenRpcServer> servers = [];
foreach (var apiDescription in apiDescriptions)
{
var actionDescriptor = apiDescription.ActionDescriptor as ControllerActionDescriptor;
var controllerSummary = actionDescriptor?.ControllerTypeInfo.GetXmlDocsSummary();
var route = apiDescription.RelativePath?.Split('#').First();

if (string.IsNullOrWhiteSpace(route) || $"/{route}" == serverOptions.RoutePrefix)
{
continue;
}

servers.AddRange(GetServers(host, route, string.IsNullOrEmpty(controllerSummary) ? null : controllerSummary));
}

return servers;
}

internal virtual Dictionary<string, OpenRpcTag> GetControllersTags()
{
var tags = apiDescriptionsProvider.ApiDescriptionGroups.Items
Expand All @@ -72,10 +99,13 @@ internal virtual Dictionary<string, OpenRpcTag> GetControllersTags()
}

// internal virtual for mocking in tests
internal virtual List<OpenRpcServer> GetServers(Uri host, string? route)
internal virtual List<OpenRpcServer> GetServers(Uri host, string? route, string? serverSummary)
{
var uriBuilder = new UriBuilder(host) { Path = route };
var server = new OpenRpcServer(openRpcOptions.DefaultServerName, uriBuilder.Uri);
var server = new OpenRpcServer(openRpcOptions.DefaultServerName, uriBuilder.Uri)
{
Summary = serverSummary
};

return new List<OpenRpcServer>
{
Expand Down Expand Up @@ -178,13 +208,15 @@ internal virtual OpenRpcContentDescriptor GetResultContentDescriptor(ApiDescript
internal virtual List<OpenRpcServer>? GetMethodServers(ApiDescription apiDescription, Uri host)
{
var route = apiDescription.RelativePath?.Split('#').First();
var actionDescriptor = apiDescription.ActionDescriptor as ControllerActionDescriptor;
var controllerSummary = actionDescriptor?.ControllerTypeInfo.GetXmlDocsSummary();

if (string.IsNullOrWhiteSpace(route) || $"/{route}" == serverOptions.RoutePrefix)
{
return null;
}

return GetServers(host, route);
return GetServers(host, route, string.IsNullOrEmpty(controllerSummary) ? null : controllerSummary);
}

// internal virtual for mocking in tests
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text.Json;
using FluentAssertions;
using JetBrains.Annotations;
Expand All @@ -20,6 +21,7 @@
using Tochka.JsonRpc.Common.Models.Response;
using Tochka.JsonRpc.OpenRpc.Models;
using Tochka.JsonRpc.OpenRpc.Services;
using Tochka.JsonRpc.Server;
using Tochka.JsonRpc.Server.Attributes;
using Tochka.JsonRpc.Server.Metadata;
using Tochka.JsonRpc.Server.Serialization;
Expand Down Expand Up @@ -64,7 +66,15 @@ public void Generate_UseArgsAndInternalMethods()
var methods = new List<OpenRpcMethod>();
var schemas = new Dictionary<string, JsonSchema>();
var tags = new Dictionary<string, OpenRpcTag>();
documentGeneratorMock.Setup(g => g.GetServers(host, serverOptions.RoutePrefix))
var apiDescription = GetValidDescription(controllerName: "ValidJsonRpc");
apiDescriptionsProviderMock.Setup(static p => p.ApiDescriptionGroups)
.Returns(new ApiDescriptionGroupCollection(new List<ApiDescriptionGroup>
{
new(null, new[] { apiDescription }),
},
0))
.Verifiable();
documentGeneratorMock.Setup(g => g.GetServers(host, serverOptions.RoutePrefix, null))
.Returns(servers)
.Verifiable();
documentGeneratorMock.Setup(g => g.GetMethods(DocumentName, host, tags))
Expand All @@ -90,7 +100,7 @@ public void Generate_UseArgsAndInternalMethods()
}
};
result.Should().BeEquivalentTo(expected);
documentGeneratorMock.Verify();
apiDescriptionsProviderMock.Verify();
}

[Test]
Expand Down Expand Up @@ -121,6 +131,55 @@ public void GetControllersTagsReturnsTagsWithControllerName()
documentGeneratorMock.Verify();
}

[Test]
public void GetServersReturnsAllEndpoints()
{
var apiDescription1 = GetValidDescription();
var apiDescription2 = GetValidDescription();
var path = "default/path";
serverOptions.RoutePrefix = "/";
apiDescription1.RelativePath = $"{path}#{MethodName}";
apiDescription2.RelativePath = $"{path}#{MethodName}";

apiDescriptionsProviderMock.Setup(static p => p.ApiDescriptionGroups)
.Returns(new ApiDescriptionGroupCollection(new List<ApiDescriptionGroup>
{
new(null, new[] { apiDescription1 }),
new(null, new[] { apiDescription2 }),
},
0))
.Verifiable();

var result = documentGeneratorMock.Object.GetServers(new Uri(Host));

apiDescriptionsProviderMock.Verify();
documentGeneratorMock.Verify();
result.Should().HaveCount(2);
}

[Test]
public void GetServersPathAndRoutePrefixSameReturnsEmptyServers()
{
var apiDescription = GetValidDescription();
var path = "default/path";
serverOptions.RoutePrefix = "/default/path";
apiDescription.RelativePath = $"{path}#{MethodName}";

apiDescriptionsProviderMock.Setup(static p => p.ApiDescriptionGroups)
.Returns(new ApiDescriptionGroupCollection(new List<ApiDescriptionGroup>
{
new(null, new[] { apiDescription }),
},
0))
.Verifiable();

var result = documentGeneratorMock.Object.GetServers(new Uri(Host));

apiDescriptionsProviderMock.Verify();
documentGeneratorMock.Verify();
result.Should().BeEmpty();
}

[Test]
public void GetMethodTagsReturnNewRefSchemaTag()
{
Expand Down Expand Up @@ -178,7 +237,7 @@ public void GetServers_ReturnsOneServerWithDefaultNameAndUrl()
var host = new Uri(Host);
var route = "route";

var result = documentGeneratorMock.Object.GetServers(host, route);
var result = documentGeneratorMock.Object.GetServers(host, route, null);

var expected = new OpenRpcServer(openRpcOptions.DefaultServerName, new Uri($"{Host}/{route}"));
result.Should().HaveCount(1);
Expand Down Expand Up @@ -767,9 +826,10 @@ public void GetMethodServers_RelativePathIsDifferent_ReturnServerWithThisRoute()
var description = GetValidDescription();
var host = new Uri(Host);
var path = "different/path";
var servers = new List<OpenRpcServer> { new("name", new Uri($"{Host}{path}")) };
var server = new OpenRpcServer("JSON-RPC", new Uri($"{Host}/{path}"));
var servers = new List<OpenRpcServer> { server };
description.RelativePath = $"{path}#{MethodName}";
documentGeneratorMock.Setup(g => g.GetServers(host, path))
documentGeneratorMock.Setup(g => g.GetServers(host, path, null))
.Returns(servers)
.Verifiable();

Expand Down Expand Up @@ -923,7 +983,8 @@ public void CombineBindingStyles_BothObjectAndArray_ReturnEither()
new JsonRpcControllerAttribute()
},
ControllerName = controllerName,

Check warning on line 985 in src/tests/Tochka.JsonRpc.OpenRpc.Tests/Services/OpenRpcDocumentGeneratorTests.cs

View workflow job for this annotation

GitHub Actions / test

Possible null reference assignment.
MethodInfo = action?.Method ?? ((Action) ValidMethod).Method
MethodInfo = action?.Method ?? ((Action) ValidMethod).Method,
ControllerTypeInfo = new TypeDelegator(typeof(ValidJsonRpcController))
},
Properties =
{
Expand All @@ -940,6 +1001,13 @@ private static void ValidMethod()
{
}

private class ValidJsonRpcController : JsonRpcControllerBase
{
public void ValidJsonRpcMethod()
{
}
}

/// <summary>summary</summary>
/// <remarks>description</remarks>
private static void MethodWithDocs()
Expand Down

0 comments on commit a7e1827

Please sign in to comment.