-
Notifications
You must be signed in to change notification settings - Fork 420
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Two important fixes (and possibly more improvements) #188
Merged
Merged
Changes from 1 commit
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
78a1291
Fix two huge memory leaks in `cgrpc_call` and `cgrpc_handler`. These …
MrMage d8ac7d4
Fix GRPCTests, hopefully once and for all (see 415307ee for an explan…
MrMage dc451e4
Shift the responsibility for draining and destroying a completion que…
MrMage 9b9ba22
Try increasing the default timeout for server-cancelling tests to 5 s…
MrMage e68cec0
Add a simple API to provide a channel's connectivity state. (See #186.)
MrMage File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -19,12 +19,21 @@ import Foundation | |
import XCTest | ||
|
||
class gRPCTests: XCTestCase { | ||
// We have seen this test flake out in rare cases fairly often due to race conditions. | ||
// To detect such rare errors, we run the tests several times. | ||
// (By now, all known errors should have been fixed, but we'd still like to detect new ones.) | ||
let testRepetitions = 10 | ||
|
||
func testConnectivity() { | ||
runTest(useSSL: false) | ||
for _ in 0..<testRepetitions { | ||
runTest(useSSL: false) | ||
} | ||
} | ||
|
||
func testConnectivitySecure() { | ||
runTest(useSSL: true) | ||
for _ in 0..<testRepetitions { | ||
runTest(useSSL: true) | ||
} | ||
} | ||
|
||
static var allTests: [(String, (gRPCTests) -> () throws -> Void)] { | ||
|
@@ -75,11 +84,8 @@ let helloServerStream = "/hello.server-stream" | |
let helloBiDiStream = "/hello.bidi-stream" | ||
|
||
// Return code/message for unary test | ||
let oddStatusCode = StatusCode.ok | ||
let oddStatusMessage = "OK" | ||
|
||
let evenStatusCode = StatusCode.notFound | ||
let eventStatusMessage = "Not Found" | ||
let evenStatusMessage = "some other status message" | ||
|
||
func runTest(useSSL: Bool) { | ||
gRPC.initialize() | ||
|
@@ -141,9 +147,12 @@ func runClient(useSSL: Bool) throws { | |
} | ||
|
||
channel.host = host | ||
try callUnary(channel: channel) | ||
try callServerStream(channel: channel) | ||
try callBiDiStream(channel: channel) | ||
for _ in 0..<10 { | ||
// Send several calls to each server we spin up, to ensure that each individual server can handle many requests. | ||
try callUnary(channel: channel) | ||
try callServerStream(channel: channel) | ||
try callBiDiStream(channel: channel) | ||
} | ||
} | ||
|
||
func callUnary(channel: Channel) throws { | ||
|
@@ -157,23 +166,32 @@ func callUnary(channel: Channel) throws { | |
try call.start(.unary, metadata: metadata, message: message) { | ||
response in | ||
// verify the basic response from the server | ||
XCTAssertEqual(response.statusCode, (i % 2 == 0) ? evenStatusCode : oddStatusCode) | ||
XCTAssertEqual(response.statusMessage, (i % 2 == 0) ? eventStatusMessage : oddStatusMessage) | ||
XCTAssertEqual(response.statusCode, .ok) | ||
XCTAssertEqual(response.statusMessage, (i % 2 == 0) ? evenStatusMessage : oddStatusMessage) | ||
|
||
// verify the message from the server | ||
if (i % 2) == 0 { | ||
let resultData = response.resultData! | ||
let messageString = String(data: resultData, encoding: .utf8) | ||
XCTAssertEqual(messageString, serverText) | ||
if let resultData = response.resultData { | ||
let messageString = String(data: resultData, encoding: .utf8) | ||
XCTAssertEqual(messageString, serverText) | ||
} else { | ||
XCTFail("callUnary response missing") | ||
} | ||
} | ||
|
||
// verify the initial metadata from the server | ||
let initialMetadata = response.initialMetadata! | ||
verify_metadata(initialMetadata, expected: initialServerMetadata) | ||
|
||
if let initialMetadata = response.initialMetadata { | ||
verify_metadata(initialMetadata, expected: initialServerMetadata) | ||
} else { | ||
XCTFail("callUnary initial metadata missing") | ||
} | ||
|
||
// verify the trailing metadata from the server | ||
let trailingMetadata = response.trailingMetadata! | ||
verify_metadata(trailingMetadata, expected: trailingServerMetadata) | ||
if let trailingMetadata = response.trailingMetadata { | ||
verify_metadata(trailingMetadata, expected: trailingServerMetadata) | ||
} else { | ||
XCTFail("callUnary trailing metadata missing") | ||
} | ||
|
||
// report completion | ||
sem.signal() | ||
|
@@ -197,8 +215,11 @@ func callServerStream(channel: Channel) throws { | |
XCTAssertEqual(response.statusMessage, "Custom Status Message ServerStreaming") | ||
|
||
// verify the trailing metadata from the server | ||
let trailingMetadata = response.trailingMetadata! | ||
verify_metadata(trailingMetadata, expected: trailingServerMetadata) | ||
if let trailingMetadata = response.trailingMetadata { | ||
verify_metadata(trailingMetadata, expected: trailingServerMetadata) | ||
} else { | ||
XCTFail("callServerStream trailing metadata missing") | ||
} | ||
|
||
sem.signal() // signal call is finished | ||
} | ||
|
@@ -224,29 +245,31 @@ let clientPing = "ping" | |
let serverPong = "pong" | ||
|
||
func callBiDiStream(channel: Channel) throws { | ||
let message = clientPing.data(using: .utf8) | ||
let metadata = Metadata(initialClientMetadata) | ||
|
||
let sem = DispatchSemaphore(value: 0) | ||
let method = helloBiDiStream | ||
let call = channel.makeCall(method) | ||
try call.start(.bidiStreaming, metadata: metadata, message: message) { | ||
try call.start(.bidiStreaming, metadata: metadata, message: nil) { | ||
response in | ||
|
||
XCTAssertEqual(response.statusCode, .ok) | ||
XCTAssertEqual(response.statusMessage, "Custom Status Message BiDi") | ||
|
||
// verify the trailing metadata from the server | ||
let trailingMetadata = response.trailingMetadata! | ||
verify_metadata(trailingMetadata, expected: trailingServerMetadata) | ||
if let trailingMetadata = response.trailingMetadata { | ||
verify_metadata(trailingMetadata, expected: trailingServerMetadata) | ||
} else { | ||
XCTFail("callBiDiStream trailing metadata missing") | ||
} | ||
|
||
sem.signal() // signal call is finished | ||
} | ||
|
||
// Send pings | ||
let message = clientPing.data(using: .utf8)! | ||
for _ in 0..<steps { | ||
let message = clientPing.data(using: .utf8) | ||
try call.sendMessage(data: message!) { (err) in | ||
try call.sendMessage(data: message) { err in | ||
XCTAssertNil(err) | ||
} | ||
call.messageQueueEmpty.wait() | ||
|
@@ -313,21 +336,28 @@ func handleUnary(requestHandler: Handler, requestCount: Int) throws { | |
let initialMetadata = requestHandler.requestMetadata | ||
verify_metadata(initialMetadata, expected: initialClientMetadata) | ||
let initialMetadataToSend = Metadata(initialServerMetadata) | ||
try requestHandler.receiveMessage(initialMetadata: initialMetadataToSend) { messageData in | ||
let messageString = String(data: messageData!, encoding: .utf8) | ||
XCTAssertEqual(messageString, clientText) | ||
try requestHandler.receiveMessage(initialMetadata: initialMetadataToSend) { | ||
if let messageData = $0 { | ||
let messageString = String(data: messageData, encoding: .utf8) | ||
XCTAssertEqual(messageString, clientText) | ||
} else { | ||
XCTFail("handleUnary message missing") | ||
} | ||
} | ||
|
||
// We need to return status OK in both cases, as it seems like the server might never send out the last few messages | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems like a huge problem. We need to assert that the server sends an appropriate status code and if it's not currently then tests should be failing |
||
// once it has been asked to send a non-OK status. Alternatively, we could send a non-OK status here, but then we | ||
// would need to sleep for a few milliseconds before sending the non-OK status. | ||
let replyMessage = serverText.data(using: .utf8)! | ||
if (requestCount % 2) == 0 { | ||
let replyMessage = serverText | ||
let trailingMetadataToSend = Metadata(trailingServerMetadata) | ||
try requestHandler.sendResponse(message: replyMessage.data(using: .utf8)!, | ||
status: ServerStatus(code: evenStatusCode, | ||
message: eventStatusMessage, | ||
try requestHandler.sendResponse(message: replyMessage, | ||
status: ServerStatus(code: .ok, | ||
message: evenStatusMessage, | ||
trailingMetadata: trailingMetadataToSend)) | ||
} else { | ||
let trailingMetadataToSend = Metadata(trailingServerMetadata) | ||
try requestHandler.sendStatus(ServerStatus(code: oddStatusCode, | ||
try requestHandler.sendStatus(ServerStatus(code: .ok, | ||
message: oddStatusMessage, | ||
trailingMetadata: trailingMetadataToSend)) | ||
} | ||
|
@@ -340,14 +370,18 @@ func handleServerStream(requestHandler: Handler) throws { | |
verify_metadata(initialMetadata, expected: initialClientMetadata) | ||
|
||
let initialMetadataToSend = Metadata(initialServerMetadata) | ||
try requestHandler.receiveMessage(initialMetadata: initialMetadataToSend) { messageData in | ||
let messageString = String(data: messageData!, encoding: .utf8) | ||
XCTAssertEqual(messageString, clientText) | ||
try requestHandler.receiveMessage(initialMetadata: initialMetadataToSend) { | ||
if let messageData = $0 { | ||
let messageString = String(data: messageData, encoding: .utf8) | ||
XCTAssertEqual(messageString, clientText) | ||
} else { | ||
XCTFail("handleServerStream message missing") | ||
} | ||
} | ||
|
||
let replyMessage = serverText | ||
let replyMessage = serverText.data(using: .utf8)! | ||
for _ in 0..<steps { | ||
try requestHandler.call.sendMessage(data: replyMessage.data(using: .utf8)!) { error in | ||
try requestHandler.call.sendMessage(data: replyMessage) { error in | ||
XCTAssertNil(error) | ||
} | ||
requestHandler.call.messageQueueEmpty.wait() | ||
|
@@ -380,8 +414,12 @@ func handleBiDiStream(requestHandler: Handler) throws { | |
for _ in 0..<steps { | ||
let receiveSem = DispatchSemaphore(value: 0) | ||
try requestHandler.call.receiveMessage { callStatus in | ||
let messageString = String(data: callStatus.resultData!, encoding: .utf8) | ||
XCTAssertEqual(messageString, clientPing) | ||
if let messageData = callStatus.resultData { | ||
let messageString = String(data: messageData, encoding: .utf8) | ||
XCTAssertEqual(messageString, clientPing) | ||
} else { | ||
XCTFail("handleBiDiStream message empty") | ||
} | ||
receiveSem.signal() | ||
} | ||
_ = receiveSem.wait() | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This means we never check for non
.ok
status codes which was the original bug filed in #144.