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 # global.json
/src/global.json /src/global.json
/global.json /global.json
# Guardian results
.gdn/r
.gdn/internal.gdnhistory
# Yaml output
YamlOutput/

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

@ -2,11 +2,10 @@
setlocal enabledelayedexpansion 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 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
@REM Restore dependencies first if needed "%MSBUILD%" -t:restore
"%%i" -t:restore
@REM Run build and generate nuget packages @REM Run build and generate nuget packages
"%%i" %MSBUILDARGS% "%MSBUILD%" %MSBUILDARGS%
exit /b !errorlevel!
)

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

@ -773,23 +773,22 @@ namespace Microsoft.PowerFx.Connectors
// https://learn.microsoft.com/en-us/connectors/custom-connectors/openapi-extensions#use-dynamic-values // 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 (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) // 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 (opPrms); ConnectorDynamicValue cdv = new (op_prms);
// Mandatory operationId for connectors, except when capibility or builtInOperation are defined // Mandatory operationId for connectors, except when capibility or builtInOperation are defined
apiObj.WhenPresent("operationId", (opId) => cdv.OperationId = OpenApiHelperFunctions.NormalizeOperationId(opId)); apiObj.WhenPresent("operationId", (opId) => cdv.OperationId = OpenApiHelperFunctions.NormalizeOperationId(opId));
apiObj.WhenPresent("value-title", (opValTitle) => cdv.ValueTitle = opValTitle); apiObj.WhenPresent("value-title", (opValTitle) => cdv.ValueTitle = opValTitle);
apiObj.WhenPresent("value-path", (opValPath) => cdv.ValuePath = opValPath); apiObj.WhenPresent("value-path", (opValPath) => cdv.ValuePath = opValPath);
apiObj.WhenPresent("value-collection", (opValCollection) => cdv.ValueCollection = opValCollection); apiObj.WhenPresent("value-collection", (opValCollection) => cdv.ValueCollection = opValCollection);
// we don't support BuiltInOperations or capabilities right now // we don't support BuiltInOperations or capabilities right now
// return null to indicate that the call to get suggestions is not needed for this parameter // return null to indicate that the call to get suggestions is not needed for this parameter
apiObj.WhenPresent("capability", (string op_capStr) => cdv = null); apiObj.WhenPresent("capability", (string op_capStr) => cdv = null);
apiObj.WhenPresent("builtInOperation", (string op_bioStr) => cdv = null); apiObj.WhenPresent("builtInOperation", (string op_bioStr) => cdv = null);
return cdv; return cdv;
}
} }
return null; return null;
@ -800,33 +799,32 @@ namespace Microsoft.PowerFx.Connectors
// https://learn.microsoft.com/en-us/connectors/custom-connectors/openapi-extensions#use-dynamic-values // 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) 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("operationId", out IOpenApiAny op_id) && op_id is OpenApiString opId)
{ {
if (apiObj.TryGetValue("parameters", out IOpenApiAny op_prms) && op_prms is OpenApiObject 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)
{ {
ConnectorDynamicList cdl = new (opPrms) OperationId = OpenApiHelperFunctions.NormalizeOperationId(opId.Value),
{ };
OperationId = OpenApiHelperFunctions.NormalizeOperationId(opId.Value),
};
if (apiObj.TryGetValue("itemTitlePath", out IOpenApiAny op_valtitle) && op_valtitle is OpenApiString opValTitle) if (apiObj.TryGetValue("itemTitlePath", out IOpenApiAny op_valtitle) && op_valtitle is OpenApiString opValTitle)
{ {
cdl.ItemTitlePath = opValTitle.Value; cdl.ItemTitlePath = opValTitle.Value;
}
if (apiObj.TryGetValue("itemsPath", out IOpenApiAny op_valpath) && op_valpath is OpenApiString opValPath)
{
cdl.ItemPath = opValPath.Value;
}
if (apiObj.TryGetValue("itemValuePath", out IOpenApiAny op_valcoll) && op_valcoll is OpenApiString opValCollection)
{
cdl.ItemValuePath = opValCollection.Value;
}
return cdl;
} }
if (apiObj.TryGetValue("itemsPath", out IOpenApiAny op_valpath) && op_valpath is OpenApiString opValPath)
{
cdl.ItemPath = opValPath.Value;
}
if (apiObj.TryGetValue("itemValuePath", out IOpenApiAny op_valcoll) && op_valcoll is OpenApiString opValCollection)
{
cdl.ItemValuePath = opValCollection.Value;
}
return cdl;
} }
else else
{ {
@ -839,7 +837,12 @@ namespace Microsoft.PowerFx.Connectors
internal static Dictionary<string, IConnectorExtensionValue> GetParameterMap(this OpenApiObject opPrms, SupportsConnectorErrors errors, bool forceString = false) internal static Dictionary<string, IConnectorExtensionValue> GetParameterMap(this OpenApiObject opPrms, SupportsConnectorErrors errors, bool forceString = false)
{ {
Dictionary<string, IConnectorExtensionValue> dvParams = new (); Dictionary<string, IConnectorExtensionValue> dvParams = new ();
if (opPrms == null)
{
return dvParams;
}
foreach (KeyValuePair<string, IOpenApiAny> prm in opPrms) foreach (KeyValuePair<string, IOpenApiAny> prm in opPrms)
{ {
@ -907,23 +910,23 @@ namespace Microsoft.PowerFx.Connectors
// https://learn.microsoft.com/en-us/connectors/custom-connectors/openapi-extensions#use-dynamic-values // 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) 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("operationId", out IOpenApiAny op_id) && op_id is OpenApiString opId)
{ {
if (apiObj.TryGetValue("parameters", out IOpenApiAny op_prms) && op_prms is OpenApiObject 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)
{ {
ConnectorDynamicSchema cds = new (opPrms) OperationId = OpenApiHelperFunctions.NormalizeOperationId(opId.Value),
{ };
OperationId = OpenApiHelperFunctions.NormalizeOperationId(opId.Value),
};
if (apiObj.TryGetValue("value-path", out IOpenApiAny op_valpath) && op_valpath is OpenApiString opValPath) if (apiObj.TryGetValue("value-path", out IOpenApiAny op_valpath) && op_valpath is OpenApiString opValPath)
{ {
cds.ValuePath = opValPath.Value; cds.ValuePath = opValPath.Value;
}
return cds;
} }
return cds;
} }
else else
{ {
@ -939,23 +942,23 @@ namespace Microsoft.PowerFx.Connectors
// https://learn.microsoft.com/en-us/connectors/custom-connectors/openapi-extensions#use-dynamic-values // 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) 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("operationId", out IOpenApiAny op_id) && op_id is OpenApiString opId)
{ {
if (apiObj.TryGetValue("parameters", out IOpenApiAny op_prms) && op_prms is OpenApiObject 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)
{ {
ConnectorDynamicProperty cdp = new (opPrms) OperationId = OpenApiHelperFunctions.NormalizeOperationId(opId.Value),
{ };
OperationId = OpenApiHelperFunctions.NormalizeOperationId(opId.Value),
};
if (apiObj.TryGetValue("itemValuePath", out IOpenApiAny op_valpath) && op_valpath is OpenApiString opValPath) if (apiObj.TryGetValue("itemValuePath", out IOpenApiAny op_valpath) && op_valpath is OpenApiString opValPath)
{ {
cdp.ItemValuePath = opValPath.Value; cdp.ItemValuePath = opValPath.Value;
}
return cdp;
} }
return cdp;
} }
else else
{ {

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

@ -84,7 +84,7 @@ namespace Microsoft.PowerFx.Connectors
{ {
configurationLogger?.LogError($"{nameof(openApiDocument)} is null"); configurationLogger?.LogError($"{nameof(openApiDocument)} is null");
return functions; return functions;
} }
if (!ValidateSupportedOpenApiDocument(openApiDocument, ref connectorIsSupported, ref connectorNotSupportedReason, connectorSettings.FailOnUnknownExtension, configurationLogger)) if (!ValidateSupportedOpenApiDocument(openApiDocument, ref connectorIsSupported, ref connectorNotSupportedReason, connectorSettings.FailOnUnknownExtension, configurationLogger))
{ {
@ -260,7 +260,11 @@ namespace Microsoft.PowerFx.Connectors
// openApiDocument.Components.RequestBodies is ok // openApiDocument.Components.RequestBodies is ok
// openApiDocument.Components.Responses contains references from "path" definitions // openApiDocument.Components.Responses contains references from "path" definitions
// openApiDocument.Components.Schemas contains global "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) if (isSupported && failOnUnknownExtensions)

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

@ -23,12 +23,12 @@ namespace Microsoft.PowerFx.Connectors.Tests
{ {
public abstract class BaseConnectorTest : PowerFxTest, IDisposable public abstract class BaseConnectorTest : PowerFxTest, IDisposable
{ {
internal ITestOutputHelper _output; internal ITestOutputHelper _output;
internal string _swaggerFile; internal string _swaggerFile;
private bool _disposedValue; private bool _disposedValue;
public BaseConnectorTest(ITestOutputHelper output, string swaggerFile) public BaseConnectorTest(ITestOutputHelper output, string swaggerFile)
{ {
_swaggerFile = swaggerFile; _swaggerFile = swaggerFile;
_output = output; _output = output;
} }
@ -43,11 +43,11 @@ namespace Microsoft.PowerFx.Connectors.Tests
public virtual ConnectorSettings GetConnectorSettings(bool returnUnknownRecordFieldsAsUntypedObjects = false) public virtual ConnectorSettings GetConnectorSettings(bool returnUnknownRecordFieldsAsUntypedObjects = false)
{ {
return new ConnectorSettings(GetNamespace()) return new ConnectorSettings(GetNamespace())
{ {
Compatibility = returnUnknownRecordFieldsAsUntypedObjects ? ConnectorCompatibility.SwaggerCompatibility : ConnectorCompatibility.PowerAppsCompatibility, Compatibility = returnUnknownRecordFieldsAsUntypedObjects ? ConnectorCompatibility.SwaggerCompatibility : ConnectorCompatibility.PowerAppsCompatibility,
IncludeInternalFunctions = true, IncludeInternalFunctions = true,
ReturnUnknownRecordFieldsAsUntypedObjects = returnUnknownRecordFieldsAsUntypedObjects ReturnUnknownRecordFieldsAsUntypedObjects = returnUnknownRecordFieldsAsUntypedObjects
}; };
} }
@ -73,10 +73,10 @@ 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) 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); HttpClient httpClient = new HttpClient(testConnector);
PowerPlatformConnectorClient client = new PowerPlatformConnectorClient(GetEndpoint(), GetEnvironment(), GetConnectionId(), () => GetJWTToken(), httpClient) { SessionId = "9315f316-5182-4260-b333-7a43a36ca3b0" }; PowerPlatformConnectorClient client = new PowerPlatformConnectorClient(GetEndpoint(), GetEnvironment(), GetConnectionId(), () => GetJWTToken(), httpClient) { SessionId = "9315f316-5182-4260-b333-7a43a36ca3b0" };
PowerFxConfig config = new PowerFxConfig(); PowerFxConfig config = new PowerFxConfig();
OpenApiDocument apiDoc = testConnector._apiDocument; OpenApiDocument apiDoc = testConnector._apiDocument;
ConnectorSettings connectorSettings = GetConnectorSettings(returnUO); ConnectorSettings connectorSettings = GetConnectorSettings(returnUO);
@ -108,7 +108,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
: ($@"Responses\{ef.Substring(4)}", (HttpStatusCode)int.Parse(ef.Substring(0, 3)))).ToArray()); : ($@"Responses\{ef.Substring(4)}", (HttpStatusCode)int.Parse(ef.Substring(0, 3)))).ToArray());
} }
FormulaValue fv = await engine.EvalAsync(expr, CancellationToken.None, options: new ParserOptions() { AllowsSideEffects = true }, runtimeConfig: runtimeConfig).ConfigureAwait(false); FormulaValue fv = await engine.EvalAsync(expr, CancellationToken.None, options: new ParserOptions() { AllowsSideEffects = true }, runtimeConfig: runtimeConfig).ConfigureAwait(false);
string network = testConnector._log.ToString(); string network = testConnector._log.ToString();
string urls = string.Join("|", Regex.Matches(network, @"x-ms-request-method: (?<r>[^ \r\n]+)\s*x-ms-request-url: (?<u>[^ \r\n]+)").Select(g => $"{g.Groups["r"].Value}:{g.Groups["u"].Value}")); string urls = string.Join("|", Regex.Matches(network, @"x-ms-request-method: (?<r>[^ \r\n]+)\s*x-ms-request-url: (?<u>[^ \r\n]+)").Select(g => $"{g.Groups["r"].Value}:{g.Groups["u"].Value}"));
@ -150,7 +150,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
else if (expectedResult.StartsWith("DATETIME:")) else if (expectedResult.StartsWith("DATETIME:"))
{ {
Assert.True(fv is not ErrorValue, fv is ErrorValue ev ? $"EvalAsync Error: {string.Join(", ", ev.Errors.Select(er => er.Message))}" : null); Assert.True(fv is not ErrorValue, fv is ErrorValue ev ? $"EvalAsync Error: {string.Join(", ", ev.Errors.Select(er => er.Message))}" : null);
DateTimeValue dtv = Assert.IsType<DateTimeValue>(fv); DateTimeValue dtv = Assert.IsType<DateTimeValue>(fv);
Assert.Equal(DateTime.Parse(expectedResult.Substring(9)).ToUniversalTime(), new ConvertToUTC(GetTimeZoneInfo()).ToUTC(dtv)); Assert.Equal(DateTime.Parse(expectedResult.Substring(9)).ToUniversalTime(), new ConvertToUTC(GetTimeZoneInfo()).ToUTC(dtv));
} }
@ -171,8 +171,8 @@ namespace Microsoft.PowerFx.Connectors.Tests
} }
Assert.Equal(xUrls, urls); Assert.Equal(xUrls, urls);
Assert.Equal(xBodies, bodies); Assert.Equal(xBodies, bodies);
if (!string.IsNullOrEmpty(extra)) if (!string.IsNullOrEmpty(extra))
{ {
foreach (string e in extra.Split("|")) foreach (string e in extra.Split("|"))
@ -237,7 +237,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
if (!_disposedValue) if (!_disposedValue)
{ {
if (disposing) if (disposing)
{ {
} }
_disposedValue = true; _disposedValue = true;

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

@ -11,7 +11,6 @@ using System.Threading.Tasks;
using Microsoft.PowerFx.Connectors; using Microsoft.PowerFx.Connectors;
using Microsoft.PowerFx.Connectors.Tests; using Microsoft.PowerFx.Connectors.Tests;
using Microsoft.PowerFx.Core.Tests; using Microsoft.PowerFx.Core.Tests;
using Microsoft.VisualStudio.TestPlatform.Utilities;
using Xunit; using Xunit;
using Xunit.Abstractions; using Xunit.Abstractions;
@ -66,7 +65,7 @@ namespace Microsoft.PowerFx.Tests
var swaggerFile = @"Swagger\TestOpenAPI.json"; var swaggerFile = @"Swagger\TestOpenAPI.json";
Console.Write(i); Console.Write(i);
using var testConnector = new LoggingTestServer(swaggerFile); using var testConnector = new LoggingTestServer(swaggerFile, _output);
testConnector.SetResponseFromFile(@"Responses\HttpCall_1.json"); testConnector.SetResponseFromFile(@"Responses\HttpCall_1.json");
List<ConnectorFunction> functions = OpenApiParser.GetFunctions("Test", testConnector._apiDocument, new ConsoleLogger(_output)).OrderBy(cf => cf.Name).ToList(); List<ConnectorFunction> functions = OpenApiParser.GetFunctions("Test", testConnector._apiDocument, new ConsoleLogger(_output)).OrderBy(cf => cf.Name).ToList();
@ -82,7 +81,7 @@ namespace Microsoft.PowerFx.Tests
var checkResult = engine.Check(fxQuery, options: _optionsPost); var checkResult = engine.Check(fxQuery, options: _optionsPost);
Assert.True(checkResult.IsSuccess, string.Join("\r\n", checkResult.Errors.Select(er => er.Message))); Assert.True(checkResult.IsSuccess, string.Join("\r\n", checkResult.Errors.Select(er => er.Message)));
var rConfig = new RuntimeConfig(); var rConfig = new RuntimeConfig();
rConfig.SetTimeZone(TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time")); rConfig.SetTimeZone(TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"));
rConfig.AddRuntimeContext(new TestConnectorRuntimeContext("Test", httpClient, console: _output)); rConfig.AddRuntimeContext(new TestConnectorRuntimeContext("Test", httpClient, console: _output));
@ -105,7 +104,7 @@ namespace Microsoft.PowerFx.Tests
[Fact] [Fact]
public async Task BasicHttpCallNullInvoker() 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 config = new PowerFxConfig();
var apiDoc = testConnector._apiDocument; var apiDoc = testConnector._apiDocument;
@ -125,7 +124,7 @@ namespace Microsoft.PowerFx.Tests
public void BasicHttpBinding() public void BasicHttpBinding()
{ {
var config = new PowerFxConfig(); 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. // If we don't pass httpClient, we can still bind, we just can't invoke.
config.AddActionConnector("Test", apiDoc, new ConsoleLogger(_output)); config.AddActionConnector("Test", apiDoc, new ConsoleLogger(_output));
@ -139,7 +138,7 @@ namespace Microsoft.PowerFx.Tests
[Fact] [Fact]
public async Task PetStore_MultiServer() 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 apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(); var config = new PowerFxConfig();

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

@ -32,7 +32,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact] [Fact]
public async Task ConnectorWizardTest() 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 HttpClient httpClient = new HttpClient(testConnector);
using PowerPlatformConnectorClient client = new PowerPlatformConnectorClient( using PowerPlatformConnectorClient client = new PowerPlatformConnectorClient(
"tip1-shared-002.azure-apim.net", // endpoint "tip1-shared-002.azure-apim.net", // endpoint
@ -154,7 +154,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact] [Fact]
public async Task ConnectorWizardTest_InvalidToken() 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 HttpClient httpClient = new HttpClient(testConnector);
using PowerPlatformConnectorClient client = new PowerPlatformConnectorClient( using PowerPlatformConnectorClient client = new PowerPlatformConnectorClient(
"tip1-shared-002.azure-apim.net", // endpoint "tip1-shared-002.azure-apim.net", // endpoint
@ -167,7 +167,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
}; };
OpenApiDocument apiDoc = testConnector._apiDocument; OpenApiDocument apiDoc = testConnector._apiDocument;
IEnumerable<ConnectorFunction> functions = OpenApiParser.GetFunctions("SQL", apiDoc, new ConsoleLogger(_output)); IEnumerable<ConnectorFunction> functions = OpenApiParser.GetFunctions("SQL", apiDoc, new ConsoleLogger(_output));
ConnectorFunction executeProcedureV2 = functions.First(cf => cf.Name == "ExecuteProcedureV2"); ConnectorFunction executeProcedureV2 = functions.First(cf => cf.Name == "ExecuteProcedureV2");
BaseRuntimeConnectorContext context = new TestConnectorRuntimeContext("SQL", client, throwOnError: true, console: _output); BaseRuntimeConnectorContext context = new TestConnectorRuntimeContext("SQL", client, throwOnError: true, console: _output);

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

@ -10,16 +10,16 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Readers; using Microsoft.OpenApi.Readers;
using Microsoft.OpenApi.Validations;
using Microsoft.PowerFx.Core.Tests; using Microsoft.PowerFx.Core.Tests;
using Microsoft.PowerFx.Intellisense; using Microsoft.PowerFx.Intellisense;
using Microsoft.PowerFx.Types; using Microsoft.PowerFx.Types;
using Microsoft.VisualStudio.TestPlatform.Utilities;
using Xunit; using Xunit;
using Xunit.Abstractions; using Xunit.Abstractions;
namespace Microsoft.PowerFx.Connectors.Tests namespace Microsoft.PowerFx.Connectors.Tests
{ {
public class DynamicTests public class DynamicTests
{ {
public const string Host = @"http://localhost:5189"; public const string Host = @"http://localhost:5189";
public const string SwaggerFile = @"http://localhost:5189/swagger/v1/swagger.json"; public const string SwaggerFile = @"http://localhost:5189/swagger/v1/swagger.json";
@ -32,18 +32,35 @@ namespace Microsoft.PowerFx.Connectors.Tests
_output = output; _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; functions = null;
doc = null; doc = null;
try try
{ {
// lock managed by XUnit // lock managed by XUnit
if (!skip) if (!skip)
{ {
using WebClient webClient = new WebClient(); 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(); functions = OpenApiParser.GetFunctions("Test", doc, new ConsoleLogger(_output)).OrderBy(cf => cf.Name).ToList();
} }
} }
@ -80,7 +97,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[SkippableFact] [SkippableFact]
public async Task DynamicValues_GetWithDynamicValuesStatic_RequiredParameters() 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"); ConnectorFunction getWithDynamicValuesStatic = functions.First(cf => cf.Name == "GetWithDynamicValuesStatic");
Assert.True(getWithDynamicValuesStatic.RequiredParameters[0].SupportsDynamicIntellisense); Assert.True(getWithDynamicValuesStatic.RequiredParameters[0].SupportsDynamicIntellisense);
@ -89,7 +106,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
string expr = "Test.GetWithDynamicValuesStatic("; string expr = "Test.GetWithDynamicValuesStatic(";
CheckResult result = engine.Check(expr, symbolTable: null); CheckResult result = engine.Check(expr, symbolTable: null);
IIntellisenseResult suggestions = engine.Suggest(result, expr.Length, services); IIntellisenseResult suggestions = engine.Suggest(result, expr.Length, services);
Assert.Equal("14|24", string.Join("|", suggestions.Suggestions.Select(s => s.DisplayText.Text))); Assert.Equal("14|24", string.Join("|", suggestions.Suggestions.Select(s => s.DisplayText.Text)));
@ -100,7 +117,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[SkippableFact] [SkippableFact]
public async Task DynamicValues_GetWithDynamicValuesStatic_OptionalParameters() 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"); ConnectorFunction getWithDynamicValuesStaticOptional = functions.First(cf => cf.Name == "GetWithDynamicValuesStaticOptional");
Assert.True(getWithDynamicValuesStaticOptional.OptionalParameters[0].SupportsDynamicIntellisense); Assert.True(getWithDynamicValuesStaticOptional.OptionalParameters[0].SupportsDynamicIntellisense);
@ -122,7 +139,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[SkippableFact] [SkippableFact]
public async Task DynamicValues_GetWithDynamicValuesStaticNoValueCollection_RequiredParameters() 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"); ConnectorFunction getWithDynamicValuesStaticNoValueCollection = functions.First(cf => cf.Name == "GetWithDynamicValuesStaticNoValueCollection");
Assert.True(getWithDynamicValuesStaticNoValueCollection.RequiredParameters[0].SupportsDynamicIntellisense); Assert.True(getWithDynamicValuesStaticNoValueCollection.RequiredParameters[0].SupportsDynamicIntellisense);
@ -142,7 +159,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[SkippableFact] [SkippableFact]
public async Task DynamicValues_GetWithDynamicValuesStaticInvalidValueCollection_RequiredParameters() 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"); ConnectorFunction getWithDynamicValuesStaticInvalidValueCollection = functions.First(cf => cf.Name == "GetWithDynamicValuesStaticInvalidValueCollection");
Assert.True(getWithDynamicValuesStaticInvalidValueCollection.RequiredParameters[0].SupportsDynamicIntellisense); Assert.True(getWithDynamicValuesStaticInvalidValueCollection.RequiredParameters[0].SupportsDynamicIntellisense);
@ -162,7 +179,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[SkippableFact] [SkippableFact]
public async Task DynamicValues_GetWithDynamicValuesStaticInvalidDisplayName_RequiredParameters() 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"); ConnectorFunction getWithDynamicValuesStaticInvalidDisplayName = functions.First(cf => cf.Name == "GetWithDynamicValuesStaticInvalidDisplayName");
Assert.True(getWithDynamicValuesStaticInvalidDisplayName.RequiredParameters[0].SupportsDynamicIntellisense); Assert.True(getWithDynamicValuesStaticInvalidDisplayName.RequiredParameters[0].SupportsDynamicIntellisense);
@ -182,7 +199,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[SkippableFact] [SkippableFact]
public async Task DynamicValues_GetWithDynamicValuesStaticInvalidValuePath_RequiredParameters() 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"); ConnectorFunction getWithDynamicValuesStaticInvalidValuePath = functions.First(cf => cf.Name == "GetWithDynamicValuesStaticInvalidValuePath");
Assert.True(getWithDynamicValuesStaticInvalidValuePath.RequiredParameters[0].SupportsDynamicIntellisense); Assert.True(getWithDynamicValuesStaticInvalidValuePath.RequiredParameters[0].SupportsDynamicIntellisense);
@ -202,7 +219,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[SkippableFact] [SkippableFact]
public async Task DynamicValues_GetWithDynamicValuesDynamic_RequiredParameters() 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"); ConnectorFunction getWithDynamicValuesDynamic = functions.First(cf => cf.Name == "GetWithDynamicValuesDynamic");
Assert.True(getWithDynamicValuesDynamic.RequiredParameters[1].SupportsDynamicIntellisense); Assert.True(getWithDynamicValuesDynamic.RequiredParameters[1].SupportsDynamicIntellisense);
@ -222,7 +239,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[SkippableFact] [SkippableFact]
public async Task DynamicValues_GetWithDynamicValuesMultipleDynamic_RequiredParameters() 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"); ConnectorFunction getWithDynamicValuesMultipleDynamic = functions.First(cf => cf.Name == "GetWithDynamicValuesMultipleDynamic");
Assert.True(getWithDynamicValuesMultipleDynamic.RequiredParameters[2].SupportsDynamicIntellisense); Assert.True(getWithDynamicValuesMultipleDynamic.RequiredParameters[2].SupportsDynamicIntellisense);
@ -255,13 +272,13 @@ namespace Microsoft.PowerFx.Connectors.Tests
Assert.Equal("![Index:w, Name:s, PrimaryKey:s]", innerType.FormulaType.ToStringWithDisplayNames()); Assert.Equal("![Index:w, Name:s, PrimaryKey:s]", innerType.FormulaType.ToStringWithDisplayNames());
ConnectorEnhancedSuggestions ces = await getWithDynamicValuesMultipleDynamic.GetConnectorSuggestionsAsync(Array.Empty<NamedValue>(), innerType.Fields.First(field => field.Name == "Index"), connectorContext, CancellationToken.None).ConfigureAwait(false); ConnectorEnhancedSuggestions ces = await getWithDynamicValuesMultipleDynamic.GetConnectorSuggestionsAsync(Array.Empty<NamedValue>(), innerType.Fields.First(field => field.Name == "Index"), connectorContext, CancellationToken.None).ConfigureAwait(false);
Assert.Equal("110|120", string.Join("|", ces.ConnectorSuggestions.Suggestions.Select(cs => cs.DisplayName))); Assert.Equal("110|120", string.Join("|", ces.ConnectorSuggestions.Suggestions.Select(cs => cs.DisplayName)));
} }
[SkippableFact] [SkippableFact]
public async Task DynamicValues_GetWithDynamicListStatic_RequiredParameters() 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"); ConnectorFunction getWithDynamicListStatic = functions.First(cf => cf.Name == "GetWithDynamicListStatic");
Assert.True(getWithDynamicListStatic.RequiredParameters[0].SupportsDynamicIntellisense); Assert.True(getWithDynamicListStatic.RequiredParameters[0].SupportsDynamicIntellisense);
@ -281,7 +298,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[SkippableFact] [SkippableFact]
public async Task DynamicValues_GetWithDynamicListDynamic_RequiredParameters() 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"); ConnectorFunction getWithDynamicListDynamic = functions.First(cf => cf.Name == "GetWithDynamicListDynamic");
Assert.True(getWithDynamicListDynamic.RequiredParameters[1].SupportsDynamicIntellisense); Assert.True(getWithDynamicListDynamic.RequiredParameters[1].SupportsDynamicIntellisense);

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

@ -6,7 +6,9 @@ using System.IO;
using System.Linq; using System.Linq;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Readers; using Microsoft.OpenApi.Readers;
using Microsoft.OpenApi.Validations;
using Xunit; using Xunit;
using Xunit.Abstractions;
namespace Microsoft.PowerFx.Tests namespace Microsoft.PowerFx.Tests
{ {
@ -45,26 +47,35 @@ namespace Microsoft.PowerFx.Tests
} }
else else
{ {
using var streamReader = new StreamReader(stream); using var streamReader = new StreamReader(stream);
return streamReader.ReadToEnd(); return streamReader.ReadToEnd();
} }
} }
} }
// Get a swagger file from the embedded resources. // 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)) using var stream = GetStream(name);
OpenApiDocument doc = new OpenApiStreamReader().Read(stream, out OpenApiDiagnostic diag);
if (diag != null && diag.Errors.Count > 0)
{ {
var doc = new OpenApiStreamReader().Read(stream, out OpenApiDiagnostic diag); foreach (OpenApiError error in diag.Errors)
{
if ((doc == null || doc.Paths == null || doc.Paths.Count == 0) && diag != null && diag.Errors.Count > 0) if (error is OpenApiValidatorError vError)
{ {
throw new InvalidDataException($"Unable to parse Swagger file: {string.Join(", ", diag.Errors.Select(err => err.Message))}"); 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;
} }
return doc;
} }
} }
} }

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

@ -13,6 +13,7 @@ using System.Threading.Tasks;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using Microsoft.PowerFx.Connectors; using Microsoft.PowerFx.Connectors;
using Xunit; using Xunit;
using Xunit.Abstractions;
namespace Microsoft.PowerFx.Tests namespace Microsoft.PowerFx.Tests
{ {
@ -26,12 +27,12 @@ namespace Microsoft.PowerFx.Tests
public OpenApiDocument _apiDocument; public OpenApiDocument _apiDocument;
public bool SendAsyncCalled = false; public bool SendAsyncCalled = false;
public bool Live = false; public bool Live = false;
public HttpClient LiveClient = null; public HttpClient LiveClient = null;
public LoggingTestServer(string swaggerName, bool live = false) public LoggingTestServer(string swaggerName, ITestOutputHelper output, bool live = false)
{ {
Live = live; Live = live;
_apiDocument = Helpers.ReadSwagger(swaggerName); _apiDocument = Helpers.ReadSwagger(swaggerName, output);
if (live) if (live)
{ {
@ -189,7 +190,7 @@ namespace Microsoft.PowerFx.Tests
{ {
clone.Headers.TryAddWithoutValidation(header.Key, header.Value); clone.Headers.TryAddWithoutValidation(header.Key, header.Value);
} }
return await LiveClient.SendAsync(clone, cancellationToken).ConfigureAwait(false); return await LiveClient.SendAsync(clone, cancellationToken).ConfigureAwait(false);
} }

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

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

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

@ -38,34 +38,45 @@ namespace Microsoft.PowerFx.Connectors.Tests
#endif #endif
public void TestAllConnectors() public void TestAllConnectors()
{ {
string outFolder = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, @"..\..\..\..\..\..")); (string outFolder, string srcFolder) = GetFolders();
string srcFolder = Path.GetFullPath(Path.Combine(outFolder, ".."));
string reportFolder = @"report"; string reportFolder = @"report";
string reportName = @$"{reportFolder}\Analysis.txt"; string reportName = @$"{reportFolder}\Analysis.txt";
string jsonReport = @$"{reportFolder}\Report.json"; string jsonReport = @$"{reportFolder}\Report.json";
// New report name every second // 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); string outFolderPath = Path.Combine(outFolder, reportFolder);
if (Directory.Exists(outFolderPath)) BaseConnectorTest.EmptyFolder(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}");
Directory.CreateDirectory(Path.Combine(outFolder, "report")); Directory.CreateDirectory(Path.Combine(outFolder, "report"));
GenerateReport(reportFolder, reportName, outFolder, srcFolder); GenerateReport(reportFolder, reportName, outFolder, srcFolder);
AnalyzeReport(reportName, outFolder, srcFolder, jsonReport); AnalyzeReport(reportName, outFolder, srcFolder, jsonReport);
File.Copy(Path.Combine(outFolder, jsonReport), Path.Combine(outFolder, jsonReport2)); 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) private void AnalyzeReport(string reportName, string outFolder, string srcFolder, string jsonReport)
{ {
List<Connector> connectors = new (); List<Connector> connectors = new ();
@ -356,23 +367,22 @@ namespace Microsoft.PowerFx.Connectors.Tests
try try
{ {
ConsoleLogger logger = new ConsoleLogger(_output); 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}]"; title = $"{doc.Info.Title} [{swaggerFile}]";
// Check we can get the functions // 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(); 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) // 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); string cFolder = Path.Combine(outFolder, reportFolder, doc.Info.Title);
int ix = 2; int ix = 2;
@ -383,7 +393,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
Directory.CreateDirectory(cFolder); Directory.CreateDirectory(cFolder);
foreach (ConnectorFunction cf1 in functions) foreach (ConnectorFunction cf1 in functions1)
{ {
ConnectorFunction cf2 = functions2.First(f => f.Name == cf1.Name); ConnectorFunction cf2 = functions2.First(f => f.Name == cf1.Name);
@ -512,7 +522,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
public void TestConnector1() public void TestConnector1()
{ {
string swaggerFile = @"c:\data\AAPT-connectors\src\ConnectorPlatform\build-system\SharedTestAssets\Assets\BaselineBuild\locPublish\Connectors\AzureAD\apidefinition.swagger.json"; 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)); IEnumerable<ConnectorFunction> functions = OpenApiParser.GetFunctions("C", doc, new ConsoleLogger(_output));
var config = new PowerFxConfig(); 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")] [Theory(Skip = "Need files from AAPT-connector, PowerPlatformConnectors and Power-Fx-TexlFunctions-Baseline projects")]
#endif #endif
[InlineData("Library")] // Default Power-Fx library [InlineData("Library")] // Default Power-Fx library
[InlineData("Aapt-Ppc", 0, "apidefinition*swagger*.json", @"C:\Data\aapt", @"C:\Data\ppc")] [InlineData("Aapt-Ppc", 0, "apidefinition*swagger*.json", @"aapt\src", @"ppc")]
[InlineData("Baseline", 1, "*.json", @"C:\Data\Power-Fx-TexlFunctions-Baseline\Swaggers")] [InlineData("Baseline", 1, "*.json", @"Power-Fx-TexlFunctions-Baseline\Swaggers")]
public void GenerateYamlFiles(string reference, int folderExclusionIndex = -1, string pattern = null, params string[] folders) public void GenerateYamlFiles(string reference, int folderExclusionIndex = -1, string pattern = null, params string[] folders)
{ {
string outFolder = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, @"..\..\..\..\..\..")); (string outFolder, string srcFolder) = GetFolders();
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 outFolderPath = Path.Combine(outFolder, "YamlOutput"); string outFolderPath = Path.Combine(outFolder, "YamlOutput");
BaseConnectorTest.EmptyFolder(Path.Combine(outFolderPath, reference)); BaseConnectorTest.EmptyFolder(Path.Combine(outFolderPath, reference));
// if no folder, use Library
if (folders.Length == 0) if (folders.Length == 0)
{ {
#pragma warning disable CS0618 // Type or member is obsolete #pragma warning disable CS0618 // Type or member is obsolete
@ -569,20 +573,22 @@ namespace Microsoft.PowerFx.Connectors.Tests
SwaggerLocatorSettings swaggerLocationSettings = folderExclusionIndex == 0 ? null : new SwaggerLocatorSettings(new List<string>()); SwaggerLocatorSettings swaggerLocationSettings = folderExclusionIndex == 0 ? null : new SwaggerLocatorSettings(new List<string>());
ConsoleLogger logger = new ConsoleLogger(_output); ConsoleLogger logger = new ConsoleLogger(_output);
ConnectorSettings connectorSettings = new ConnectorSettings("FakeNamespace") ConnectorSettings connectorSettings = new ConnectorSettings("FakeNamespace")
{ {
AllowUnsupportedFunctions = true, AllowUnsupportedFunctions = true,
IncludeInternalFunctions = true, IncludeInternalFunctions = true,
FailOnUnknownExtension = false, FailOnUnknownExtension = false,
Compatibility = ConnectorCompatibility.PowerAppsCompatibility Compatibility = ConnectorCompatibility.PowerAppsCompatibility
}; };
string[] rootedFolders = folders.Select(f => Path.Combine(srcFolder, f)).ToArray();
// Step 1: Identify the list of swagger files to consider // Step 1: Identify the list of swagger files to consider
// The output of LocateSwaggerFilesWithDocuments is a dictionary where // The output of LocateSwaggerFilesWithDocuments is a dictionary where
// - Key is the connector display name // - 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 // - 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) // 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()}"); _output.WriteLine($"Number of connectors found: {swaggerFiles.Count()}");
foreach (KeyValuePair<string, (string folder, string location, OpenApiDocument document)> connector in swaggerFiles) 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.IsBehavior = connectorFunction.IsBehavior;
func.IsSupported = connectorFunction.IsSupported;
func.NotSupportedReason = connectorFunction.NotSupportedReason;
func.IsDeprecated = connectorFunction.IsDeprecated; func.IsDeprecated = connectorFunction.IsDeprecated;
func.IsInternal = connectorFunction.IsInternal; func.IsInternal = connectorFunction.IsInternal;
func.IsPageable = connectorFunction.IsPageable; func.IsPageable = connectorFunction.IsPageable;

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

@ -11,13 +11,22 @@ using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.OpenApi.Models; using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Readers; using Microsoft.OpenApi.Readers;
using Microsoft.OpenApi.Validations;
using Microsoft.PowerFx.Types; using Microsoft.PowerFx.Types;
using Xunit; using Xunit;
using Xunit.Abstractions;
namespace Microsoft.PowerFx.Connectors.Tests namespace Microsoft.PowerFx.Connectors.Tests
{ {
public class LivePublicSwaggerTests 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")] [Fact(Skip = "These APIs are rate limited and HTTP error 429 is possible")]
public async Task RealTest() 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://api.apis.guru/v2/specs/weatherbit.io/2.0.0/swagger.json"
// "https://www.weatherbit.io/static/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 // No BaseAdress specified, we'll use the 1st HTTPS one found in the swagger file
using var client = new HttpClient(); // public auth using var client = new HttpClient(); // public auth
@ -72,13 +81,13 @@ namespace Microsoft.PowerFx.Connectors.Tests
// Note that these APIs are rate limited and HTTP error 429 is possible // 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"; 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 // Here we specify the BaseAddress
using var client = new HttpClient() { BaseAddress = new Uri("https://api.math.tools") }; using var client = new HttpClient() { BaseAddress = new Uri("https://api.math.tools") };
// FailOnUnknownExtension in connectorsettings is set to false (default) as this swagger uses some extensions we don't honnor like x-apisguru-categories, x-origin, x-providerName // FailOnUnknownExtension in connectorsettings is set to false (default) as this swagger uses some extensions we don't honnor like x-apisguru-categories, x-origin, x-providerName
var funcs = config.AddActionConnector(new ConnectorSettings("Math"), doc); var funcs = config.AddActionConnector(new ConnectorSettings("Math"), doc);
var engine = new RecalcEngine(config); var engine = new RecalcEngine(config);
var expr = "Math.numbersbasebinary(632506623)"; var expr = "Math.numbersbasebinary(632506623)";
@ -129,7 +138,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
// https://date.nager.at/ // https://date.nager.at/
var swaggerUrl = "https://date.nager.at/swagger/v3/swagger.json"; 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") }; using var client = new HttpClient() { BaseAddress = new Uri("https://date.nager.at") };
var funcs = config.AddActionConnector("Holiday", doc); var funcs = config.AddActionConnector("Holiday", doc);
@ -143,7 +152,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
Assert.True(ok, string.Join(", ", check.Errors.Select(er => er.Message))); Assert.True(ok, string.Join(", ", check.Errors.Select(er => er.Message)));
var runtimeConfig = new RuntimeConfig().AddRuntimeContext(new TestConnectorRuntimeContext("Holiday", client)); var runtimeConfig = new RuntimeConfig().AddRuntimeContext(new TestConnectorRuntimeContext("Holiday", client));
FormulaValue result = await engine.EvalAsync(expr, CancellationToken.None, runtimeConfig: runtimeConfig).ConfigureAwait(false); FormulaValue result = await engine.EvalAsync(expr, CancellationToken.None, runtimeConfig: runtimeConfig).ConfigureAwait(false);
if (result is ErrorValue ev) if (result is ErrorValue ev)
{ {
@ -173,8 +182,8 @@ namespace Microsoft.PowerFx.Connectors.Tests
public async Task RealTest4() public async Task RealTest4()
{ {
var config = new PowerFxConfig(); 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);
OpenApiDocument docWorldTime = await ReadSwaggerFromUrl(@"https://api.apis.guru/v2/specs/worldtimeapi.org/20210108/openapi.json").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 clientXkcd = new HttpClient() { BaseAddress = new Uri(@"http://xkcd.com/") };
using var clientWorldTime = new HttpClient() { BaseAddress = new Uri(@"http://worldtimeapi.org/api/") }; using var clientWorldTime = new HttpClient() { BaseAddress = new Uri(@"http://worldtimeapi.org/api/") };
@ -182,7 +191,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
var funcsWorldTime = config.AddActionConnector(new ConnectorSettings("WorldTime"), docWorldTime); var funcsWorldTime = config.AddActionConnector(new ConnectorSettings("WorldTime"), docWorldTime);
var engine = new RecalcEngine(config); var engine = new RecalcEngine(config);
var runtimeConfig = new RuntimeConfig().AddRuntimeContext(new TestConnectorRuntimeContext("Xkcd", clientXkcd).Add("WorldTime", clientWorldTime)); var runtimeConfig = new RuntimeConfig().AddRuntimeContext(new TestConnectorRuntimeContext("Xkcd", clientXkcd).Add("WorldTime", clientWorldTime));
FormulaValue fv1 = await engine.EvalAsync(@"Xkcd.comicIdinfo0json(1).transcript", CancellationToken.None, runtimeConfig: runtimeConfig).ConfigureAwait(false); FormulaValue fv1 = await engine.EvalAsync(@"Xkcd.comicIdinfo0json(1).transcript", CancellationToken.None, runtimeConfig: runtimeConfig).ConfigureAwait(false);
string transcript = ((StringValue)fv1).Value.Replace("\n", "\r\n"); string transcript = ((StringValue)fv1).Value.Replace("\n", "\r\n");
@ -201,7 +210,7 @@ Boy: I wonder where I'll float next?
public async Task FailOnUnknownExtensionTest() public async Task FailOnUnknownExtensionTest()
{ {
var config = new PowerFxConfig(); 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); 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. // Get a swagger file from the embedded resources.
private static async Task<OpenApiDocument> ReadSwaggerFromUrl(string url) private static async Task<OpenApiDocument> ReadSwaggerFromUrl(string url, ITestOutputHelper output)
{ {
using var http = new HttpClient(); using HttpClient http = new HttpClient();
using (var stream = await http.GetStreamAsync(new Uri(url)).ConfigureAwait(false)) 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 (diag != null && diag.Errors.Count > 0)
{ {
ReadResult rr = await new OpenApiStreamReader().ReadAsync(stream, CancellationToken.None).ConfigureAwait(false); foreach (OpenApiError error in diag.Errors)
OpenApiDiagnostic diag = rr.OpenApiDiagnostic;
OpenApiDocument doc = rr.OpenApiDocument;
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))}"); 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;
} }
return doc;
} }
} }
} }

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

@ -20,7 +20,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact] [Fact]
public void ConnectorLogger_Test1() public void ConnectorLogger_Test1()
{ {
ConsoleLogger logger = new ConsoleLogger(_output); ConsoleLogger logger = new ConsoleLogger(_output);
IReadOnlyList<ConnectorFunction> functions = (null as PowerFxConfig).AddActionConnector(null as string, null, logger); IReadOnlyList<ConnectorFunction> functions = (null as PowerFxConfig).AddActionConnector(null as string, null, logger);
@ -51,7 +51,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
PowerFxConfig config = new PowerFxConfig(Features.PowerFxV1); PowerFxConfig config = new PowerFxConfig(Features.PowerFxV1);
IReadOnlyList<ConnectorFunction> functions = config.AddActionConnector(null as ConnectorSettings, null, logger); IReadOnlyList<ConnectorFunction> functions = config.AddActionConnector(null as ConnectorSettings, null, logger);
Assert.Empty(functions); Assert.Empty(functions);
Assert.Equal( Assert.Equal(
@"[INFO ] Entering in ConfigExtensions.AddActionConnector, with ConnectorSettings <null>|" + @"[INFO ] Entering in ConfigExtensions.AddActionConnector, with ConnectorSettings <null>|" +
@"[ERROR] connectorSettings is null|" + @"[ERROR] connectorSettings is null|" +
@ -69,7 +69,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
Assert.Equal( Assert.Equal(
@"[INFO ] Entering in ConfigExtensions.AddActionConnector, with ConnectorSettings Namespace <Namespace is null>, MaxRows 1000, FailOnUnknownExtension False, AllowUnsupportedFunctions False, IncludeInternalFunctions False, |" + @"[INFO ] Entering in ConfigExtensions.AddActionConnector, with ConnectorSettings Namespace <Namespace is null>, MaxRows 1000, FailOnUnknownExtension False, AllowUnsupportedFunctions False, IncludeInternalFunctions False, |" +
@"[ERROR] connectorSettings.Namespace is null|" + @"[ERROR] connectorSettings.Namespace is null|" +
@"[INFO ] Exiting ConfigExtensions.AddActionConnector, returning 0 functions", logger.GetLogs()); @"[INFO ] Exiting ConfigExtensions.AddActionConnector, returning 0 functions", logger.GetLogs());
} }
[Fact] [Fact]
@ -83,7 +83,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
Assert.Equal( Assert.Equal(
@"[INFO ] Entering in ConfigExtensions.AddActionConnector, with ConnectorSettings Namespace Test, MaxRows 1000, FailOnUnknownExtension False, AllowUnsupportedFunctions False, IncludeInternalFunctions False, |" + @"[INFO ] Entering in ConfigExtensions.AddActionConnector, with ConnectorSettings Namespace Test, MaxRows 1000, FailOnUnknownExtension False, AllowUnsupportedFunctions False, IncludeInternalFunctions False, |" +
@"[ERROR] openApiDocument is null|" + @"[ERROR] openApiDocument is null|" +
@"[INFO ] Exiting ConfigExtensions.AddActionConnector, returning 0 functions", logger.GetLogs()); @"[INFO ] Exiting ConfigExtensions.AddActionConnector, returning 0 functions", logger.GetLogs());
} }
[Fact] [Fact]
@ -97,7 +97,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
Assert.Equal( Assert.Equal(
@"[INFO ] Entering in ConfigExtensions.AddActionConnector, with ConnectorSettings Namespace Test, MaxRows 1000, FailOnUnknownExtension False, AllowUnsupportedFunctions False, IncludeInternalFunctions False, |" + @"[INFO ] Entering in ConfigExtensions.AddActionConnector, with ConnectorSettings Namespace Test, MaxRows 1000, FailOnUnknownExtension False, AllowUnsupportedFunctions False, IncludeInternalFunctions False, |" +
@"[ERROR] OpenApiDocument is invalid, it has no Path|" + @"[ERROR] OpenApiDocument is invalid, it has no Path|" +
@"[INFO ] Exiting ConfigExtensions.AddActionConnector, returning 0 functions", logger.GetLogs()); @"[INFO ] Exiting ConfigExtensions.AddActionConnector, returning 0 functions", logger.GetLogs());
} }
[Fact] [Fact]
@ -111,15 +111,15 @@ namespace Microsoft.PowerFx.Connectors.Tests
Assert.Equal( Assert.Equal(
@"[INFO ] Entering in ConfigExtensions.AddActionConnector, with ConnectorSettings Namespace , MaxRows 1000, FailOnUnknownExtension False, AllowUnsupportedFunctions False, IncludeInternalFunctions False, |" + @"[INFO ] Entering in ConfigExtensions.AddActionConnector, with ConnectorSettings Namespace , MaxRows 1000, FailOnUnknownExtension False, AllowUnsupportedFunctions False, IncludeInternalFunctions False, |" +
@"[ERROR] connectorSettings.Namespace is not a valid DName|" + @"[ERROR] connectorSettings.Namespace is not a valid DName|" +
@"[INFO ] Exiting ConfigExtensions.AddActionConnector, returning 0 functions", logger.GetLogs()); @"[INFO ] Exiting ConfigExtensions.AddActionConnector, returning 0 functions", logger.GetLogs());
} }
[Fact] [Fact]
public void ConnectorLogger_Test8() public void ConnectorLogger_Test8()
{ {
ConsoleLogger logger = new ConsoleLogger(_output); ConsoleLogger logger = new ConsoleLogger(_output);
PowerFxConfig config = new PowerFxConfig(Features.PowerFxV1); 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); IReadOnlyList<ConnectorFunction> functions = config.AddActionConnector(new ConnectorSettings("SQL"), testConnector._apiDocument, logger);
Assert.NotEmpty(functions); Assert.NotEmpty(functions);

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

@ -29,7 +29,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact] [Fact]
public void ACSL_GetFunctionNames() 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 // OpenAPI spec: Info.Title is required
Assert.Equal("Azure Cognitive Service for Language", doc.Info.Title); Assert.Equal("Azure Cognitive Service for Language", doc.Info.Title);
@ -51,7 +51,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact] [Fact]
public void ACSL_GetFunctionNames22() 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(); List<ConnectorFunction> functions = OpenApiParser.GetFunctions("ACSL", doc, new ConsoleLogger(_output)).OrderBy(cf => cf.Name).ToList();
ConnectorFunction detectSentimentV3 = functions.First(cf => cf.Name == "DetectSentimentV3"); ConnectorFunction detectSentimentV3 = functions.First(cf => cf.Name == "DetectSentimentV3");
@ -62,12 +62,12 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact] [Fact]
public void ACSL_Load() 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)); (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(connectorFunctions, func => func.Namespace == "ACSL" && func.Name == "ConversationAnalysisAnalyzeConversationConversation");
Assert.Contains(texlFunctions, func => func.Namespace.Name.Value == "ACSL" && func.Name == "ConversationAnalysisAnalyzeConversationConversation"); Assert.Contains(texlFunctions, func => func.Namespace.Name.Value == "ACSL" && func.Name == "ConversationAnalysisAnalyzeConversationConversation");
ConnectorFunction func1 = connectorFunctions.First(f => f.Name == "AnalyzeTextSubmitJobCustomEntityRecognition"); ConnectorFunction func1 = connectorFunctions.First(f => f.Name == "AnalyzeTextSubmitJobCustomEntityRecognition");
Assert.Equal("analysisInput:![documents:*[id:s, language:s, text:s]]|task:![parameters:![deploymentName:s, projectName:s, stringIndexType:s]]", string.Join("|", func1.RequiredParameters.Select(rp => $"{rp.Name}:{rp.FormulaType._type}"))); Assert.Equal("analysisInput:![documents:*[id:s, language:s, text:s]]|task:![parameters:![deploymentName:s, projectName:s, stringIndexType:s]]", string.Join("|", func1.RequiredParameters.Select(rp => $"{rp.Name}:{rp.FormulaType._type}")));
Assert.Equal("displayName:s", string.Join("|", func1.OptionalParameters.Select(rp => $"{rp.Name}:{rp.FormulaType._type}"))); Assert.Equal("displayName:s", string.Join("|", func1.OptionalParameters.Select(rp => $"{rp.Name}:{rp.FormulaType._type}")));
@ -75,7 +75,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
Assert.Contains(connectorFunctions, func => func.Namespace == "ACSL" && func.Name == "ConversationAnalysisAnalyzeConversationConversation"); Assert.Contains(connectorFunctions, func => func.Namespace == "ACSL" && func.Name == "ConversationAnalysisAnalyzeConversationConversation");
Assert.Contains(texlFunctions, func => func.Namespace.Name.Value == "ACSL" && func.Name == "ConversationAnalysisAnalyzeConversationConversation"); Assert.Contains(texlFunctions, func => func.Namespace.Name.Value == "ACSL" && func.Name == "ConversationAnalysisAnalyzeConversationConversation");
func1 = connectorFunctions.First(f => f.Name == "AnalyzeTextSubmitJobCustomEntityRecognition"); func1 = connectorFunctions.First(f => f.Name == "AnalyzeTextSubmitJobCustomEntityRecognition");
Assert.Equal("analysisInput:![documents:*[id:s, language:s, text:s]]|task:![parameters:![deploymentName:s, projectName:s]]", string.Join("|", func1.RequiredParameters.Select(rp => $"{rp.Name}:{rp.FormulaType._type}"))); Assert.Equal("analysisInput:![documents:*[id:s, language:s, text:s]]|task:![parameters:![deploymentName:s, projectName:s]]", string.Join("|", func1.RequiredParameters.Select(rp => $"{rp.Name}:{rp.FormulaType._type}")));
Assert.Empty(func1.OptionalParameters); Assert.Empty(func1.OptionalParameters);
} }
@ -83,7 +83,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact] [Fact]
public void SF_TextCsv() 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)); (List<ConnectorFunction> connectorFunctions, List<ConnectorTexlFunction> texlFunctions) = OpenApiParser.ParseInternal(new ConnectorSettings("SF") { Compatibility = ConnectorCompatibility.SwaggerCompatibility }, doc, new ConsoleLogger(_output));
// function returns text/csv // function returns text/csv
@ -99,7 +99,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact] [Fact]
public void ACSL_GetFunctionParameters_PowerAppsCompatibility() 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]; ConnectorFunction function = OpenApiParser.GetFunctions(new ConnectorSettings("ACSL") { Compatibility = ConnectorCompatibility.PowerAppsCompatibility }, doc).OrderBy(cf => cf.Name).ToList()[14];
Assert.Equal("ConversationAnalysisAnalyzeConversationConversation", function.Name); Assert.Equal("ConversationAnalysisAnalyzeConversationConversation", function.Name);
@ -212,7 +212,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact] [Fact]
public void ACSL_GetFunctionParameters_SwaggerCompatibility() 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]; ConnectorFunction function = OpenApiParser.GetFunctions(new ConnectorSettings("ACSL") { Compatibility = ConnectorCompatibility.SwaggerCompatibility }, doc).OrderBy(cf => cf.Name).ToList()[14];
Assert.Equal("ConversationAnalysisAnalyzeConversationConversation", function.Name); Assert.Equal("ConversationAnalysisAnalyzeConversationConversation", function.Name);
@ -221,11 +221,11 @@ namespace Microsoft.PowerFx.Connectors.Tests
RecordType analysisInputRecordType = Extensions.MakeRecordType( RecordType analysisInputRecordType = Extensions.MakeRecordType(
("conversationItem", Extensions.MakeRecordType( ("conversationItem", Extensions.MakeRecordType(
("language", FormulaType.String), ("language", FormulaType.String),
("text", FormulaType.String)))); ("text", FormulaType.String))));
RecordType parametersRecordType = Extensions.MakeRecordType( RecordType parametersRecordType = Extensions.MakeRecordType(
("deploymentName", FormulaType.String), ("deploymentName", FormulaType.String),
("projectName", FormulaType.String), ("projectName", FormulaType.String),
("verbose", FormulaType.Boolean)); ("verbose", FormulaType.Boolean));
Assert.Equal(2, function.RequiredParameters.Length); Assert.Equal(2, function.RequiredParameters.Length);
@ -320,11 +320,11 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact] [Fact]
public async Task ACSL_InvokeFunction() 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; OpenApiDocument apiDoc = testConnector._apiDocument;
ConsoleLogger logger = new ConsoleLogger(_output); ConsoleLogger logger = new ConsoleLogger(_output);
PowerFxConfig pfxConfig = new PowerFxConfig(Features.PowerFxV1); PowerFxConfig pfxConfig = new PowerFxConfig(Features.PowerFxV1);
ConnectorFunction function = OpenApiParser.GetFunctions(new ConnectorSettings("ACSL") { Compatibility = ConnectorCompatibility.SwaggerCompatibility }, apiDoc).OrderBy(cf => cf.Name).ToList()[14]; ConnectorFunction function = OpenApiParser.GetFunctions(new ConnectorSettings("ACSL") { Compatibility = ConnectorCompatibility.SwaggerCompatibility }, apiDoc).OrderBy(cf => cf.Name).ToList()[14];
Assert.Equal("ConversationAnalysisAnalyzeConversationConversation", function.Name); Assert.Equal("ConversationAnalysisAnalyzeConversationConversation", function.Name);
Assert.Equal("![kind:s, result:![detectedLanguage:s, prediction:![entities:*[category:s, confidenceScore:w, extraInformation:O, length:w, offset:w, resolutions:O, text:s], intents:*[category:s, confidenceScore:w], projectKind:s, topIntent:s], query:s]]", function.ReturnType.ToStringWithDisplayNames()); Assert.Equal("![kind:s, result:![detectedLanguage:s, prediction:![entities:*[category:s, confidenceScore:w, extraInformation:O, length:w, offset:w, resolutions:O, text:s], intents:*[category:s, confidenceScore:w], projectKind:s, topIntent:s], query:s]]", function.ReturnType.ToStringWithDisplayNames());
@ -351,7 +351,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
client.Dispose(); client.Dispose();
testConnector.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); using var httpClient2 = new HttpClient(testConnector2);
testConnector2.SetResponseFromFile(@"Responses\Azure Cognitive Service for Language_Response.json"); 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) 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] [Fact]
public async Task AzureOpenAiGetFunctions() 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; OpenApiDocument apiDoc = testConnector._apiDocument;
PowerFxConfig pfxConfig = new PowerFxConfig(Features.PowerFxV1); PowerFxConfig pfxConfig = new PowerFxConfig(Features.PowerFxV1);
@ -426,7 +426,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact] [Fact]
public async Task ACSL_InvokeFunction_v21() 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; OpenApiDocument apiDoc = testConnector._apiDocument;
ConsoleLogger logger = new ConsoleLogger(_output); ConsoleLogger logger = new ConsoleLogger(_output);
@ -636,7 +636,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact] [Fact]
public void LQA_Load() 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)); (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"); Assert.Contains(texlFunctions, func => func.Namespace.Name.Value == "LQA" && func.Name == "GetAnswersFromText");
} }
@ -644,7 +644,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact] [Fact]
public void SQL_Load() 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)); (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"); Assert.Contains(texlFunctions, func => func.Namespace.Name.Value == "SQL" && func.Name == "GetProcedureV2");
} }
@ -652,7 +652,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact] [Fact]
public void Dataverse_Sample() 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(); ConnectorFunction[] functions = OpenApiParser.GetFunctions("DV", doc, new ConsoleLogger(_output)).ToArray();
Assert.NotNull(functions); Assert.NotNull(functions);
@ -704,7 +704,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact] [Fact]
public void VisibilityTest() 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[] functions = OpenApiParser.GetFunctions("AzBlob", doc, new ConsoleLogger(_output)).ToArray();
ConnectorFunction createFileV2 = functions.First(f => f.Name == "CreateFileV2"); ConnectorFunction createFileV2 = functions.First(f => f.Name == "CreateFileV2");
@ -742,7 +742,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
public void DynamicReturnValueTest() public void DynamicReturnValueTest()
{ {
using HttpClient httpClient = new (); 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[] functions = OpenApiParser.GetFunctions("SQL", doc, new ConsoleLogger(_output)).ToArray();
ConnectorFunction createFileV2 = functions.First(f => f.Name == "ExecuteProcedureV2"); ConnectorFunction createFileV2 = functions.First(f => f.Name == "ExecuteProcedureV2");
@ -797,7 +797,7 @@ namespace Microsoft.PowerFx.Connectors.Tests
[Fact] [Fact]
public async Task DirectIntellisenseTest() 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 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" }; 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] [Fact]
public async Task DataverseTest() 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 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" }; 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) public async Task DataverseTest2(string swaggerFile)
{ {
PowerFxConfig powerFxConfig = new PowerFxConfig(); PowerFxConfig powerFxConfig = new PowerFxConfig();
OpenApiDocument doc = Helpers.ReadSwagger(swaggerFile); OpenApiDocument doc = Helpers.ReadSwagger(swaggerFile, _output);
OpenApiParser.GetFunctions("namespace", doc); // missing logger OpenApiParser.GetFunctions("namespace", doc); // missing logger
powerFxConfig.AddActionConnector("namespace", doc); powerFxConfig.AddActionConnector("namespace", doc);
@ -995,18 +995,18 @@ POST https://tip1-shared.azure-apim.net/invoke
[Fact] [Fact]
public async Task CardsForPowerApps_Invoke() 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 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" }; 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" };
BaseRuntimeConnectorContext runtimeContext = new TestConnectorRuntimeContext("DV", client, console: _output); BaseRuntimeConnectorContext runtimeContext = new TestConnectorRuntimeContext("DV", client, console: _output);
ConnectorFunction[] functions = OpenApiParser.GetFunctions( ConnectorFunction[] functions = OpenApiParser.GetFunctions(
new ConnectorSettings("DV") new ConnectorSettings("DV")
{ {
Compatibility = ConnectorCompatibility.SwaggerCompatibility, Compatibility = ConnectorCompatibility.SwaggerCompatibility,
ReturnUnknownRecordFieldsAsUntypedObjects = true ReturnUnknownRecordFieldsAsUntypedObjects = true
}, },
testConnector._apiDocument).ToArray(); testConnector._apiDocument).ToArray();
ConnectorFunction createCardInstance = functions.First(f => f.Name == "CreateCardInstance"); ConnectorFunction createCardInstance = functions.First(f => f.Name == "CreateCardInstance");
@ -1044,7 +1044,7 @@ POST https://tip1-shared.azure-apim.net/invoke
[Fact] [Fact]
public async Task CardsForPowerApps_Suggestion() 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 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" }; 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] [Fact]
public async Task Teams_GetMessageDetails_WithComplexParameterReference() 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 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" }; 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" };
@ -1092,7 +1092,7 @@ POST https://tip1-shared.azure-apim.net/invoke
CancellationToken.None).ConfigureAwait(false); CancellationToken.None).ConfigureAwait(false);
var bodyConnectorType = parameters.ParametersWithSuggestions[2].ConnectorType; var bodyConnectorType = parameters.ParametersWithSuggestions[2].ConnectorType;
ConnectorParameterWithSuggestions suggestions = parameters.ParametersWithSuggestions[2]; ConnectorParameterWithSuggestions suggestions = parameters.ParametersWithSuggestions[2];
testConnector.SetResponseFromFile(@"Responses\Teams_GetMessageDetails_GetSuggestionsForChannel.json"); testConnector.SetResponseFromFile(@"Responses\Teams_GetMessageDetails_GetSuggestionsForChannel.json");

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

