From 2c3a939dca89957b9e5b2185ca46e9ce0b1deef9 Mon Sep 17 00:00:00 2001 From: Claudia Murialdo Date: Tue, 7 Jun 2022 17:36:34 -0300 Subject: [PATCH 1/3] Add new test for Azure httphandler and API object. --- dotnet/DotNetStandardClasses.sln | 7 + .../AzureFunctionsTest.csproj | 4 + .../AzureFunctionsTest/HttpTriggerTest.cs | 36 ++++ .../private/apiattractions.grp.json | 17 ++ .../type_SdtAttractionOut_Attraction.cs | 196 ++++++++++++++++++ .../test/apiattractions/apiattractions.cs | 93 +++++++++ .../test/apiattractions/apiattractions.csproj | 14 ++ 7 files changed, 367 insertions(+) create mode 100644 dotnet/src/extensions/Azure/test/AzureFunctionsTest/private/apiattractions.grp.json create mode 100644 dotnet/src/extensions/Azure/test/GeneXus.Programs.Common/type_SdtAttractionOut_Attraction.cs create mode 100644 dotnet/src/extensions/Azure/test/apiattractions/apiattractions.cs create mode 100644 dotnet/src/extensions/Azure/test/apiattractions/apiattractions.csproj diff --git a/dotnet/DotNetStandardClasses.sln b/dotnet/DotNetStandardClasses.sln index a76069393..ac114bd0e 100644 --- a/dotnet/DotNetStandardClasses.sln +++ b/dotnet/DotNetStandardClasses.sln @@ -200,6 +200,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestMockDBAccess", "src\ext EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GeneXus.Programs.Common", "src\extensions\Azure\test\GeneXus.Programs.Common\GeneXus.Programs.Common.csproj", "{DCEC0B38-93B6-4003-81E6-9FBC2BB4F163}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "apiattractions", "src\extensions\Azure\test\apiattractions\apiattractions.csproj", "{E85FDB0F-FA81-4CDD-8BF3-865269CE2DB3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -486,6 +488,10 @@ Global {DCEC0B38-93B6-4003-81E6-9FBC2BB4F163}.Debug|Any CPU.Build.0 = Debug|Any CPU {DCEC0B38-93B6-4003-81E6-9FBC2BB4F163}.Release|Any CPU.ActiveCfg = Release|Any CPU {DCEC0B38-93B6-4003-81E6-9FBC2BB4F163}.Release|Any CPU.Build.0 = Release|Any CPU + {E85FDB0F-FA81-4CDD-8BF3-865269CE2DB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E85FDB0F-FA81-4CDD-8BF3-865269CE2DB3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E85FDB0F-FA81-4CDD-8BF3-865269CE2DB3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E85FDB0F-FA81-4CDD-8BF3-865269CE2DB3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -582,6 +588,7 @@ Global {C16BD5A9-4412-4B91-BB70-5C88B7AAE675} = {5045873B-E7CF-4317-94C1-0EF8623D23FA} {B01A243D-C012-4BEB-BAA9-E1D9AC1468C8} = {C16BD5A9-4412-4B91-BB70-5C88B7AAE675} {DCEC0B38-93B6-4003-81E6-9FBC2BB4F163} = {7BA5A2CE-7992-4F87-9D84-91AE4D046F5A} + {E85FDB0F-FA81-4CDD-8BF3-865269CE2DB3} = {7BA5A2CE-7992-4F87-9D84-91AE4D046F5A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E18684C9-7D76-45CD-BF24-E3944B7F174C} diff --git a/dotnet/src/extensions/Azure/test/AzureFunctionsTest/AzureFunctionsTest.csproj b/dotnet/src/extensions/Azure/test/AzureFunctionsTest/AzureFunctionsTest.csproj index 06bc6b9b2..f3d9485b2 100644 --- a/dotnet/src/extensions/Azure/test/AzureFunctionsTest/AzureFunctionsTest.csproj +++ b/dotnet/src/extensions/Azure/test/AzureFunctionsTest/AzureFunctionsTest.csproj @@ -19,6 +19,7 @@ + @@ -31,6 +32,9 @@ PreserveNewest + + PreserveNewest + PreserveNewest diff --git a/dotnet/src/extensions/Azure/test/AzureFunctionsTest/HttpTriggerTest.cs b/dotnet/src/extensions/Azure/test/AzureFunctionsTest/HttpTriggerTest.cs index 90dd77fdf..3d51cb396 100644 --- a/dotnet/src/extensions/Azure/test/AzureFunctionsTest/HttpTriggerTest.cs +++ b/dotnet/src/extensions/Azure/test/AzureFunctionsTest/HttpTriggerTest.cs @@ -18,6 +18,42 @@ namespace Extensions.AzureFunctions.Test { public class HttpTriggerTest { + [Fact] + public void HttpApiObjectTest() + { + try + { + ServiceCollection serviceCollection = new ServiceCollection(); + serviceCollection.AddScoped(); + ServiceProvider serviceProvider = serviceCollection.BuildServiceProvider(); + + Mock context = new Mock(); + context.SetupProperty(c => c.InstanceServices, serviceProvider); + + context.SetupGet(c => c.FunctionId).Returns("6202c88748614a51851a40fa6a4366e6"); + context.SetupGet(c => c.FunctionDefinition.Name).Returns("timerTest"); + context.SetupGet(c => c.InvocationId).Returns("6a871dbc3cb74a9fa95f05ae63505c2c"); + + MockHttpRequestData request = new MockHttpRequestData( + context.Object, + new Uri("http://localhost/apiattractions/listattractions")); + + HttpTriggerHandler function = new HttpTriggerHandler(new GXRouting(String.Empty), null); + HttpResponseData response = function.Run(request, context.Object); + Assert.NotNull(response); + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); + response.Body.Seek(0, SeekOrigin.Begin); + StreamReader reader = new StreamReader(response.Body); + string responseBody = reader.ReadToEnd(); + Assert.NotEmpty(responseBody); + + } + catch (Exception ex) + { + throw new Exception("Exception should not be thrown.", ex); + } + + } [Fact] public void HttpTest() { diff --git a/dotnet/src/extensions/Azure/test/AzureFunctionsTest/private/apiattractions.grp.json b/dotnet/src/extensions/Azure/test/AzureFunctionsTest/private/apiattractions.grp.json new file mode 100644 index 000000000..ac00ab8a5 --- /dev/null +++ b/dotnet/src/extensions/Azure/test/AzureFunctionsTest/private/apiattractions.grp.json @@ -0,0 +1,17 @@ +{ +"ObjectType":"ServiceGroup", +"Name":"APIAttractions", +"BasePath":"APIAttractions", +"Mappings": +[ +{ +"Name":"listattractions", +"Bodystyle":"Wrapped", +"VariableAlias": [], +"ServiceMethod":"gxep_listattractions", +"Implementation":"AttractionsDP", +"Verb":"GET", +"PathRegexp":"listattractions", +"Path":"listattractions" + +}]} \ No newline at end of file diff --git a/dotnet/src/extensions/Azure/test/GeneXus.Programs.Common/type_SdtAttractionOut_Attraction.cs b/dotnet/src/extensions/Azure/test/GeneXus.Programs.Common/type_SdtAttractionOut_Attraction.cs new file mode 100644 index 000000000..f86eb5251 --- /dev/null +++ b/dotnet/src/extensions/Azure/test/GeneXus.Programs.Common/type_SdtAttractionOut_Attraction.cs @@ -0,0 +1,196 @@ +/* + File: type_SdtAttractionOut_Attraction + Description: AttractionOut + Author: Nemo 🐠 for C# (.NET) version 17.0.10.160814 + Program type: Callable routine + Main DBMS: +*/ +using System; +using System.Collections; +using GeneXus.Utils; +using GeneXus.Resources; +using GeneXus.Application; +using GeneXus.Metadata; +using GeneXus.Cryptography; +using GeneXus.Encryption; +using GeneXus.Http.Client; +using GeneXus.Http.Server; +using System.Reflection; +using System.Xml.Serialization; +using System.Runtime.Serialization; + + +namespace GeneXus.Programs +{ + [XmlRoot(ElementName="Attraction")] + [XmlType(TypeName="Attraction" , Namespace="TestServerlessGAM" )] + [Serializable] + public class SdtAttractionOut_Attraction : GxUserType + { + public SdtAttractionOut_Attraction( ) + { + /* Constructor for serialization */ + gxTv_SdtAttractionOut_Attraction_Attractionname = ""; + + } + + public SdtAttractionOut_Attraction(IGxContext context) + { + this.context = context; + initialize(); + } + + #region Json + private static Hashtable mapper; + public override string JsonMap(string value) + { + if (mapper == null) + { + mapper = new Hashtable(); + } + return (string)mapper[value]; ; + } + + public override void ToJSON() + { + ToJSON(true) ; + return; + } + + public override void ToJSON(bool includeState) + { + AddObjectProperty("AttractionId", gxTpr_Attractionid, false); + + + AddObjectProperty("AttractionName", gxTpr_Attractionname, false); + + return; + } + #endregion + + #region Properties + + [SoapElement(ElementName="AttractionId")] + [XmlElement(ElementName="AttractionId")] + public short gxTpr_Attractionid + { + get { + return gxTv_SdtAttractionOut_Attraction_Attractionid; + } + set { + gxTv_SdtAttractionOut_Attraction_Attractionid = value; + SetDirty("Attractionid"); + } + } + + + + + [SoapElement(ElementName="AttractionName")] + [XmlElement(ElementName="AttractionName")] + public string gxTpr_Attractionname + { + get { + return gxTv_SdtAttractionOut_Attraction_Attractionname; + } + set { + gxTv_SdtAttractionOut_Attraction_Attractionname = value; + SetDirty("Attractionname"); + } + } + + + + public override bool ShouldSerializeSdtJson() + { + return true; + } + + + + #endregion + + #region Initialization + + public void initialize( ) + { + gxTv_SdtAttractionOut_Attraction_Attractionname = ""; + return ; + } + + + + #endregion + + #region Declaration + + protected short gxTv_SdtAttractionOut_Attraction_Attractionid; + + + protected string gxTv_SdtAttractionOut_Attraction_Attractionname; + + + + #endregion + } + #region Rest interface + [DataContract(Name=@"Attraction", Namespace="TestServerlessGAM")] + public class SdtAttractionOut_Attraction_RESTInterface : GxGenericCollectionItem, System.Web.SessionState.IRequiresSessionState + { + public SdtAttractionOut_Attraction_RESTInterface( ) : base() + { + } + + public SdtAttractionOut_Attraction_RESTInterface( SdtAttractionOut_Attraction psdt ) : base(psdt) + { + } + + #region Rest Properties + [DataMember(Name="AttractionId", Order=0)] + public short gxTpr_Attractionid + { + get { + return sdt.gxTpr_Attractionid; + + } + set { + sdt.gxTpr_Attractionid = value; + } + } + + [DataMember(Name="AttractionName", Order=1)] + public string gxTpr_Attractionname + { + get { + return StringUtil.RTrim( sdt.gxTpr_Attractionname); + + } + set { + sdt.gxTpr_Attractionname = value; + } + } + + + #endregion + + public SdtAttractionOut_Attraction sdt + { + get { + return (SdtAttractionOut_Attraction)Sdt; + } + set { + Sdt = value; + } + } + + [OnDeserializing] + void checkSdt( StreamingContext ctx ) + { + if ( sdt == null ) + { + sdt = new SdtAttractionOut_Attraction() ; + } + } + } + #endregion +} \ No newline at end of file diff --git a/dotnet/src/extensions/Azure/test/apiattractions/apiattractions.cs b/dotnet/src/extensions/Azure/test/apiattractions/apiattractions.cs new file mode 100644 index 000000000..aadbc0a40 --- /dev/null +++ b/dotnet/src/extensions/Azure/test/apiattractions/apiattractions.cs @@ -0,0 +1,93 @@ +using GeneXus.Application; +using GeneXus.Data; +using GeneXus.Http; +using GeneXus.Procedure; +using GeneXus.Utils; +namespace GeneXus.Programs +{ + public class apiattractions : GXProcedure + { + protected override bool IntegratedSecurityEnabled + { + get + { + return true; + } + + } + + protected override GAMSecurityLevel IntegratedSecurityLevel + { + get + { + return GAMSecurityLevel.SecurityLow; + } + + } + + public apiattractions() + { + context = new GxContext(); + dsGAM = context.GetDataStore("GAM"); + dsDefault = context.GetDataStore("Default"); + IsMain = true; + IsApiObject = true; + } + + public apiattractions(IGxContext context) + { + this.context = context; + IsMain = false; + IsApiObject = true; + dsGAM = context.GetDataStore("GAM"); + dsDefault = context.GetDataStore("Default"); + } + + public void execute() + { + executePrivate(); + } + + void executePrivate() + { + /* GeneXus formulas */ + /* Output device settings */ + this.cleanup(); + } + + public void gxep_listattractions(out GXBaseCollection aP0_AttractionOut) + { + + initialize(); + initialized = 1; + GXBaseCollection Gxm2rootcol = new GXBaseCollection(context, "Attraction", "TestServerlessGAM"); + /* ListAttractions Constructor */ + SdtAttractionOut_Attraction Gxm1attractionout = new SdtAttractionOut_Attraction(context); + Gxm2rootcol.Add(Gxm1attractionout, 0); + Gxm1attractionout.gxTpr_Attractionid = 1; + Gxm1attractionout.gxTpr_Attractionname = "AttractionName"; + + aP0_AttractionOut=Gxm2rootcol; + } + + public override void cleanup() + { + CloseOpenCursors(); + } + + protected void CloseOpenCursors() + { + } + + public override void initialize() + { + /* GeneXus formulas. */ + context.Gx_err = 0; + } + + protected short initialized; + protected IGxDataStore dsGAM; + protected IGxDataStore dsDefault; + } + +} diff --git a/dotnet/src/extensions/Azure/test/apiattractions/apiattractions.csproj b/dotnet/src/extensions/Azure/test/apiattractions/apiattractions.csproj new file mode 100644 index 000000000..12c8a31ed --- /dev/null +++ b/dotnet/src/extensions/Azure/test/apiattractions/apiattractions.csproj @@ -0,0 +1,14 @@ + + + + net6.0 + enable + enable + + + + + + + + From a5d59c04b31dc8c40acae998d2d8e56b853ab4ba Mon Sep 17 00:00:00 2001 From: Claudia Murialdo Date: Wed, 8 Jun 2022 15:00:16 -0300 Subject: [PATCH 2/3] Fix url casing for the test in order to reproduce error 500. --- .../Azure/test/AzureFunctionsTest/HttpTriggerTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dotnet/src/extensions/Azure/test/AzureFunctionsTest/HttpTriggerTest.cs b/dotnet/src/extensions/Azure/test/AzureFunctionsTest/HttpTriggerTest.cs index 3d51cb396..c9131311e 100644 --- a/dotnet/src/extensions/Azure/test/AzureFunctionsTest/HttpTriggerTest.cs +++ b/dotnet/src/extensions/Azure/test/AzureFunctionsTest/HttpTriggerTest.cs @@ -31,12 +31,12 @@ public void HttpApiObjectTest() context.SetupProperty(c => c.InstanceServices, serviceProvider); context.SetupGet(c => c.FunctionId).Returns("6202c88748614a51851a40fa6a4366e6"); - context.SetupGet(c => c.FunctionDefinition.Name).Returns("timerTest"); + context.SetupGet(c => c.FunctionDefinition.Name).Returns("apiattractions"); context.SetupGet(c => c.InvocationId).Returns("6a871dbc3cb74a9fa95f05ae63505c2c"); MockHttpRequestData request = new MockHttpRequestData( context.Object, - new Uri("http://localhost/apiattractions/listattractions")); + new Uri("http://localhost/APIAttractions/ListAttractions")); HttpTriggerHandler function = new HttpTriggerHandler(new GXRouting(String.Empty), null); HttpResponseData response = function.Run(request, context.Object); From e4e32e11c85e1e31762145cbf92f4f97a4cfe569 Mon Sep 17 00:00:00 2001 From: Claudia Murialdo Date: Wed, 8 Jun 2022 20:44:55 -0300 Subject: [PATCH 3/3] Add the fix made at #607 but keeping the conditional operator OR. --- dotnet/src/dotnetcore/GxClasses.Web/Middleware/GXRouting.cs | 3 ++- .../Azure/test/AzureFunctionsTest/HttpTriggerTest.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/dotnet/src/dotnetcore/GxClasses.Web/Middleware/GXRouting.cs b/dotnet/src/dotnetcore/GxClasses.Web/Middleware/GXRouting.cs index b1deaadaa..192d77fd2 100644 --- a/dotnet/src/dotnetcore/GxClasses.Web/Middleware/GXRouting.cs +++ b/dotnet/src/dotnetcore/GxClasses.Web/Middleware/GXRouting.cs @@ -188,7 +188,8 @@ public Task ProcessRestRequest(HttpContext context) string path = context.Request.Path.ToString(); string actualPath = string.Empty; - if (path.Contains($"/{restBaseURL}") || ServiceInPath(path, out actualPath) || (AzureRuntime && path.Contains(oauthRoute))) + bool isServiceInPath = ServiceInPath(path, out actualPath); + if (path.Contains($"/{restBaseURL}") || isServiceInPath || (AzureRuntime && path.Contains(oauthRoute))) { string controllerWithParms = string.Empty; if (!AzureRuntime) diff --git a/dotnet/src/extensions/Azure/test/AzureFunctionsTest/HttpTriggerTest.cs b/dotnet/src/extensions/Azure/test/AzureFunctionsTest/HttpTriggerTest.cs index c9131311e..bed11eb6b 100644 --- a/dotnet/src/extensions/Azure/test/AzureFunctionsTest/HttpTriggerTest.cs +++ b/dotnet/src/extensions/Azure/test/AzureFunctionsTest/HttpTriggerTest.cs @@ -31,7 +31,7 @@ public void HttpApiObjectTest() context.SetupProperty(c => c.InstanceServices, serviceProvider); context.SetupGet(c => c.FunctionId).Returns("6202c88748614a51851a40fa6a4366e6"); - context.SetupGet(c => c.FunctionDefinition.Name).Returns("apiattractions"); + context.SetupGet(c => c.FunctionDefinition.Name).Returns("listattractions"); context.SetupGet(c => c.InvocationId).Returns("6a871dbc3cb74a9fa95f05ae63505c2c"); MockHttpRequestData request = new MockHttpRequestData(