Skip to content

Commit

Permalink
Json fix
Browse files Browse the repository at this point in the history
  • Loading branch information
LucGenetier committed Apr 2, 2024
1 parent 69894e3 commit 8038004
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 5 deletions.
21 changes: 16 additions & 5 deletions src/libraries/Microsoft.PowerFx.Json/FormulaValueJSON.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
using System.Diagnostics.Contracts;
using System.Linq;
using System.Text.Json;
using Microsoft.PowerFx.Core.Functions;
using Microsoft.PowerFx.Core.IR;
using Microsoft.PowerFx.Core.Types;
using Microsoft.PowerFx.Functions;
Expand All @@ -32,10 +31,22 @@ public static FormulaValue FromJson(string jsonString, FormulaType formulaType =

public static FormulaValue FromJson(string jsonString, FormulaValueJsonSerializerSettings settings, FormulaType formulaType = null)
{
using JsonDocument document = JsonDocument.Parse(jsonString);
JsonElement propBag = document.RootElement;

return FromJson(propBag, settings, formulaType);
try
{
using JsonDocument document = JsonDocument.Parse(jsonString);
JsonElement propBag = document.RootElement;

return FromJson(propBag, settings, formulaType);
}
catch (JsonException je)
{
return new ErrorValue(IRContext.NotInSource(formulaType), new ExpressionError()
{
Message = $"{je.GetType().Name} {je.Message} {je.StackTrace}",
Span = new Syntax.Span(0, 0),
Kind = ErrorKind.Network
});
}
}

/// <summary>
Expand Down
33 changes: 33 additions & 0 deletions src/tests/Microsoft.PowerFx.Connectors.Tests/IntellisenseTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,39 @@ public void ConnectorIntellisenseTest_ServerError()
Assert.Equal(string.Empty, list);
}

[Fact]
public void ConnectorIntellisenseTest_EmptyResponse()
{
string expression = @"SQL.ExecuteProcedureV2(""default"", ""default"", ""sp_2"", { ";

using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\SQL Server.json", _output);
OpenApiDocument apiDoc = testConnector._apiDocument;
PowerFxConfig config = new PowerFxConfig(Features.PowerFxV1);

using HttpClient httpClient = new HttpClient(testConnector);
using PowerPlatformConnectorClient client = new PowerPlatformConnectorClient("tip1-shared-002.azure-apim.net", "a2df3fb8-e4a4-e5e6-905c-e3dff9f93b46", "5f57ec83acef477b8ccc769e52fa22cc", () => "eyJ0eXA...", httpClient)
{
SessionId = "8e67ebdc-d402-455a-b33a-304820832383"
};

config.AddActionConnector("SQL", apiDoc, new ConsoleLogger(_output));

// The response is empty, this is to ensure we manage properly the exception coming from ExtractFromJson
testConnector.SetResponseFromFile(@"Responses\EmptyResponse.json");

RecalcEngine engine = new RecalcEngine(config);
BasicServiceProvider serviceProvider = new BasicServiceProvider().AddRuntimeContext(new TestConnectorRuntimeContext("SQL", client, console: _output));

CheckResult checkResult = engine.Check(expression, symbolTable: null);

// This call should not throw an exception
IIntellisenseResult suggestions = engine.Suggest(checkResult, expression.Length, serviceProvider);

// We don't get any result as the response is invalid
string list = string.Join("|", suggestions.Suggestions.Select(s => s.DisplayText.Text).OrderBy(x => x));
Assert.Equal(string.Empty, list);
}

[Theory]
[InlineData(1, 1, @"SQL.ExecuteProcedureV2(""default"", ""default"", ""sp_1"", ", @"p1")] // stored proc with 1 param, out of record
public void ConnectorIntellisenseTestLSP(int responseIndex, int networkCall, string expression, string expectedSuggestions)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1422,6 +1422,64 @@ public async Task SQL_ExecuteStoredProc_WithUserAgent()
Assert.Equal(expected, actual);
}

