Skip to content

Commit

Permalink
Merge pull request #5344 from microsoft/andrueastman/failingTestForFi…
Browse files Browse the repository at this point in the history
…ltering

path filtering validation
  • Loading branch information
andrueastman authored Sep 6, 2024
2 parents 60bc107 + 2d718b6 commit 00554b5
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 8 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Changed

- Fixed a when generating a plugin when only an operation is selected in the root node in the extension. [#5300](https://github.com/microsoft/kiota/issues/5300)

## [1.18.0] - 2024-09-05

### Added
Expand Down
3 changes: 3 additions & 0 deletions src/Kiota.Builder/Plugins/PluginsGenerationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,9 @@ private OpenApiDocument GetDocumentWithTrimmedComponentsAndResponses(OpenApiDocu
requestUrls[key] = path.Value.Operations.Keys.Select(static key => key.ToString().ToUpperInvariant()).ToList();
}

if (requestUrls.Count == 0)
throw new InvalidOperationException("No paths found in the OpenAPI document.");

var predicate = OpenApiFilterService.CreatePredicate(requestUrls: requestUrls, source: doc);
return OpenApiFilterService.CreateFilteredDocument(doc, predicate);
}
Expand Down
4 changes: 2 additions & 2 deletions src/kiota/Handlers/Plugin/AddHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,10 @@ public override async Task<int> InvokeAsync(InvocationContext context)
catch (Exception ex)
{
#if DEBUG
logger.LogCritical(ex, "error adding the client: {exceptionMessage}", ex.Message);
logger.LogCritical(ex, "error adding the plugin: {exceptionMessage}", ex.Message);
throw; // so debug tools go straight to the source of the exception when attached
#else
logger.LogCritical("error adding the client: {exceptionMessage}", ex.Message);
logger.LogCritical("error adding the plugin: {exceptionMessage}", ex.Message);
return 1;
#endif
}
Expand Down
4 changes: 2 additions & 2 deletions src/kiota/Handlers/Plugin/EditHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,10 @@ public override async Task<int> InvokeAsync(InvocationContext context)
catch (Exception ex)
{
#if DEBUG
logger.LogCritical(ex, "error adding the plugin: {exceptionMessage}", ex.Message);
logger.LogCritical(ex, "error editing the plugin: {exceptionMessage}", ex.Message);
throw; // so debug tools go straight to the source of the exception when attached
#else
logger.LogCritical("error adding the plugin: {exceptionMessage}", ex.Message);
logger.LogCritical("error editing the plugin: {exceptionMessage}", ex.Message);
return 1;
#endif
}
Expand Down
4 changes: 2 additions & 2 deletions src/kiota/Handlers/Plugin/GenerateHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@ public override async Task<int> InvokeAsync(InvocationContext context)
catch (Exception ex)
{
#if DEBUG
logger.LogCritical(ex, "error adding the client: {ExceptionMessage}", ex.Message);
logger.LogCritical(ex, "error generating the plugin: {ExceptionMessage}", ex.Message);
throw; // so debug tools go straight to the source of the exception when attached
#else
logger.LogCritical("error adding the client: {ExceptionMessage}", ex.Message);
logger.LogCritical("error generating the plugin: {ExceptionMessage}", ex.Message);
return 1;
#endif
}
Expand Down
2 changes: 1 addition & 1 deletion src/kiota/Rpc/Server.cs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ public async Task<List<LogEntry>> GeneratePluginAsync(string openAPIFilePath, st
}
catch (Exception ex)
{
globalLogger.LogCritical(ex, "error adding the client: {exceptionMessage}", ex.Message);
globalLogger.LogCritical(ex, "error generating the plugin: {exceptionMessage}", ex.Message);
}
return globalLogger.LogEntries;
}
Expand Down
67 changes: 67 additions & 0 deletions tests/Kiota.Builder.Tests/KiotaBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5994,6 +5994,73 @@ public void SetsReadonlyProperties(bool isReadonly)
var nameProperty = objectClass.Properties.First(static x => "name".Equals(x.Name, StringComparison.OrdinalIgnoreCase));
Assert.Equal(isReadonly, nameProperty.ReadOnly);
}
[Theory]
[InlineData("#GET", 0)]
[InlineData("/#GET", 1)]
public void SupportsIncludeFilterOnRootPath(string inputPattern, int expectedPathsCount)
{
var myObjectSchema = new OpenApiSchema
{
Type = "object",
Properties = new Dictionary<string, OpenApiSchema> {
{
"name", new OpenApiSchema {
Type = "string",
}
}
},
Reference = new OpenApiReference
{
Id = "myobject",
Type = ReferenceType.Schema
},
UnresolvedReference = false,
};
var document = new OpenApiDocument
{
Paths = new OpenApiPaths
{
["/"] = new OpenApiPathItem
{
Operations = {
[OperationType.Get] = new OpenApiOperation
{
Responses = new OpenApiResponses
{
["200"] = new OpenApiResponse {
Content = {
["application/json"] = new OpenApiMediaType {
Schema = myObjectSchema
}
}
},
}
}
}
},
},
Components = new()
{
Schemas = new Dictionary<string, OpenApiSchema> {
{
"myobject", myObjectSchema
}
}
}
};
var mockLogger = new Mock<ILogger<KiotaBuilder>>();
var builder = new KiotaBuilder(mockLogger.Object, new GenerationConfiguration
{
ClientClassName = "TestClient",
ClientNamespaceName = "TestSdk",
ApiRootUrl = "https://localhost",
IncludePatterns = new() {
inputPattern
}
}, _httpClient);
builder.FilterPathsByPatterns(document);
Assert.Equal(expectedPathsCount, document.Paths.Count);
}
[Fact]
public void SupportsIncludeFilter()
{
Expand Down
35 changes: 35 additions & 0 deletions tests/Kiota.Builder.Tests/Plugins/PluginsGenerationServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
using Kiota.Builder.Configuration;
using Kiota.Builder.Plugins;
Expand Down Expand Up @@ -115,6 +116,40 @@ public async Task GeneratesManifestAsync(string inputPluginName, string expected
private const string OpenAIPluginFileName = "openai-plugins.json";
private const string OpenApiFileName = "client-openapi.yml";

[Fact]
public async Task ThrowsOnEmptyPathsAfterFilteringAsync()
{
var simpleDescriptionContent = @"openapi: 3.0.0
info:
title: test
version: 1.0
servers:
- url: http://localhost/
description: There's no place like home
paths:
/test:
get:
description: description for test path
responses:
'200':
description: test";
var workingDirectory = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
var simpleDescriptionPath = Path.Combine(workingDirectory) + "description.yaml";
await File.WriteAllTextAsync(simpleDescriptionPath, simpleDescriptionContent);
var outputDirectory = Path.Combine(workingDirectory, "output");
var generationConfiguration = new GenerationConfiguration
{
OutputPath = outputDirectory,
OpenAPIFilePath = simpleDescriptionPath,
PluginTypes = [PluginType.APIPlugin, PluginType.APIManifest, PluginType.OpenAI],
ClientClassName = "testPlugin",
IncludePatterns = ["test/id"]// this would filter out all paths
};
var kiotaBuilder = new KiotaBuilder(new Mock<ILogger<KiotaBuilder>>().Object, generationConfiguration, _httpClient, true);
var exception = await Assert.ThrowsAsync<InvalidOperationException>(async () => await kiotaBuilder.GeneratePluginAsync(CancellationToken.None));
Assert.Equal("No paths found in the OpenAPI document.", exception.Message);
}

[Fact]
public async Task GeneratesManifestAndCleansUpInputDescriptionAsync()
{
Expand Down
6 changes: 5 additions & 1 deletion vscode/microsoft-kiota/src/openApiTreeProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,11 @@ export class OpenApiTreeProvider implements vscode.TreeDataProvider<OpenApiTreeN
if ((currentNode.isOperation || false) && this.rawRootNode) {
const parent = this.findApiNode(getPathSegments(trimOperation(currentNode.path)), this.rawRootNode);
if (parent && !parent.selected) {
result.push(currentNode.path.replace(/\\/g, pathSeparator));
let operationPath = currentNode.path.replace(/\\/g, pathSeparator);
if(operationPath.startsWith('#')) {//its a operation at the root it needs a leading slash
operationPath = `${pathSeparator}${operationPath}`;
}
result.push(operationPath);
}
} else {
result.push(currentNode.path.replace(/\\/g, pathSeparator));
Expand Down

0 comments on commit 00554b5

Please sign in to comment.