Merge github.com:grpc/grpc into tell-the-world-about-ALL-the-things

pull/2829/head
Craig Tiller 10 years ago
commit 26f8b283a4
  1. 131
      doc/interop-test-descriptions.md
  2. 30
      include/grpc++/channel_interface.h
  3. 6
      include/grpc++/stream.h
  4. 4
      src/core/channel/client_channel.c
  5. 40
      src/cpp/client/channel.cc
  6. 15
      src/cpp/client/channel.h
  7. 11
      src/objective-c/GRPCClient/GRPCCall+Tests.h
  8. 8
      src/objective-c/GRPCClient/GRPCCall+Tests.m
  9. 39
      src/objective-c/GRPCClient/private/GRPCHost.m
  10. 7
      src/objective-c/tests/GRPCClientTests.m
  11. 2
      src/objective-c/tests/InteropTests.h
  12. 10
      src/objective-c/tests/InteropTests.m
  13. 2
      templates/tools/run_tests/tests.json.template
  14. 24
      test/core/end2end/fixtures/chttp2_simple_ssl_fullstack_with_proxy.c
  15. 4
      test/core/end2end/fixtures/chttp2_socket_pair_with_grpc_trace.c
  16. 28
      test/core/end2end/gen_build_json.py
  17. 4
      test/core/end2end/tests/request_response_with_payload_and_call_creds.c
  18. 24
      test/cpp/end2end/end2end_test.cc
  19. 5
      tools/buildgen/plugins/expand_bin_attrs.py
  20. 6
      tools/run_tests/run_tests.py
  21. 4129
      tools/run_tests/tests.json

