public void FindDefaultFunctionType_NoFunctionTypes() =>
 Assert.Throws <ArgumentException>(() => HostingInternals.FindDefaultFunctionType(
                                       typeof(FunctionTargetTest),
                                       typeof(FunctionsEnvironmentVariablesConfigurationSourceTest),
                                       typeof(AbstractHttpFunction), // Abstract, doesn't count
                                       typeof(INamedHttpFunction)    // Interface, doesn't count
                                       ));
        public async Task NonGenericCloudEventFunction()
        {
            var services = new ServiceCollection();

            services.AddLogging();
            HostingInternals.AddServicesForFunctionTarget(services, typeof(EventIdRememberingFunction));
            var provider = services.BuildServiceProvider();

            var function = provider.GetRequiredService <IHttpFunction>();

            Assert.Equal(typeof(EventIdRememberingFunction), provider.GetRequiredService <HostingInternals.FunctionTypeProvider>().FunctionType);
            string eventId = Guid.NewGuid().ToString();
            var    context = new DefaultHttpContext
            {
                Request =
                {
                    // No actual content, but that's okay.
                    ContentType = "application/json",
                    Headers     =
                    {
                        { "ce-specversion", "1.0"   },
                        { "ce-source",      "test"  },
                        { "ce-type",        "test"  },
                        { "ce-id",          eventId }
                    }
                }
            };

            await function.HandleAsync(context);

            Assert.Equal(eventId, EventIdRememberingFunction.LastEventId);
        }
        public async Task TargetFunction_EventFunction_Generic()
        {
            var services = new ServiceCollection();

            services.AddLogging();
            HostingInternals.AddServicesForFunctionTarget(services, typeof(StorageCloudEventFunction));
            var provider = services.BuildServiceProvider();
            var function = provider.GetRequiredService <IHttpFunction>();

            Assert.Equal(typeof(StorageCloudEventFunction), provider.GetRequiredService <HostingInternals.FunctionTypeProvider>().FunctionType);
            var eventId = Guid.NewGuid().ToString();
            var context = new DefaultHttpContext
            {
                Request =
                {
                    ContentType = "application/json",
                    Body        = new MemoryStream(Encoding.UTF8.GetBytes("{\"name\": \"testdata\"}")),
                    Headers     =
                    {
                        { "ce-specversion", "1.0"   },
                        { "ce-source",      "test"  },
                        { "ce-type",        "test"  },
                        { "ce-id",          eventId }
                    }
                },
            };

            await function.HandleAsync(context);

            Assert.Equal(eventId, StorageCloudEventFunction.LastEventId);
            Assert.Equal("testdata", StorageCloudEventFunction.LastData.Name);
        }
        public void FindDefaultFunctionType_TypedCloudEventFunction()
        {
            var expected = typeof(StorageCloudEventFunction);
            var actual   = HostingInternals.FindDefaultFunctionType(typeof(StorageCloudEventFunction));

            Assert.Equal(expected, actual);
        }
 /// <summary>
 /// Uses the functions startup classes specified by <see cref="FunctionsStartupAttribute"/> when configuring the host.
 /// Startup classes can contribute to logging, configuration sources, services, and application configuration.
 /// </summary>
 /// <param name="webHostBuilder">The web host builder to configure.</param>
 /// <param name="assembly">The assembly to query for attributes specifying startup classes.</param>
 /// <returns>The original builder, for method chaining.</returns>
 public static IWebHostBuilder UseFunctionsStartups(this IWebHostBuilder webHostBuilder, Assembly assembly)
 {
     foreach (var startup in HostingInternals.GetStartups(assembly))
     {
         webHostBuilder.UseFunctionsStartup(startup);
     }
     return(webHostBuilder);
 }
        public void GetStartups()
        {
            var startups    = HostingInternals.GetStartups(typeof(FunctionsStartupTest).Assembly);
            var actualTypes = startups.Select(startup => startup.GetType()).ToArray();
            // TestStartup2 comes before TestStartup1 due to the Order properties.
            var expectedTypes = new[] { typeof(TestStartup2), typeof(TestStartup1) };

            Assert.Equal(expectedTypes, actualTypes);
        }
        public void NonInstantiableFunctionType()
        {
            var services = new ServiceCollection();

            services.AddLogging();
            HostingInternals.AddServicesForFunctionTarget(services, typeof(NonInstantiableFunction));
            // We only find out when we try to get an IHttpFunction that we can't actually instantiate the function.
            var provider = services.BuildServiceProvider();

            Assert.Throws <InvalidOperationException>(() => provider.GetRequiredService <IHttpFunction>());
        }
        public void FindDefaultFunctionType_SingleFunctionType()
        {
            var expected = typeof(DefaultFunction);
            var actual   = HostingInternals.FindDefaultFunctionType(
                typeof(FunctionTargetTest),
                typeof(FunctionsEnvironmentVariablesConfigurationSourceTest),
                typeof(AbstractHttpFunction), // Abstract, doesn't count
                typeof(INamedHttpFunction),   // Interface, doesn't count
                typeof(DefaultFunction));

            Assert.Equal(expected, actual);
        }
        public async Task DependencyScopingIntegration()
        {
            // We create a test server, but we bypass most of it - we're really just using it to create
            // services we can execute an HttpContext against. (This is simpler than interacting via
            // an actual HTTP request and response.)
            var host = Host.CreateDefaultBuilder()
                       .ConfigureWebHost(webHostBuilder => webHostBuilder
                                         .ConfigureServices((context, services) => services.AddFunctionTarget <DependencyTestFunction>())
                                         .UseFunctionsStartup(new DependencyStartup())
                                         .Configure((context, app) => app.UseFunctionsFramework(context))
                                         .UseTestServer())
                       .Build();
            var testServer = host.GetTestServer();

            // Execute two requests, and remember the dependencies we saw in each of them.
            var request1Deps = await MakeRequestAsync();

            var request2Deps = await MakeRequestAsync();

            // We should get dependencies on every call
            Assert.NotNull(request1Deps.dep1);
            Assert.NotNull(request1Deps.dep2);
            Assert.NotNull(request2Deps.dep1);
            Assert.NotNull(request2Deps.dep2);

            // Dependency1 is registered as a singleton, so we should have the same value in both requests.
            Assert.Same(request1Deps.dep1, request2Deps.dep1);
            // Dependency2 is registered as a scoped service, so we should have different values in each request.
            Assert.NotSame(request1Deps.dep2, request2Deps.dep2);

            async Task <(object dep1, object dep2)> MakeRequestAsync()
            {
                using (var scope = testServer.Services.CreateScope())
                {
                    var context = new DefaultHttpContext {
                        RequestServices = scope.ServiceProvider
                    };
                    await HostingInternals.Execute(context);

                    return(context.Items[DependencyTestFunction.Dependency1Key], context.Items[DependencyTestFunction.Dependency2Key]);
                }
            }
        }