@ -44,7 +44,7 @@ namespace Microsoft.PowerFx.Tests
[InlineData(false)] [InlineData(false)]
public async Task MSNWeatherConnector_CurrentWeather(bool useSwaggerParameter) 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 apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(); var config = new PowerFxConfig();
@ -111,13 +111,13 @@ namespace Microsoft.PowerFx.Tests
[InlineData(100, null)] // Continue [InlineData(100, null)] // Continue
[InlineData(200, null)] // Ok [InlineData(200, null)] // Ok
[InlineData(202, null)] // Accepted [InlineData(202, null)] // Accepted
[InlineData(305, "Use Proxy")] [InlineData(305, "Use Proxy")]
[InlineData(411, "Length Required")] [InlineData(411, "Length Required")]
[InlineData(500, "Internal Server Error")] [InlineData(500, "Internal Server Error")]
[InlineData(502, "Bad Gateway")] [InlineData(502, "Bad Gateway")]
public async Task Connector_GenerateErrors(int statusCode, string reasonPhrase) 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 apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(); var config = new PowerFxConfig();
@ -209,7 +209,7 @@ namespace Microsoft.PowerFx.Tests
[InlineData(false, true)] [InlineData(false, true)]
public async Task AzureBlobConnector_UploadFile(bool useSwaggerParameter, bool useHttpsPrefix) 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 apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(); var config = new PowerFxConfig();
var token = @"eyJ0eX..."; var token = @"eyJ0eX...";
@ -280,7 +280,7 @@ namespace Microsoft.PowerFx.Tests
[Fact] [Fact]
public async Task AzureBlobConnector_UseOfDeprecatedFunction() 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; OpenApiDocument apiDoc = testConnector._apiDocument;
PowerFxConfig config = new PowerFxConfig(); PowerFxConfig config = new PowerFxConfig();
string token = @"eyJ0eXAi..."; string token = @"eyJ0eXAi...";
@ -321,7 +321,7 @@ namespace Microsoft.PowerFx.Tests
[Fact] [Fact]
public async Task AzureBlobConnector_Paging() 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; OpenApiDocument apiDoc = testConnector._apiDocument;
PowerFxConfig config = new PowerFxConfig(); PowerFxConfig config = new PowerFxConfig();
string token = @"eyJ0eX..."; string token = @"eyJ0eX...";
@ -350,7 +350,7 @@ namespace Microsoft.PowerFx.Tests
[InlineData("Office365Outlook.FindMeetingTimesV2(")] [InlineData("Office365Outlook.FindMeetingTimesV2(")]
public void IntellisenseHelpStringsOptionalParms(string expr) 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(); var config = new PowerFxConfig();
config.AddActionConnector("Office365Outlook", apiDocOutlook, new ConsoleLogger(_output)); config.AddActionConnector("Office365Outlook", apiDocOutlook, new ConsoleLogger(_output));
@ -372,7 +372,7 @@ namespace Microsoft.PowerFx.Tests
[InlineData("Behavior(); MSNWeather.CurrentWeather(", false, true)] [InlineData("Behavior(); MSNWeather.CurrentWeather(", false, true)]
public void IntellisenseHelpStrings(string expr, bool withAllowSideEffects, bool expectedBehaviorError) 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(); var config = new PowerFxConfig();
config.AddActionConnector("MSNWeather", apiDoc, new ConsoleLogger(_output)); config.AddActionConnector("MSNWeather", apiDoc, new ConsoleLogger(_output));
@ -447,7 +447,7 @@ namespace Microsoft.PowerFx.Tests
Assert.NotNull(ppcl2); Assert.NotNull(ppcl2);
Assert.Equal("firstrelease-001.azure-apim.net:117", ppcl2.Endpoint); 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; var apiDoc = testConnector._apiDocument;
using var ppcl3 = new PowerPlatformConnectorClient( using var ppcl3 = new PowerPlatformConnectorClient(
@ -460,7 +460,7 @@ namespace Microsoft.PowerFx.Tests
Assert.NotNull(ppcl3); Assert.NotNull(ppcl3);
Assert.Equal("localhost:23340", ppcl3.Endpoint); 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 apiDoc2 = testConnector2._apiDocument;
var ex2 = Assert.Throws<PowerFxConnectorException>(() => new PowerPlatformConnectorClient( var ex2 = Assert.Throws<PowerFxConnectorException>(() => new PowerPlatformConnectorClient(
@ -476,7 +476,7 @@ namespace Microsoft.PowerFx.Tests
[Fact] [Fact]
public async Task Office365Users_UserProfile_V2() 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 apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(); var config = new PowerFxConfig();
@ -507,7 +507,7 @@ namespace Microsoft.PowerFx.Tests
[Fact] [Fact]
public async Task Office365Users_MyProfile_V2() 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 apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(); var config = new PowerFxConfig();
@ -537,7 +537,7 @@ namespace Microsoft.PowerFx.Tests
[Fact] [Fact]
public async Task Office365Users_DirectReports_V2() 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 apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(); var config = new PowerFxConfig();
@ -567,7 +567,7 @@ namespace Microsoft.PowerFx.Tests
[Fact] [Fact]
public async Task Office365Users_SearchUsers_V2() 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 apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(); var config = new PowerFxConfig();
@ -597,7 +597,7 @@ namespace Microsoft.PowerFx.Tests
[Fact] [Fact]
public async Task Office365Users_UseDates() 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 apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(); var config = new PowerFxConfig();
@ -638,7 +638,7 @@ namespace Microsoft.PowerFx.Tests
[Fact] [Fact]
public async Task Office365Outlook_GetEmailsV2() 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 apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(); 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"")")] [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) 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 apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(); var config = new PowerFxConfig();
@ -741,7 +741,7 @@ namespace Microsoft.PowerFx.Tests
[Fact] [Fact]
public async Task Office365Outlook_ExportEmailV2() 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 apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(); var config = new PowerFxConfig();
@ -786,7 +786,7 @@ namespace Microsoft.PowerFx.Tests
[Fact] [Fact]
public async Task Office365Outlook_FindMeetingTimesV2() 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 apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(); var config = new PowerFxConfig();
@ -833,7 +833,7 @@ namespace Microsoft.PowerFx.Tests
[Fact] [Fact]
public async Task Office365Outlook_FlagV2() 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 apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(); var config = new PowerFxConfig();
@ -880,7 +880,7 @@ namespace Microsoft.PowerFx.Tests
[Fact] [Fact]
public async Task Office365Outlook_GetMailTipsV2() 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 apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(); var config = new PowerFxConfig();
@ -927,7 +927,7 @@ namespace Microsoft.PowerFx.Tests
[Fact] [Fact]
public async Task Office365Outlook_GetRoomListsV2() 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 apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(); var config = new PowerFxConfig();
@ -975,7 +975,7 @@ namespace Microsoft.PowerFx.Tests
[Fact] [Fact]
public async Task Office365Outlook_Load() 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 apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(); var config = new PowerFxConfig();
@ -1010,7 +1010,7 @@ namespace Microsoft.PowerFx.Tests
[Fact] [Fact]
public async Task Office365Outlook_GetRooms() 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 apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(Features.PowerFxV1); var config = new PowerFxConfig(Features.PowerFxV1);
@ -1060,7 +1060,7 @@ namespace Microsoft.PowerFx.Tests
[Fact] [Fact]
public async Task BingMaps_GetRouteV3() 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 apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(); var config = new PowerFxConfig();
@ -1108,7 +1108,7 @@ namespace Microsoft.PowerFx.Tests
[Fact] [Fact]
public async Task SQL_GetStoredProcs() 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 apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(Features.PowerFxV1); var config = new PowerFxConfig(Features.PowerFxV1);
@ -1157,7 +1157,7 @@ namespace Microsoft.PowerFx.Tests
[Fact] [Fact]
public async Task SQL_ExecuteStoredProc() 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 apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(Features.PowerFxV1); var config = new PowerFxConfig(Features.PowerFxV1);
@ -1206,7 +1206,7 @@ namespace Microsoft.PowerFx.Tests
[Fact] [Fact]
public async Task SQL_ExecuteStoredProc_WithUserAgent() 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 apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(Features.PowerFxV1); var config = new PowerFxConfig(Features.PowerFxV1);
@ -1256,7 +1256,7 @@ namespace Microsoft.PowerFx.Tests
[Fact] [Fact]
public async Task SharePointOnlineTest() 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; OpenApiDocument apiDoc = testConnector._apiDocument;
PowerFxConfig config = new PowerFxConfig(); PowerFxConfig config = new PowerFxConfig();
string token = @"eyJ0eXA..."; string token = @"eyJ0eXA...";
@ -1274,14 +1274,14 @@ namespace Microsoft.PowerFx.Tests
Assert.Equal(101 - 51, functions.Count(f => f.IsInternal)); Assert.Equal(101 - 51, functions.Count(f => f.IsInternal));
IEnumerable<ConnectorFunction> funcInfos = config.AddActionConnector( IEnumerable<ConnectorFunction> funcInfos = config.AddActionConnector(
new ConnectorSettings("SP") new ConnectorSettings("SP")
{ {
// This shouldn't be used with expressions but this is OK here as this is a tabular connector and has no impact for this connector/these functions // This shouldn't be used with expressions but this is OK here as this is a tabular connector and has no impact for this connector/these functions
Compatibility = ConnectorCompatibility.SwaggerCompatibility, Compatibility = ConnectorCompatibility.SwaggerCompatibility,
IncludeInternalFunctions = true, IncludeInternalFunctions = true,
ReturnUnknownRecordFieldsAsUntypedObjects = true ReturnUnknownRecordFieldsAsUntypedObjects = true
}, },
apiDoc, apiDoc,
new ConsoleLogger(_output)); new ConsoleLogger(_output));
RecalcEngine engine = new RecalcEngine(config); RecalcEngine engine = new RecalcEngine(config);
RuntimeConfig rc = new RuntimeConfig().AddRuntimeContext(new TestConnectorRuntimeContext("SP", ppClient, console: _output)); RuntimeConfig rc = new RuntimeConfig().AddRuntimeContext(new TestConnectorRuntimeContext("SP", ppClient, console: _output));
@ -1305,7 +1305,7 @@ namespace Microsoft.PowerFx.Tests
Assert.Equal("1e54c4b5-2a59-4a2a-9633-cc611a2ff718", ((StringValue)((TableValue)fv4).Rows.Skip(1).First().Value.GetField("Name")).Value); Assert.Equal("1e54c4b5-2a59-4a2a-9633-cc611a2ff718", ((StringValue)((TableValue)fv4).Rows.Skip(1).First().Value.GetField("Name")).Value);
testConnector.SetResponseFromFile(@"Responses\SPO_Response5.json"); testConnector.SetResponseFromFile(@"Responses\SPO_Response5.json");
FormulaValue fv5 = await engine.EvalAsync($@"SP.GetItems(""{dataset}"", ""{table}"", {{'$top': 4}})", CancellationToken.None, runtimeConfig: rc).ConfigureAwait(false); FormulaValue fv5 = await engine.EvalAsync($@"SP.GetItems(""{dataset}"", ""{table}"", {{'$top': 4}})", CancellationToken.None, runtimeConfig: rc).ConfigureAwait(false);
Assert.Equal("Shared Documents/Document.docx", ((UntypedObjectValue)((RecordValue)((TableValue)((RecordValue)fv5).GetField("value")).Rows.First().Value).GetField("{FullPath}")).Impl.GetString()); Assert.Equal("Shared Documents/Document.docx", ((UntypedObjectValue)((RecordValue)((TableValue)((RecordValue)fv5).GetField("value")).Rows.First().Value).GetField("{FullPath}")).Impl.GetString());
string version = PowerPlatformConnectorClient.Version; string version = PowerPlatformConnectorClient.Version;
@ -1367,7 +1367,7 @@ POST https://tip1-shared-002.azure-apim.net/invoke
[Fact] [Fact]
public async Task ExcelOnlineTest() 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; OpenApiDocument apiDoc = testConnector._apiDocument;
PowerFxConfig config = new PowerFxConfig(); PowerFxConfig config = new PowerFxConfig();
string token = @"eyJ0eXAiOiJ..."; string token = @"eyJ0eXAiOiJ...";
@ -1375,12 +1375,12 @@ POST https://tip1-shared-002.azure-apim.net/invoke
using HttpClient httpClient = new HttpClient(testConnector); using HttpClient httpClient = new HttpClient(testConnector);
using PowerPlatformConnectorClient ppClient = new PowerPlatformConnectorClient("https://tip1-shared-002.azure-apim.net", "36897fc0-0c0c-eee5-ac94-e12765496c20" /* env */, "b20e87387f9149e884bdf0b0c87a67e8" /* connId */, () => $"{token}", httpClient) { SessionId = "547d471f-c04c-4c4a-b3af-337ab0637a0d" }; using PowerPlatformConnectorClient ppClient = new PowerPlatformConnectorClient("https://tip1-shared-002.azure-apim.net", "36897fc0-0c0c-eee5-ac94-e12765496c20" /* env */, "b20e87387f9149e884bdf0b0c87a67e8" /* connId */, () => $"{token}", httpClient) { SessionId = "547d471f-c04c-4c4a-b3af-337ab0637a0d" };
ConnectorSettings connectorSettings = new ConnectorSettings("exob") ConnectorSettings connectorSettings = new ConnectorSettings("exob")
{ {
// This shouldn't be used with expressions but this is OK here as this is a tabular connector // This shouldn't be used with expressions but this is OK here as this is a tabular connector
Compatibility = ConnectorCompatibility.SwaggerCompatibility, Compatibility = ConnectorCompatibility.SwaggerCompatibility,
AllowUnsupportedFunctions = true, AllowUnsupportedFunctions = true,
IncludeInternalFunctions = true, IncludeInternalFunctions = true,
ReturnUnknownRecordFieldsAsUntypedObjects = true ReturnUnknownRecordFieldsAsUntypedObjects = true
}; };
List<ConnectorFunction> functions = OpenApiParser.GetFunctions(connectorSettings, apiDoc).OrderBy(f => f.Name).ToList(); List<ConnectorFunction> functions = OpenApiParser.GetFunctions(connectorSettings, apiDoc).OrderBy(f => f.Name).ToList();
@ -1430,7 +1430,7 @@ POST https://tip1-shared-002.azure-apim.net/invoke
[Fact] [Fact]
public async Task DataverseTest_WithComplexMapping() 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 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" }; 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 })")] [InlineData(ConnectorCompatibility.SwaggerCompatibility, "Office365Users.SearchUserV2(", "SearchUserV2({ searchTerm:String,top:Decimal,isSearchTermRequired:Boolean })")]
public async Task ConnectorCompatibilityIntellisenseTest(ConnectorCompatibility compact, string expression, string expected) 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 apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(); var config = new PowerFxConfig();

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

@ -67,13 +67,13 @@ namespace Microsoft.PowerFx.TexlFunctionExporter
int distinctDocCount = docs.Select(t => t.document.HashCode).Distinct().Count(); int distinctDocCount = docs.Select(t => t.document.HashCode).Distinct().Count();
// if single document or all documents with same hashcode // if single document or all documents with same hashcode
if (distinctDocCount == 1) if (distinctDocCount == 1)
{ {
list2.Add(swagger.Key, docs.First()); list2.Add(swagger.Key, docs.First());
} }
// if 2 docs have same description + with one in aapt & one in ppc folders, take the one in 1st folder which aapt version (internal version) // if 2 docs have same description + with one in aapt & one in ppc folders, take the one in 1st folder which aapt version (internal version)
else if (distinctDocCount == 2) else if (distinctDocCount == 2)
{ {
var first = docs.First(); var first = docs.First();
var second = docs.Last(); var second = docs.Last();
@ -117,6 +117,12 @@ namespace Microsoft.PowerFx.TexlFunctionExporter
try try
{ {
OpenApiDocument doc = ReadSwagger(swaggerFile); OpenApiDocument doc = ReadSwagger(swaggerFile);
if (doc == null || doc.Info == null)
{
return;
}
string title = doc.Info.Title; string title = doc.Info.Title;
var item = (folder, swaggerFile, doc); var item = (folder, swaggerFile, doc);
@ -136,17 +142,8 @@ namespace Microsoft.PowerFx.TexlFunctionExporter
public static OpenApiDocument ReadSwagger(string name) public static OpenApiDocument ReadSwagger(string name)
{ {
using (var stream = File.OpenRead(name)) using FileStream stream = File.OpenRead(name);
{ return new OpenApiStreamReader().Read(stream, out OpenApiDiagnostic diag);
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;
}
} }
} }