@ -55,7 +55,7 @@ Server features:
Procedure: Procedure:
1. Client calls EmptyCall with the default Empty message 1. Client calls EmptyCall with the default Empty message
Asserts: Client asserts:
* call was successful * call was successful
* response is non-null * response is non-null
@ -84,7 +84,7 @@ Procedure:
} }
``` ```
Asserts: Client asserts:
* call was successful * call was successful
* response payload type is COMPRESSABLE * response payload type is COMPRESSABLE
* response payload body is 314159 bytes in size * response payload body is 314159 bytes in size
@ -110,6 +110,7 @@ Procedure:
} }
} }
``` ```
3. Client then sends: 3. Client then sends:
``` ```
@ -119,6 +120,7 @@ Procedure:
} }
} }
``` ```
4. Client then sends: 4. Client then sends:
``` ```
@ -128,6 +130,7 @@ Procedure:
} }
} }
``` ```
5. Client then sends: 5. Client then sends:
``` ```
@ -137,9 +140,10 @@ Procedure:
} }
} }
``` ```
6. Client halfCloses
Asserts: 6. Client half-closes
Client asserts:
* call was successful * call was successful
* response aggregated_payload_size is 74922 * response aggregated_payload_size is 74922
@ -172,7 +176,7 @@ Procedure:
} }
``` ```
Asserts: Client asserts:
* call was successful * call was successful
* exactly four responses * exactly four responses
* response payloads are COMPRESSABLE * response payloads are COMPRESSABLE
@ -202,6 +206,7 @@ Procedure:
} }
} }
``` ```
2. After getting a reply, it sends: 2. After getting a reply, it sends:
``` ```
@ -215,6 +220,7 @@ Procedure:
} }
} }
``` ```
3. After getting a reply, it sends: 3. After getting a reply, it sends:
``` ```
@ -228,6 +234,7 @@ Procedure:
} }
} }
``` ```
4. After getting a reply, it sends: 4. After getting a reply, it sends:
``` ```
@ -242,7 +249,9 @@ Procedure:
} }
``` ```
Asserts: 5. After getting a reply, client half-closes
Client asserts:
* call was successful * call was successful
* exactly four responses * exactly four responses
* response payloads are COMPRESSABLE * response payloads are COMPRESSABLE
@ -261,7 +270,7 @@ Server features:
Procedure: Procedure:
1. Client calls FullDuplexCall and then half-closes 1. Client calls FullDuplexCall and then half-closes
Asserts: Client asserts:
* call was successful * call was successful
* exactly zero responses * exactly zero responses
@ -300,7 +309,7 @@ Procedure:
} }
``` ```
Asserts: Client asserts:
* call was successful * call was successful
* received SimpleResponse.username equals the value of `--default_service_account` flag * received SimpleResponse.username equals the value of `--default_service_account` flag
* received SimpleResponse.oauth_scope is in `--oauth_scope` * received SimpleResponse.oauth_scope is in `--oauth_scope`
@ -328,7 +337,7 @@ Server features:
* [Echo OAuth Scope][] * [Echo OAuth Scope][]
Procedure: Procedure:
1. Client configures the channel to use ServiceAccountCredentials. 1. Client configures the channel to use ServiceAccountCredentials
2. Client calls UnaryCall with: 2. Client calls UnaryCall with:
``` ```
@ -343,7 +352,7 @@ Procedure:
} }
``` ```
Asserts: Client asserts:
* call was successful * call was successful
* received SimpleResponse.username is in the json key file read from * received SimpleResponse.username is in the json key file read from
`--service_account_key_file` `--service_account_key_file`
@ -370,7 +379,7 @@ Server features:
* [Echo OAuth Scope][] * [Echo OAuth Scope][]
Procedure: Procedure:
1. Client configures the channel to use JWTTokenCredentials. 1. Client configures the channel to use JWTTokenCredentials
2. Client calls UnaryCall with: 2. Client calls UnaryCall with:
``` ```
@ -384,7 +393,7 @@ Procedure:
} }
``` ```
Asserts: Client asserts:
* call was successful * call was successful
* received SimpleResponse.username is in the json key file read from * received SimpleResponse.username is in the json key file read from
`--service_account_key_file` `--service_account_key_file`
@ -422,7 +431,7 @@ Server features:
Procedure: Procedure:
1. Client uses the auth library to obtain an authorization token 1. Client uses the auth library to obtain an authorization token
2. Client configures the channel to use AccessTokenCredentials with the access token obtained in step 1. 2. Client configures the channel to use AccessTokenCredentials with the access token obtained in step 1
3. Client calls UnaryCall with the following message 3. Client calls UnaryCall with the following message
``` ```
@ -431,8 +440,8 @@ Procedure:
fill_oauth_scope: true fill_oauth_scope: true
} }
``` ```
Asserts: Client asserts:
* call was successful * call was successful
* received SimpleResponse.username is in the json key file used by the auth * received SimpleResponse.username is in the json key file used by the auth
library to obtain the authorization token library to obtain the authorization token
@ -464,10 +473,10 @@ Server features:
Procedure: Procedure:
1. Client uses the auth library to obtain an authorization token 1. Client uses the auth library to obtain an authorization token
2. Client configures the channel with just SSL credentials. 2. Client configures the channel with just SSL credentials
3. Client calls UnaryCall, setting per-call credentials to 3. Client calls UnaryCall, setting per-call credentials to
AccessTokenCredentials with the access token obtained in step 1. The request is AccessTokenCredentials with the access token obtained in step 1. The request
the following message is the following message
``` ```
{ {
@ -475,8 +484,8 @@ Procedure:
fill_oauth_scope: true fill_oauth_scope: true
} }
``` ```
Asserts: Client asserts:
* call was successful * call was successful
* received SimpleResponse.username is in the json key file used by the auth * received SimpleResponse.username is in the json key file used by the auth
library to obtain the authorization token library to obtain the authorization token
@ -496,8 +505,14 @@ Server features:
* [Echo Metadata][] * [Echo Metadata][]
Procedure: Procedure:
1. While sending custom metadata (ascii + binary) in the header, client calls 1. The client attaches custom metadata with the following keys and values:
UnaryCall with:
```
key: "x-grpc-test-echo-initial", value: "test_initial_metadata_value"
key: "x-grpc-test-echo-trailing-bin", value: 0xababab
```
to a UnaryCall with request:
``` ```
{ {
@ -508,23 +523,41 @@ Procedure:
} }
} }
``` ```
The client attaches custom metadata with the following keys and values:
2. The client attaches custom metadata with the following keys and values:
``` ```
key: "x-grpc-test-echo-initial", value: "test_initial_metadata_value" key: "x-grpc-test-echo-initial", value: "test_initial_metadata_value"
key: "x-grpc-test-echo-trailing-bin", value: 0xababab key: "x-grpc-test-echo-trailing-bin", value: 0xababab
``` ```
2. Client repeats step 1. with FullDuplexCall instead of UnaryCall.
Asserts: to a FullDuplexCall with request:
```
{
response_type: COMPRESSABLE
response_size: 314159
payload:{
body: 271828 bytes of zeros
}
}
```
and then half-closes
Client asserts:
* call was successful * call was successful
* metadata with key `"x-grpc-test-echo-initial"` and value `"test_initial_metadata_value"`is received in the initial metadata. * metadata with key `"x-grpc-test-echo-initial"` and value
* metadata with key `"x-grpc-test-echo-trailing-bin"` and value `0xababab` is received in the trailing metadata. `"test_initial_metadata_value"`is received in the initial metadata for calls
in Procedure steps 1 and 2.
* metadata with key `"x-grpc-test-echo-trailing-bin"` and value `0xababab` is
received in the trailing metadata for calls in Procedure steps 1 and 2.
### status_code_and_message ### status_code_and_message
This test verifies unary calls succeed in sending messages, and propagates back This test verifies unary calls succeed in sending messages, and propagate back
status code and message sent along with the messages. status code and message sent along with the messages.
Server features: Server features:
@ -543,12 +576,26 @@ Procedure:
} }
} }
``` ```
2. Client repeats step 1. with FullDuplexCall instead of UnaryCall.
2. Client calls FullDuplexCall with:
```
{
response_status:{
code: 2
message: "test status message"
}
}
```
and then half-closes
Asserts:
* received status code is the same with sent code Client asserts:
* received status message is the same with sent message * received status code is the same as the sent code for both Procedure steps 1
and 2
* received status message is the same as the sent message for both Procedure
steps 1 and 2
### unimplemented_method ### unimplemented_method
@ -556,15 +603,19 @@ Status: Ready for implementation. Blocking beta.
This test verifies calling unimplemented RPC method returns the UNIMPLEMENTED status code. This test verifies calling unimplemented RPC method returns the UNIMPLEMENTED status code.
Server features:
N/A
Procedure: Procedure:
* Client calls `grpc.testing.UnimplementedService/UnimplementedCall` with an empty request (defined as `grpc.testing.Empty`): * Client calls `grpc.testing.UnimplementedService/UnimplementedCall` with an
empty request (defined as `grpc.testing.Empty`):
``` ```
{ {
} }
``` ```
Asserts: Client asserts:
* received status code is 12 (UNIMPLEMENTED) * received status code is 12 (UNIMPLEMENTED)
* received status message is empty or null/unset * received status message is empty or null/unset
@ -580,7 +631,7 @@ Procedure:
1. Client starts StreamingInputCall 1. Client starts StreamingInputCall
2. Client immediately cancels request 2. Client immediately cancels request
Asserts: Client asserts:
* Call completed with status CANCELLED * Call completed with status CANCELLED
### cancel_after_first_response ### cancel_after_first_response
@ -606,9 +657,10 @@ Procedure:
} }
} }
``` ```
2. After receiving a response, client cancels request 2. After receiving a response, client cancels request
Asserts: Client asserts:
* Call completed with status CANCELLED * Call completed with status CANCELLED
### timeout_on_sleeping_server ### timeout_on_sleeping_server
@ -620,7 +672,8 @@ Server features:
* [FullDuplexCall][] * [FullDuplexCall][]
Procedure: Procedure:
1. Client calls FullDuplexCall with the following request and sets its timeout to 1ms. 1. Client calls FullDuplexCall with the following request and sets its timeout
to 1ms
``` ```
{ {
@ -630,7 +683,9 @@ Procedure:
} }
``` ```
Asserts: 2. Client waits
Client asserts:
* Call completed with status DEADLINE_EXCEEDED. * Call completed with status DEADLINE_EXCEEDED.
### concurrent_large_unary ### concurrent_large_unary

