public async Task CompilerError_IsRetried_UpToLimit()
        {
            // Create the invoker dependencies and setup the appropriate method to throw the exception
            RunDependencies dependencies = CreateDependencies();

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

            var metadata = new FunctionMetadata
            {
                ScriptFile        = "run.csx",
                FunctionDirectory = "c:\\somedir",
                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 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(ScriptType.CSharp, It.IsAny <IFunctionMetadataResolver>())).Returns(dotnetCompilationService.Object);

            var invoker = new DotNetFunctionInvoker(dependencies.Host.Object, metadata, new Collection <FunctionBinding>(),
                                                    new Collection <FunctionBinding> {
                testBinding.Object
            }, new FunctionEntryPointResolver(), new FunctionAssemblyLoader(string.Empty),
                                                    compilationFactory.Object, 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());
        }
        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 FunctionAssemblyLoader(string.Empty),
                                                        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 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);

                // 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(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);
                }

                // 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);
            }
        }
Beispiel #4
0
 private FuncPtg(int funcIndex, FunctionMetadata fm) :
     base(funcIndex, fm.ReturnClassCode, fm.ParameterClassCodes, fm.MinParams) // minParams same as max since these are not var-arg funcs {
 {
 }
Beispiel #5
0
 public MockInvoker(ScriptHost host, IMetricsLogger metrics, FunctionMetadata metadata) : base(host, metadata)
 {
     _fastLogger = new FunctionInstanceLogger(
         (name) => this.Host.GetFunctionOrNull(name),
         metrics);
 }
        /// <summary>
        /// Execution a function fired by a trigger or an activity function scheduled by an orchestration.
        /// </summary>
        internal Hashtable InvokeFunction(
            AzFunctionInfo functionInfo,
            Hashtable triggerMetadata,
            IList <ParameterBinding> inputData)
        {
            string scriptPath = functionInfo.ScriptPath;
            string entryPoint = functionInfo.EntryPoint;

            try
            {
                if (string.IsNullOrEmpty(entryPoint))
                {
                    _pwsh.AddCommand(functionInfo.DeployedPSFuncName ?? scriptPath);
                }
                else
                {
                    // If an entry point is defined, we import the script module.
                    _pwsh.AddCommand(Utils.ImportModuleCmdletInfo)
                    .AddParameter("Name", scriptPath)
                    .InvokeAndClearCommands();

                    _pwsh.AddCommand(entryPoint);
                }

                // Set arguments for each input binding parameter
                foreach (ParameterBinding binding in inputData)
                {
                    string bindingName = binding.Name;
                    if (functionInfo.FuncParameters.TryGetValue(bindingName, out PSScriptParamInfo paramInfo))
                    {
                        var bindingInfo = functionInfo.InputBindings[bindingName];
                        var valueToUse  = Utils.TransformInBindingValueAsNeeded(paramInfo, bindingInfo, binding.Data.ToObject());
                        _pwsh.AddParameter(bindingName, valueToUse);
                    }
                }

                // Gives access to additional Trigger Metadata if the user specifies TriggerMetadata
                if (functionInfo.HasTriggerMetadataParam)
                {
                    _pwsh.AddParameter(AzFunctionInfo.TriggerMetadata, triggerMetadata);
                }

                Collection <object> pipelineItems = _pwsh.AddCommand("Microsoft.Azure.Functions.PowerShellWorker\\Trace-PipelineObject")
                                                    .InvokeAndClearCommands <object>();

                Hashtable outputBindings = FunctionMetadata.GetOutputBindingHashtable(_pwsh.Runspace.InstanceId);
                Hashtable result         = new Hashtable(outputBindings, StringComparer.OrdinalIgnoreCase);
                outputBindings.Clear();

                /*
                 * TODO: See GitHub issue #82. We are not settled on how to handle the Azure Functions concept of the $returns Output Binding
                 * if (pipelineItems != null && pipelineItems.Count > 0)
                 * {
                 *  // If we would like to support Option 1 from #82, use the following 3 lines of code:
                 *  object[] items = new object[pipelineItems.Count];
                 *  pipelineItems.CopyTo(items, 0);
                 *  result.Add(AzFunctionInfo.DollarReturn, items);
                 *
                 *  // If we would like to support Option 2 from #82, use this line:
                 *  result.Add(AzFunctionInfo.DollarReturn, pipelineItems[pipelineItems.Count - 1]);
                 * }
                 */

                return(result);
            }
            finally
            {
                ResetRunspace();
            }
        }
 public bool TryGetFunctionMetadata(string functionName, out FunctionMetadata functionMetadata, bool forceRefresh)
 {
     functionMetadata = _functions.FirstOrDefault(p => Utility.FunctionNamesMatch(p.Name, functionName));
     return(functionMetadata != null);
 }
        public async Task Generate_EndToEnd()
        {
            // construct our TimerTrigger attribute ([TimerTrigger("00:00:02", RunOnStartup = true)])
            Collection <ParameterDescriptor> parameters = new Collection <ParameterDescriptor>();
            ParameterDescriptor    parameter            = new ParameterDescriptor("timerInfo", typeof(TimerInfo));
            ConstructorInfo        ctorInfo             = typeof(TimerTriggerAttribute).GetConstructor(new Type[] { typeof(string) });
            PropertyInfo           runOnStartupProperty = typeof(TimerTriggerAttribute).GetProperty("RunOnStartup");
            CustomAttributeBuilder attributeBuilder     = new CustomAttributeBuilder(
                ctorInfo,
                new object[] { "00:00:02" },
                new PropertyInfo[] { runOnStartupProperty },
                new object[] { true });

            parameter.CustomAttributes.Add(attributeBuilder);
            parameters.Add(parameter);

            // create the FunctionDefinition
            FunctionMetadata   metadata = new FunctionMetadata();
            TestInvoker        invoker  = new TestInvoker();
            FunctionDescriptor function = new FunctionDescriptor("TimerFunction", invoker, metadata, parameters, null, null, null);
            Collection <FunctionDescriptor> functions = new Collection <FunctionDescriptor>();

            functions.Add(function);

            // Get the Type Attributes (in this case, a TimeoutAttribute)
            ScriptHostConfiguration scriptConfig = new ScriptHostConfiguration();

            scriptConfig.FunctionTimeout = TimeSpan.FromMinutes(5);
            Collection <CustomAttributeBuilder> typeAttributes = ScriptHost.CreateTypeAttributes(scriptConfig);

            // generate the Type
            Type functionType = FunctionGenerator.Generate("TestScriptHost", "TestFunctions", typeAttributes, functions);

            // verify the generated function
            MethodInfo       method           = functionType.GetMethod("TimerFunction");
            TimeoutAttribute timeoutAttribute = (TimeoutAttribute)functionType.GetCustomAttributes().Single();

            Assert.Equal(TimeSpan.FromMinutes(5), timeoutAttribute.Timeout);
            Assert.True(timeoutAttribute.ThrowOnTimeout);
            Assert.True(timeoutAttribute.TimeoutWhileDebugging);
            ParameterInfo         triggerParameter = method.GetParameters()[0];
            TimerTriggerAttribute triggerAttribute = triggerParameter.GetCustomAttribute <TimerTriggerAttribute>();

            Assert.NotNull(triggerAttribute);

            // start the JobHost which will start running the timer function
            JobHostConfiguration config = new JobHostConfiguration()
            {
                TypeLocator = new TypeLocator(functionType)
            };

            config.UseTimers();
            JobHost host = new JobHost(config);

            await host.StartAsync();

            await Task.Delay(3000);

            await host.StopAsync();

            // verify our custom invoker was called
            Assert.True(invoker.InvokeCount >= 2);
        }
        /// <summary>
        /// Maps FunctionMetadata to FunctionMetadataResponse.
        /// </summary>
        /// <param name="functionMetadata">FunctionMetadata to be mapped.</param>
        /// <param name="request">Current HttpRequest</param>
        /// <param name="config">ScriptHostConfig</param>
        /// <returns>Promise of a FunctionMetadataResponse</returns>
        public static async Task <FunctionMetadataResponse> ToFunctionMetadataResponse(this FunctionMetadata functionMetadata, HttpRequest request, ScriptHostConfiguration config, IWebJobsRouter router = null)
        {
            var functionPath             = Path.Combine(config.RootScriptPath, functionMetadata.Name);
            var functionMetadataFilePath = Path.Combine(functionPath, ScriptConstants.FunctionMetadataFileName);
            var baseUrl = request != null
                ? $"{request.Scheme}://{request.Host}"
                : "https://localhost/";

            var response = new FunctionMetadataResponse
            {
                Name = functionMetadata.Name,

                // Q: can functionMetadata.ScriptFile be null or empty?
                ScriptHref         = VirtualFileSystem.FilePathToVfsUri(Path.Combine(config.RootScriptPath, functionMetadata.ScriptFile), baseUrl, config),
                ConfigHref         = VirtualFileSystem.FilePathToVfsUri(functionMetadataFilePath, baseUrl, config),
                ScriptRootPathHref = VirtualFileSystem.FilePathToVfsUri(functionPath, baseUrl, config, isDirectory: true),
                TestDataHref       = VirtualFileSystem.FilePathToVfsUri(functionMetadata.GetTestDataFilePath(config), baseUrl, config),
                Href     = GetFunctionHref(functionMetadata.Name, baseUrl),
                TestData = await GetTestData(functionMetadata.GetTestDataFilePath(config), config),
                Config   = await GetFunctionConfig(functionMetadataFilePath),

                // Properties below this comment are not present in the kudu version.
                IsDirect          = functionMetadata.IsDirect,
                IsDisabled        = functionMetadata.IsDisabled,
                IsProxy           = functionMetadata.IsProxy,
                InvokeUrlTemplate = GetFunctionInvokeUrlTemplate(baseUrl, functionMetadata.Name, router)
            };

            return(response);
        }
        public static ScriptInvocationContext GetScriptInvocationContext(string functionName, Guid invocationId, ILogger testLogger, DataType dataType = DataType.String)
        {
            ScriptInvocationContext scriptInvocationContext = new ScriptInvocationContext()
            {
                ExecutionContext = new ExecutionContext()
                {
                    InvocationId = invocationId,
                    FunctionName = functionName,
                },
                BindingData           = GetScriptInvocationBindingData(),
                Inputs                = GetScriptInvocationInputs(),
                ResultSource          = new TaskCompletionSource <ScriptInvocationResult>(),
                Logger                = testLogger,
                AsyncExecutionContext = System.Threading.ExecutionContext.Capture()
            };
            var functionMetadata = new FunctionMetadata
            {
                Name = functionName
            };

            var httpTriggerBinding = new BindingMetadata
            {
                Name      = "req",
                Type      = "httpTrigger",
                Direction = BindingDirection.In,
                Raw       = new JObject()
            };

            var queueInputBinding = new BindingMetadata
            {
                Name      = "queueInput",
                Type      = "queue",
                Direction = BindingDirection.In,
                DataType  = dataType
            };

            var httpOutputBinding = new BindingMetadata
            {
                Name      = "res",
                Type      = "http",
                Direction = BindingDirection.Out,
                Raw       = new JObject(),
                DataType  = dataType
            };

            var queueOutputBinding1 = new BindingMetadata
            {
                Name      = "output1",
                Type      = "queue",
                Direction = BindingDirection.Out,
                DataType  = dataType
            };

            var queueOutputBinding2 = new BindingMetadata
            {
                Name      = "output2",
                Type      = "queue",
                Direction = BindingDirection.Out,
                DataType  = dataType
            };

            var queueOutputRetrun = new BindingMetadata
            {
                Name      = "$return",
                Type      = "queue",
                Direction = BindingDirection.Out,
                DataType  = dataType
            };

            functionMetadata.Bindings.Add(httpTriggerBinding);
            functionMetadata.Bindings.Add(queueOutputBinding1);
            functionMetadata.Bindings.Add(queueOutputBinding2);
            functionMetadata.Bindings.Add(queueOutputRetrun);
            scriptInvocationContext.FunctionMetadata = functionMetadata;
            return(scriptInvocationContext);
        }
 protected override IFunctionInvoker CreateFunctionInvoker(string scriptFilePath, BindingMetadata triggerMetadata, FunctionMetadata functionMetadata, Collection <FunctionBinding> inputBindings, Collection <FunctionBinding> outputBindings)
 {
     throw new NotImplementedException();
 }
 public MockInvoker(ScriptHost host, FunctionMetadata metadata) : base(host, metadata)
 {
 }
        public async Task ToRpcInvocationRequest_Http_OmitsDuplicateBodyOfBindingData()
        {
            var logger = new TestLogger("test");

            var httpContext = new DefaultHttpContext();

            httpContext.Request.Host   = new HostString("local");
            httpContext.Request.Path   = "/test";
            httpContext.Request.Method = "Post";

            var inputs = new List <(string name, DataType type, object val)>
            {
                ("req", DataType.String, httpContext.Request)
            };

            var bindingData = new Dictionary <string, object>
            {
                { "req", httpContext.Request },
                { "$request", httpContext.Request },
                { "headers", httpContext.Request.Headers.ToDictionary(p => p.Key, p => p.Value) },
                { "query", httpContext.Request.QueryString.ToString() },
                { "sys", new SystemBindingData() }
            };

            var invocationContext = new ScriptInvocationContext()
            {
                ExecutionContext = new ExecutionContext()
                {
                    InvocationId = Guid.NewGuid(),
                    FunctionName = "Test",
                },
                BindingData           = bindingData,
                Inputs                = inputs,
                ResultSource          = new TaskCompletionSource <ScriptInvocationResult>(),
                Logger                = logger,
                AsyncExecutionContext = System.Threading.ExecutionContext.Capture()
            };

            var functionMetadata = new FunctionMetadata
            {
                Name = "Test"
            };

            var httpTriggerBinding = new BindingMetadata
            {
                Name      = "req",
                Type      = "httpTrigger",
                Direction = BindingDirection.In,
                Raw       = new JObject()
            };

            var httpOutputBinding = new BindingMetadata
            {
                Name      = "res",
                Type      = "http",
                Direction = BindingDirection.Out,
                Raw       = new JObject(),
                DataType  = DataType.String
            };

            functionMetadata.Bindings.Add(httpTriggerBinding);
            functionMetadata.Bindings.Add(httpOutputBinding);
            invocationContext.FunctionMetadata = functionMetadata;

            Capabilities capabilities = new Capabilities(logger);
            MapField <string, string> addedCapabilities = new MapField <string, string>
            {
                { RpcWorkerConstants.RpcHttpTriggerMetadataRemoved, "1" },
                { RpcWorkerConstants.RpcHttpBodyOnly, "1" }
            };

            capabilities.UpdateCapabilities(addedCapabilities);

            var result = await invocationContext.ToRpcInvocationRequest(logger, capabilities);

            Assert.Equal(1, result.InputData.Count);
            Assert.Equal(3, result.TriggerMetadata.Count);
            Assert.True(result.TriggerMetadata.ContainsKey("headers"));
            Assert.True(result.TriggerMetadata.ContainsKey("query"));
            Assert.True(result.TriggerMetadata.ContainsKey("sys"));
        }
 public MockInvoker(ScriptHost host, FunctionMetadata metadata, ITraceWriterFactory traceWriterFactory = null) : base(host, metadata, traceWriterFactory)
 {
 }
        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.EmitAsync(It.IsAny <CancellationToken>()))
            .ReturnsAsync(typeof(object).Assembly);

            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, new FunctionAssemblyLoader(string.Empty),
                                                    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 string GetTestDataFilePath(this FunctionMetadata functionMetadata, ScriptHostConfiguration config) =>
 GetTestDataFilePath(functionMetadata.Name, config);
