Exemplo n.º 1
0
        public async Task Compilation_WithMissingBindingArguments_LogsAF004Warning(IDictionary <string, string> environment)
        {
            using (var testEnvironment = new TestScopedEnvironmentVariable(environment))
            {
                // Create the compilation exception we expect to throw during the reload
                string rootFunctionsFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
                Directory.CreateDirectory(rootFunctionsFolder);

                // Create the invoker dependencies and setup the appropriate method to throw the exception
                RunDependencies dependencies = CreateDependencies();

                // Create a dummy file to represent our function
                string filePath = Path.Combine(rootFunctionsFolder, Guid.NewGuid().ToString() + ".csx");
                File.WriteAllText(filePath, Resources.TestFunctionWithMissingBindingArgumentsCode);

                var metadata = new FunctionMetadata
                {
                    ScriptFile        = filePath,
                    FunctionDirectory = Path.GetDirectoryName(filePath),
                    Name       = Guid.NewGuid().ToString(),
                    ScriptType = ScriptType.CSharp
                };

                metadata.Bindings.Add(new BindingMetadata()
                {
                    Name = "myQueueItem", Type = "ManualTrigger"
                });

                var testBinding = new Mock <FunctionBinding>(null, new BindingMetadata()
                {
                    Name = "TestBinding", Type = "blob"
                }, FileAccess.Write);

                var invoker = new DotNetFunctionInvoker(dependencies.Host.Object, metadata, new Collection <FunctionBinding>(),
                                                        new Collection <FunctionBinding> {
                    testBinding.Object
                }, new FunctionEntryPointResolver(), new DotNetCompilationServiceFactory(null));

                try
                {
                    await invoker.GetFunctionTargetAsync();
                }
                catch (CompilationErrorException exc)
                {
                    var builder = new StringBuilder();
                    builder.AppendLine(Resources.TestFunctionWithMissingBindingArgumentsCode);
                    builder.AppendLine();

                    string compilationDetails = exc.Diagnostics.Aggregate(
                        builder,
                        (a, d) => a.AppendLine(d.ToString()),
                        a => a.ToString());

                    throw new Exception(compilationDetails, exc);
                }

                Assert.Contains(dependencies.LoggerProvider.GetAllLogMessages(),
                                t => t.FormattedMessage.Contains($"warning {DotNetConstants.MissingBindingArgumentCompilationCode}") && t.FormattedMessage.Contains("'TestBinding'"));
            }
        }
Exemplo n.º 2
0
        private RunDependencies CreateDependencies(TraceLevel traceLevel = TraceLevel.Info, IScriptHostEnvironment environment = null)
        {
            var dependencies = new RunDependencies();

            var functionTraceWriter     = new TestTraceWriter(System.Diagnostics.TraceLevel.Verbose);
            var traceWriter             = new TestTraceWriter(System.Diagnostics.TraceLevel.Verbose);
            var scriptHostConfiguration = new ScriptHostConfiguration
            {
                HostConfig          = new JobHostConfiguration(),
                TraceWriter         = traceWriter,
                FileLoggingMode     = FileLoggingMode.Always,
                FileWatchingEnabled = true
            };

            scriptHostConfiguration.HostConfig.Tracing.ConsoleLevel = System.Diagnostics.TraceLevel.Verbose;
            var eventManager = new ScriptEventManager();
            var host         = new Mock <ScriptHost>(environment ?? new NullScriptHostEnvironment(), eventManager, scriptHostConfiguration, null, null);

            var traceWriterFactory = new Mock <IFunctionTraceWriterFactory>();

            traceWriterFactory.Setup(f => f.Create(It.IsAny <string>(), null))
            .Returns(functionTraceWriter);

            host.SetupGet(h => h.IsPrimary).Returns(true);
            host.SetupGet(h => h.FunctionTraceWriterFactory).Returns(traceWriterFactory.Object);

            var entrypointResolver = new Mock <IFunctionEntryPointResolver>();

            var compilation = new Mock <IDotNetCompilation>();

            compilation.Setup(c => c.GetDiagnostics())
            .Returns(ImmutableArray <Diagnostic> .Empty);

            var compilationService = new Mock <ICompilationService <IDotNetCompilation> >();

            compilationService.Setup(s => s.SupportedFileTypes)
            .Returns(() => new[] { ".csx" });
            compilationService.Setup(s => s.GetFunctionCompilationAsync(It.IsAny <FunctionMetadata>()))
            .ReturnsAsync(compilation.Object);

            var compilationServiceFactory = new Mock <ICompilationServiceFactory <ICompilationService <IDotNetCompilation>, IFunctionMetadataResolver> >();

            compilationServiceFactory.Setup(f => f.CreateService(ScriptType.CSharp, It.IsAny <IFunctionMetadataResolver>()))
            .Returns(compilationService.Object);

            var metricsLogger = new MetricsLogger();

            scriptHostConfiguration.HostConfig.AddService <IMetricsLogger>(metricsLogger);

            return(new RunDependencies
            {
                Host = host,
                EntrypointResolver = entrypointResolver,
                Compilation = compilation,
                CompilationService = compilationService,
                CompilationServiceFactory = compilationServiceFactory,
                TraceWriterFactory = traceWriterFactory,
                TraceWriter = functionTraceWriter
            });
        }