Exemple #10
0
 /// <summary>
 /// Internal method called directly by EntryPoint, so that it can validate that the appropriate startup
 /// classes to use haven't changed as a result of using the startup classes that *have* been executed.
 /// </summary>
 internal static IApplicationBuilder UseFunctionsFramework(this IApplicationBuilder app, WebHostBuilderContext context, bool validateStartups) =>
 HostingInternals.ConfigureApplication(context, app, validateStartups);
Exemple #11
0
 /// <summary>
 /// Adds the given startup class into the service collection. This method can be called multiple times, and all startup
 /// classes will be used.
 /// Startup classes can contribute to logging, configuration sources, services, and application configuration.
 /// </summary>
 /// <param name="webHostBuilder">The web host builder to configure.</param>
 /// <param name="startup">The startup class to use.</param>
 /// <returns>The original builder, for method chaining.</returns>
 public static IWebHostBuilder UseFunctionsStartup(
     this IWebHostBuilder webHostBuilder, FunctionsStartup startup) =>
 HostingInternals.AddStartup(webHostBuilder, startup);
 /// <summary>
 /// Adds services required for the Functions Framework to use the specified function target type, which must
 /// implement one of the Functions Framework function interfaces.
 /// </summary>
 /// <remarks>
 /// If this method completes successfully, a binding for <see cref="IHttpFunction"/> will definitely
 /// have been added to the service collection. Other bindings may also be present, in order to adapt
 /// the function to <see cref="IHttpFunction"/>.
 /// </remarks>
 /// <param name="services">The service collection to configure.</param>
 /// <param name="type">The target function type.</param>
 /// <returns>The original service collection, for method chaining.</returns>
 public static IServiceCollection AddFunctionTarget(this IServiceCollection services, Type type) =>
 HostingInternals.AddServicesForFunctionTarget(services, type);
        public void FunctionTypeImplementsMultipleInterfaces()
        {
            var services = new ServiceCollection();

            Assert.Throws <InvalidOperationException>(() => HostingInternals.AddServicesForFunctionTarget(services, typeof(MultipleCloudEventTypes)));
        }
