|
|
@@ -19,10 +19,12 @@ import Foundation
|
|
|
import XCTest
|
|
|
|
|
|
fileprivate let testStatus = ServerStatus(code: .permissionDenied, message: "custom status message")
|
|
|
+fileprivate let testStatusWithTrailingMetadata = ServerStatus(code: .permissionDenied, message: "custom status message",
|
|
|
+ trailingMetadata: try! Metadata(["some_long_key": "bar"]))
|
|
|
|
|
|
fileprivate class StatusThrowingProvider: Echo_EchoProvider {
|
|
|
func get(request: Echo_EchoRequest, session _: Echo_EchoGetSession) throws -> Echo_EchoResponse {
|
|
|
- throw testStatus
|
|
|
+ throw testStatusWithTrailingMetadata
|
|
|
}
|
|
|
|
|
|
func expand(request: Echo_EchoRequest, session: Echo_EchoExpandSession) throws -> ServerStatus? {
|
|
|
@@ -42,6 +44,7 @@ class ServerThrowingTests: BasicEchoTestCase {
|
|
|
static var allTests: [(String, (ServerThrowingTests) -> () throws -> Void)] {
|
|
|
return [
|
|
|
("testServerThrowsUnary", testServerThrowsUnary),
|
|
|
+ ("testServerThrowsUnary_noTrailingMetadataCorruption", testServerThrowsUnary_noTrailingMetadataCorruptionAfterOriginalTrailingMetadataGetsReleased),
|
|
|
("testServerThrowsClientStreaming", testServerThrowsClientStreaming),
|
|
|
("testServerThrowsServerStreaming", testServerThrowsServerStreaming),
|
|
|
("testServerThrowsBidirectionalStreaming", testServerThrowsBidirectionalStreaming)
|
|
|
@@ -52,15 +55,37 @@ class ServerThrowingTests: BasicEchoTestCase {
|
|
|
}
|
|
|
|
|
|
extension ServerThrowingTests {
|
|
|
- func testServerThrowsUnary() {
|
|
|
+ func testServerThrowsUnary() throws {
|
|
|
do {
|
|
|
let result = try client.get(Echo_EchoRequest(text: "foo")).text
|
|
|
XCTFail("should have thrown, received \(result) instead")
|
|
|
- } catch {
|
|
|
- guard case let .callError(callResult) = error as! RPCError
|
|
|
+ return
|
|
|
+ } catch let error as RPCError {
|
|
|
+ guard case let .callError(callResult) = error
|
|
|
else { XCTFail("unexpected error \(error)"); return }
|
|
|
+
|
|
|
XCTAssertEqual(.permissionDenied, callResult.statusCode)
|
|
|
XCTAssertEqual("custom status message", callResult.statusMessage)
|
|
|
+ XCTAssertEqual(["some_long_key": "bar"], callResult.trailingMetadata?.dictionaryRepresentation)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ func testServerThrowsUnary_noTrailingMetadataCorruptionAfterOriginalTrailingMetadataGetsReleased() throws {
|
|
|
+ do {
|
|
|
+ let result = try client.get(Echo_EchoRequest(text: "foo")).text
|
|
|
+ XCTFail("should have thrown, received \(result) instead")
|
|
|
+ return
|
|
|
+ } catch let error as RPCError {
|
|
|
+ guard case let .callError(callResult) = error
|
|
|
+ else { XCTFail("unexpected error \(error)"); return }
|
|
|
+
|
|
|
+ // Send another RPC to cause the original metadata array to be deallocated.
|
|
|
+ // If we were not copying the metadata array correctly, this would cause the metadata of the call result to become
|
|
|
+ // corrupted.
|
|
|
+ _ = try? client.get(Echo_EchoRequest(text: "foo")).text
|
|
|
+ // It seems like we need this sleep for the memory corruption to occur.
|
|
|
+ Thread.sleep(forTimeInterval: 0.01)
|
|
|
+ XCTAssertEqual(["some_long_key": "bar"], callResult.trailingMetadata?.dictionaryRepresentation)
|
|
|
}
|
|
|
}
|
|
|
|