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)));
            });
        }
Exemple #2
0
 private string Format(object?result)
 {
     return(result switch
     {
         string value => value,
         CompilationErrorException value => string.Join("\n", value.Diagnostics.Select(x => x.ToString())),
         Exception value => $"{value.GetType().Name}: {value.InnerException?.Message ?? value.Message}",
         _ => new InspectionFormatter(result).ToString()
     });
Exemple #3
0
        public async Task <CompilationErrorException> EvaluateCore(string code)
        {
            CompilationErrorException error = null;

            try {
                this.State = await this.State.ContinueWithAsync(code);
            } catch (CompilationErrorException cex) {
                error = cex;
            } catch (Exception ex) {
                this.OnError?.Invoke(ex.Message, ex);
            }
            return(error);
        }
Exemple #4
0
 private static ScriptResult FromCompilationException(CompilationErrorException ex)
 {
     return(new ScriptResult
     {
         CompilerErrors = ex.Diagnostics.Select(
             e =>
             new CompilerError
         {
             Text = e.ToString(),
             SourceSpan = new TextSpan(e.Location.SourceSpan.Start, e.Location.SourceSpan.Length)
         }).ToArray()
     });
 }
Exemple #5
0
        public void GetFunctionEntryPoint_WithNoPublicMethods_ThrowsCompilationException()
        {
            var resolver = new FunctionEntryPointResolver();

            CompilationErrorException exc = Assert.Throws(typeof(CompilationErrorException), () => resolver.GetFunctionEntryPoint(new[]
            {
                new TestMethodReference("Run", false),
                new TestMethodReference("PrivateMethodName", false)
            })) as CompilationErrorException;

            var diagnostic = exc.Diagnostics.First();

            Assert.Equal(DotNetConstants.MissingFunctionEntryPointCompilationCode, diagnostic.Id);
        }
Exemple #6
0
        // Evaluate without telling the delegates
        public async Task <CompilationErrorException> EvaluateSilently(string code)
        {
            CompilationErrorException error = null;

            try
            {
                ScriptState = await ScriptState.ContinueWithAsync(code);
            }
            catch (CompilationErrorException e)
            {
                error = e;
            }

            return(error);
        }
Exemple #7
0
        public void GetFunctionEntryPoint_WithMultiplePublicRunMethods_ThrowsCompilationException()
        {
            var resolver = new FunctionEntryPointResolver();

            CompilationErrorException exc = Assert.Throws(typeof(CompilationErrorException), () => resolver.GetFunctionEntryPoint(new[]
            {
                new TestMethodReference("Run", true),
                new TestMethodReference("Run", true),
                new TestMethodReference("Run", true)
            })) as CompilationErrorException;

            var diagnostic = exc.Diagnostics.First();

            Assert.Equal(DotNetConstants.AmbiguousFunctionEntryPointsCompilationCode, diagnostic.Id);
        }
Exemple #8
0
        public void GetFunctionEntryPoint_WithMissingNamedMethod_ThrowsCompilationException()
        {
            var resolver = new FunctionEntryPointResolver("NamedMethod");

            CompilationErrorException exc = Assert.Throws(typeof(CompilationErrorException), () => resolver.GetFunctionEntryPoint(new[]
            {
                new TestMethodReference("Method1", true),
                new TestMethodReference("Method2", true),
                new TestMethodReference("NamedMethod", false)
            })) as CompilationErrorException;

            var diagnostic = exc.Diagnostics.First();

            Assert.Equal(DotNetConstants.InvalidEntryPointNameCompilationCode, diagnostic.Id);
        }
        private Exception CompileException(CompilationErrorException ex, string code)
        {
            Exception result = ex;
            var       match  = System.Text.RegularExpressions.Regex.Match(ex.Message, @"\(\s*(?<line>\d+)\s*,\s*(?<column>\d+)\s*\)\s*:\s*(?<message>.*)");

            if (match.Success)
            {
                var lineNumber = int.Parse(match.Groups["line"].Value) - 1;
                var column     = int.Parse(match.Groups["column"].Value) - 1;
                var line       = code.Split('\n')[lineNumber];
                var minCol     = Math.Max(0, column - 20);
                var maxCol     = Math.Min(line.Length, column + 20);
                var msg        = line.Substring(minCol, column - minCol) + "^" + line.Substring(column, maxCol - column);
                result = new ArgumentException(match.Groups["message"].Value + ": " + msg);
            }
            return(result);
        }
Exemple #10
0
        public static EvalResult CreateErrorResult(string code, string consoleOut, TimeSpan compileTime, ImmutableArray <Diagnostic> compileErrors)
        {
            var ex          = new CompilationErrorException(string.Join("\n", compileErrors.Select(a => a.GetMessage())), compileErrors);
            var errorResult = new EvalResult
            {
                Code           = code,
                CompileTime    = compileTime,
                ConsoleOut     = consoleOut,
                Exception      = ex.Message,
                ExceptionType  = ex.GetType().Name,
                ExecutionTime  = TimeSpan.FromMilliseconds(0),
                ReturnValue    = null,
                ReturnTypeName = null
            };

            return(errorResult);
        }
Exemple #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))));
        }