Exemplo n.º 3
0
        // TODO: DI (FACAVAL) Use test helpers to create host and inject services
        private RunDependencies CreateDependencies(Action <IServiceCollection> configureServices = null)
        {
            var dependencies = new RunDependencies();

            TestLoggerProvider loggerProvider = new TestLoggerProvider();
            ILoggerFactory     loggerFactory  = new LoggerFactory();

            loggerFactory.AddProvider(loggerProvider);

            var eventManager       = new ScriptEventManager();
            var entrypointResolver = new Mock <IFunctionEntryPointResolver>();

            var compilation = new Mock <IDotNetCompilation>();

            compilation.Setup(c => c.GetDiagnostics())
            .Returns(ImmutableArray <Diagnostic> .Empty);

            var compilationService = new Mock <ICompilationService <IDotNetCompilation> >();

            compilationService.Setup(s => s.SupportedFileTypes)
            .Returns(() => new[] { ".csx" });
            compilationService.Setup(s => s.GetFunctionCompilationAsync(It.IsAny <FunctionMetadata>()))
            .ReturnsAsync(compilation.Object);

            var compilationServiceFactory = new Mock <ICompilationServiceFactory <ICompilationService <IDotNetCompilation>, IFunctionMetadataResolver> >();

            compilationServiceFactory.Setup(f => f.CreateService(DotNetScriptTypes.CSharp, It.IsAny <IFunctionMetadataResolver>()))
            .Returns(compilationService.Object);

            var metricsLogger = new MetricsLogger();

            var hostBuilder = new HostBuilder()
                              .ConfigureDefaultTestWebScriptHost(o =>
            {
                o.ScriptPath = TestHelpers.FunctionsTestDirectory;
                o.LogPath    = TestHelpers.GetHostLogFileDirectory().Parent.FullName;
            });

            if (configureServices != null)
            {
                hostBuilder.ConfigureServices(configureServices);
            }

            var host = hostBuilder.Build();

            var scriptHost = host.GetScriptHost();

            return(new RunDependencies
            {
                Host = scriptHost,
                EntrypointResolver = entrypointResolver,
                Compilation = compilation,
                CompilationService = compilationService,
                CompilationServiceFactory = compilationServiceFactory,
                LoggerProvider = loggerProvider,
                LoggerFactory = loggerFactory,
                MetricsLogger = metricsLogger
            });
        }
        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>()))
            .Throws(exception);
            dependencies.Compilation.Setup(c => c.Emit(It.IsAny <CancellationToken>()))
            .Returns(typeof(object).Assembly);

            string rootFunctionsFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());

            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,
                Name       = Guid.NewGuid().ToString(),
                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, new FunctionAssemblyLoader(string.Empty),
                                                    dependencies.CompilationServiceFactory.Object, dependencies.TraceWriterFactory.Object);

            // Update the file to trigger a reload
            File.WriteAllText(filePath, string.Empty);

            await TestHelpers.Await(() =>
            {
                return(dependencies.TraceWriter.Traces.Any(t => t.Message.Contains("Compilation failed.")) &&
                       dependencies.TraceWriter.Traces.Any(t => t.Message.Contains(DotNetConstants.MissingFunctionEntryPointCompilationCode)));
            });

            dependencies.TraceWriter.Traces.Clear();

            CompilationErrorException resultException = await Assert.ThrowsAsync <CompilationErrorException>(() => invoker.GetFunctionTargetAsync());

            await TestHelpers.Await(() =>
            {
                return(dependencies.TraceWriter.Traces.Any(t => t.Message.Contains("Function compilation error")) &&
                       dependencies.TraceWriter.Traces.Any(t => t.Message.Contains(DotNetConstants.MissingFunctionEntryPointCompilationCode)));
            });
        }