Exemple #14
0
 /// <summary>
 /// Adds a configuration source for the Functions Framework based on command line arguments.
 /// </summary>
 /// <param name="builder">The configuration builder to add the source to.</param>
 /// <param name="args">The command line arguments to use for configuration.</param>
 /// <returns>The original builder, for method chaining.</returns>
 public static IConfigurationBuilder AddFunctionsCommandLine(this IConfigurationBuilder builder, string[] args) =>
 HostingInternals.AddCommandLineArguments(builder, args);
 /// <summary>
 /// Configures the given application builder to use the Functions Framework.
 /// This method executes the <see cref="FunctionsStartup.Configure(WebHostBuilderContext, AspNetCore.Builder.IApplicationBuilder)"/>
 /// method on any registered functions startup classes before adding handlers that
 /// return "not found" responses for fixed paths (e.g. "favicon.ico") and setting the terminal
 /// handler to execute the target function.
 /// </summary>
 /// <remarks>
 /// This method requires (at a minimum) that a function target has been registered,
 /// as it uses the <see cref="IHttpFunction"/> interface to handle requests.
 /// The target is typically registered using the
 /// <see cref="FunctionsFrameworkServiceCollectionExtensions.AddFunctionTarget(IServiceCollection, WebHostBuilderContext, System.Reflection.Assembly)"/>
 /// method or another <c>AddFunctionTarget</c> overload.
 /// </remarks>
 /// <param name="app">The application builder to configure.</param>
 /// <param name="context">The context of the web host builder being configured.</param>
 /// <returns>The original builder, for method chaining.</returns>
 public static IApplicationBuilder UseFunctionsFramework(this IApplicationBuilder app, WebHostBuilderContext context) =>
 HostingInternals.ConfigureApplication(context, app);
        public void NonFunctionType()
        {
            var services = new ServiceCollection();

            Assert.Throws <InvalidOperationException>(() => HostingInternals.AddServicesForFunctionTarget(services, typeof(NonFunction)));
        }
 public void FindDefaultFunctionType_MultipleCloudEventTypesFunction() =>
 Assert.Throws <ArgumentException>(() => HostingInternals.FindDefaultFunctionType(
                                       typeof(MultipleCloudEventTypes)));
 public void FindDefaultFunctionType_MultipleFunctionTypes() =>
 Assert.Throws <ArgumentException>(() => HostingInternals.FindDefaultFunctionType(
                                       typeof(DefaultFunction),
                                       typeof(EventIdRememberingFunction)));
 /// <summary>
 /// Adds required services to the service collection within the given web host builder for the Functions Framework
 /// to use a target function from the given assembly. If the Functions Framework configuration within the web host
 /// builder (typically provided by command line arguments or environment variables)
 /// does not specify a target function, the assembly is scanned for a single compatible function type.
 /// </summary>
 /// <remarks>
 /// If this method completes successfully, a binding for <see cref="IHttpFunction"/> will definitely
 /// have been added to the service collection. Other bindings may also be present, in order to adapt
 /// the function to <see cref="IHttpFunction"/>.
 /// </remarks>
 /// <param name="services">The service collection to configure.</param>
 /// <param name="context">The context of the web host builder being configured.</param>
 /// <param name="assembly">The assembly expected to contain the Functions Framework target function.</param>
 /// <returns>The original builder, for method chaining.</returns>
 public static IServiceCollection AddFunctionTarget(this IServiceCollection services, WebHostBuilderContext context, Assembly assembly) =>
 HostingInternals.AddServicesForFunctionTarget(services, HostingInternals.GetFunctionTarget(context, assembly));