Exemple #1
0
        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);
            }
        }
Exemple #2
0
        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)]);
        }
Exemple #3
0
        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);
            }
        }
Exemple #4
0
        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);
        }
Exemple #5
0
        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);
        }
Exemple #6
0
        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]);
        }