Exemplo n.º 5
0
        private RunDependencies CreateDependencies(IScriptHostEnvironment environment = null)
        {
            var dependencies = new RunDependencies();

            var scriptHostConfiguration = new ScriptHostConfiguration
            {
                HostConfig          = new JobHostConfiguration(),
                FileLoggingMode     = FileLoggingMode.Always,
                FileWatchingEnabled = true,
                BindingProviders    = new List <ScriptBindingProvider>()
            };

            TestLoggerProvider loggerProvider = new TestLoggerProvider();
            ILoggerFactory     loggerFactory  = new LoggerFactory();

            loggerFactory.AddProvider(loggerProvider);
            scriptHostConfiguration.HostConfig.LoggerFactory = loggerFactory;

            var eventManager = new ScriptEventManager();

            var host = new Mock <ScriptHost>(environment ?? new NullScriptHostEnvironment(), eventManager, scriptHostConfiguration, null, null, null);

            host.CallBase = true;

            host.SetupGet(h => h.IsPrimary).Returns(true);
            var entrypointResolver = new Mock <IFunctionEntryPointResolver>();

            var compilation = new Mock <IDotNetCompilation>();

            compilation.Setup(c => c.GetDiagnostics())
            .Returns(ImmutableArray <Diagnostic> .Empty);

            var compilationService = new Mock <ICompilationService <IDotNetCompilation> >();

            compilationService.Setup(s => s.SupportedFileTypes)
            .Returns(() => new[] { ".csx" });
            compilationService.Setup(s => s.GetFunctionCompilationAsync(It.IsAny <FunctionMetadata>()))
            .ReturnsAsync(compilation.Object);

            var compilationServiceFactory = new Mock <ICompilationServiceFactory <ICompilationService <IDotNetCompilation>, IFunctionMetadataResolver> >();

            compilationServiceFactory.Setup(f => f.CreateService(ScriptType.CSharp, It.IsAny <IFunctionMetadataResolver>()))
            .Returns(compilationService.Object);

            var metricsLogger = new MetricsLogger();

            scriptHostConfiguration.HostConfig.AddService <IMetricsLogger>(metricsLogger);

            return(new RunDependencies
            {
                Host = host,
                EntrypointResolver = entrypointResolver,
                Compilation = compilation,
                CompilationService = compilationService,
                CompilationServiceFactory = compilationServiceFactory,
                LoggerProvider = loggerProvider
            });
        }
        private RunDependencies CreateDependencies(TraceLevel traceLevel = TraceLevel.Info)
        {
            var dependencies = new RunDependencies();

            var traceWriter             = new TestTraceWriter(System.Diagnostics.TraceLevel.Verbose);
            var scriptHostConfiguration = new ScriptHostConfiguration
            {
                HostConfig          = new JobHostConfiguration(),
                TraceWriter         = traceWriter,
                FileLoggingMode     = FileLoggingMode.Always,
                FileWatchingEnabled = true
            };

            scriptHostConfiguration.HostConfig.Tracing.ConsoleLevel = System.Diagnostics.TraceLevel.Verbose;

            var host = new Mock <ScriptHost>(scriptHostConfiguration);

            host.SetupGet(h => h.IsPrimary).Returns(true);

            var entrypointResolver = new Mock <IFunctionEntryPointResolver>();

            var compilation = new Mock <ICompilation>();

            compilation.Setup(c => c.GetDiagnostics())
            .Returns(ImmutableArray <Diagnostic> .Empty);

            var compilationService = new Mock <ICompilationService>();

            compilationService.Setup(s => s.SupportedFileTypes)
            .Returns(() => new[] { ".csx" });
            compilationService.Setup(s => s.GetFunctionCompilation(It.IsAny <FunctionMetadata>()))
            .Returns(compilation.Object);

            var compilationServiceFactory = new Mock <ICompilationServiceFactory>();

            compilationServiceFactory.Setup(f => f.CreateService(ScriptType.CSharp, It.IsAny <IFunctionMetadataResolver>()))
            .Returns(compilationService.Object);

            var traceWriterFactory = new Mock <ITraceWriterFactory>();

            traceWriterFactory.Setup(f => f.Create())
            .Returns(traceWriter);

            return(new RunDependencies
            {
                Host = host,
                EntrypointResolver = entrypointResolver,
                Compilation = compilation,
                CompilationService = compilationService,
                CompilationServiceFactory = compilationServiceFactory,
                TraceWriterFactory = traceWriterFactory,
                TraceWriter = traceWriter
            });
        }