Exemple #12
0
        public ErrorLine(Exception ex, bool isWarning = false)
        {
            InitializeComponent();

            this.FindControl <MyExpandable>("expander").ExpandedChanged += ExpandedChanged;

            InputTextBox headerBox;

            this.FindControl <MyExpandable>("expander").Header = headerBox = new InputTextBox()
            {
                FontSize = 12, Background = null, BorderThickness = new Thickness(0, 0, 0, 0), FontFamily = ScriptConsoleControl.RobotoMono, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Center, Margin = new Thickness(-5, 0, 0, 0), MyReadOnly = true, Foreground = new SolidColorBrush(Color.FromRgb(255, 0, 0))
            };

            if (isWarning)
            {
                this.FindControl <Canvas>("errorIcon").IsVisible   = false;
                this.FindControl <Canvas>("warningIcon").IsVisible = true;
                this.FindControl <Canvas>("background").Background = new SolidColorBrush(Color.FromRgb(255, 251, 230));
                this.FindControl <Canvas>("border1").Background    = new SolidColorBrush(Color.FromRgb(255, 245, 194));
                this.FindControl <Canvas>("border2").Background    = new SolidColorBrush(Color.FromRgb(255, 245, 194));
                headerBox.Foreground = new SolidColorBrush(Color.FromRgb(149, 127, 81));
            }

            headerBox.Text = ex.Message;

            if (ex is CompilationErrorException)
            {
                CompilationErrorException err = ((CompilationErrorException)ex);
                if (err.Diagnostics.Length == 1)
                {
                    headerBox.Text = err.GetType().Name + ": " + err.Diagnostics[0].GetMessage();

                    FileLinePositionSpan lineSpan = err.Diagnostics[0].Location.GetMappedLineSpan();

                    this.FindControl <InputTextBox>("locationBox").Text = "    " + err.Diagnostics[0].Id + " at " + lineSpan.Path + (!string.IsNullOrEmpty(lineSpan.Path) ? ":" : "") + (lineSpan.StartLinePosition.Line + 1).ToString() + ":" + (lineSpan.StartLinePosition.Character + 1).ToString();
                    this.FindControl <InputTextBox>("lineBox").Text     = "    " + err.Diagnostics[0].Location.SourceTree.GetText().Lines[lineSpan.StartLinePosition.Line].ToString().Replace("\t", "    ");
                    this.FindControl <InputTextBox>("positionBox").Text = "    " + new string(' ', err.Diagnostics[0].Location.SourceTree.GetText().Lines[lineSpan.StartLinePosition.Line].ToString().CountCharsUpToPosition(lineSpan.StartLinePosition.Character)) + "^";
                }
                else
                {
                    this.FindControl <Grid>("detailsGrid").Children.Clear();
                    this.FindControl <Grid>("detailsGrid").RowDefinitions.Clear();

                    headerBox.Text = err.GetType().Name + "[" + err.Diagnostics.Length.ToString() + "]";

                    for (int i = 0; i < err.Diagnostics.Length; i++)
                    {
                        this.FindControl <Grid>("detailsGrid").RowDefinitions.Add(new RowDefinition()
                        {
                            Height = GridLength.Auto
                        });
                        this.FindControl <Grid>("detailsGrid").RowDefinitions.Add(new RowDefinition()
                        {
                            Height = GridLength.Auto
                        });
                        this.FindControl <Grid>("detailsGrid").RowDefinitions.Add(new RowDefinition()
                        {
                            Height = GridLength.Auto
                        });
                        this.FindControl <Grid>("detailsGrid").RowDefinitions.Add(new RowDefinition()
                        {
                            Height = GridLength.Auto
                        });

                        InputTextBox message = new InputTextBox()
                        {
                            Background = null, BorderThickness = new Thickness(0), FontFamily = ScriptConsoleControl.RobotoMono, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Top, Padding = new Thickness(0, 1.2, 0, 0), MyReadOnly = true, Foreground = new SolidColorBrush(Color.FromRgb(255, 0, 0))
                        };
                        Grid.SetRow(message, i * 4);
                        Grid.SetColumn(message, 1);

                        message.Text = "• " + err.Diagnostics[i].GetMessage();

                        InputTextBox location = new InputTextBox()
                        {
                            Background = null, BorderThickness = new Thickness(0), FontFamily = ScriptConsoleControl.RobotoMono, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Top, Padding = new Thickness(0, 1.2, 0, 0), MyReadOnly = true
                        };
                        Grid.SetRow(location, i * 4 + 1);
                        Grid.SetColumn(location, 1);

                        FileLinePositionSpan lineSpan = err.Diagnostics[i].Location.GetMappedLineSpan();
                        location.Text = "    " + err.Diagnostics[i].Id + " at " + lineSpan.Path + (!string.IsNullOrEmpty(lineSpan.Path) ? ":" : "") + (lineSpan.StartLinePosition.Line + 1).ToString() + ":" + (lineSpan.StartLinePosition.Character + 1).ToString();

                        InputTextBox line = new InputTextBox()
                        {
                            Background = null, BorderThickness = new Thickness(0), FontFamily = ScriptConsoleControl.RobotoMono, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Top, Padding = new Thickness(0, 1.2, 0, 0), Margin = new Thickness(8, 4, 0, 0), MyReadOnly = true, Foreground = new SolidColorBrush(Color.FromRgb(0x3F, 0x48, 0xCC))
                        };
                        Grid.SetRow(line, i * 4 + 2);
                        Grid.SetColumn(line, 1);
                        line.Text = "    " + err.Diagnostics[i].Location.SourceTree.GetText().Lines[lineSpan.StartLinePosition.Line].ToString().Replace("\t", "    ");

                        InputTextBox position = new InputTextBox()
                        {
                            Background = null, BorderThickness = new Thickness(0), FontFamily = ScriptConsoleControl.RobotoMono, VerticalAlignment = Avalonia.Layout.VerticalAlignment.Top, Padding = new Thickness(0, 1.2, 0, 0), Margin = new Thickness(8, -5, 0, 0), MyReadOnly = true, Foreground = new SolidColorBrush(Color.FromRgb(255, 0, 0))
                        };
                        Grid.SetRow(position, i * 4 + 3);
                        Grid.SetColumn(position, 1);
                        position.Text = "    " + new string(' ', err.Diagnostics[i].Location.SourceTree.GetText().Lines[lineSpan.StartLinePosition.Line].ToString().CountCharsUpToPosition(lineSpan.StartLinePosition.Character)) + "^";

                        this.FindControl <Grid>("detailsGrid").Children.Add(message);
                        this.FindControl <Grid>("detailsGrid").Children.Add(location);
                        this.FindControl <Grid>("detailsGrid").Children.Add(line);
                        this.FindControl <Grid>("detailsGrid").Children.Add(position);
                    }
                }
            }
            else
            {
                headerBox.Text = ex.GetType().Name + ": " + ex.Message;

                this.FindControl <Grid>("detailsGrid").Children.Clear();
                this.FindControl <Grid>("detailsGrid").RowDefinitions.Clear();
                this.FindControl <Grid>("detailsGrid").ColumnDefinitions.Clear();
                this.FindControl <Grid>("detailsGrid").Margin = new Thickness(20, 0, 0, 0);
                this.FindControl <Grid>("detailsGrid").Children.Add(CSharpOutputLine.contentElement(ex));
            }
        }
Exemple #13
0
        private void OnEvaluationError(string output, CompilationErrorException error)
        {
            Content.Add(new OutputItem(output));

            ScrollToEnd();
        }
Exemple #14
0
 private void AddCompileErrorMessage(CompilationErrorException exp)
 {
     AddMessage(ScriptMessageType.Error, exp.Message);
 }
        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)));
            });
        }
 public static CompilerError[] ArrayFromException(CompilationErrorException exception)
 {
     return(ArrayFromDiagnostics(exception.Diagnostics));
 }