@@ -3,16 +3,15 @@ import NIO
33import RxSwift
44@testable import GraphQL
55
6+
67class SubscriptionTests : XCTestCase {
78
9+ /// Creates a subscription result for the input pub/sub, schema, and AST document
810 private func createSubscription(
911 pubsub: Observable < Any > ,
10- schema: GraphQLSchema = emailSchemaWithResolvers ( subscribe : nil , resolve : nil ) ,
12+ schema: GraphQLSchema ? = nil ,
1113 document: Document = defaultSubscriptionAST
12- ) -> EventLoopFuture < SubscriptionResult > {
13-
14- let eventLoopGroup = MultiThreadedEventLoopGroup ( numberOfThreads: System . coreCount)
15-
14+ ) throws -> Observable < GraphQLResult > {
1615
1716 var emails = [
1817 Email (
@@ -22,167 +21,170 @@ class SubscriptionTests : XCTestCase {
2221 unread: false
2322 )
2423 ]
25-
26- func importantEmail( priority: Int ) -> Observable < EmailEvent > {
27- let inbox = Inbox ( emails: emails)
28- let emailSubject = PublishSubject < Email > ( )
29- let emailEventSubject = emailSubject. map { email -> EmailEvent in
24+
25+ let testSchema = schema ?? emailSchemaWithResolvers (
26+ subscribe: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture < Any ? > in
27+ return eventLoopGroup. next ( ) . makeSucceededFuture ( pubsub)
28+ } ,
29+ resolve: { emailAny, _, _, eventLoopGroup, _ throws -> EventLoopFuture < Any ? > in
30+ let email = emailAny as! Email
3031 emails. append ( email)
31- return EmailEvent ( email: email, inbox: inbox)
32+ return eventLoopGroup. next ( ) . makeSucceededFuture ( EmailEvent (
33+ email: email,
34+ inbox: Inbox ( emails: emails)
35+ ) )
3236 }
33- return emailEventSubject
34- }
37+ )
3538
36- // TODO This seems weird and should probably be an object type
37- let rootValue : [ String : Any ] = [
38- " inbox " : Inbox ( emails: emails) ,
39- " importantEmail " : importantEmail
40- ]
39+ let eventLoopGroup = MultiThreadedEventLoopGroup ( numberOfThreads: System . coreCount)
4140
42- return subscribe (
41+ let subscriptionResult = try subscribe (
4342 queryStrategy: SerialFieldExecutionStrategy ( ) ,
4443 mutationStrategy: SerialFieldExecutionStrategy ( ) ,
4544 subscriptionStrategy: SerialFieldExecutionStrategy ( ) ,
4645 instrumentation: NoOpInstrumentation,
47- schema: schema ,
46+ schema: testSchema ,
4847 documentAST: document,
49- rootValue: rootValue ,
48+ rootValue: Void ( ) ,
5049 context: Void ( ) ,
5150 eventLoopGroup: eventLoopGroup,
5251 variableValues: [ : ] ,
5352 operationName: nil
54- )
55- }
56-
57-
58-
59- // TODO Delete me - this just goes thru the entire pipeline
60- func testDELETEME( ) throws {
61- let pubsub = PublishSubject < Any > ( )
62- let testSchema = emailSchemaWithResolvers (
63- subscribe: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture < Any ? > in
64- return eventLoopGroup. next ( ) . makeSucceededFuture ( pubsub)
65- } ,
66- resolve: nil
67- )
68- let subscriptionResult = try createSubscription ( pubsub: pubsub, schema: testSchema) . wait ( )
53+ ) . wait ( )
54+
6955 switch subscriptionResult {
7056 case . success( let subscription) :
71- let subscriber = subscription. subscribe {
72- print ( " Event: \( $0) " )
73- }
74- pubsub. onNext ( Email (
75- from: " yuzhi@graphql.org " ,
76- subject: " Alright " ,
77- message: " Tests are good " ,
78- unread: true
79- ) )
57+ return subscription
8058 case . failure( let error) :
8159 throw error
8260 }
8361 }
8462
85- // MARK: Subscription Initialization Phase
86-
87- /// accepts multiple subscription fields defined in schema
88- // TODO Finish up this test
89- func testAcceptsMultipleSubscriptionFields( ) throws {
63+ // MARK: Basic test to see if publishing is working
64+ func testBasic( ) throws {
65+ let disposeBag = DisposeBag ( )
9066 let pubsub = PublishSubject < Any > ( )
91- let subscriptionTypeMultiple = try GraphQLObjectType (
92- name: " Subscription " ,
93- fields: [
94- " importantEmail " : GraphQLField ( type: EmailEventType) ,
95- " notImportantEmail " : GraphQLField ( type: EmailEventType)
96- ]
97- )
98- let testSchema = try GraphQLSchema (
99- query: EmailQueryType,
100- subscription: subscriptionTypeMultiple
101- )
102- let subscriptionResult = try createSubscription ( pubsub: pubsub, schema: testSchema) . wait ( )
103- switch subscriptionResult {
104- case . success:
105- pubsub. onNext ( Email (
106- from: " yuzhi@graphql.org " ,
107- subject: " Alright " ,
108- message: " Tests are good " ,
109- unread: true
110- ) )
111- case . failure( let error) :
112- throw error
113- }
114- }
115-
116-
117- // TODO Not working. I think it's because it's checking the Resolver return against the Schema-defined return type...
118- func testResolverReturningErrorSchema( ) throws {
119- let eventLoopGroup = MultiThreadedEventLoopGroup ( numberOfThreads: System . coreCount)
120- let schema = emailSchemaWithResolvers (
121- subscribe: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture < Any ? > in
122- return eventLoopGroup. next ( ) . makeSucceededFuture ( GraphQLError ( message: " test error " ) )
123- } ,
124- resolve: nil
125- )
126- let document = try parse ( source: """
127- subscription {
128- importantEmail
129- }
130- """ )
131- let result = try createSourceEventStream (
132- queryStrategy: SerialFieldExecutionStrategy ( ) ,
133- mutationStrategy: SerialFieldExecutionStrategy ( ) ,
134- subscriptionStrategy: SerialFieldExecutionStrategy ( ) ,
135- instrumentation: NoOpInstrumentation,
136- schema: schema,
137- documentAST: document,
138- rootValue: Void ( ) ,
139- context: Void ( ) ,
140- eventLoopGroup: eventLoopGroup
141- ) . wait ( )
67+ let subscription = try createSubscription ( pubsub: pubsub)
14268
143- switch result {
144- case . success:
145- XCTFail ( )
146- case . failure( let error) :
147- let expected = GraphQLError ( message: " test error " )
148- XCTAssertEqual ( expected, error)
149- }
150- }
151-
152- // Working!!!
153- func testResolverThrowingErrorSchema( ) throws {
154- let eventLoopGroup = MultiThreadedEventLoopGroup ( numberOfThreads: System . coreCount)
155- let schema = emailSchemaWithResolvers (
156- subscribe: { _, _, _, eventLoopGroup, _ throws -> EventLoopFuture < Any ? > in
157- throw GraphQLError ( message: " test error " )
158- } ,
159- resolve: nil
69+ let expected = GraphQLResult (
70+ data: [ " importantEmail " : [
71+ " inbox " : [
72+ " total " : 2 ,
73+ " unread " : 1
74+ ] ,
75+ " email " : [
76+ " subject " : " Alright " ,
77+ " from " : " yuzhi@graphql.org "
78+ ]
79+ ] ]
16080 )
161- let document = try parse ( source: """
162- subscription {
163- importantEmail
164- }
165- """ )
166- let result = try createSourceEventStream (
167- queryStrategy: SerialFieldExecutionStrategy ( ) ,
168- mutationStrategy: SerialFieldExecutionStrategy ( ) ,
169- subscriptionStrategy: SerialFieldExecutionStrategy ( ) ,
170- instrumentation: NoOpInstrumentation,
171- schema: schema,
172- documentAST: document,
173- rootValue: Void ( ) ,
174- context: Void ( ) ,
175- eventLoopGroup: eventLoopGroup
176- ) . wait ( )
177-
178- switch result {
179- case . success( let observable) :
180- XCTFail ( )
181- case . failure( let error) :
182- let expected = GraphQLError ( message: " test error " )
183- XCTAssertEqual ( expected, error)
184- }
81+ let _ = subscription. subscribe { event in
82+ XCTAssertEqual ( event. element, expected)
83+ } . disposed ( by: disposeBag)
84+ pubsub. onNext ( Email (
85+ from: " yuzhi@graphql.org " ,
86+ subject: " Alright " ,
87+ message: " Tests are good " ,
88+ unread: true
89+ ) )
18590 }
91+
92+
93+ // MARK: Subscription Initialization Phase
94+
95+ /// accepts multiple subscription fields defined in schema
96+ // func testAcceptsMultipleSubscriptionFields() throws {
97+ // let pubsub = PublishSubject<Any>()
98+ // let subscriptionTypeMultiple = try GraphQLObjectType(
99+ // name: "Subscription",
100+ // fields: [
101+ // "importantEmail": GraphQLField (type: EmailEventType),
102+ // "notImportantEmail": GraphQLField (type: EmailEventType)
103+ // ]
104+ // )
105+ // let testSchema = try GraphQLSchema(
106+ // query: EmailQueryType,
107+ // subscription: subscriptionTypeMultiple
108+ // )
109+ // let subscription = try createSubscription(pubsub: pubsub, schema: testSchema)
110+ // pubsub.onNext(Email(
111+ // from: "yuzhi@graphql.org",
112+ // subject: "Alright",
113+ // message: "Tests are good",
114+ // unread: true
115+ // ))
116+ // }
117+ //
118+ //
119+ // // TODO Not working. I think it's because it's checking the Resolver return against the Schema-defined return type...
120+ // func testResolverReturningErrorSchema() throws {
121+ // let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
122+ // let schema = emailSchemaWithResolvers(
123+ // subscribe: {_, _, _, eventLoopGroup, _ throws -> EventLoopFuture<Any?> in
124+ // return eventLoopGroup.next().makeSucceededFuture(GraphQLError(message: "test error"))
125+ // },
126+ // resolve: nil
127+ // )
128+ // let document = try parse(source: """
129+ // subscription {
130+ // importantEmail
131+ // }
132+ // """)
133+ // let result = try createSourceEventStream(
134+ // queryStrategy: SerialFieldExecutionStrategy(),
135+ // mutationStrategy: SerialFieldExecutionStrategy(),
136+ // subscriptionStrategy: SerialFieldExecutionStrategy(),
137+ // instrumentation: NoOpInstrumentation,
138+ // schema: schema,
139+ // documentAST: document,
140+ // rootValue: Void(),
141+ // context: Void(),
142+ // eventLoopGroup: eventLoopGroup
143+ // ).wait()
144+ //
145+ // switch result {
146+ // case .success:
147+ // XCTFail()
148+ // case .failure(let error):
149+ // let expected = GraphQLError(message:"test error")
150+ // XCTAssertEqual(expected, error)
151+ // }
152+ // }
153+ //
154+ // // Working!!!
155+ // func testResolverThrowingErrorSchema() throws {
156+ // let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: System.coreCount)
157+ // let schema = emailSchemaWithResolvers(
158+ // subscribe: {_, _, _, eventLoopGroup, _ throws -> EventLoopFuture<Any?> in
159+ // throw GraphQLError(message: "test error")
160+ // },
161+ // resolve: nil
162+ // )
163+ // let document = try parse(source: """
164+ // subscription {
165+ // importantEmail
166+ // }
167+ // """)
168+ // let result = try createSourceEventStream(
169+ // queryStrategy: SerialFieldExecutionStrategy(),
170+ // mutationStrategy: SerialFieldExecutionStrategy(),
171+ // subscriptionStrategy: SerialFieldExecutionStrategy(),
172+ // instrumentation: NoOpInstrumentation,
173+ // schema: schema,
174+ // documentAST: document,
175+ // rootValue: Void(),
176+ // context: Void(),
177+ // eventLoopGroup: eventLoopGroup
178+ // ).wait()
179+ //
180+ // switch result {
181+ // case .success(let observable):
182+ // XCTFail()
183+ // case .failure(let error):
184+ // let expected = GraphQLError(message:"test error")
185+ // XCTAssertEqual(expected, error)
186+ // }
187+ // }
186188}
187189
188190let defaultSubscriptionAST = try ! parse ( source: """
@@ -201,18 +203,18 @@ let defaultSubscriptionAST = try! parse(source: """
201203""" )
202204
203205// MARK: Types
204- struct Email {
206+ struct Email : Encodable {
205207 let from : String
206208 let subject : String
207209 let message : String
208210 let unread : Bool
209211}
210212
211- struct Inbox {
213+ struct Inbox : Encodable {
212214 let emails : [ Email ]
213215}
214216
215- struct EmailEvent {
217+ struct EmailEvent : Encodable {
216218 let email : Email
217219 let inbox : Inbox
218220}
@@ -247,13 +249,12 @@ let InboxType = try! GraphQLObjectType(
247249 ( inbox as! Inbox ) . emails. count
248250 }
249251 ) ,
250- // TODO figure out how to do searches
251- // "unread": GraphQLField(
252- // type: GraphQLInt,
253- // resolve: { inbox, _, _, _ in
254- // (inbox as! InboxType).emails.
255- // }
256- // ),
252+ " unread " : GraphQLField (
253+ type: GraphQLInt,
254+ resolve: { inbox, _, _, _ in
255+ ( inbox as! Inbox ) . emails. filter ( { $0. unread} ) . count
256+ }
257+ ) ,
257258 ]
258259)
259260
0 commit comments