Exemplo n.º 7
0
        public async Task RestorePackagesAsync_WithUpdatedReferences_TriggersShutdown(bool initialInstall, bool referencesChanged, bool shutdownExpected)
        {
            using (var tempDirectory = new TempDirectory())
            {
                var environmentMock = new Mock <IScriptJobHostEnvironment>();

                // Create the invoker dependencies and setup the appropriate method to throw the exception
                RunDependencies dependencies = CreateDependencies(s =>
                {
                    s.AddSingleton <IScriptJobHostEnvironment>(environmentMock.Object);
                });

                // Create a dummy file to represent our function
                string filePath = Path.Combine(tempDirectory.Path, Guid.NewGuid().ToString() + ".csx");
                File.WriteAllText(filePath, Resources.TestFunctionWithMissingBindingArgumentsCode);

                var metadata = new FunctionMetadata
                {
                    ScriptFile = filePath,
                    Name       = Guid.NewGuid().ToString(),
                    Language   = DotNetScriptTypes.CSharp,
                };

                metadata.Bindings.Add(new BindingMetadata {
                    Type = "TestTrigger", Direction = BindingDirection.In
                });

                var metadataResolver = new Mock <IFunctionMetadataResolver>();
                metadataResolver.Setup(r => r.RestorePackagesAsync())
                .ReturnsAsync(new PackageRestoreResult {
                    IsInitialInstall = initialInstall, ReferencesChanged = referencesChanged
                });

                var testBinding = new Mock <FunctionBinding>(null, new BindingMetadata()
                {
                    Name = "TestBinding", Type = "blob"
                }, FileAccess.Write);

                var invoker = new DotNetFunctionInvoker(dependencies.Host, metadata, new Collection <FunctionBinding>(),
                                                        new Collection <FunctionBinding> {
                    testBinding.Object
                }, new FunctionEntryPointResolver(),
                                                        new DotNetCompilationServiceFactory(null), dependencies.LoggerFactory, dependencies.MetricsLogger, new Collection <IScriptBindingProvider>(), metadataResolver.Object);

                await invoker.RestorePackagesAsync(true);

                // Delay the check as the shutdown call is debounced
                // and won't be made immediately
                await Task.Delay(1000);

                environmentMock.Verify(e => e.Shutdown(), Times.Exactly(shutdownExpected ? 1 : 0));
            }
        }
Exemplo n.º 8
0
        public async Task Compilation_WithMissingBindingArguments_LogsAF004Warning()
        {
            // Create the compilation exception we expect to throw during the reload
            string rootFunctionsFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());

            Directory.CreateDirectory(rootFunctionsFolder);

            // Create the invoker dependencies and setup the appropriate method to throw the exception
            RunDependencies dependencies = CreateDependencies();

            // Create a dummy file to represent our function
            string filePath = Path.Combine(rootFunctionsFolder, Guid.NewGuid().ToString() + ".csx");

            File.WriteAllText(filePath, Resources.TestFunctionWithMissingBindingArgumentsCode);

            var metadata = new FunctionMetadata
            {
                ScriptFile = filePath,
                Name       = Guid.NewGuid().ToString(),
                ScriptType = ScriptType.CSharp
            };

            metadata.Bindings.Add(new BindingMetadata()
            {
                Name = "myQueueItem", Type = "ManualTrigger"
            });

            var testBinding = new Mock <FunctionBinding>(null, new BindingMetadata()
            {
                Name = "TestBinding", Type = "blob"
            }, FileAccess.Write);

            var invoker = new DotNetFunctionInvoker(dependencies.Host.Object, metadata, new Collection <FunctionBinding>(),
                                                    new Collection <FunctionBinding> {
                testBinding.Object
            }, new FunctionEntryPointResolver(), new FunctionAssemblyLoader(string.Empty),
                                                    new DotNetCompilationServiceFactory());

            await invoker.GetFunctionTargetAsync();

            // Verify that our expected messages were logged, including the compilation result
            await TestHelpers.Await(() =>
            {
                Collection <string> logs = TestHelpers.GetFunctionLogsAsync(metadata.Name, false).Result;
                if (logs != null)
                {
                    //Check that our warning diagnostic was logged (e.g. "warning AF004: Missing binding argument named 'TestBinding'.");
                    return(logs.Any(s => s.Contains($"warning {DotNetConstants.MissingBindingArgumentCompilationCode}") && s.Contains("'TestBinding'")));
                }

                return(false);
            }, 10 * 1000);
        }
