Skip to content

Commit

Permalink
Merge github.com:grpc/grpc into direct-calls
Browse files Browse the repository at this point in the history
  • Loading branch information
ctiller committed Oct 13, 2016
2 parents 9381c00 + d44144c commit 272c8d2
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 0 deletions.
41 changes: 41 additions & 0 deletions doc/interop-test-descriptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,35 @@ Client asserts:
*It may be possible to use UnaryCall instead of EmptyCall, but it is harder to
ensure that the proto serialized to zero bytes.*

### cacheable_unary

This test verifies that gRPC requests marked as cacheable use GET verb instead
of POST, and that server sets appropriate cache control headers for the response
to be cached by a proxy. This test requires that the server is behind
a caching proxy. Use of current timestamp in the request prevents accidental
cache matches left over from previous tests.

Server features:
* [CacheableUnaryCall][]

Procedure:
1. Client calls CacheableUnaryCall with `SimpleRequest` request with payload
set to current timestamp. Timestamp format is irrelevant, and resolution is
in nanoseconds.
Client adds a `x-user-ip` header with value `1.2.3.4` to the request.
This is done since some proxys such as GFE will not cache requests from
localhost.
Client marks the request as cacheable by setting the cacheable flag in the
request context. Longer term this should be driven by the method option
specified in the proto file itself.
2. Client calls CacheableUnaryCall with `SimpleRequest` request again
immediately with the same payload as the previous request. Cacheable flag is
also set for this request's context.

Client asserts:
* Both calls were successful
* The payload body of both responses is the same.

### large_unary