@ -36,6 +36,7 @@
#include <memory> #include <memory>
#include <grpc/grpc.h>
#include <grpc++/status.h> #include <grpc++/status.h>
#include <grpc++/impl/call.h> #include <grpc++/impl/call.h>
@ -47,7 +48,6 @@ class CallOpBuffer;
class ClientContext; class ClientContext;
class CompletionQueue; class CompletionQueue;
class RpcMethod; class RpcMethod;
class CallInterface;
class ChannelInterface : public CallHook, class ChannelInterface : public CallHook,
public std::enable_shared_from_this<ChannelInterface> { public std::enable_shared_from_this<ChannelInterface> {
@ -57,6 +57,34 @@ class ChannelInterface : public CallHook,
virtual void* RegisterMethod(const char* method_name) = 0; virtual void* RegisterMethod(const char* method_name) = 0;
virtual Call CreateCall(const RpcMethod& method, ClientContext* context, virtual Call CreateCall(const RpcMethod& method, ClientContext* context,
CompletionQueue* cq) = 0; CompletionQueue* cq) = 0;
// Get the current channel state. If the channel is in IDLE and try_to_connect
// is set to true, try to connect.
virtual grpc_connectivity_state GetState(bool try_to_connect) = 0;
// Return the tag on cq when the channel state is changed or deadline expires.
// GetState needs to called to get the current state.
template <typename T>
void NotifyOnStateChange(grpc_connectivity_state last_observed, T deadline,
CompletionQueue* cq, void* tag) {
TimePoint<T> deadline_tp(deadline);
NotifyOnStateChangeImpl(last_observed, deadline_tp.raw_time(), cq, tag);
}
// Blocking wait for channel state change or deadline expiration.
// GetState needs to called to get the current state.
template <typename T>
bool WaitForStateChange(grpc_connectivity_state last_observed, T deadline) {
TimePoint<T> deadline_tp(deadline);
return WaitForStateChangeImpl(last_observed, deadline_tp.raw_time());
}
private:
virtual void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline,
CompletionQueue* cq, void* tag) = 0;
virtual bool WaitForStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline) = 0;
}; };
} // namespace grpc } // namespace grpc

@ -54,7 +54,11 @@ class ClientStreamingInterface {
// client side declares it has no more message to send, either implicitly or // client side declares it has no more message to send, either implicitly or
// by calling WritesDone, it needs to make sure there is no more message to // by calling WritesDone, it needs to make sure there is no more message to
// be received from the server, either implicitly or by getting a false from // be received from the server, either implicitly or by getting a false from
// a Read(). Otherwise, this implicitly cancels the stream. // a Read().
// This function will return either:
// - when all incoming messages have been read and the server has returned
// status
// - OR when the server has returned a non-OK status
virtual Status Finish() = 0; virtual Status Finish() = 0;
}; };

