diff --git a/src/HotChocolate/PersistedQueries/src/PersistedQueries.Redis/Extensions/HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions.cs b/src/HotChocolate/PersistedQueries/src/PersistedQueries.Redis/Extensions/HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions.cs index a349256c414..a6a753bbbad 100644 --- a/src/HotChocolate/PersistedQueries/src/PersistedQueries.Redis/Extensions/HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions.cs +++ b/src/HotChocolate/PersistedQueries/src/PersistedQueries.Redis/Extensions/HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions.cs @@ -4,169 +4,181 @@ using HotChocolate.Execution.Configuration; using HotChocolate; -namespace Microsoft.Extensions.DependencyInjection +namespace Microsoft.Extensions.DependencyInjection; + +/// +/// Provides utility methods to setup dependency injection. +/// +public static class HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions { /// - /// Provides utility methods to setup dependency injection. + /// Adds a redis read and write query storage to the + /// services collection. /// - public static class HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions + /// + /// The service collection to which the services are added. + /// + /// + /// A factory that resolves the redis database that + /// shall be used for persistence. + /// + /// + /// A timeout after which a query is removed from the Redis cache. + /// + public static IRequestExecutorBuilder AddRedisQueryStorage( + this IRequestExecutorBuilder builder, + Func databaseFactory, + TimeSpan? queryExpiration = null) { - /// - /// Adds a redis read and write query storage to the - /// services collection. - /// - /// - /// The service collection to which the services are added. - /// - /// - /// A factory that resolves the redis database that - /// shall be used for persistence. - /// - public static IRequestExecutorBuilder AddRedisQueryStorage( - this IRequestExecutorBuilder builder, - Func databaseFactory) + if (builder is null) { - if (builder is null) - { - throw new ArgumentNullException(nameof(builder)); - } - - if (databaseFactory is null) - { - throw new ArgumentNullException(nameof(databaseFactory)); - } - - return builder.ConfigureSchemaServices( - s => s.AddRedisQueryStorage(sp => databaseFactory(sp.GetCombinedServices()))); + throw new ArgumentNullException(nameof(builder)); } - /// - /// Adds a redis read and write query storage to the - /// services collection. - /// - /// - /// The service collection to which the services are added. - /// - /// - /// A factory that resolves the redis connection multiplexer. - /// - public static IRequestExecutorBuilder AddRedisQueryStorage( - this IRequestExecutorBuilder builder, - Func multiplexerFactory) + if (databaseFactory is null) { - if (builder is null) - { - throw new ArgumentNullException(nameof(builder)); - } - - if (multiplexerFactory is null) - { - throw new ArgumentNullException(nameof(multiplexerFactory)); - } - - return builder.ConfigureSchemaServices( - s => s.AddRedisQueryStorage( - sp => multiplexerFactory(sp.GetCombinedServices()).GetDatabase())); + throw new ArgumentNullException(nameof(databaseFactory)); } - /// - /// Adds a redis read and write query storage to the - /// services collection and uses the first - /// registered on the application services. - /// - /// - /// The service collection to which the services are added. - /// - public static IRequestExecutorBuilder AddRedisQueryStorage( - this IRequestExecutorBuilder builder) + return builder.ConfigureSchemaServices( + s => s.AddRedisQueryStorage( + sp => databaseFactory(sp.GetCombinedServices()), + queryExpiration)); + } + + /// + /// Adds a redis read and write query storage to the + /// services collection. + /// + /// + /// The service collection to which the services are added. + /// + /// + /// A factory that resolves the redis connection multiplexer. + /// + /// + /// A timeout after which a query is removed from the Redis cache. + /// + public static IRequestExecutorBuilder AddRedisQueryStorage( + this IRequestExecutorBuilder builder, + Func multiplexerFactory, + TimeSpan? queryExpiration = null) + { + if (builder is null) { - if (builder is null) - { - throw new ArgumentNullException(nameof(builder)); - } + throw new ArgumentNullException(nameof(builder)); + } - return builder.AddRedisQueryStorage( - sp => sp.GetRequiredService()); + if (multiplexerFactory is null) + { + throw new ArgumentNullException(nameof(multiplexerFactory)); } - /// - /// Adds a redis read-only query storage to the services collection. - /// - /// - /// The service collection to which the services are added. - /// - /// - /// A factory that resolves the redis database that - /// shall be used for persistence. - /// - public static IRequestExecutorBuilder AddReadOnlyRedisQueryStorage( - this IRequestExecutorBuilder builder, - Func databaseFactory) + return builder.ConfigureSchemaServices( + s => s.AddRedisQueryStorage( + sp => multiplexerFactory(sp.GetCombinedServices()).GetDatabase(), + queryExpiration)); + } + + /// + /// Adds a redis read and write query storage to the + /// services collection and uses the first + /// registered on the application services. + /// + /// + /// The service collection to which the services are added. + /// + /// + /// A timeout after which a query is removed from the Redis cache. + /// + public static IRequestExecutorBuilder AddRedisQueryStorage( + this IRequestExecutorBuilder builder, + TimeSpan? queryExpiration = null) + { + if (builder is null) { - if (builder is null) - { - throw new ArgumentNullException(nameof(builder)); - } - - if (databaseFactory is null) - { - throw new ArgumentNullException(nameof(databaseFactory)); - } - - return builder.ConfigureSchemaServices( - s => s.AddReadOnlyRedisQueryStorage( - sp => databaseFactory(sp.GetCombinedServices()))); + throw new ArgumentNullException(nameof(builder)); } - /// - /// Adds a redis read-only query storage to the services collection. - /// - /// - /// The service collection to which the services are added. - /// - /// - /// A factory that resolves the redis connection multiplexer. - /// - public static IRequestExecutorBuilder AddReadOnlyRedisQueryStorage( - this IRequestExecutorBuilder builder, - Func multiplexerFactory) + return builder.AddRedisQueryStorage( + sp => sp.GetRequiredService(), + queryExpiration); + } + + /// + /// Adds a redis read-only query storage to the services collection. + /// + /// + /// The service collection to which the services are added. + /// + /// + /// A factory that resolves the redis database that + /// shall be used for persistence. + /// + public static IRequestExecutorBuilder AddReadOnlyRedisQueryStorage( + this IRequestExecutorBuilder builder, + Func databaseFactory) + { + if (builder is null) { - if (builder is null) - { - throw new ArgumentNullException(nameof(builder)); - } - - if (multiplexerFactory is null) - { - throw new ArgumentNullException(nameof(multiplexerFactory)); - } - - return builder.ConfigureSchemaServices( - s => s.AddReadOnlyRedisQueryStorage( - sp => multiplexerFactory(sp.GetCombinedServices()).GetDatabase())); + throw new ArgumentNullException(nameof(builder)); } - /// - /// Adds a redis read-only query storage to the services collection - /// and uses the first - /// registered on the application services. - /// - /// - /// The service collection to which the services are added. - /// - /// - /// A factory that resolves the redis connection multiplexer. - /// - public static IRequestExecutorBuilder AddReadOnlyRedisQueryStorage( - this IRequestExecutorBuilder builder) + if (databaseFactory is null) { - if (builder is null) - { - throw new ArgumentNullException(nameof(builder)); - } + throw new ArgumentNullException(nameof(databaseFactory)); + } - return builder.AddReadOnlyRedisQueryStorage( - sp => sp.GetRequiredService()); + return builder.ConfigureSchemaServices( + s => s.AddReadOnlyRedisQueryStorage( + sp => databaseFactory(sp.GetCombinedServices()))); + } + + /// + /// Adds a redis read-only query storage to the services collection. + /// + /// + /// The service collection to which the services are added. + /// + /// + /// A factory that resolves the redis connection multiplexer. + /// + public static IRequestExecutorBuilder AddReadOnlyRedisQueryStorage( + this IRequestExecutorBuilder builder, + Func multiplexerFactory) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + if (multiplexerFactory is null) + { + throw new ArgumentNullException(nameof(multiplexerFactory)); } + + return builder.ConfigureSchemaServices( + s => s.AddReadOnlyRedisQueryStorage( + sp => multiplexerFactory(sp.GetCombinedServices()).GetDatabase())); + } + + /// + /// Adds a redis read-only query storage to the services collection + /// and uses the first + /// registered on the application services. + /// + /// + /// The service collection to which the services are added. + /// + public static IRequestExecutorBuilder AddReadOnlyRedisQueryStorage( + this IRequestExecutorBuilder builder) + { + if (builder is null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return builder.AddReadOnlyRedisQueryStorage( + sp => sp.GetRequiredService()); } } diff --git a/src/HotChocolate/PersistedQueries/src/PersistedQueries.Redis/Extensions/HotChocolateRedisPersistedQueriesServiceCollectionExtensions.cs b/src/HotChocolate/PersistedQueries/src/PersistedQueries.Redis/Extensions/HotChocolateRedisPersistedQueriesServiceCollectionExtensions.cs index 4fbffdb8375..9701c8bf298 100644 --- a/src/HotChocolate/PersistedQueries/src/PersistedQueries.Redis/Extensions/HotChocolateRedisPersistedQueriesServiceCollectionExtensions.cs +++ b/src/HotChocolate/PersistedQueries/src/PersistedQueries.Redis/Extensions/HotChocolateRedisPersistedQueriesServiceCollectionExtensions.cs @@ -1,90 +1,96 @@ using System; using System.Linq; -using Microsoft.Extensions.DependencyInjection; -using StackExchange.Redis; using HotChocolate.Execution; using HotChocolate.PersistedQueries.Redis; +using Microsoft.Extensions.DependencyInjection; +using StackExchange.Redis; + +namespace HotChocolate; -namespace HotChocolate +/// +/// Provides utility methods to setup dependency injection. +/// +public static class HotChocolateRedisPersistedQueriesServiceCollectionExtensions { /// - /// Provides utility methods to setup dependency injection. + /// Adds a redis read and write query storage to the + /// services collection. /// - public static class HotChocolateRedisPersistedQueriesServiceCollectionExtensions + /// + /// The service collection to which the services are added. + /// + /// + /// A factory that resolves the redis database that + /// shall be used for persistence. + /// + /// + /// A timeout after which a query is removed from the Redis cache. + /// + public static IServiceCollection AddRedisQueryStorage( + this IServiceCollection services, + Func databaseFactory, + TimeSpan? queryExpiration = null) { - /// - /// Adds a redis read and write query storage to the - /// services collection. - /// - /// - /// The service collection to which the services are added. - /// - /// - /// A factory that resolves the redis database that - /// shall be used for persistence. - /// - public static IServiceCollection AddRedisQueryStorage( - this IServiceCollection services, - Func databaseFactory) + if (services is null) { - if (services is null) - { - throw new ArgumentNullException(nameof(services)); - } - - if (databaseFactory is null) - { - throw new ArgumentNullException(nameof(databaseFactory)); - } - - return services - .AddReadOnlyRedisQueryStorage(databaseFactory) - .AddSingleton(sp => sp.GetRequiredService()); + throw new ArgumentNullException(nameof(services)); } - /// - /// Adds a redis read-only query storage to the services collection. - /// - /// - /// The service collection to which the services are added. - /// - /// - /// A factory that resolves the redis database that - /// shall be used for persistence. - /// - public static IServiceCollection AddReadOnlyRedisQueryStorage( - this IServiceCollection services, - Func databaseFactory) + if (databaseFactory is null) { - if (services is null) - { - throw new ArgumentNullException(nameof(services)); - } + throw new ArgumentNullException(nameof(databaseFactory)); + } - if (databaseFactory is null) - { - throw new ArgumentNullException(nameof(databaseFactory)); - } + return services + .RemoveService() + .RemoveService() + .AddSingleton(sp => new RedisQueryStorage(databaseFactory(sp), queryExpiration)) + .AddSingleton(sp => sp.GetRequiredService()) + .AddSingleton(sp => sp.GetRequiredService()); + } - return services - .RemoveService() - .RemoveService() - .AddSingleton(sp => new RedisQueryStorage(databaseFactory(sp))) - .AddSingleton(sp => sp.GetRequiredService()); + /// + /// Adds a redis read-only query storage to the services collection. + /// + /// + /// The service collection to which the services are added. + /// + /// + /// A factory that resolves the redis database that + /// shall be used for persistence. + /// + public static IServiceCollection AddReadOnlyRedisQueryStorage( + this IServiceCollection services, + Func databaseFactory) + { + if (services is null) + { + throw new ArgumentNullException(nameof(services)); } - private static IServiceCollection RemoveService( - this IServiceCollection services) + if (databaseFactory is null) { - ServiceDescriptor? serviceDescriptor = services - .FirstOrDefault(t => t.ServiceType == typeof(TService)); + throw new ArgumentNullException(nameof(databaseFactory)); + } - if (serviceDescriptor != null) - { - services.Remove(serviceDescriptor); - } + return services + .RemoveService() + .RemoveService() + .AddSingleton(sp => new RedisQueryStorage(databaseFactory(sp))) + .AddSingleton(sp => sp.GetRequiredService()); + } - return services; + private static IServiceCollection RemoveService( + this IServiceCollection services) + { + ServiceDescriptor? serviceDescriptor = services + .FirstOrDefault(t => t.ServiceType == typeof(TService)); + + if (serviceDescriptor != null) + { + services.Remove(serviceDescriptor); } + + return services; } } diff --git a/src/HotChocolate/PersistedQueries/src/PersistedQueries.Redis/RedisQueryStorage.cs b/src/HotChocolate/PersistedQueries/src/PersistedQueries.Redis/RedisQueryStorage.cs index 1220781266f..bfbf35c29d8 100644 --- a/src/HotChocolate/PersistedQueries/src/PersistedQueries.Redis/RedisQueryStorage.cs +++ b/src/HotChocolate/PersistedQueries/src/PersistedQueries.Redis/RedisQueryStorage.cs @@ -5,66 +5,71 @@ using HotChocolate.Language; using StackExchange.Redis; -namespace HotChocolate.PersistedQueries.Redis +namespace HotChocolate.PersistedQueries.Redis; + +/// +/// An implementation of +/// and that +/// uses a redis database. +/// +public class RedisQueryStorage + : IReadStoredQueries + , IWriteStoredQueries { + private readonly IDatabase _database; + private readonly TimeSpan? _queryExpiration; + /// - /// An implementation of - /// and that - /// uses a redis database. + /// Initializes a new instance of the class. /// - public class RedisQueryStorage - : IReadStoredQueries - , IWriteStoredQueries + /// The redis database instance. + /// + /// A timespan after that a query will be removed from the cache. + /// + public RedisQueryStorage(IDatabase database, TimeSpan? queryExpiration = null) { - private readonly IDatabase _database; + _database = database ?? throw new ArgumentNullException(nameof(database)); + _queryExpiration = queryExpiration; + } - /// - /// Initializes a new instance of the class. - /// - /// The redis database instance. - public RedisQueryStorage(IDatabase database) + /// + public Task TryReadQueryAsync( + string queryId, + CancellationToken cancellationToken = default) + { + if (string.IsNullOrWhiteSpace(queryId)) { - _database = database - ?? throw new ArgumentNullException(nameof(database)); + throw new ArgumentNullException(nameof(queryId)); } - /// - public Task TryReadQueryAsync( - string queryId, - CancellationToken cancellationToken = default) - { - if (string.IsNullOrWhiteSpace(queryId)) - { - throw new ArgumentNullException(nameof(queryId)); - } + return TryReadQueryInternalAsync(queryId); + } - return TryReadQueryInternalAsync(queryId); - } + private async Task TryReadQueryInternalAsync( + string queryId) + { + var buffer = (byte[]?)await _database.StringGetAsync(queryId).ConfigureAwait(false); + return buffer is null ? null : new QueryDocument(Utf8GraphQLParser.Parse(buffer)); + } - private async Task TryReadQueryInternalAsync( - string queryId) + /// + public Task WriteQueryAsync( + string queryId, + IQuery query, + CancellationToken cancellationToken = default) + { + if (string.IsNullOrWhiteSpace(queryId)) { - var buffer = (byte[]?)await _database.StringGetAsync(queryId).ConfigureAwait(false); - return buffer is null ? null : new QueryDocument(Utf8GraphQLParser.Parse(buffer)); + throw new ArgumentNullException(nameof(queryId)); } - /// - public Task WriteQueryAsync( - string queryId, - IQuery query, - CancellationToken cancellationToken = default) + if (query is null) { - if (string.IsNullOrWhiteSpace(queryId)) - { - throw new ArgumentNullException(nameof(queryId)); - } - - if (query is null) - { - throw new ArgumentNullException(nameof(query)); - } - - return _database.StringSetAsync(queryId, query.AsSpan().ToArray()); + throw new ArgumentNullException(nameof(query)); } + + return _queryExpiration.HasValue + ? _database.StringSetAsync(queryId, query.AsSpan().ToArray(), _queryExpiration.Value) + : _database.StringSetAsync(queryId, query.AsSpan().ToArray()); } } diff --git a/src/HotChocolate/PersistedQueries/test/PersistedQueries.Redis.Tests/IntegrationTests.cs b/src/HotChocolate/PersistedQueries/test/PersistedQueries.Redis.Tests/IntegrationTests.cs index 35cc5c72bf9..f4cb50edf65 100644 --- a/src/HotChocolate/PersistedQueries/test/PersistedQueries.Redis.Tests/IntegrationTests.cs +++ b/src/HotChocolate/PersistedQueries/test/PersistedQueries.Redis.Tests/IntegrationTests.cs @@ -1,174 +1,256 @@ using System; using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; -using HotChocolate.Types; using HotChocolate.Execution; +using HotChocolate.Types; +using Microsoft.Extensions.DependencyInjection; using Snapshooter.Xunit; using Squadron; using StackExchange.Redis; using Xunit; -namespace HotChocolate.PersistedQueries.Redis +namespace HotChocolate.PersistedQueries.Redis; + +public class IntegrationTests : IClassFixture { - public class IntegrationTests : IClassFixture + private readonly IConnectionMultiplexer _multiplexer; + private readonly IDatabase _database; + + public IntegrationTests(RedisResource redisResource) + { + _multiplexer = redisResource.GetConnection(); + _database = _multiplexer.GetDatabase(); + } + + [Fact] + public async Task ExecutePersistedQuery() { - private readonly IConnectionMultiplexer _multiplexer; - private readonly IDatabase _database; - - public IntegrationTests(RedisResource redisResource) - { - _multiplexer = redisResource.GetConnection(); - _database = _multiplexer.GetDatabase(); - } - - [Fact] - public async Task ExecutePersistedQuery() - { - // arrange - var queryId = Guid.NewGuid().ToString("N"); - var storage = new RedisQueryStorage(_database); - await storage.WriteQueryAsync(queryId, new QuerySourceText("{ __typename }")); - - IRequestExecutor executor = - await new ServiceCollection() - .AddGraphQL() - .AddQueryType(c => c.Name("Query").Field("a").Resolve("b")) - .AddRedisQueryStorage(s => _database) - .UseRequest(n => async c => + // arrange + var queryId = Guid.NewGuid().ToString("N"); + var storage = new RedisQueryStorage(_database); + await storage.WriteQueryAsync(queryId, new QuerySourceText("{ __typename }")); + + IRequestExecutor executor = + await new ServiceCollection() + .AddGraphQL() + .AddQueryType(c => c.Name("Query").Field("a").Resolve("b")) + .AddRedisQueryStorage(_ => _database) + .UseRequest(n => async c => + { + await n(c); + + if (c.IsPersistedDocument && c.Result is IQueryResult r) { - await n(c); - - if (c.IsPersistedDocument && c.Result is IQueryResult r) - { - c.Result = QueryResultBuilder - .FromResult(r) - .SetExtension("persistedDocument", true) - .Create(); - } - }) - .UsePersistedQueryPipeline() - .BuildRequestExecutorAsync(); - - // act - IExecutionResult result = - await executor.ExecuteAsync(new QueryRequest(queryId: queryId)); - - // assert - result.MatchSnapshot(); - } - - [Fact] - public async Task ExecutePersistedQuery_ApplicationDI() - { - // arrange - var queryId = Guid.NewGuid().ToString("N"); - var storage = new RedisQueryStorage(_database); - await storage.WriteQueryAsync(queryId, new QuerySourceText("{ __typename }")); - - IRequestExecutor executor = - await new ServiceCollection() - // we register the multiplexer on the application services - .AddSingleton(_multiplexer) - .AddGraphQL() - .AddQueryType(c => c.Name("Query").Field("a").Resolve("b")) - // and in the redis storage setup refer to that instance. - .AddRedisQueryStorage(sp => sp.GetRequiredService()) - .UseRequest(n => async c => + c.Result = QueryResultBuilder + .FromResult(r) + .SetExtension("persistedDocument", true) + .Create(); + } + }) + .UsePersistedQueryPipeline() + .BuildRequestExecutorAsync(); + + // act + IExecutionResult result = await executor.ExecuteAsync(new QueryRequest(queryId: queryId)); + + // assert + result.MatchSnapshot(); + } + + [Fact] + public async Task ExecutePersistedQuery_After_Expiration() + { + // arrange + var queryId = Guid.NewGuid().ToString("N"); + + IRequestExecutor executor = + await new ServiceCollection() + .AddGraphQL() + .AddQueryType(c => c.Name("Query").Field("a").Resolve("b")) + .AddRedisQueryStorage(_ => _database, TimeSpan.FromMilliseconds(10)) + .UseRequest(n => async c => + { + await n(c); + + if (c.IsPersistedDocument && c.Result is IQueryResult r) { - await n(c); - - if (c.IsPersistedDocument && c.Result is IQueryResult r) - { - c.Result = QueryResultBuilder - .FromResult(r) - .SetExtension("persistedDocument", true) - .Create(); - } - }) - .UsePersistedQueryPipeline() - .BuildRequestExecutorAsync(); - - // act - IExecutionResult result = - await executor.ExecuteAsync(new QueryRequest(queryId: queryId)); - - // assert - result.MatchSnapshot(); - } - - [Fact] - public async Task ExecutePersistedQuery_ApplicationDI_Default() - { - // arrange - var queryId = Guid.NewGuid().ToString("N"); - var storage = new RedisQueryStorage(_database); - await storage.WriteQueryAsync(queryId, new QuerySourceText("{ __typename }")); - - IRequestExecutor executor = - await new ServiceCollection() - // we register the multiplexer on the application services - .AddSingleton(_multiplexer) - .AddGraphQL() - .AddQueryType(c => c.Name("Query").Field("a").Resolve("b")) - // and in the redis storage setup refer to that instance. - .AddRedisQueryStorage() - .UseRequest(n => async c => + c.Result = QueryResultBuilder + .FromResult(r) + .SetExtension("persistedDocument", true) + .Create(); + } + }) + .UsePersistedQueryPipeline() + .BuildRequestExecutorAsync(); + + // ... write query to cache + IWriteStoredQueries cache = executor.Services.GetRequiredService(); + await cache.WriteQueryAsync(queryId, new QuerySourceText("{ __typename }")); + + // ... wait for query to expire + await Task.Delay(100).ConfigureAwait(false); + + // act + IExecutionResult result = await executor.ExecuteAsync(new QueryRequest(queryId: queryId)); + + // assert + Assert.Collection( + result.ExpectQueryResult().Errors!, + error => + { + Assert.Equal("The query request contains no document.", error.Message); + Assert.Equal("HC0015", error.Code); + }); + result.MatchSnapshot(); + } + + [Fact] + public async Task ExecutePersistedQuery_Before_Expiration() + { + // arrange + var queryId = Guid.NewGuid().ToString("N"); + var storage = new RedisQueryStorage(_database, TimeSpan.FromMilliseconds(10000)); + await storage.WriteQueryAsync(queryId, new QuerySourceText("{ __typename }")); + + IRequestExecutor executor = + await new ServiceCollection() + .AddGraphQL() + .AddQueryType(c => c.Name("Query").Field("a").Resolve("b")) + .AddRedisQueryStorage(s => _database) + .UseRequest(n => async c => + { + await n(c); + + if (c.IsPersistedDocument && c.Result is IQueryResult r) { - await n(c); - - if (c.IsPersistedDocument && c.Result is IQueryResult r) - { - c.Result = QueryResultBuilder - .FromResult(r) - .SetExtension("persistedDocument", true) - .Create(); - } - }) - .UsePersistedQueryPipeline() - .BuildRequestExecutorAsync(); - - // act - IExecutionResult result = - await executor.ExecuteAsync(new QueryRequest(queryId: queryId)); - - // assert - result.MatchSnapshot(); - } - - [Fact] - public async Task ExecutePersistedQuery_NotFound() - { - // arrange - var queryId = Guid.NewGuid().ToString("N"); - var storage = new RedisQueryStorage(_database); - await storage.WriteQueryAsync(queryId, new QuerySourceText("{ __typename }")); - - IRequestExecutor executor = - await new ServiceCollection() - .AddGraphQL() - .AddQueryType(c => c.Name("Query").Field("a").Resolve("b")) - .AddRedisQueryStorage(s => _database) - .UseRequest(n => async c => + c.Result = QueryResultBuilder + .FromResult(r) + .SetExtension("persistedDocument", true) + .Create(); + } + }) + .UsePersistedQueryPipeline() + .BuildRequestExecutorAsync(); + + // act + IExecutionResult result = await executor.ExecuteAsync(new QueryRequest(queryId: queryId)); + + // assert + Assert.Null(result.ExpectQueryResult().Errors); + result.MatchSnapshot(); + + } + + [Fact] + public async Task ExecutePersistedQuery_ApplicationDI() + { + // arrange + var queryId = Guid.NewGuid().ToString("N"); + var storage = new RedisQueryStorage(_database); + await storage.WriteQueryAsync(queryId, new QuerySourceText("{ __typename }")); + + IRequestExecutor executor = + await new ServiceCollection() + // we register the multiplexer on the application services + .AddSingleton(_multiplexer) + .AddGraphQL() + .AddQueryType(c => c.Name("Query").Field("a").Resolve("b")) + // and in the redis storage setup refer to that instance. + .AddRedisQueryStorage(sp => sp.GetRequiredService()) + .UseRequest(n => async c => + { + await n(c); + + if (c.IsPersistedDocument && c.Result is IQueryResult r) + { + c.Result = QueryResultBuilder + .FromResult(r) + .SetExtension("persistedDocument", true) + .Create(); + } + }) + .UsePersistedQueryPipeline() + .BuildRequestExecutorAsync(); + + // act + IExecutionResult result = + await executor.ExecuteAsync(new QueryRequest(queryId: queryId)); + + // assert + result.MatchSnapshot(); + } + + [Fact] + public async Task ExecutePersistedQuery_ApplicationDI_Default() + { + // arrange + var queryId = Guid.NewGuid().ToString("N"); + var storage = new RedisQueryStorage(_database); + await storage.WriteQueryAsync(queryId, new QuerySourceText("{ __typename }")); + + IRequestExecutor executor = + await new ServiceCollection() + // we register the multiplexer on the application services + .AddSingleton(_multiplexer) + .AddGraphQL() + .AddQueryType(c => c.Name("Query").Field("a").Resolve("b")) + // and in the redis storage setup refer to that instance. + .AddRedisQueryStorage() + .UseRequest(n => async c => + { + await n(c); + + if (c.IsPersistedDocument && c.Result is IQueryResult r) { - await n(c); - - if (c.IsPersistedDocument && c.Result is IQueryResult r) - { - c.Result = QueryResultBuilder - .FromResult(r) - .SetExtension("persistedDocument", true) - .Create(); - } - }) - .UsePersistedQueryPipeline() - .BuildRequestExecutorAsync(); - - // act - IExecutionResult result = - await executor.ExecuteAsync(new QueryRequest(queryId: "does_not_exist")); - - // assert - result.MatchSnapshot(); - } + c.Result = QueryResultBuilder + .FromResult(r) + .SetExtension("persistedDocument", true) + .Create(); + } + }) + .UsePersistedQueryPipeline() + .BuildRequestExecutorAsync(); + + // act + IExecutionResult result = + await executor.ExecuteAsync(new QueryRequest(queryId: queryId)); + + // assert + result.MatchSnapshot(); + } + + [Fact] + public async Task ExecutePersistedQuery_NotFound() + { + // arrange + var queryId = Guid.NewGuid().ToString("N"); + var storage = new RedisQueryStorage(_database); + await storage.WriteQueryAsync(queryId, new QuerySourceText("{ __typename }")); + + IRequestExecutor executor = + await new ServiceCollection() + .AddGraphQL() + .AddQueryType(c => c.Name("Query").Field("a").Resolve("b")) + .AddRedisQueryStorage(s => _database) + .UseRequest(n => async c => + { + await n(c); + + if (c.IsPersistedDocument && c.Result is IQueryResult r) + { + c.Result = QueryResultBuilder + .FromResult(r) + .SetExtension("persistedDocument", true) + .Create(); + } + }) + .UsePersistedQueryPipeline() + .BuildRequestExecutorAsync(); + + // act + IExecutionResult result = + await executor.ExecuteAsync(new QueryRequest(queryId: "does_not_exist")); + + // assert + result.MatchSnapshot(); } } diff --git a/src/HotChocolate/PersistedQueries/test/PersistedQueries.Redis.Tests/RedisQueryStorageTests.cs b/src/HotChocolate/PersistedQueries/test/PersistedQueries.Redis.Tests/RedisQueryStorageTests.cs index be716ce5e05..5dc510422b2 100644 --- a/src/HotChocolate/PersistedQueries/test/PersistedQueries.Redis.Tests/RedisQueryStorageTests.cs +++ b/src/HotChocolate/PersistedQueries/test/PersistedQueries.Redis.Tests/RedisQueryStorageTests.cs @@ -10,25 +10,25 @@ using StackExchange.Redis; using Xunit; -namespace HotChocolate.PersistedQueries.Redis +namespace HotChocolate.PersistedQueries.Redis; + +public class RedisQueryStorageTests + : IClassFixture { - public class RedisQueryStorageTests - : IClassFixture - { - private readonly IDatabase _database; + private readonly IDatabase _database; - public RedisQueryStorageTests(RedisResource redisResource) - { - _database = redisResource.GetConnection().GetDatabase(); - } + public RedisQueryStorageTests(RedisResource redisResource) + { + _database = redisResource.GetConnection().GetDatabase(); + } - [Fact] - public Task Write_Query_To_Storage() - { - SnapshotFullName snapshotName = Snapshot.FullName(); - var queryId = Guid.NewGuid().ToString("N"); + [Fact] + public Task Write_Query_To_Storage() + { + SnapshotFullName snapshotName = Snapshot.FullName(); + var queryId = Guid.NewGuid().ToString("N"); - return TryTest(async () => + return TryTest(async () => { // arrange var storage = new RedisQueryStorage(_database); @@ -42,49 +42,49 @@ public Task Write_Query_To_Storage() Utf8GraphQLParser.Parse(buffer).Print().MatchSnapshot(snapshotName); }, () => _database.KeyDeleteAsync(queryId)); - } + } - [InlineData(null)] - [InlineData("")] - [Theory] - public Task Write_Query_QueryId_Invalid(string queryId) + [InlineData(null)] + [InlineData("")] + [Theory] + public Task Write_Query_QueryId_Invalid(string queryId) + { + return TryTest(async () => { - return TryTest(async () => - { - var storage = new RedisQueryStorage(_database); - var query = new QuerySourceText("{ foo }"); + var storage = new RedisQueryStorage(_database); + var query = new QuerySourceText("{ foo }"); - // act - Task Action() => storage.WriteQueryAsync(queryId, query); + // act + Task Action() => storage.WriteQueryAsync(queryId, query); - // assert - await Assert.ThrowsAsync(Action); - }); - } + // assert + await Assert.ThrowsAsync(Action); + }); + } - [Fact] - public Task Write_Query_Query_Is_Null() + [Fact] + public Task Write_Query_Query_Is_Null() + { + return TryTest(async () => { - return TryTest(async () => - { - var storage = new RedisQueryStorage(_database); - var queryId = Guid.NewGuid().ToString("N"); + var storage = new RedisQueryStorage(_database); + var queryId = Guid.NewGuid().ToString("N"); - // act - Task Action() => storage.WriteQueryAsync(queryId, null!); + // act + Task Action() => storage.WriteQueryAsync(queryId, null!); - // assert - await Assert.ThrowsAsync(Action); - }); - } + // assert + await Assert.ThrowsAsync(Action); + }); + } - [Fact] - public Task Read_Query_From_Storage() - { - SnapshotFullName snapshotName = Snapshot.FullName(); - var queryId = Guid.NewGuid().ToString("N"); + [Fact] + public Task Read_Query_From_Storage() + { + SnapshotFullName snapshotName = Snapshot.FullName(); + var queryId = Guid.NewGuid().ToString("N"); - return TryTest(async () => + return TryTest(async () => { // arrange var storage = new RedisQueryStorage(_database); @@ -99,74 +99,73 @@ public Task Read_Query_From_Storage() query.Document.Print().MatchSnapshot(snapshotName); }, () => _database.KeyDeleteAsync(queryId)); - } + } - [InlineData(null)] - [InlineData("")] - [Theory] - public Task Read_Query_QueryId_Invalid(string queryId) + [InlineData(null)] + [InlineData("")] + [Theory] + public Task Read_Query_QueryId_Invalid(string queryId) + { + return TryTest(async () => { - return TryTest(async () => - { - var storage = new RedisQueryStorage(_database); + var storage = new RedisQueryStorage(_database); - // act - Task Action() => storage.TryReadQueryAsync(queryId); + // act + Task Action() => storage.TryReadQueryAsync(queryId); - // assert - await Assert.ThrowsAsync(Action); - }); - } + // assert + await Assert.ThrowsAsync(Action); + }); + } - private static async Task TryTest( - Func action, - Func cleanup = null) - { - // we will try four times .... - var count = 0; - var wait = 50; + private static async Task TryTest( + Func action, + Func cleanup = null) + { + // we will try four times .... + var count = 0; + var wait = 50; - while (true) + while (true) + { + try { - try + if (count < 3) { - if (count < 3) - { - try - { - await action().ConfigureAwait(false); - break; - } - catch - { - // try again - } - } - else + try { await action().ConfigureAwait(false); break; } - } - finally - { - try + catch { - if (cleanup != null) - { - await cleanup().ConfigureAwait(false); - } + // try again } - catch + } + else + { + await action().ConfigureAwait(false); + break; + } + } + finally + { + try + { + if (cleanup != null) { - // ignore cleanup errors + await cleanup().ConfigureAwait(false); } } - - await Task.Delay(wait).ConfigureAwait(false); - wait *= 2; - count++; + catch + { + // ignore cleanup errors + } } + + await Task.Delay(wait).ConfigureAwait(false); + wait *= 2; + count++; } } -} +} \ No newline at end of file diff --git a/src/HotChocolate/PersistedQueries/test/PersistedQueries.Redis.Tests/RequestExecutorBuilderTests.cs b/src/HotChocolate/PersistedQueries/test/PersistedQueries.Redis.Tests/RequestExecutorBuilderTests.cs index 3bb29e1db76..8c2d4736e7a 100644 --- a/src/HotChocolate/PersistedQueries/test/PersistedQueries.Redis.Tests/RequestExecutorBuilderTests.cs +++ b/src/HotChocolate/PersistedQueries/test/PersistedQueries.Redis.Tests/RequestExecutorBuilderTests.cs @@ -5,161 +5,160 @@ using StackExchange.Redis; using Xunit; -namespace HotChocolate.PersistedQueries.Redis +namespace HotChocolate.PersistedQueries.Redis; + +public class RequestExecutorBuilderTests : IClassFixture { - public class RequestExecutorBuilderTests : IClassFixture + private readonly IConnectionMultiplexer _multiplexer; + private readonly IDatabase _database; + + public RequestExecutorBuilderTests(RedisResource redisResource) + { + _multiplexer = redisResource.GetConnection(); + _database = _multiplexer.GetDatabase(); + } + + [Fact] + public void AddRedisQueryStorage_Services_Is_Null() + { + // arrange + // act + void Action() => + HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions + .AddRedisQueryStorage(null!, _ => _database); + + // assert + Assert.Throws(Action); + } + + [Fact] + public void AddRedisQueryStorage_MultiplexerServices_Is_Null() + { + // arrange + // act + void Action() => + HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions + .AddRedisQueryStorage(null!, _ => _multiplexer); + + // assert + Assert.Throws(Action); + } + + [Fact] + public void AddRedisQueryStorage_DefaultServices_Is_Null() + { + // arrange + // act + void Action() => + HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions + .AddRedisQueryStorage(null!); + + // assert + Assert.Throws(Action); + } + + [Fact] + public void AddRedisQueryStorage_Factory_Is_Null() + { + // arrange + IRequestExecutorBuilder builder = new ServiceCollection().AddGraphQL(); + + // act + void Action() => + HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions + .AddRedisQueryStorage(builder, default(Func)!); + + // assert + Assert.Throws(Action); + } + + [Fact] + public void AddRedisQueryStorage_MultiplexerFactory_Is_Null() + { + // arrange + IRequestExecutorBuilder builder = new ServiceCollection().AddGraphQL(); + + // act + void Action() => + HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions + .AddRedisQueryStorage( + builder, + default(Func)!); + + // assert + Assert.Throws(Action); + } + + [Fact] + public void AddReadOnlyRedisQueryStorage_Services_Is_Null() + { + // arrange + // act + void Action() => + HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions + .AddReadOnlyRedisQueryStorage(null!, _ => _database); + + // assert + Assert.Throws(Action); + } + + [Fact] + public void AddReadOnlyRedisQueryStorage_MultiplexerServices_Is_Null() + { + // arrange + // act + void Action() => + HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions + .AddReadOnlyRedisQueryStorage(null!, _ => _multiplexer); + + // assert + Assert.Throws(Action); + } + + [Fact] + public void AddReadOnlyRedisQueryStorage_DefaultServices_Is_Null() + { + // arrange + // act + void Action() => + HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions + .AddReadOnlyRedisQueryStorage(null!); + + // assert + Assert.Throws(Action); + } + + [Fact] + public void AddReadOnlyRedisQueryStorage_Factory_Is_Null() + { + // arrange + IRequestExecutorBuilder builder = new ServiceCollection().AddGraphQL(); + + // act + void Action() => + HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions + .AddReadOnlyRedisQueryStorage( + builder, + default(Func)!); + + // assert + Assert.Throws(Action); + } + + [Fact] + public void AddReadOnlyRedisQueryStorage_MultiplexerFactory_Is_Null() { - private readonly IConnectionMultiplexer _multiplexer; - private readonly IDatabase _database; - - public RequestExecutorBuilderTests(RedisResource redisResource) - { - _multiplexer = redisResource.GetConnection(); - _database = _multiplexer.GetDatabase(); - } - - [Fact] - public void AddRedisQueryStorage_Services_Is_Null() - { - // arrange - // act - void Action() => - HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions - .AddRedisQueryStorage(null!, _ => _database); - - // assert - Assert.Throws(Action); - } - - [Fact] - public void AddRedisQueryStorage_MultiplexerServices_Is_Null() - { - // arrange - // act - void Action() => - HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions - .AddRedisQueryStorage(null!, _ => _multiplexer); - - // assert - Assert.Throws(Action); - } - - [Fact] - public void AddRedisQueryStorage_DefaultServices_Is_Null() - { - // arrange - // act - void Action() => - HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions - .AddRedisQueryStorage(null!); - - // assert - Assert.Throws(Action); - } - - [Fact] - public void AddRedisQueryStorage_Factory_Is_Null() - { - // arrange - IRequestExecutorBuilder builder = new ServiceCollection().AddGraphQL(); - - // act - void Action() => - HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions - .AddRedisQueryStorage(builder, default(Func)!); - - // assert - Assert.Throws(Action); - } - - [Fact] - public void AddRedisQueryStorage_MultiplexerFactory_Is_Null() - { - // arrange - IRequestExecutorBuilder builder = new ServiceCollection().AddGraphQL(); - - // act - void Action() => - HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions - .AddRedisQueryStorage( - builder, - default(Func)!); - - // assert - Assert.Throws(Action); - } - - [Fact] - public void AddReadOnlyRedisQueryStorage_Services_Is_Null() - { - // arrange - // act - void Action() => - HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions - .AddReadOnlyRedisQueryStorage(null!, _ => _database); - - // assert - Assert.Throws(Action); - } - - [Fact] - public void AddReadOnlyRedisQueryStorage_MultiplexerServices_Is_Null() - { - // arrange - // act - void Action() => - HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions - .AddReadOnlyRedisQueryStorage(null!, _ => _multiplexer); - - // assert - Assert.Throws(Action); - } - - [Fact] - public void AddReadOnlyRedisQueryStorage_DefaultServices_Is_Null() - { - // arrange - // act - void Action() => - HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions - .AddReadOnlyRedisQueryStorage(null!); - - // assert - Assert.Throws(Action); - } - - [Fact] - public void AddReadOnlyRedisQueryStorage_Factory_Is_Null() - { - // arrange - IRequestExecutorBuilder builder = new ServiceCollection().AddGraphQL(); - - // act - void Action() => - HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions - .AddReadOnlyRedisQueryStorage( - builder, - default(Func)!); - - // assert - Assert.Throws(Action); - } - - [Fact] - public void AddReadOnlyRedisQueryStorage_MultiplexerFactory_Is_Null() - { - // arrange - IRequestExecutorBuilder builder = new ServiceCollection().AddGraphQL(); - - // act - void Action() => - HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions - .AddReadOnlyRedisQueryStorage( - builder, - default(Func)!); - - // assert - Assert.Throws(Action); - } + // arrange + IRequestExecutorBuilder builder = new ServiceCollection().AddGraphQL(); + + // act + void Action() => + HotChocolateRedisPersistedQueriesRequestExecutorBuilderExtensions + .AddReadOnlyRedisQueryStorage( + builder, + default(Func)!); + + // assert + Assert.Throws(Action); } -} +} \ No newline at end of file diff --git a/src/HotChocolate/PersistedQueries/test/PersistedQueries.Redis.Tests/ServiceCollectionExtensionsTests.cs b/src/HotChocolate/PersistedQueries/test/PersistedQueries.Redis.Tests/ServiceCollectionExtensionsTests.cs index f24a56632cf..095409f8917 100644 --- a/src/HotChocolate/PersistedQueries/test/PersistedQueries.Redis.Tests/ServiceCollectionExtensionsTests.cs +++ b/src/HotChocolate/PersistedQueries/test/PersistedQueries.Redis.Tests/ServiceCollectionExtensionsTests.cs @@ -7,108 +7,107 @@ using StackExchange.Redis; using Xunit; -namespace HotChocolate.PersistedQueries.Redis +namespace HotChocolate.PersistedQueries.Redis; + +public class ServiceCollectionExtensionsTests + : IClassFixture { - public class ServiceCollectionExtensionsTests - : IClassFixture + private readonly IDatabase _database; + + public ServiceCollectionExtensionsTests(RedisResource redisResource) + { + _database = redisResource.GetConnection().GetDatabase(); + } + + [Fact] + public void AddRedisQueryStorage_Services_Is_Null() + { + // arrange + // act + void Action() + => HotChocolateRedisPersistedQueriesServiceCollectionExtensions + .AddRedisQueryStorage(null!, _ => _database); + + // assert + Assert.Throws(Action); + } + + [Fact] + public void AddRedisQueryStorage_Factory_Is_Null() { - private IDatabase _database; - - public ServiceCollectionExtensionsTests(RedisResource redisResource) - { - _database = redisResource.GetConnection().GetDatabase(); - } - - [Fact] - public void AddRedisQueryStorage_Services_Is_Null() - { - // arrange - // act - Action action = () => - HotChocolateRedisPersistedQueriesServiceCollectionExtensions - .AddRedisQueryStorage(null, sp => _database); - - // assert - Assert.Throws(action); - } - - [Fact] - public void AddRedisQueryStorage_Factory_Is_Null() - { - // arrange - var services = new ServiceCollection(); - - // act - Action action = () => - HotChocolateRedisPersistedQueriesServiceCollectionExtensions - .AddRedisQueryStorage(services, null); - - // assert - Assert.Throws(action); - } - - [Fact] - public void AddRedisQueryStorage_Services() - { - // arrange - var services = new ServiceCollection(); - - // act - HotChocolateRedisPersistedQueriesServiceCollectionExtensions - .AddRedisQueryStorage(services, sp => _database); - - // assert - services.ToDictionary( + // arrange + var services = new ServiceCollection(); + + // act + void Action() + => HotChocolateRedisPersistedQueriesServiceCollectionExtensions + .AddRedisQueryStorage(services, null!); + + // assert + Assert.Throws(Action); + } + + [Fact] + public void AddRedisQueryStorage_Services() + { + // arrange + var services = new ServiceCollection(); + + // act + HotChocolateRedisPersistedQueriesServiceCollectionExtensions + .AddRedisQueryStorage(services, _ => _database); + + // assert + services.ToDictionary( k => k.ServiceType.GetTypeName(), v => v.ImplementationType?.GetTypeName()) - .OrderBy(t => t.Key) - .MatchSnapshot(); - } - - [Fact] - public void AddReadOnlyRedisQueryStorage_Services_Is_Null() - { - // arrange - // act - Action action = () => - HotChocolateRedisPersistedQueriesServiceCollectionExtensions - .AddReadOnlyRedisQueryStorage(null, sp => _database); - - // assert - Assert.Throws(action); - } - - [Fact] - public void AddReadOnlyRedisQueryStorage_Factory_Is_Null() - { - // arrange - var services = new ServiceCollection(); - - // act - Action action = () => - HotChocolateRedisPersistedQueriesServiceCollectionExtensions - .AddReadOnlyRedisQueryStorage(services, null); - - // assert - Assert.Throws(action); - } - - [Fact] - public void AddReadOnlyRedisQueryStorage_Services() - { - // arrange - var services = new ServiceCollection(); - - // act - HotChocolateRedisPersistedQueriesServiceCollectionExtensions - .AddReadOnlyRedisQueryStorage(services, sp => _database); - - // assert - services.ToDictionary( + .OrderBy(t => t.Key) + .MatchSnapshot(); + } + + [Fact] + public void AddReadOnlyRedisQueryStorage_Services_Is_Null() + { + // arrange + // act + void Action() + => HotChocolateRedisPersistedQueriesServiceCollectionExtensions + .AddReadOnlyRedisQueryStorage(null!, _ => _database); + + // assert + Assert.Throws(Action); + } + + [Fact] + public void AddReadOnlyRedisQueryStorage_Factory_Is_Null() + { + // arrange + var services = new ServiceCollection(); + + // act + void Action() + => HotChocolateRedisPersistedQueriesServiceCollectionExtensions + .AddReadOnlyRedisQueryStorage(services, null!); + + // assert + Assert.Throws(Action); + } + + [Fact] + public void AddReadOnlyRedisQueryStorage_Services() + { + // arrange + var services = new ServiceCollection(); + + // act + HotChocolateRedisPersistedQueriesServiceCollectionExtensions + .AddReadOnlyRedisQueryStorage(services, _ => _database); + + // assert + services.ToDictionary( k => k.ServiceType.GetTypeName(), v => v.ImplementationType?.GetTypeName()) - .OrderBy(t => t.Key) - .MatchSnapshot(); - } + .OrderBy(t => t.Key) + .MatchSnapshot(); } } diff --git a/src/HotChocolate/PersistedQueries/test/PersistedQueries.Redis.Tests/__snapshots__/IntegrationTests.ExecutePersistedQuery_After_Expiration.snap b/src/HotChocolate/PersistedQueries/test/PersistedQueries.Redis.Tests/__snapshots__/IntegrationTests.ExecutePersistedQuery_After_Expiration.snap new file mode 100644 index 00000000000..7aaebfa6d3e --- /dev/null +++ b/src/HotChocolate/PersistedQueries/test/PersistedQueries.Redis.Tests/__snapshots__/IntegrationTests.ExecutePersistedQuery_After_Expiration.snap @@ -0,0 +1,22 @@ +{ + "Kind": "SingleResult", + "Label": null, + "Path": null, + "Data": null, + "Errors": [ + { + "Message": "The query request contains no document.", + "Code": "HC0015", + "Path": null, + "Locations": null, + "Extensions": { + "code": "HC0015" + }, + "Exception": null, + "SyntaxNode": null + } + ], + "Extensions": null, + "ContextData": null, + "HasNext": null +} diff --git a/src/HotChocolate/PersistedQueries/test/PersistedQueries.Redis.Tests/__snapshots__/IntegrationTests.ExecutePersistedQuery_Before_Expiration.snap b/src/HotChocolate/PersistedQueries/test/PersistedQueries.Redis.Tests/__snapshots__/IntegrationTests.ExecutePersistedQuery_Before_Expiration.snap new file mode 100644 index 00000000000..b215a250601 --- /dev/null +++ b/src/HotChocolate/PersistedQueries/test/PersistedQueries.Redis.Tests/__snapshots__/IntegrationTests.ExecutePersistedQuery_Before_Expiration.snap @@ -0,0 +1,14 @@ +{ + "Kind": "SingleResult", + "Label": null, + "Path": null, + "Data": { + "__typename": "Query" + }, + "Errors": null, + "Extensions": { + "persistedDocument": true + }, + "ContextData": null, + "HasNext": null +}