Exemplo n.º 9
0
        public async Task Compilation_OnSecondaryHost_SuppressesLogs()
        {
            // Create the compilation exception we expect to throw during the reload
            string rootFunctionsFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());

            Directory.CreateDirectory(rootFunctionsFolder);

            // Create the invoker dependencies and setup the appropriate method to throw the exception
            RunDependencies dependencies = CreateDependencies();

            // Set the host to secondary
            dependencies.Host.SetupGet(h => h.IsPrimary).Returns(false);

            // Create a dummy file to represent our function
            string filePath = Path.Combine(rootFunctionsFolder, Guid.NewGuid().ToString() + ".csx");

            File.WriteAllText(filePath, Resources.TestFunctionWithMissingBindingArgumentsCode);

            var metadata = new FunctionMetadata
            {
                ScriptFile        = filePath,
                FunctionDirectory = Path.GetDirectoryName(filePath),
                Name       = Guid.NewGuid().ToString(),
                ScriptType = ScriptType.CSharp
            };

            metadata.Bindings.Add(new BindingMetadata()
            {
                Name = "myQueueItem", Type = "ManualTrigger"
            });

            var testBinding = new Mock <FunctionBinding>(null, new BindingMetadata()
            {
                Name = "TestBinding", Type = "blob"
            }, FileAccess.Write);

            var invoker = new DotNetFunctionInvoker(dependencies.Host.Object, metadata, new Collection <FunctionBinding>(),
                                                    new Collection <FunctionBinding> {
                testBinding.Object
            }, new FunctionEntryPointResolver(), new FunctionAssemblyLoader(string.Empty),
                                                    new DotNetCompilationServiceFactory(NullTraceWriter.Instance, null));

            await invoker.GetFunctionTargetAsync();

            // Verify that logs on the second instance were suppressed
            int count = dependencies.TraceWriter.Traces.Count();

            Assert.Equal(0, count);
        }
Exemplo n.º 10
0
        public async Task Compilation_WithMissingBindingArguments_LogsAF004Warning()
        {
            // Create the compilation exception we expect to throw during the reload
            string rootFunctionsFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());

            Directory.CreateDirectory(rootFunctionsFolder);

            // Create the invoker dependencies and setup the appropriate method to throw the exception
            RunDependencies dependencies = CreateDependencies();

            // Create a dummy file to represent our function
            string filePath = Path.Combine(rootFunctionsFolder, Guid.NewGuid().ToString() + ".csx");

            File.WriteAllText(filePath, Resources.TestFunctionWithMissingBindingArgumentsCode);

            var metadata = new FunctionMetadata
            {
                ScriptFile        = filePath,
                FunctionDirectory = Path.GetDirectoryName(filePath),
                Name       = Guid.NewGuid().ToString(),
                ScriptType = ScriptType.CSharp
            };

            metadata.Bindings.Add(new BindingMetadata()
            {
                Name = "myQueueItem", Type = "ManualTrigger"
            });

            var testBinding = new Mock <FunctionBinding>(null, new BindingMetadata()
            {
                Name = "TestBinding", Type = "blob"
            }, FileAccess.Write);

            var invoker = new DotNetFunctionInvoker(dependencies.Host.Object, metadata, new Collection <FunctionBinding>(),
                                                    new Collection <FunctionBinding> {
                testBinding.Object
            }, new FunctionEntryPointResolver(), new FunctionAssemblyLoader(string.Empty),
                                                    new DotNetCompilationServiceFactory(NullTraceWriter.Instance, null));

            await invoker.GetFunctionTargetAsync();

            Assert.Contains(dependencies.TraceWriter.Traces,
                            t => t.Message.Contains($"warning {DotNetConstants.MissingBindingArgumentCompilationCode}") && t.Message.Contains("'TestBinding'"));
        }
