Skip to content

Commit 14ef81b

Browse files
authored
Fixed: Subscription is not working with variables (#1176)
1 parent 94cc778 commit 14ef81b

File tree

2 files changed

+143
-20
lines changed

2 files changed

+143
-20
lines changed

src/Core/Core/Execution/SubscriptionExecutionStrategy.cs

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
1+
using System.Runtime.InteropServices.ComTypes;
2+
using System.IO;
13
using System;
24
using System.Collections.Generic;
35
using System.Linq;
46
using System.Threading;
57
using System.Threading.Tasks;
8+
using Microsoft.Extensions.DependencyInjection;
69
using HotChocolate.Execution.Configuration;
7-
using HotChocolate.Language;
810
using HotChocolate.Properties;
9-
using HotChocolate.Resolvers;
1011
using HotChocolate.Subscriptions;
11-
using HotChocolate.Types;
12+
using HotChocolate.Language;
1213

1314
namespace HotChocolate.Execution
1415
{
@@ -71,30 +72,41 @@ private static EventDescription CreateEvent(
7172
if (selections.Count == 1)
7273
{
7374
FieldSelection selection = selections.Single();
74-
return new EventDescription(
75-
selection.Field.Name,
76-
selection.Selection.Arguments);
75+
var arguments = new List<ArgumentNode>();
76+
IVariableValueCollection variables = executionContext.Variables;
77+
78+
foreach (ArgumentNode argument in selection.Selection.Arguments)
79+
{
80+
if (argument.Value is VariableNode v)
81+
{
82+
IValueNode value = variables.GetVariable<IValueNode>(v.Name.Value);
83+
arguments.Add(argument.WithValue(value));
84+
}
85+
else
86+
{
87+
arguments.Add(argument);
88+
}
89+
}
90+
91+
return new EventDescription(selection.Field.Name, arguments);
7792
}
7893
else
7994
{
80-
throw new QueryException(
81-
CoreResources.Subscriptions_SingleRootField);
95+
throw new QueryException(CoreResources.Subscriptions_SingleRootField);
8296
}
8397
}
8498

8599
private static Task<IEventStream> SubscribeAsync(
86100
IServiceProvider services,
87101
IEventDescription @event)
88102
{
89-
var eventRegistry = (IEventRegistry)services
90-
.GetService(typeof(IEventRegistry));
103+
var eventRegistry = services.GetService<IEventRegistry>();
91104

92105
if (eventRegistry == null)
93106
{
94107
throw new QueryException(
95108
ErrorBuilder.New()
96-
.SetMessage(CoreResources
97-
.SubscriptionExecutionStrategy_NoEventRegistry)
109+
.SetMessage(CoreResources.SubscriptionExecutionStrategy_NoEventRegistry)
98110
.Build());
99111
}
100112

@@ -121,7 +133,7 @@ private async Task<IReadOnlyQueryResult> ExecuteSubscriptionQueryAsync(
121133
executionContext,
122134
batchOperationHandler,
123135
cancellationToken)
124-
.ConfigureAwait(false);
136+
.ConfigureAwait(false);
125137

126138
return result.AsReadOnly();
127139
}

src/Core/Subscriptions.Tests/SubscriptionTests.cs

Lines changed: 118 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
using System;
1+
using System.Threading;
2+
using System;
23
using System.Threading.Tasks;
34
using HotChocolate.Execution;
5+
using HotChocolate.Language;
46
using HotChocolate.Types;
57
using Moq;
68
using Xunit;
@@ -10,7 +12,7 @@ namespace HotChocolate.Subscriptions
1012
public class SubscriptionTests
1113
{
1214
[Fact]
13-
public async Task Subscribe_RaiseEvent_ReceiveSubscriptionResult()
15+
public async Task Subscribe_RaiseEvent_No_Arguments()
1416
{
1517
// arrange
1618
var registry = new InMemoryEventRegistry();
@@ -45,9 +47,106 @@ await executor.ExecuteAsync("subscription { foo }")
4547
await executor.ExecuteAsync("mutation { foo }");
4648

4749
// assert
48-
IReadOnlyQueryResult result = await responseStream.ReadAsync();
49-
Assert.False(responseStream.IsCompleted);
50-
Assert.Equal("bar", result.Data["foo"]);
50+
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30)))
51+
{
52+
IReadOnlyQueryResult result = await responseStream.ReadAsync(cts.Token);
53+
Assert.False(responseStream.IsCompleted);
54+
Assert.Equal("bar", result.Data["foo"]);
55+
}
56+
}
57+
58+
[Fact]
59+
public async Task Subscribe_RaiseEvent_With_Argument()
60+
{
61+
// arrange
62+
var registry = new InMemoryEventRegistry();
63+
64+
var services = new Mock<IServiceProvider>();
65+
services.Setup(t => t.GetService(It.IsAny<Type>()))
66+
.Returns(new Func<Type, object>(t =>
67+
{
68+
if (t == typeof(IEventRegistry)
69+
|| t == typeof(IEventSender))
70+
{
71+
return registry;
72+
}
73+
return null;
74+
}));
75+
76+
ISchema schema = Schema.Create(c =>
77+
{
78+
c.RegisterQueryType<DummyQuery>();
79+
c.RegisterServiceProvider(services.Object);
80+
c.RegisterMutationType<MutationType>();
81+
c.RegisterSubscriptionType<SubscriptionType>();
82+
});
83+
84+
IQueryExecutor executor = schema.MakeExecutable();
85+
86+
var responseStream =
87+
await executor.ExecuteAsync("subscription { bar(baz:\"123\") }")
88+
as IResponseStream;
89+
90+
// act
91+
await executor.ExecuteAsync("mutation { bar(baz:\"123\") }");
92+
93+
// assert
94+
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30)))
95+
{
96+
IReadOnlyQueryResult result = await responseStream.ReadAsync(cts.Token);
97+
Assert.False(responseStream.IsCompleted);
98+
Assert.Equal("123", result.Data["bar"]);
99+
}
100+
}
101+
102+
[Fact]
103+
public async Task Subscribe_RaiseEvent_With_Argument_As_Variables()
104+
{
105+
// arrange
106+
var registry = new InMemoryEventRegistry();
107+
108+
var services = new Mock<IServiceProvider>();
109+
services.Setup(t => t.GetService(It.IsAny<Type>()))
110+
.Returns(new Func<Type, object>(t =>
111+
{
112+
if (t == typeof(IEventRegistry)
113+
|| t == typeof(IEventSender))
114+
{
115+
return registry;
116+
}
117+
return null;
118+
}));
119+
120+
ISchema schema = Schema.Create(c =>
121+
{
122+
c.RegisterQueryType<DummyQuery>();
123+
c.RegisterServiceProvider(services.Object);
124+
c.RegisterMutationType<MutationType>();
125+
c.RegisterSubscriptionType<SubscriptionType>();
126+
});
127+
128+
IQueryExecutor executor = schema.MakeExecutable();
129+
130+
var responseStream =
131+
await executor.ExecuteAsync(QueryRequestBuilder.New()
132+
.SetQuery("subscription($a: String!) { bar(baz:$a) }")
133+
.AddVariableValue("a", "123")
134+
.Create())
135+
as IResponseStream;
136+
137+
// act
138+
await executor.ExecuteAsync(QueryRequestBuilder.New()
139+
.SetQuery("mutation($a: String!) { bar(baz:$a) }")
140+
.AddVariableValue("a", "123")
141+
.Create());
142+
143+
// assert
144+
using (var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30)))
145+
{
146+
IReadOnlyQueryResult result = await responseStream.ReadAsync(cts.Token);
147+
Assert.False(responseStream.IsCompleted);
148+
Assert.Equal("123", result.Data["bar"]);
149+
}
51150
}
52151