@ -401,6 +401,7 @@ static void perform_transport_stream_op(grpc_call_element *elem,
calld->state = CALL_WAITING_FOR_CONFIG; calld->state = CALL_WAITING_FOR_CONFIG;
add_to_lb_policy_wait_queue_locked_state_config(elem); add_to_lb_policy_wait_queue_locked_state_config(elem);
if (!chand->started_resolving && chand->resolver != NULL) { if (!chand->started_resolving && chand->resolver != NULL) {
GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver");
chand->started_resolving = 1; chand->started_resolving = 1;
grpc_resolver_next(chand->resolver, grpc_resolver_next(chand->resolver,
&chand->incoming_configuration, &chand->incoming_configuration,
@ -701,11 +702,11 @@ void grpc_client_channel_set_resolver(grpc_channel_stack *channel_stack,
gpr_mu_lock(&chand->mu_config); gpr_mu_lock(&chand->mu_config);
GPR_ASSERT(!chand->resolver); GPR_ASSERT(!chand->resolver);
chand->resolver = resolver; chand->resolver = resolver;
GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver");
GRPC_RESOLVER_REF(resolver, "channel"); GRPC_RESOLVER_REF(resolver, "channel");
if (chand->waiting_for_config_closures != NULL || if (chand->waiting_for_config_closures != NULL ||
chand->exit_idle_when_lb_policy_arrives) { chand->exit_idle_when_lb_policy_arrives) {
chand->started_resolving = 1; chand->started_resolving = 1;
GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver");
grpc_resolver_next(resolver, &chand->incoming_configuration, grpc_resolver_next(resolver, &chand->incoming_configuration,
&chand->on_config_changed); &chand->on_config_changed);
} }
@ -724,6 +725,7 @@ grpc_connectivity_state grpc_client_channel_check_connectivity_state(
} else { } else {
chand->exit_idle_when_lb_policy_arrives = 1; chand->exit_idle_when_lb_policy_arrives = 1;
if (!chand->started_resolving && chand->resolver != NULL) { if (!chand->started_resolving && chand->resolver != NULL) {
GRPC_CHANNEL_INTERNAL_REF(chand->master, "resolver");
chand->started_resolving = 1; chand->started_resolving = 1;
grpc_resolver_next(chand->resolver, &chand->incoming_configuration, grpc_resolver_next(chand->resolver, &chand->incoming_configuration,
&chand->on_config_changed); &chand->on_config_changed);

@ -48,6 +48,7 @@
#include <grpc++/impl/call.h> #include <grpc++/impl/call.h>
#include <grpc++/impl/rpc_method.h> #include <grpc++/impl/rpc_method.h>
#include <grpc++/status.h> #include <grpc++/status.h>
#include <grpc++/time.h>
namespace grpc { namespace grpc {
@ -95,4 +96,43 @@ void* Channel::RegisterMethod(const char* method) {
host_.empty() ? NULL : host_.c_str()); host_.empty() ? NULL : host_.c_str());
} }
grpc_connectivity_state Channel::GetState(bool try_to_connect) {
return grpc_channel_check_connectivity_state(c_channel_, try_to_connect);
}
namespace {
class TagSaver GRPC_FINAL : public CompletionQueueTag {
public:
explicit TagSaver(void* tag) : tag_(tag) {}
~TagSaver() GRPC_OVERRIDE {}
bool FinalizeResult(void** tag, bool* status) GRPC_OVERRIDE {
*tag = tag_;
delete this;
return true;
}
private:
void* tag_;
};
} // namespace
void Channel::NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline,
CompletionQueue* cq, void* tag) {
TagSaver* tag_saver = new TagSaver(tag);
grpc_channel_watch_connectivity_state(c_channel_, last_observed, deadline,
cq->cq(), tag_saver);
}
bool Channel::WaitForStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline) {
CompletionQueue cq;
bool ok = false;
void* tag = NULL;
NotifyOnStateChangeImpl(last_observed, deadline, &cq, NULL);
cq.Next(&tag, &ok);
GPR_ASSERT(tag == NULL);
return ok;
}
} // namespace grpc } // namespace grpc

@ -56,13 +56,22 @@ class Channel GRPC_FINAL : public GrpcLibrary, public ChannelInterface {
Channel(const grpc::string& host, grpc_channel* c_channel); Channel(const grpc::string& host, grpc_channel* c_channel);
~Channel() GRPC_OVERRIDE; ~Channel() GRPC_OVERRIDE;
virtual void* RegisterMethod(const char* method) GRPC_OVERRIDE; void* RegisterMethod(const char* method) GRPC_OVERRIDE;
virtual Call CreateCall(const RpcMethod& method, ClientContext* context, Call CreateCall(const RpcMethod& method, ClientContext* context,
CompletionQueue* cq) GRPC_OVERRIDE; CompletionQueue* cq) GRPC_OVERRIDE;
virtual void PerformOpsOnCall(CallOpSetInterface* ops, void PerformOpsOnCall(CallOpSetInterface* ops,
Call* call) GRPC_OVERRIDE; Call* call) GRPC_OVERRIDE;
grpc_connectivity_state GetState(bool try_to_connect) GRPC_OVERRIDE;
private: private:
void NotifyOnStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline, CompletionQueue* cq,
void* tag) GRPC_OVERRIDE;
bool WaitForStateChangeImpl(grpc_connectivity_state last_observed,
gpr_timespec deadline) GRPC_OVERRIDE;
const grpc::string host_; const grpc::string host_;
grpc_channel* const c_channel_; // owned grpc_channel* const c_channel_; // owned
}; };

@ -33,13 +33,22 @@
#import "GRPCCall.h" #import "GRPCCall.h"
// Methods to let tune down the security of gRPC connections for specific hosts. These shouldn't be
// used in releases, but are sometimes needed for testing.
@interface GRPCCall (Tests) @interface GRPCCall (Tests)
// Establish all SSL connections to the provided host using the passed SSL target name and the root // Establish all SSL connections to the provided host using the passed SSL target name and the root
// certificates found in the file at |certsPath|. // certificates found in the file at |certsPath|.
// Must be called before any gRPC call to that host is made. //
// Must be called before any gRPC call to that host is made. It's illegal to pass the same host to
// more than one invocation of the methods of this category.
+ (void)useTestCertsPath:(NSString *)certsPath + (void)useTestCertsPath:(NSString *)certsPath
testName:(NSString *)testName testName:(NSString *)testName
forHost:(NSString *)host; forHost:(NSString *)host;
// Establish all connections to the provided host using cleartext instead of SSL.
//
// Must be called before any gRPC call to that host is made. It's illegal to pass the same host to
// more than one invocation of the methods of this category.
+ (void)useInsecureConnectionsForHost:(NSString *)host;
@end @end

@ -36,12 +36,18 @@
#import "private/GRPCHost.h" #import "private/GRPCHost.h"
@implementation GRPCCall (Tests) @implementation GRPCCall (Tests)
+ (void)useTestCertsPath:(NSString *)certsPath + (void)useTestCertsPath:(NSString *)certsPath
testName:(NSString *)testName testName:(NSString *)testName
forHost:(NSString *)host { forHost:(NSString *)host {
GRPCHost *hostConfig = [GRPCHost hostWithAddress:host]; GRPCHost *hostConfig = [GRPCHost hostWithAddress:host];
hostConfig.secure = YES;
hostConfig.pathToCertificates = certsPath; hostConfig.pathToCertificates = certsPath;
hostConfig.hostNameOverride = testName; hostConfig.hostNameOverride = testName;
} }
+ (void)useInsecureConnectionsForHost:(NSString *)host {
GRPCHost *hostConfig = [GRPCHost hostWithAddress:host];
hostConfig.secure = NO;
}
@end @end

@ -58,22 +58,14 @@
// Default initializer. // Default initializer.
- (instancetype)initWithAddress:(NSString *)address { - (instancetype)initWithAddress:(NSString *)address {
// Verify and normalize the address, and decide whether to use SSL. // To provide a default port, we try to interpret the address. If it's just a host name without
if (![address rangeOfString:@"://"].length) { // scheme and without port, we'll use port 443. If it has a scheme, we pass it untouched to the C
// No scheme provided; assume https. // gRPC library.
address = [@"https://" stringByAppendingString:address]; // TODO(jcanizales): Add unit tests for the types of addresses we want to let pass untouched.
NSURL *hostURL = [NSURL URLWithString:[@"https://" stringByAppendingString:address]];
if (hostURL && !hostURL.port) {
address = [hostURL.host stringByAppendingString:@":443"];
} }
NSURL *hostURL = [NSURL URLWithString:address];
if (!hostURL) {
[NSException raise:NSInvalidArgumentException format:@"Invalid URL: %@", address];
}
NSString *scheme = hostURL.scheme;
if (![scheme isEqualToString:@"https"] && ![scheme isEqualToString:@"http"]) {
[NSException raise:NSInvalidArgumentException format:@"URL scheme %@ isn't supported.", scheme];
}
// If the user didn't specify a port (hostURL.port is nil), provide a default one.
NSNumber *port = hostURL.port ?: [scheme isEqualToString:@"https"] ? @443 : @80;
address = [@[hostURL.host, port] componentsJoinedByString:@":"];
// Look up the GRPCHost in the cache. // Look up the GRPCHost in the cache.
static NSMutableDictionary *hostCache; static NSMutableDictionary *hostCache;
@ -84,19 +76,15 @@
@synchronized(hostCache) { @synchronized(hostCache) {
GRPCHost *cachedHost = hostCache[address]; GRPCHost *cachedHost = hostCache[address];
if (cachedHost) { if (cachedHost) {
// We could verify here that the cached host uses the same protocol that we're expecting. But
// creating non-SSL channels by adding "http://" to the address is going away (to make the use
// of insecure channels less subtle), so it's not worth it now.
return cachedHost; return cachedHost;
} }
if ((self = [super init])) { if ((self = [super init])) {
_address = address; _address = address;
_secure = [scheme isEqualToString:@"https"]; _secure = YES;
hostCache[address] = self; hostCache[address] = self;
}
return self;
} }
return self;
} }
- (grpc_call *)unmanagedCallWithPath:(NSString *)path completionQueue:(GRPCCompletionQueue *)queue { - (grpc_call *)unmanagedCallWithPath:(NSString *)path completionQueue:(GRPCCompletionQueue *)queue {
@ -131,4 +119,7 @@
return _hostNameOverride ?: _address; return _hostNameOverride ?: _address;
} }
// TODO(jcanizales): Don't let set |secure| to |NO| if |pathToCertificates| or |hostNameOverride|
// have been set. Don't let set either of the latter if |secure| has been set to |NO|.
@end @end

@ -35,6 +35,7 @@
#import <XCTest/XCTest.h> #import <XCTest/XCTest.h>
#import <GRPCClient/GRPCCall.h> #import <GRPCClient/GRPCCall.h>
#import <GRPCClient/GRPCCall+Tests.h>
#import <ProtoRPC/ProtoMethod.h> #import <ProtoRPC/ProtoMethod.h>
#import <RemoteTest/Messages.pbobjc.h> #import <RemoteTest/Messages.pbobjc.h>
#import <RxLibrary/GRXWriteable.h> #import <RxLibrary/GRXWriteable.h>
@ -43,8 +44,7 @@
// These are a few tests similar to InteropTests, but which use the generic gRPC client (GRPCCall) // These are a few tests similar to InteropTests, but which use the generic gRPC client (GRPCCall)
// rather than a generated proto library on top of it. // rather than a generated proto library on top of it.
// grpc-test.sandbox.google.com static NSString * const kHostAddress = @"localhost:5050";
static NSString * const kHostAddress = @"http://localhost:5050";
static NSString * const kPackage = @"grpc.testing"; static NSString * const kPackage = @"grpc.testing";
static NSString * const kService = @"TestService"; static NSString * const kService = @"TestService";
@ -58,6 +58,9 @@ static ProtoMethod *kUnaryCallMethod;
@implementation GRPCClientTests @implementation GRPCClientTests
- (void)setUp { - (void)setUp {
// Register test server as non-SSL.
[GRPCCall useInsecureConnectionsForHost:kHostAddress];
// This method isn't implemented by the remote server. // This method isn't implemented by the remote server.
kInexistentMethod = [[ProtoMethod alloc] initWithPackage:kPackage kInexistentMethod = [[ProtoMethod alloc] initWithPackage:kPackage
service:kService service:kService

@ -37,7 +37,7 @@
// https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md // https://github.com/grpc/grpc/blob/master/doc/interop-test-descriptions.md
@interface InteropTests : XCTestCase @interface InteropTests : XCTestCase
// Returns @"http://localhost:5050". // Returns @"localhost:5050".
// Override in a subclass to perform the same tests against a different address. // Override in a subclass to perform the same tests against a different address.
// For interop tests, use @"grpc-test.sandbox.google.com". // For interop tests, use @"grpc-test.sandbox.google.com".
+ (NSString *)host; + (NSString *)host;

@ -35,6 +35,7 @@
#include <grpc/status.h> #include <grpc/status.h>
#import <GRPCClient/GRPCCall+Tests.h>
#import <ProtoRPC/ProtoRPC.h> #import <ProtoRPC/ProtoRPC.h>
#import <RemoteTest/Empty.pbobjc.h> #import <RemoteTest/Empty.pbobjc.h>
#import <RemoteTest/Messages.pbobjc.h> #import <RemoteTest/Messages.pbobjc.h>
@ -75,15 +76,22 @@
} }
@end @end
#pragma mark Tests
static NSString * const kLocalCleartextHost = @"localhost:5050";
@implementation InteropTests { @implementation InteropTests {
RMTTestService *_service; RMTTestService *_service;
} }
+ (NSString *)host { + (NSString *)host {
return @"http://localhost:5050"; return kLocalCleartextHost;
} }
- (void)setUp { - (void)setUp {
// Register test server as non-SSL.
[GRPCCall useInsecureConnectionsForHost:kLocalCleartextHost];
_service = [[RMTTestService alloc] initWithHost:self.class.host]; _service = [[RMTTestService alloc] initWithHost:self.class.host];
} }

@ -5,8 +5,8 @@ import json
${json.dumps([{"name": tgt.name, ${json.dumps([{"name": tgt.name,
"language": tgt.language, "language": tgt.language,
"platforms": tgt.platforms, "platforms": tgt.platforms,
"ci_platforms": tgt.ci_platforms,
"flaky": tgt.flaky} "flaky": tgt.flaky}
for tgt in targets for tgt in targets
if tgt.get('run', True) and tgt.build == 'test'], if tgt.get('run', True) and tgt.build == 'test'],
sort_keys=True, indent=2)} sort_keys=True, indent=2)}

@ -96,6 +96,14 @@ static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack(
return f; return f;
} }
static void process_auth_failure(void *state, grpc_auth_context *ctx,
const grpc_metadata *md, size_t md_count,
grpc_process_auth_metadata_done_cb cb,
void *user_data) {
GPR_ASSERT(state == NULL);
cb(user_data, NULL, 0, 0);
}
static void chttp2_init_client_secure_fullstack(grpc_end2end_test_fixture *f, static void chttp2_init_client_secure_fullstack(grpc_end2end_test_fixture *f,
grpc_channel_args *client_args, grpc_channel_args *client_args,
grpc_credentials *creds) { grpc_credentials *creds) {
@ -139,12 +147,28 @@ static void chttp2_init_client_simple_ssl_secure_fullstack(
grpc_channel_args_destroy(new_client_args); grpc_channel_args_destroy(new_client_args);
} }
static int fail_server_auth_check(grpc_channel_args *server_args) {
size_t i;
if (server_args == NULL) return 0;
for (i = 0; i < server_args->num_args; i++) {
if (strcmp(server_args->args[i].key, FAIL_AUTH_CHECK_SERVER_ARG_NAME) ==
0) {
return 1;
}
}
return 0;
}
static void chttp2_init_server_simple_ssl_secure_fullstack( static void chttp2_init_server_simple_ssl_secure_fullstack(
grpc_end2end_test_fixture *f, grpc_channel_args *server_args) { grpc_end2end_test_fixture *f, grpc_channel_args *server_args) {
grpc_ssl_pem_key_cert_pair pem_cert_key_pair = {test_server1_key, grpc_ssl_pem_key_cert_pair pem_cert_key_pair = {test_server1_key,
test_server1_cert}; test_server1_cert};
grpc_server_credentials *ssl_creds = grpc_server_credentials *ssl_creds =
grpc_ssl_server_credentials_create(NULL, &pem_cert_key_pair, 1, 0); grpc_ssl_server_credentials_create(NULL, &pem_cert_key_pair, 1, 0);
if (fail_server_auth_check(server_args)) {
grpc_auth_metadata_processor processor = {process_auth_failure, NULL};
grpc_server_credentials_set_auth_metadata_processor(ssl_creds, processor);
}
chttp2_init_server_secure_fullstack(f, server_args, ssl_creds); chttp2_init_server_secure_fullstack(f, server_args, ssl_creds);
} }

@ -148,7 +148,11 @@ int main(int argc, char **argv) {
/* force tracing on, with a value to force many /* force tracing on, with a value to force many
code paths in trace.c to be taken */ code paths in trace.c to be taken */
gpr_setenv("GRPC_TRACE", "doesnt-exist,http,all"); gpr_setenv("GRPC_TRACE", "doesnt-exist,http,all");
#ifdef GPR_POSIX_SOCKET
g_fixture_slowdown_factor = isatty(STDOUT_FILENO) ? 10.0 : 1.0;
#else
g_fixture_slowdown_factor = 10.0; g_fixture_slowdown_factor = 10.0;
#endif
grpc_test_init(argc, argv); grpc_test_init(argc, argv);
grpc_init(); grpc_init();

@ -36,27 +36,27 @@ import simplejson
import collections import collections
FixtureOptions = collections.namedtuple('FixtureOptions', 'fullstack includes_proxy dns_resolver secure platforms') FixtureOptions = collections.namedtuple('FixtureOptions', 'fullstack includes_proxy dns_resolver secure platforms ci_mac')
default_unsecure_fixture_options = FixtureOptions(True, False, True, False, ['windows', 'linux', 'mac', 'posix']) default_unsecure_fixture_options = FixtureOptions(True, False, True, False, ['windows', 'linux', 'mac', 'posix'], True)
socketpair_unsecure_fixture_options = default_unsecure_fixture_options._replace(fullstack=False, dns_resolver=False) socketpair_unsecure_fixture_options = default_unsecure_fixture_options._replace(fullstack=False, dns_resolver=False)
default_secure_fixture_options = default_unsecure_fixture_options._replace(secure=True) default_secure_fixture_options = default_unsecure_fixture_options._replace(secure=True)
uds_fixture_options = default_unsecure_fixture_options._replace(dns_resolver=False, platforms=['linux', 'mac', 'posix']) uds_fixture_options = default_unsecure_fixture_options._replace(dns_resolver=False, platforms=['linux', 'mac', 'posix'])
# maps fixture name to whether it requires the security library # maps fixture name to whether it requires the security library
END2END_FIXTURES = { END2END_FIXTURES = {
'chttp2_fake_security': default_secure_fixture_options, 'chttp2_fake_security': default_secure_fixture_options._replace(ci_mac=False),
'chttp2_fullstack': default_unsecure_fixture_options, 'chttp2_fullstack': default_unsecure_fixture_options,
'chttp2_fullstack_compression': default_unsecure_fixture_options, 'chttp2_fullstack_compression': default_unsecure_fixture_options,
'chttp2_fullstack_uds_posix': uds_fixture_options, 'chttp2_fullstack_uds_posix': uds_fixture_options,
'chttp2_fullstack_uds_posix_with_poll': uds_fixture_options._replace(platforms=['linux']), 'chttp2_fullstack_uds_posix_with_poll': uds_fixture_options._replace(platforms=['linux']),
'chttp2_fullstack_with_poll': default_unsecure_fixture_options._replace(platforms=['linux']), 'chttp2_fullstack_with_poll': default_unsecure_fixture_options._replace(platforms=['linux']),
'chttp2_fullstack_with_proxy': default_unsecure_fixture_options._replace(includes_proxy=True), 'chttp2_fullstack_with_proxy': default_unsecure_fixture_options._replace(includes_proxy=True, ci_mac=False),
'chttp2_simple_ssl_fullstack': default_secure_fixture_options, 'chttp2_simple_ssl_fullstack': default_secure_fixture_options,
'chttp2_simple_ssl_fullstack_with_poll': default_secure_fixture_options._replace(platforms=['linux']), 'chttp2_simple_ssl_fullstack_with_poll': default_secure_fixture_options._replace(platforms=['linux']),
'chttp2_simple_ssl_fullstack_with_proxy': default_secure_fixture_options._replace(includes_proxy=True), 'chttp2_simple_ssl_fullstack_with_proxy': default_secure_fixture_options._replace(includes_proxy=True, ci_mac=False),
'chttp2_simple_ssl_with_oauth2_fullstack': default_secure_fixture_options, 'chttp2_simple_ssl_with_oauth2_fullstack': default_secure_fixture_options._replace(ci_mac=False),
'chttp2_socket_pair': socketpair_unsecure_fixture_options, 'chttp2_socket_pair': socketpair_unsecure_fixture_options._replace(ci_mac=False),
'chttp2_socket_pair_one_byte_at_a_time': socketpair_unsecure_fixture_options, 'chttp2_socket_pair_one_byte_at_a_time': socketpair_unsecure_fixture_options._replace(ci_mac=False),
'chttp2_socket_pair_with_grpc_trace': socketpair_unsecure_fixture_options, 'chttp2_socket_pair_with_grpc_trace': socketpair_unsecure_fixture_options,
} }
@ -115,6 +115,12 @@ def compatible(f, t):
return True return True
def without(l, e):
l = l[:]
l.remove(e)
return l
def main(): def main():
sec_deps = [ sec_deps = [
'end2end_certs', 'end2end_certs',
@ -173,6 +179,9 @@ def main():
'src': [], 'src': [],
'flaky': END2END_TESTS[t].flaky, 'flaky': END2END_TESTS[t].flaky,
'platforms': END2END_FIXTURES[f].platforms, 'platforms': END2END_FIXTURES[f].platforms,
'ci_platforms': (END2END_FIXTURES[f].platforms
if END2END_FIXTURES[f].ci_mac
else without(END2END_FIXTURES[f].platforms, 'mac')),
'deps': [ 'deps': [
'end2end_fixture_%s' % f, 'end2end_fixture_%s' % f,
'end2end_test_%s' % t] + sec_deps 'end2end_test_%s' % t] + sec_deps
@ -188,6 +197,9 @@ def main():
'src': [], 'src': [],
'flaky': END2END_TESTS[t].flaky, 'flaky': END2END_TESTS[t].flaky,
'platforms': END2END_FIXTURES[f].platforms, 'platforms': END2END_FIXTURES[f].platforms,
'ci_platforms': (END2END_FIXTURES[f].platforms
if END2END_FIXTURES[f].ci_mac
else without(END2END_FIXTURES[f].platforms, 'mac')),
'deps': [ 'deps': [
'end2end_fixture_%s' % f, 'end2end_fixture_%s' % f,
'end2end_test_%s' % t] + unsec_deps 'end2end_test_%s' % t] + unsec_deps

@ -400,8 +400,8 @@ static void test_request_with_server_rejecting_client_creds(
f = begin_test(config, "test_request_with_server_rejecting_client_creds", 1); f = begin_test(config, "test_request_with_server_rejecting_client_creds", 1);
cqv = cq_verifier_create(f.cq); cqv = cq_verifier_create(f.cq);
c = grpc_channel_create_call(f.client, f.cq, "/foo", "foo.test.google.fr", c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
deadline); "/foo", "foo.test.google.fr", deadline);
GPR_ASSERT(c); GPR_ASSERT(c);
creds = grpc_iam_credentials_create(iam_token, iam_selector); creds = grpc_iam_credentials_create(iam_token, iam_selector);

@ -869,7 +869,8 @@ TEST_P(End2endTest, HugeResponse) {
} }
namespace { namespace {
void ReaderThreadFunc(ClientReaderWriter<EchoRequest, EchoResponse>* stream, gpr_event *ev) { void ReaderThreadFunc(ClientReaderWriter<EchoRequest, EchoResponse>* stream,
gpr_event *ev) {
EchoResponse resp; EchoResponse resp;
gpr_event_set(ev, (void*)1); gpr_event_set(ev, (void*)1);
while (stream->Read(&resp)) { while (stream->Read(&resp)) {
@ -908,6 +909,27 @@ TEST_P(End2endTest, Peer) {
EXPECT_TRUE(CheckIsLocalhost(context.peer())); EXPECT_TRUE(CheckIsLocalhost(context.peer()));
} }
TEST_F(End2endTest, ChannelState) {
ResetStub(false);
// Start IDLE
EXPECT_EQ(GRPC_CHANNEL_IDLE, channel_->GetState(false));
// Did not ask to connect, no state change.
CompletionQueue cq;
std::chrono::system_clock::time_point deadline =
std::chrono::system_clock::now() + std::chrono::milliseconds(10);
channel_->NotifyOnStateChange(GRPC_CHANNEL_IDLE, deadline, &cq, NULL);
void* tag;
bool ok = true;
cq.Next(&tag, &ok);
EXPECT_FALSE(ok);
EXPECT_EQ(GRPC_CHANNEL_IDLE, channel_->GetState(true));
EXPECT_TRUE(channel_->WaitForStateChange(
GRPC_CHANNEL_IDLE, gpr_inf_future(GPR_CLOCK_REALTIME)));
EXPECT_EQ(GRPC_CHANNEL_CONNECTING, channel_->GetState(false));
}
INSTANTIATE_TEST_CASE_P(End2end, End2endTest, ::testing::Values(false, true)); INSTANTIATE_TEST_CASE_P(End2end, End2endTest, ::testing::Values(false, true));
} // namespace testing } // namespace testing

@ -44,8 +44,9 @@ def mako_plugin(dictionary):
""" """
targets = dictionary.get('targets') targets = dictionary.get('targets')
default_platforms = ['windows', 'posix', 'linux', 'mac']
for tgt in targets: for tgt in targets:
tgt['flaky'] = tgt.get('flaky', False) tgt['flaky'] = tgt.get('flaky', False)
tgt['platforms'] = sorted(tgt.get('platforms', ['windows', 'posix'])) tgt['platforms'] = sorted(tgt.get('platforms', default_platforms))
tgt['ci_platforms'] = sorted(tgt.get('ci_platforms', tgt['platforms']))

@ -127,10 +127,14 @@ class CLanguage(object):
for tgt in js for tgt in js
if tgt['language'] == test_lang and if tgt['language'] == test_lang and
platform_string() in tgt['platforms']] platform_string() in tgt['platforms']]
self.ci_binaries = [tgt
for tgt in js
if tgt['language'] == test_lang and
platform_string() in tgt['ci_platforms']]
def test_specs(self, config, travis): def test_specs(self, config, travis):
out = [] out = []
for target in self.binaries: for target in (self.ci_binaries if travis else self.binaries):
if travis and target['flaky']: if travis and target['flaky']:
continue continue
if self.platform == 'windows': if self.platform == 'windows':

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save