|
|
|
@ -16,6 +16,7 @@ |
|
|
|
|
* |
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
#include <algorithm> |
|
|
|
|
#include <functional> |
|
|
|
|
#include <mutex> |
|
|
|
|
#include <sstream> |
|
|
|
@ -104,8 +105,8 @@ class ClientCallbackEnd2endTest |
|
|
|
|
do_not_test_ = true; |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
int port = grpc_pick_unused_port_or_die(); |
|
|
|
|
server_address_ << "localhost:" << port; |
|
|
|
|
picked_port_ = grpc_pick_unused_port_or_die(); |
|
|
|
|
server_address_ << "localhost:" << picked_port_; |
|
|
|
|
builder.AddListeningPort(server_address_.str(), server_creds); |
|
|
|
|
} |
|
|
|
|
if (!GetParam().callback_server) { |
|
|
|
@ -166,6 +167,9 @@ class ClientCallbackEnd2endTest |
|
|
|
|
if (is_server_started_) { |
|
|
|
|
server_->Shutdown(); |
|
|
|
|
} |
|
|
|
|
if (picked_port_ > 0) { |
|
|
|
|
grpc_recycle_unused_port(picked_port_); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void SendRpcs(int num_rpcs, bool with_binary_metadata) { |
|
|
|
@ -321,6 +325,7 @@ class ClientCallbackEnd2endTest |
|
|
|
|
} |
|
|
|
|
bool do_not_test_{false}; |
|
|
|
|
bool is_server_started_{false}; |
|
|
|
|
int picked_port_{0}; |
|
|
|
|
std::shared_ptr<Channel> channel_; |
|
|
|
|
std::unique_ptr<grpc::testing::EchoTestService::Stub> stub_; |
|
|
|
|
std::unique_ptr<grpc::GenericStub> generic_stub_; |
|
|
|
@ -489,13 +494,22 @@ TEST_P(ClientCallbackEnd2endTest, RequestEchoServerCancel) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
struct ClientCancelInfo { |
|
|
|
|
bool cancel{false}; |
|
|
|
|
int ops_before_cancel; |
|
|
|
|
ClientCancelInfo() : cancel{false} {} |
|
|
|
|
// Allow the single-op version to be non-explicit for ease of use
|
|
|
|
|
ClientCancelInfo(int ops) : cancel{true}, ops_before_cancel{ops} {} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
class WriteClient : public grpc::experimental::ClientWriteReactor<EchoRequest> { |
|
|
|
|
public: |
|
|
|
|
WriteClient(grpc::testing::EchoTestService::Stub* stub, |
|
|
|
|
ServerTryCancelRequestPhase server_try_cancel, |
|
|
|
|
int num_msgs_to_send) |
|
|
|
|
int num_msgs_to_send, ClientCancelInfo client_cancel = {}) |
|
|
|
|
: server_try_cancel_(server_try_cancel), |
|
|
|
|
num_msgs_to_send_(num_msgs_to_send) { |
|
|
|
|
num_msgs_to_send_(num_msgs_to_send), |
|
|
|
|
client_cancel_{client_cancel} { |
|
|
|
|
grpc::string msg{"Hello server."}; |
|
|
|
|
for (int i = 0; i < num_msgs_to_send; i++) { |
|
|
|
|
desired_ += msg; |
|
|
|
@ -512,13 +526,17 @@ class WriteClient : public grpc::experimental::ClientWriteReactor<EchoRequest> { |
|
|
|
|
MaybeWrite(); |
|
|
|
|
} |
|
|
|
|
void OnWriteDone(bool ok) override { |
|
|
|
|
num_msgs_sent_++; |
|
|
|
|
if (ok) { |
|
|
|
|
num_msgs_sent_++; |
|
|
|
|
MaybeWrite(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
void OnDone(const Status& s) override { |
|
|
|
|
gpr_log(GPR_INFO, "Sent %d messages", num_msgs_sent_); |
|
|
|
|
int num_to_send = |
|
|
|
|
(client_cancel_.cancel) |
|
|
|
|
? std::min(num_msgs_to_send_, client_cancel_.ops_before_cancel) |
|
|
|
|
: num_msgs_to_send_; |
|
|
|
|
switch (server_try_cancel_) { |
|
|
|
|
case CANCEL_BEFORE_PROCESSING: |
|
|
|
|
case CANCEL_DURING_PROCESSING: |
|
|
|
@ -526,19 +544,19 @@ class WriteClient : public grpc::experimental::ClientWriteReactor<EchoRequest> { |
|
|
|
|
// client, it means that the client most likely did not get a chance to
|
|
|
|
|
// send all the messages it wanted to send. i.e num_msgs_sent <=
|
|
|
|
|
// num_msgs_to_send
|
|
|
|
|
EXPECT_LE(num_msgs_sent_, num_msgs_to_send_); |
|
|
|
|
EXPECT_LE(num_msgs_sent_, num_to_send); |
|
|
|
|
break; |
|
|
|
|
case DO_NOT_CANCEL: |
|
|
|
|
case CANCEL_AFTER_PROCESSING: |
|
|
|
|
// If the RPC was not canceled or canceled after all messages were read
|
|
|
|
|
// by the server, the client did get a chance to send all its messages
|
|
|
|
|
EXPECT_EQ(num_msgs_sent_, num_msgs_to_send_); |
|
|
|
|
EXPECT_EQ(num_msgs_sent_, num_to_send); |
|
|
|
|
break; |
|
|
|
|
default: |
|
|
|
|
assert(false); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
if (server_try_cancel_ == DO_NOT_CANCEL) { |
|
|
|
|
if ((server_try_cancel_ == DO_NOT_CANCEL) && !client_cancel_.cancel) { |
|
|
|
|
EXPECT_TRUE(s.ok()); |
|
|
|
|
EXPECT_EQ(response_.message(), desired_); |
|
|
|
|
} else { |
|
|
|
@ -558,7 +576,10 @@ class WriteClient : public grpc::experimental::ClientWriteReactor<EchoRequest> { |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
void MaybeWrite() { |
|
|
|
|
if (num_msgs_to_send_ > num_msgs_sent_ + 1) { |
|
|
|
|
if (client_cancel_.cancel && |
|
|
|
|
num_msgs_sent_ == client_cancel_.ops_before_cancel) { |
|
|
|
|
context_.TryCancel(); |
|
|
|
|
} else if (num_msgs_to_send_ > num_msgs_sent_ + 1) { |
|
|
|
|
StartWrite(&request_); |
|
|
|
|
} else if (num_msgs_to_send_ == num_msgs_sent_ + 1) { |
|
|
|
|
StartWriteLast(&request_, WriteOptions()); |
|
|
|
@ -571,6 +592,7 @@ class WriteClient : public grpc::experimental::ClientWriteReactor<EchoRequest> { |
|
|
|
|
int num_msgs_sent_{0}; |
|
|
|
|
const int num_msgs_to_send_; |
|
|
|
|
grpc::string desired_; |
|
|
|
|
const ClientCancelInfo client_cancel_; |
|
|
|
|
std::mutex mu_; |
|
|
|
|
std::condition_variable cv_; |
|
|
|
|
bool done_ = false; |
|
|
|
@ -627,8 +649,9 @@ TEST_P(ClientCallbackEnd2endTest, RequestStreamServerCancelAfterReads) { |
|
|
|
|
class ReadClient : public grpc::experimental::ClientReadReactor<EchoResponse> { |
|
|
|
|
public: |
|
|
|
|
ReadClient(grpc::testing::EchoTestService::Stub* stub, |
|
|
|
|
ServerTryCancelRequestPhase server_try_cancel) |
|
|
|
|
: server_try_cancel_(server_try_cancel) { |
|
|
|
|
ServerTryCancelRequestPhase server_try_cancel, |
|
|
|
|
ClientCancelInfo client_cancel = {}) |
|
|
|
|
: server_try_cancel_(server_try_cancel), client_cancel_{client_cancel} { |
|
|
|
|
if (server_try_cancel_ != DO_NOT_CANCEL) { |
|
|
|
|
// Send server_try_cancel value in the client metadata
|
|
|
|
|
context_.AddMetadata(kServerTryCancelRequest, |
|
|
|
@ -636,12 +659,18 @@ class ReadClient : public grpc::experimental::ClientReadReactor<EchoResponse> { |
|
|
|
|
} |
|
|
|
|
request_.set_message("Hello client "); |
|
|
|
|
stub->experimental_async()->ResponseStream(&context_, &request_, this); |
|
|
|
|
if (client_cancel_.cancel && |
|
|
|
|
reads_complete_ == client_cancel_.ops_before_cancel) { |
|
|
|
|
context_.TryCancel(); |
|
|
|
|
} |
|
|
|
|
// Even if we cancel, read until failure because there might be responses
|
|
|
|
|
// pending
|
|
|
|
|
StartRead(&response_); |
|
|
|
|
StartCall(); |
|
|
|
|
} |
|
|
|
|
void OnReadDone(bool ok) override { |
|
|
|
|
if (!ok) { |
|
|
|
|
if (server_try_cancel_ == DO_NOT_CANCEL) { |
|
|
|
|
if (server_try_cancel_ == DO_NOT_CANCEL && !client_cancel_.cancel) { |
|
|
|
|
EXPECT_EQ(reads_complete_, kServerDefaultResponseStreamsToSend); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
@ -649,6 +678,12 @@ class ReadClient : public grpc::experimental::ClientReadReactor<EchoResponse> { |
|
|
|
|
EXPECT_EQ(response_.message(), |
|
|
|
|
request_.message() + grpc::to_string(reads_complete_)); |
|
|
|
|
reads_complete_++; |
|
|
|
|
if (client_cancel_.cancel && |
|
|
|
|
reads_complete_ == client_cancel_.ops_before_cancel) { |
|
|
|
|
context_.TryCancel(); |
|
|
|
|
} |
|
|
|
|
// Even if we cancel, read until failure because there might be responses
|
|
|
|
|
// pending
|
|
|
|
|
StartRead(&response_); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -656,8 +691,19 @@ class ReadClient : public grpc::experimental::ClientReadReactor<EchoResponse> { |
|
|
|
|
gpr_log(GPR_INFO, "Read %d messages", reads_complete_); |
|
|
|
|
switch (server_try_cancel_) { |
|
|
|
|
case DO_NOT_CANCEL: |
|
|
|
|
EXPECT_TRUE(s.ok()); |
|
|
|
|
EXPECT_EQ(reads_complete_, kServerDefaultResponseStreamsToSend); |
|
|
|
|
if (!client_cancel_.cancel || client_cancel_.ops_before_cancel > |
|
|
|
|
kServerDefaultResponseStreamsToSend) { |
|
|
|
|
EXPECT_TRUE(s.ok()); |
|
|
|
|
EXPECT_EQ(reads_complete_, kServerDefaultResponseStreamsToSend); |
|
|
|
|
} else { |
|
|
|
|
EXPECT_GE(reads_complete_, client_cancel_.ops_before_cancel); |
|
|
|
|
EXPECT_LE(reads_complete_, kServerDefaultResponseStreamsToSend); |
|
|
|
|
// Status might be ok or cancelled depending on whether server
|
|
|
|
|
// sent status before client cancel went through
|
|
|
|
|
if (!s.ok()) { |
|
|
|
|
EXPECT_EQ(grpc::StatusCode::CANCELLED, s.error_code()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case CANCEL_BEFORE_PROCESSING: |
|
|
|
|
EXPECT_FALSE(s.ok()); |
|
|
|
@ -694,6 +740,7 @@ class ReadClient : public grpc::experimental::ClientReadReactor<EchoResponse> { |
|
|
|
|
ClientContext context_; |
|
|
|
|
const ServerTryCancelRequestPhase server_try_cancel_; |
|
|
|
|
int reads_complete_{0}; |
|
|
|
|
const ClientCancelInfo client_cancel_; |
|
|
|
|
std::mutex mu_; |
|
|
|
|
std::condition_variable cv_; |
|
|
|
|
bool done_ = false; |
|
|
|
@ -710,6 +757,15 @@ TEST_P(ClientCallbackEnd2endTest, ResponseStream) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TEST_P(ClientCallbackEnd2endTest, ClientCancelsResponseStream) { |
|
|
|
|
MAYBE_SKIP_TEST; |
|
|
|
|
ResetStub(); |
|
|
|
|
ReadClient test{stub_.get(), DO_NOT_CANCEL, 2}; |
|
|
|
|
test.Await(); |
|
|
|
|
// Because cancel in this case races with server finish, we can't be sure that
|
|
|
|
|
// server interceptors even see cancellation
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Server to cancel before sending any response messages
|
|
|
|
|
TEST_P(ClientCallbackEnd2endTest, ResponseStreamServerCancelBefore) { |
|
|
|
|
MAYBE_SKIP_TEST; |
|
|
|
@ -752,8 +808,10 @@ class BidiClient |
|
|
|
|
public: |
|
|
|
|
BidiClient(grpc::testing::EchoTestService::Stub* stub, |
|
|
|
|
ServerTryCancelRequestPhase server_try_cancel, |
|
|
|
|
int num_msgs_to_send) |
|
|
|
|
: server_try_cancel_(server_try_cancel), msgs_to_send_{num_msgs_to_send} { |
|
|
|
|
int num_msgs_to_send, ClientCancelInfo client_cancel = {}) |
|
|
|
|
: server_try_cancel_(server_try_cancel), |
|
|
|
|
msgs_to_send_{num_msgs_to_send}, |
|
|
|
|
client_cancel_{client_cancel} { |
|
|
|
|
if (server_try_cancel_ != DO_NOT_CANCEL) { |
|
|
|
|
// Send server_try_cancel value in the client metadata
|
|
|
|
|
context_.AddMetadata(kServerTryCancelRequest, |
|
|
|
@ -761,14 +819,18 @@ class BidiClient |
|
|
|
|
} |
|
|
|
|
request_.set_message("Hello fren "); |
|
|
|
|
stub->experimental_async()->BidiStream(&context_, this); |
|
|
|
|
MaybeWrite(); |
|
|
|
|
StartRead(&response_); |
|
|
|
|
StartWrite(&request_); |
|
|
|
|
StartCall(); |
|
|
|
|
} |
|
|
|
|
void OnReadDone(bool ok) override { |
|
|
|
|
if (!ok) { |
|
|
|
|
if (server_try_cancel_ == DO_NOT_CANCEL) { |
|
|
|
|
EXPECT_EQ(reads_complete_, msgs_to_send_); |
|
|
|
|
if (!client_cancel_.cancel) { |
|
|
|
|
EXPECT_EQ(reads_complete_, msgs_to_send_); |
|
|
|
|
} else { |
|
|
|
|
EXPECT_LE(reads_complete_, writes_complete_); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
EXPECT_LE(reads_complete_, msgs_to_send_); |
|
|
|
@ -783,20 +845,25 @@ class BidiClient |
|
|
|
|
} else if (!ok) { |
|
|
|
|
return; |
|
|
|
|
} |
|
|
|
|
if (++writes_complete_ == msgs_to_send_) { |
|
|
|
|
StartWritesDone(); |
|
|
|
|
} else { |
|
|
|
|
StartWrite(&request_); |
|
|
|
|
} |
|
|
|
|
writes_complete_++; |
|
|
|
|
MaybeWrite(); |
|
|
|
|
} |
|
|
|
|
void OnDone(const Status& s) override { |
|
|
|
|
gpr_log(GPR_INFO, "Sent %d messages", writes_complete_); |
|
|
|
|
gpr_log(GPR_INFO, "Read %d messages", reads_complete_); |
|
|
|
|
switch (server_try_cancel_) { |
|
|
|
|
case DO_NOT_CANCEL: |
|
|
|
|
EXPECT_TRUE(s.ok()); |
|
|
|
|
EXPECT_EQ(writes_complete_, msgs_to_send_); |
|
|
|
|
EXPECT_EQ(reads_complete_, writes_complete_); |
|
|
|
|
if (!client_cancel_.cancel || |
|
|
|
|
client_cancel_.ops_before_cancel > msgs_to_send_) { |
|
|
|
|
EXPECT_TRUE(s.ok()); |
|
|
|
|
EXPECT_EQ(writes_complete_, msgs_to_send_); |
|
|
|
|
EXPECT_EQ(reads_complete_, writes_complete_); |
|
|
|
|
} else { |
|
|
|
|
EXPECT_FALSE(s.ok()); |
|
|
|
|
EXPECT_EQ(grpc::StatusCode::CANCELLED, s.error_code()); |
|
|
|
|
EXPECT_EQ(writes_complete_, client_cancel_.ops_before_cancel); |
|
|
|
|
EXPECT_LE(reads_complete_, writes_complete_); |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case CANCEL_BEFORE_PROCESSING: |
|
|
|
|
EXPECT_FALSE(s.ok()); |
|
|
|
@ -837,6 +904,16 @@ class BidiClient |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
void MaybeWrite() { |
|
|
|
|
if (client_cancel_.cancel && |
|
|
|
|
writes_complete_ == client_cancel_.ops_before_cancel) { |
|
|
|
|
context_.TryCancel(); |
|
|
|
|
} else if (writes_complete_ == msgs_to_send_) { |
|
|
|
|
StartWritesDone(); |
|
|
|
|
} else { |
|
|
|
|
StartWrite(&request_); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
EchoRequest request_; |
|
|
|
|
EchoResponse response_; |
|
|
|
|
ClientContext context_; |
|
|
|
@ -844,6 +921,7 @@ class BidiClient |
|
|
|
|
int reads_complete_{0}; |
|
|
|
|
int writes_complete_{0}; |
|
|
|
|
const int msgs_to_send_; |
|
|
|
|
const ClientCancelInfo client_cancel_; |
|
|
|
|
std::mutex mu_; |
|
|
|
|
std::condition_variable cv_; |
|
|
|
|
bool done_ = false; |
|
|
|
@ -861,6 +939,18 @@ TEST_P(ClientCallbackEnd2endTest, BidiStream) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
TEST_P(ClientCallbackEnd2endTest, ClientCancelsBidiStream) { |
|
|
|
|
MAYBE_SKIP_TEST; |
|
|
|
|
ResetStub(); |
|
|
|
|
BidiClient test{stub_.get(), DO_NOT_CANCEL, |
|
|
|
|
kServerDefaultResponseStreamsToSend, 2}; |
|
|
|
|
test.Await(); |
|
|
|
|
// Make sure that the server interceptors were notified of a cancel
|
|
|
|
|
if (GetParam().use_interceptors) { |
|
|
|
|
EXPECT_EQ(20, DummyInterceptor::GetNumTimesCancel()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Server to cancel before reading/writing any requests/responses on the stream
|
|
|
|
|
TEST_P(ClientCallbackEnd2endTest, BidiStreamServerCancelBefore) { |
|
|
|
|
MAYBE_SKIP_TEST; |
|
|
|
|