diff --git a/Directory.Build.props b/Directory.Build.props deleted file mode 100644 index ab09286..0000000 --- a/Directory.Build.props +++ /dev/null @@ -1,9 +0,0 @@ - - - - 3.0.0.0 - $(AssemblyVersion) - $(AssemblyVersion) - - - diff --git a/FunctionsSdk.sln b/FunctionsSdk.sln index 0815f4b..78da388 100644 --- a/FunctionsSdk.sln +++ b/FunctionsSdk.sln @@ -7,7 +7,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{14D6456E-2F9 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{9B6D0171-3FFD-4892-B407-B633CA4E6712}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.NET.Sdk.Functions.Generator.Tests", "test\Microsoft.NET.Sdk.Functions.Generator.Tests\Microsoft.NET.Sdk.Functions.Generator.Tests.csproj", "{9D59910B-B90E-4BBE-BD26-C2CBF85D37E1}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.NET.Sdk.Functions.Generator.Tests", "test\Microsoft.NET.Sdk.Functions.Generator.Tests\Microsoft.NET.Sdk.Functions.Generator.Tests.csproj", "{9D59910B-B90E-4BBE-BD26-C2CBF85D37E1}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "pack", "pack", "{8D555953-A625-4C7F-93A7-C737644820AB}" EndProject @@ -25,6 +25,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.NET.Sdk.Functions EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.NET.Sdk.Functions.MSBuild", "src\Microsoft.NET.Sdk.Functions.MSBuild\Microsoft.NET.Sdk.Functions.MSBuild.csproj", "{1DB38EB5-DBA9-4678-BB99-2BCD1255DDBE}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.NET.Sdk.Functions.EndToEnd.Tests", "test\Microsoft.NET.Sdk.Functions.EndToEnd.Tests\Microsoft.NET.Sdk.Functions.EndToEnd.Tests.csproj", "{3F8DD976-ABCC-4B6B-B991-CEAAA4C03736}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -51,6 +53,10 @@ Global {1DB38EB5-DBA9-4678-BB99-2BCD1255DDBE}.Debug|Any CPU.Build.0 = Debug|Any CPU {1DB38EB5-DBA9-4678-BB99-2BCD1255DDBE}.Release|Any CPU.ActiveCfg = Release|Any CPU {1DB38EB5-DBA9-4678-BB99-2BCD1255DDBE}.Release|Any CPU.Build.0 = Release|Any CPU + {3F8DD976-ABCC-4B6B-B991-CEAAA4C03736}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3F8DD976-ABCC-4B6B-B991-CEAAA4C03736}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3F8DD976-ABCC-4B6B-B991-CEAAA4C03736}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3F8DD976-ABCC-4B6B-B991-CEAAA4C03736}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -61,6 +67,7 @@ Global {6CEDE940-9F0A-4B2A-97D4-D1EEEE42AF35} = {14D6456E-2F9D-4483-A378-03701A6EB12D} {B80DA350-8A69-4CD2-9E60-01C51B5A8633} = {9B6D0171-3FFD-4892-B407-B633CA4E6712} {1DB38EB5-DBA9-4678-BB99-2BCD1255DDBE} = {14D6456E-2F9D-4483-A378-03701A6EB12D} + {3F8DD976-ABCC-4B6B-B991-CEAAA4C03736} = {9B6D0171-3FFD-4892-B407-B633CA4E6712} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {DA731A15-774F-46C2-B8DF-298F828DCC2A} diff --git a/appveyor.cmd b/appveyor.cmd index 6e8c4bb..49634ba 100644 --- a/appveyor.cmd +++ b/appveyor.cmd @@ -1,4 +1,4 @@ powershell Invoke-WebRequest -Uri 'https://dot.net/v1/dotnet-install.ps1' -UseBasicParsing -OutFile '%TEMP%\dotnet-install.ps1' -powershell %TEMP%\dotnet-install.ps1 -Architecture x64 -Version '3.0.100' -InstallDir '%ProgramFiles%\dotnet' +powershell %TEMP%\dotnet-install.ps1 -Architecture x64 -Version '3.1.301' -InstallDir '%ProgramFiles%\dotnet' .paket\paket.exe install packages\FAKE\tools\fake .\build.fsx \ No newline at end of file diff --git a/build.fsx b/build.fsx index 4c81270..9f385fb 100644 --- a/build.fsx +++ b/build.fsx @@ -57,6 +57,7 @@ Target "Build" (fun _ -> Configuration = "Release"}) ) + Target "UnitTest" (fun _ -> DotNetCli.Test (fun p -> {p with @@ -67,16 +68,22 @@ Target "UnitTest" (fun _ -> {p with Project = "test\\Microsoft.NET.Sdk.Functions.MSBuild.Tests" Configuration = "Debug"}) + + DotNetCli.Test (fun p -> + {p with + Project = "test\\Microsoft.NET.Sdk.Functions.EndToEnd.Tests" + Configuration = "Debug" + AdditionalArgs=["--logger"; "console;verbosity=detailed"]}) ) Target "GenerateZipToSign" (fun _ -> - !! (packOutputPath @@ "netcoreapp3.0\\Microsoft.NET.Sdk.Functions.dll") + !! (packOutputPath @@ "netcoreapp3.1\\Microsoft.NET.Sdk.Functions.dll") ++ (buildTaskOutputPath @@ "netstandard2.0\\Microsoft.NET.Sdk.Functions.MSBuild.dll") - ++ (generatorOutputPath @@ "netcoreapp3.0\\Microsoft.NET.Sdk.Functions.Generator.dll") + ++ (generatorOutputPath @@ "netcoreapp3.1\\Microsoft.NET.Sdk.Functions.Generator.dll") |> CreateZip "." (version + "netstandard2.zip") "" 7 true - !! (generatorOutputPath @@ "netcoreapp3.0\\Newtonsoft.Json.dll") - ++ (generatorOutputPath @@ "netcoreapp3.0\\Mono.Cecil.dll") + !! (generatorOutputPath @@ "netcoreapp3.1\\Newtonsoft.Json.dll") + ++ (generatorOutputPath @@ "netcoreapp3.1\\Mono.Cecil.dll") |> CreateZip "." (version + "netstandard2thirdparty.zip") "" 7 true ) @@ -126,9 +133,9 @@ Target "WaitForSigning" (fun _ -> match signed with | Success file -> Unzip "tmpBuild" file - MoveFileTo ("tmpBuild" @@ "Microsoft.NET.Sdk.Functions.dll", packOutputPath @@ "netcoreapp3.0\\Microsoft.NET.Sdk.Functions.dll") + MoveFileTo ("tmpBuild" @@ "Microsoft.NET.Sdk.Functions.dll", packOutputPath @@ "netcoreapp3.1\\Microsoft.NET.Sdk.Functions.dll") MoveFileTo ("tmpBuild" @@ "Microsoft.NET.Sdk.Functions.MSBuild.dll", buildTaskOutputPath @@ "netstandard2.0\\Microsoft.NET.Sdk.Functions.MSBuild.dll") - MoveFileTo ("tmpBuild" @@ "Microsoft.NET.Sdk.Functions.Generator.dll", generatorOutputPath @@ "netcoreapp3.0\\Microsoft.NET.Sdk.Functions.Generator.dll") + MoveFileTo ("tmpBuild" @@ "Microsoft.NET.Sdk.Functions.Generator.dll", generatorOutputPath @@ "netcoreapp3.1\\Microsoft.NET.Sdk.Functions.Generator.dll") | Failure e -> targetError e null |> ignore CleanDir "tmpBuild" @@ -137,8 +144,8 @@ Target "WaitForSigning" (fun _ -> match signed with | Success file -> Unzip "tmpBuild" file - MoveFileTo ("tmpBuild" @@ "Newtonsoft.Json.dll", generatorOutputPath @@ "netcoreapp3.0\\Newtonsoft.Json.dll") - MoveFileTo ("tmpBuild" @@ "Mono.Cecil.dll", generatorOutputPath @@ "netcoreapp3.0\\Mono.Cecil.dll") + MoveFileTo ("tmpBuild" @@ "Newtonsoft.Json.dll", generatorOutputPath @@ "netcoreapp3.1\\Newtonsoft.Json.dll") + MoveFileTo ("tmpBuild" @@ "Mono.Cecil.dll", generatorOutputPath @@ "netcoreapp3.1\\Mono.Cecil.dll") | Failure e -> targetError e null |> ignore ) diff --git a/pack/Microsoft.NET.Sdk.Functions/Microsoft.NET.Sdk.Functions.csproj b/pack/Microsoft.NET.Sdk.Functions/Microsoft.NET.Sdk.Functions.csproj index 272c81b..73b88e9 100644 --- a/pack/Microsoft.NET.Sdk.Functions/Microsoft.NET.Sdk.Functions.csproj +++ b/pack/Microsoft.NET.Sdk.Functions/Microsoft.NET.Sdk.Functions.csproj @@ -4,14 +4,13 @@ - netcoreapp3.0 + netcoreapp3.1 Microsoft.NET.Sdk.Functions $(FunctionsSdkVersion) Microsoft https://github.com/Azure/azure-functions-vs-build-sdk https://github.com/Azure/azure-functions-vs-build-sdk - https://github.com/Azure/azure-functions-vs-build-sdk/blob/master/LICENSE - https://github.com/Azure/azure-functions-vs-build-sdk/blob/master/LICENSE + MIT https://github.com/Azure/azure-functions-vs-build-sdk git azurefunctions @@ -20,8 +19,8 @@ Build SDK for Azure Functions true tools - ..\..\src\Microsoft.NET.Sdk.Functions.MSBuild\bin\Release - ..\..\src\Microsoft.NET.Sdk.Functions.Generator\bin\Release + ..\..\src\Microsoft.NET.Sdk.Functions.MSBuild\bin\$(Configuration) + ..\..\src\Microsoft.NET.Sdk.Functions.Generator\bin\$(Configuration) false @@ -44,29 +43,29 @@ true - tools\netcoreapp3.0\ + tools\netcoreapp3.1\ - + true - tools\netcoreapp3.0\ + tools\netcoreapp3.1\ - + true - tools\netcoreapp3.0\ + tools\netcoreapp3.1\ - + true - tools\netcoreapp3.0\ + tools\netcoreapp3.1\ - + true - tools\netcoreapp3.0\ + tools\netcoreapp3.1\ - + true - tools\netcoreapp3.0\ + tools\netcoreapp3.1\ diff --git a/src/Microsoft.NET.Sdk.Functions.Generator/Microsoft.NET.Sdk.Functions.Generator.csproj b/src/Microsoft.NET.Sdk.Functions.Generator/Microsoft.NET.Sdk.Functions.Generator.csproj index 030cd2a..3790171 100644 --- a/src/Microsoft.NET.Sdk.Functions.Generator/Microsoft.NET.Sdk.Functions.Generator.csproj +++ b/src/Microsoft.NET.Sdk.Functions.Generator/Microsoft.NET.Sdk.Functions.Generator.csproj @@ -1,9 +1,10 @@  - + + - 3.0.0 + $(FunctionsSdkVersion) Exe - netcoreapp3.0 + netcoreapp3.1 true Debug diff --git a/src/Microsoft.NET.Sdk.Functions.MSBuild/Microsoft.NET.Sdk.Functions.MSBuild.csproj b/src/Microsoft.NET.Sdk.Functions.MSBuild/Microsoft.NET.Sdk.Functions.MSBuild.csproj index 44e50f5..62e7fce 100644 --- a/src/Microsoft.NET.Sdk.Functions.MSBuild/Microsoft.NET.Sdk.Functions.MSBuild.csproj +++ b/src/Microsoft.NET.Sdk.Functions.MSBuild/Microsoft.NET.Sdk.Functions.MSBuild.csproj @@ -1,7 +1,8 @@  + - 3.0.0 + $(FunctionsSdkVersion) netstandard2.0 diff --git a/src/Microsoft.NET.Sdk.Functions.MSBuild/Targets/Microsoft.NET.Sdk.Functions.Build.targets b/src/Microsoft.NET.Sdk.Functions.MSBuild/Targets/Microsoft.NET.Sdk.Functions.Build.targets index e6074cf..a01da3d 100644 --- a/src/Microsoft.NET.Sdk.Functions.MSBuild/Targets/Microsoft.NET.Sdk.Functions.Build.targets +++ b/src/Microsoft.NET.Sdk.Functions.MSBuild/Targets/Microsoft.NET.Sdk.Functions.Build.targets @@ -19,20 +19,8 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and ============================================================ --> - - true - - - - - - - - + AfterTargets="Build" + DependsOnTargets="_FunctionsPostBuildCollectFiles;_FunctionsPostBuildCopyFiles"> + + + + + + + + + + - + + + + + + + + - - + + + diff --git a/src/Microsoft.NET.Sdk.Functions.MSBuild/Targets/Microsoft.NET.Sdk.Functions.Publish.targets b/src/Microsoft.NET.Sdk.Functions.MSBuild/Targets/Microsoft.NET.Sdk.Functions.Publish.targets index faa8d5e..772a75b 100644 --- a/src/Microsoft.NET.Sdk.Functions.MSBuild/Targets/Microsoft.NET.Sdk.Functions.Publish.targets +++ b/src/Microsoft.NET.Sdk.Functions.MSBuild/Targets/Microsoft.NET.Sdk.Functions.Publish.targets @@ -17,22 +17,6 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and - - - + diff --git a/src/Microsoft.NET.Sdk.Functions.MSBuild/Targets/Microsoft.NET.Sdk.Functions.targets b/src/Microsoft.NET.Sdk.Functions.MSBuild/Targets/Microsoft.NET.Sdk.Functions.targets index d892ded..7c59a7c 100644 --- a/src/Microsoft.NET.Sdk.Functions.MSBuild/Targets/Microsoft.NET.Sdk.Functions.targets +++ b/src/Microsoft.NET.Sdk.Functions.MSBuild/Targets/Microsoft.NET.Sdk.Functions.targets @@ -12,12 +12,13 @@ WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <_FunctionsTaskFramework>netcoreapp3.0 + <_FunctionsTaskFramework>netcoreapp3.1 <_FunctionsTasksDir Condition=" '$(_FunctionsTasksDir)'=='' ">$(MSBuildThisFileDirectory)..\tools\$(_FunctionsTaskFramework)\ <_FunctionsTaskAssemblyFullPath Condition=" '$(_FunctionsTaskAssemblyFullPath)'=='' ">$(_FunctionsTasksDir)\Microsoft.NET.Sdk.Functions.MSBuild.dll true pdbonly - false + false + true true diff --git a/src/Microsoft.NET.Sdk.Functions.MSBuild/Tasks/GenerateFunctions.cs b/src/Microsoft.NET.Sdk.Functions.MSBuild/Tasks/GenerateFunctions.cs index 652236e..ae0a8f1 100644 --- a/src/Microsoft.NET.Sdk.Functions.MSBuild/Tasks/GenerateFunctions.cs +++ b/src/Microsoft.NET.Sdk.Functions.MSBuild/Tasks/GenerateFunctions.cs @@ -6,13 +6,7 @@ namespace Microsoft.NET.Sdk.Functions.Tasks { -#if NET46 - [LoadInSeparateAppDomain] - public class GenerateFunctions : AppDomainIsolatedTask -#else - public class GenerateFunctions : Task -#endif { [Required] public string TargetPath { get; set; } @@ -23,18 +17,13 @@ public class GenerateFunctions : Task [Required] public string TaskAssemblyDirectory { get; set; } - public bool UseNETCoreGenerator { get; set; } - - public bool UseNETFrameworkGenerator { get; set; } - public bool GenerateHostJson { get; set; } public ITaskItem[] UserProvidedFunctionJsonFiles { get; set; } public bool FunctionsInDependencies { get; set; } - private const string NETFrameworkFolder = "net46"; - private const string NETStandardFolder = "netcoreapp3.0"; + private const string NETCoreAppFolder = "netcoreapp3.1"; public override bool Execute() { @@ -47,21 +36,8 @@ public override bool Execute() string taskDirectoryFullPath = Path.GetFullPath(TaskAssemblyDirectory).TrimEnd(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }); string baseDirectory = Path.GetDirectoryName(taskDirectoryFullPath); - ProcessStartInfo processStartInfo = null; -#if NET46 - processStartInfo = GetProcessStartInfo(baseDirectory, isCore: false); - if (UseNETCoreGenerator) - { - processStartInfo = GetProcessStartInfo(baseDirectory, isCore: true); - } -#else - processStartInfo = GetProcessStartInfo(baseDirectory, isCore: true); - if (UseNETFrameworkGenerator) - { - processStartInfo = GetProcessStartInfo(baseDirectory, isCore: false); - } + ProcessStartInfo processStartInfo = GetProcessStartInfo(baseDirectory); -#endif this.Log.LogMessage(MessageImportance.Low, $"Function generator path: '{processStartInfo.FileName}'"); this.Log.LogCommandLine(MessageImportance.Low, processStartInfo.Arguments); using (Process process = new Process { StartInfo = processStartInfo }) @@ -89,11 +65,11 @@ public override bool Execute() } } - private ProcessStartInfo GetProcessStartInfo(string baseLocation, bool isCore) + private ProcessStartInfo GetProcessStartInfo(string baseLocation) { - string workingDirectory = isCore ? Path.Combine(baseLocation, NETStandardFolder) : Path.Combine(baseLocation, NETFrameworkFolder); - string exePath = isCore ? DotNetMuxer.MuxerPathOrDefault() : Path.Combine(workingDirectory, "Microsoft.NET.Sdk.Functions.Generator.exe"); - string arguments = isCore ? $"Microsoft.NET.Sdk.Functions.Generator.dll \"{TargetPath} \" \"{OutputPath} \" \"{FunctionsInDependencies} \"" : $"\"{TargetPath} \" \"{OutputPath} \" \"{FunctionsInDependencies} \""; + string workingDirectory = Path.Combine(baseLocation, NETCoreAppFolder); + string exePath = DotNetMuxer.MuxerPathOrDefault(); + string arguments = $"Microsoft.NET.Sdk.Functions.Generator.dll \"{TargetPath} \" \"{OutputPath} \" \"{FunctionsInDependencies} \""; string excludedFunctionNamesArg = UserProvidedFunctionJsonFiles? .Select(f => f.ItemSpec.Replace("/", @"\").Replace(@"\function.json", string.Empty)) diff --git a/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/FunctionsSdkTests.cs b/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/FunctionsSdkTests.cs new file mode 100644 index 0000000..cf8d90e --- /dev/null +++ b/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/FunctionsSdkTests.cs @@ -0,0 +1,141 @@ +using System.IO; +using System.Linq; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.NET.Sdk.Functions.EndToEnd.Tests +{ + public class FunctionsSdkTests + { + private string _packageSource; + private string _testsDirectory; + private TestInitialize _testInitializer; + private ITestOutputHelper _testOutputHelper; + public FunctionsSdkTests(ITestOutputHelper output) + { + _testInitializer = new TestInitialize(output); + _testOutputHelper = output; + _packageSource = _testInitializer.PackageSource; + _testsDirectory = _testInitializer.TestDirectory; + } + + [Fact] + public void BuildAndPublish_CopiesBinariesToAdditionalBinFolder() + { + // Name of the csproj + string projectFileToTest = "FunctionsSdk"; + string projectFileDirectory = Path.Combine(_testsDirectory, projectFileToTest); + + // Restore + string dotnetArgs = $"restore {projectFileToTest}.csproj --source {_packageSource}"; + int? exitCode = new ProcessWrapper().RunProcess(TestInitialize.DotNetExecutable, dotnetArgs, projectFileDirectory, out int? _, createDirectoryIfNotExists: false, testOutputHelper: _testOutputHelper); + Assert.True(exitCode.HasValue && exitCode.Value == 0); + + // Build + dotnetArgs = $"build {projectFileToTest}.csproj --configuration {TestInitialize.Configuration}"; + exitCode = new ProcessWrapper().RunProcess(TestInitialize.DotNetExecutable, dotnetArgs, projectFileDirectory, out int? _, createDirectoryIfNotExists: false, testOutputHelper: _testOutputHelper); + Assert.True(exitCode.HasValue && exitCode.Value == 0); + + string additionalBinDir = Path.Combine(projectFileDirectory, "bin", TestInitialize.Configuration, TestInitialize.Framework, "bin"); + Assert.True(Directory.Exists(additionalBinDir)); + + var files = Directory.EnumerateFiles(additionalBinDir, "*.dll", SearchOption.AllDirectories); + Assert.True(files.Count() > 1); + + // Publish + dotnetArgs = $"publish {projectFileToTest}.csproj --configuration {TestInitialize.Configuration}"; + exitCode = new ProcessWrapper().RunProcess(TestInitialize.DotNetExecutable, dotnetArgs, projectFileDirectory, out int? _, createDirectoryIfNotExists: false, testOutputHelper: _testOutputHelper); + Assert.True(exitCode.HasValue && exitCode.Value == 0); + + string additionalPublishBinDir = Path.Combine(projectFileDirectory, "bin", TestInitialize.Configuration, TestInitialize.Framework, "publish", "bin"); + Assert.True(Directory.Exists(additionalPublishBinDir)); + + files = Directory.EnumerateFiles(additionalPublishBinDir, "*.dll", SearchOption.AllDirectories); + Assert.True(files.Count() > 1); + } + + [Fact] + public void BuildAndPublish_CopiesRuntimesToAdditionalBinFolder() + { + // Name of the csproj + string projectFileToTest = "FunctionsSdkWithSQLClient"; + string projectFileDirectory = Path.Combine(_testsDirectory, projectFileToTest); + + // Restore + string dotnetArgs = $"restore {projectFileToTest}.csproj --source {TestInitialize.NuGetPackageSource};{_packageSource}"; + int? exitCode = new ProcessWrapper().RunProcess(TestInitialize.DotNetExecutable, dotnetArgs, projectFileDirectory, out int? _, createDirectoryIfNotExists: false, testOutputHelper: _testOutputHelper); + Assert.True(exitCode.HasValue && exitCode.Value == 0); + + // Build + dotnetArgs = $"build {projectFileToTest}.csproj --configuration {TestInitialize.Configuration}"; + exitCode = new ProcessWrapper().RunProcess(TestInitialize.DotNetExecutable, dotnetArgs, projectFileDirectory, out int? _, createDirectoryIfNotExists: false, testOutputHelper: _testOutputHelper); + Assert.True(exitCode.HasValue && exitCode.Value == 0); + + string additionalBinDir = Path.Combine(projectFileDirectory, "bin", TestInitialize.Configuration, TestInitialize.Framework, "bin"); + Assert.True(Directory.Exists(additionalBinDir)); + + var files = Directory.EnumerateFiles(additionalBinDir, "*.dll", SearchOption.AllDirectories); + Assert.True(files.Count() > 1); + + files = Directory.EnumerateFiles(Path.Combine(additionalBinDir, "runtimes"), "*.dll", SearchOption.AllDirectories); + Assert.True(files.Count() > 1); + + // Publish + dotnetArgs = $"publish {projectFileToTest}.csproj --configuration {TestInitialize.Configuration}"; + exitCode = new ProcessWrapper().RunProcess(TestInitialize.DotNetExecutable, dotnetArgs, projectFileDirectory, out int? _, createDirectoryIfNotExists: false, testOutputHelper: _testOutputHelper); + Assert.True(exitCode.HasValue && exitCode.Value == 0); + + string additionalPublishBinDir = Path.Combine(projectFileDirectory, "bin", TestInitialize.Configuration, TestInitialize.Framework, "publish", "bin"); + Assert.True(Directory.Exists(additionalPublishBinDir)); + + files = Directory.EnumerateFiles(additionalPublishBinDir, "*.dll", SearchOption.AllDirectories); + Assert.True(files.Count() > 1); + + files = Directory.EnumerateFiles(Path.Combine(additionalPublishBinDir, "runtimes"), "*.dll", SearchOption.AllDirectories); + Assert.True(files.Count() > 1); + } + + [Fact] + public void Build_FunctionAppWithHttpTrigger_GeneratedFunction() + { + // Name of the csproj + string projectFileToTest = "FunctionAppWithHttpTrigger"; + string projectFileDirectory = Path.Combine(_testsDirectory, projectFileToTest); + + // Restore + string dotnetArgs = $"restore {projectFileToTest}.csproj --source {_packageSource}"; + int? exitCode = new ProcessWrapper().RunProcess(TestInitialize.DotNetExecutable, dotnetArgs, projectFileDirectory, out int? _, createDirectoryIfNotExists: false, testOutputHelper: _testOutputHelper); + Assert.True(exitCode.HasValue && exitCode.Value == 0); + + // Build + dotnetArgs = $"build {projectFileToTest}.csproj --configuration {TestInitialize.Configuration}"; + exitCode = new ProcessWrapper().RunProcess(TestInitialize.DotNetExecutable, dotnetArgs, projectFileDirectory, out int? _, createDirectoryIfNotExists: false, testOutputHelper: _testOutputHelper); + Assert.True(exitCode.HasValue && exitCode.Value == 0); + + string binDir = Path.Combine(projectFileDirectory, "bin", TestInitialize.Configuration, TestInitialize.Framework); + string additionalBinDir = Path.Combine(binDir, "bin"); + Assert.True(Directory.Exists(additionalBinDir)); + var files = Directory.EnumerateFiles(additionalBinDir, "*.dll", SearchOption.AllDirectories); + Assert.True(files.Count() > 1); + + // Check if the http function is generated + string httpTriggerFunctionpath = Path.Combine(binDir, "HttpFunction", "function.json"); + Assert.True(File.Exists(httpTriggerFunctionpath)); + + // Publish + dotnetArgs = $"publish {projectFileToTest}.csproj --configuration {TestInitialize.Configuration}"; + exitCode = new ProcessWrapper().RunProcess(TestInitialize.DotNetExecutable, dotnetArgs, projectFileDirectory, out int? _, createDirectoryIfNotExists: false, testOutputHelper: _testOutputHelper); + Assert.True(exitCode.HasValue && exitCode.Value == 0); + + string publishDir = Path.Combine(projectFileDirectory, "bin", TestInitialize.Configuration, TestInitialize.Framework, "publish"); + string additionalPublishBinDir = Path.Combine(publishDir, "bin"); + Assert.True(Directory.Exists(additionalPublishBinDir)); + + files = Directory.EnumerateFiles(additionalPublishBinDir, "*.dll", SearchOption.AllDirectories); + Assert.True(files.Count() > 1); + + httpTriggerFunctionpath = Path.Combine(publishDir, "HttpFunction", "function.json"); + Assert.True(File.Exists(httpTriggerFunctionpath)); + } + } +} diff --git a/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/Microsoft.NET.Sdk.Functions.EndToEnd.Tests.csproj b/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/Microsoft.NET.Sdk.Functions.EndToEnd.Tests.csproj new file mode 100644 index 0000000..66d424b --- /dev/null +++ b/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/Microsoft.NET.Sdk.Functions.EndToEnd.Tests.csproj @@ -0,0 +1,22 @@ + + + + netcoreapp3.1 + + + + + + + + + + Always + + + + + + + + diff --git a/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/ProcessWrapper.cs b/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/ProcessWrapper.cs new file mode 100644 index 0000000..4498f45 --- /dev/null +++ b/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/ProcessWrapper.cs @@ -0,0 +1,46 @@ +using System; +using System.Diagnostics; +using System.IO; +using Xunit.Abstractions; + +namespace Microsoft.NET.Sdk.Functions.EndToEnd.Tests +{ + public class ProcessWrapper + { + public int? RunProcess(string fileName, string arguments, string workingDirectory, out int? processId, bool createDirectoryIfNotExists = true, bool waitForExit = true, ITestOutputHelper testOutputHelper = null) + { + if (createDirectoryIfNotExists && !Directory.Exists(workingDirectory)) + { + Directory.CreateDirectory(workingDirectory); + } + + ProcessStartInfo startInfo = new ProcessStartInfo + { + CreateNoWindow = true, + UseShellExecute = false, + WorkingDirectory = workingDirectory, + FileName = fileName, + RedirectStandardError = true, + RedirectStandardOutput = true, + }; + if (!string.IsNullOrEmpty(arguments)) + { + startInfo.Arguments = arguments; + } + + Process testProcess = Process.Start(startInfo); + processId = testProcess?.Id; + if (waitForExit) + { + testProcess.WaitForExit(3 * 60 * 1000); + var standardOut = testProcess.StandardOutput.ReadToEnd(); + var standardError = testProcess.StandardError.ReadToEnd(); + testOutputHelper?.WriteLine(standardOut); + testOutputHelper?.WriteLine(standardError); + return testProcess?.ExitCode; + } + + return -1; + } + } +} diff --git a/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/Resources/FunctionAppWithHttpTrigger/FunctionAppWithHttpTrigger.csproj b/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/Resources/FunctionAppWithHttpTrigger/FunctionAppWithHttpTrigger.csproj new file mode 100644 index 0000000..7380a99 --- /dev/null +++ b/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/Resources/FunctionAppWithHttpTrigger/FunctionAppWithHttpTrigger.csproj @@ -0,0 +1,23 @@ + + + + + netcoreapp3.1 + v3 + + + + + + + + + PreserveNewest + + + PreserveNewest + Never + + + + \ No newline at end of file diff --git a/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/Resources/FunctionAppWithHttpTrigger/HttpFunction.cs b/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/Resources/FunctionAppWithHttpTrigger/HttpFunction.cs new file mode 100644 index 0000000..ae2ea34 --- /dev/null +++ b/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/Resources/FunctionAppWithHttpTrigger/HttpFunction.cs @@ -0,0 +1,35 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Azure.WebJobs; +using Microsoft.Azure.WebJobs.Extensions.Http; +using Microsoft.AspNetCore.Http; +using Microsoft.Extensions.Logging; +using Newtonsoft.Json; + +namespace FunctionApp1 +{ + public static class HttpFunction + { + [FunctionName("HttpFunction")] + public static async Task Run( + [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req, + ILogger log) + { + log.LogInformation("C# HTTP trigger function processed a request."); + + string name = req.Query["name"]; + + string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); + dynamic data = JsonConvert.DeserializeObject(requestBody); + name = name ?? data?.name; + + string responseMessage = string.IsNullOrEmpty(name) + ? "This HTTP triggered function executed successfully. Pass a name in the query string or in the request body for a personalized response." + : $"Hello, {name}. This HTTP triggered function executed successfully."; + + return new OkObjectResult(responseMessage); + } + } +} diff --git a/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/Resources/FunctionAppWithHttpTrigger/host.json b/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/Resources/FunctionAppWithHttpTrigger/host.json new file mode 100644 index 0000000..bb3b8da --- /dev/null +++ b/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/Resources/FunctionAppWithHttpTrigger/host.json @@ -0,0 +1,11 @@ +{ + "version": "2.0", + "logging": { + "applicationInsights": { + "samplingExcludedTypes": "Request", + "samplingSettings": { + "isEnabled": true + } + } + } +} \ No newline at end of file diff --git a/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/Resources/FunctionAppWithHttpTrigger/local.settings.json b/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/Resources/FunctionAppWithHttpTrigger/local.settings.json new file mode 100644 index 0000000..4fce9ff --- /dev/null +++ b/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/Resources/FunctionAppWithHttpTrigger/local.settings.json @@ -0,0 +1,7 @@ +{ + "IsEncrypted": false, + "Values": { + "AzureWebJobsStorage": "UseDevelopmentStorage=true", + "FUNCTIONS_WORKER_RUNTIME": "dotnet" + } +} \ No newline at end of file diff --git a/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/Resources/FunctionsSdk/FunctionsSdk.csproj b/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/Resources/FunctionsSdk/FunctionsSdk.csproj new file mode 100644 index 0000000..a4c317b --- /dev/null +++ b/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/Resources/FunctionsSdk/FunctionsSdk.csproj @@ -0,0 +1,13 @@ + + + + + netcoreapp3.1 + v3 + + + + + + + \ No newline at end of file diff --git a/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/Resources/FunctionsSdkWithSQLClient/FunctionsSdkWithSQlClient.csproj b/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/Resources/FunctionsSdkWithSQLClient/FunctionsSdkWithSQlClient.csproj new file mode 100644 index 0000000..4f7e7b2 --- /dev/null +++ b/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/Resources/FunctionsSdkWithSQLClient/FunctionsSdkWithSQlClient.csproj @@ -0,0 +1,13 @@ + + + + + netcoreapp3.1 + v3 + + + + + + + \ No newline at end of file diff --git a/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/TestInitialize.cs b/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/TestInitialize.cs new file mode 100644 index 0000000..dbd667a --- /dev/null +++ b/test/Microsoft.NET.Sdk.Functions.EndToEnd.Tests/TestInitialize.cs @@ -0,0 +1,100 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.NET.Sdk.Functions.EndToEnd.Tests +{ + public class TestInitialize + { + public const string TestProjectsSourceDirectory = "Resources"; + public const string TestProjectsTargetDirectory = "TestResults"; + public const string FunctionsNetSdkProject = "Microsoft.Net.Sdk.Functions"; + public const string FunctionsMsBuildProject = "Microsoft.NET.Sdk.Functions.MSBuild"; + public const string FunctionsGeneratorProject = "Microsoft.NET.Sdk.Functions.Generator"; + public const string Configuration = "Debug"; + public const string Framework = "netcoreapp3.1"; + public const string NuGetPackageSource = @"https://api.nuget.org/v3/index.json"; + + public static readonly string DotNetExecutable = "dotnet"; + public static readonly string PathToRepoRoot = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, @"..\..\..\..\..\")); + public static readonly string SrcRoot = Path.Combine(PathToRepoRoot, "src"); + public static readonly string PackRoot = Path.Combine(PathToRepoRoot, "pack"); + public static readonly string TestRoot = Path.Combine(PathToRepoRoot, "test"); + + public string PackageSource { get; private set; } + public string TestDirectory { get; private set; } + + public TestInitialize(ITestOutputHelper testOutputHelper, bool runRestore = false, bool runBuild = false, bool runPack = true) + { + string dotnetArgs; + int? exitCode; + string projectDir = Path.Combine(PackRoot, FunctionsNetSdkProject); + + if (runRestore) + { + // Run dotnet restore at solution root. + dotnetArgs = $"restore"; + exitCode = new ProcessWrapper().RunProcess(DotNetExecutable, dotnetArgs, PathToRepoRoot, out int? _, createDirectoryIfNotExists: false, testOutputHelper: testOutputHelper); + Debug.Assert(exitCode.HasValue && exitCode.Value == 0); + } + + if (runBuild) + { + dotnetArgs = $"build --configuration {Configuration}"; + + // Build the functions msbuild project. + projectDir = Path.Combine(SrcRoot, FunctionsMsBuildProject); + exitCode = new ProcessWrapper().RunProcess(DotNetExecutable, dotnetArgs, projectDir, out int? _, createDirectoryIfNotExists: false, testOutputHelper: testOutputHelper); + Debug.Assert(exitCode.HasValue && exitCode.Value == 0); + + // Build the functions generator project. + projectDir = Path.Combine(SrcRoot, FunctionsGeneratorProject); + exitCode = new ProcessWrapper().RunProcess(DotNetExecutable, dotnetArgs, projectDir, out _, createDirectoryIfNotExists: false, testOutputHelper: testOutputHelper); + Debug.Assert(exitCode.HasValue && exitCode.Value == 0); + } + + if (runPack) + { + dotnetArgs = $"pack --configuration {Configuration}"; + + // Create the package + projectDir = Path.Combine(PackRoot, FunctionsNetSdkProject); + exitCode = new ProcessWrapper().RunProcess(DotNetExecutable, dotnetArgs, projectDir, out _, createDirectoryIfNotExists: false, testOutputHelper: testOutputHelper); + Debug.Assert(exitCode.HasValue && exitCode.Value == 0); + } + + // Setup the package source. + PackageSource = Path.Combine(projectDir, "bin", Configuration) + Path.DirectorySeparatorChar; + + // Setup the test directory. + string sourceDirectory = Path.Combine(AppContext.BaseDirectory, TestProjectsSourceDirectory); + DirectoryInfo diSource = new DirectoryInfo(sourceDirectory); + + string targetDirectory = Path.Combine(PathToRepoRoot, TestProjectsTargetDirectory); + DirectoryInfo diTarget = new DirectoryInfo(targetDirectory); + + CopyAll(diSource, diTarget); + TestDirectory = targetDirectory; + } + + private void CopyAll(DirectoryInfo source, DirectoryInfo target) + { + Directory.CreateDirectory(target.FullName); + + foreach (FileInfo fi in source.GetFiles()) + { + fi.CopyTo(Path.Combine(target.FullName, fi.Name), true); + } + + foreach (DirectoryInfo diSourceSubDir in source.GetDirectories()) + { + DirectoryInfo nextTargetSubDir = + target.CreateSubdirectory(diSourceSubDir.Name); + CopyAll(diSourceSubDir, nextTargetSubDir); + } + } + } +} diff --git a/test/Microsoft.NET.Sdk.Functions.Generator.Tests/Microsoft.NET.Sdk.Functions.Generator.Tests.csproj b/test/Microsoft.NET.Sdk.Functions.Generator.Tests/Microsoft.NET.Sdk.Functions.Generator.Tests.csproj index dcd4657..d9dc629 100644 --- a/test/Microsoft.NET.Sdk.Functions.Generator.Tests/Microsoft.NET.Sdk.Functions.Generator.Tests.csproj +++ b/test/Microsoft.NET.Sdk.Functions.Generator.Tests/Microsoft.NET.Sdk.Functions.Generator.Tests.csproj @@ -1,7 +1,7 @@  Library - netcoreapp3.0 + netcoreapp3.1 true PublicKey.snk true diff --git a/test/Microsoft.NET.Sdk.Functions.MSBuild.Tests/Microsoft.NET.Sdk.Functions.MSBuild.Tests.csproj b/test/Microsoft.NET.Sdk.Functions.MSBuild.Tests/Microsoft.NET.Sdk.Functions.MSBuild.Tests.csproj index 038adf6..15a6a09 100644 --- a/test/Microsoft.NET.Sdk.Functions.MSBuild.Tests/Microsoft.NET.Sdk.Functions.MSBuild.Tests.csproj +++ b/test/Microsoft.NET.Sdk.Functions.MSBuild.Tests/Microsoft.NET.Sdk.Functions.MSBuild.Tests.csproj @@ -1,7 +1,7 @@ - netcoreapp2.0 + netcoreapp3.1