mirror of https://github.com/grpc/grpc.git
commit
ba5dc1b36b
142 changed files with 5171 additions and 584 deletions
@ -0,0 +1,26 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* Copyright 2017 gRPC authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef GRPC_CORE_LIB_IOMGR_GETHOSTNAME_H |
||||||
|
#define GRPC_CORE_LIB_IOMGR_GETHOSTNAME_H |
||||||
|
|
||||||
|
// Returns the hostname of the local machine.
|
||||||
|
// Caller takes ownership of result.
|
||||||
|
char *grpc_gethostname(); |
||||||
|
|
||||||
|
#endif /* GRPC_CORE_LIB_IOMGR_GETHOSTNAME_H */ |
@ -0,0 +1,27 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* Copyright 2017 gRPC authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "src/core/lib/iomgr/port.h" |
||||||
|
|
||||||
|
#ifdef GRPC_GETHOSTNAME_FALLBACK |
||||||
|
|
||||||
|
#include <stddef.h> |
||||||
|
|
||||||
|
char *grpc_gethostname() { return NULL; } |
||||||
|
|
||||||
|
#endif // GRPC_GETHOSTNAME_FALLBACK
|
@ -0,0 +1,37 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* Copyright 2017 gRPC authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "src/core/lib/iomgr/port.h" |
||||||
|
|
||||||
|
#ifdef GRPC_POSIX_HOST_NAME_MAX |
||||||
|
|
||||||
|
#include <limits.h> |
||||||
|
#include <unistd.h> |
||||||
|
|
||||||
|
#include <grpc/support/alloc.h> |
||||||
|
|
||||||
|
char *grpc_gethostname() { |
||||||
|
char *hostname = (char *)gpr_malloc(HOST_NAME_MAX); |
||||||
|
if (gethostname(hostname, HOST_NAME_MAX) != 0) { |
||||||
|
gpr_free(hostname); |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
return hostname; |
||||||
|
} |
||||||
|
|
||||||
|
#endif // GRPC_POSIX_HOST_NAME_MAX
|
@ -0,0 +1,37 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* Copyright 2017 gRPC authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "src/core/lib/iomgr/port.h" |
||||||
|
|
||||||
|
#ifdef GRPC_POSIX_SYSCONF |
||||||
|
|
||||||
|
#include <unistd.h> |
||||||
|
|
||||||
|
#include <grpc/support/alloc.h> |
||||||
|
|
||||||
|
char *grpc_gethostname() { |
||||||
|
size_t host_name_max = (size_t)sysconf(_SC_HOST_NAME_MAX); |
||||||
|
char *hostname = (char *)gpr_malloc(host_name_max); |
||||||
|
if (gethostname(hostname, host_name_max) != 0) { |
||||||
|
gpr_free(hostname); |
||||||
|
return NULL; |
||||||
|
} |
||||||
|
return hostname; |
||||||
|
} |
||||||
|
|
||||||
|
#endif // GRPC_POSIX_SYSCONF
|
@ -0,0 +1,40 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* Copyright 2015-2017 gRPC authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef GRPC_CORE_LIB_SURFACE_ALARM_INTERNAL_H |
||||||
|
#define GRPC_CORE_LIB_SURFACE_ALARM_INTERNAL_H |
||||||
|
|
||||||
|
#include <grpc/support/log.h> |
||||||
|
#include "src/core/lib/debug/trace.h" |
||||||
|
|
||||||
|
#ifndef NDEBUG |
||||||
|
|
||||||
|
extern grpc_tracer_flag grpc_trace_alarm_refcount; |
||||||
|
|
||||||
|
#define GRPC_ALARM_REF(a, reason) alarm_ref_dbg(a, reason, __FILE__, __LINE__) |
||||||
|
#define GRPC_ALARM_UNREF(a, reason) \ |
||||||
|
alarm_unref_dbg(a, reason, __FILE__, __LINE__) |
||||||
|
|
||||||
|
#else /* !defined(NDEBUG) */ |
||||||
|
|
||||||
|
#define GRPC_ALARM_REF(a, reason) alarm_ref(a) |
||||||
|
#define GRPC_ALARM_UNREF(a, reason) alarm_unref(a) |
||||||
|
|
||||||
|
#endif /* defined(NDEBUG) */ |
||||||
|
|
||||||
|
#endif /* GRPC_CORE_LIB_SURFACE_ALARM_INTERNAL_H */ |
@ -0,0 +1,64 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* Copyright 2017 gRPC authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "src/core/tsi/transport_security_grpc.h" |
||||||
|
|
||||||
|
/* This method creates a tsi_zero_copy_grpc_protector object. */ |
||||||
|
tsi_result tsi_handshaker_result_create_zero_copy_grpc_protector( |
||||||
|
const tsi_handshaker_result *self, size_t *max_output_protected_frame_size, |
||||||
|
tsi_zero_copy_grpc_protector **protector) { |
||||||
|
if (self == NULL || self->vtable == NULL || protector == NULL) { |
||||||
|
return TSI_INVALID_ARGUMENT; |
||||||
|
} |
||||||
|
if (self->vtable->create_zero_copy_grpc_protector == NULL) { |
||||||
|
return TSI_UNIMPLEMENTED; |
||||||
|
} |
||||||
|
return self->vtable->create_zero_copy_grpc_protector( |
||||||
|
self, max_output_protected_frame_size, protector); |
||||||
|
} |
||||||
|
|
||||||
|
/* --- tsi_zero_copy_grpc_protector common implementation. ---
|
||||||
|
|
||||||
|
Calls specific implementation after state/input validation. */ |
||||||
|
|
||||||
|
tsi_result tsi_zero_copy_grpc_protector_protect( |
||||||
|
tsi_zero_copy_grpc_protector *self, grpc_slice_buffer *unprotected_slices, |
||||||
|
grpc_slice_buffer *protected_slices) { |
||||||
|
if (self == NULL || self->vtable == NULL || unprotected_slices == NULL || |
||||||
|
protected_slices == NULL) { |
||||||
|
return TSI_INVALID_ARGUMENT; |
||||||
|
} |
||||||
|
if (self->vtable->protect == NULL) return TSI_UNIMPLEMENTED; |
||||||
|
return self->vtable->protect(self, unprotected_slices, protected_slices); |
||||||
|
} |
||||||
|
|
||||||
|
tsi_result tsi_zero_copy_grpc_protector_unprotect( |
||||||
|
tsi_zero_copy_grpc_protector *self, grpc_slice_buffer *protected_slices, |
||||||
|
grpc_slice_buffer *unprotected_slices) { |
||||||
|
if (self == NULL || self->vtable == NULL || protected_slices == NULL || |
||||||
|
unprotected_slices == NULL) { |
||||||
|
return TSI_INVALID_ARGUMENT; |
||||||
|
} |
||||||
|
if (self->vtable->unprotect == NULL) return TSI_UNIMPLEMENTED; |
||||||
|
return self->vtable->unprotect(self, protected_slices, unprotected_slices); |
||||||
|
} |
||||||
|
|
||||||
|
void tsi_zero_copy_grpc_protector_destroy(tsi_zero_copy_grpc_protector *self) { |
||||||
|
if (self == NULL) return; |
||||||
|
self->vtable->destroy(self); |
||||||
|
} |
@ -0,0 +1,80 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* Copyright 2017 gRPC authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef GRPC_CORE_TSI_TRANSPORT_SECURITY_GRPC_H |
||||||
|
#define GRPC_CORE_TSI_TRANSPORT_SECURITY_GRPC_H |
||||||
|
|
||||||
|
#include <grpc/slice_buffer.h> |
||||||
|
#include "src/core/tsi/transport_security.h" |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
extern "C" { |
||||||
|
#endif |
||||||
|
|
||||||
|
/* This method creates a tsi_zero_copy_grpc_protector object. It return TSI_OK
|
||||||
|
assuming there is no fatal error. |
||||||
|
The caller is responsible for destroying the protector. */ |
||||||
|
tsi_result tsi_handshaker_result_create_zero_copy_grpc_protector( |
||||||
|
const tsi_handshaker_result *self, size_t *max_output_protected_frame_size, |
||||||
|
tsi_zero_copy_grpc_protector **protector); |
||||||
|
|
||||||
|
/* -- tsi_zero_copy_grpc_protector object -- */ |
||||||
|
|
||||||
|
/* Outputs protected frames.
|
||||||
|
- unprotected_slices is the unprotected data to be protected. |
||||||
|
- protected_slices is the protected output frames. One or more frames |
||||||
|
may be produced in this protect function. |
||||||
|
- This method returns TSI_OK in case of success or a specific error code in |
||||||
|
case of failure. */ |
||||||
|
tsi_result tsi_zero_copy_grpc_protector_protect( |
||||||
|
tsi_zero_copy_grpc_protector *self, grpc_slice_buffer *unprotected_slices, |
||||||
|
grpc_slice_buffer *protected_slices); |
||||||
|
|
||||||
|
/* Outputs unprotected bytes.
|
||||||
|
- protected_slices is the bytes of protected frames. |
||||||
|
- unprotected_slices is the unprotected output data. |
||||||
|
- This method returns TSI_OK in case of success. Success includes cases where |
||||||
|
there is not enough data to output in which case unprotected_slices has 0 |
||||||
|
bytes. */ |
||||||
|
tsi_result tsi_zero_copy_grpc_protector_unprotect( |
||||||
|
tsi_zero_copy_grpc_protector *self, grpc_slice_buffer *protected_slices, |
||||||
|
grpc_slice_buffer *unprotected_slices); |
||||||
|
|
||||||
|
/* Destroys the tsi_zero_copy_grpc_protector object. */ |
||||||
|
void tsi_zero_copy_grpc_protector_destroy(tsi_zero_copy_grpc_protector *self); |
||||||
|
|
||||||
|
/* Base for tsi_zero_copy_grpc_protector implementations. */ |
||||||
|
typedef struct { |
||||||
|
tsi_result (*protect)(tsi_zero_copy_grpc_protector *self, |
||||||
|
grpc_slice_buffer *unprotected_slices, |
||||||
|
grpc_slice_buffer *protected_slices); |
||||||
|
tsi_result (*unprotect)(tsi_zero_copy_grpc_protector *self, |
||||||
|
grpc_slice_buffer *protected_slices, |
||||||
|
grpc_slice_buffer *unprotected_slices); |
||||||
|
void (*destroy)(tsi_zero_copy_grpc_protector *self); |
||||||
|
} tsi_zero_copy_grpc_protector_vtable; |
||||||
|
|
||||||
|
struct tsi_zero_copy_grpc_protector { |
||||||
|
const tsi_zero_copy_grpc_protector_vtable *vtable; |
||||||
|
}; |
||||||
|
|
||||||
|
#ifdef __cplusplus |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
#endif /* GRPC_CORE_TSI_TRANSPORT_SECURITY_GRPC_H */ |
@ -0,0 +1,23 @@ |
|||||||
|
# Copyright 2017 gRPC authors. |
||||||
|
# |
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
# you may not use this file except in compliance with the License. |
||||||
|
# You may obtain a copy of the License at |
||||||
|
# |
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
# |
||||||
|
# Unless required by applicable law or agreed to in writing, software |
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
# See the License for the specific language governing permissions and |
||||||
|
# limitations under the License. |
||||||
|
|
||||||
|
from grpc_testing._channel import _channel |
||||||
|
from grpc_testing._channel import _channel_state |
||||||
|
|
||||||
|
|
||||||
|
# descriptors is reserved for later use. |
||||||
|
# pylint: disable=unused-argument |
||||||
|
def testing_channel(descriptors, time): |
||||||
|
return _channel.TestingChannel(time, _channel_state.State()) |
||||||
|
# pylint: enable=unused-argument |
@ -0,0 +1,62 @@ |
|||||||
|
# Copyright 2017 gRPC authors. |
||||||
|
# |
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
# you may not use this file except in compliance with the License. |
||||||
|
# You may obtain a copy of the License at |
||||||
|
# |
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
# |
||||||
|
# Unless required by applicable law or agreed to in writing, software |
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
# See the License for the specific language governing permissions and |
||||||
|
# limitations under the License. |
||||||
|
|
||||||
|
import grpc_testing |
||||||
|
from grpc_testing._channel import _channel_rpc |
||||||
|
from grpc_testing._channel import _multi_callable |
||||||
|
|
||||||
|
|
||||||
|
# All serializer and deserializer parameters are not (yet) used by this |
||||||
|
# test infrastructure. |
||||||
|
# pylint: disable=unused-argument |
||||||
|
class TestingChannel(grpc_testing.Channel): |
||||||
|
|
||||||
|
def __init__(self, time, state): |
||||||
|
self._time = time |
||||||
|
self._state = state |
||||||
|
|
||||||
|
def subscribe(self, callback, try_to_connect=False): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
def unsubscribe(self, callback): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
def unary_unary( |
||||||
|
self, method, request_serializer=None, response_deserializer=None): |
||||||
|
return _multi_callable.UnaryUnary(method, self._state) |
||||||
|
|
||||||
|
def unary_stream( |
||||||
|
self, method, request_serializer=None, response_deserializer=None): |
||||||
|
return _multi_callable.UnaryStream(method, self._state) |
||||||
|
|
||||||
|
def stream_unary( |
||||||
|
self, method, request_serializer=None, response_deserializer=None): |
||||||
|
return _multi_callable.StreamUnary(method, self._state) |
||||||
|
|
||||||
|
def stream_stream( |
||||||
|
self, method, request_serializer=None, response_deserializer=None): |
||||||
|
return _multi_callable.StreamStream(method, self._state) |
||||||
|
|
||||||
|
def take_unary_unary(self, method_descriptor): |
||||||
|
return _channel_rpc.unary_unary(self._state, method_descriptor) |
||||||
|
|
||||||
|
def take_unary_stream(self, method_descriptor): |
||||||
|
return _channel_rpc.unary_stream(self._state, method_descriptor) |
||||||
|
|
||||||
|
def take_stream_unary(self, method_descriptor): |
||||||
|
return _channel_rpc.stream_unary(self._state, method_descriptor) |
||||||
|
|
||||||
|
def take_stream_stream(self, method_descriptor): |
||||||
|
return _channel_rpc.stream_stream(self._state, method_descriptor) |
||||||
|
# pylint: enable=unused-argument |
@ -0,0 +1,119 @@ |
|||||||
|
# Copyright 2017 gRPC authors. |
||||||
|
# |
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
# you may not use this file except in compliance with the License. |
||||||
|
# You may obtain a copy of the License at |
||||||
|
# |
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
# |
||||||
|
# Unless required by applicable law or agreed to in writing, software |
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
# See the License for the specific language governing permissions and |
||||||
|
# limitations under the License. |
||||||
|
|
||||||
|
import grpc_testing |
||||||
|
|
||||||
|
|
||||||
|
class _UnaryUnary(grpc_testing.UnaryUnaryChannelRpc): |
||||||
|
|
||||||
|
def __init__(self, rpc_state): |
||||||
|
self._rpc_state = rpc_state |
||||||
|
|
||||||
|
def send_initial_metadata(self, initial_metadata): |
||||||
|
self._rpc_state.send_initial_metadata(initial_metadata) |
||||||
|
|
||||||
|
def cancelled(self): |
||||||
|
self._rpc_state.cancelled() |
||||||
|
|
||||||
|
def terminate(self, response, trailing_metadata, code, details): |
||||||
|
self._rpc_state.terminate_with_response( |
||||||
|
response, trailing_metadata, code, details) |
||||||
|
|
||||||
|
|
||||||
|
class _UnaryStream(grpc_testing.UnaryStreamChannelRpc): |
||||||
|
|
||||||
|
def __init__(self, rpc_state): |
||||||
|
self._rpc_state = rpc_state |
||||||
|
|
||||||
|
def send_initial_metadata(self, initial_metadata): |
||||||
|
self._rpc_state.send_initial_metadata(initial_metadata) |
||||||
|
|
||||||
|
def send_response(self, response): |
||||||
|
self._rpc_state.send_response(response) |
||||||
|
|
||||||
|
def cancelled(self): |
||||||
|
self._rpc_state.cancelled() |
||||||
|
|
||||||
|
def terminate(self, trailing_metadata, code, details): |
||||||
|
self._rpc_state.terminate(trailing_metadata, code, details) |
||||||
|
|
||||||
|
|
||||||
|
class _StreamUnary(grpc_testing.StreamUnaryChannelRpc): |
||||||
|
|
||||||
|
def __init__(self, rpc_state): |
||||||
|
self._rpc_state = rpc_state |
||||||
|
|
||||||
|
def send_initial_metadata(self, initial_metadata): |
||||||
|
self._rpc_state.send_initial_metadata(initial_metadata) |
||||||
|
|
||||||
|
def take_request(self): |
||||||
|
return self._rpc_state.take_request() |
||||||
|
|
||||||
|
def requests_closed(self): |
||||||
|
return self._rpc_state.requests_closed() |
||||||
|
|
||||||
|
def cancelled(self): |
||||||
|
self._rpc_state.cancelled() |
||||||
|
|
||||||
|
def terminate(self, response, trailing_metadata, code, details): |
||||||
|
self._rpc_state.terminate_with_response( |
||||||
|
response, trailing_metadata, code, details) |
||||||
|
|
||||||
|
|
||||||
|
class _StreamStream(grpc_testing.StreamStreamChannelRpc): |
||||||
|
|
||||||
|
def __init__(self, rpc_state): |
||||||
|
self._rpc_state = rpc_state |
||||||
|
|
||||||
|
def send_initial_metadata(self, initial_metadata): |
||||||
|
self._rpc_state.send_initial_metadata(initial_metadata) |
||||||
|
|
||||||
|
def take_request(self): |
||||||
|
return self._rpc_state.take_request() |
||||||
|
|
||||||
|
def send_response(self, response): |
||||||
|
self._rpc_state.send_response(response) |
||||||
|
|
||||||
|
def requests_closed(self): |
||||||
|
return self._rpc_state.requests_closed() |
||||||
|
|
||||||
|
def cancelled(self): |
||||||
|
self._rpc_state.cancelled() |
||||||
|
|
||||||
|
def terminate(self, trailing_metadata, code, details): |
||||||
|
self._rpc_state.terminate(trailing_metadata, code, details) |
||||||
|
|
||||||
|
|
||||||
|
def unary_unary(channel_state, method_descriptor): |
||||||
|
rpc_state = channel_state.take_rpc_state(method_descriptor) |
||||||
|
invocation_metadata, request = ( |
||||||
|
rpc_state.take_invocation_metadata_and_request()) |
||||||
|
return invocation_metadata, request, _UnaryUnary(rpc_state) |
||||||
|
|
||||||
|
|
||||||
|
def unary_stream(channel_state, method_descriptor): |
||||||
|
rpc_state = channel_state.take_rpc_state(method_descriptor) |
||||||
|
invocation_metadata, request = ( |
||||||
|
rpc_state.take_invocation_metadata_and_request()) |
||||||
|
return invocation_metadata, request, _UnaryStream(rpc_state) |
||||||
|
|
||||||
|
|
||||||
|
def stream_unary(channel_state, method_descriptor): |
||||||
|
rpc_state = channel_state.take_rpc_state(method_descriptor) |
||||||
|
return rpc_state.take_invocation_metadata(), _StreamUnary(rpc_state) |
||||||
|
|
||||||
|
|
||||||
|
def stream_stream(channel_state, method_descriptor): |
||||||
|
rpc_state = channel_state.take_rpc_state(method_descriptor) |
||||||
|
return rpc_state.take_invocation_metadata(), _StreamStream(rpc_state) |
@ -0,0 +1,48 @@ |
|||||||
|
# Copyright 2017 gRPC authors. |
||||||
|
# |
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
# you may not use this file except in compliance with the License. |
||||||
|
# You may obtain a copy of the License at |
||||||
|
# |
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
# |
||||||
|
# Unless required by applicable law or agreed to in writing, software |
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
# See the License for the specific language governing permissions and |
||||||
|
# limitations under the License. |
||||||
|
|
||||||
|
import collections |
||||||
|
import threading |
||||||
|
|
||||||
|
from grpc_testing import _common |
||||||
|
from grpc_testing._channel import _rpc_state |
||||||
|
|
||||||
|
|
||||||
|
class State(_common.ChannelHandler): |
||||||
|
|
||||||
|
def __init__(self): |
||||||
|
self._condition = threading.Condition() |
||||||
|
self._rpc_states = collections.defaultdict(list) |
||||||
|
|
||||||
|
def invoke_rpc( |
||||||
|
self, method_full_rpc_name, invocation_metadata, requests, |
||||||
|
requests_closed, timeout): |
||||||
|
rpc_state = _rpc_state.State( |
||||||
|
invocation_metadata, requests, requests_closed) |
||||||
|
with self._condition: |
||||||
|
self._rpc_states[method_full_rpc_name].append(rpc_state) |
||||||
|
self._condition.notify_all() |
||||||
|
return rpc_state |
||||||
|
|
||||||
|
def take_rpc_state(self, method_descriptor): |
||||||
|
method_full_rpc_name = '/{}/{}'.format( |
||||||
|
method_descriptor.containing_service.full_name, |
||||||
|
method_descriptor.name) |
||||||
|
with self._condition: |
||||||
|
while True: |
||||||
|
method_rpc_states = self._rpc_states[method_full_rpc_name] |
||||||
|
if method_rpc_states: |
||||||
|
return method_rpc_states.pop(0) |
||||||
|
else: |
||||||
|
self._condition.wait() |
@ -0,0 +1,322 @@ |
|||||||
|
# Copyright 2017 gRPC authors. |
||||||
|
# |
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
# you may not use this file except in compliance with the License. |
||||||
|
# You may obtain a copy of the License at |
||||||
|
# |
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
# |
||||||
|
# Unless required by applicable law or agreed to in writing, software |
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
# See the License for the specific language governing permissions and |
||||||
|
# limitations under the License. |
||||||
|
|
||||||
|
import logging |
||||||
|
import threading |
||||||
|
|
||||||
|
import grpc |
||||||
|
|
||||||
|
_NOT_YET_OBSERVED = object() |
||||||
|
|
||||||
|
|
||||||
|
def _cancel(handler): |
||||||
|
return handler.cancel(grpc.StatusCode.CANCELLED, 'Locally cancelled!') |
||||||
|
|
||||||
|
|
||||||
|
def _is_active(handler): |
||||||
|
return handler.is_active() |
||||||
|
|
||||||
|
|
||||||
|
def _time_remaining(unused_handler): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
|
||||||
|
def _add_callback(handler, callback): |
||||||
|
return handler.add_callback(callback) |
||||||
|
|
||||||
|
|
||||||
|
def _initial_metadata(handler): |
||||||
|
return handler.initial_metadata() |
||||||
|
|
||||||
|
|
||||||
|
def _trailing_metadata(handler): |
||||||
|
trailing_metadata, unused_code, unused_details = handler.termination() |
||||||
|
return trailing_metadata |
||||||
|
|
||||||
|
|
||||||
|
def _code(handler): |
||||||
|
unused_trailing_metadata, code, unused_details = handler.termination() |
||||||
|
return code |
||||||
|
|
||||||
|
|
||||||
|
def _details(handler): |
||||||
|
unused_trailing_metadata, unused_code, details = handler.termination() |
||||||
|
return details |
||||||
|
|
||||||
|
|
||||||
|
class _Call(grpc.Call): |
||||||
|
|
||||||
|
def __init__(self, handler): |
||||||
|
self._handler = handler |
||||||
|
|
||||||
|
def cancel(self): |
||||||
|
_cancel(self._handler) |
||||||
|
|
||||||
|
def is_active(self): |
||||||
|
return _is_active(self._handler) |
||||||
|
|
||||||
|
def time_remaining(self): |
||||||
|
return _time_remaining(self._handler) |
||||||
|
|
||||||
|
def add_callback(self, callback): |
||||||
|
return _add_callback(self._handler, callback) |
||||||
|
|
||||||
|
def initial_metadata(self): |
||||||
|
return _initial_metadata(self._handler) |
||||||
|
|
||||||
|
def trailing_metadata(self): |
||||||
|
return _trailing_metadata(self._handler) |
||||||
|
|
||||||
|
def code(self): |
||||||
|
return _code(self._handler) |
||||||
|
|
||||||
|
def details(self): |
||||||
|
return _details(self._handler) |
||||||
|
|
||||||
|
|
||||||
|
class _RpcErrorCall(grpc.RpcError, grpc.Call): |
||||||
|
|
||||||
|
def __init__(self, handler): |
||||||
|
self._handler = handler |
||||||
|
|
||||||
|
def cancel(self): |
||||||
|
_cancel(self._handler) |
||||||
|
|
||||||
|
def is_active(self): |
||||||
|
return _is_active(self._handler) |
||||||
|
|
||||||
|
def time_remaining(self): |
||||||
|
return _time_remaining(self._handler) |
||||||
|
|
||||||
|
def add_callback(self, callback): |
||||||
|
return _add_callback(self._handler, callback) |
||||||
|
|
||||||
|
def initial_metadata(self): |
||||||
|
return _initial_metadata(self._handler) |
||||||
|
|
||||||
|
def trailing_metadata(self): |
||||||
|
return _trailing_metadata(self._handler) |
||||||
|
|
||||||
|
def code(self): |
||||||
|
return _code(self._handler) |
||||||
|
|
||||||
|
def details(self): |
||||||
|
return _details(self._handler) |
||||||
|
|
||||||
|
|
||||||
|
def _next(handler): |
||||||
|
read = handler.take_response() |
||||||
|
if read.code is None: |
||||||
|
return read.response |
||||||
|
elif read.code is grpc.StatusCode.OK: |
||||||
|
raise StopIteration() |
||||||
|
else: |
||||||
|
raise _RpcErrorCall(handler) |
||||||
|
|
||||||
|
|
||||||
|
class _HandlerExtras(object): |
||||||
|
|
||||||
|
def __init__(self): |
||||||
|
self.condition = threading.Condition() |
||||||
|
self.unary_response = _NOT_YET_OBSERVED |
||||||
|
self.cancelled = False |
||||||
|
|
||||||
|
|
||||||
|
def _with_extras_cancel(handler, extras): |
||||||
|
with extras.condition: |
||||||
|
if handler.cancel(grpc.StatusCode.CANCELLED, 'Locally cancelled!'): |
||||||
|
extras.cancelled = True |
||||||
|
return True |
||||||
|
else: |
||||||
|
return False |
||||||
|
|
||||||
|
|
||||||
|
def _extras_without_cancelled(extras): |
||||||
|
with extras.condition: |
||||||
|
return extras.cancelled |
||||||
|
|
||||||
|
|
||||||
|
def _running(handler): |
||||||
|
return handler.is_active() |
||||||
|
|
||||||
|
|
||||||
|
def _done(handler): |
||||||
|
return not handler.is_active() |
||||||
|
|
||||||
|
|
||||||
|
def _with_extras_unary_response(handler, extras): |
||||||
|
with extras.condition: |
||||||
|
if extras.unary_response is _NOT_YET_OBSERVED: |
||||||
|
read = handler.take_response() |
||||||
|
if read.code is None: |
||||||
|
extras.unary_response = read.response |
||||||
|
return read.response |
||||||
|
else: |
||||||
|
raise _RpcErrorCall(handler) |
||||||
|
else: |
||||||
|
return extras.unary_response |
||||||
|
|
||||||
|
|
||||||
|
def _exception(unused_handler): |
||||||
|
raise NotImplementedError('TODO!') |
||||||
|
|
||||||
|
|
||||||
|
def _traceback(unused_handler): |
||||||
|
raise NotImplementedError('TODO!') |
||||||
|
|
||||||
|
|
||||||
|
def _add_done_callback(handler, callback, future): |
||||||
|
adapted_callback = lambda: callback(future) |
||||||
|
if not handler.add_callback(adapted_callback): |
||||||
|
callback(future) |
||||||
|
|
||||||
|
|
||||||
|
class _FutureCall(grpc.Future, grpc.Call): |
||||||
|
|
||||||
|
def __init__(self, handler, extras): |
||||||
|
self._handler = handler |
||||||
|
self._extras = extras |
||||||
|
|
||||||
|
def cancel(self): |
||||||
|
return _with_extras_cancel(self._handler, self._extras) |
||||||
|
|
||||||
|
def cancelled(self): |
||||||
|
return _extras_without_cancelled(self._extras) |
||||||
|
|
||||||
|
def running(self): |
||||||
|
return _running(self._handler) |
||||||
|
|
||||||
|
def done(self): |
||||||
|
return _done(self._handler) |
||||||
|
|
||||||
|
def result(self): |
||||||
|
return _with_extras_unary_response(self._handler, self._extras) |
||||||
|
|
||||||
|
def exception(self): |
||||||
|
return _exception(self._handler) |
||||||
|
|
||||||
|
def traceback(self): |
||||||
|
return _traceback(self._handler) |
||||||
|
|
||||||
|
def add_done_callback(self, fn): |
||||||
|
_add_done_callback(self._handler, fn, self) |
||||||
|
|
||||||
|
def is_active(self): |
||||||
|
return _is_active(self._handler) |
||||||
|
|
||||||
|
def time_remaining(self): |
||||||
|
return _time_remaining(self._handler) |
||||||
|
|
||||||
|
def add_callback(self, callback): |
||||||
|
return _add_callback(self._handler, callback) |
||||||
|
|
||||||
|
def initial_metadata(self): |
||||||
|
return _initial_metadata(self._handler) |
||||||
|
|
||||||
|
def trailing_metadata(self): |
||||||
|
return _trailing_metadata(self._handler) |
||||||
|
|
||||||
|
def code(self): |
||||||
|
return _code(self._handler) |
||||||
|
|
||||||
|
def details(self): |
||||||
|
return _details(self._handler) |
||||||
|
|
||||||
|
|
||||||
|
def consume_requests(request_iterator, handler): |
||||||
|
|
||||||
|
def _consume(): |
||||||
|
while True: |
||||||
|
try: |
||||||
|
request = next(request_iterator) |
||||||
|
added = handler.add_request(request) |
||||||
|
if not added: |
||||||
|
break |
||||||
|
except StopIteration: |
||||||
|
handler.close_requests() |
||||||
|
break |
||||||
|
except Exception: # pylint: disable=broad-except |
||||||
|
details = 'Exception iterating requests!' |
||||||
|
logging.exception(details) |
||||||
|
handler.cancel(grpc.StatusCode.UNKNOWN, details) |
||||||
|
|
||||||
|
consumption = threading.Thread(target=_consume) |
||||||
|
consumption.start() |
||||||
|
|
||||||
|
|
||||||
|
def blocking_unary_response(handler): |
||||||
|
read = handler.take_response() |
||||||
|
if read.code is None: |
||||||
|
unused_trailing_metadata, code, unused_details = handler.termination() |
||||||
|
if code is grpc.StatusCode.OK: |
||||||
|
return read.response |
||||||
|
else: |
||||||
|
raise _RpcErrorCall(handler) |
||||||
|
else: |
||||||
|
raise _RpcErrorCall(handler) |
||||||
|
|
||||||
|
|
||||||
|
def blocking_unary_response_with_call(handler): |
||||||
|
read = handler.take_response() |
||||||
|
if read.code is None: |
||||||
|
unused_trailing_metadata, code, unused_details = handler.termination() |
||||||
|
if code is grpc.StatusCode.OK: |
||||||
|
return read.response, _Call(handler) |
||||||
|
else: |
||||||
|
raise _RpcErrorCall(handler) |
||||||
|
else: |
||||||
|
raise _RpcErrorCall(handler) |
||||||
|
|
||||||
|
|
||||||
|
def future_call(handler): |
||||||
|
return _FutureCall(handler, _HandlerExtras()) |
||||||
|
|
||||||
|
|
||||||
|
class ResponseIteratorCall(grpc.Call): |
||||||
|
|
||||||
|
def __init__(self, handler): |
||||||
|
self._handler = handler |
||||||
|
|
||||||
|
def __iter__(self): |
||||||
|
return self |
||||||
|
|
||||||
|
def __next__(self): |
||||||
|
return _next(self._handler) |
||||||
|
|
||||||
|
def next(self): |
||||||
|
return _next(self._handler) |
||||||
|
|
||||||
|
def cancel(self): |
||||||
|
_cancel(self._handler) |
||||||
|
|
||||||
|
def is_active(self): |
||||||
|
return _is_active(self._handler) |
||||||
|
|
||||||
|
def time_remaining(self): |
||||||
|
return _time_remaining(self._handler) |
||||||
|
|
||||||
|
def add_callback(self, callback): |
||||||
|
return _add_callback(self._handler, callback) |
||||||
|
|
||||||
|
def initial_metadata(self): |
||||||
|
return _initial_metadata(self._handler) |
||||||
|
|
||||||
|
def trailing_metadata(self): |
||||||
|
return _trailing_metadata(self._handler) |
||||||
|
|
||||||
|
def code(self): |
||||||
|
return _code(self._handler) |
||||||
|
|
||||||
|
def details(self): |
||||||
|
return _details(self._handler) |
@ -0,0 +1,115 @@ |
|||||||
|
# Copyright 2017 gRPC authors. |
||||||
|
# |
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
# you may not use this file except in compliance with the License. |
||||||
|
# You may obtain a copy of the License at |
||||||
|
# |
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
# |
||||||
|
# Unless required by applicable law or agreed to in writing, software |
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
# See the License for the specific language governing permissions and |
||||||
|
# limitations under the License. |
||||||
|
|
||||||
|
import grpc |
||||||
|
from grpc_testing import _common |
||||||
|
from grpc_testing._channel import _invocation |
||||||
|
|
||||||
|
# All per-call credentials parameters are unused by this test infrastructure. |
||||||
|
# pylint: disable=unused-argument |
||||||
|
class UnaryUnary(grpc.UnaryUnaryMultiCallable): |
||||||
|
|
||||||
|
def __init__(self, method_full_rpc_name, channel_handler): |
||||||
|
self._method_full_rpc_name = method_full_rpc_name |
||||||
|
self._channel_handler = channel_handler |
||||||
|
|
||||||
|
def __call__(self, request, timeout=None, metadata=None, credentials=None): |
||||||
|
rpc_handler = self._channel_handler.invoke_rpc( |
||||||
|
self._method_full_rpc_name, _common.fuss_with_metadata(metadata), |
||||||
|
[request], True, timeout) |
||||||
|
return _invocation.blocking_unary_response(rpc_handler) |
||||||
|
|
||||||
|
def with_call(self, request, timeout=None, metadata=None, credentials=None): |
||||||
|
rpc_handler = self._channel_handler.invoke_rpc( |
||||||
|
self._method_full_rpc_name, _common.fuss_with_metadata(metadata), |
||||||
|
[request], True, timeout) |
||||||
|
return _invocation.blocking_unary_response_with_call(rpc_handler) |
||||||
|
|
||||||
|
def future(self, request, timeout=None, metadata=None, credentials=None): |
||||||
|
rpc_handler = self._channel_handler.invoke_rpc( |
||||||
|
self._method_full_rpc_name, _common.fuss_with_metadata(metadata), |
||||||
|
[request], True, timeout) |
||||||
|
return _invocation.future_call(rpc_handler) |
||||||
|
|
||||||
|
|
||||||
|
class UnaryStream(grpc.StreamStreamMultiCallable): |
||||||
|
|
||||||
|
def __init__(self, method_full_rpc_name, channel_handler): |
||||||
|
self._method_full_rpc_name = method_full_rpc_name |
||||||
|
self._channel_handler = channel_handler |
||||||
|
|
||||||
|
def __call__(self, request, timeout=None, metadata=None, credentials=None): |
||||||
|
rpc_handler = self._channel_handler.invoke_rpc( |
||||||
|
self._method_full_rpc_name, |
||||||
|
_common.fuss_with_metadata(metadata), [request], True, timeout) |
||||||
|
return _invocation.ResponseIteratorCall(rpc_handler) |
||||||
|
|
||||||
|
|
||||||
|
class StreamUnary(grpc.StreamUnaryMultiCallable): |
||||||
|
|
||||||
|
def __init__(self, method_full_rpc_name, channel_handler): |
||||||
|
self._method_full_rpc_name = method_full_rpc_name |
||||||
|
self._channel_handler = channel_handler |
||||||
|
|
||||||
|
def __call__(self, |
||||||
|
request_iterator, |
||||||
|
timeout=None, |
||||||
|
metadata=None, |
||||||
|
credentials=None): |
||||||
|
rpc_handler = self._channel_handler.invoke_rpc( |
||||||
|
self._method_full_rpc_name, |
||||||
|
_common.fuss_with_metadata(metadata), [], False, timeout) |
||||||
|
_invocation.consume_requests(request_iterator, rpc_handler) |
||||||
|
return _invocation.blocking_unary_response(rpc_handler) |
||||||
|
|
||||||
|
def with_call(self, |
||||||
|
request_iterator, |
||||||
|
timeout=None, |
||||||
|
metadata=None, |
||||||
|
credentials=None): |
||||||
|
rpc_handler = self._channel_handler.invoke_rpc( |
||||||
|
self._method_full_rpc_name, |
||||||
|
_common.fuss_with_metadata(metadata), [], False, timeout) |
||||||
|
_invocation.consume_requests(request_iterator, rpc_handler) |
||||||
|
return _invocation.blocking_unary_response_with_call(rpc_handler) |
||||||
|
|
||||||
|
def future(self, |
||||||
|
request_iterator, |
||||||
|
timeout=None, |
||||||
|
metadata=None, |
||||||
|
credentials=None): |
||||||
|
rpc_handler = self._channel_handler.invoke_rpc( |
||||||
|
self._method_full_rpc_name, |
||||||
|
_common.fuss_with_metadata(metadata), [], False, timeout) |
||||||
|
_invocation.consume_requests(request_iterator, rpc_handler) |
||||||
|
return _invocation.future_call(rpc_handler) |
||||||
|
|
||||||
|
|
||||||
|
class StreamStream(grpc.StreamStreamMultiCallable): |
||||||
|
|
||||||
|
def __init__(self, method_full_rpc_name, channel_handler): |
||||||
|
self._method_full_rpc_name = method_full_rpc_name |
||||||
|
self._channel_handler = channel_handler |
||||||
|
|
||||||
|
def __call__(self, |
||||||
|
request_iterator, |
||||||
|
timeout=None, |
||||||
|
metadata=None, |
||||||
|
credentials=None): |
||||||
|
rpc_handler = self._channel_handler.invoke_rpc( |
||||||
|
self._method_full_rpc_name, |
||||||
|
_common.fuss_with_metadata(metadata), [], False, timeout) |
||||||
|
_invocation.consume_requests(request_iterator, rpc_handler) |
||||||
|
return _invocation.ResponseIteratorCall(rpc_handler) |
||||||
|
# pylint: enable=unused-argument |
@ -0,0 +1,193 @@ |
|||||||
|
# Copyright 2017 gRPC authors. |
||||||
|
# |
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
# you may not use this file except in compliance with the License. |
||||||
|
# You may obtain a copy of the License at |
||||||
|
# |
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
# |
||||||
|
# Unless required by applicable law or agreed to in writing, software |
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
# See the License for the specific language governing permissions and |
||||||
|
# limitations under the License. |
||||||
|
|
||||||
|
import threading |
||||||
|
|
||||||
|
import grpc |
||||||
|
from grpc_testing import _common |
||||||
|
|
||||||
|
|
||||||
|
class State(_common.ChannelRpcHandler): |
||||||
|
|
||||||
|
def __init__(self, invocation_metadata, requests, requests_closed): |
||||||
|
self._condition = threading.Condition() |
||||||
|
self._invocation_metadata = invocation_metadata |
||||||
|
self._requests = requests |
||||||
|
self._requests_closed = requests_closed |
||||||
|
self._initial_metadata = None |
||||||
|
self._responses = [] |
||||||
|
self._trailing_metadata = None |
||||||
|
self._code = None |
||||||
|
self._details = None |
||||||
|
|
||||||
|
def initial_metadata(self): |
||||||
|
with self._condition: |
||||||
|
while True: |
||||||
|
if self._initial_metadata is None: |
||||||
|
if self._code is None: |
||||||
|
self._condition.wait() |
||||||
|
else: |
||||||
|
return _common.FUSSED_EMPTY_METADATA |
||||||
|
else: |
||||||
|
return self._initial_metadata |
||||||
|
|
||||||
|
def add_request(self, request): |
||||||
|
with self._condition: |
||||||
|
if self._code is None and not self._requests_closed: |
||||||
|
self._requests.append(request) |
||||||
|
self._condition.notify_all() |
||||||
|
return True |
||||||
|
else: |
||||||
|
return False |
||||||
|
|
||||||
|
def close_requests(self): |
||||||
|
with self._condition: |
||||||
|
if self._code is None and not self._requests_closed: |
||||||
|
self._requests_closed = True |
||||||
|
self._condition.notify_all() |
||||||
|
|
||||||
|
def take_response(self): |
||||||
|
with self._condition: |
||||||
|
while True: |
||||||
|
if self._code is grpc.StatusCode.OK: |
||||||
|
if self._responses: |
||||||
|
response = self._responses.pop(0) |
||||||
|
return _common.ChannelRpcRead( |
||||||
|
response, None, None, None) |
||||||
|
else: |
||||||
|
return _common.ChannelRpcRead( |
||||||
|
None, self._trailing_metadata, |
||||||
|
grpc.StatusCode.OK, self._details) |
||||||
|
elif self._code is None: |
||||||
|
if self._responses: |
||||||
|
response = self._responses.pop(0) |
||||||
|
return _common.ChannelRpcRead( |
||||||
|
response, None, None, None) |
||||||
|
else: |
||||||
|
self._condition.wait() |
||||||
|
else: |
||||||
|
return _common.ChannelRpcRead( |
||||||
|
None, self._trailing_metadata, self._code, |
||||||
|
self._details) |
||||||
|
|
||||||
|
def termination(self): |
||||||
|
with self._condition: |
||||||
|
while True: |
||||||
|
if self._code is None: |
||||||
|
self._condition.wait() |
||||||
|
else: |
||||||
|
return self._trailing_metadata, self._code, self._details |
||||||
|
|
||||||
|
def cancel(self, code, details): |
||||||
|
with self._condition: |
||||||
|
if self._code is None: |
||||||
|
if self._initial_metadata is None: |
||||||
|
self._initial_metadata = _common.FUSSED_EMPTY_METADATA |
||||||
|
self._trailing_metadata = _common.FUSSED_EMPTY_METADATA |
||||||
|
self._code = code |
||||||
|
self._details = details |
||||||
|
self._condition.notify_all() |
||||||
|
return True |
||||||
|
else: |
||||||
|
return False |
||||||
|
|
||||||
|
def take_invocation_metadata(self): |
||||||
|
with self._condition: |
||||||
|
if self._invocation_metadata is None: |
||||||
|
raise ValueError('Expected invocation metadata!') |
||||||
|
else: |
||||||
|
invocation_metadata = self._invocation_metadata |
||||||
|
self._invocation_metadata = None |
||||||
|
return invocation_metadata |
||||||
|
|
||||||
|
def take_invocation_metadata_and_request(self): |
||||||
|
with self._condition: |
||||||
|
if self._invocation_metadata is None: |
||||||
|
raise ValueError('Expected invocation metadata!') |
||||||
|
elif not self._requests: |
||||||
|
raise ValueError('Expected at least one request!') |
||||||
|
else: |
||||||
|
invocation_metadata = self._invocation_metadata |
||||||
|
self._invocation_metadata = None |
||||||
|
return invocation_metadata, self._requests.pop(0) |
||||||
|
|
||||||
|
def send_initial_metadata(self, initial_metadata): |
||||||
|
with self._condition: |
||||||
|
self._initial_metadata = _common.fuss_with_metadata( |
||||||
|
initial_metadata) |
||||||
|
self._condition.notify_all() |
||||||
|
|
||||||
|
def take_request(self): |
||||||
|
with self._condition: |
||||||
|
while True: |
||||||
|
if self._requests: |
||||||
|
return self._requests.pop(0) |
||||||
|
else: |
||||||
|
self._condition.wait() |
||||||
|
|
||||||
|
def requests_closed(self): |
||||||
|
with self._condition: |
||||||
|
while True: |
||||||
|
if self._requests_closed: |
||||||
|
return |
||||||
|
else: |
||||||
|
self._condition.wait() |
||||||
|
|
||||||
|
def send_response(self, response): |
||||||
|
with self._condition: |
||||||
|
if self._code is None: |
||||||
|
self._responses.append(response) |
||||||
|
self._condition.notify_all() |
||||||
|
|
||||||
|
def terminate_with_response( |
||||||
|
self, response, trailing_metadata, code, details): |
||||||
|
with self._condition: |
||||||
|
if self._initial_metadata is None: |
||||||
|
self._initial_metadata = _common.FUSSED_EMPTY_METADATA |
||||||
|
self._responses.append(response) |
||||||
|
self._trailing_metadata = _common.fuss_with_metadata( |
||||||
|
trailing_metadata) |
||||||
|
self._code = code |
||||||
|
self._details = details |
||||||
|
self._condition.notify_all() |
||||||
|
|
||||||
|
def terminate(self, trailing_metadata, code, details): |
||||||
|
with self._condition: |
||||||
|
if self._initial_metadata is None: |
||||||
|
self._initial_metadata = _common.FUSSED_EMPTY_METADATA |
||||||
|
self._trailing_metadata = _common.fuss_with_metadata( |
||||||
|
trailing_metadata) |
||||||
|
self._code = code |
||||||
|
self._details = details |
||||||
|
self._condition.notify_all() |
||||||
|
|
||||||
|
def cancelled(self): |
||||||
|
with self._condition: |
||||||
|
while True: |
||||||
|
if self._code is grpc.StatusCode.CANCELLED: |
||||||
|
return |
||||||
|
elif self._code is None: |
||||||
|
self._condition.wait() |
||||||
|
else: |
||||||
|
raise ValueError( |
||||||
|
'Status code unexpectedly {}!'.format(self._code)) |
||||||
|
|
||||||
|
def is_active(self): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
def time_remaining(self): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
def add_callback(self, callback): |
||||||
|
raise NotImplementedError() |
@ -0,0 +1,92 @@ |
|||||||
|
# Copyright 2017 gRPC authors. |
||||||
|
# |
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
# you may not use this file except in compliance with the License. |
||||||
|
# You may obtain a copy of the License at |
||||||
|
# |
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
# |
||||||
|
# Unless required by applicable law or agreed to in writing, software |
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
# See the License for the specific language governing permissions and |
||||||
|
# limitations under the License. |
||||||
|
"""Common interfaces and implementation.""" |
||||||
|
|
||||||
|
import abc |
||||||
|
import collections |
||||||
|
|
||||||
|
import six |
||||||
|
|
||||||
|
|
||||||
|
def _fuss(tuplified_metadata): |
||||||
|
return tuplified_metadata + ( |
||||||
|
( |
||||||
|
'grpc.metadata_added_by_runtime', |
||||||
|
'gRPC is allowed to add metadata in transmission and does so.', |
||||||
|
), |
||||||
|
) |
||||||
|
|
||||||
|
FUSSED_EMPTY_METADATA = _fuss(()) |
||||||
|
|
||||||
|
|
||||||
|
def fuss_with_metadata(metadata): |
||||||
|
if metadata is None: |
||||||
|
return FUSSED_EMPTY_METADATA |
||||||
|
else: |
||||||
|
return _fuss(tuple(metadata)) |
||||||
|
|
||||||
|
|
||||||
|
class ChannelRpcRead( |
||||||
|
collections.namedtuple( |
||||||
|
'ChannelRpcRead', |
||||||
|
('response', 'trailing_metadata', 'code', 'details',))): |
||||||
|
pass |
||||||
|
|
||||||
|
|
||||||
|
class ChannelRpcHandler(six.with_metaclass(abc.ABCMeta)): |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def initial_metadata(self): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def add_request(self, request): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def close_requests(self): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def take_response(self): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def cancel(self, code, details): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def termination(self): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def is_active(self): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def time_remaining(self): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def add_callback(self, callback): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
|
||||||
|
class ChannelHandler(six.with_metaclass(abc.ABCMeta)): |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def invoke_rpc( |
||||||
|
self, method_full_rpc_name, invocation_metadata, requests, |
||||||
|
requests_closed, timeout): |
||||||
|
raise NotImplementedError() |
@ -0,0 +1,36 @@ |
|||||||
|
# Copyright 2017 gRPC authors. |
||||||
|
# |
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
# you may not use this file except in compliance with the License. |
||||||
|
# You may obtain a copy of the License at |
||||||
|
# |
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
# |
||||||
|
# Unless required by applicable law or agreed to in writing, software |
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
# See the License for the specific language governing permissions and |
||||||
|
# limitations under the License. |
||||||
|
"""An example gRPC Python-using application's common code elements.""" |
||||||
|
|
||||||
|
from tests.testing.proto import requests_pb2 |
||||||
|
from tests.testing.proto import services_pb2 |
||||||
|
|
||||||
|
SERVICE_NAME = 'tests_of_grpc_testing.FirstService' |
||||||
|
UNARY_UNARY_METHOD_NAME = 'UnUn' |
||||||
|
UNARY_STREAM_METHOD_NAME = 'UnStre' |
||||||
|
STREAM_UNARY_METHOD_NAME = 'StreUn' |
||||||
|
STREAM_STREAM_METHOD_NAME = 'StreStre' |
||||||
|
|
||||||
|
UNARY_UNARY_REQUEST = requests_pb2.Up(first_up_field=2) |
||||||
|
ERRONEOUS_UNARY_UNARY_REQUEST = requests_pb2.Up(first_up_field=3) |
||||||
|
UNARY_UNARY_RESPONSE = services_pb2.Down(first_down_field=5) |
||||||
|
ERRONEOUS_UNARY_UNARY_RESPONSE = services_pb2.Down(first_down_field=7) |
||||||
|
UNARY_STREAM_REQUEST = requests_pb2.Charm(first_charm_field=11) |
||||||
|
STREAM_UNARY_REQUEST = requests_pb2.Charm(first_charm_field=13) |
||||||
|
STREAM_UNARY_RESPONSE = services_pb2.Strange(first_strange_field=17) |
||||||
|
STREAM_STREAM_REQUEST = requests_pb2.Top(first_top_field=19) |
||||||
|
STREAM_STREAM_RESPONSE = services_pb2.Bottom(first_bottom_field=23) |
||||||
|
TWO_STREAM_STREAM_RESPONSES = (STREAM_STREAM_RESPONSE,) * 2 |
||||||
|
|
||||||
|
INFINITE_REQUEST_STREAM_TIMEOUT = 0.2 |
@ -0,0 +1,33 @@ |
|||||||
|
# Copyright 2017 gRPC authors. |
||||||
|
# |
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
# you may not use this file except in compliance with the License. |
||||||
|
# You may obtain a copy of the License at |
||||||
|
# |
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
# |
||||||
|
# Unless required by applicable law or agreed to in writing, software |
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
# See the License for the specific language governing permissions and |
||||||
|
# limitations under the License. |
||||||
|
|
||||||
|
import grpc_testing |
||||||
|
|
||||||
|
from tests.testing.proto import requests_pb2 |
||||||
|
from tests.testing.proto import services_pb2 |
||||||
|
|
||||||
|
# TODO(https://github.com/grpc/grpc/issues/11657): Eliminate this entirely. |
||||||
|
# TODO(https://github.com/google/protobuf/issues/3452): Eliminate this if/else. |
||||||
|
if services_pb2.DESCRIPTOR.services_by_name.get('FirstService') is None: |
||||||
|
FIRST_SERVICE = 'Fix protobuf issue 3452!' |
||||||
|
FIRST_SERVICE_UNUN = 'Fix protobuf issue 3452!' |
||||||
|
FIRST_SERVICE_UNSTRE = 'Fix protobuf issue 3452!' |
||||||
|
FIRST_SERVICE_STREUN = 'Fix protobuf issue 3452!' |
||||||
|
FIRST_SERVICE_STRESTRE = 'Fix protobuf issue 3452!' |
||||||
|
else: |
||||||
|
FIRST_SERVICE = services_pb2.DESCRIPTOR.services_by_name['FirstService'] |
||||||
|
FIRST_SERVICE_UNUN = FIRST_SERVICE.methods_by_name['UnUn'] |
||||||
|
FIRST_SERVICE_UNSTRE = FIRST_SERVICE.methods_by_name['UnStre'] |
||||||
|
FIRST_SERVICE_STREUN = FIRST_SERVICE.methods_by_name['StreUn'] |
||||||
|
FIRST_SERVICE_STRESTRE = FIRST_SERVICE.methods_by_name['StreStre'] |
@ -0,0 +1,260 @@ |
|||||||
|
# Copyright 2017 gRPC authors. |
||||||
|
# |
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
# you may not use this file except in compliance with the License. |
||||||
|
# You may obtain a copy of the License at |
||||||
|
# |
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
# |
||||||
|
# Unless required by applicable law or agreed to in writing, software |
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
# See the License for the specific language governing permissions and |
||||||
|
# limitations under the License. |
||||||
|
"""An example gRPC Python-using client-side application.""" |
||||||
|
|
||||||
|
import collections |
||||||
|
import enum |
||||||
|
import threading |
||||||
|
import time |
||||||
|
|
||||||
|
import grpc |
||||||
|
from tests.unit.framework.common import test_constants |
||||||
|
|
||||||
|
from tests.testing.proto import requests_pb2 |
||||||
|
from tests.testing.proto import services_pb2 |
||||||
|
from tests.testing.proto import services_pb2_grpc |
||||||
|
|
||||||
|
from tests.testing import _application_common |
||||||
|
|
||||||
|
|
||||||
|
@enum.unique |
||||||
|
class Scenario(enum.Enum): |
||||||
|
UNARY_UNARY = 'unary unary' |
||||||
|
UNARY_STREAM = 'unary stream' |
||||||
|
STREAM_UNARY = 'stream unary' |
||||||
|
STREAM_STREAM = 'stream stream' |
||||||
|
CONCURRENT_STREAM_UNARY = 'concurrent stream unary' |
||||||
|
CONCURRENT_STREAM_STREAM = 'concurrent stream stream' |
||||||
|
CANCEL_UNARY_UNARY = 'cancel unary unary' |
||||||
|
CANCEL_UNARY_STREAM = 'cancel unary stream' |
||||||
|
INFINITE_REQUEST_STREAM = 'infinite request stream' |
||||||
|
|
||||||
|
|
||||||
|
class Outcome(collections.namedtuple('Outcome', ('kind', 'code', 'details'))): |
||||||
|
"""Outcome of a client application scenario. |
||||||
|
|
||||||
|
Attributes: |
||||||
|
kind: A Kind value describing the overall kind of scenario execution. |
||||||
|
code: A grpc.StatusCode value. Only valid if kind is Kind.RPC_ERROR. |
||||||
|
details: A status details string. Only valid if kind is Kind.RPC_ERROR. |
||||||
|
""" |
||||||
|
|
||||||
|
@enum.unique |
||||||
|
class Kind(enum.Enum): |
||||||
|
SATISFACTORY = 'satisfactory' |
||||||
|
UNSATISFACTORY = 'unsatisfactory' |
||||||
|
RPC_ERROR = 'rpc error' |
||||||
|
|
||||||
|
|
||||||
|
_SATISFACTORY_OUTCOME = Outcome(Outcome.Kind.SATISFACTORY, None, None) |
||||||
|
_UNSATISFACTORY_OUTCOME = Outcome(Outcome.Kind.UNSATISFACTORY, None, None) |
||||||
|
|
||||||
|
|
||||||
|
class _Pipe(object): |
||||||
|
|
||||||
|
def __init__(self): |
||||||
|
self._condition = threading.Condition() |
||||||
|
self._values = [] |
||||||
|
self._open = True |
||||||
|
|
||||||
|
def __iter__(self): |
||||||
|
return self |
||||||
|
|
||||||
|
def _next(self): |
||||||
|
with self._condition: |
||||||
|
while True: |
||||||
|
if self._values: |
||||||
|
return self._values.pop(0) |
||||||
|
elif not self._open: |
||||||
|
raise StopIteration() |
||||||
|
else: |
||||||
|
self._condition.wait() |
||||||
|
|
||||||
|
def __next__(self): # (Python 3 Iterator Protocol) |
||||||
|
return self._next() |
||||||
|
|
||||||
|
def next(self): # (Python 2 Iterator Protocol) |
||||||
|
return self._next() |
||||||
|
|
||||||
|
def add(self, value): |
||||||
|
with self._condition: |
||||||
|
self._values.append(value) |
||||||
|
self._condition.notify_all() |
||||||
|
|
||||||
|
def close(self): |
||||||
|
with self._condition: |
||||||
|
self._open = False |
||||||
|
self._condition.notify_all() |
||||||
|
|
||||||
|
|
||||||
|
def _run_unary_unary(stub): |
||||||
|
response = stub.UnUn(_application_common.UNARY_UNARY_REQUEST) |
||||||
|
if _application_common.UNARY_UNARY_RESPONSE == response: |
||||||
|
return _SATISFACTORY_OUTCOME |
||||||
|
else: |
||||||
|
return _UNSATISFACTORY_OUTCOME |
||||||
|
|
||||||
|
|
||||||
|
def _run_unary_stream(stub): |
||||||
|
response_iterator = stub.UnStre(_application_common.UNARY_STREAM_REQUEST) |
||||||
|
try: |
||||||
|
next(response_iterator) |
||||||
|
except StopIteration: |
||||||
|
return _SATISFACTORY_OUTCOME |
||||||
|
else: |
||||||
|
return _UNSATISFACTORY_OUTCOME |
||||||
|
|
||||||
|
|
||||||
|
def _run_stream_unary(stub): |
||||||
|
response, call = stub.StreUn.with_call( |
||||||
|
iter((_application_common.STREAM_UNARY_REQUEST,) * 3)) |
||||||
|
if (_application_common.STREAM_UNARY_RESPONSE == response and |
||||||
|
call.code() is grpc.StatusCode.OK): |
||||||
|
return _SATISFACTORY_OUTCOME |
||||||
|
else: |
||||||
|
return _UNSATISFACTORY_OUTCOME |
||||||
|
|
||||||
|
|
||||||
|
def _run_stream_stream(stub): |
||||||
|
request_pipe = _Pipe() |
||||||
|
response_iterator = stub.StreStre(iter(request_pipe)) |
||||||
|
request_pipe.add(_application_common.STREAM_STREAM_REQUEST) |
||||||
|
first_responses = next(response_iterator), next(response_iterator), |
||||||
|
request_pipe.add(_application_common.STREAM_STREAM_REQUEST) |
||||||
|
second_responses = next(response_iterator), next(response_iterator), |
||||||
|
request_pipe.close() |
||||||
|
try: |
||||||
|
next(response_iterator) |
||||||
|
except StopIteration: |
||||||
|
unexpected_extra_response = False |
||||||
|
else: |
||||||
|
unexpected_extra_response = True |
||||||
|
if (first_responses == _application_common.TWO_STREAM_STREAM_RESPONSES and |
||||||
|
second_responses == _application_common.TWO_STREAM_STREAM_RESPONSES |
||||||
|
and not unexpected_extra_response): |
||||||
|
return _SATISFACTORY_OUTCOME |
||||||
|
else: |
||||||
|
return _UNSATISFACTORY_OUTCOME |
||||||
|
|
||||||
|
|
||||||
|
def _run_concurrent_stream_unary(stub): |
||||||
|
future_calls = tuple( |
||||||
|
stub.StreUn.future( |
||||||
|
iter((_application_common.STREAM_UNARY_REQUEST,) * 3)) |
||||||
|
for _ in range(test_constants.THREAD_CONCURRENCY)) |
||||||
|
for future_call in future_calls: |
||||||
|
if future_call.code() is grpc.StatusCode.OK: |
||||||
|
response = future_call.result() |
||||||
|
if _application_common.STREAM_UNARY_RESPONSE != response: |
||||||
|
return _UNSATISFACTORY_OUTCOME |
||||||
|
else: |
||||||
|
return _UNSATISFACTORY_OUTCOME |
||||||
|
else: |
||||||
|
return _SATISFACTORY_OUTCOME |
||||||
|
|
||||||
|
|
||||||
|
def _run_concurrent_stream_stream(stub): |
||||||
|
condition = threading.Condition() |
||||||
|
outcomes = [None] * test_constants.RPC_CONCURRENCY |
||||||
|
|
||||||
|
def run_stream_stream(index): |
||||||
|
outcome = _run_stream_stream(stub) |
||||||
|
with condition: |
||||||
|
outcomes[index] = outcome |
||||||
|
condition.notify() |
||||||
|
|
||||||
|
for index in range(test_constants.RPC_CONCURRENCY): |
||||||
|
thread = threading.Thread(target=run_stream_stream, args=(index,)) |
||||||
|
thread.start() |
||||||
|
with condition: |
||||||
|
while True: |
||||||
|
if all(outcomes): |
||||||
|
for outcome in outcomes: |
||||||
|
if outcome.kind is not Outcome.Kind.SATISFACTORY: |
||||||
|
return _UNSATISFACTORY_OUTCOME |
||||||
|
else: |
||||||
|
return _SATISFACTORY_OUTCOME |
||||||
|
else: |
||||||
|
condition.wait() |
||||||
|
|
||||||
|
|
||||||
|
def _run_cancel_unary_unary(stub): |
||||||
|
response_future_call = stub.UnUn.future( |
||||||
|
_application_common.UNARY_UNARY_REQUEST) |
||||||
|
initial_metadata = response_future_call.initial_metadata() |
||||||
|
cancelled = response_future_call.cancel() |
||||||
|
if initial_metadata is not None and cancelled: |
||||||
|
return _SATISFACTORY_OUTCOME |
||||||
|
else: |
||||||
|
return _UNSATISFACTORY_OUTCOME |
||||||
|
|
||||||
|
|
||||||
|
def _run_infinite_request_stream(stub): |
||||||
|
|
||||||
|
def infinite_request_iterator(): |
||||||
|
while True: |
||||||
|
yield _application_common.STREAM_UNARY_REQUEST |
||||||
|
|
||||||
|
response_future_call = stub.StreUn.future( |
||||||
|
infinite_request_iterator(), |
||||||
|
timeout=_application_common.INFINITE_REQUEST_STREAM_TIMEOUT) |
||||||
|
if response_future_call.code() is grpc.StatusCode.DEADLINE_EXCEEDED: |
||||||
|
return _SATISFACTORY_OUTCOME |
||||||
|
else: |
||||||
|
return _UNSATISFACTORY_OUTCOME |
||||||
|
|
||||||
|
|
||||||
|
def run(scenario, channel): |
||||||
|
stub = services_pb2_grpc.FirstServiceStub(channel) |
||||||
|
try: |
||||||
|
if scenario is Scenario.UNARY_UNARY: |
||||||
|
return _run_unary_unary(stub) |
||||||
|
elif scenario is Scenario.UNARY_STREAM: |
||||||
|
return _run_unary_stream(stub) |
||||||
|
elif scenario is Scenario.STREAM_UNARY: |
||||||
|
return _run_stream_unary(stub) |
||||||
|
elif scenario is Scenario.STREAM_STREAM: |
||||||
|
return _run_stream_stream(stub) |
||||||
|
elif scenario is Scenario.CONCURRENT_STREAM_UNARY: |
||||||
|
return _run_concurrent_stream_unary(stub) |
||||||
|
elif scenario is Scenario.CONCURRENT_STREAM_STREAM: |
||||||
|
return _run_concurrent_stream_stream(stub) |
||||||
|
elif scenario is Scenario.CANCEL_UNARY_UNARY: |
||||||
|
return _run_cancel_unary_unary(stub) |
||||||
|
elif scenario is Scenario.INFINITE_REQUEST_STREAM: |
||||||
|
return _run_infinite_request_stream(stub) |
||||||
|
except grpc.RpcError as rpc_error: |
||||||
|
return Outcome(Outcome.Kind.RPC_ERROR, |
||||||
|
rpc_error.code(), rpc_error.details()) |
||||||
|
|
||||||
|
|
||||||
|
_IMPLEMENTATIONS = { |
||||||
|
Scenario.UNARY_UNARY: _run_unary_unary, |
||||||
|
Scenario.UNARY_STREAM: _run_unary_stream, |
||||||
|
Scenario.STREAM_UNARY: _run_stream_unary, |
||||||
|
Scenario.STREAM_STREAM: _run_stream_stream, |
||||||
|
Scenario.CONCURRENT_STREAM_UNARY: _run_concurrent_stream_unary, |
||||||
|
Scenario.CONCURRENT_STREAM_STREAM: _run_concurrent_stream_stream, |
||||||
|
Scenario.CANCEL_UNARY_UNARY: _run_cancel_unary_unary, |
||||||
|
Scenario.INFINITE_REQUEST_STREAM: _run_infinite_request_stream, |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
def run(scenario, channel): |
||||||
|
stub = services_pb2_grpc.FirstServiceStub(channel) |
||||||
|
try: |
||||||
|
return _IMPLEMENTATIONS[scenario](stub) |
||||||
|
except grpc.RpcError as rpc_error: |
||||||
|
return Outcome(Outcome.Kind.RPC_ERROR, |
||||||
|
rpc_error.code(), rpc_error.details()) |
@ -0,0 +1,306 @@ |
|||||||
|
# Copyright 2017 gRPC authors. |
||||||
|
# |
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
# you may not use this file except in compliance with the License. |
||||||
|
# You may obtain a copy of the License at |
||||||
|
# |
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
# |
||||||
|
# Unless required by applicable law or agreed to in writing, software |
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
# See the License for the specific language governing permissions and |
||||||
|
# limitations under the License. |
||||||
|
|
||||||
|
from concurrent import futures |
||||||
|
import time |
||||||
|
import unittest |
||||||
|
|
||||||
|
import grpc |
||||||
|
from grpc.framework.foundation import logging_pool |
||||||
|
from tests.unit.framework.common import test_constants |
||||||
|
import grpc_testing |
||||||
|
|
||||||
|
from tests.testing import _application_common |
||||||
|
from tests.testing import _application_testing_common |
||||||
|
from tests.testing import _client_application |
||||||
|
from tests.testing.proto import requests_pb2 |
||||||
|
from tests.testing.proto import services_pb2 |
||||||
|
|
||||||
|
|
||||||
|
# TODO(https://github.com/google/protobuf/issues/3452): Drop this skip. |
||||||
|
@unittest.skipIf( |
||||||
|
services_pb2.DESCRIPTOR.services_by_name.get('FirstService') is None, |
||||||
|
'Fix protobuf issue 3452!') |
||||||
|
class ClientTest(unittest.TestCase): |
||||||
|
|
||||||
|
def setUp(self): |
||||||
|
# In this test the client-side application under test executes in |
||||||
|
# a separate thread while we retain use of the test thread to "play |
||||||
|
# server". |
||||||
|
self._client_execution_thread_pool = logging_pool.pool(1) |
||||||
|
|
||||||
|
self._fake_time = grpc_testing.strict_fake_time(time.time()) |
||||||
|
self._real_time = grpc_testing.strict_real_time() |
||||||
|
self._fake_time_channel = grpc_testing.channel( |
||||||
|
services_pb2.DESCRIPTOR.services_by_name.values(), self._fake_time) |
||||||
|
self._real_time_channel = grpc_testing.channel( |
||||||
|
services_pb2.DESCRIPTOR.services_by_name.values(), self._real_time) |
||||||
|
|
||||||
|
def tearDown(self): |
||||||
|
self._client_execution_thread_pool.shutdown(wait=True) |
||||||
|
|
||||||
|
def test_successful_unary_unary(self): |
||||||
|
application_future = self._client_execution_thread_pool.submit( |
||||||
|
_client_application.run, _client_application.Scenario.UNARY_UNARY, |
||||||
|
self._real_time_channel) |
||||||
|
invocation_metadata, request, rpc = ( |
||||||
|
self._real_time_channel.take_unary_unary( |
||||||
|
_application_testing_common.FIRST_SERVICE_UNUN)) |
||||||
|
rpc.send_initial_metadata(()) |
||||||
|
rpc.terminate(_application_common.UNARY_UNARY_RESPONSE, (), |
||||||
|
grpc.StatusCode.OK, '') |
||||||
|
application_return_value = application_future.result() |
||||||
|
|
||||||
|
self.assertEqual(_application_common.UNARY_UNARY_REQUEST, request) |
||||||
|
self.assertIs(application_return_value.kind, |
||||||
|
_client_application.Outcome.Kind.SATISFACTORY) |
||||||
|
|
||||||
|
def test_successful_unary_stream(self): |
||||||
|
application_future = self._client_execution_thread_pool.submit( |
||||||
|
_client_application.run, _client_application.Scenario.UNARY_STREAM, |
||||||
|
self._fake_time_channel) |
||||||
|
invocation_metadata, request, rpc = ( |
||||||
|
self._fake_time_channel.take_unary_stream( |
||||||
|
_application_testing_common.FIRST_SERVICE_UNSTRE)) |
||||||
|
rpc.send_initial_metadata(()) |
||||||
|
rpc.terminate((), grpc.StatusCode.OK, '') |
||||||
|
application_return_value = application_future.result() |
||||||
|
|
||||||
|
self.assertEqual(_application_common.UNARY_STREAM_REQUEST, request) |
||||||
|
self.assertIs(application_return_value.kind, |
||||||
|
_client_application.Outcome.Kind.SATISFACTORY) |
||||||
|
|
||||||
|
def test_successful_stream_unary(self): |
||||||
|
application_future = self._client_execution_thread_pool.submit( |
||||||
|
_client_application.run, _client_application.Scenario.STREAM_UNARY, |
||||||
|
self._real_time_channel) |
||||||
|
invocation_metadata, rpc = self._real_time_channel.take_stream_unary( |
||||||
|
_application_testing_common.FIRST_SERVICE_STREUN) |
||||||
|
rpc.send_initial_metadata(()) |
||||||
|
first_request = rpc.take_request() |
||||||
|
second_request = rpc.take_request() |
||||||
|
third_request = rpc.take_request() |
||||||
|
rpc.requests_closed() |
||||||
|
rpc.terminate(_application_common.STREAM_UNARY_RESPONSE, (), |
||||||
|
grpc.StatusCode.OK, '') |
||||||
|
application_return_value = application_future.result() |
||||||
|
|
||||||
|
self.assertEqual(_application_common.STREAM_UNARY_REQUEST, |
||||||
|
first_request) |
||||||
|
self.assertEqual(_application_common.STREAM_UNARY_REQUEST, |
||||||
|
second_request) |
||||||
|
self.assertEqual(_application_common.STREAM_UNARY_REQUEST, |
||||||
|
third_request) |
||||||
|
self.assertIs(application_return_value.kind, |
||||||
|
_client_application.Outcome.Kind.SATISFACTORY) |
||||||
|
|
||||||
|
def test_successful_stream_stream(self): |
||||||
|
application_future = self._client_execution_thread_pool.submit( |
||||||
|
_client_application.run, _client_application.Scenario.STREAM_STREAM, |
||||||
|
self._fake_time_channel) |
||||||
|
invocation_metadata, rpc = self._fake_time_channel.take_stream_stream( |
||||||
|
_application_testing_common.FIRST_SERVICE_STRESTRE) |
||||||
|
first_request = rpc.take_request() |
||||||
|
rpc.send_response(_application_common.STREAM_STREAM_RESPONSE) |
||||||
|
rpc.send_response(_application_common.STREAM_STREAM_RESPONSE) |
||||||
|
second_request = rpc.take_request() |
||||||
|
rpc.send_response(_application_common.STREAM_STREAM_RESPONSE) |
||||||
|
rpc.send_response(_application_common.STREAM_STREAM_RESPONSE) |
||||||
|
rpc.requests_closed() |
||||||
|
rpc.terminate((), grpc.StatusCode.OK, '') |
||||||
|
application_return_value = application_future.result() |
||||||
|
|
||||||
|
self.assertEqual(_application_common.STREAM_STREAM_REQUEST, |
||||||
|
first_request) |
||||||
|
self.assertEqual(_application_common.STREAM_STREAM_REQUEST, |
||||||
|
second_request) |
||||||
|
self.assertIs(application_return_value.kind, |
||||||
|
_client_application.Outcome.Kind.SATISFACTORY) |
||||||
|
|
||||||
|
def test_concurrent_stream_stream(self): |
||||||
|
application_future = self._client_execution_thread_pool.submit( |
||||||
|
_client_application.run, |
||||||
|
_client_application.Scenario.CONCURRENT_STREAM_STREAM, |
||||||
|
self._real_time_channel) |
||||||
|
rpcs = [] |
||||||
|
for _ in range(test_constants.RPC_CONCURRENCY): |
||||||
|
invocation_metadata, rpc = ( |
||||||
|
self._real_time_channel.take_stream_stream( |
||||||
|
_application_testing_common.FIRST_SERVICE_STRESTRE)) |
||||||
|
rpcs.append(rpc) |
||||||
|
requests = {} |
||||||
|
for rpc in rpcs: |
||||||
|
requests[rpc] = [rpc.take_request()] |
||||||
|
for rpc in rpcs: |
||||||
|
rpc.send_response(_application_common.STREAM_STREAM_RESPONSE) |
||||||
|
rpc.send_response(_application_common.STREAM_STREAM_RESPONSE) |
||||||
|
for rpc in rpcs: |
||||||
|
requests[rpc].append(rpc.take_request()) |
||||||
|
for rpc in rpcs: |
||||||
|
rpc.send_response(_application_common.STREAM_STREAM_RESPONSE) |
||||||
|
rpc.send_response(_application_common.STREAM_STREAM_RESPONSE) |
||||||
|
for rpc in rpcs: |
||||||
|
rpc.requests_closed() |
||||||
|
for rpc in rpcs: |
||||||
|
rpc.terminate((), grpc.StatusCode.OK, '') |
||||||
|
application_return_value = application_future.result() |
||||||
|
|
||||||
|
for requests_of_one_rpc in requests.values(): |
||||||
|
for request in requests_of_one_rpc: |
||||||
|
self.assertEqual(_application_common.STREAM_STREAM_REQUEST, |
||||||
|
request) |
||||||
|
self.assertIs(application_return_value.kind, |
||||||
|
_client_application.Outcome.Kind.SATISFACTORY) |
||||||
|
|
||||||
|
def test_cancelled_unary_unary(self): |
||||||
|
application_future = self._client_execution_thread_pool.submit( |
||||||
|
_client_application.run, |
||||||
|
_client_application.Scenario.CANCEL_UNARY_UNARY, |
||||||
|
self._fake_time_channel) |
||||||
|
invocation_metadata, request, rpc = ( |
||||||
|
self._fake_time_channel.take_unary_unary( |
||||||
|
_application_testing_common.FIRST_SERVICE_UNUN)) |
||||||
|
rpc.send_initial_metadata(()) |
||||||
|
rpc.cancelled() |
||||||
|
application_return_value = application_future.result() |
||||||
|
|
||||||
|
self.assertEqual(_application_common.UNARY_UNARY_REQUEST, request) |
||||||
|
self.assertIs(application_return_value.kind, |
||||||
|
_client_application.Outcome.Kind.SATISFACTORY) |
||||||
|
|
||||||
|
def test_status_stream_unary(self): |
||||||
|
application_future = self._client_execution_thread_pool.submit( |
||||||
|
_client_application.run, |
||||||
|
_client_application.Scenario.CONCURRENT_STREAM_UNARY, |
||||||
|
self._fake_time_channel) |
||||||
|
rpcs = tuple( |
||||||
|
self._fake_time_channel.take_stream_unary( |
||||||
|
_application_testing_common.FIRST_SERVICE_STREUN)[1] |
||||||
|
for _ in range(test_constants.THREAD_CONCURRENCY)) |
||||||
|
for rpc in rpcs: |
||||||
|
rpc.take_request() |
||||||
|
rpc.take_request() |
||||||
|
rpc.take_request() |
||||||
|
rpc.requests_closed() |
||||||
|
rpc.send_initial_metadata(( |
||||||
|
('my_metadata_key', 'My Metadata Value!',),)) |
||||||
|
for rpc in rpcs[:-1]: |
||||||
|
rpc.terminate(_application_common.STREAM_UNARY_RESPONSE, (), |
||||||
|
grpc.StatusCode.OK, '') |
||||||
|
rpcs[-1].terminate(_application_common.STREAM_UNARY_RESPONSE, (), |
||||||
|
grpc.StatusCode.RESOURCE_EXHAUSTED, |
||||||
|
'nope; not able to handle all those RPCs!') |
||||||
|
application_return_value = application_future.result() |
||||||
|
|
||||||
|
self.assertIs(application_return_value.kind, |
||||||
|
_client_application.Outcome.Kind.UNSATISFACTORY) |
||||||
|
|
||||||
|
def test_status_stream_stream(self): |
||||||
|
code = grpc.StatusCode.DEADLINE_EXCEEDED |
||||||
|
details = 'test deadline exceeded!' |
||||||
|
|
||||||
|
application_future = self._client_execution_thread_pool.submit( |
||||||
|
_client_application.run, _client_application.Scenario.STREAM_STREAM, |
||||||
|
self._real_time_channel) |
||||||
|
invocation_metadata, rpc = self._real_time_channel.take_stream_stream( |
||||||
|
_application_testing_common.FIRST_SERVICE_STRESTRE) |
||||||
|
first_request = rpc.take_request() |
||||||
|
rpc.send_response(_application_common.STREAM_STREAM_RESPONSE) |
||||||
|
rpc.send_response(_application_common.STREAM_STREAM_RESPONSE) |
||||||
|
second_request = rpc.take_request() |
||||||
|
rpc.send_response(_application_common.STREAM_STREAM_RESPONSE) |
||||||
|
rpc.send_response(_application_common.STREAM_STREAM_RESPONSE) |
||||||
|
rpc.requests_closed() |
||||||
|
rpc.terminate((), code, details) |
||||||
|
application_return_value = application_future.result() |
||||||
|
|
||||||
|
self.assertEqual(_application_common.STREAM_STREAM_REQUEST, |
||||||
|
first_request) |
||||||
|
self.assertEqual(_application_common.STREAM_STREAM_REQUEST, |
||||||
|
second_request) |
||||||
|
self.assertIs(application_return_value.kind, |
||||||
|
_client_application.Outcome.Kind.RPC_ERROR) |
||||||
|
self.assertIs(application_return_value.code, code) |
||||||
|
self.assertEqual(application_return_value.details, details) |
||||||
|
|
||||||
|
def test_misbehaving_server_unary_unary(self): |
||||||
|
application_future = self._client_execution_thread_pool.submit( |
||||||
|
_client_application.run, _client_application.Scenario.UNARY_UNARY, |
||||||
|
self._fake_time_channel) |
||||||
|
invocation_metadata, request, rpc = ( |
||||||
|
self._fake_time_channel.take_unary_unary( |
||||||
|
_application_testing_common.FIRST_SERVICE_UNUN)) |
||||||
|
rpc.send_initial_metadata(()) |
||||||
|
rpc.terminate(_application_common.ERRONEOUS_UNARY_UNARY_RESPONSE, (), |
||||||
|
grpc.StatusCode.OK, '') |
||||||
|
application_return_value = application_future.result() |
||||||
|
|
||||||
|
self.assertEqual(_application_common.UNARY_UNARY_REQUEST, request) |
||||||
|
self.assertIs(application_return_value.kind, |
||||||
|
_client_application.Outcome.Kind.UNSATISFACTORY) |
||||||
|
|
||||||
|
def test_misbehaving_server_stream_stream(self): |
||||||
|
application_future = self._client_execution_thread_pool.submit( |
||||||
|
_client_application.run, _client_application.Scenario.STREAM_STREAM, |
||||||
|
self._real_time_channel) |
||||||
|
invocation_metadata, rpc = self._real_time_channel.take_stream_stream( |
||||||
|
_application_testing_common.FIRST_SERVICE_STRESTRE) |
||||||
|
first_request = rpc.take_request() |
||||||
|
rpc.send_response(_application_common.STREAM_STREAM_RESPONSE) |
||||||
|
rpc.send_response(_application_common.STREAM_STREAM_RESPONSE) |
||||||
|
rpc.send_response(_application_common.STREAM_STREAM_RESPONSE) |
||||||
|
second_request = rpc.take_request() |
||||||
|
rpc.send_response(_application_common.STREAM_STREAM_RESPONSE) |
||||||
|
rpc.send_response(_application_common.STREAM_STREAM_RESPONSE) |
||||||
|
rpc.send_response(_application_common.STREAM_STREAM_RESPONSE) |
||||||
|
rpc.requests_closed() |
||||||
|
rpc.terminate((), grpc.StatusCode.OK, '') |
||||||
|
application_return_value = application_future.result() |
||||||
|
|
||||||
|
self.assertEqual(_application_common.STREAM_STREAM_REQUEST, |
||||||
|
first_request) |
||||||
|
self.assertEqual(_application_common.STREAM_STREAM_REQUEST, |
||||||
|
second_request) |
||||||
|
self.assertIs(application_return_value.kind, |
||||||
|
_client_application.Outcome.Kind.UNSATISFACTORY) |
||||||
|
|
||||||
|
def test_infinite_request_stream_real_time(self): |
||||||
|
application_future = self._client_execution_thread_pool.submit( |
||||||
|
_client_application.run, |
||||||
|
_client_application.Scenario.INFINITE_REQUEST_STREAM, |
||||||
|
self._real_time_channel) |
||||||
|
invocation_metadata, rpc = self._real_time_channel.take_stream_unary( |
||||||
|
_application_testing_common.FIRST_SERVICE_STREUN) |
||||||
|
rpc.send_initial_metadata(()) |
||||||
|
first_request = rpc.take_request() |
||||||
|
second_request = rpc.take_request() |
||||||
|
third_request = rpc.take_request() |
||||||
|
self._real_time.sleep_for( |
||||||
|
_application_common.INFINITE_REQUEST_STREAM_TIMEOUT) |
||||||
|
rpc.terminate(_application_common.STREAM_UNARY_RESPONSE, (), |
||||||
|
grpc.StatusCode.DEADLINE_EXCEEDED, '') |
||||||
|
application_return_value = application_future.result() |
||||||
|
|
||||||
|
self.assertEqual(_application_common.STREAM_UNARY_REQUEST, |
||||||
|
first_request) |
||||||
|
self.assertEqual(_application_common.STREAM_UNARY_REQUEST, |
||||||
|
second_request) |
||||||
|
self.assertEqual(_application_common.STREAM_UNARY_REQUEST, |
||||||
|
third_request) |
||||||
|
self.assertIs(application_return_value.kind, |
||||||
|
_client_application.Outcome.Kind.SATISFACTORY) |
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__': |
||||||
|
unittest.main(verbosity=2) |
@ -0,0 +1,13 @@ |
|||||||
|
# Copyright 2017 gRPC authors. |
||||||
|
# |
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
# you may not use this file except in compliance with the License. |
||||||
|
# You may obtain a copy of the License at |
||||||
|
# |
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
# |
||||||
|
# Unless required by applicable law or agreed to in writing, software |
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
# See the License for the specific language governing permissions and |
||||||
|
# limitations under the License. |
@ -0,0 +1,29 @@ |
|||||||
|
// Copyright 2015 gRPC authors. |
||||||
|
// |
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
// you may not use this file except in compliance with the License. |
||||||
|
// You may obtain a copy of the License at |
||||||
|
// |
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
// |
||||||
|
// Unless required by applicable law or agreed to in writing, software |
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
// See the License for the specific language governing permissions and |
||||||
|
// limitations under the License. |
||||||
|
|
||||||
|
syntax = "proto3"; |
||||||
|
|
||||||
|
package tests_of_grpc_testing; |
||||||
|
|
||||||
|
message Up { |
||||||
|
int32 first_up_field = 1; |
||||||
|
} |
||||||
|
|
||||||
|
message Charm { |
||||||
|
int32 first_charm_field = 1; |
||||||
|
} |
||||||
|
|
||||||
|
message Top { |
||||||
|
int32 first_top_field = 1; |
||||||
|
} |
@ -0,0 +1,42 @@ |
|||||||
|
// Copyright 2017 gRPC authors. |
||||||
|
// |
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
// you may not use this file except in compliance with the License. |
||||||
|
// You may obtain a copy of the License at |
||||||
|
// |
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0 |
||||||
|
// |
||||||
|
// Unless required by applicable law or agreed to in writing, software |
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
// See the License for the specific language governing permissions and |
||||||
|
// limitations under the License. |
||||||
|
|
||||||
|
syntax = "proto3"; |
||||||
|
|
||||||
|
import "tests/testing/proto/requests.proto"; |
||||||
|
|
||||||
|
package tests_of_grpc_testing; |
||||||
|
|
||||||
|
message Down { |
||||||
|
int32 first_down_field = 1; |
||||||
|
} |
||||||
|
|
||||||
|
message Strange { |
||||||
|
int32 first_strange_field = 1; |
||||||
|
} |
||||||
|
|
||||||
|
message Bottom { |
||||||
|
int32 first_bottom_field = 1; |
||||||
|
} |
||||||
|
|
||||||
|
service FirstService { |
||||||
|
rpc UnUn(Up) returns (Down); |
||||||
|
rpc UnStre(Charm) returns (stream Strange); |
||||||
|
rpc StreUn(stream Charm) returns (Strange); |
||||||
|
rpc StreStre(stream Top) returns (stream Bottom); |
||||||
|
} |
||||||
|
|
||||||
|
service SecondService { |
||||||
|
rpc UnStre(Strange) returns (stream Charm); |
||||||
|
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue