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
+}