Forráskód Böngészése

Add sample test suites to demonstrate how one would test client/server code.

These tests don't really test the logic of the SwiftGRPC library, but are meant as an example of how one would go about testing their own client/server code that relies on SwiftGRPC.
Daniel Alm 7 éve
szülő
commit
e7645b48ef

+ 5 - 6
Sources/SwiftGRPC/Runtime/ClientCallBidirectionalStreaming.swift

@@ -59,15 +59,14 @@ open class ClientCallBidirectionalStreamingTestStub<InputType: Message, OutputTy
   
   public init() {}
 
-  open func receive(completion: @escaping (ResultOrRPCError<OutputType?>) -> Void) throws {
-    completion(.result(outputs.first))
-    outputs.removeFirst()
-  }
-
   open func receive() throws -> OutputType? {
-    defer { outputs.removeFirst() }
+    defer { if !outputs.isEmpty { outputs.removeFirst() } }
     return outputs.first
   }
+  
+  open func receive(completion: @escaping (ResultOrRPCError<OutputType?>) -> Void) throws {
+    completion(.result(try self.receive()))
+  }
 
   open func send(_ message: InputType, completion _: @escaping (Error?) -> Void) throws {
     inputs.append(message)

+ 6 - 7
Sources/SwiftGRPC/Runtime/ClientCallServerStreaming.swift

@@ -44,16 +44,15 @@ open class ClientCallServerStreamingTestStub<OutputType: Message>: ClientCallSer
   open var outputs: [OutputType] = []
   
   public init() {}
-
-  open func receive(completion: @escaping (ResultOrRPCError<OutputType?>) -> Void) throws {
-    completion(.result(outputs.first))
-    outputs.removeFirst()
-  }
-
+  
   open func receive() throws -> OutputType? {
-    defer { outputs.removeFirst() }
+    defer { if !outputs.isEmpty { outputs.removeFirst() } }
     return outputs.first
   }
+  
+  open func receive(completion: @escaping (ResultOrRPCError<OutputType?>) -> Void) throws {
+    completion(.result(try self.receive()))
+  }
 
   open func cancel() {}
 }

+ 2 - 3
Sources/SwiftGRPC/Runtime/ServerSessionBidirectionalStreaming.swift

