public async Task SingletonMiddlewareWithUserProvidedInstance_NeverAttemptsToCreateAnInstance() { var serverBuilder = new TestServerBuilder <GraphSchema>(TestOptions.UseCodeDeclaredNames) .AddGraphType <MiddlewareController>(); var idsCalled = new List <string>(); var middlewareService = new Mock <IMiddlewareTestService>(); middlewareService.Setup(x => x.BeforeNext(It.IsAny <string>())).Callback( (string idValue) => { idsCalled.Add(idValue); }).Verifiable(); serverBuilder.AddSingleton(middlewareService.Object); // mock the calls that would be made through the primary builder to generate a fake pipeline var pipelineBuilder = new SchemaPipelineBuilder <GraphSchema, IGraphFieldExecutionMiddleware, GraphFieldExecutionContext>(); pipelineBuilder.TypeReferenceAdded += this.CreateTypeAddHandler(serverBuilder); // premake the singleton middleware component var component = new TestMiddlewareSingleton(middlewareService.Object); // inject the component into the pipeline as an item, not just a type reference pipelineBuilder.AddMiddleware(component); // make sure a delegate was created var pipeline = pipelineBuilder.Build(); Assert.IsNotNull(pipeline); var server = serverBuilder.Build(); var builder = server.CreateFieldContextBuilder <MiddlewareController>(nameof(MiddlewareController.FieldOfData)); // make an empty service collection (preventing creation if the middleware isnt found) var sc = new ServiceCollection(); builder.ServiceProvider = sc.BuildServiceProvider(); // execute the pipeline multiple times await pipeline.InvokeAsync(builder.CreateExecutionContext(), CancellationToken.None); await pipeline.InvokeAsync(builder.CreateExecutionContext(), CancellationToken.None); await pipeline.InvokeAsync(builder.CreateExecutionContext(), CancellationToken.None); await pipeline.InvokeAsync(builder.CreateExecutionContext(), CancellationToken.None); await pipeline.InvokeAsync(builder.CreateExecutionContext(), CancellationToken.None); // ensure all methods that were expected to be called, were called middlewareService.Verify(x => x.BeforeNext(It.IsAny <string>()), Times.Exactly(5)); // ensure that each time the middleware was called and an id saved off // that hte Id never changed (it was never "newed up" more than once and the original object id was used each time) Assert.AreEqual(5, idsCalled.Count); foreach (var id in idsCalled) { Assert.AreEqual(component.Id, id); } }
public async Task BatchExtension_SingleQueryForSingleSybling_ExecutesOnce_AndReturnsData() { var counter = new Dictionary <string, int>(); var batchService = new Mock <IBatchCounterService>(); batchService.Setup(x => x.CallCount).Returns(counter); var serverBuilder = new TestServerBuilder() .AddGraphType <BatchController>(); serverBuilder.AddSingleton(batchService.Object); var server = serverBuilder.Build(); var builder = server.CreateQueryContextBuilder(); builder.AddQueryText("query { batch { fetchData { property1, property2, sybling { syblingId, name }}}}"); var response = await server.RenderResult(builder); var expected = @" { ""data"": { ""batch"" : { ""fetchData"": [ { ""property1"": ""object0"", ""property2"": 0, ""sybling"": { ""syblingId"": ""object0"", ""name"": ""object0_sybling"" } }, { ""property1"": ""object1"", ""property2"": 1, ""sybling"": { ""syblingId"": ""object1"", ""name"": ""object1_sybling"" } }, { ""property1"": ""object2"", ""property2"": 2, ""sybling"": { ""syblingId"": ""object2"", ""name"": ""object2_sybling"" } }] } } }"; CommonAssertions.AreEqualJsonStrings(expected, response); Assert.AreEqual(1, counter[nameof(BatchController.PrimaryDataFetch)]); Assert.IsFalse(counter.ContainsKey(nameof(BatchController.FetchChildren))); Assert.AreEqual(1, counter[nameof(BatchController.FetchSibling)]); }
public async Task SingletonMiddlewareComponent_IsNeverInstantiatedMoreThanOnce() { var serverBuilder = new TestServerBuilder <GraphSchema>(TestOptions.UseCodeDeclaredNames) .AddGraphType <MiddlewareController>(); var idsCalled = new List <string>(); var middlewareService = new Mock <IMiddlewareTestService>(); middlewareService.Setup(x => x.BeforeNext(It.IsAny <string>())).Callback( (string idValue) => { idsCalled.Add(idValue); }).Verifiable(); serverBuilder.AddSingleton(middlewareService.Object); // mock the calls that would be made through the primary builder to generate a fake pipeline var pipelineBuilder = new SchemaPipelineBuilder <GraphSchema, IGraphFieldExecutionMiddleware, GraphFieldExecutionContext>(); pipelineBuilder.TypeReferenceAdded += this.CreateTypeAddHandler(serverBuilder); pipelineBuilder.AddMiddleware <TestMiddlewareSingleton>(ServiceLifetime.Singleton); // make sure a delegate was created var pipeline = pipelineBuilder.Build(); Assert.IsNotNull(pipeline); Assert.AreEqual(2, serverBuilder.Count); // 1 middleware component + the service // fake a graph ql request context var server = serverBuilder.Build(); var builder = server.CreateFieldContextBuilder <MiddlewareController>(nameof(MiddlewareController.FieldOfData)); // execute the pipeline multiple times await pipeline.InvokeAsync(builder.CreateExecutionContext(), CancellationToken.None); await pipeline.InvokeAsync(builder.CreateExecutionContext(), CancellationToken.None); await pipeline.InvokeAsync(builder.CreateExecutionContext(), CancellationToken.None); await pipeline.InvokeAsync(builder.CreateExecutionContext(), CancellationToken.None); await pipeline.InvokeAsync(builder.CreateExecutionContext(), CancellationToken.None); // ensure all methods that were expected to be called, were called middlewareService.Verify(x => x.BeforeNext(It.IsAny <string>()), Times.Exactly(5)); // ensure that each time the middleware was called and an id saved off // that hte Id never changed (it was never "newed up" more than once) Assert.AreEqual(5, idsCalled.Count); var singleton = server.ServiceProvider.GetService <TestMiddlewareSingleton>(); foreach (var id in idsCalled) { Assert.AreEqual(singleton.Id, id); } }
public async Task WithAttachedQueryCache_RendersPlanToCache() { var keyManager = new DefaultQueryPlanCacheKeyManager(new GraphQLParser()); var cacheInstance = new MemoryCache(nameof(WithAttachedQueryCache_RendersPlanToCache)); var cache = new DefaultQueryPlanCacheProvider(cacheInstance); var builder = new TestServerBuilder() .AddGraphType <SimpleExecutionController>(); builder.AddSingleton <IGraphQueryPlanCacheProvider>(cache); builder.AddSingleton <IGraphQueryPlanCacheKeyManager>(keyManager); // configure an absolute expriation of a few seconds to ensure the plan remains in cache // long enough to be fetched by tis expected key builder.AddGraphQL(o => { o.CacheOptions.TimeToLiveInMilliseconds = 10000; }); var server = builder.Build(); var queryText = "query { simple{ simpleQueryMethod { property1} } }"; var expectedCacheKey = keyManager.CreateKey <GraphSchema>(queryText); var queryBuilder = server.CreateQueryContextBuilder(); queryBuilder.AddQueryText(queryText); var result = await server.ExecuteQuery(queryBuilder); Assert.IsNotNull(result); Assert.AreEqual(1, cache.Count); // ensure we can pull the plan directly from the cache instance var cachedPlan = cacheInstance.GetCacheItem(expectedCacheKey); Assert.IsNotNull(cachedPlan); // attempt eviction through the provider await cache.EvictAsync(expectedCacheKey); // ensure underlying cache instance was evicted cachedPlan = cacheInstance.GetCacheItem(expectedCacheKey); Assert.IsNull(cachedPlan); }
public async Task EndToEndIntegrationTest() { var builder = new TestServerBuilder(); builder.AddScoped <IMusicService, MusicService>(); builder.AddSingleton <IMusicRepository, MusicRepository>(); builder.AddGraphType <MusicController>(); builder.AddGraphQL(o => { o.ExecutionOptions.AwaitEachRequestedField = true; }); var server = builder.Build(); // Test the following areas // ----------------------------------- // queries // input values: scalars // batch child query ("records" is a batch list extension method) // root level controller actions (note no nesting under the declared "music" field of the controller for the "artists" field) var expected = LoadOutputFile("RetrieveArtistsAndRecords.json"); var queryBuilder = server.CreateQueryContextBuilder(); queryBuilder.AddQueryText( @"query { artists(searchText: ""queen"") { id name records { id name genre { id name } } } }"); var result1 = await server.RenderResult(queryBuilder); CommonAssertions.AreEqualJsonStrings(expected, result1, "(1): " + result1); // Test the following areas // ----------------------------------- // virtual routing (the "music" field is a virtual field declared on the controller) // mutations // input values: scalars // batch sybling query ("company" is a batch sybling extension method) expected = LoadOutputFile("CreateNewArtist.json"); queryBuilder = server.CreateQueryContextBuilder(); queryBuilder.AddQueryText( @"mutation { music{ createArtist(artistName: ""EXO"", recordCompanyId: 4) { id name company { id name } } }}"); var result2 = await server.RenderResult(queryBuilder); CommonAssertions.AreEqualJsonStrings(expected, result2, "(2): " + result2); // Test the following areas // ----------------------------------- // virtual routing (the "music" field is a virtual field declared on the controller) // mutations // input values: complex objects // unicode characters expected = LoadOutputFile("CreateRecord.json"); queryBuilder = server.CreateQueryContextBuilder(); queryBuilder.AddQueryText( @"mutation { music{ createRecord(artist: {id: 10, name: ""EXO"", recordCompanyId: 4}, genre: {id:2, name: ""pop""}, songName:""다이아몬드"") { id artistId genre { id name } name } }}"); var result3 = await server.RenderResult(queryBuilder); CommonAssertions.AreEqualJsonStrings(expected, result3, "(3): " + result3); }
public async Task SingularPipelineInvokesComponentsInOrder() { var serverBuilder = new TestServerBuilder <GraphSchema>(TestOptions.UseCodeDeclaredNames) .AddGraphType <MiddlewareController>(); // setup a mock pipeline to verify that each middleware piece called into the service // and that hte order of the invocation was in the order the pipeline was declared var orderOfBeforeCalls = new List <string>(); var orderOfAfterCalls = new List <string>(); var middlewareService = new Mock <IMiddlewareTestService>(); middlewareService.Setup(x => x.AfterNext(It.IsAny <string>())).Callback( (string name) => { orderOfAfterCalls.Add(name); }).Verifiable(); middlewareService.Setup(x => x.BeforeNext(It.IsAny <string>())).Callback( (string name) => { orderOfBeforeCalls.Add(name); }).Verifiable(); // mock the calls that would be made through the primary builder to generate a fake pipeline var pipelineBuilder = new SchemaPipelineBuilder <GraphSchema, IGraphFieldExecutionMiddleware, GraphFieldExecutionContext>(); pipelineBuilder.TypeReferenceAdded += this.CreateTypeAddHandler(serverBuilder); pipelineBuilder.AddMiddleware <TestMiddleware1>(ServiceLifetime.Singleton); pipelineBuilder.AddMiddleware <TestMiddleware2>(ServiceLifetime.Singleton); pipelineBuilder.AddMiddleware <TestMiddleware3>(ServiceLifetime.Singleton); // ensure types were added via the event serverBuilder.AddSingleton(middlewareService.Object); Assert.AreEqual(4, serverBuilder.Count); // 3 middleware components + the service // create the pipleine var pipeline = pipelineBuilder.Build(); Assert.IsNotNull(pipeline); // fake a graph ql request context var server = serverBuilder.Build(); var fieldBuilder = server.CreateFieldContextBuilder <MiddlewareController>(nameof(MiddlewareController.FieldOfData)); var executionContext = fieldBuilder.CreateExecutionContext(); // execute the pipeline await pipeline.InvokeAsync(executionContext, CancellationToken.None); // ensure all methods that were expected to be called, were called middlewareService.Verify(x => x.BeforeNext(nameof(TestMiddleware1)), Times.Exactly(1)); middlewareService.Verify(x => x.AfterNext(nameof(TestMiddleware1)), Times.Exactly(1)); middlewareService.Verify(x => x.BeforeNext(nameof(TestMiddleware2)), Times.Exactly(1)); middlewareService.Verify(x => x.AfterNext(nameof(TestMiddleware2)), Times.Exactly(1)); middlewareService.Verify(x => x.BeforeNext(nameof(TestMiddleware3)), Times.Exactly(1)); middlewareService.Verify(x => x.AfterNext(nameof(TestMiddleware3)), Times.Exactly(1)); // ensure the invocation order was as expected // in ccreated order for the "before calls" Assert.AreEqual(3, orderOfBeforeCalls.Count); Assert.AreEqual(nameof(TestMiddleware1), orderOfBeforeCalls[0]); Assert.AreEqual(nameof(TestMiddleware2), orderOfBeforeCalls[1]); Assert.AreEqual(nameof(TestMiddleware3), orderOfBeforeCalls[2]); // in reverse order for the "after calls" Assert.AreEqual(3, orderOfAfterCalls.Count); Assert.AreEqual(nameof(TestMiddleware3), orderOfAfterCalls[0]); Assert.AreEqual(nameof(TestMiddleware2), orderOfAfterCalls[1]); Assert.AreEqual(nameof(TestMiddleware1), orderOfAfterCalls[2]); }