Fix dynamic connector extensions & update internal testing (#2146)

Fix dynamic connector extensions management in making 'parameters'
optional despite the spec which says it's required
Update internal tests
Add Guardian files
Update .gitignore file
Fix BuildLocalPackages.cmd script
This commit is contained in:
Luc Genetier 2024-01-16 19:03:56 +01:00 коммит произвёл GitHub
Родитель 382540a26b
Коммит cdcef30472
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
19 изменённых файлов: 372 добавлений и 292 удалений

5
.gdn/.gdnsettings Normal file
Просмотреть файл

@ -0,0 +1,5 @@
{
"jobs": [],
"commands": [],
"tools": []
}

11
.gdn/.gitignore поставляемый Normal file
Просмотреть файл

@ -0,0 +1,11 @@
## Ignore Guardian internal files
.r/
rc/
rs/
i/
p/
c/
o/
## Ignore Guardian Local settings
LocalSettings.gdn.json

8
.gitignore поставляемый
Просмотреть файл

@ -364,3 +364,11 @@ suppress.*.xml
# global.json
/src/global.json
/global.json
# Guardian results
.gdn/r
.gdn/internal.gdnhistory
# Yaml output
YamlOutput/

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

@ -2,11 +2,10 @@
setlocal enabledelayedexpansion
set MSBUILDARGS=-p:PublishRepositoryUrl=true -p:GeneratePackages=true -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg -p:InternalBuild=true -p:Configuration=Debug -p:Platform="Any CPU"
set MSBUILD=C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\amd64\MSBuild.exe
for /f "usebackq tokens=*" %%i in (`"%programfiles(x86)%\Microsoft Visual Studio\Installer\vswhere" -latest -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe`) do (
@REM Restore dependencies first if needed
"%%i" -t:restore
@REM Run build and generate nuget packages
"%%i" %MSBUILDARGS%
exit /b !errorlevel!
)
@REM Restore dependencies first if needed
"%MSBUILD%" -t:restore
@REM Run build and generate nuget packages
"%MSBUILD%" %MSBUILDARGS%

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

@ -773,9 +773,9 @@ namespace Microsoft.PowerFx.Connectors
// https://learn.microsoft.com/en-us/connectors/custom-connectors/openapi-extensions#use-dynamic-values
if (param?.Extensions != null && param.Extensions.TryGetValue(XMsDynamicValues, out IOpenApiExtension ext) && ext is OpenApiObject apiObj)
{
if (apiObj.TryGetValue("parameters", out IOpenApiAny op_prms) && op_prms is OpenApiObject opPrms)
{
ConnectorDynamicValue cdv = new (opPrms);
// Parameters is required in the spec but there are examples where it's not specified and we'll support this condition with an empty list
OpenApiObject op_prms = apiObj.TryGetValue("parameters", out IOpenApiAny openApiAny) && openApiAny is OpenApiObject apiString ? apiString : null;
ConnectorDynamicValue cdv = new (op_prms);
// Mandatory operationId for connectors, except when capibility or builtInOperation are defined
apiObj.WhenPresent("operationId", (opId) => cdv.OperationId = OpenApiHelperFunctions.NormalizeOperationId(opId));
@ -790,7 +790,6 @@ namespace Microsoft.PowerFx.Connectors
return cdv;
}
}
return null;
}
@ -800,12 +799,12 @@ namespace Microsoft.PowerFx.Connectors
// https://learn.microsoft.com/en-us/connectors/custom-connectors/openapi-extensions#use-dynamic-values
if (param?.Extensions != null && param.Extensions.TryGetValue(XMsDynamicList, out IOpenApiExtension ext) && ext is OpenApiObject apiObj)
{
// Mandatory openrationId for connectors
// Mandatory operationId for connectors
if (apiObj.TryGetValue("operationId", out IOpenApiAny op_id) && op_id is OpenApiString opId)
{
if (apiObj.TryGetValue("parameters", out IOpenApiAny op_prms) && op_prms is OpenApiObject opPrms)
{
ConnectorDynamicList cdl = new (opPrms)
// Parameters is required in the spec but there are examples where it's not specified and we'll support this condition with an empty list
OpenApiObject op_prms = apiObj.TryGetValue("parameters", out IOpenApiAny openApiAny) && openApiAny is OpenApiObject apiString ? apiString : null;
ConnectorDynamicList cdl = new (op_prms)
{
OperationId = OpenApiHelperFunctions.NormalizeOperationId(opId.Value),
};
@ -827,7 +826,6 @@ namespace Microsoft.PowerFx.Connectors
return cdl;
}
}
else
{
return new ConnectorDynamicList($"Missing mandatory parameters operationId and parameters in {XMsDynamicList} extension");
@ -841,6 +839,11 @@ namespace Microsoft.PowerFx.Connectors
{
Dictionary<string, IConnectorExtensionValue> dvParams = new ();
if (opPrms == null)
{
return dvParams;
}
foreach (KeyValuePair<string, IOpenApiAny> prm in opPrms)
{
if (!TryGetOpenApiValue(prm.Value, null, out FormulaValue fv, errors, forceString))
@ -907,12 +910,13 @@ namespace Microsoft.PowerFx.Connectors
// https://learn.microsoft.com/en-us/connectors/custom-connectors/openapi-extensions#use-dynamic-values
if (param?.Extensions != null && param.Extensions.TryGetValue(XMsDynamicSchema, out IOpenApiExtension ext) && ext is OpenApiObject apiObj)
{
// Mandatory openrationId for connectors
// Mandatory operationId for connectors
if (apiObj.TryGetValue("operationId", out IOpenApiAny op_id) && op_id is OpenApiString opId)
{
if (apiObj.TryGetValue("parameters", out IOpenApiAny op_prms) && op_prms is OpenApiObject opPrms)
{
ConnectorDynamicSchema cds = new (opPrms)
// Parameters is required in the spec but there are examples where it's not specified and we'll support this condition with an empty list
OpenApiObject op_prms = apiObj.TryGetValue("parameters", out IOpenApiAny openApiAny) && openApiAny is OpenApiObject apiString ? apiString : null;
ConnectorDynamicSchema cds = new (op_prms)
{
OperationId = OpenApiHelperFunctions.NormalizeOperationId(opId.Value),
};
@ -924,7 +928,6 @@ namespace Microsoft.PowerFx.Connectors
return cds;
}
}
else
{
return new ConnectorDynamicSchema(error: $"Missing mandatory parameters operationId and parameters in {XMsDynamicSchema} extension");
@ -939,12 +942,13 @@ namespace Microsoft.PowerFx.Connectors
// https://learn.microsoft.com/en-us/connectors/custom-connectors/openapi-extensions#use-dynamic-values
if (param?.Extensions != null && param.Extensions.TryGetValue(XMsDynamicProperties, out IOpenApiExtension ext) && ext is OpenApiObject apiObj)
{
// Mandatory openrationId for connectors
// Mandatory operationId for connectors
if (apiObj.TryGetValue("operationId", out IOpenApiAny op_id) && op_id is OpenApiString opId)
{
if (apiObj.TryGetValue("parameters", out IOpenApiAny op_prms) && op_prms is OpenApiObject opPrms)
{
ConnectorDynamicProperty cdp = new (opPrms)
// Parameters is required in the spec but there are examples where it's not specified and we'll support this condition with an empty list
OpenApiObject op_prms = apiObj.TryGetValue("parameters", out IOpenApiAny openApiAny) && openApiAny is OpenApiObject apiString ? apiString : null;
ConnectorDynamicProperty cdp = new (op_prms)
{
OperationId = OpenApiHelperFunctions.NormalizeOperationId(opId.Value),
};
@ -956,7 +960,6 @@ namespace Microsoft.PowerFx.Connectors
return cdp;
}
}
else
{
return new ConnectorDynamicProperty(error: $"Missing mandatory parameters operationId and parameters in {XMsDynamicProperties} extension");

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

@ -260,7 +260,11 @@ namespace Microsoft.PowerFx.Connectors
// openApiDocument.Components.RequestBodies is ok
// openApiDocument.Components.Responses contains references from "path" definitions
// openApiDocument.Components.Schemas contains global "definitions"
// openApiDocument.Components.SecuritySchemes are critical but as we don't manage them at all, we'll ignore this parameter
if (openApiDocument.Components.SecuritySchemes.Count > 0)
{
logger?.LogInformation($"Unsupported document: {notSupportedReason}");
}
}
if (isSupported && failOnUnknownExtensions)

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

@ -73,7 +73,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
internal (LoggingTestServer testConnector, OpenApiDocument apiDoc, PowerFxConfig config, HttpClient httpClient, PowerPlatformConnectorClient client, ConnectorSettings connectorSettings, RuntimeConfig runtimeConfig) GetElements(bool live = false, bool returnUO = false)
{
var testConnector = new LoggingTestServer(_swaggerFile, live);
var testConnector = new LoggingTestServer(_swaggerFile, _output, live);
HttpClient httpClient = new HttpClient(testConnector);
PowerPlatformConnectorClient client = new PowerPlatformConnectorClient(GetEndpoint(), GetEnvironment(), GetConnectionId(), () => GetJWTToken(), httpClient) { SessionId = "9315f316-5182-4260-b333-7a43a36ca3b0" };

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

@ -11,7 +11,6 @@ using System.Threading.Tasks;
using Microsoft.PowerFx.Connectors;
using Microsoft.PowerFx.Connectors.Tests;
using Microsoft.PowerFx.Core.Tests;
using Microsoft.VisualStudio.TestPlatform.Utilities;
using Xunit;
using Xunit.Abstractions;
@ -66,7 +65,7 @@ namespace Microsoft.PowerFx.Tests
var swaggerFile = @"Swagger\TestOpenAPI.json";
Console.Write(i);
using var testConnector = new LoggingTestServer(swaggerFile);
using var testConnector = new LoggingTestServer(swaggerFile, _output);
testConnector.SetResponseFromFile(@"Responses\HttpCall_1.json");
List<ConnectorFunction> functions = OpenApiParser.GetFunctions("Test", testConnector._apiDocument, new ConsoleLogger(_output)).OrderBy(cf => cf.Name).ToList();
@ -105,7 +104,7 @@ namespace Microsoft.PowerFx.Tests
[Fact]
public async Task BasicHttpCallNullInvoker()
{
using var testConnector = new LoggingTestServer(@"Swagger\TestOpenAPI.json");
using var testConnector = new LoggingTestServer(@"Swagger\TestOpenAPI.json", _output);
var config = new PowerFxConfig();
var apiDoc = testConnector._apiDocument;
@ -125,7 +124,7 @@ namespace Microsoft.PowerFx.Tests
public void BasicHttpBinding()
{
var config = new PowerFxConfig();
var apiDoc = Helpers.ReadSwagger(@"Swagger\TestOpenAPI.json");
var apiDoc = Helpers.ReadSwagger(@"Swagger\TestOpenAPI.json", _output);
// If we don't pass httpClient, we can still bind, we just can't invoke.
config.AddActionConnector("Test", apiDoc, new ConsoleLogger(_output));
@ -139,7 +138,7 @@ namespace Microsoft.PowerFx.Tests
[Fact]
public async Task PetStore_MultiServer()
{
using var testConnector = new LoggingTestServer(@"Swagger\PetStore.json");
using var testConnector = new LoggingTestServer(@"Swagger\PetStore.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig();

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

@ -32,7 +32,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact]
public async Task ConnectorWizardTest()
{
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\SQL Server.json");
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\SQL Server.json", _output);
using HttpClient httpClient = new HttpClient(testConnector);
using PowerPlatformConnectorClient client = new PowerPlatformConnectorClient(
"tip1-shared-002.azure-apim.net", // endpoint
@ -154,7 +154,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact]
public async Task ConnectorWizardTest_InvalidToken()
{
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\SQL Server.json");
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\SQL Server.json", _output);
using HttpClient httpClient = new HttpClient(testConnector);
using PowerPlatformConnectorClient client = new PowerPlatformConnectorClient(
"tip1-shared-002.azure-apim.net", // endpoint

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

@ -10,10 +10,10 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Readers;
using Microsoft.OpenApi.Validations;
using Microsoft.PowerFx.Core.Tests;
using Microsoft.PowerFx.Intellisense;
using Microsoft.PowerFx.Types;
using Microsoft.VisualStudio.TestPlatform.Utilities;
using Xunit;
using Xunit.Abstractions;
@ -32,7 +32,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
_output = output;
}
private void GetFunctionsInternal(out OpenApiDocument doc, out List<ConnectorFunction> functions)
private void GetFunctionsInternal(ITestOutputHelper output, out OpenApiDocument doc, out List<ConnectorFunction> functions)
{
functions = null;
doc = null;
@ -43,7 +43,24 @@ namespace Microsoft.PowerFx.Connectors.Tests
if (!skip)
{
using WebClient webClient = new WebClient();
doc = new OpenApiStreamReader().Read(webClient.OpenRead(SwaggerFile), out var diagnostic);
doc = new OpenApiStreamReader().Read(webClient.OpenRead(SwaggerFile), out var diag);
if (diag != null && diag.Errors.Count > 0)
{
foreach (OpenApiError error in diag.Errors)
{
if (error is OpenApiValidatorError vError)
{
output.WriteLine($"[OpenApi Error] {vError.RuleName} {vError.Pointer} {vError.Message}");
}
else
{
// Could be OpenApiError or OpenApiReferenceError
output.WriteLine($"[OpenApi Error] {error.Pointer} {error.Message}");
}
}
}
functions = OpenApiParser.GetFunctions("Test", doc, new ConsoleLogger(_output)).OrderBy(cf => cf.Name).ToList();
}
}
@ -80,7 +97,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[SkippableFact]
public async Task DynamicValues_GetWithDynamicValuesStatic_RequiredParameters()
{
GetFunctionsInternal(out OpenApiDocument doc, out List<ConnectorFunction> functions);
GetFunctionsInternal(_output, out OpenApiDocument doc, out List<ConnectorFunction> functions);
ConnectorFunction getWithDynamicValuesStatic = functions.First(cf => cf.Name == "GetWithDynamicValuesStatic");
Assert.True(getWithDynamicValuesStatic.RequiredParameters[0].SupportsDynamicIntellisense);
@ -100,7 +117,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[SkippableFact]
public async Task DynamicValues_GetWithDynamicValuesStatic_OptionalParameters()
{
GetFunctionsInternal(out OpenApiDocument doc, out List<ConnectorFunction> functions);
GetFunctionsInternal(_output, out OpenApiDocument doc, out List<ConnectorFunction> functions);
ConnectorFunction getWithDynamicValuesStaticOptional = functions.First(cf => cf.Name == "GetWithDynamicValuesStaticOptional");
Assert.True(getWithDynamicValuesStaticOptional.OptionalParameters[0].SupportsDynamicIntellisense);
@ -122,7 +139,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[SkippableFact]
public async Task DynamicValues_GetWithDynamicValuesStaticNoValueCollection_RequiredParameters()
{
GetFunctionsInternal(out OpenApiDocument doc, out List<ConnectorFunction> functions);
GetFunctionsInternal(_output, out OpenApiDocument doc, out List<ConnectorFunction> functions);
ConnectorFunction getWithDynamicValuesStaticNoValueCollection = functions.First(cf => cf.Name == "GetWithDynamicValuesStaticNoValueCollection");
Assert.True(getWithDynamicValuesStaticNoValueCollection.RequiredParameters[0].SupportsDynamicIntellisense);
@ -142,7 +159,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[SkippableFact]
public async Task DynamicValues_GetWithDynamicValuesStaticInvalidValueCollection_RequiredParameters()
{
GetFunctionsInternal(out OpenApiDocument doc, out List<ConnectorFunction> functions);
GetFunctionsInternal(_output, out OpenApiDocument doc, out List<ConnectorFunction> functions);
ConnectorFunction getWithDynamicValuesStaticInvalidValueCollection = functions.First(cf => cf.Name == "GetWithDynamicValuesStaticInvalidValueCollection");
Assert.True(getWithDynamicValuesStaticInvalidValueCollection.RequiredParameters[0].SupportsDynamicIntellisense);
@ -162,7 +179,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[SkippableFact]
public async Task DynamicValues_GetWithDynamicValuesStaticInvalidDisplayName_RequiredParameters()
{
GetFunctionsInternal(out OpenApiDocument doc, out List<ConnectorFunction> functions);
GetFunctionsInternal(_output, out OpenApiDocument doc, out List<ConnectorFunction> functions);
ConnectorFunction getWithDynamicValuesStaticInvalidDisplayName = functions.First(cf => cf.Name == "GetWithDynamicValuesStaticInvalidDisplayName");
Assert.True(getWithDynamicValuesStaticInvalidDisplayName.RequiredParameters[0].SupportsDynamicIntellisense);
@ -182,7 +199,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[SkippableFact]
public async Task DynamicValues_GetWithDynamicValuesStaticInvalidValuePath_RequiredParameters()
{
GetFunctionsInternal(out OpenApiDocument doc, out List<ConnectorFunction> functions);
GetFunctionsInternal(_output, out OpenApiDocument doc, out List<ConnectorFunction> functions);
ConnectorFunction getWithDynamicValuesStaticInvalidValuePath = functions.First(cf => cf.Name == "GetWithDynamicValuesStaticInvalidValuePath");
Assert.True(getWithDynamicValuesStaticInvalidValuePath.RequiredParameters[0].SupportsDynamicIntellisense);
@ -202,7 +219,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[SkippableFact]
public async Task DynamicValues_GetWithDynamicValuesDynamic_RequiredParameters()
{
GetFunctionsInternal(out OpenApiDocument doc, out List<ConnectorFunction> functions);
GetFunctionsInternal(_output, out OpenApiDocument doc, out List<ConnectorFunction> functions);
ConnectorFunction getWithDynamicValuesDynamic = functions.First(cf => cf.Name == "GetWithDynamicValuesDynamic");
Assert.True(getWithDynamicValuesDynamic.RequiredParameters[1].SupportsDynamicIntellisense);
@ -222,7 +239,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[SkippableFact]
public async Task DynamicValues_GetWithDynamicValuesMultipleDynamic_RequiredParameters()
{
GetFunctionsInternal(out OpenApiDocument doc, out List<ConnectorFunction> functions);
GetFunctionsInternal(_output, out OpenApiDocument doc, out List<ConnectorFunction> functions);
ConnectorFunction getWithDynamicValuesMultipleDynamic = functions.First(cf => cf.Name == "GetWithDynamicValuesMultipleDynamic");
Assert.True(getWithDynamicValuesMultipleDynamic.RequiredParameters[2].SupportsDynamicIntellisense);
@ -261,7 +278,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[SkippableFact]
public async Task DynamicValues_GetWithDynamicListStatic_RequiredParameters()
{
GetFunctionsInternal(out OpenApiDocument doc, out List<ConnectorFunction> functions);
GetFunctionsInternal(_output, out OpenApiDocument doc, out List<ConnectorFunction> functions);
ConnectorFunction getWithDynamicListStatic = functions.First(cf => cf.Name == "GetWithDynamicListStatic");
Assert.True(getWithDynamicListStatic.RequiredParameters[0].SupportsDynamicIntellisense);
@ -281,7 +298,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[SkippableFact]
public async Task DynamicValues_GetWithDynamicListDynamic_RequiredParameters()
{
GetFunctionsInternal(out OpenApiDocument doc, out List<ConnectorFunction> functions);
GetFunctionsInternal(_output, out OpenApiDocument doc, out List<ConnectorFunction> functions);
ConnectorFunction getWithDynamicListDynamic = functions.First(cf => cf.Name == "GetWithDynamicListDynamic");
Assert.True(getWithDynamicListDynamic.RequiredParameters[1].SupportsDynamicIntellisense);

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

@ -6,7 +6,9 @@ using System.IO;
using System.Linq;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Readers;
using Microsoft.OpenApi.Validations;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.PowerFx.Tests
{
@ -52,19 +54,28 @@ namespace Microsoft.PowerFx.Tests
}
// Get a swagger file from the embedded resources.
public static OpenApiDocument ReadSwagger(string name)
public static OpenApiDocument ReadSwagger(string name, ITestOutputHelper output)
{
using (var stream = GetStream(name))
{
var doc = new OpenApiStreamReader().Read(stream, out OpenApiDiagnostic diag);
using var stream = GetStream(name);
OpenApiDocument doc = new OpenApiStreamReader().Read(stream, out OpenApiDiagnostic diag);
if ((doc == null || doc.Paths == null || doc.Paths.Count == 0) && diag != null && diag.Errors.Count > 0)
if (diag != null && diag.Errors.Count > 0)
{
throw new InvalidDataException($"Unable to parse Swagger file: {string.Join(", ", diag.Errors.Select(err => err.Message))}");
foreach (OpenApiError error in diag.Errors)
{
if (error is OpenApiValidatorError vError)
{
output.WriteLine($"[OpenApi Error] {vError.RuleName} {vError.Pointer} {vError.Message}");
}
else
{
// Could be OpenApiError or OpenApiReferenceError
output.WriteLine($"[OpenApi Error] {error.Pointer} {error.Message}");
}
}
}
return doc;
}
}
}
}

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

@ -13,6 +13,7 @@ using System.Threading.Tasks;
using Microsoft.OpenApi.Models;
using Microsoft.PowerFx.Connectors;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.PowerFx.Tests
{
@ -28,10 +29,10 @@ namespace Microsoft.PowerFx.Tests
public bool Live = false;
public HttpClient LiveClient = null;
public LoggingTestServer(string swaggerName, bool live = false)
public LoggingTestServer(string swaggerName, ITestOutputHelper output, bool live = false)
{
Live = live;
_apiDocument = Helpers.ReadSwagger(swaggerName);
_apiDocument = Helpers.ReadSwagger(swaggerName, output);
if (live)
{

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

@ -9,7 +9,6 @@ using System.Threading.Tasks;
using Microsoft.OpenApi.Models;
using Microsoft.PowerFx.Intellisense;
using Microsoft.PowerFx.Tests;
using Microsoft.VisualStudio.TestPlatform.Utilities;
using Xunit;
using Xunit.Abstractions;
@ -47,7 +46,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
public void ConnectorIntellisenseTest(int responseIndex, int queryIndex, string expression, string expectedSuggestions)
{
// These tests are exercising 'x-ms-dynamic-values' extension property
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\SQL Server.json");
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\SQL Server.json", _output);
OpenApiDocument apiDoc = testConnector._apiDocument;
PowerFxConfig config = new PowerFxConfig(Features.PowerFxV1);
@ -128,7 +127,7 @@ $@"POST https://tip1-shared-002.azure-apim.net/invoke
public void ConnectorIntellisenseTest2(int responseIndex, int networkCall, string expression, string expectedSuggestions)
{
// These tests are exercising 'x-ms-dynamic-schema' extension property
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\SQL Server.json");
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\SQL Server.json", _output);
OpenApiDocument apiDoc = testConnector._apiDocument;
PowerFxConfig config = new PowerFxConfig(Features.PowerFxV1);
@ -185,7 +184,7 @@ $@"POST https://tip1-shared-002.azure-apim.net/invoke
public void ConnectorIntellisenseTestLSP(int responseIndex, int networkCall, string expression, string expectedSuggestions)
{
// These tests are exercising 'x-ms-dynamic-schema' extension property
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\SQL Server.json");
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\SQL Server.json", _output);
OpenApiDocument apiDoc = testConnector._apiDocument;
PowerFxConfig config = new PowerFxConfig(Features.PowerFxV1);
@ -248,7 +247,7 @@ $@"POST https://tip1-shared-002.azure-apim.net/invoke
[Fact]
public async Task ConnectorIntellisenseTest3()
{
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\SharePoint.json");
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\SharePoint.json", _output);
OpenApiDocument apiDoc = testConnector._apiDocument;
PowerFxConfig config = new PowerFxConfig();
string token = @"eyJ0eXA...";
@ -283,7 +282,7 @@ $@"POST https://tip1-shared-002.azure-apim.net/invoke
{
// This Path can be found in the Swagger file SQL Server.json
var deprecatedFunctionExample = "SQL.ExecutePassThroughNativeQuery";
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\SQL Server.json");
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\SQL Server.json", _output);
OpenApiDocument apiDoc = testConnector._apiDocument;
PowerFxConfig config = new PowerFxConfig(Features.PowerFxV1);

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

@ -38,34 +38,45 @@ namespace Microsoft.PowerFx.Connectors.Tests
#endif
public void TestAllConnectors()
{
string outFolder = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, @"..\..\..\..\..\.."));
string srcFolder = Path.GetFullPath(Path.Combine(outFolder, ".."));
(string outFolder, string srcFolder) = GetFolders();
string reportFolder = @"report";
string reportName = @$"{reportFolder}\Analysis.txt";
string jsonReport = @$"{reportFolder}\Report.json";
// New report name every second
string jsonReport2 = @$"report\Report_{Math.Round(DateTime.UtcNow.Ticks / 1e7):00000000000}.json";
string jsonReport2 = @$"{reportFolder}\Report_{Math.Round(DateTime.UtcNow.Ticks / 1e7):00000000000}.json";
string outFolderPath = Path.Combine(outFolder, reportFolder);
if (Directory.Exists(outFolderPath))
{
Directory.Delete(outFolderPath, true);
}
// On build servers: ENV: C:\__w\1\s\pfx\src\tests\Microsoft.PowerFx.Connectors.Tests\bin\Release\netcoreapp3.1
// Locally : ENV: C:\Data\Power-Fx\src\tests\Microsoft.PowerFx.Connectors.Tests\bin\Debug\netcoreapp3.1
_output.WriteLine($"ENV: {Environment.CurrentDirectory}");
_output.WriteLine($"OUT: {outFolder}");
_output.WriteLine($"SRC: {srcFolder}");
BaseConnectorTest.EmptyFolder(outFolderPath);
Directory.CreateDirectory(Path.Combine(outFolder, "report"));
GenerateReport(reportFolder, reportName, outFolder, srcFolder);
AnalyzeReport(reportName, outFolder, srcFolder, jsonReport);
File.Copy(Path.Combine(outFolder, jsonReport), Path.Combine(outFolder, jsonReport2));
}
private (string outFolder, string srcFolder) GetFolders()
{
string outFolder = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, @"..\..\..\..\..\.."));
string srcFolder = Path.GetFullPath(Path.Combine(outFolder, ".."));
// On build servers: ENV: C:\__w\1\s\pfx\src\tests\Microsoft.PowerFx.Connectors.Tests\bin\Release\netcoreapp3.1
// Locally : ENV: C:\Data\Power-Fx\src\tests\Microsoft.PowerFx.Connectors.Tests\bin\Debug\netcoreapp3.1
_output.WriteLine($"ENV: {Environment.CurrentDirectory}");
// On build servers: OUT: C:\__w\1\s\pfx
// Locally : OUT: C:\Data\Power-Fx
_output.WriteLine($"OUT: {outFolder}");
// On build servers: SRC: C:\__w\1\s
// Locally : SRC: C:\Data
_output.WriteLine($"SRC: {srcFolder}");
return (outFolder, srcFolder);
}
private void AnalyzeReport(string reportName, string outFolder, string srcFolder, string jsonReport)
{
List<Connector> connectors = new ();
@ -356,23 +367,22 @@ namespace Microsoft.PowerFx.Connectors.Tests
try
{
ConsoleLogger logger = new ConsoleLogger(_output);
OpenApiDocument doc = Helpers.ReadSwagger(swaggerFile);
OpenApiDocument doc = Helpers.ReadSwagger(swaggerFile, _output);
ConnectorSettings connectorSettings = new ConnectorSettings("Connector") { AllowUnsupportedFunctions = true, IncludeInternalFunctions = true };
ConnectorSettings swaggerConnectorSettings = new ConnectorSettings("Connector") { AllowUnsupportedFunctions = true, IncludeInternalFunctions = true, Compatibility = ConnectorCompatibility.SwaggerCompatibility };
title = $"{doc.Info.Title} [{swaggerFile}]";
// Check we can get the functions
IEnumerable<ConnectorFunction> functions = OpenApiParser.GetFunctions("C", doc, logger);
IEnumerable<ConnectorFunction> functions1 = OpenApiParser.GetFunctions(connectorSettings, doc, logger);
allFunctions.Add(title, functions);
allFunctions.Add(title, functions1);
var config = new PowerFxConfig();
using var client = new PowerPlatformConnectorClient("firstrelease-001.azure-apim.net", "839eace6-59ab-4243-97ec-a5b8fcc104e4", "72c42ee1b3c7403c8e73aa9c02a7fbcc", () => "Some JWT token")
{
SessionId = "ce55fe97-6e74-4f56-b8cf-529e275b253f"
};
// Check we can add the service (more comprehensive test)
config.AddActionConnector("Connector", doc, logger);
config.AddActionConnector(connectorSettings, doc, logger);
IEnumerable<ConnectorFunction> functions2 = OpenApiParser.GetFunctions(new ConnectorSettings("C1") { Compatibility = ConnectorCompatibility.SwaggerCompatibility }, doc);
IEnumerable<ConnectorFunction> functions2 = OpenApiParser.GetFunctions(swaggerConnectorSettings, doc);
string cFolder = Path.Combine(outFolder, reportFolder, doc.Info.Title);
int ix = 2;
@ -383,7 +393,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
Directory.CreateDirectory(cFolder);
foreach (ConnectorFunction cf1 in functions)
foreach (ConnectorFunction cf1 in functions1)
{
ConnectorFunction cf2 = functions2.First(f => f.Name == cf1.Name);
@ -512,7 +522,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
public void TestConnector1()
{
string swaggerFile = @"c:\data\AAPT-connectors\src\ConnectorPlatform\build-system\SharedTestAssets\Assets\BaselineBuild\locPublish\Connectors\AzureAD\apidefinition.swagger.json";
OpenApiDocument doc = Helpers.ReadSwagger(swaggerFile);
OpenApiDocument doc = Helpers.ReadSwagger(swaggerFile, _output);
IEnumerable<ConnectorFunction> functions = OpenApiParser.GetFunctions("C", doc, new ConsoleLogger(_output));
var config = new PowerFxConfig();
@ -538,22 +548,16 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Theory(Skip = "Need files from AAPT-connector, PowerPlatformConnectors and Power-Fx-TexlFunctions-Baseline projects")]
#endif
[InlineData("Library")] // Default Power-Fx library
[InlineData("Aapt-Ppc", 0, "apidefinition*swagger*.json", @"C:\Data\aapt", @"C:\Data\ppc")]
[InlineData("Baseline", 1, "*.json", @"C:\Data\Power-Fx-TexlFunctions-Baseline\Swaggers")]
[InlineData("Aapt-Ppc", 0, "apidefinition*swagger*.json", @"aapt\src", @"ppc")]
[InlineData("Baseline", 1, "*.json", @"Power-Fx-TexlFunctions-Baseline\Swaggers")]
public void GenerateYamlFiles(string reference, int folderExclusionIndex = -1, string pattern = null, params string[] folders)
{
string outFolder = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, @"..\..\..\..\..\.."));
string srcFolder = Path.GetFullPath(Path.Combine(outFolder, ".."));
// On build servers: ENV: C:\__w\1\s\pfx\src\tests\Microsoft.PowerFx.Connectors.Tests\bin\Release\netcoreapp3.1
// Locally : ENV: C:\Data\Power-Fx\src\tests\Microsoft.PowerFx.Connectors.Tests\bin\Debug\netcoreapp3.1
_output.WriteLine($"ENV: {Environment.CurrentDirectory}");
_output.WriteLine($"OUT: {outFolder}");
_output.WriteLine($"SRC: {srcFolder}");
(string outFolder, string srcFolder) = GetFolders();
string outFolderPath = Path.Combine(outFolder, "YamlOutput");
BaseConnectorTest.EmptyFolder(Path.Combine(outFolderPath, reference));
// if no folder, use Library
if (folders.Length == 0)
{
#pragma warning disable CS0618 // Type or member is obsolete
@ -577,12 +581,14 @@ namespace Microsoft.PowerFx.Connectors.Tests
Compatibility = ConnectorCompatibility.PowerAppsCompatibility
};
string[] rootedFolders = folders.Select(f => Path.Combine(srcFolder, f)).ToArray();
// Step 1: Identify the list of swagger files to consider
// The output of LocateSwaggerFilesWithDocuments is a dictionary where
// - Key is the connector display name
// - Value is a (folder, location, document) tuple where folder is the source folder at the origin of the swagger identification, location is the exact swagger file location, document is the corresponding OpenApiDocument
// LocateSwaggerFiles could also be used here and would only return a Dictionary<displayName, location> (no source folder or document)
Dictionary<string, (string folder, string location, OpenApiDocument document)> swaggerFiles = SwaggerFileIdentification.LocateSwaggerFilesWithDocuments(folders, pattern, swaggerLocationSettings);
Dictionary<string, (string folder, string location, OpenApiDocument document)> swaggerFiles = SwaggerFileIdentification.LocateSwaggerFilesWithDocuments(rootedFolders, pattern, swaggerLocationSettings);
_output.WriteLine($"Number of connectors found: {swaggerFiles.Count()}");
foreach (KeyValuePair<string, (string folder, string location, OpenApiDocument document)> connector in swaggerFiles)
@ -646,6 +652,8 @@ namespace Microsoft.PowerFx.Connectors.Tests
}
func.IsBehavior = connectorFunction.IsBehavior;
func.IsSupported = connectorFunction.IsSupported;
func.NotSupportedReason = connectorFunction.NotSupportedReason;
func.IsDeprecated = connectorFunction.IsDeprecated;
func.IsInternal = connectorFunction.IsInternal;
func.IsPageable = connectorFunction.IsPageable;

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

@ -11,13 +11,22 @@ using System.Threading;
using System.Threading.Tasks;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Readers;
using Microsoft.OpenApi.Validations;
using Microsoft.PowerFx.Types;
using Xunit;
using Xunit.Abstractions;
namespace Microsoft.PowerFx.Connectors.Tests
{
public class LivePublicSwaggerTests
{
private readonly ITestOutputHelper _output;
public LivePublicSwaggerTests(ITestOutputHelper output)
{
_output = output;
}
[Fact(Skip = "These APIs are rate limited and HTTP error 429 is possible")]
public async Task RealTest()
{
@ -30,7 +39,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
// "https://api.apis.guru/v2/specs/weatherbit.io/2.0.0/swagger.json"
// "https://www.weatherbit.io/static/swagger.json"
OpenApiDocument doc = await ReadSwaggerFromUrl(swaggerUrl).ConfigureAwait(false);
OpenApiDocument doc = await ReadSwaggerFromUrl(swaggerUrl, _output).ConfigureAwait(false);
// No BaseAdress specified, we'll use the 1st HTTPS one found in the swagger file
using var client = new HttpClient(); // public auth
@ -72,7 +81,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
// Note that these APIs are rate limited and HTTP error 429 is possible
var swaggerUrl = "https://api.apis.guru/v2/specs/math.tools/1.5/openapi.json";
OpenApiDocument doc = await ReadSwaggerFromUrl(swaggerUrl).ConfigureAwait(false);
OpenApiDocument doc = await ReadSwaggerFromUrl(swaggerUrl, _output).ConfigureAwait(false);
// Here we specify the BaseAddress
using var client = new HttpClient() { BaseAddress = new Uri("https://api.math.tools") };
@ -129,7 +138,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
// https://date.nager.at/
var swaggerUrl = "https://date.nager.at/swagger/v3/swagger.json";
OpenApiDocument doc = await ReadSwaggerFromUrl(swaggerUrl).ConfigureAwait(false);
OpenApiDocument doc = await ReadSwaggerFromUrl(swaggerUrl, _output).ConfigureAwait(false);
using var client = new HttpClient() { BaseAddress = new Uri("https://date.nager.at") };
var funcs = config.AddActionConnector("Holiday", doc);
@ -173,8 +182,8 @@ namespace Microsoft.PowerFx.Connectors.Tests
public async Task RealTest4()
{
var config = new PowerFxConfig();
OpenApiDocument docXkcd = await ReadSwaggerFromUrl(@"https://api.apis.guru/v2/specs/xkcd.com/1.0.0/openapi.json").ConfigureAwait(false);
OpenApiDocument docWorldTime = await ReadSwaggerFromUrl(@"https://api.apis.guru/v2/specs/worldtimeapi.org/20210108/openapi.json").ConfigureAwait(false);
OpenApiDocument docXkcd = await ReadSwaggerFromUrl(@"https://api.apis.guru/v2/specs/xkcd.com/1.0.0/openapi.json", _output).ConfigureAwait(false);
OpenApiDocument docWorldTime = await ReadSwaggerFromUrl(@"https://api.apis.guru/v2/specs/worldtimeapi.org/20210108/openapi.json", _output).ConfigureAwait(false);
using var clientXkcd = new HttpClient() { BaseAddress = new Uri(@"http://xkcd.com/") };
using var clientWorldTime = new HttpClient() { BaseAddress = new Uri(@"http://worldtimeapi.org/api/") };
@ -201,7 +210,7 @@ Boy: I wonder where I'll float next?
public async Task FailOnUnknownExtensionTest()
{
var config = new PowerFxConfig();
OpenApiDocument docXkcd = await ReadSwaggerFromUrl(@"https://api.apis.guru/v2/specs/xkcd.com/1.0.0/openapi.json").ConfigureAwait(false);
OpenApiDocument docXkcd = await ReadSwaggerFromUrl(@"https://api.apis.guru/v2/specs/xkcd.com/1.0.0/openapi.json", _output).ConfigureAwait(false);
IReadOnlyList<ConnectorFunction> funcsXkcd = config.AddActionConnector(new ConnectorSettings("Xkcd") { FailOnUnknownExtension = true }, docXkcd);
@ -217,22 +226,31 @@ Boy: I wonder where I'll float next?
}
// Get a swagger file from the embedded resources.
private static async Task<OpenApiDocument> ReadSwaggerFromUrl(string url)
{
using var http = new HttpClient();
using (var stream = await http.GetStreamAsync(new Uri(url)).ConfigureAwait(false))
private static async Task<OpenApiDocument> ReadSwaggerFromUrl(string url, ITestOutputHelper output)
{
using HttpClient http = new HttpClient();
using Stream stream = await http.GetStreamAsync(new Uri(url)).ConfigureAwait(false);
ReadResult rr = await new OpenApiStreamReader().ReadAsync(stream, CancellationToken.None).ConfigureAwait(false);
OpenApiDiagnostic diag = rr.OpenApiDiagnostic;
OpenApiDocument doc = rr.OpenApiDocument;
if ((doc == null || doc.Paths == null || doc.Paths.Count == 0) && diag != null && diag.Errors.Count > 0)
if (diag != null && diag.Errors.Count > 0)
{
throw new InvalidDataException($"Unable to parse Swagger file: {string.Join(", ", diag.Errors.Select(err => err.Message))}");
foreach (OpenApiError error in diag.Errors)
{
if (error is OpenApiValidatorError vError)
{
output.WriteLine($"[OpenApi Error] {vError.RuleName} {vError.Pointer} {vError.Message}");
}
else
{
// Could be OpenApiError or OpenApiReferenceError
output.WriteLine($"[OpenApi Error] {error.Pointer} {error.Message}");
}
}
}
return doc;
}
}
}
}

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

@ -119,7 +119,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
{
ConsoleLogger logger = new ConsoleLogger(_output);
PowerFxConfig config = new PowerFxConfig(Features.PowerFxV1);
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\SQL Server.json");
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\SQL Server.json", _output);
IReadOnlyList<ConnectorFunction> functions = config.AddActionConnector(new ConnectorSettings("SQL"), testConnector._apiDocument, logger);
Assert.NotEmpty(functions);

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

@ -29,7 +29,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact]
public void ACSL_GetFunctionNames()
{
OpenApiDocument doc = Helpers.ReadSwagger(@"Swagger\Azure Cognitive Service for Language.json");
OpenApiDocument doc = Helpers.ReadSwagger(@"Swagger\Azure Cognitive Service for Language.json", _output);
// OpenAPI spec: Info.Title is required
Assert.Equal("Azure Cognitive Service for Language", doc.Info.Title);
@ -51,7 +51,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact]
public void ACSL_GetFunctionNames22()
{
OpenApiDocument doc = Helpers.ReadSwagger(@"Swagger\Azure Cognitive Service for Language v2.2.json");
OpenApiDocument doc = Helpers.ReadSwagger(@"Swagger\Azure Cognitive Service for Language v2.2.json", _output);
List<ConnectorFunction> functions = OpenApiParser.GetFunctions("ACSL", doc, new ConsoleLogger(_output)).OrderBy(cf => cf.Name).ToList();
ConnectorFunction detectSentimentV3 = functions.First(cf => cf.Name == "DetectSentimentV3");
@ -62,7 +62,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact]
public void ACSL_Load()
{
OpenApiDocument doc = Helpers.ReadSwagger(@"Swagger\Azure Cognitive Service for Language.json");
OpenApiDocument doc = Helpers.ReadSwagger(@"Swagger\Azure Cognitive Service for Language.json", _output);
(List<ConnectorFunction> connectorFunctions, List<ConnectorTexlFunction> texlFunctions) = OpenApiParser.ParseInternal(new ConnectorSettings("ACSL"), doc, new ConsoleLogger(_output));
Assert.Contains(connectorFunctions, func => func.Namespace == "ACSL" && func.Name == "ConversationAnalysisAnalyzeConversationConversation");
Assert.Contains(texlFunctions, func => func.Namespace.Name.Value == "ACSL" && func.Name == "ConversationAnalysisAnalyzeConversationConversation");
@ -83,7 +83,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact]
public void SF_TextCsv()
{
OpenApiDocument doc = Helpers.ReadSwagger(@"Swagger\SalesForce.json");
OpenApiDocument doc = Helpers.ReadSwagger(@"Swagger\SalesForce.json", _output);
(List<ConnectorFunction> connectorFunctions, List<ConnectorTexlFunction> texlFunctions) = OpenApiParser.ParseInternal(new ConnectorSettings("SF") { Compatibility = ConnectorCompatibility.SwaggerCompatibility }, doc, new ConsoleLogger(_output));
// function returns text/csv
@ -99,7 +99,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact]
public void ACSL_GetFunctionParameters_PowerAppsCompatibility()
{
OpenApiDocument doc = Helpers.ReadSwagger(@"Swagger\Azure Cognitive Service for Language.json");
OpenApiDocument doc = Helpers.ReadSwagger(@"Swagger\Azure Cognitive Service for Language.json", _output);
ConnectorFunction function = OpenApiParser.GetFunctions(new ConnectorSettings("ACSL") { Compatibility = ConnectorCompatibility.PowerAppsCompatibility }, doc).OrderBy(cf => cf.Name).ToList()[14];
Assert.Equal("ConversationAnalysisAnalyzeConversationConversation", function.Name);
@ -212,7 +212,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact]
public void ACSL_GetFunctionParameters_SwaggerCompatibility()
{
OpenApiDocument doc = Helpers.ReadSwagger(@"Swagger\Azure Cognitive Service for Language.json");
OpenApiDocument doc = Helpers.ReadSwagger(@"Swagger\Azure Cognitive Service for Language.json", _output);
ConnectorFunction function = OpenApiParser.GetFunctions(new ConnectorSettings("ACSL") { Compatibility = ConnectorCompatibility.SwaggerCompatibility }, doc).OrderBy(cf => cf.Name).ToList()[14];
Assert.Equal("ConversationAnalysisAnalyzeConversationConversation", function.Name);
@ -320,7 +320,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact]
public async Task ACSL_InvokeFunction()
{
using var testConnector = new LoggingTestServer(@"Swagger\Azure Cognitive Service for Language.json");
using var testConnector = new LoggingTestServer(@"Swagger\Azure Cognitive Service for Language.json", _output);
OpenApiDocument apiDoc = testConnector._apiDocument;
ConsoleLogger logger = new ConsoleLogger(_output);
@ -351,7 +351,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
client.Dispose();
testConnector.Dispose();
using var testConnector2 = new LoggingTestServer(@"Swagger\Azure Cognitive Service for Language.json");
using var testConnector2 = new LoggingTestServer(@"Swagger\Azure Cognitive Service for Language.json", _output);
using var httpClient2 = new HttpClient(testConnector2);
testConnector2.SetResponseFromFile(@"Responses\Azure Cognitive Service for Language_Response.json");
using PowerPlatformConnectorClient client2 = new PowerPlatformConnectorClient("https://lucgen-apim.azure-api.net", "aaa373836ffd4915bf6eefd63d164adc" /* environment Id */, "16e7c181-2f8d-4cae-b1f0-179c5c4e4d8b" /* connectionId */, () => "No Auth", httpClient2)
@ -407,7 +407,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact]
public async Task AzureOpenAiGetFunctions()
{
using var testConnector = new LoggingTestServer(@"Swagger\Azure Open AI.json");
using var testConnector = new LoggingTestServer(@"Swagger\Azure Open AI.json", _output);
OpenApiDocument apiDoc = testConnector._apiDocument;
PowerFxConfig pfxConfig = new PowerFxConfig(Features.PowerFxV1);
@ -426,7 +426,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact]
public async Task ACSL_InvokeFunction_v21()
{
using var testConnector = new LoggingTestServer(@"Swagger\Azure Cognitive Service for Language v2.1.json");
using var testConnector = new LoggingTestServer(@"Swagger\Azure Cognitive Service for Language v2.1.json", _output);
OpenApiDocument apiDoc = testConnector._apiDocument;
ConsoleLogger logger = new ConsoleLogger(_output);
@ -636,7 +636,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact]
public void LQA_Load()
{
OpenApiDocument doc = Helpers.ReadSwagger(@"Swagger\Language - Question Answering.json");
OpenApiDocument doc = Helpers.ReadSwagger(@"Swagger\Language - Question Answering.json", _output);
(List<ConnectorFunction> connectorFunctions, List<ConnectorTexlFunction> texlFunctions) = OpenApiParser.ParseInternal(new ConnectorSettings("LQA"), doc, new ConsoleLogger(_output));
Assert.Contains(texlFunctions, func => func.Namespace.Name.Value == "LQA" && func.Name == "GetAnswersFromText");
}
@ -644,7 +644,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact]
public void SQL_Load()
{
OpenApiDocument doc = Helpers.ReadSwagger(@"Swagger\SQL Server.json");
OpenApiDocument doc = Helpers.ReadSwagger(@"Swagger\SQL Server.json", _output);
(List<ConnectorFunction> connectorFunctions, List<ConnectorTexlFunction> texlFunctions) = OpenApiParser.ParseInternal(new ConnectorSettings("SQL") { IncludeInternalFunctions = true }, doc, new ConsoleLogger(_output));
Assert.Contains(texlFunctions, func => func.Namespace.Name.Value == "SQL" && func.Name == "GetProcedureV2");
}
@ -652,7 +652,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact]
public void Dataverse_Sample()
{
OpenApiDocument doc = Helpers.ReadSwagger(@"Swagger\DataverseSample.json");
OpenApiDocument doc = Helpers.ReadSwagger(@"Swagger\DataverseSample.json", _output);
ConnectorFunction[] functions = OpenApiParser.GetFunctions("DV", doc, new ConsoleLogger(_output)).ToArray();
Assert.NotNull(functions);
@ -704,7 +704,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact]
public void VisibilityTest()
{
OpenApiDocument doc = Helpers.ReadSwagger(@"Swagger\AzureBlobStorage.json");
OpenApiDocument doc = Helpers.ReadSwagger(@"Swagger\AzureBlobStorage.json", _output);
ConnectorFunction[] functions = OpenApiParser.GetFunctions("AzBlob", doc, new ConsoleLogger(_output)).ToArray();
ConnectorFunction createFileV2 = functions.First(f => f.Name == "CreateFileV2");
@ -742,7 +742,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
public void DynamicReturnValueTest()
{
using HttpClient httpClient = new ();
OpenApiDocument doc = Helpers.ReadSwagger(@"Swagger\SQL Server.json");
OpenApiDocument doc = Helpers.ReadSwagger(@"Swagger\SQL Server.json", _output);
ConnectorFunction[] functions = OpenApiParser.GetFunctions("SQL", doc, new ConsoleLogger(_output)).ToArray();
ConnectorFunction createFileV2 = functions.First(f => f.Name == "ExecuteProcedureV2");
@ -797,7 +797,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact]
public async Task DirectIntellisenseTest()
{
using var testConnector = new LoggingTestServer(@"Swagger\SQL Server.json");
using var testConnector = new LoggingTestServer(@"Swagger\SQL Server.json", _output);
using var httpClient = new HttpClient(testConnector);
using PowerPlatformConnectorClient client = new PowerPlatformConnectorClient("https://tip1002-002.azure-apihub.net", "ddadf2c7-ebdd-ec01-a5d1-502dc07f04b4" /* environment Id */, "4bf9a87fc9054b6db3a4d07a1c1f5a5b" /* connectionId */, () => "eyJ0eXAi...", httpClient) { SessionId = "a41bd03b-6c3c-4509-a844-e8c51b61f878" };
@ -909,7 +909,7 @@ POST https://tip1002-002.azure-apihub.net/invoke
[Fact]
public async Task DataverseTest()
{
using var testConnector = new LoggingTestServer(@"Swagger\Dataverse.json");
using var testConnector = new LoggingTestServer(@"Swagger\Dataverse.json", _output);
using var httpClient = new HttpClient(testConnector);
using PowerPlatformConnectorClient client = new PowerPlatformConnectorClient("https://tip1-shared.azure-apim.net", "Default-9f6be790-4a16-4dd6-9850-44a0d2649aef" /* environment Id */, "461a30624723445c9ba87313d8bbefa3" /* connectionId */, () => "eyJ0eXAiO...", httpClient) { SessionId = "a41bd03b-6c3c-4509-a844-e8c51b61f878" };
@ -986,7 +986,7 @@ POST https://tip1-shared.azure-apim.net/invoke
public async Task DataverseTest2(string swaggerFile)
{
PowerFxConfig powerFxConfig = new PowerFxConfig();
OpenApiDocument doc = Helpers.ReadSwagger(swaggerFile);
OpenApiDocument doc = Helpers.ReadSwagger(swaggerFile, _output);
OpenApiParser.GetFunctions("namespace", doc); // missing logger
powerFxConfig.AddActionConnector("namespace", doc);
@ -995,7 +995,7 @@ POST https://tip1-shared.azure-apim.net/invoke
[Fact]
public async Task CardsForPowerApps_Invoke()
{
using var testConnector = new LoggingTestServer(@"Swagger\CardsForPowerApps.json");
using var testConnector = new LoggingTestServer(@"Swagger\CardsForPowerApps.json", _output);
using var httpClient = new HttpClient(testConnector);
using PowerPlatformConnectorClient client = new PowerPlatformConnectorClient("https://tip1002-002.azure-apihub.net", "7592282b-e371-e3f6-8e04-e8f23e64227c" /* environment Id */, "shared-cardsforpower-eafc4fa0-c560-4eba-a5b2-3e1ebc63193a" /* connectionId */, () => "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dC...", httpClient) { SessionId = "a41bd03b-6c3c-4509-a844-e8c51b61f878" };
@ -1044,7 +1044,7 @@ POST https://tip1-shared.azure-apim.net/invoke
[Fact]
public async Task CardsForPowerApps_Suggestion()
{
using var testConnector = new LoggingTestServer(@"Swagger\CardsForPowerApps.json");
using var testConnector = new LoggingTestServer(@"Swagger\CardsForPowerApps.json", _output);
using var httpClient = new HttpClient(testConnector);
using PowerPlatformConnectorClient client = new PowerPlatformConnectorClient("https://tip1002-002.azure-apihub.net", "7592282b-e371-e3f6-8e04-e8f23e64227c" /* environment Id */, "shared-cardsforpower-eafc4fa0-c560-4eba-a5b2-3e1ebc63193a" /* connectionId */, () => "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dC...", httpClient) { SessionId = "a41bd03b-6c3c-4509-a844-e8c51b61f878" };
@ -1071,7 +1071,7 @@ POST https://tip1-shared.azure-apim.net/invoke
[Fact]
public async Task Teams_GetMessageDetails_WithComplexParameterReference()
{
using var testConnector = new LoggingTestServer(@"Swagger\Teams.json");
using var testConnector = new LoggingTestServer(@"Swagger\Teams.json", _output);
using var httpClient = new HttpClient(testConnector);
using PowerPlatformConnectorClient client = new PowerPlatformConnectorClient("https://tip1002-002.azure-apihub.net", "7592282b-e371-e3f6-8e04-e8f23e64227c" /* environment Id */, "shared-cardsforpower-eafc4fa0-c560-4eba-a5b2-3e1ebc63193a" /* connectionId */, () => "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dC...", httpClient) { SessionId = "a41bd03b-6c3c-4509-a844-e8c51b61f878" };

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

@ -44,7 +44,7 @@ namespace Microsoft.PowerFx.Tests
[InlineData(false)]
public async Task MSNWeatherConnector_CurrentWeather(bool useSwaggerParameter)
{
using var testConnector = new LoggingTestServer(@"Swagger\MSNWeather.json");
using var testConnector = new LoggingTestServer(@"Swagger\MSNWeather.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig();
@ -117,7 +117,7 @@ namespace Microsoft.PowerFx.Tests
[InlineData(502, "Bad Gateway")]
public async Task Connector_GenerateErrors(int statusCode, string reasonPhrase)
{
using var testConnector = new LoggingTestServer(@"Swagger\TestConnector12.json");
using var testConnector = new LoggingTestServer(@"Swagger\TestConnector12.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig();
@ -209,7 +209,7 @@ namespace Microsoft.PowerFx.Tests
[InlineData(false, true)]
public async Task AzureBlobConnector_UploadFile(bool useSwaggerParameter, bool useHttpsPrefix)
{
using var testConnector = new LoggingTestServer(@"Swagger\AzureBlobStorage.json");
using var testConnector = new LoggingTestServer(@"Swagger\AzureBlobStorage.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig();
var token = @"eyJ0eX...";
@ -280,7 +280,7 @@ namespace Microsoft.PowerFx.Tests
[Fact]
public async Task AzureBlobConnector_UseOfDeprecatedFunction()
{
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\AzureBlobStorage.json");
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\AzureBlobStorage.json", _output);
OpenApiDocument apiDoc = testConnector._apiDocument;
PowerFxConfig config = new PowerFxConfig();
string token = @"eyJ0eXAi...";
@ -321,7 +321,7 @@ namespace Microsoft.PowerFx.Tests
[Fact]
public async Task AzureBlobConnector_Paging()
{
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\AzureBlobStorage.json");
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\AzureBlobStorage.json", _output);
OpenApiDocument apiDoc = testConnector._apiDocument;
PowerFxConfig config = new PowerFxConfig();
string token = @"eyJ0eX...";
@ -350,7 +350,7 @@ namespace Microsoft.PowerFx.Tests
[InlineData("Office365Outlook.FindMeetingTimesV2(")]
public void IntellisenseHelpStringsOptionalParms(string expr)
{
var apiDocOutlook = Helpers.ReadSwagger(@"Swagger\Office_365_Outlook.json");
var apiDocOutlook = Helpers.ReadSwagger(@"Swagger\Office_365_Outlook.json", _output);
var config = new PowerFxConfig();
config.AddActionConnector("Office365Outlook", apiDocOutlook, new ConsoleLogger(_output));
@ -372,7 +372,7 @@ namespace Microsoft.PowerFx.Tests
[InlineData("Behavior(); MSNWeather.CurrentWeather(", false, true)]
public void IntellisenseHelpStrings(string expr, bool withAllowSideEffects, bool expectedBehaviorError)
{
var apiDoc = Helpers.ReadSwagger(@"Swagger\MSNWeather.json");
var apiDoc = Helpers.ReadSwagger(@"Swagger\MSNWeather.json", _output);
var config = new PowerFxConfig();
config.AddActionConnector("MSNWeather", apiDoc, new ConsoleLogger(_output));
@ -447,7 +447,7 @@ namespace Microsoft.PowerFx.Tests
Assert.NotNull(ppcl2);
Assert.Equal("firstrelease-001.azure-apim.net:117", ppcl2.Endpoint);
using var testConnector = new LoggingTestServer(@"Swagger\AzureBlobStorage.json");
using var testConnector = new LoggingTestServer(@"Swagger\AzureBlobStorage.json", _output);
var apiDoc = testConnector._apiDocument;
using var ppcl3 = new PowerPlatformConnectorClient(
@ -460,7 +460,7 @@ namespace Microsoft.PowerFx.Tests
Assert.NotNull(ppcl3);
Assert.Equal("localhost:23340", ppcl3.Endpoint);
using var testConnector2 = new LoggingTestServer(@"Swagger\TestOpenAPI.json");
using var testConnector2 = new LoggingTestServer(@"Swagger\TestOpenAPI.json", _output);
var apiDoc2 = testConnector2._apiDocument;
var ex2 = Assert.Throws<PowerFxConnectorException>(() => new PowerPlatformConnectorClient(
@ -476,7 +476,7 @@ namespace Microsoft.PowerFx.Tests
[Fact]
public async Task Office365Users_UserProfile_V2()
{
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Users.json");
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Users.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig();
@ -507,7 +507,7 @@ namespace Microsoft.PowerFx.Tests
[Fact]
public async Task Office365Users_MyProfile_V2()
{
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Users.json");
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Users.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig();
@ -537,7 +537,7 @@ namespace Microsoft.PowerFx.Tests
[Fact]
public async Task Office365Users_DirectReports_V2()
{
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Users.json");
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Users.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig();
@ -567,7 +567,7 @@ namespace Microsoft.PowerFx.Tests
[Fact]
public async Task Office365Users_SearchUsers_V2()
{
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Users.json");
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Users.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig();
@ -597,7 +597,7 @@ namespace Microsoft.PowerFx.Tests
[Fact]
public async Task Office365Users_UseDates()
{
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Outlook.json");
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Outlook.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig();
@ -638,7 +638,7 @@ namespace Microsoft.PowerFx.Tests
[Fact]
public async Task Office365Outlook_GetEmailsV2()
{
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Outlook.json");
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Outlook.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig();
@ -690,7 +690,7 @@ namespace Microsoft.PowerFx.Tests
[InlineData(2, @"Office365Outlook.V4CalendarPostItem(""Calendar"", ""Subject"", DateTime(2023, 6, 2, 11, 00, 00), DateTime(2023, 6, 2, 11, 30, 00), ""(UTC+01:00) Brussels, Copenhagen, Madrid, Paris"")")]
public async Task Office365Outlook_V4CalendarPostItem(int id, string expr)
{
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Outlook.json");
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Outlook.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig();
@ -741,7 +741,7 @@ namespace Microsoft.PowerFx.Tests
[Fact]
public async Task Office365Outlook_ExportEmailV2()
{
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Outlook.json");
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Outlook.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig();
@ -786,7 +786,7 @@ namespace Microsoft.PowerFx.Tests
[Fact]
public async Task Office365Outlook_FindMeetingTimesV2()
{
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Outlook.json");
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Outlook.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig();
@ -833,7 +833,7 @@ namespace Microsoft.PowerFx.Tests
[Fact]
public async Task Office365Outlook_FlagV2()
{
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Outlook.json");
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Outlook.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig();
@ -880,7 +880,7 @@ namespace Microsoft.PowerFx.Tests
[Fact]
public async Task Office365Outlook_GetMailTipsV2()
{
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Outlook.json");
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Outlook.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig();
@ -927,7 +927,7 @@ namespace Microsoft.PowerFx.Tests
[Fact]
public async Task Office365Outlook_GetRoomListsV2()
{
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Outlook.json");
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Outlook.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig();
@ -975,7 +975,7 @@ namespace Microsoft.PowerFx.Tests
[Fact]
public async Task Office365Outlook_Load()
{
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Outlook.json");
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Outlook.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig();
@ -1010,7 +1010,7 @@ namespace Microsoft.PowerFx.Tests
[Fact]
public async Task Office365Outlook_GetRooms()
{
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Outlook.json");
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Outlook.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(Features.PowerFxV1);
@ -1060,7 +1060,7 @@ namespace Microsoft.PowerFx.Tests
[Fact]
public async Task BingMaps_GetRouteV3()
{
using var testConnector = new LoggingTestServer(@"Swagger\Bing_Maps.json");
using var testConnector = new LoggingTestServer(@"Swagger\Bing_Maps.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig();
@ -1108,7 +1108,7 @@ namespace Microsoft.PowerFx.Tests
[Fact]
public async Task SQL_GetStoredProcs()
{
using var testConnector = new LoggingTestServer(@"Swagger\SQL Server.json");
using var testConnector = new LoggingTestServer(@"Swagger\SQL Server.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(Features.PowerFxV1);
@ -1157,7 +1157,7 @@ namespace Microsoft.PowerFx.Tests
[Fact]
public async Task SQL_ExecuteStoredProc()
{
using var testConnector = new LoggingTestServer(@"Swagger\SQL Server.json");
using var testConnector = new LoggingTestServer(@"Swagger\SQL Server.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(Features.PowerFxV1);
@ -1206,7 +1206,7 @@ namespace Microsoft.PowerFx.Tests
[Fact]
public async Task SQL_ExecuteStoredProc_WithUserAgent()
{
using var testConnector = new LoggingTestServer(@"Swagger\SQL Server.json");
using var testConnector = new LoggingTestServer(@"Swagger\SQL Server.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(Features.PowerFxV1);
@ -1256,7 +1256,7 @@ namespace Microsoft.PowerFx.Tests
[Fact]
public async Task SharePointOnlineTest()
{
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\SharePoint.json");
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\SharePoint.json", _output);
OpenApiDocument apiDoc = testConnector._apiDocument;
PowerFxConfig config = new PowerFxConfig();
string token = @"eyJ0eXA...";
@ -1367,7 +1367,7 @@ POST https://tip1-shared-002.azure-apim.net/invoke
[Fact]
public async Task ExcelOnlineTest()
{
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\ExcelOnlineBusiness.swagger.json");
using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\ExcelOnlineBusiness.swagger.json", _output);
OpenApiDocument apiDoc = testConnector._apiDocument;
PowerFxConfig config = new PowerFxConfig();
string token = @"eyJ0eXAiOiJ...";
@ -1430,7 +1430,7 @@ POST https://tip1-shared-002.azure-apim.net/invoke
[Fact]
public async Task DataverseTest_WithComplexMapping()
{
using var testConnector = new LoggingTestServer(@"Swagger\Dataverse.json");
using var testConnector = new LoggingTestServer(@"Swagger\Dataverse.json", _output);
using var httpClient = new HttpClient(testConnector);
using PowerPlatformConnectorClient client = new PowerPlatformConnectorClient("https://tip1002-002.azure-apihub.net", "b29c41cf-173b-e469-830b-4f00163d296b" /* environment Id */, "82728ddb6bfa461ea3e50e17da8ab164" /* connectionId */, () => "eyJ0eXAiOiJKV1QiLCJ...", httpClient) { SessionId = "a41bd03b-6c3c-4509-a844-e8c51b61f878" };
@ -1478,7 +1478,7 @@ POST https://tip1-shared-002.azure-apim.net/invoke
[InlineData(ConnectorCompatibility.SwaggerCompatibility, "Office365Users.SearchUserV2(", "SearchUserV2({ searchTerm:String,top:Decimal,isSearchTermRequired:Boolean })")]
public async Task ConnectorCompatibilityIntellisenseTest(ConnectorCompatibility compact, string expression, string expected)
{
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Users.json");
using var testConnector = new LoggingTestServer(@"Swagger\Office_365_Users.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig();

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

@ -117,6 +117,12 @@ namespace Microsoft.PowerFx.TexlFunctionExporter
try
{
OpenApiDocument doc = ReadSwagger(swaggerFile);
if (doc == null || doc.Info == null)
{
return;
}
string title = doc.Info.Title;
var item = (folder, swaggerFile, doc);
@ -136,17 +142,8 @@ namespace Microsoft.PowerFx.TexlFunctionExporter
public static OpenApiDocument ReadSwagger(string name)
{
using (var stream = File.OpenRead(name))
{
var doc = new OpenApiStreamReader().Read(stream, out OpenApiDiagnostic diag);
if ((doc == null || doc.Paths == null || doc.Paths.Count == 0) && diag != null && diag.Errors.Count > 0)
{
throw new InvalidDataException($"Unable to parse Swagger file: {string.Join(", ", diag.Errors.Select(err => err.Message))}");
}
return doc;
}
using FileStream stream = File.OpenRead(name);
return new OpenApiStreamReader().Read(stream, out OpenApiDiagnostic diag);
}
}