Exemplo n.º 11
0
        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))));
        }
Exemplo n.º 12
0
        public async Task CompilerError_IsRetried_UpToLimit()
        {
            // Set the host to primary
            var stateProviderMock = new Mock <IPrimaryHostStateProvider>();

            stateProviderMock.Setup(m => m.IsPrimary).Returns(false);

            // Create the invoker dependencies and setup the appropriate method to throw the exception
            RunDependencies dependencies = CreateDependencies(configureServices: s => { s.AddSingleton(stateProviderMock.Object); });

            var metadata = new FunctionMetadata
            {
                ScriptFile        = "run.csx",
                FunctionDirectory = "c:\\somedir",
                Name     = Guid.NewGuid().ToString(),
                Language = DotNetScriptTypes.CSharp
            };

            metadata.Bindings.Add(new BindingMetadata()
            {
                Name = "myQueueItem", Type = "ManualTrigger"
            });

            var testBinding = new Mock <FunctionBinding>(null, new BindingMetadata()
            {
                Name = "TestBinding", Type = "blob"
            }, FileAccess.Write);

            var dotNetCompilation        = new Mock <IDotNetCompilation>();
            var dotnetCompilationService = new Mock <ICompilationService <IDotNetCompilation> >();

            dotnetCompilationService
            .SetupSequence(s => s.GetFunctionCompilationAsync(It.IsAny <FunctionMetadata>()))
            .ThrowsAsync(new CompilationServiceException("1"))
            .ThrowsAsync(new CompilationServiceException("2"))
            .ThrowsAsync(new CompilationServiceException("3"))
            .ThrowsAsync(new CompilationServiceException("4"));     // This should not be reached

            var compilationFactory = new Mock <ICompilationServiceFactory <ICompilationService <IDotNetCompilation>, IFunctionMetadataResolver> >();

            compilationFactory
            .Setup(f => f.CreateService(DotNetScriptTypes.CSharp, It.IsAny <IFunctionMetadataResolver>()))
            .Returns(dotnetCompilationService.Object);

            var invoker = new DotNetFunctionInvoker(dependencies.Host, metadata, new Collection <FunctionBinding>(),
                                                    new Collection <FunctionBinding> {
                testBinding.Object
            }, new FunctionEntryPointResolver(),
                                                    compilationFactory.Object, dependencies.LoggerFactory, dependencies.MetricsLogger, new Collection <IScriptBindingProvider>(), new Mock <IFunctionMetadataResolver>().Object);

            var arguments = new object[]
            {
                new ExecutionContext()
                {
                    FunctionDirectory = "c:\\test",
                    FunctionName      = "test",
                    InvocationId      = Guid.NewGuid()
                }
            };

            for (int i = 1; i <= 10; i++)
            {
                var expectedAttempt = Math.Min(i, 3);
                CompilationServiceException exception = await Assert.ThrowsAsync <CompilationServiceException>(() => invoker.Invoke(arguments));

                Assert.Equal(expectedAttempt.ToString(), exception.Message);
            }

            var compilerErrorTraces = dependencies.LoggerProvider.GetAllLogMessages()
                                      .Where(t => string.Equals(t.FormattedMessage, "Function loader reset. Failed compilation result will not be cached."));

            // 3 attempts total, make sure we've logged the 2 retries.
            Assert.Equal(2, compilerErrorTraces.Count());
        }