53152
public class DummyQuery
@@ -62,6 +161,9 @@ protected override void Configure(IObjectTypeDescriptor descriptor)
62161
{
63162
descriptor.Name("subscription");
64163
descriptor.Field("foo").Resolver(() => "bar");
164+
descriptor.Field("bar")
165+
.Argument("baz", a => a.Type<NonNullType<StringType>>())
166+
.Resolver(ctx => ctx.Argument<string>("baz"));
65167
}
66168
}
67169

@@ -73,8 +175,17 @@ protected override void Configure(IObjectTypeDescriptor descriptor)
73175
descriptor.Name("mutation");
74176
descriptor.Field("foo").Resolver(ctx =>
75177
{
76-
ctx.Service<IEventSender>()
77-
.SendAsync(new EventMessage("foo"));
178+
ctx.Service<IEventSender>().SendAsync(new EventMessage("foo"));
179+
return "barmut";
180+
});
181+
182+
descriptor.Field("bar")
183+
.Argument("baz", a => a.Type<NonNullType<StringType>>())
184+
.Resolver(ctx =>
185+
{
186+
IValueNode argumentValue = ctx.Argument<IValueNode>("baz");
187+
ctx.Service<IEventSender>().SendAsync(
188+
new EventMessage("bar", new ArgumentNode("baz", argumentValue)));
78189
return "barmut";
79190
});
80191
}

0 commit comments

Comments
 (0)