public void Disables_Ssl_If_SkipSslValidation_Enabled(int skipSslValidation, string syncTriggersUri) { var vars = new Dictionary <string, string> { { EnvironmentSettingNames.SkipSslValidation, skipSslValidation.ToString() }, { EnvironmentSettingNames.AzureWebsiteHostName, "sitename" }, }; using (var env = new TestScopedEnvironmentVariable(vars)) { var httpRequest = WebFunctionsManager.BuildSyncTriggersRequest(); Assert.Equal(syncTriggersUri, httpRequest.RequestUri.AbsoluteUri); Assert.Equal(HttpMethod.Post, httpRequest.Method); } }
public async Task SetOfflineResponseAsync_ReturnsCorrectResponse() { string offlineFilePath = null; try { // create a test offline file var rootPath = Path.GetTempPath(); offlineFilePath = TestHelpers.CreateOfflineFile(); var sendFileFeatureMock = new Mock <IHttpSendFileFeature>(); sendFileFeatureMock.Setup(s => s.SendFileAsync(offlineFilePath, 0, null, CancellationToken.None)).Returns(Task.FromResult <int>(0)); // simulate an App Service request var vars = new Dictionary <string, string> { { EnvironmentSettingNames.AzureWebsiteInstanceId, "123" } }; using (var env = new TestScopedEnvironmentVariable(vars)) { // without header (thus an internal request) var context = new DefaultHttpContext(); context.Features.Set(sendFileFeatureMock.Object); Assert.True(context.Request.IsAppServiceInternalRequest()); await context.SetOfflineResponseAsync(rootPath); Assert.Equal(StatusCodes.Status503ServiceUnavailable, context.Response.StatusCode); Assert.Equal(0, context.Response.Body.Length); sendFileFeatureMock.Verify(p => p.SendFileAsync(offlineFilePath, 0, null, CancellationToken.None), Times.Never); // with header (thus an external request) context = new DefaultHttpContext(); context.Features.Set(sendFileFeatureMock.Object); context.Request.Headers.Add(ScriptConstants.AntaresLogIdHeaderName, new StringValues("456")); Assert.False(context.Request.IsAppServiceInternalRequest()); await context.SetOfflineResponseAsync(rootPath); Assert.Equal(StatusCodes.Status503ServiceUnavailable, context.Response.StatusCode); Assert.Equal("text/html", context.Response.Headers["Content-Type"]); sendFileFeatureMock.Verify(p => p.SendFileAsync(offlineFilePath, 0, null, CancellationToken.None), Times.Once); } } finally { TestHelpers.DeleteTestFile(offlineFilePath); } }
public async Task TrySyncTriggers_BackgroundSync_DoesNotPostsEmptyContent() { _emptyContent = true; using (var env = new TestScopedEnvironmentVariable(_vars)) { var syncResult = await _functionsSyncManager.TrySyncTriggersAsync(isBackgroundSync : true); Assert.Equal(0, _mockHttpHandler.RequestCount); Assert.Equal(0, _contentBuilder.Length); Assert.True(syncResult.Success); Assert.Null(syncResult.Error); var logs = _loggerProvider.GetAllLogMessages().Where(m => m.Category.Equals(SyncManagerLogCategory)).Select(p => p.FormattedMessage).ToArray(); Assert.Equal("No functions found. Skipping Sync operation.", logs.Single()); } }
public async Task TrySyncTriggers_PostsExpectedContent() { using (var env = new TestScopedEnvironmentVariable(_vars)) { // Act var result = await _functionsSyncManager.TrySyncTriggersAsync(); var triggers = JArray.Parse(_contentBuilder.ToString()); // Assert Assert.True(result.Success, "SyncTriggers should return success true"); Assert.True(string.IsNullOrEmpty(result.Error), "Error should be null or empty"); // verify triggers Assert.Equal(_expectedSyncTriggersPayload, triggers.ToString(Formatting.None)); } }
public void IssuedToken_WithInvalidValues_FailsValidation() { using (var variables = new TestScopedEnvironmentVariable(Constants.AzureWebsiteLocalEncryptionKey, TestKeyValue)) { var token = JwtGenerator.GenerateToken("testissuer", "testaudience"); var testParameters = new TokenValidationParameters() { IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(TestKeyValue)), ValidateIssuer = true, ValidateAudience = true }; bool result = JwtGenerator.IsTokenValid(token, testParameters); Assert.False(result); } }
public void GeneratedToken_ContainsExpectedClaims() { using (var variables = new TestScopedEnvironmentVariable(Constants.AzureWebsiteLocalEncryptionKey, TestKeyValue)) { var issuer = "testissuer"; var audience = "testaudience"; var expiration = new DateTime(2017, 1, 1, 0, 0, 0, DateTimeKind.Utc); var notBefore = expiration.AddSeconds(-10); var token = JwtGenerator.GenerateToken(issuer, audience, notBefore, expiration); var jwt = new JwtSecurityToken(token); Assert.Equal(issuer, jwt.Issuer); Assert.Equal(audience, jwt.Audiences.First()); Assert.Equal(expiration, jwt.ValidTo); Assert.Equal(notBefore, jwt.ValidFrom); } }
public async Task TrySyncTriggers_MaxSyncTriggersPayloadSize_Succeeds() { // create a dummy file that pushes us over size string maxString = new string('x', ScriptConstants.MaxTriggersStringLength + 1); _function1 = $"{{ bindings: [], test: '{maxString}'}}"; using (var env = new TestScopedEnvironmentVariable(_vars)) { Assert.True(_functionsSyncManager.ArmCacheEnabled); var result = await _functionsSyncManager.TrySyncTriggersAsync(); Assert.True(result.Success); string syncString = _contentBuilder.ToString(); Assert.True(syncString.Length < ScriptConstants.MaxTriggersStringLength); var syncContent = JToken.Parse(syncString); Assert.Equal(JTokenType.Array, syncContent.Type); } }
public async Task VerifyDurableTaskHubNameIsAdded() { var vars = new Dictionary <string, string> { { EnvironmentSettingNames.WebSiteAuthEncryptionKey, TestHelpers.GenerateKeyHexString() }, { EnvironmentSettingNames.AzureWebsiteHostName, "appName.azurewebsites.net" } }; using (var env = new TestScopedEnvironmentVariable(vars)) { // Setup const string expectedSyncTriggersPayload = "[{\"authLevel\":\"anonymous\",\"type\":\"httpTrigger\",\"direction\":\"in\",\"name\":\"req\",\"functionName\":\"function1\"}," + "{\"name\":\"myQueueItem\",\"type\":\"orchestrationTrigger\",\"direction\":\"in\",\"queueName\":\"myqueue-items\",\"connection\":\"DurableStorage\",\"functionName\":\"function2\",\"taskHubName\":\"TestHubValue\"}," + "{\"name\":\"myQueueItem\",\"type\":\"activityTrigger\",\"direction\":\"in\",\"queueName\":\"myqueue-items\",\"connection\":\"DurableStorage\",\"functionName\":\"function3\",\"taskHubName\":\"TestHubValue\"}]"; var options = CreateApplicationHostOptions(); var fileSystem = CreateFileSystem(options.ScriptPath); var loggerFactory = MockNullLogerFactory.CreateLoggerFactory(); var contentBuilder = new StringBuilder(); var httpClient = CreateHttpClient(contentBuilder); var factory = new TestOptionsFactory <ScriptApplicationHostOptions>(options); var tokenSource = new TestChangeTokenSource(); var changeTokens = new[] { tokenSource }; var optionsMonitor = new OptionsMonitor <ScriptApplicationHostOptions>(factory, changeTokens, factory); var webManager = new WebFunctionsManager(optionsMonitor, new OptionsWrapper <LanguageWorkerOptions>(CreateLanguageWorkerConfigSettings()), loggerFactory, httpClient); FileUtility.Instance = fileSystem; // Act (var success, var error) = await webManager.TrySyncTriggers(); var content = contentBuilder.ToString(); // Assert Assert.True(success, "SyncTriggers should return success true"); Assert.True(string.IsNullOrEmpty(error), "Error should be null or empty"); Assert.Equal(expectedSyncTriggersPayload, content); } }
public async Task Legacy_RequestTypes_Succeed() { var vars = new Dictionary <string, string> { { LanguageWorkerConstants.FunctionWorkerRuntimeSettingName, LanguageWorkerConstants.DotNetLanguageWorkerName } }; using (var env = new TestScopedEnvironmentVariable(vars)) { string functionKey = await _fixture.Host.GetFunctionSecretAsync("HttpTrigger-Compat"); string id = Guid.NewGuid().ToString(); string uri = $"api/HttpTrigger-Compat?code={functionKey}"; HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, uri); HttpResponseMessage response = await _fixture.Host.HttpClient.SendAsync(request); string responseContent = await response.Content.ReadAsAsync <string>(); Assert.Equal(HttpStatusCode.OK, response.StatusCode); Assert.Equal("Hello from HttpResponseMessage", responseContent); } }
public async Task VerifyDurableTaskHubNameIsAdded() { var vars = new Dictionary <string, string> { { EnvironmentSettingNames.WebSiteAuthEncryptionKey, TestHelpers.GenerateKeyHexString() }, { EnvironmentSettingNames.AzureWebsiteHostName, "appName.azurewebsites.net" } }; using (var env = new TestScopedEnvironmentVariable(vars)) { // Setup const string expectedSyncTriggersPayload = "[{\"authLevel\":\"anonymous\",\"type\":\"httpTrigger\",\"direction\":\"in\",\"name\":\"req\",\"functionName\":\"function1\"}," + "{\"name\":\"myQueueItem\",\"type\":\"orchestrationTrigger\",\"direction\":\"in\",\"queueName\":\"myqueue-items\",\"connection\":\"DurableStorage\",\"functionName\":\"function2\",\"taskHubName\":\"TestHubValue\"}," + "{\"name\":\"myQueueItem\",\"type\":\"activityTrigger\",\"direction\":\"in\",\"queueName\":\"myqueue-items\",\"connection\":\"DurableStorage\",\"functionName\":\"function3\",\"taskHubName\":\"TestHubValue\"}]"; var settings = CreateWebSettings(); var fileSystem = CreateFileSystem(settings.ScriptPath); var loggerFactory = MockNullLogerFactory.CreateLoggerFactory(); var contentBuilder = new StringBuilder(); var httpClient = CreateHttpClient(contentBuilder); var proxyMetadataManager = new Mock <IProxyMetadataManager>(MockBehavior.Strict); var proxyMetadata = new ProxyMetadataInfo(new FunctionMetadata[0].ToImmutableArray(), null, null); proxyMetadataManager.SetupGet(p => p.ProxyMetadata).Returns(proxyMetadata); var webManager = new WebFunctionsManager(new OptionsWrapper <ScriptApplicationHostOptions>(settings), new OptionsWrapper <LanguageWorkerOptions>(CreateLanguageWorkerConfigSettings()), loggerFactory, httpClient, proxyMetadataManager.Object); FileUtility.Instance = fileSystem; // Act (var success, var error) = await webManager.TrySyncTriggers(); var content = contentBuilder.ToString(); // Assert Assert.True(success, "SyncTriggers should return success true"); Assert.True(string.IsNullOrEmpty(error), "Error should be null or empty"); Assert.Equal(expectedSyncTriggersPayload, content); } }
public async Task HttpTrigger_Identities_AnonymousAccessSucceeds() { var vars = new Dictionary <string, string> { { LanguageWorkerConstants.FunctionWorkerRuntimeSettingName, LanguageWorkerConstants.DotNetLanguageWorkerName }, { "WEBSITE_AUTH_ENABLED", "TRUE" } }; using (var env = new TestScopedEnvironmentVariable(vars)) { string uri = $"api/httptrigger-identities"; HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, uri); MockEasyAuth(request, "facebook", "Connor McMahon", "10241897674253170"); HttpResponseMessage response = await this._fixture.Host.HttpClient.SendAsync(request); Assert.Equal(HttpStatusCode.OK, response.StatusCode); string responseContent = await response.Content.ReadAsStringAsync(); string[] identityStrings = StripBookendQuotations(responseContent).Split(';'); Assert.Equal("Identity: (facebook, Connor McMahon, 10241897674253170)", identityStrings[0]); } }
public async Task HttpTrigger_CustomRoute_ReturnsExpectedResponse() { var vars = new Dictionary <string, string> { { LanguageWorkerConstants.FunctionWorkerRuntimeSettingName, LanguageWorkerConstants.DotNetLanguageWorkerName } }; using (var env = new TestScopedEnvironmentVariable(vars)) { string functionName = "HttpTrigger-CustomRoute"; string functionKey = await _fixture.Host.GetFunctionSecretAsync(functionName); string uri = $"api/csharp/products/electronics/123/extra?code={functionKey}"; HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, uri); HttpResponseMessage response = await _fixture.Host.HttpClient.SendAsync(request); Assert.Equal(HttpStatusCode.OK, response.StatusCode); string json = await response.Content.ReadAsStringAsync(); var product = JObject.Parse(json); Assert.Equal("electronics", (string)product["category"]); Assert.Equal(123, (int?)product["id"]); var logs = _fixture.Host.GetScriptHostLogMessages("Function.HttpTrigger-CustomRoute.User"); Assert.Contains(logs, l => string.Equals(l.FormattedMessage, "Parameters: category=electronics id=123 extra=extra")); Assert.True(logs.Any(p => p.FormattedMessage.Contains("ProductInfo: Category=electronics Id=123"))); // test optional id parameter // test optional extra parameter (not in POCO binding contract) _fixture.Host.ClearLogMessages(); uri = $"api/csharp/products/electronics?code={functionKey}"; request = new HttpRequestMessage(HttpMethod.Get, uri); response = await _fixture.Host.HttpClient.SendAsync(request); Assert.Equal(HttpStatusCode.OK, response.StatusCode); json = await response.Content.ReadAsStringAsync(); product = JObject.Parse(json); Assert.Equal("electronics", (string)product["category"]); Assert.Null((int?)product["id"]); logs = _fixture.Host.GetScriptHostLogMessages("Function.HttpTrigger-CustomRoute.User"); Assert.Contains(logs, l => string.Equals(l.FormattedMessage, "Parameters: category=electronics id= extra=")); // test optional category parameter _fixture.Host.ClearLogMessages(); uri = $"api/csharp/products?code={functionKey}"; request = new HttpRequestMessage(HttpMethod.Get, uri); response = await _fixture.Host.HttpClient.SendAsync(request); Assert.Equal(HttpStatusCode.OK, response.StatusCode); json = await response.Content.ReadAsStringAsync(); product = JObject.Parse(json); Assert.Null((string)product["category"]); Assert.Null((int?)product["id"]); logs = _fixture.Host.GetScriptHostLogMessages("Function.HttpTrigger-CustomRoute.User"); Assert.Contains(logs, l => string.Equals(l.FormattedMessage, "Parameters: category= id= extra=")); // test a constraint violation (invalid id) uri = $"api/csharp/products/electronics/1x3?code={functionKey}"; request = new HttpRequestMessage(HttpMethod.Get, uri); response = await _fixture.Host.HttpClient.SendAsync(request); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); // test a constraint violation (invalid category) uri = $"api/csharp/products/999/123?code={functionKey}"; request = new HttpRequestMessage(HttpMethod.Get, uri); response = await _fixture.Host.HttpClient.SendAsync(request); Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); } }
public async Task TrySyncTriggers_PostsExpectedContent(bool cacheEnabled) { _mockEnvironment.Setup(p => p.GetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteArmCacheEnabled)).Returns(cacheEnabled ? "1" : "0"); using (var env = new TestScopedEnvironmentVariable(_vars)) { Assert.Equal(_functionsSyncManager.ArmCacheEnabled, cacheEnabled); // Act var syncResult = await _functionsSyncManager.TrySyncTriggersAsync(); // Assert Assert.True(syncResult.Success, "SyncTriggers should return success true"); Assert.True(string.IsNullOrEmpty(syncResult.Error), "Error should be null or empty"); // verify expected headers Assert.Equal(ScriptConstants.FunctionsUserAgent, _mockHttpHandler.LastRequest.Headers.UserAgent.ToString()); Assert.True(_mockHttpHandler.LastRequest.Headers.Contains(ScriptConstants.AntaresLogIdHeaderName)); if (cacheEnabled) { // verify triggers var result = JObject.Parse(_contentBuilder.ToString()); var triggers = result["triggers"]; Assert.Equal(_expectedSyncTriggersPayload, triggers.ToString(Formatting.None)); // verify functions var functions = (JArray)result["functions"]; Assert.Equal(3, functions.Count); // verify secrets var secrets = (JObject)result["secrets"]; var hostSecrets = (JObject)secrets["host"]; Assert.Equal("aaa", (string)hostSecrets["master"]); var hostFunctionSecrets = (JObject)hostSecrets["function"]; Assert.Equal("aaa", (string)hostFunctionSecrets["TestHostFunctionKey1"]); Assert.Equal("bbb", (string)hostFunctionSecrets["TestHostFunctionKey2"]); var systemSecrets = (JObject)hostSecrets["system"]; Assert.Equal("aaa", (string)systemSecrets["TestSystemKey1"]); Assert.Equal("bbb", (string)systemSecrets["TestSystemKey2"]); var functionSecrets = (JArray)secrets["function"]; Assert.Equal(1, functionSecrets.Count); var function1Secrets = (JObject)functionSecrets[0]; Assert.Equal("function1", function1Secrets["name"]); Assert.Equal("aaa", (string)function1Secrets["secrets"]["TestFunctionKey1"]); Assert.Equal("bbb", (string)function1Secrets["secrets"]["TestFunctionKey2"]); var logs = _loggerProvider.GetAllLogMessages(); var log = logs[0]; int startIdx = log.FormattedMessage.IndexOf("Content=") + 8; int endIdx = log.FormattedMessage.LastIndexOf(')'); var triggersLog = log.FormattedMessage.Substring(startIdx, endIdx - startIdx).Trim(); var logObject = JObject.Parse(triggersLog); Assert.Equal(_expectedSyncTriggersPayload, logObject["triggers"].ToString(Formatting.None)); Assert.False(triggersLog.Contains("secrets")); } else { var triggers = JArray.Parse(_contentBuilder.ToString()); Assert.Equal(_expectedSyncTriggersPayload, triggers.ToString(Formatting.None)); var logs = _loggerProvider.GetAllLogMessages(); var log = logs[0]; int startIdx = log.FormattedMessage.IndexOf("Content=") + 8; int endIdx = log.FormattedMessage.LastIndexOf(')'); var triggersLog = log.FormattedMessage.Substring(startIdx, endIdx - startIdx).Trim(); Assert.Equal(_expectedSyncTriggersPayload, triggersLog); } } }