@@ -70,13 +70,12 @@ open class ServerSessionBidirectionalStreamingTestStub<InputType: Message, Outpu
   open var status: ServerStatus?
 
   open func receive() throws -> InputType? {
-    defer { inputs.removeFirst() }
+    defer { if !inputs.isEmpty { inputs.removeFirst() } }
     return inputs.first
   }
   
   open func receive(completion: @escaping (ResultOrRPCError<InputType?>) -> Void) throws {
-    completion(.result(inputs.first))
-    inputs.removeFirst()
+    completion(.result(try self.receive()))
   }
 
   open func send(_ message: OutputType, completion _: @escaping (Error?) -> Void) throws {

+ 2 - 3
Sources/SwiftGRPC/Runtime/ServerSessionClientStreaming.swift

@@ -72,13 +72,12 @@ open class ServerSessionClientStreamingTestStub<InputType: Message, OutputType:
   open var status: ServerStatus?
 
   open func receive() throws -> InputType? {
-    defer { inputs.removeFirst() }
+    defer { if !inputs.isEmpty { inputs.removeFirst() } }
     return inputs.first
   }
   
   open func receive(completion: @escaping (ResultOrRPCError<InputType?>) -> Void) throws {
-    completion(.result(inputs.first))
-    inputs.removeFirst()
+    completion(.result(try self.receive()))
   }
 
   open func sendAndClose(response: OutputType, status: ServerStatus, completion: ((CallResult) -> Void)?) throws {

+ 2 - 0
Tests/LinuxMain.swift

@@ -18,9 +18,11 @@ import XCTest
 
 XCTMain([
   testCase(gRPCTests.allTests),
+  testCase(ClientTestExample.allTests),
   testCase(ClientTimeoutTests.allTests),
   testCase(ConnectionFailureTests.allTests),
   testCase(EchoTests.allTests),
+  testCase(ServerTestExample.allTests),
   testCase(ServerThrowingTests.allTests),
   testCase(ServerTimeoutTests.allTests)
 ])

+ 6 - 0
Tests/SwiftGRPCTests/BasicEchoTestCase.swift

@@ -24,6 +24,12 @@ extension Echo_EchoRequest {
   }
 }
 
+extension Echo_EchoResponse {
+  init(text: String) {
+    self.text = text
+  }
+}
+
 class BasicEchoTestCase: XCTestCase {
   func makeProvider() -> Echo_EchoProvider { return EchoProvider() }
   

+ 141 - 0
Tests/SwiftGRPCTests/ClientTestExample.swift

@@ -0,0 +1,141 @@
+/*
+ * Copyright 2018, gRPC Authors All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import Dispatch
+import Foundation
+@testable import SwiftGRPC
+import XCTest
+
+// Sample test suite to demonstrate how one would test client code that
+// uses an object that implements the `...Service` protocol.
+// These tests don't really test the logic of the SwiftGRPC library, but are meant
+// as an example of how one would go about testing their own client/server code that
+// relies on SwiftGRPC.
+fileprivate class ClientUnderTest {
+  let service: Echo_EchoService
+  
+  init(service: Echo_EchoService) {
+    self.service = service
+  }
+  
+  func getWord(_ input: String) throws -> String {
+    return try service.get(Echo_EchoRequest(text: input)).text
+  }
+  
+  func collectWords(_ input: [String]) throws -> String {
+    let call = try service.collect(completion: nil)
+    for text in input {
+      try call.send(Echo_EchoRequest(text: text), completion: { _ in })
+    }
+    call.waitForSendOperationsToFinish()
+    return try call.closeAndReceive().text
+  }
+  
+  func expandWords(_ input: String) throws -> [String] {
+    let call = try service.expand(Echo_EchoRequest(text: input), completion: nil)
+    var results: [String] = []
+    while let response = try call.receive() {
+      results.append(response.text)
+    }
+    return results
+  }
+  
+  func updateWords(_ input: [String]) throws -> [String] {
+    let call = try service.update(completion: nil)
+    for text in input {
+      try call.send(Echo_EchoRequest(text: text), completion: { _ in })
+    }
+    call.waitForSendOperationsToFinish()
+    
+    var results: [String] = []
+    while let response = try call.receive() {
+      results.append(response.text)
+    }
+    return results
+  }
+}
+
+class ClientTestExample: XCTestCase {
+  static var allTests: [(String, (ClientTestExample) -> () throws -> Void)] {
+    return [
+      ("testUnary", testUnary),
+      ("testClientStreaming", testClientStreaming),
+      ("testServerStreaming", testServerStreaming),
+      ("testBidirectionalStreaming", testBidirectionalStreaming)
+    ]
+  }
+}
+
+extension ClientTestExample {
+  func testUnary() {
+    let fakeService = Echo_EchoServiceTestStub()
+    fakeService.getResponses.append(Echo_EchoResponse(text: "bar"))
+    
+    let client = ClientUnderTest(service: fakeService)
+    XCTAssertEqual("bar", try client.getWord("foo"))
+    
+    // Ensure that all responses have been consumed.
+    XCTAssertEqual(0, fakeService.getResponses.count)
+    // Ensure that the expected requests have been sent.
+    XCTAssertEqual([Echo_EchoRequest(text: "foo")], fakeService.getRequests)
+  }
+  
+  func testClientStreaming() {
+    let inputStrings = ["foo", "bar", "baz"]
+    let fakeService = Echo_EchoServiceTestStub()
+    let fakeCall = Echo_EchoCollectCallTestStub()
+    fakeCall.output = Echo_EchoResponse(text: "response")
+    fakeService.collectCalls.append(fakeCall)
+    
+    let client = ClientUnderTest(service: fakeService)
+    XCTAssertEqual("response", try client.collectWords(inputStrings))
+    
+    // Ensure that the expected requests have been sent.
+    XCTAssertEqual(inputStrings.map { Echo_EchoRequest(text: $0) }, fakeCall.inputs)
+  }
+  
+  func testServerStreaming() {
+    let outputStrings = ["foo", "bar", "baz"]
+    let fakeService = Echo_EchoServiceTestStub()
+    let fakeCall = Echo_EchoExpandCallTestStub()
+    fakeCall.outputs = outputStrings.map { Echo_EchoResponse(text: $0) }
+    fakeService.expandCalls.append(fakeCall)
+    
+    let client = ClientUnderTest(service: fakeService)
+    XCTAssertEqual(outputStrings, try client.expandWords("inputWord"))
+    
+    // Ensure that all responses have been consumed.
+    XCTAssertEqual(0, fakeCall.outputs.count)
+    // Ensure that the expected requests have been sent.
+    XCTAssertEqual([Echo_EchoRequest(text: "inputWord")], fakeService.expandRequests)
+  }
+  
+  func testBidirectionalStreaming() {
+    let inputStrings = ["foo", "bar", "baz"]
+    let outputStrings = ["foo2", "bar2", "baz2"]
+    let fakeService = Echo_EchoServiceTestStub()
+    let fakeCall = Echo_EchoUpdateCallTestStub()
+    fakeCall.outputs = outputStrings.map { Echo_EchoResponse(text: $0) }
+    fakeService.updateCalls.append(fakeCall)
+    
+    let client = ClientUnderTest(service: fakeService)
+    XCTAssertEqual(outputStrings, try client.updateWords(inputStrings))
+    
+    // Ensure that all responses have been consumed.
+    XCTAssertEqual(0, fakeCall.outputs.count)
+    // Ensure that the expected requests have been sent.
+    XCTAssertEqual(inputStrings.map { Echo_EchoRequest(text: $0) }, fakeCall.inputs)
+  }
+}

+ 92 - 0
Tests/SwiftGRPCTests/ServerTestExample.swift

@@ -0,0 +1,92 @@
+/*
+ * Copyright 2018, gRPC Authors All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import Dispatch
+import Foundation
+@testable import SwiftGRPC
+import XCTest
+
+// Sample test suite to demonstrate how one would test a `Provider` implementation.
+// These tests don't really test the logic of the SwiftGRPC library, but are meant
+// as an example of how one would go about testing their own client/server code that
+// relies on SwiftGRPC.
+class ServerTestExample: XCTestCase {
+  static var allTests: [(String, (ServerTestExample) -> () throws -> Void)] {
+    return [
+      ("testUnary", testUnary),
+      ("testClientStreaming", testClientStreaming),
+      ("testServerStreaming", testServerStreaming),
+      ("testBidirectionalStreaming", testBidirectionalStreaming)
+    ]
+  }
+  
+  var provider: Echo_EchoProvider!
+  
+  override func setUp() {
+    super.setUp()
+    
+    provider = EchoProvider()
+  }
+  
+  override func tearDown() {
+    provider = nil
+    
+    super.tearDown()
+  }
+}
+
+extension ServerTestExample {
+  func testUnary() {
+    XCTAssertEqual(Echo_EchoResponse(text: "Swift echo get: "),
+                   try provider.get(request: Echo_EchoRequest(text: ""), session: Echo_EchoGetSessionTestStub()))
+    XCTAssertEqual(Echo_EchoResponse(text: "Swift echo get: foo"),
+                   try provider.get(request: Echo_EchoRequest(text: "foo"), session: Echo_EchoGetSessionTestStub()))
+    XCTAssertEqual(Echo_EchoResponse(text: "Swift echo get: foo bar"),
+                   try provider.get(request: Echo_EchoRequest(text: "foo bar"), session: Echo_EchoGetSessionTestStub()))
+  }
+  
+  func testClientStreaming() {
+    let session = Echo_EchoCollectSessionTestStub()
+    session.inputs = ["foo", "bar", "baz"].map { Echo_EchoRequest(text: $0) }
+    
+    XCTAssertNoThrow(try provider.collect(session: session))
+    
+    XCTAssertEqual(.ok, session.status!.code)
+    XCTAssertEqual(Echo_EchoResponse(text: "Swift echo collect: foo bar baz"),
+                   session.output)
+  }
+  
+  func testServerStreaming() {
+    let session = Echo_EchoExpandSessionTestStub()
+    XCTAssertNoThrow(try provider.expand(request: Echo_EchoRequest(text: "foo bar baz"), session: session))
+    
+    XCTAssertEqual(.ok, session.status!.code)
+    XCTAssertEqual(["foo", "bar", "baz"].enumerated()
+      .map { Echo_EchoResponse(text: "Swift echo expand (\($0)): \($1)") },
+                   session.outputs)
+  }
+  
+  func testBidirectionalStreaming() {
+    let inputStrings = ["foo", "bar", "baz"]
+    let session = Echo_EchoUpdateSessionTestStub()
+    session.inputs = inputStrings.map { Echo_EchoRequest(text: $0) }
+    XCTAssertNoThrow(try provider.update(session: session))
+    
+    XCTAssertEqual(.ok, session.status!.code)
+    XCTAssertEqual(inputStrings.enumerated()
+      .map { Echo_EchoResponse(text: "Swift echo update (\($0)): \($1)") },
+                   session.outputs)
+  }
+}