This test verifies unary calls succeed in sending messages, and touches on flow
Expand Down Expand Up @@ -941,6 +970,18 @@ payload body of size `SimpleRequest.response_size` bytes and type as appropriate
for the `SimpleRequest.response_type`. If the server does not support the
`response_type`, then it should fail the RPC with `INVALID_ARGUMENT`.
### CacheableUnaryCall
Server gets the default SimpleRequest proto as the request. The content of the
request is ignored. It returns the SimpleResponse proto with the payload set
to current timestamp. The timestamp is an integer representing current time
with nanosecond resolution. This integer is formated as ASCII decimal in the
response. The format is not really important as long as the response payload
is different for each request. In addition it adds
1. cache control headers such that the response can be cached by proxies in
the response path. Server should be behind a caching proxy for this test
to pass. Currently we set the max-age to 60 seconds.
### CompressedResponse
[CompressedResponse]: #compressedresponse
Expand Down
5 changes: 5 additions & 0 deletions src/proto/grpc/testing/test.proto
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ service TestService {
// One request followed by one response.
rpc UnaryCall(SimpleRequest) returns (SimpleResponse);

// One request followed by one response. Response has cache control
// headers set such that a caching HTTP proxy (such as GFE) can
// satisfy subsequent requests.
rpc CacheableUnaryCall(SimpleRequest) returns (SimpleResponse);

// One request followed by a sequence of responses (streamed download).
// The server returns the payload with client desired type and sizes.
rpc StreamingOutputCall(StreamingOutputCallRequest)
Expand Down
4 changes: 4 additions & 0 deletions test/cpp/interop/client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ int main(int argc, char** argv) {
client.DoStatusWithMessage();
} else if (FLAGS_test_case == "custom_metadata") {
client.DoCustomMetadata();
} else if (FLAGS_test_case == "cacheable_unary") {
client.DoCacheableUnary();
} else if (FLAGS_test_case == "all") {
client.DoEmpty();
client.DoLargeUnary();
Expand All @@ -166,6 +168,7 @@ int main(int argc, char** argv) {
client.DoEmptyStream();
client.DoStatusWithMessage();
client.DoCustomMetadata();
client.DoCacheableUnary();
// service_account_creds and jwt_token_creds can only run with ssl.
if (FLAGS_use_tls) {
grpc::string json_key = GetServiceAccountJsonKey();
Expand All @@ -177,6 +180,7 @@ int main(int argc, char** argv) {
// compute_engine_creds only runs in GCE.
} else {
const char* testcases[] = {"all",
"cacheable_unary",
"cancel_after_begin",
"cancel_after_first_response",
"client_compressed_streaming",
Expand Down
44 changes: 44 additions & 0 deletions test/cpp/interop/interop_client.cc
Original file line number Diff line number Diff line change
Expand Up @@ -846,6 +846,50 @@ bool InteropClient::DoStatusWithMessage() {
return true;
}

bool InteropClient::DoCacheableUnary() {
gpr_log(GPR_DEBUG, "Sending RPC with cacheable response");

// Create request with current timestamp
gpr_timespec ts = gpr_now(GPR_CLOCK_PRECISE);
std::string timestamp = std::to_string((long long unsigned)ts.tv_nsec);
SimpleRequest request;
request.mutable_payload()->set_body(timestamp.c_str(), timestamp.size());

// Request 1
ClientContext context1;
SimpleResponse response1;
context1.set_cacheable(true);
// Add fake user IP since some proxy's (GFE) won't cache requests from
// localhost.
context1.AddMetadata("x-user-ip", "1.2.3.4");
Status s1 =
serviceStub_.Get()->CacheableUnaryCall(&context1, request, &response1);
if (!AssertStatusOk(s1)) {
return false;
}
gpr_log(GPR_DEBUG, "response 1 payload: %s",
response1.payload().body().c_str());

// Request 2
ClientContext context2;
SimpleResponse response2;
context2.set_cacheable(true);
context2.AddMetadata("x-user-ip", "1.2.3.4");
Status s2 =
serviceStub_.Get()->CacheableUnaryCall(&context2, request, &response2);
if (!AssertStatusOk(s2)) {
return false;
}
gpr_log(GPR_DEBUG, "response 2 payload: %s",
response2.payload().body().c_str());

// Check that the body is same for both requests. It will be the same if the
// second response is a cached copy of the first response
GPR_ASSERT(response2.payload().body() == response1.payload().body());

return true;
}

bool InteropClient::DoCustomMetadata() {
const grpc::string kEchoInitialMetadataKey("x-grpc-test-echo-initial");
const grpc::string kInitialMetadataValue("test_initial_metadata_value");
Expand Down
1 change: 1 addition & 0 deletions test/cpp/interop/interop_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class InteropClient {
bool DoEmptyStream();
bool DoStatusWithMessage();
bool DoCustomMetadata();
bool DoCacheableUnary();
// Auth tests.
// username is a string containing the user email
bool DoJwtTokenCreds(const grpc::string& username);
Expand Down
12 changes: 12 additions & 0 deletions test/cpp/interop/interop_server.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
#include <grpc/support/log.h>
#include <grpc/support/useful.h>

#include "src/core/lib/support/string.h"
#include "src/core/lib/transport/byte_stream.h"
#include "src/proto/grpc/testing/empty.grpc.pb.h"
#include "src/proto/grpc/testing/messages.grpc.pb.h"
Expand Down Expand Up @@ -153,6 +154,17 @@ class TestServiceImpl : public TestService::Service {
return Status::OK;
}

// Response contains current timestamp. We ignore everything in the request.
Status CacheableUnaryCall(ServerContext* context,
const SimpleRequest* request,
SimpleResponse* response) {
gpr_timespec ts = gpr_now(GPR_CLOCK_PRECISE);
std::string timestamp = std::to_string((long long unsigned)ts.tv_nsec);
response->mutable_payload()->set_body(timestamp.c_str(), timestamp.size());
context->AddInitialMetadata("cache-control", "max-age=60, public");
return Status::OK;
}

Status UnaryCall(ServerContext* context, const SimpleRequest* request,
SimpleResponse* response) {
MaybeEchoMetadata(context);
Expand Down

0 comments on commit 272c8d2

Please sign in to comment.