diff --git a/DotNetFunction.sln b/DotNetFunction.sln index 0c98633..f5a849e 100644 --- a/DotNetFunction.sln +++ b/DotNetFunction.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26720.2 +VisualStudioVersion = 15.0.26730.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DotNetFunction", "src\DotNetFunction\DotNetFunction.csproj", "{E82A3F5E-9CA6-4E2E-8D51-A938DD62A363}" EndProject diff --git a/README.md b/README.md index ab79120..0885c2e 100644 --- a/README.md +++ b/README.md @@ -82,3 +82,4 @@ Here are the DevOps practices highlighted within this CD pipeline: - [Application Insights integration with Functions now in preview](https://blogs.msdn.microsoft.com/appserviceteam/2017/05/10/application-insights-integration-with-functions-now-in-preview/) - Deploying Azure Function App with Deployment Slots using ARM Templates - Blog series: [First](https://nascent.blog/2017/05/31/azure-function-app-deployment-slots-arm-template/), [Second](https://nascent.blog/2017/06/22/azure-functions-arm-templates-snags-1-http-triggers-keys/) and [Third](https://nascent.blog/2017/06/27/azure-functions-slots-arm-templates-snags-2-redeploy-causes-unwanted-swap/) - [Is Your Serverless Application Testable? – Azure Functions](https://blog.kloud.com.au/2017/07/22/is-your-serverless-application-testable-azure-functions/) +- [Azure Functions Proxies Sample](https://github.com/Azure-Samples/functions-js-spa) diff --git a/docs/DotNet-FunctionApp-CD.md b/docs/DotNet-FunctionApp-CD.md index c33732d..bb9c0f0 100644 --- a/docs/DotNet-FunctionApp-CD.md +++ b/docs/DotNet-FunctionApp-CD.md @@ -71,7 +71,7 @@ TODO - Override Template Parameters = -functionAppName $(ResourceGroupName) -slotName $(SlotName) - Deployment Mode = Incremental - Deploy Function App on Staging - - Type = Deploy Staging + - Type = Azure App Service Deploy - Version = 3.* - Azure Subscription = set appropriate - App Service Name = $(ResourceGroupName) @@ -80,20 +80,28 @@ TODO - Slot = $(SlotName) - Package or Folder = $(System.DefaultWorkingDirectory)/DotNet-FunctionApp-CI/function - Publish using Web Deploy = true -- Check Production URL +- Check Staging URL - Type = [Check URL Status](https://marketplace.visualstudio.com/items?itemName=saeidbabaei.checkUrl) - - URL = https://$(ResourceGroupName)-$(SlotName).azurewebsites.net/api/SampleHelloDotNetFunction/test + - Version = 1.* + - URL = https://$(ResourceGroupName)-$(SlotName).azurewebsites.net/api/SampleHelloDotNetFunction +- Replace tokens in integration tests config file + - Type = [Replace Tokens](https://marketplace.visualstudio.com/items?itemName=qetza.replacetokens) + - Version = 2.* + - Target files = $(System.DefaultWorkingDirectory)/xUnit-CI/integration-tests/*.config + - Files encoding = auto + - Write unicode BOM = true + - Action (Missing variables) = log warning + - Keep token = true + - Token prefix = #{ + - Token suffix = }# - Run IntegrationTests - Type = Visual Studio Test - Version = 2.* - Select tests using = Test assemblies - Test assemblies = *IntegrationTests.dll - Search folder = $(System.DefaultWorkingDirectory)/DotNet-FunctionApp-CI/integration-tests - - Test filter criteria = TestCategory=IntegrationTests - Select test platform using = Version - Test paltform version = Latest - - Settings file = $(System.DefaultWorkingDirectory)/DotNet-FunctionApp-CI/integration-tests/TestRunParameters.runsettings - - Override test run parameters = -BaseUrl https://$(ResourceGroupName)-$(SlotName).azurewebsites.net/api/SampleHelloDotNetFunction - Test run title = IntegrationTests - Build Platform = $(ReleasePlatform) - Build Configuration = $(ReleaseConfiguration) @@ -133,6 +141,7 @@ TODO - Script Arguments = -ResourceGroupName $(ResourceGroupName) - Check Production URL - Type = [Check URL Status](https://marketplace.visualstudio.com/items?itemName=saeidbabaei.checkUrl) + - Version = 1.* - URL = https://$(ResourceGroupName).azurewebsites.net/api/SampleHelloDotNetFunction/test ### General remark @@ -167,6 +176,7 @@ This environment should be used just if necessary when the bad things happened i - Swap with Production = true - Check Production URL - Type = [Check URL Status](https://marketplace.visualstudio.com/items?itemName=saeidbabaei.checkUrl) + - Version = 1.* - URL = https://$(ResourceGroupName).azurewebsites.net/api/SampleHelloDotNetFunction/test # Deploy to Azure buttons diff --git a/docs/DotNet-FunctionApp-CI.md b/docs/DotNet-FunctionApp-CI.md index 0cf703b..89e836f 100644 --- a/docs/DotNet-FunctionApp-CI.md +++ b/docs/DotNet-FunctionApp-CI.md @@ -66,10 +66,13 @@ TODO - Select tests using = Test assemblies - Test assemblies = \**\$(BuildConfiguration)\*UnitTests.dll\n!**\obj\** - Search folder = $(System.DefaultWorkingDirectory) - - Test filter criteria = TestCategory=UnitTests + - Select test platform using = Version + - Test platform version = Latest + - Code coverage enabled = true - Test run title = UnitTests - Build Platform = $(BuildPlatform) - Build Configuration = $(BuildConfiguration) + - Upload test attachments = true - Validate ARM Templates: production - Type = Azure Resource Group Deployment - Version = 2.* diff --git a/docs/imgs/DotNet-FunctionApp-CD-Rollback.PNG b/docs/imgs/DotNet-FunctionApp-CD-Rollback.PNG index 231218b..0e2a339 100644 Binary files a/docs/imgs/DotNet-FunctionApp-CD-Rollback.PNG and b/docs/imgs/DotNet-FunctionApp-CD-Rollback.PNG differ diff --git a/docs/imgs/DotNet-FunctionApp-CD-Staging.PNG b/docs/imgs/DotNet-FunctionApp-CD-Staging.PNG index 99f3f56..7c7cec4 100644 Binary files a/docs/imgs/DotNet-FunctionApp-CD-Staging.PNG and b/docs/imgs/DotNet-FunctionApp-CD-Staging.PNG differ diff --git a/docs/imgs/DotNet-FunctionApp-CD.PNG b/docs/imgs/DotNet-FunctionApp-CD.PNG index 3105c25..0ba6c30 100644 Binary files a/docs/imgs/DotNet-FunctionApp-CD.PNG and b/docs/imgs/DotNet-FunctionApp-CD.PNG differ diff --git a/src/DotNetFunction/SampleHelloDotNetFunction.cs b/src/DotNetFunction/SampleHelloDotNetFunction.cs index 5fc7fe8..8e63046 100644 --- a/src/DotNetFunction/SampleHelloDotNetFunction.cs +++ b/src/DotNetFunction/SampleHelloDotNetFunction.cs @@ -1,31 +1,50 @@ using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Extensions.Http; -using Microsoft.Azure.WebJobs.Host; +using System.Linq; using System.Net; using System.Net.Http; +using System.Threading.Tasks; namespace DotNetFunction { public static class SampleHelloDotNetFunction { [FunctionName("SampleHelloDotNetFunction")] - public static HttpResponseMessage Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "SampleHelloDotNetFunction/{name}")]HttpRequestMessage request, string name, TraceWriter log) + public static async Task Run([HttpTrigger(AuthorizationLevel.Anonymous, "get")]HttpRequestMessage request) { - var responseText = InternalSampleHelloDotNetFunction(name); + var name = request.GetQueryNameValuePairs() + .FirstOrDefault(q => string.Compare(q.Key, "name", true) == 0) + .Value; - log?.Info($"Response text: {responseText}"); + dynamic data = await request.Content.ReadAsAsync(); - return request.CreateResponse(HttpStatusCode.OK, responseText); + var responseMessage = string.Empty; + HttpStatusCode httpStatusCode = HttpStatusCode.OK; + if(!GetResponseMessage(name, data?.name, out responseMessage)) + { + httpStatusCode = HttpStatusCode.BadRequest; + } + + return request.CreateResponse(httpStatusCode, responseMessage); } - public static string InternalSampleHelloDotNetFunction(string name) + /// + /// Get the response message to display according the name value passed either in the query string or in the request body. + /// Note: The query string has priority over the request body. + /// + /// The name value in the query string. + /// The name value in the request body. + /// The out parameter containing the response message. + /// Return true if an appropriate name was provided and set a response message accordingly. Otherwise return false and set an help message. + public static bool GetResponseMessage(string nameInQueryString, string nameInRequestBody, out string responseMessage) { - var responseText = "Hello, World!"; + var name = !string.IsNullOrWhiteSpace(nameInQueryString) ? nameInQueryString : nameInRequestBody; - if (!string.IsNullOrEmpty(name)) - responseText = $"Hello, {name}!"; + responseMessage = string.IsNullOrWhiteSpace(name) + ? "Please pass a name on the query string or in the request body." + : $"Hello, {name}!"; - return responseText; + return !string.IsNullOrWhiteSpace(name); } } } \ No newline at end of file diff --git a/test/DotNetFunction.IntegrationTests/App.config b/test/DotNetFunction.IntegrationTests/App.config new file mode 100644 index 0000000..3ca8e4a --- /dev/null +++ b/test/DotNetFunction.IntegrationTests/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/test/DotNetFunction.IntegrationTests/DotNetFunction.IntegrationTests.csproj b/test/DotNetFunction.IntegrationTests/DotNetFunction.IntegrationTests.csproj index c810c61..cc4b01a 100644 --- a/test/DotNetFunction.IntegrationTests/DotNetFunction.IntegrationTests.csproj +++ b/test/DotNetFunction.IntegrationTests/DotNetFunction.IntegrationTests.csproj @@ -1,6 +1,7 @@  - - + + + Debug AnyCPU @@ -11,12 +12,6 @@ DotNetFunction.IntegrationTests v4.6.1 512 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 15.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages - False - UnitTest @@ -38,36 +33,48 @@ 4 - - ..\..\packages\MSTest.TestFramework.1.1.18\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll - True - - - ..\..\packages\MSTest.TestFramework.1.1.18\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll - True - + + + + + + + + ..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll + + + ..\..\packages\xunit.assert.2.2.0\lib\netstandard1.1\xunit.assert.dll + + + ..\..\packages\xunit.extensibility.core.2.2.0\lib\netstandard1.1\xunit.core.dll + + + ..\..\packages\xunit.extensibility.execution.2.2.0\lib\net452\xunit.execution.desktop.dll + - + - - + Always - + + + + + + + - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - + - \ No newline at end of file diff --git a/test/DotNetFunction.IntegrationTests/Properties/AssemblyInfo.cs b/test/DotNetFunction.IntegrationTests/Properties/AssemblyInfo.cs index 0c1b43a..d5d115b 100644 --- a/test/DotNetFunction.IntegrationTests/Properties/AssemblyInfo.cs +++ b/test/DotNetFunction.IntegrationTests/Properties/AssemblyInfo.cs @@ -1,7 +1,10 @@ -using System.Reflection; +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. [assembly: AssemblyTitle("DotNetFunction.IntegrationTests")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] @@ -11,10 +14,23 @@ [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] -[assembly: Guid("a6398be2-943a-4c33-b05d-e796cbb86cf4")] +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("05254f4f-38fe-467d-9916-8679165cd921")] +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/test/DotNetFunction.IntegrationTests/SampleHelloDotNetFunctionTests.cs b/test/DotNetFunction.IntegrationTests/SampleHelloDotNetFunctionTests.cs index 2420053..0609581 100644 --- a/test/DotNetFunction.IntegrationTests/SampleHelloDotNetFunctionTests.cs +++ b/test/DotNetFunction.IntegrationTests/SampleHelloDotNetFunctionTests.cs @@ -1,28 +1,23 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using System.Configuration; using System.Net.Http; using System.Threading.Tasks; +using Xunit; namespace DotNetFunction.IntegrationTests { - [TestClass] public class SampleHelloDotNetFunctionTests { - public TestContext TestContext { get; set; } - private string BaseUrl = "http://localhost:7071/api/SampleHelloDotNetFunction"; + private string BaseUrl = "https://localhost:7071/api/SampleHelloDotNetFunction"; - [TestInitialize()] - public void TestInitialize() + public SampleHelloDotNetFunctionTests() { - if (TestContext.Properties["BaseUrl"] != null) - { - //Set the BaseURL from a build - BaseUrl = TestContext.Properties["BaseUrl"].ToString(); - } + var appSettings = ConfigurationManager.AppSettings; + var baseUrlParameter = appSettings["BaseUrl"]; + BaseUrl = string.IsNullOrEmpty(baseUrlParameter) || baseUrlParameter == "#{BaseUrl}#" ? BaseUrl : baseUrlParameter; } - [TestMethod] - [TestCategory("IntegrationTests")] - public async Task EmptyNameShouldSendNotFound() + [Fact] + public async Task Get_EmptyName_ShouldSendBadRequestAndHelpMessage() { //Arrange var httpClient = new HttpClient(); @@ -30,27 +25,60 @@ public async Task EmptyNameShouldSendNotFound() //Act var response = await httpClient.GetAsync(urlTested); + var text = await response.Content.ReadAsStringAsync(); + + //Assert + Assert.Equal(response.StatusCode, System.Net.HttpStatusCode.BadRequest); + Assert.Equal(text, "Please pass a name on the query string or in the request body."); + } + + [Fact] + public async Task Post_ShouldSendNotAllowed() + { + //Arrange + var httpClient = new HttpClient(); + var urlTested = BaseUrl; + var name = "test"; + var httpContent = new StringContent($"name={name}"); + + //Act + var response = await httpClient.PostAsync(urlTested, httpContent); + + //Assert + Assert.Equal(response.StatusCode, System.Net.HttpStatusCode.MethodNotAllowed); + } + + [Fact] + public async Task Put_ShouldSendNotAllowed() + { + //Arrange + var httpClient = new HttpClient(); + var urlTested = BaseUrl; + var name = "test"; + var httpContent = new StringContent($"name={name}"); + + //Act + var response = await httpClient.PutAsync(urlTested, httpContent); //Assert - Assert.AreEqual(response.StatusCode, System.Net.HttpStatusCode.NotFound); + Assert.Equal(response.StatusCode, System.Net.HttpStatusCode.MethodNotAllowed); } - [TestMethod] - [TestCategory("IntegrationTests")] + [Fact] public async Task NotEmptyNameShouldSendOK() { //Arrange var httpClient = new HttpClient(); - var nameTested = "john"; - var urlTested = $"{BaseUrl}/{nameTested}"; + var name = "john"; + var urlTested = $"{BaseUrl}/{name}"; //Act var response = await httpClient.GetAsync(urlTested); var text = await response.Content.ReadAsStringAsync(); //Assert - Assert.AreEqual(response.StatusCode, System.Net.HttpStatusCode.OK); - Assert.AreEqual(text, $"\"Hello, {nameTested}!\""); + Assert.Equal(response.StatusCode, System.Net.HttpStatusCode.OK); + Assert.Equal(text, $"\"Hello, {name}!\""); } } diff --git a/test/DotNetFunction.IntegrationTests/TestRunParameters.runsettings b/test/DotNetFunction.IntegrationTests/TestRunParameters.runsettings deleted file mode 100644 index 827561f..0000000 --- a/test/DotNetFunction.IntegrationTests/TestRunParameters.runsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/test/DotNetFunction.IntegrationTests/packages.config b/test/DotNetFunction.IntegrationTests/packages.config index d8c1b90..c2ba02a 100644 --- a/test/DotNetFunction.IntegrationTests/packages.config +++ b/test/DotNetFunction.IntegrationTests/packages.config @@ -1,5 +1,11 @@  - - + + + + + + + + \ No newline at end of file diff --git a/test/DotNetFunction.UnitTests/DotNetFunction.UnitTests.csproj b/test/DotNetFunction.UnitTests/DotNetFunction.UnitTests.csproj index e302133..e7ab6a0 100644 --- a/test/DotNetFunction.UnitTests/DotNetFunction.UnitTests.csproj +++ b/test/DotNetFunction.UnitTests/DotNetFunction.UnitTests.csproj @@ -1,6 +1,7 @@  - - + + + Debug AnyCPU @@ -11,12 +12,6 @@ DotNetFunction.UnitTests v4.6.1 512 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 15.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages - False - UnitTest @@ -38,25 +33,33 @@ 4 - - ..\..\packages\MSTest.TestFramework.1.1.18\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.dll - True - - - ..\..\packages\MSTest.TestFramework.1.1.18\lib\net45\Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll - True - + + + + + + + + ..\..\packages\xunit.abstractions.2.0.1\lib\net35\xunit.abstractions.dll + + + ..\..\packages\xunit.assert.2.2.0\lib\netstandard1.1\xunit.assert.dll + + + ..\..\packages\xunit.extensibility.core.2.2.0\lib\netstandard1.1\xunit.core.dll + + + ..\..\packages\xunit.extensibility.execution.2.2.0\lib\net452\xunit.execution.desktop.dll + - - Designer - + @@ -64,14 +67,14 @@ DotNetFunction - + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - + - \ No newline at end of file diff --git a/test/DotNetFunction.UnitTests/Properties/AssemblyInfo.cs b/test/DotNetFunction.UnitTests/Properties/AssemblyInfo.cs index 40a70b5..520b9cd 100644 --- a/test/DotNetFunction.UnitTests/Properties/AssemblyInfo.cs +++ b/test/DotNetFunction.UnitTests/Properties/AssemblyInfo.cs @@ -1,7 +1,10 @@ -using System.Reflection; +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. [assembly: AssemblyTitle("DotNetFunction.UnitTests")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] @@ -11,10 +14,23 @@ [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. [assembly: ComVisible(false)] -[assembly: Guid("f1674604-9fdc-4033-bf0e-ade1ac5fafba")] +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c17f344e-ccda-4ed2-93c1-e7bd6d4507e4")] +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] [assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/test/DotNetFunction.UnitTests/SampleHelloDotNetFunctionTests.cs b/test/DotNetFunction.UnitTests/SampleHelloDotNetFunctionTests.cs index a6751db..b94311f 100644 --- a/test/DotNetFunction.UnitTests/SampleHelloDotNetFunctionTests.cs +++ b/test/DotNetFunction.UnitTests/SampleHelloDotNetFunctionTests.cs @@ -1,36 +1,76 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; +using Xunit; namespace DotNetFunction.UnitTests { - [TestClass] public class SampleHelloDotNetFunctionTests { - [TestMethod] - [TestCategory("UnitTests")] - public void EmptyNameShouldReturnHelloWorld() + [Theory] + [InlineData("", "")] + [InlineData(" ", "")] + [InlineData("", " ")] + [InlineData(" ", " ")] + [InlineData(null, null)] + public void EmptyNameInQueryString_And_EmptyNameInRequestBody_Should_ReturnHelpMessage(string nameInQueryString, string nameInRequestBody) { //Arrange - var name = string.Empty; + var responseMessage = string.Empty; //Act - var result = SampleHelloDotNetFunction.InternalSampleHelloDotNetFunction(name); + var result = SampleHelloDotNetFunction.GetResponseMessage(nameInQueryString, nameInRequestBody, out responseMessage); //Assert - Assert.AreEqual(result, "Hello, World!"); + Assert.False(result); + Assert.Equal(responseMessage, "Please pass a name on the query string or in the request body."); } - [TestMethod] - [TestCategory("UnitTests")] - public void NotEmptyNameShouldReturnAppropriateHello() + [Theory] + [InlineData("", "John")] + [InlineData(" ", "Test")] + [InlineData(null, "Peter")] + public void EmptyNameInQueryString_And_NotEmptyNameInRequestBody_Should_ReturnMessageWithNameInRequestBody(string nameInQueryString, string nameInRequestBody) { //Arrange - var name = "John"; + var responseMessage = string.Empty; //Act - var result = SampleHelloDotNetFunction.InternalSampleHelloDotNetFunction(name); + var result = SampleHelloDotNetFunction.GetResponseMessage(nameInQueryString, nameInRequestBody, out responseMessage); //Assert - Assert.AreEqual(result, $"Hello, {name}!"); + Assert.True(result); + Assert.Equal(responseMessage, $"Hello, {nameInRequestBody}!"); + } + + [Theory] + [InlineData("John", "")] + [InlineData("Test", " ")] + [InlineData("Peter", null)] + public void NotEmptyNameInQueryString_And_EmptyNameInRequestBody_Should_ReturnMessageWithNameInQueryString(string nameInQueryString, string nameInRequestBody) + { + //Arrange + var responseMessage = string.Empty; + + //Act + var result = SampleHelloDotNetFunction.GetResponseMessage(nameInQueryString, nameInRequestBody, out responseMessage); + + //Assert + Assert.True(result); + Assert.Equal(responseMessage, $"Hello, {nameInQueryString}!"); + } + + [Theory] + [InlineData("John", "Body")] + [InlineData("Test", "Request")] + public void NotEmptyNameInQueryString_And_NotEmptyNameInRequestBody_Should_ReturnMessageWithNameInQueryString(string nameInQueryString, string nameInRequestBody) + { + //Arrange + var responseMessage = string.Empty; + + //Act + var result = SampleHelloDotNetFunction.GetResponseMessage(nameInQueryString, nameInRequestBody, out responseMessage); + + //Assert + Assert.True(result); + Assert.Equal(responseMessage, $"Hello, {nameInQueryString}!"); } } } diff --git a/test/DotNetFunction.UnitTests/packages.config b/test/DotNetFunction.UnitTests/packages.config index d8c1b90..c2ba02a 100644 --- a/test/DotNetFunction.UnitTests/packages.config +++ b/test/DotNetFunction.UnitTests/packages.config @@ -1,5 +1,11 @@  - - + + + + + + + + \ No newline at end of file diff --git a/vsts/DotNet-FunctionApp-CD.json b/vsts/DotNet-FunctionApp-CD.json index d020554..b5a003c 100644 --- a/vsts/DotNet-FunctionApp-CD.json +++ b/vsts/DotNet-FunctionApp-CD.json @@ -1,7 +1,7 @@ { "source": 2, "id": 1, - "revision": 50, + "revision": 53, "name": "DotNet-FunctionApp-CD", "description": null, "createdBy": { @@ -19,7 +19,7 @@ "url": "https://app.vssps.visualstudio.com/A6d1a4ff8-9a1f-46cb-bd61-54cb9a797939/_apis/Identities/17256fe4-f2a3-4370-b081-ec283edb6a77", "imageUrl": "https://mabenoit-ms.visualstudio.com/_api/_common/identityImage?id=17256fe4-f2a3-4370-b081-ec283edb6a77" }, - "modifiedOn": "2017-07-26T19:59:48.017Z", + "modifiedOn": "2017-08-03T18:29:34.553Z", "path": "\\", "variables": { "Location": { @@ -221,6 +221,30 @@ "url": "https://$(ResourceGroupName)-$(SlotName).azurewebsites.net/api/SampleHelloDotNetFunction/test" } }, + { + "taskId": "a8515ec8-7254-4ffd-912c-86772e2b5962", + "version": "2.*", + "name": "Replace tokens in integration tests config file", + "refName": "replacetokens1", + "enabled": true, + "alwaysRun": false, + "continueOnError": false, + "timeoutInMinutes": 0, + "definitionType": "task", + "overrideInputs": {}, + "condition": "succeeded()", + "inputs": { + "rootDirectory": "", + "targetFiles": "$(System.DefaultWorkingDirectory)/xUnit-CI/integration-tests/*.config", + "encoding": "auto", + "writeBOM": "true", + "actionOnMissing": "warn", + "keepToken": "true", + "tokenPrefix": "#{", + "tokenSuffix": "}#", + "emptyValue": "(empty)" + } + }, { "taskId": "ef087383-ee5e-42c7-9a53-ab56c98420f9", "version": "2.*", @@ -241,15 +265,15 @@ "testConfiguration": "", "tcmTestRun": "$(test.RunId)", "searchFolder": "$(System.DefaultWorkingDirectory)/DotNet-FunctionApp-CI/integration-tests", - "testFiltercriteria": "TestCategory=IntegrationTests", + "testFiltercriteria": "", "runOnlyImpactedTests": "False", "runAllTestsAfterXBuilds": "50", "uiTests": "false", "vstestLocationMethod": "version", "vsTestVersion": "latest", "vstestLocation": "", - "runSettingsFile": "$(System.DefaultWorkingDirectory)/DotNet-FunctionApp-CI/integration-tests/TestRunParameters.runsettings", - "overrideTestrunParameters": "-BaseUrl https://$(ResourceGroupName)-$(SlotName).azurewebsites.net/api/SampleHelloDotNetFunction", + "runSettingsFile": "", + "overrideTestrunParameters": "", "runInParallel": "False", "runTestsInIsolation": "False", "pathtoCustomTestAdapters": "", @@ -558,7 +582,7 @@ { "taskId": "2a1711d0-b4a4-11e6-a3c2-edf36ba3fddc", "version": "1.*", - "name": "CheckUrl Production URL", + "name": "Check Production URL", "refName": "check-url2", "enabled": true, "alwaysRun": false, diff --git a/vsts/DotNet-FunctionApp-CI.json b/vsts/DotNet-FunctionApp-CI.json index e7dbff1..01eac48 100644 --- a/vsts/DotNet-FunctionApp-CI.json +++ b/vsts/DotNet-FunctionApp-CI.json @@ -89,121 +89,31 @@ "name": "CanceledBuilds", "scope": "refs/heads/master", "intValue": 0, - "date": "2017-07-19T00:00:00.000Z" - }, - { - "name": "CanceledBuilds", - "scope": "refs/heads/master", - "intValue": 0, - "date": "2017-07-18T00:00:00.000Z" - }, - { - "name": "CanceledBuilds", - "scope": "refs/heads/master", - "intValue": 0, - "date": "2017-07-17T00:00:00.000Z" - }, - { - "name": "CanceledBuilds", - "scope": "refs/heads/master", - "intValue": 0, - "date": "2017-07-14T00:00:00.000Z" - }, - { - "name": "FailedBuilds", - "scope": "refs/heads/master", - "intValue": 0, - "date": "2017-07-19T00:00:00.000Z" - }, - { - "name": "FailedBuilds", - "scope": "refs/heads/master", - "intValue": 0, - "date": "2017-07-18T00:00:00.000Z" - }, - { - "name": "FailedBuilds", - "scope": "refs/heads/master", - "intValue": 3, - "date": "2017-07-17T00:00:00.000Z" + "date": "2017-08-02T00:00:00.000Z" }, { "name": "FailedBuilds", "scope": "refs/heads/master", - "intValue": 0, - "date": "2017-07-14T00:00:00.000Z" - }, - { - "name": "PartiallySuccessfulBuilds", - "scope": "refs/heads/master", - "intValue": 0, - "date": "2017-07-19T00:00:00.000Z" - }, - { - "name": "PartiallySuccessfulBuilds", - "scope": "refs/heads/master", - "intValue": 0, - "date": "2017-07-18T00:00:00.000Z" - }, - { - "name": "PartiallySuccessfulBuilds", - "scope": "refs/heads/master", - "intValue": 0, - "date": "2017-07-17T00:00:00.000Z" + "intValue": 1, + "date": "2017-08-02T00:00:00.000Z" }, { "name": "PartiallySuccessfulBuilds", "scope": "refs/heads/master", "intValue": 0, - "date": "2017-07-14T00:00:00.000Z" - }, - { - "name": "SuccessfulBuilds", - "scope": "refs/heads/master", - "intValue": 2, - "date": "2017-07-19T00:00:00.000Z" - }, - { - "name": "SuccessfulBuilds", - "scope": "refs/heads/master", - "intValue": 4, - "date": "2017-07-18T00:00:00.000Z" + "date": "2017-08-02T00:00:00.000Z" }, { "name": "SuccessfulBuilds", "scope": "refs/heads/master", - "intValue": 8, - "date": "2017-07-17T00:00:00.000Z" - }, - { - "name": "SuccessfulBuilds", - "scope": "refs/heads/master", - "intValue": 4, - "date": "2017-07-14T00:00:00.000Z" + "intValue": 1, + "date": "2017-08-02T00:00:00.000Z" }, { "name": "TotalBuilds", "scope": "refs/heads/master", "intValue": 2, - "date": "2017-07-19T00:00:00.000Z" - }, - { - "name": "TotalBuilds", - "scope": "refs/heads/master", - "intValue": 4, - "date": "2017-07-18T00:00:00.000Z" - }, - { - "name": "TotalBuilds", - "scope": "refs/heads/master", - "intValue": 11, - "date": "2017-07-17T00:00:00.000Z" - }, - { - "name": "TotalBuilds", - "scope": "refs/heads/master", - "intValue": 4, - "date": "2017-07-14T00:00:00.000Z" + "date": "2017-08-02T00:00:00.000Z" } ], "_links": { @@ -449,10 +359,10 @@ "environment": {}, "enabled": true, "continueOnError": false, - "alwaysRun": true, + "alwaysRun": false, "displayName": "Publish Artifact: function", "timeoutInMinutes": 0, - "condition": "succeededOrFailed()", + "condition": "succeeded()", "refName": "PublishBuildArtifacts_5", "task": { "id": "2ff763a7-ce83-4e1f-bc89-0ae63477cebe", @@ -617,8 +527,8 @@ "uri": "vstfs:///Build/Definition/27", "path": "\\", "type": 2, - "revision": 41, - "createdDate": "2017-07-21T15:08:13.073Z", + "revision": 42, + "createdDate": "2017-08-02T22:29:15.863Z", "project": { "id": "8994a52e-3e36-43b0-aad3-751820cb0816", "name": "DotNetMethodOnFunctionApp",