dark-loop / functions-authorize

An ASP.NET Core based authentication and authorization middleware for HTTP triggered Azure Functions (In-Proc and Isolated)
Apache License 2.0
40 stars 5 forks source link

Testing functions using TestServer. #18

Closed dgallo-igloo closed 6 months ago

dgallo-igloo commented 11 months ago

I am trying to setup integration tests in my project to test my functions through the full HTTP pipeline rather than unit testing at the function level and bypassing the pipeline.

When I attempt to setup the test server in my test class, I am getting the following error

Failed UserServiceTest.IntegrationTest.GetFunctionTests.GetUsersByIds_CanBeCalledWithoutError [1 ms]
  Error Message:
   System.TypeInitializationException : The type initializer for 'DarkLoop.Azure.Functions.Authorize.Security.AuthHelper' threw an exception.
---- System.IO.FileNotFoundException : Could not load file or assembly 'Microsoft.Azure.WebJobs.Script.WebHost, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.

  Stack Trace:
     at DarkLoop.Azure.Functions.Authorize.Security.AuthHelper.AddFunctionsBuiltInAuthorization(IServiceCollection services)
   at Microsoft.Extensions.DependencyInjection.AuthorizationExtensions.AddFunctionsAuthorization(IServiceCollection services, Action`1 configure)
   at Microsoft.Extensions.DependencyInjection.AuthorizationExtensions.AddAuthorization(IFunctionsHostBuilder builder)
   at Igloo.UserService.Startup.ConfigureServices(IFunctionsHostBuilder builder) in /Users/dgallo/Dropbox/Projects/app-user-service/v1/UserService/src/Startup/Startup.cs:line 112
   at Igloo.UserService.Startup.Configure(IFunctionsHostBuilder builder) in /Users/dgallo/Dropbox/Projects/app-user-service/v1/UserService/src/Startup/Startup.cs:line 107
   at UserServiceTest.IntegrationTest.TestStartup.Configure(IFunctionsHostBuilder builder) in /Users/dgallo/Dropbox/Projects/app-user-service/v1/UserService/test/IntegrationTest/GetFunctionTests.cs:line 21
   at Microsoft.Azure.Functions.Extensions.DependencyInjection.FunctionsStartup.Configure(WebJobsBuilderContext context, IWebJobsBuilder builder)
   at Microsoft.Azure.WebJobs.WebJobsBuilderExtensions.ConfigureStartup(IWebJobsStartup startup, WebJobsBuilderContext context, IWebJobsBuilder builder) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Hosting\WebJobsBuilderExtensions.cs:line 162
   at Microsoft.Azure.WebJobs.WebJobsBuilderExtensions.UseWebJobsStartup(IWebJobsBuilder builder, Type startupType, WebJobsBuilderContext context, ILoggerFactory loggerFactory) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Hosting\WebJobsBuilderExtensions.cs:line 111
   at UserServiceTest.IntegrationTest.GetFunctionTests.<>c.<.ctor>b__4_0(IWebJobsBuilder builder) in /Users/dgallo/Dropbox/Projects/app-user-service/v1/UserService/test/IntegrationTest/GetFunctionTests.cs:line 38
   at Microsoft.Extensions.Hosting.WebJobsHostBuilderExtensions.<>c__DisplayClass2_0.<ConfigureWebJobs>b__0(HostBuilderContext context, IWebJobsBuilder b) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Hosting\WebJobsHostBuilderExtensions.cs:line 27
   at Microsoft.Extensions.Hosting.WebJobsHostBuilderExtensions.<>c__DisplayClass5_0.<ConfigureWebJobs>b__1(HostBuilderContext context, IServiceCollection services) in C:\projects\azure-webjobs-sdk-rqm4t\src\Microsoft.Azure.WebJobs.Host\Hosting\WebJobsHostBuilderExtensions.cs:line 54
   at Microsoft.Extensions.Hosting.HostBuilder.CreateServiceProvider()
   at Microsoft.Extensions.Hosting.HostBuilder.Build()
   at UserServiceTest.IntegrationTest.GetFunctionTests..ctor(TestStartup testStartup) in /Users/dgallo/Dropbox/Projects/app-user-service/v1/UserService/test/IntegrationTest/GetFunctionTests.cs:line 36
----- Inner Stack Trace -----
   at System.Reflection.RuntimeAssembly.InternalLoad(ObjectHandleOnStack assemblyName, ObjectHandleOnStack requestingAssembly, StackCrawlMarkHandle stackMark, Boolean throwOnFileNotFound, ObjectHandleOnStack assemblyLoadContext, ObjectHandleOnStack retAssembly)
   at System.Reflection.RuntimeAssembly.InternalLoad(AssemblyName assemblyName, RuntimeAssembly requestingAssembly, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, AssemblyLoadContext assemblyLoadContext)
   at System.Reflection.Assembly.Load(String assemblyString)
   at DarkLoop.Azure.Functions.Authorize.Security.AuthHelper..cctor()

The setup of the test server is done like so and this is where the error is being raised within:

_testServer = new HostBuilder()
                .ConfigureWebJobs(
                    builder => builder.UseWebJobsStartup(typeof(TestStartup), new WebJobsBuilderContext(), NullLoggerFactory.Instance)
                )
                .Build()
                .GetTestServer();

Then the test looks like this:

[Fact]
        public async Task GetUsersByIds_CanBeCalledWithoutError()
        {

            var request = new HttpRequestMessage(HttpMethod.Get, "users/ids");
            var response = await _testHttpClient.SendAsync(request);

            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
        }

After some research, it seems as though the Microsoft.Azure.WebJobs.Script.WebHost assembly is provided by the Azure Functions Runtime. Since, I'm using a TestServer, its not running in the Azure Functions Runtime.

Is there an approach to perform tests like this when Darkloop is being used?

artmasa commented 11 months ago

@dgallo-igloo, as you noticed, ...Script.WebHost is only available in the functions runtime. It is not a package available that can be referenced. This is the exact reason why AuthHelper is there; to interact with the functions host libraries. As runtime gets updated the library is also updated and loaded by the runtime. We cannot have a hard dependency on a specific version. If you are in control of your test environment and your runtime version is locked, you might be able to store and reference the dll within the test project and load it.

artmasa commented 9 months ago

@dgallo-igloo I will close this issue as the solution would require Functions runtime to be loaded.

artmasa commented 7 months ago

@dgallo-igloo, by looking into the functions core tools project I found out they publish the webhost assembly to an Azure Artifacts repo, not NuGet. You can check NuGet.config to check them out. And you can see how I utilized the package for my in-proc test project.