Пример #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'"));
            }
        }
        public void ValidateFunctionBindingArguments_ReturnBinding_Succeeds()
        {
            Collection <FunctionParameter> parameters = new Collection <FunctionParameter>()
            {
                new FunctionParameter("input", "String", false, RefKind.None)
            };
            FunctionSignature signature = new FunctionSignature("Test", "Test", ImmutableArray.CreateRange <FunctionParameter>(parameters), "Test", false);

            Collection <FunctionBinding> inputBindings = new Collection <FunctionBinding>()
            {
                TestHelpers.CreateTestBinding(new JObject
                {
                    { "type", "blobTrigger" },
                    { "name", "input" },
                    { "direction", "in" },
                    { "path", "test" }
                })
            };
            Collection <FunctionBinding> outputBindings = new Collection <FunctionBinding>()
            {
                TestHelpers.CreateTestBinding(new JObject
                {
                    { "type", "blob" },
                    { "name", ScriptConstants.SystemReturnParameterBindingName },
                    { "direction", "out" },
                    { "path", "test/test" }
                })
            };
            var diagnostics = DotNetFunctionInvoker.ValidateFunctionBindingArguments(signature, "input", inputBindings, outputBindings);

            Assert.Equal(0, diagnostics.Count());
        }
        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)));
            });
        }
        internal static async Task <object> Unwrap(object result)
        {
            // unwrap the task
            if (result is Task)
            {
                result = await((Task)result).ContinueWith(t => DotNetFunctionInvoker.GetTaskResult(t), TaskContinuationOptions.ExecuteSynchronously);
            }

            return(result);
        }
Пример #5
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));
            }
        }
Пример #6
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);
        }
Пример #7
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);
        }
Пример #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,
                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'"));
        }
Пример #9
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))));
        }
Пример #10
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());
        }
Пример #11
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)));
            });
        }