public async Task NonSocketRequest_AgainstDifferentRoute_IsSkipped() { bool nextCalled = false; Task CallNext(HttpContext context) { nextCalled = true; return(Task.CompletedTask); } var next = new RequestDelegate(CallNext); var options = new SubscriptionServerOptions <GraphSchema>(); var server = new Mock <ISubscriptionServer <GraphSchema> >(); var middleware = new DefaultGraphQLHttpSubscriptionMiddleware <GraphSchema>( next, server.Object, options); var context = new DefaultHttpContext(); context.RequestServices = new Mock <IServiceProvider>().Object; context.Request.Path = "/stuff/data"; // not a socket request aginst the route // should be skipped await middleware.InvokeAsync(context); Assert.IsTrue(nextCalled); }
public async Task StartConnection_OnReadClose_IfConnectionIsOpen_CloseConnection() { // set the underlying connection to not auto close when it retrieves a close message // from the queue, leaving it up to the apollo client to do the close var socketClient = new MockClientConnection(autoCloseOnReadCloseMessage: false); var options = new SubscriptionServerOptions <GraphSchema>(); var provider = new ServiceCollection().BuildServiceProvider(); var apolloClient = new ApolloClientProxy <GraphSchema>( socketClient, options, new ApolloMessageConverterFactory(), null, false); var eventCalled = false; void ConnectionClosed(object sender, EventArgs e) { eventCalled = true; } apolloClient.ConnectionClosed += ConnectionClosed; // execute the connection sequence socketClient.QueueConnectionCloseMessage(); await apolloClient.StartConnection(); Assert.IsTrue(eventCalled, "Connection Closed Event Handler not called"); }
public async Task SocketRequest_AgainstListeningRoute_ExceptionOnClientCreation_ResultsInBadRequest() { bool nextCalled = false; Task CallNext(HttpContext context) { nextCalled = true; return(Task.CompletedTask); } var next = new RequestDelegate(CallNext); var server = new Mock <ISubscriptionServer <GraphSchema> >(); server.Setup(x => x.RegisterNewClient(It.IsAny <IClientConnection>())).Throws(new InvalidOperationException("failed")); var options = new SubscriptionServerOptions <GraphSchema>(); var middleware = new DefaultGraphQLHttpSubscriptionMiddleware <GraphSchema>( next, server.Object, options); var context = new FakeWebSocketHttpContext(); context.RequestServices = new Mock <IServiceProvider>().Object; context.Request.Path = options.Route; // not a socket request aginst the route // next middleware component should not be invoked await middleware.InvokeAsync(context); Assert.IsFalse(nextCalled); Assert.AreEqual((int)HttpStatusCode.InternalServerError, context.Response.StatusCode); }
/// <summary> /// Initializes a new instance of the <see cref="DefaultGraphQLHttpSubscriptionMiddleware{TSchema}" /> class. /// </summary> /// <param name="next">The delegate pointing to the next middleware component /// in the pipeline.</param> /// <param name="subscriptionServer">The subscription server configured for /// this web host.</param> /// <param name="options">The options.</param> public DefaultGraphQLHttpSubscriptionMiddleware( RequestDelegate next, ISubscriptionServer <TSchema> subscriptionServer, SubscriptionServerOptions <TSchema> options) { _next = next; _options = Validation.ThrowIfNullOrReturn(options, nameof(options)); _subscriptionServer = Validation.ThrowIfNullOrReturn(subscriptionServer, nameof(subscriptionServer)); _routePath = Validation.ThrowIfNullOrReturn(_options.Route, nameof(_options.Route)); }
public void GeneralPropertyCheck() { // ensure no funny business with retrieving set values var options = new SubscriptionServerOptions <GraphSchema>(); Assert.IsFalse(options.DisableDefaultRoute); options.DisableDefaultRoute = true; Assert.IsTrue(options.DisableDefaultRoute); options.Route = "bob"; Assert.AreEqual("bob", options.Route); options.MessageBufferSize = 15; Assert.AreEqual(15, options.MessageBufferSize); }
public void GeneralPropertyCheck() { using var restorePoint = new GraphQLProviderRestorePoint(); GraphQLProviders.TemplateProvider = null; var primaryOptions = new SchemaOptions <GraphSchema>(); var subscriptionOptions = new SubscriptionServerOptions <GraphSchema>(); var extension = new SubscriptionPublisherSchemaExtension <GraphSchema>(); extension.Configure(primaryOptions); Assert.IsTrue(primaryOptions.DeclarationOptions.AllowedOperations.Contains(GraphCollection.Subscription)); Assert.IsTrue(GraphQLProviders.TemplateProvider is SubscriptionEnabledTemplateProvider); }
/// <summary> /// Adds subscription server support to the test server builder. /// </summary> /// <typeparam name="TSchema">The type of the schema the builder supports.</typeparam> /// <param name="serverBuilder">The server builder.</param> /// <param name="options">The options to configure the schema with.</param> /// <returns>TestServerBuilder<TSchema>.</returns> public static TestServerBuilder <TSchema> AddSubscriptionServer <TSchema>( this TestServerBuilder <TSchema> serverBuilder, Action <SubscriptionServerOptions <TSchema> > options = null) where TSchema : class, ISchema { var subscriptionsOptions = new SubscriptionServerOptions <TSchema>(); options?.Invoke(subscriptionsOptions); serverBuilder.AddSchemaBuilderAction(schemaBuilder => { DefaultSubscriptionBuilderExtensions .AddSubscriptionServer(schemaBuilder, options); }); return(serverBuilder); }
/// <summary> /// Initializes a new instance of the <see cref="ApolloClientProxy{TSchema}" /> class. /// </summary> /// <param name="clientConnection">The underlying client connection for apollo to manage.</param> /// <param name="options">The options used to configure the registration.</param> /// <param name="messageConverter">The message converter factory that will generate /// json converters for the various <see cref="ApolloMessage" /> the proxy shuttles to the client.</param> /// <param name="logger">The logger to record client level events to, if any.</param> /// <param name="enableMetrics">if set to <c>true</c> any queries this client /// executes will have metrics attached.</param> public ApolloClientProxy( IClientConnection clientConnection, SubscriptionServerOptions <TSchema> options, ApolloMessageConverterFactory messageConverter, IGraphEventLogger logger = null, bool enableMetrics = false) { _connection = Validation.ThrowIfNullOrReturn(clientConnection, nameof(clientConnection)); _options = Validation.ThrowIfNullOrReturn(options, nameof(options)); _messageConverter = Validation.ThrowIfNullOrReturn(messageConverter, nameof(messageConverter)); _reservedMessageIds = new ClientTrackedMessageIdSet(); _subscriptions = new ApolloSubscriptionCollection <TSchema>(); _enableKeepAlive = options.KeepAliveInterval != TimeSpan.Zero; _logger = logger != null ? new ApolloClientEventLogger <TSchema>(this, logger) : null; _enableMetrics = enableMetrics; }
/// <summary> /// Initializes a new instance of the <see cref="ApolloSubscriptionServer{TSchema}" /> class. /// </summary> /// <param name="schema">The schema instance this sever will use for various comparisons.</param> /// <param name="options">The user configured options for this server.</param> /// <param name="eventRouter">The listener watching for new events that need to be communicated /// to clients managed by this server.</param> /// <param name="logger">The logger to record server events to, if any.</param> public ApolloSubscriptionServer( TSchema schema, SubscriptionServerOptions <TSchema> options, ISubscriptionEventRouter eventRouter, IGraphEventLogger logger = null) { _schema = Validation.ThrowIfNullOrReturn(schema, nameof(schema)); _serverOptions = Validation.ThrowIfNullOrReturn(options, nameof(options)); _eventRouter = Validation.ThrowIfNullOrReturn(eventRouter, nameof(eventRouter)); _clients = new HashSet <ApolloClientProxy <TSchema> >(); _eventSendSemaphore = new SemaphoreSlim(_serverOptions.MaxConcurrentClientNotifications); _logger = logger != null ? new ApolloServerEventLogger <TSchema>(this, logger) : null; _subCountByName = new Dictionary <SubscriptionEventName, HashSet <ApolloClientProxy <TSchema> > >( SubscriptionEventNameEqualityComparer.Instance); this.Id = Guid.NewGuid().ToString(); }
/// <summary> /// Adds a subscription server to this instance that will accept connected clients and /// process subscription requests from those clients. This extension will attempt to inject subscription related /// middleware into the primary query excution pipeline and replace it. Call this method before injecting or /// adding your own query execution middleware items. /// </summary> /// <typeparam name="TSchema">The type of the schema being built.</typeparam> /// <param name="schemaBuilder">The schema builder.</param> /// <param name="options">An action function to configure the subscription options.</param> /// <returns>ISchemaBuilder<TSchema>.</returns> public static ISchemaBuilder <TSchema> AddSubscriptionServer <TSchema>( this ISchemaBuilder <TSchema> schemaBuilder, Action <SubscriptionServerOptions <TSchema> > options = null) where TSchema : class, ISchema { var subscriptionsOptions = new SubscriptionServerOptions <TSchema>(); options?.Invoke(subscriptionsOptions); var extension = new ApolloSubscriptionServerSchemaExtension <TSchema>(schemaBuilder, subscriptionsOptions); // register the default router type to the service collection var defaultRouter = CreateDefaultSubscriptionRouterDescriptor(); extension.OptionalServices.Add(defaultRouter); schemaBuilder.Options.RegisterExtension(extension); return(schemaBuilder); }
public async Task SocketRequest_AgainstListeningRoute_SocketIsInvoked() { bool nextCalled = false; Task CallNext(HttpContext context) { nextCalled = true; return(Task.CompletedTask); } var next = new RequestDelegate(CallNext); var connection = new Mock <ISubscriptionClientProxy>(); connection.Setup(x => x.StartConnection()).Returns(Task.CompletedTask); var server = new Mock <ISubscriptionServer <GraphSchema> >(); server.Setup(x => x.RegisterNewClient(It.IsAny <IClientConnection>())).ReturnsAsync(connection.Object); var options = new SubscriptionServerOptions <GraphSchema>(); var middleware = new DefaultGraphQLHttpSubscriptionMiddleware <GraphSchema>( next, server.Object, options); var context = new FakeWebSocketHttpContext(); context.RequestServices = new Mock <IServiceProvider>().Object; context.Request.Path = options.Route; // not a socket request aginst the route // next middleware component should not be invoked await middleware.InvokeAsync(context); Assert.IsFalse(nextCalled); }
/// <summary> /// Initializes a new instance of the <see cref="ApolloSubscriptionServerSchemaExtension{TSchema}" /> class. /// </summary> /// <param name="schemaBuilder">The schema builder created when adding graphql to the server /// originally.</param> /// <param name="options">The options.</param> public ApolloSubscriptionServerSchemaExtension(ISchemaBuilder <TSchema> schemaBuilder, SubscriptionServerOptions <TSchema> options) { _schemaBuilder = Validation.ThrowIfNullOrReturn(schemaBuilder, nameof(schemaBuilder)); this.SubscriptionOptions = Validation.ThrowIfNullOrReturn(options, nameof(options)); this.RequiredServices = new List <ServiceDescriptor>(); this.OptionalServices = new List <ServiceDescriptor>(); }
public void GeneralPropertyCheck() { using var restorePoint = new GraphQLProviderRestorePoint(); GraphQLProviders.TemplateProvider = null; var primaryOptions = new SchemaOptions <GraphSchema>(); var subscriptionOptions = new SubscriptionServerOptions <GraphSchema>(); (var builder, var queryPipeline, var fieldPipeline) = CreateSchemaBuilderMock(); var extension = new ApolloSubscriptionServerSchemaExtension <GraphSchema>(builder.Object, subscriptionOptions); extension.Configure(primaryOptions); Assert.IsTrue(primaryOptions.DeclarationOptions.AllowedOperations.Contains(GraphCollection.Subscription)); Assert.AreEqual(2, extension.RequiredServices.Count); Assert.IsNotNull(extension.RequiredServices.SingleOrDefault(x => x.ServiceType == typeof(SubscriptionServerOptions <GraphSchema>))); Assert.IsNotNull(extension.RequiredServices.SingleOrDefault(x => x.ServiceType == typeof(ApolloMessageConverterFactory))); Assert.AreEqual(1, extension.OptionalServices.Count); Assert.IsNotNull(extension.OptionalServices.SingleOrDefault(x => x.ServiceType == typeof(ISubscriptionServer <GraphSchema>))); Assert.IsTrue(GraphQLProviders.TemplateProvider is SubscriptionEnabledTemplateProvider); // 9 middleware components in the subscription-swapped primary query pipeline registered by type // 1 middleware component registered by instance queryPipeline.Verify(x => x.Clear()); queryPipeline.Verify( x => x.AddMiddleware <IGraphMiddlewareComponent <GraphQueryExecutionContext> >( It.IsAny <ServiceLifetime>(), It.IsAny <string>()), Times.Exactly(9)); queryPipeline.Verify( x => x.AddMiddleware( It.IsAny <IGraphMiddlewareComponent <GraphQueryExecutionContext> >(), It.IsAny <string>()), Times.Exactly(1)); // ensur query level authorzation component was added queryPipeline.Verify( x => x.AddMiddleware <AuthorizeQueryOperationMiddleware <GraphSchema> >( It.IsAny <ServiceLifetime>(), It.IsAny <string>()), Times.Exactly(1)); // four components in the sub swaped field pipeline fieldPipeline.Verify(x => x.Clear()); fieldPipeline.Verify( x => x.AddMiddleware <IGraphMiddlewareComponent <GraphFieldExecutionContext> >(It.IsAny <ServiceLifetime>(), It.IsAny <string>()), Times.Exactly(4)); // ensure field authroization component was NOT added // to the field pipeline fieldPipeline.Verify( x => x.AddMiddleware <AuthorizeFieldMiddleware <GraphSchema> >(It.IsAny <ServiceLifetime>(), It.IsAny <string>()), Times.Exactly(0)); }