Exemplo n.º 13
0
        public async Task Compilation_OnSecondaryHost_SuppressesLogs(IDictionary <string, string> environment)
        {
            using (new TestScopedEnvironmentVariable(environment))
            {
                // Create the compilation exception we expect to throw during the reload
                string rootFunctionsFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
                Directory.CreateDirectory(rootFunctionsFolder);

                // Set the host to secondary
                var stateProviderMock = new Mock <IPrimaryHostStateProvider>();
                stateProviderMock.Setup(m => m.IsPrimary).Returns(false);

                // Create the invoker dependencies and setup the appropriate method to throw the exception
                RunDependencies dependencies = CreateDependencies(configureServices: s => { s.AddSingleton(stateProviderMock.Object); });

                // Create a dummy file to represent our function
                string filePath = Path.Combine(rootFunctionsFolder, Guid.NewGuid().ToString() + ".csx");
                File.WriteAllText(filePath, Resources.TestFunctionWithMissingBindingArgumentsCode);

                var metadata = new FunctionMetadata
                {
                    ScriptFile        = filePath,
                    FunctionDirectory = Path.GetDirectoryName(filePath),
                    Name     = Guid.NewGuid().ToString(),
                    Language = DotNetScriptTypes.CSharp
                };

                metadata.Bindings.Add(new BindingMetadata()
                {
                    Name = "myQueueItem", Type = "ManualTrigger"
                });

                var testBinding = new Mock <FunctionBinding>(null, new BindingMetadata()
                {
                    Name = "TestBinding", Type = "blob"
                }, FileAccess.Write);

                var invoker = new DotNetFunctionInvoker(dependencies.Host, metadata, new Collection <FunctionBinding>(),
                                                        new Collection <FunctionBinding> {
                    testBinding.Object
                }, new FunctionEntryPointResolver(), new DotNetCompilationServiceFactory(null),
                                                        dependencies.LoggerFactory, dependencies.MetricsLogger, new Collection <IScriptBindingProvider>());
                try
                {
                    await invoker.GetFunctionTargetAsync();
                }
                catch (CompilationErrorException exc)
                {
                    var builder = new StringBuilder();
                    builder.AppendLine(Resources.TestFunctionWithMissingBindingArgumentsCode);
                    builder.AppendLine();

                    string compilationDetails = exc.Diagnostics.Aggregate(
                        builder,
                        (a, d) => a.AppendLine(d.ToString()),
                        a => a.ToString());

                    throw new Exception(compilationDetails, exc);
                }

                // Verify that we send the log, but that it has MS_PrimaryHost set so the logger can filter appropriately.
                var logMessage = dependencies.LoggerProvider.GetAllLogMessages().Single();
                Assert.True((bool)logMessage.State.Single(k => k.Key == ScriptConstants.LogPropertyPrimaryHostKey).Value);
            }
        }
        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)));
            });
        }
        private RunDependencies CreateDependencies(TraceLevel traceLevel = TraceLevel.Info)
        {
            var dependencies = new RunDependencies();

            var functionTraceWriter = new TestTraceWriter(System.Diagnostics.TraceLevel.Verbose);
            var traceWriter = new TestTraceWriter(System.Diagnostics.TraceLevel.Verbose);
            var scriptHostConfiguration = new ScriptHostConfiguration
            {
                HostConfig = new JobHostConfiguration(),
                TraceWriter = traceWriter,
                FileLoggingMode = FileLoggingMode.Always,
                FileWatchingEnabled = true
            };

            scriptHostConfiguration.HostConfig.Tracing.ConsoleLevel = System.Diagnostics.TraceLevel.Verbose;

            var host = new Mock<ScriptHost>(scriptHostConfiguration);
            host.SetupGet(h => h.IsPrimary).Returns(true);

            var entrypointResolver = new Mock<IFunctionEntryPointResolver>();

            var compilation = new Mock<ICompilation>();
            compilation.Setup(c => c.GetDiagnostics())
                .Returns(ImmutableArray<Diagnostic>.Empty);

            var compilationService = new Mock<ICompilationService>();
            compilationService.Setup(s => s.SupportedFileTypes)
                .Returns(() => new[] { ".csx" });
            compilationService.Setup(s => s.GetFunctionCompilation(It.IsAny<FunctionMetadata>()))
                .Returns(compilation.Object);

            var compilationServiceFactory = new Mock<ICompilationServiceFactory>();
            compilationServiceFactory.Setup(f => f.CreateService(ScriptType.CSharp, It.IsAny<IFunctionMetadataResolver>()))
                .Returns(compilationService.Object);

            var traceWriterFactory = new Mock<ITraceWriterFactory>();
            traceWriterFactory.Setup(f => f.Create())
                .Returns(functionTraceWriter);

            var metricsLogger = new MetricsLogger();
            scriptHostConfiguration.HostConfig.AddService<IMetricsLogger>(metricsLogger);

            return new RunDependencies
            {
                Host = host,
                EntrypointResolver = entrypointResolver,
                Compilation = compilation,
                CompilationService = compilationService,
                CompilationServiceFactory = compilationServiceFactory,
                TraceWriterFactory = traceWriterFactory,
                TraceWriter = functionTraceWriter
            };
        }