public async Task SetupAsync() { ScriptPath = Path.Combine(GetCSharpSamplePath(), BenchmarkTrigger, "run.csx"); ScriptSource = File.ReadAllText(ScriptPath); FunctionMetadata = new FunctionMetadata() { FunctionDirectory = Path.GetDirectoryName(ScriptPath), ScriptFile = ScriptPath, Name = BenchmarkTrigger, Language = DotNetScriptTypes.CSharp }; Resolver = new ScriptFunctionMetadataResolver(ScriptPath, Array.Empty <IScriptBindingProvider>(), NullLogger.Instance); CompilationService = new CSharpCompilationService(Resolver, OptimizationLevel.Release); ScriptCompilation = await CompilationService.GetFunctionCompilationAsync(FunctionMetadata); ScriptAssembly = await ScriptCompilation.EmitAsync(default);
public async Task GetFunctionTargetAsync_CompilationError_ReportsResults() { // Create the compilation exception we expect to throw var descriptor = new DiagnosticDescriptor(DotNetConstants.MissingFunctionEntryPointCompilationCode, "Test compilation exception", "Test compilation error", "AzureFunctions", DiagnosticSeverity.Error, true); var exception = new CompilationErrorException("Test compilation exception", ImmutableArray.Create(Diagnostic.Create(descriptor, Location.None))); // Create the invoker dependencies and setup the appropriate method to throw the exception RunDependencies dependencies = CreateDependencies(); dependencies.Compilation.Setup(c => c.GetEntryPointSignature(It.IsAny <IFunctionEntryPointResolver>(), It.IsAny <Assembly>())) .Throws(exception); dependencies.Compilation.Setup(c => c.EmitAsync(It.IsAny <CancellationToken>())) .ReturnsAsync(DotNetCompilationResult.FromPath(typeof(DotNetFunctionInvokerTests).Assembly.Location)); string functionName = Guid.NewGuid().ToString(); string rootFunctionsFolder = Path.Combine(Path.GetTempPath(), functionName); Directory.CreateDirectory(rootFunctionsFolder); // Create a dummy file to represent our function string filePath = Path.Combine(rootFunctionsFolder, Guid.NewGuid().ToString() + ".csx"); File.WriteAllText(filePath, string.Empty); var metadata = new FunctionMetadata { ScriptFile = filePath, FunctionDirectory = Path.GetDirectoryName(filePath), Name = functionName, Language = DotNetScriptTypes.CSharp }; metadata.Bindings.Add(new BindingMetadata() { Name = "Test", Type = "ManualTrigger" }); var invoker = new DotNetFunctionInvoker(dependencies.Host, metadata, new Collection <FunctionBinding>(), new Collection <FunctionBinding>(), dependencies.EntrypointResolver.Object, dependencies.CompilationServiceFactory.Object, dependencies.LoggerFactory, dependencies.MetricsLogger, new Collection <IScriptBindingProvider>()); // Send file change notification to trigger a reload var fileEventArgs = new FileSystemEventArgs(WatcherChangeTypes.Changed, Path.GetTempPath(), Path.Combine(Path.GetFileName(rootFunctionsFolder), Path.GetFileName(filePath))); dependencies.Host.EventManager.Publish(new FileEvent(EventSources.ScriptFiles, fileEventArgs)); LogMessage[] logMessages = null; var loggerProvider = dependencies.LoggerProvider; await TestHelpers.Await(() => { logMessages = loggerProvider.GetAllLogMessages().ToArray(); return(logMessages.Any(t => t.FormattedMessage.Contains("Compilation failed.")) && logMessages.Any(t => t.FormattedMessage.Contains(DotNetConstants.MissingFunctionEntryPointCompilationCode))); }); // verify expected logs when the function target is retrieved // NOT on the invocation path dependencies.LoggerProvider.ClearAllLogMessages(); await Assert.ThrowsAsync <CompilationErrorException>(async() => { await invoker.GetFunctionTargetAsync(); }); Assert.Equal(3, logMessages.Length); Assert.Equal($"Script for function '{functionName}' changed. Reloading.", logMessages[0].FormattedMessage); Assert.Equal(LogLevel.Information, logMessages[0].Level); Assert.Equal("error AF001: Test compilation error", logMessages[1].FormattedMessage); Assert.Equal(LogLevel.Error, logMessages[1].Level); Assert.True(logMessages[1].State.Any(q => q.Key == ScriptConstants.LogPropertyIsUserLogKey)); Assert.Equal("Compilation failed.", logMessages[2].FormattedMessage); Assert.Equal(LogLevel.Information, logMessages[2].Level); Assert.True(logMessages.All(p => p.State.Any(q => q.Key == ScriptConstants.LogPropertyPrimaryHostKey))); await TestHelpers.Await(() => { logMessages = loggerProvider.GetAllLogMessages().ToArray(); return(logMessages.Any(t => t.FormattedMessage.Contains("Function compilation error")) && logMessages.Any(t => t.FormattedMessage.Contains(DotNetConstants.MissingFunctionEntryPointCompilationCode))); }); // now test the invoke path and verify that the compilation error // details are written loggerProvider.ClearAllLogMessages(); await Assert.ThrowsAsync <CompilationErrorException>(async() => { await invoker.GetFunctionTargetAsync(isInvocation: true); }); logMessages = loggerProvider.GetAllLogMessages().ToArray(); Assert.Equal(2, logMessages.Length); Assert.Equal("Function compilation error", logMessages[0].FormattedMessage); Assert.Equal(LogLevel.Error, logMessages[0].Level); Assert.Same("Test compilation exception", logMessages[0].Exception.Message); Assert.Equal("error AF001: Test compilation error", logMessages[1].FormattedMessage); Assert.Equal(LogLevel.Error, logMessages[1].Level); Assert.True(logMessages[1].State.Any(q => q.Key == ScriptConstants.LogPropertyIsUserLogKey)); Assert.True(logMessages.All(p => !(p.State != null && p.State.Any(q => q.Key == ScriptConstants.LogPropertyPrimaryHostKey)))); }
public async Task ReloadScript_WithInvalidCompilationAndMissingMethod_ReportsResults() { // Create the compilation exception we expect to throw during the reload var descriptor = new DiagnosticDescriptor(DotNetConstants.MissingFunctionEntryPointCompilationCode, "Test compilation exception", "Test compilation error", "AzureFunctions", DiagnosticSeverity.Error, true); var exception = new CompilationErrorException("Test compilation exception", ImmutableArray.Create(Diagnostic.Create(descriptor, Location.None))); // Create the invoker dependencies and setup the appropriate method to throw the exception RunDependencies dependencies = CreateDependencies(); dependencies.Compilation.Setup(c => c.GetEntryPointSignature(It.IsAny <IFunctionEntryPointResolver>(), It.IsAny <Assembly>())) .Throws(exception); dependencies.Compilation.Setup(c => c.EmitAsync(It.IsAny <CancellationToken>())) .ReturnsAsync(DotNetCompilationResult.FromPath(typeof(DotNetFunctionInvokerTests).Assembly.Location)); string functionName = Guid.NewGuid().ToString(); string rootFunctionsFolder = Path.Combine(Path.GetTempPath(), functionName); Directory.CreateDirectory(rootFunctionsFolder); // Create a dummy file to represent our function string filePath = Path.Combine(rootFunctionsFolder, Guid.NewGuid().ToString() + ".csx"); File.WriteAllText(filePath, string.Empty); var metadata = new FunctionMetadata { ScriptFile = filePath, FunctionDirectory = Path.GetDirectoryName(filePath), Name = functionName, ScriptType = ScriptType.CSharp }; metadata.Bindings.Add(new BindingMetadata() { Name = "Test", Type = "ManualTrigger" }); var invoker = new DotNetFunctionInvoker(dependencies.Host.Object, metadata, new Collection <Script.Binding.FunctionBinding>(), new Collection <FunctionBinding>(), dependencies.EntrypointResolver.Object, dependencies.CompilationServiceFactory.Object); // Send file change notification to trigger a reload var fileEventArgs = new FileSystemEventArgs(WatcherChangeTypes.Changed, Path.GetTempPath(), Path.Combine(Path.GetFileName(rootFunctionsFolder), Path.GetFileName(filePath))); dependencies.Host.Object.EventManager.Publish(new FileEvent(EventSources.ScriptFiles, fileEventArgs)); await TestHelpers.Await(() => { IEnumerable <LogMessage> logMessages = dependencies.LoggerProvider.GetAllLogMessages(); return(logMessages.Any(t => t.FormattedMessage.Contains("Compilation failed.")) && logMessages.Any(t => t.FormattedMessage.Contains(DotNetConstants.MissingFunctionEntryPointCompilationCode))); }); dependencies.LoggerProvider.ClearAllLogMessages(); CompilationErrorException resultException = await Assert.ThrowsAsync <CompilationErrorException>(() => invoker.GetFunctionTargetAsync()); await TestHelpers.Await(() => { IEnumerable <LogMessage> logMessages = dependencies.LoggerProvider.GetAllLogMessages(); return(logMessages.Any(t => t.FormattedMessage.Contains("Function compilation error")) && logMessages.Any(t => t.FormattedMessage.Contains(DotNetConstants.MissingFunctionEntryPointCompilationCode))); }); }