[Fact]
public async Task SQL_ExecuteStoredProc_WithEmptyServerResponse()
{
using var testConnector = new LoggingTestServer(@"Swagger\SQL Server.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(Features.PowerFxV1);
using var httpClient = new HttpClient(testConnector);
using var client = new PowerPlatformConnectorClient("tip1-shared-002.azure-apim.net", "a2df3fb8-e4a4-e5e6-905c-e3dff9f93b46", "5f57ec83acef477b8ccc769e52fa22cc", () => "eyJ0eX...", "MyProduct/v1.2", httpClient)
{
SessionId = "8e67ebdc-d402-455a-b33a-304820832383"
};

config.AddActionConnector("SQL", apiDoc, new ConsoleLogger(_output));
var engine = new RecalcEngine(config);
RuntimeConfig rc = new RuntimeConfig().AddRuntimeContext(new TestConnectorRuntimeContext("SQL", client, console: _output));

testConnector.SetResponseFromFile(@"Responses\EmptyResponse.json");
FormulaValue result = await engine.EvalAsync(@"SQL.ExecuteProcedureV2(""pfxdev-sql.database.windows.net"", ""connectortest"", ""sp_1"", { p1: 50 })", CancellationToken.None, new ParserOptions() { AllowsSideEffects = true }, runtimeConfig: rc).ConfigureAwait(false);
Assert.True(result is BlankValue);
}

[Fact]
public async Task SQL_ExecuteStoredProc_WithInvalidResponse()
{
using var testConnector = new LoggingTestServer(@"Swagger\SQL Server.json", _output);
var apiDoc = testConnector._apiDocument;
var config = new PowerFxConfig(Features.PowerFxV1);
using var httpClient = new HttpClient(testConnector);
using var client = new PowerPlatformConnectorClient("tip1-shared-002.azure-apim.net", "a2df3fb8-e4a4-e5e6-905c-e3dff9f93b46", "5f57ec83acef477b8ccc769e52fa22cc", () => "eyJ0eX...", "MyProduct/v1.2", httpClient)
{
SessionId = "8e67ebdc-d402-455a-b33a-304820832383"
};

config.AddActionConnector("SQL", apiDoc, new ConsoleLogger(_output));
var engine = new RecalcEngine(config);
RuntimeConfig rc = new RuntimeConfig().AddRuntimeContext(new TestConnectorRuntimeContext("SQL", client, console: _output));

testConnector.SetResponseFromFile(@"Responses\Invalid.txt");
FormulaValue result = await engine.EvalAsync(@"SQL.ExecuteProcedureV2(""pfxdev-sql.database.windows.net"", ""connectortest"", ""sp_1"", { p1: 50 })", CancellationToken.None, new ParserOptions() { AllowsSideEffects = true }, runtimeConfig: rc).ConfigureAwait(false);

ErrorValue ev = Assert.IsType<ErrorValue>(result);

#pragma warning disable SA1116 // Split parameters should start on line after declaration

Assert.Equal(@$"SQL.ExecuteProcedureV2 failed: JsonReaderException '+' is an invalid start of a value. LineNumber: 0 | BytePositionInLine: 0. at System.Text.Json.ThrowHelper.ThrowJsonReaderException(Utf8JsonReader& json, ExceptionResource resource, Byte nextByte, ReadOnlySpan`1 bytes)
at System.Text.Json.Utf8JsonReader.ConsumeValue(Byte marker)
at System.Text.Json.Utf8JsonReader.ReadFirstToken(Byte first)
at System.Text.Json.Utf8JsonReader.ReadSingleSegment()
at System.Text.Json.Utf8JsonReader.Read()
at System.Text.Json.JsonDocument.Parse(ReadOnlySpan`1 utf8JsonSpan, JsonReaderOptions readerOptions, MetadataDb& database, StackRowStack& stack)
at System.Text.Json.JsonDocument.Parse(ReadOnlyMemory`1 utf8Json, JsonReaderOptions readerOptions, Byte[] extraRentedArrayPoolBytes, PooledByteBufferWriter extraPooledByteBufferWriter)
at System.Text.Json.JsonDocument.Parse(ReadOnlyMemory`1 json, JsonDocumentOptions options)
at System.Text.Json.JsonDocument.Parse(String json, JsonDocumentOptions options)
at Microsoft.PowerFx.Types.FormulaValueJSON.FromJson(String jsonString, FormulaValueJsonSerializerSettings settings, FormulaType formulaType) in C:\Data\Power-Fx\src\libraries\Microsoft.PowerFx.Json\FormulaValueJSON.cs:line 38", ev.Errors[0].Message);

#pragma warning restore SA1116 // Split parameters should start on line after declaration
}

[Fact]
public async Task SharePointOnlineTest()
{
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
+

0 comments on commit 8038004

Please sign in to comment.