Beispiel #17
0
        internal static bool TryParseFunctionMetadata(string functionName, JObject functionConfig, Dictionary <string, HttpTriggerBindingMetadata> mappedHttpFunctions, TraceWriter traceWriter, Lazy <string[]> functionFilesProvider, out FunctionMetadata functionMetadata, out string error)
        {
            error            = null;
            functionMetadata = ParseFunctionMetadata(functionName, functionConfig);

            if (functionMetadata.IsExcluded)
            {
                traceWriter.Info(string.Format("Function '{0}' is marked as excluded", functionName));
                functionMetadata = null;
                return(true);
            }

            if (functionMetadata.IsDisabled)
            {
                traceWriter.Info(string.Format("Function '{0}' is disabled", functionName));
            }

            // determine the primary script
            string[] functionFiles = functionFilesProvider.Value;
            if (functionFiles.Length == 0)
            {
                error = "No function script files present.";
                return(false);
            }
            string scriptFile = DeterminePrimaryScriptFile(functionConfig, functionFiles);

            if (string.IsNullOrEmpty(scriptFile))
            {
                error =
                    "Unable to determine the primary function script. Try renaming your entry point script to 'run' (or 'index' in the case of Node), " +
                    "or alternatively you can specify the name of the entry point script explicitly by adding a 'scriptFile' property to your function metadata.";
                return(false);
            }
            functionMetadata.ScriptFile = scriptFile;

            // determine the script type based on the primary script file extension
            functionMetadata.ScriptType = ParseScriptType(functionMetadata.ScriptFile);

            functionMetadata.EntryPoint = (string)functionConfig["entryPoint"];

            var httpTriggerBindingMetadata = functionMetadata.InputBindings.OfType <HttpTriggerBindingMetadata>().SingleOrDefault();

            if (httpTriggerBindingMetadata != null)
            {
                if (string.IsNullOrWhiteSpace(httpTriggerBindingMetadata.Route))
                {
                    // if no explicit route is provided, default to the function name
                    httpTriggerBindingMetadata.Route = functionName;
                }

                // disallow custom routes in our own reserved route space
                string httpRoute = httpTriggerBindingMetadata.Route.Trim('/').ToLowerInvariant();
                if (httpRoute.StartsWith("admin"))
                {
                    error = "The specified route conflicts with one or more built in routes.";
                    return(false);
                }

                // prevent duplicate/conflicting routes
                foreach (var pair in mappedHttpFunctions)
                {
                    if (HttpRoutesConflict(httpTriggerBindingMetadata, pair.Value))
                    {
                        error = $"The route specified conflicts with the route defined by function '{pair.Key}'.";
                        return(false);
                    }
                }

                mappedHttpFunctions.Add(functionName, httpTriggerBindingMetadata);
            }

            return(true);
        }
        private Collection <FunctionDescriptor> ReadFunctions(ScriptHostConfiguration config, IEnumerable <FunctionDescriptorProvider> descriptorProviders)
        {
            string scriptRootPath             = config.RootScriptPath;
            List <FunctionMetadata> metadatas = new List <FunctionMetadata>();

            foreach (var scriptDir in Directory.EnumerateDirectories(scriptRootPath))
            {
                string functionName = null;

                try
                {
                    // read the function config
                    string functionConfigPath = Path.Combine(scriptDir, ScriptConstants.FunctionMetadataFileName);
                    if (!File.Exists(functionConfigPath))
                    {
                        // not a function directory
                        continue;
                    }

                    functionName = Path.GetFileNameWithoutExtension(scriptDir);

                    if (ScriptConfig.Functions != null &&
                        !ScriptConfig.Functions.Contains(functionName, StringComparer.OrdinalIgnoreCase))
                    {
                        // a functions filter has been specified and the current function is
                        // not in the filter list
                        continue;
                    }

                    ValidateFunctionName(functionName);

                    // TODO: we need to define a json schema document and do
                    // schema validation and give more informative responses
                    string           json           = File.ReadAllText(functionConfigPath);
                    JObject          functionConfig = JObject.Parse(json);
                    FunctionMetadata metadata       = ParseFunctionMetadata(functionName, functionConfig);

                    if (metadata.IsExcluded)
                    {
                        TraceWriter.Info(string.Format("Function '{0}' is marked as excluded", functionName));
                        continue;
                    }

                    if (metadata.IsDisabled)
                    {
                        TraceWriter.Info(string.Format("Function '{0}' is disabled", functionName));
                    }

                    // determine the primary script
                    string[] functionFiles = Directory.EnumerateFiles(scriptDir).Where(p => Path.GetFileName(p).ToLowerInvariant() != ScriptConstants.FunctionMetadataFileName).ToArray();
                    if (functionFiles.Length == 0)
                    {
                        AddFunctionError(functionName, "No function script files present.");
                        continue;
                    }
                    string scriptFile = DeterminePrimaryScriptFile(functionConfig, functionFiles);
                    if (string.IsNullOrEmpty(scriptFile))
                    {
                        AddFunctionError(functionName,
                                         "Unable to determine the primary function script. Try renaming your entry point script to 'run' (or 'index' in the case of Node), " +
                                         "or alternatively you can specify the name of the entry point script explicitly by adding a 'scriptFile' property to your function metadata.");
                        continue;
                    }
                    metadata.ScriptFile = scriptFile;

                    // determine the script type based on the primary script file extension
                    metadata.ScriptType = ParseScriptType(metadata.ScriptFile);

                    metadata.EntryPoint = (string)functionConfig["entryPoint"];

                    metadatas.Add(metadata);
                }
                catch (Exception ex)
                {
                    // log any unhandled exceptions and continue
                    AddFunctionError(functionName, ex.Message);
                }
            }

            return(ReadFunctions(metadatas, descriptorProviders));
        }
        public override RfcPreparedFunction PrepareFunction(string functionName)
        {
            FunctionMetadata metadata = this.metadataCache.GetFunctionMetadata(functionName);

            return(new SoapRfcPreparedFunction(metadata, this.structureMapper, this._webClient));
        }
 public MockInvoker(ScriptHost host, IMetricsLogger metrics, IFunctionMetadataManager functionMetadataManager, FunctionMetadata metadata, ILoggerFactory loggerFactory)
     : base(host, metadata, loggerFactory)
 {
     _instanceLogger = new FunctionInstanceLogger(functionMetadataManager, metrics);
 }