commit
da8a169928
105 changed files with 4575 additions and 4743 deletions
File diff suppressed because it is too large
Load Diff
@ -1,28 +0,0 @@ |
|||||||
/*
|
|
||||||
* |
|
||||||
* 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. |
|
||||||
* |
|
||||||
*/ |
|
||||||
|
|
||||||
#ifndef GRPC_CORE_LIB_IOMGR_EV_EPOLL_LIMITED_POLLERS_LINUX_H |
|
||||||
#define GRPC_CORE_LIB_IOMGR_EV_EPOLL_LIMITED_POLLERS_LINUX_H |
|
||||||
|
|
||||||
#include "src/core/lib/iomgr/ev_posix.h" |
|
||||||
#include "src/core/lib/iomgr/port.h" |
|
||||||
|
|
||||||
const grpc_event_engine_vtable *grpc_init_epoll_limited_pollers_linux( |
|
||||||
bool explicitly_requested); |
|
||||||
|
|
||||||
#endif /* GRPC_CORE_LIB_IOMGR_EV_EPOLL_LIMITED_POLLERS_LINUX_H */ |
|
File diff suppressed because it is too large
Load Diff
@ -1,28 +0,0 @@ |
|||||||
/*
|
|
||||||
* |
|
||||||
* 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_EV_EPOLL_THREAD_POOL_LINUX_H |
|
||||||
#define GRPC_CORE_LIB_IOMGR_EV_EPOLL_THREAD_POOL_LINUX_H |
|
||||||
|
|
||||||
#include "src/core/lib/iomgr/ev_posix.h" |
|
||||||
#include "src/core/lib/iomgr/port.h" |
|
||||||
|
|
||||||
const grpc_event_engine_vtable *grpc_init_epoll_thread_pool_linux( |
|
||||||
bool requested_explicitly); |
|
||||||
|
|
||||||
#endif /* GRPC_CORE_LIB_IOMGR_EV_EPOLL_THREAD_POOL_LINUX_H */ |
|
@ -0,0 +1,20 @@ |
|||||||
|
# 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._server import _server |
||||||
|
|
||||||
|
|
||||||
|
def server_from_dictionary(descriptors_to_servicers, time): |
||||||
|
return _server.server_from_descriptor_to_servicers( |
||||||
|
descriptors_to_servicers, time) |
@ -0,0 +1,215 @@ |
|||||||
|
# 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 abc |
||||||
|
import threading |
||||||
|
|
||||||
|
import grpc |
||||||
|
from grpc_testing import _common |
||||||
|
|
||||||
|
_CLIENT_INACTIVE = object() |
||||||
|
|
||||||
|
|
||||||
|
class Handler(_common.ServerRpcHandler): |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def initial_metadata(self): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def add_request(self, request): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def take_response(self): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def requests_closed(self): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def cancel(self): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def unary_response_termination(self): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def stream_response_termination(self): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
|
||||||
|
class _Handler(Handler): |
||||||
|
|
||||||
|
def __init__(self, requests_closed): |
||||||
|
self._condition = threading.Condition() |
||||||
|
self._requests = [] |
||||||
|
self._requests_closed = requests_closed |
||||||
|
self._initial_metadata = None |
||||||
|
self._responses = [] |
||||||
|
self._trailing_metadata = None |
||||||
|
self._code = None |
||||||
|
self._details = None |
||||||
|
self._unary_response = None |
||||||
|
self._expiration_future = None |
||||||
|
self._termination_callbacks = [] |
||||||
|
|
||||||
|
def send_initial_metadata(self, initial_metadata): |
||||||
|
with self._condition: |
||||||
|
self._initial_metadata = initial_metadata |
||||||
|
self._condition.notify_all() |
||||||
|
|
||||||
|
def take_request(self): |
||||||
|
with self._condition: |
||||||
|
while True: |
||||||
|
if self._code is None: |
||||||
|
if self._requests: |
||||||
|
request = self._requests.pop(0) |
||||||
|
self._condition.notify_all() |
||||||
|
return _common.ServerRpcRead(request, False, False) |
||||||
|
elif self._requests_closed: |
||||||
|
return _common.REQUESTS_CLOSED |
||||||
|
else: |
||||||
|
self._condition.wait() |
||||||
|
else: |
||||||
|
return _common.TERMINATED |
||||||
|
|
||||||
|
def is_active(self): |
||||||
|
with self._condition: |
||||||
|
return self._code is None |
||||||
|
|
||||||
|
def add_response(self, response): |
||||||
|
with self._condition: |
||||||
|
self._responses.append(response) |
||||||
|
self._condition.notify_all() |
||||||
|
|
||||||
|
def send_termination(self, trailing_metadata, code, details): |
||||||
|
with self._condition: |
||||||
|
self._trailing_metadata = trailing_metadata |
||||||
|
self._code = code |
||||||
|
self._details = details |
||||||
|
if self._expiration_future is not None: |
||||||
|
self._expiration_future.cancel() |
||||||
|
self._condition.notify_all() |
||||||
|
|
||||||
|
def add_termination_callback(self, termination_callback): |
||||||
|
with self._condition: |
||||||
|
if self._code is None: |
||||||
|
self._termination_callbacks.append(termination_callback) |
||||||
|
return True |
||||||
|
else: |
||||||
|
return False |
||||||
|
|
||||||
|
def initial_metadata(self): |
||||||
|
with self._condition: |
||||||
|
while True: |
||||||
|
if self._initial_metadata is None: |
||||||
|
if self._code is None: |
||||||
|
self._condition.wait() |
||||||
|
else: |
||||||
|
raise ValueError( |
||||||
|
'No initial metadata despite status code!') |
||||||
|
else: |
||||||
|
return self._initial_metadata |
||||||
|
|
||||||
|
def add_request(self, request): |
||||||
|
with self._condition: |
||||||
|
self._requests.append(request) |
||||||
|
self._condition.notify_all() |
||||||
|
|
||||||
|
def take_response(self): |
||||||
|
with self._condition: |
||||||
|
while True: |
||||||
|
if self._responses: |
||||||
|
response = self._responses.pop(0) |
||||||
|
self._condition.notify_all() |
||||||
|
return response |
||||||
|
elif self._code is None: |
||||||
|
self._condition.wait() |
||||||
|
else: |
||||||
|
raise ValueError('No more responses!') |
||||||
|
|
||||||
|
def requests_closed(self): |
||||||
|
with self._condition: |
||||||
|
self._requests_closed = True |
||||||
|
self._condition.notify_all() |
||||||
|
|
||||||
|
def cancel(self): |
||||||
|
with self._condition: |
||||||
|
if self._code is None: |
||||||
|
self._code = _CLIENT_INACTIVE |
||||||
|
termination_callbacks = self._termination_callbacks |
||||||
|
self._termination_callbacks = None |
||||||
|
if self._expiration_future is not None: |
||||||
|
self._expiration_future.cancel() |
||||||
|
self._condition.notify_all() |
||||||
|
for termination_callback in termination_callbacks: |
||||||
|
termination_callback() |
||||||
|
|
||||||
|
def unary_response_termination(self): |
||||||
|
with self._condition: |
||||||
|
while True: |
||||||
|
if self._code is _CLIENT_INACTIVE: |
||||||
|
raise ValueError('Huh? Cancelled but wanting status?') |
||||||
|
elif self._code is None: |
||||||
|
self._condition.wait() |
||||||
|
else: |
||||||
|
if self._unary_response is None: |
||||||
|
if self._responses: |
||||||
|
self._unary_response = self._responses.pop(0) |
||||||
|
return ( |
||||||
|
self._unary_response, self._trailing_metadata, |
||||||
|
self._code, self._details,) |
||||||
|
|
||||||
|
|
||||||
|
def stream_response_termination(self): |
||||||
|
with self._condition: |
||||||
|
while True: |
||||||
|
if self._code is _CLIENT_INACTIVE: |
||||||
|
raise ValueError('Huh? Cancelled but wanting status?') |
||||||
|
elif self._code is None: |
||||||
|
self._condition.wait() |
||||||
|
else: |
||||||
|
return self._trailing_metadata, self._code, self._details, |
||||||
|
|
||||||
|
def expire(self): |
||||||
|
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 = grpc.StatusCode.DEADLINE_EXCEEDED |
||||||
|
self._details = 'Took too much time!' |
||||||
|
termination_callbacks = self._termination_callbacks |
||||||
|
self._termination_callbacks = None |
||||||
|
self._condition.notify_all() |
||||||
|
for termination_callback in termination_callbacks: |
||||||
|
termination_callback() |
||||||
|
|
||||||
|
def set_expiration_future(self, expiration_future): |
||||||
|
with self._condition: |
||||||
|
self._expiration_future = expiration_future |
||||||
|
|
||||||
|
|
||||||
|
def handler_without_deadline(requests_closed): |
||||||
|
return _Handler(requests_closed) |
||||||
|
|
||||||
|
|
||||||
|
def handler_with_deadline(requests_closed, time, deadline): |
||||||
|
handler = _Handler(requests_closed) |
||||||
|
expiration_future = time.call_at(handler.expire, deadline) |
||||||
|
handler.set_expiration_future(expiration_future) |
||||||
|
return handler |
@ -0,0 +1,153 @@ |
|||||||
|
# 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 |
||||||
|
from grpc_testing import _common |
||||||
|
|
||||||
|
|
||||||
|
class Rpc(object): |
||||||
|
|
||||||
|
def __init__(self, handler, invocation_metadata): |
||||||
|
self._condition = threading.Condition() |
||||||
|
self._handler = handler |
||||||
|
self._invocation_metadata = invocation_metadata |
||||||
|
self._initial_metadata_sent = False |
||||||
|
self._pending_trailing_metadata = None |
||||||
|
self._pending_code = None |
||||||
|
self._pending_details = None |
||||||
|
self._callbacks = [] |
||||||
|
self._active = True |
||||||
|
self._rpc_errors = [] |
||||||
|
|
||||||
|
def _ensure_initial_metadata_sent(self): |
||||||
|
if not self._initial_metadata_sent: |
||||||
|
self._handler.send_initial_metadata(_common.FUSSED_EMPTY_METADATA) |
||||||
|
self._initial_metadata_sent = True |
||||||
|
|
||||||
|
def _call_back(self): |
||||||
|
callbacks = tuple(self._callbacks) |
||||||
|
self._callbacks = None |
||||||
|
|
||||||
|
def call_back(): |
||||||
|
for callback in callbacks: |
||||||
|
try: |
||||||
|
callback() |
||||||
|
except Exception: # pylint: disable=broad-except |
||||||
|
logging.exception('Exception calling server-side callback!') |
||||||
|
|
||||||
|
callback_calling_thread = threading.Thread(target=call_back) |
||||||
|
callback_calling_thread.start() |
||||||
|
|
||||||
|
def _terminate(self, trailing_metadata, code, details): |
||||||
|
if self._active: |
||||||
|
self._active = False |
||||||
|
self._handler.send_termination(trailing_metadata, code, details) |
||||||
|
self._call_back() |
||||||
|
self._condition.notify_all() |
||||||
|
|
||||||
|
def _complete(self): |
||||||
|
if self._pending_trailing_metadata is None: |
||||||
|
trailing_metadata = _common.FUSSED_EMPTY_METADATA |
||||||
|
else: |
||||||
|
trailing_metadata = self._pending_trailing_metadata |
||||||
|
if self._pending_code is None: |
||||||
|
code = grpc.StatusCode.OK |
||||||
|
else: |
||||||
|
code = self._pending_code |
||||||
|
details = '' if self._pending_details is None else self._pending_details |
||||||
|
self._terminate(trailing_metadata, code, details) |
||||||
|
|
||||||
|
def _abort(self, code, details): |
||||||
|
self._terminate(_common.FUSSED_EMPTY_METADATA, code, details) |
||||||
|
|
||||||
|
def add_rpc_error(self, rpc_error): |
||||||
|
with self._condition: |
||||||
|
self._rpc_errors.append(rpc_error) |
||||||
|
|
||||||
|
def application_cancel(self): |
||||||
|
with self._condition: |
||||||
|
self._abort( |
||||||
|
grpc.StatusCode.CANCELLED, |
||||||
|
'Cancelled by server-side application!') |
||||||
|
|
||||||
|
def application_exception_abort(self, exception): |
||||||
|
with self._condition: |
||||||
|
if exception not in self._rpc_errors: |
||||||
|
logging.exception('Exception calling application!') |
||||||
|
self._abort( |
||||||
|
grpc.StatusCode.UNKNOWN, |
||||||
|
'Exception calling application: {}'.format(exception)) |
||||||
|
|
||||||
|
def extrinsic_abort(self): |
||||||
|
with self._condition: |
||||||
|
if self._active: |
||||||
|
self._active = False |
||||||
|
self._call_back() |
||||||
|
self._condition.notify_all() |
||||||
|
|
||||||
|
def unary_response_complete(self, response): |
||||||
|
with self._condition: |
||||||
|
self._ensure_initial_metadata_sent() |
||||||
|
self._handler.add_response(response) |
||||||
|
self._complete() |
||||||
|
|
||||||
|
def stream_response(self, response): |
||||||
|
with self._condition: |
||||||
|
self._ensure_initial_metadata_sent() |
||||||
|
self._handler.add_response(response) |
||||||
|
|
||||||
|
def stream_response_complete(self): |
||||||
|
with self._condition: |
||||||
|
self._ensure_initial_metadata_sent() |
||||||
|
self._complete() |
||||||
|
|
||||||
|
def send_initial_metadata(self, initial_metadata): |
||||||
|
with self._condition: |
||||||
|
if self._initial_metadata_sent: |
||||||
|
return False |
||||||
|
else: |
||||||
|
self._handler.send_initial_metadata(initial_metadata) |
||||||
|
self._initial_metadata_sent = True |
||||||
|
return True |
||||||
|
|
||||||
|
def is_active(self): |
||||||
|
with self._condition: |
||||||
|
return self._active |
||||||
|
|
||||||
|
def add_callback(self, callback): |
||||||
|
with self._condition: |
||||||
|
if self._callbacks is None: |
||||||
|
return False |
||||||
|
else: |
||||||
|
self._callbacks.append(callback) |
||||||
|
return True |
||||||
|
|
||||||
|
def invocation_metadata(self): |
||||||
|
with self._condition: |
||||||
|
return self._invocation_metadata |
||||||
|
|
||||||
|
def set_trailing_metadata(self, trailing_metadata): |
||||||
|
with self._condition: |
||||||
|
self._pending_trailing_metadata = trailing_metadata |
||||||
|
|
||||||
|
def set_code(self, code): |
||||||
|
with self._condition: |
||||||
|
self._pending_code = code |
||||||
|
|
||||||
|
def set_details(self, details): |
||||||
|
with self._condition: |
||||||
|
self._pending_details = details |
@ -0,0 +1,149 @@ |
|||||||
|
# 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_testing |
||||||
|
from grpc_testing import _common |
||||||
|
from grpc_testing._server import _handler |
||||||
|
from grpc_testing._server import _rpc |
||||||
|
from grpc_testing._server import _server_rpc |
||||||
|
from grpc_testing._server import _service |
||||||
|
from grpc_testing._server import _servicer_context |
||||||
|
|
||||||
|
|
||||||
|
def _implementation(descriptors_to_servicers, method_descriptor): |
||||||
|
servicer = descriptors_to_servicers[method_descriptor.containing_service] |
||||||
|
return getattr(servicer, method_descriptor.name) |
||||||
|
|
||||||
|
|
||||||
|
def _unary_unary_service(request): |
||||||
|
def service(implementation, rpc, servicer_context): |
||||||
|
_service.unary_unary( |
||||||
|
implementation, rpc, request, servicer_context) |
||||||
|
return service |
||||||
|
|
||||||
|
|
||||||
|
def _unary_stream_service(request): |
||||||
|
def service(implementation, rpc, servicer_context): |
||||||
|
_service.unary_stream( |
||||||
|
implementation, rpc, request, servicer_context) |
||||||
|
return service |
||||||
|
|
||||||
|
|
||||||
|
def _stream_unary_service(handler): |
||||||
|
def service(implementation, rpc, servicer_context): |
||||||
|
_service.stream_unary(implementation, rpc, handler, servicer_context) |
||||||
|
return service |
||||||
|
|
||||||
|
|
||||||
|
def _stream_stream_service(handler): |
||||||
|
def service(implementation, rpc, servicer_context): |
||||||
|
_service.stream_stream(implementation, rpc, handler, servicer_context) |
||||||
|
return service |
||||||
|
|
||||||
|
|
||||||
|
class _Serverish(_common.Serverish): |
||||||
|
|
||||||
|
def __init__(self, descriptors_to_servicers, time): |
||||||
|
self._descriptors_to_servicers = descriptors_to_servicers |
||||||
|
self._time = time |
||||||
|
|
||||||
|
def _invoke( |
||||||
|
self, service_behavior, method_descriptor, handler, |
||||||
|
invocation_metadata, deadline): |
||||||
|
implementation = _implementation( |
||||||
|
self._descriptors_to_servicers, method_descriptor) |
||||||
|
rpc = _rpc.Rpc(handler, invocation_metadata) |
||||||
|
if handler.add_termination_callback(rpc.extrinsic_abort): |
||||||
|
servicer_context = _servicer_context.ServicerContext( |
||||||
|
rpc, self._time, deadline) |
||||||
|
service_thread = threading.Thread( |
||||||
|
target=service_behavior, |
||||||
|
args=(implementation, rpc, servicer_context,)) |
||||||
|
service_thread.start() |
||||||
|
|
||||||
|
def invoke_unary_unary( |
||||||
|
self, method_descriptor, handler, invocation_metadata, request, |
||||||
|
deadline): |
||||||
|
self._invoke( |
||||||
|
_unary_unary_service(request), method_descriptor, handler, |
||||||
|
invocation_metadata, deadline) |
||||||
|
|
||||||
|
def invoke_unary_stream( |
||||||
|
self, method_descriptor, handler, invocation_metadata, request, |
||||||
|
deadline): |
||||||
|
self._invoke( |
||||||
|
_unary_stream_service(request), method_descriptor, handler, |
||||||
|
invocation_metadata, deadline) |
||||||
|
|
||||||
|
def invoke_stream_unary( |
||||||
|
self, method_descriptor, handler, invocation_metadata, deadline): |
||||||
|
self._invoke( |
||||||
|
_stream_unary_service(handler), method_descriptor, handler, |
||||||
|
invocation_metadata, deadline) |
||||||
|
|
||||||
|
def invoke_stream_stream( |
||||||
|
self, method_descriptor, handler, invocation_metadata, deadline): |
||||||
|
self._invoke( |
||||||
|
_stream_stream_service(handler), method_descriptor, handler, |
||||||
|
invocation_metadata, deadline) |
||||||
|
|
||||||
|
|
||||||
|
def _deadline_and_handler(requests_closed, time, timeout): |
||||||
|
if timeout is None: |
||||||
|
return None, _handler.handler_without_deadline(requests_closed) |
||||||
|
else: |
||||||
|
deadline = time.time() + timeout |
||||||
|
handler = _handler.handler_with_deadline(requests_closed, time, deadline) |
||||||
|
return deadline, handler |
||||||
|
|
||||||
|
|
||||||
|
class _Server(grpc_testing.Server): |
||||||
|
|
||||||
|
def __init__(self, serverish, time): |
||||||
|
self._serverish = serverish |
||||||
|
self._time = time |
||||||
|
|
||||||
|
def invoke_unary_unary( |
||||||
|
self, method_descriptor, invocation_metadata, request, timeout): |
||||||
|
deadline, handler = _deadline_and_handler(True, self._time, timeout) |
||||||
|
self._serverish.invoke_unary_unary( |
||||||
|
method_descriptor, handler, invocation_metadata, request, deadline) |
||||||
|
return _server_rpc.UnaryUnaryServerRpc(handler) |
||||||
|
|
||||||
|
def invoke_unary_stream( |
||||||
|
self, method_descriptor, invocation_metadata, request, timeout): |
||||||
|
deadline, handler = _deadline_and_handler(True, self._time, timeout) |
||||||
|
self._serverish.invoke_unary_stream( |
||||||
|
method_descriptor, handler, invocation_metadata, request, deadline) |
||||||
|
return _server_rpc.UnaryStreamServerRpc(handler) |
||||||
|
|
||||||
|
def invoke_stream_unary( |
||||||
|
self, method_descriptor, invocation_metadata, timeout): |
||||||
|
deadline, handler = _deadline_and_handler(False, self._time, timeout) |
||||||
|
self._serverish.invoke_stream_unary( |
||||||
|
method_descriptor, handler, invocation_metadata, deadline) |
||||||
|
return _server_rpc.StreamUnaryServerRpc(handler) |
||||||
|
|
||||||
|
def invoke_stream_stream( |
||||||
|
self, method_descriptor, invocation_metadata, timeout): |
||||||
|
deadline, handler = _deadline_and_handler(False, self._time, timeout) |
||||||
|
self._serverish.invoke_stream_stream( |
||||||
|
method_descriptor, handler, invocation_metadata, deadline) |
||||||
|
return _server_rpc.StreamStreamServerRpc(handler) |
||||||
|
|
||||||
|
|
||||||
|
def server_from_descriptor_to_servicers(descriptors_to_servicers, time): |
||||||
|
return _Server(_Serverish(descriptors_to_servicers, time), time) |
@ -0,0 +1,93 @@ |
|||||||
|
# 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 UnaryUnaryServerRpc(grpc_testing.UnaryUnaryServerRpc): |
||||||
|
|
||||||
|
def __init__(self, handler): |
||||||
|
self._handler = handler |
||||||
|
|
||||||
|
def initial_metadata(self): |
||||||
|
return self._handler.initial_metadata() |
||||||
|
|
||||||
|
def cancel(self): |
||||||
|
self._handler.cancel() |
||||||
|
|
||||||
|
def termination(self): |
||||||
|
return self._handler.unary_response_termination() |
||||||
|
|
||||||
|
|
||||||
|
class UnaryStreamServerRpc(grpc_testing.UnaryStreamServerRpc): |
||||||
|
|
||||||
|
def __init__(self, handler): |
||||||
|
self._handler = handler |
||||||
|
|
||||||
|
def initial_metadata(self): |
||||||
|
return self._handler.initial_metadata() |
||||||
|
|
||||||
|
def take_response(self): |
||||||
|
return self._handler.take_response() |
||||||
|
|
||||||
|
def cancel(self): |
||||||
|
self._handler.cancel() |
||||||
|
|
||||||
|
def termination(self): |
||||||
|
return self._handler.stream_response_termination() |
||||||
|
|
||||||
|
|
||||||
|
class StreamUnaryServerRpc(grpc_testing.StreamUnaryServerRpc): |
||||||
|
|
||||||
|
def __init__(self, handler): |
||||||
|
self._handler = handler |
||||||
|
|
||||||
|
def initial_metadata(self): |
||||||
|
return self._handler.initial_metadata() |
||||||
|
|
||||||
|
def send_request(self, request): |
||||||
|
self._handler.add_request(request) |
||||||
|
|
||||||
|
def requests_closed(self): |
||||||
|
self._handler.requests_closed() |
||||||
|
|
||||||
|
def cancel(self): |
||||||
|
self._handler.cancel() |
||||||
|
|
||||||
|
def termination(self): |
||||||
|
return self._handler.unary_response_termination() |
||||||
|
|
||||||
|
|
||||||
|
class StreamStreamServerRpc(grpc_testing.StreamStreamServerRpc): |
||||||
|
|
||||||
|
def __init__(self, handler): |
||||||
|
self._handler = handler |
||||||
|
|
||||||
|
def initial_metadata(self): |
||||||
|
return self._handler.initial_metadata() |
||||||
|
|
||||||
|
def send_request(self, request): |
||||||
|
self._handler.add_request(request) |
||||||
|
|
||||||
|
def requests_closed(self): |
||||||
|
self._handler.requests_closed() |
||||||
|
|
||||||
|
def take_response(self): |
||||||
|
return self._handler.take_response() |
||||||
|
|
||||||
|
def cancel(self): |
||||||
|
self._handler.cancel() |
||||||
|
|
||||||
|
def termination(self): |
||||||
|
return self._handler.stream_response_termination() |
@ -0,0 +1,88 @@ |
|||||||
|
# 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 |
||||||
|
|
||||||
|
|
||||||
|
class _RequestIterator(object): |
||||||
|
|
||||||
|
def __init__(self, rpc, handler): |
||||||
|
self._rpc = rpc |
||||||
|
self._handler = handler |
||||||
|
|
||||||
|
def _next(self): |
||||||
|
read = self._handler.take_request() |
||||||
|
if read.requests_closed: |
||||||
|
raise StopIteration() |
||||||
|
elif read.terminated: |
||||||
|
rpc_error = grpc.RpcError() |
||||||
|
self._rpc.add_rpc_error(rpc_error) |
||||||
|
raise rpc_error |
||||||
|
else: |
||||||
|
return read.request |
||||||
|
|
||||||
|
def __iter__(self): |
||||||
|
return self |
||||||
|
|
||||||
|
def __next__(self): |
||||||
|
return self._next() |
||||||
|
|
||||||
|
def next(self): |
||||||
|
return self._next() |
||||||
|
|
||||||
|
|
||||||
|
def _unary_response(argument, implementation, rpc, servicer_context): |
||||||
|
try: |
||||||
|
response = implementation(argument, servicer_context) |
||||||
|
except Exception as exception: # pylint: disable=broad-except |
||||||
|
rpc.application_exception_abort(exception) |
||||||
|
else: |
||||||
|
rpc.unary_response_complete(response) |
||||||
|
|
||||||
|
|
||||||
|
def _stream_response(argument, implementation, rpc, servicer_context): |
||||||
|
try: |
||||||
|
response_iterator = implementation(argument, servicer_context) |
||||||
|
except Exception as exception: # pylint: disable=broad-except |
||||||
|
rpc.application_exception_abort(exception) |
||||||
|
else: |
||||||
|
while True: |
||||||
|
try: |
||||||
|
response = next(response_iterator) |
||||||
|
except StopIteration: |
||||||
|
rpc.stream_response_complete() |
||||||
|
break |
||||||
|
except Exception as exception: # pylint: disable=broad-except |
||||||
|
rpc.application_exception_abort(exception) |
||||||
|
break |
||||||
|
else: |
||||||
|
rpc.stream_response(response) |
||||||
|
|
||||||
|
|
||||||
|
def unary_unary(implementation, rpc, request, servicer_context): |
||||||
|
_unary_response(request, implementation, rpc, servicer_context) |
||||||
|
|
||||||
|
|
||||||
|
def unary_stream(implementation, rpc, request, servicer_context): |
||||||
|
_stream_response(request, implementation, rpc, servicer_context) |
||||||
|
|
||||||
|
|
||||||
|
def stream_unary(implementation, rpc, handler, servicer_context): |
||||||
|
_unary_response( |
||||||
|
_RequestIterator(rpc, handler), implementation, rpc, servicer_context) |
||||||
|
|
||||||
|
|
||||||
|
def stream_stream(implementation, rpc, handler, servicer_context): |
||||||
|
_stream_response( |
||||||
|
_RequestIterator(rpc, handler), implementation, rpc, servicer_context) |
@ -0,0 +1,74 @@ |
|||||||
|
# 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 |
||||||
|
|
||||||
|
|
||||||
|
class ServicerContext(grpc.ServicerContext): |
||||||
|
|
||||||
|
def __init__(self, rpc, time, deadline): |
||||||
|
self._rpc = rpc |
||||||
|
self._time = time |
||||||
|
self._deadline = deadline |
||||||
|
|
||||||
|
def is_active(self): |
||||||
|
return self._rpc.is_active() |
||||||
|
|
||||||
|
def time_remaining(self): |
||||||
|
if self._rpc.is_active(): |
||||||
|
if self._deadline is None: |
||||||
|
return None |
||||||
|
else: |
||||||
|
return max(0.0, self._deadline - self._time.time()) |
||||||
|
else: |
||||||
|
return 0.0 |
||||||
|
|
||||||
|
def cancel(self): |
||||||
|
self._rpc.application_cancel() |
||||||
|
|
||||||
|
def add_callback(self, callback): |
||||||
|
return self._rpc.add_callback(callback) |
||||||
|
|
||||||
|
def invocation_metadata(self): |
||||||
|
return self._rpc.invocation_metadata() |
||||||
|
|
||||||
|
def peer(self): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
def peer_identities(self): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
def peer_identity_key(self): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
def auth_context(self): |
||||||
|
raise NotImplementedError() |
||||||
|
|
||||||
|
def send_initial_metadata(self, initial_metadata): |
||||||
|
initial_metadata_sent = self._rpc.send_initial_metadata( |
||||||
|
_common.fuss_with_metadata(initial_metadata)) |
||||||
|
if not initial_metadata_sent: |
||||||
|
raise ValueError( |
||||||
|
'ServicerContext.send_initial_metadata called too late!') |
||||||
|
|
||||||
|
def set_trailing_metadata(self, trailing_metadata): |
||||||
|
self._rpc.set_trailing_metadata( |
||||||
|
_common.fuss_with_metadata(trailing_metadata)) |
||||||
|
|
||||||
|
def set_code(self, code): |
||||||
|
self._rpc.set_code(code) |
||||||
|
|
||||||
|
def set_details(self, details): |
||||||
|
self._rpc.set_details(details) |
@ -0,0 +1,66 @@ |
|||||||
|
# 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 server-side application.""" |
||||||
|
|
||||||
|
import grpc |
||||||
|
|
||||||
|
# requests_pb2 is a semantic dependency of this module. |
||||||
|
from tests.testing import _application_common |
||||||
|
from tests.testing.proto import requests_pb2 # pylint: disable=unused-import |
||||||
|
from tests.testing.proto import services_pb2 |
||||||
|
from tests.testing.proto import services_pb2_grpc |
||||||
|
|
||||||
|
|
||||||
|
class FirstServiceServicer(services_pb2_grpc.FirstServiceServicer): |
||||||
|
"""Services RPCs.""" |
||||||
|
|
||||||
|
def UnUn(self, request, context): |
||||||
|
if _application_common.UNARY_UNARY_REQUEST == request: |
||||||
|
return _application_common.UNARY_UNARY_RESPONSE |
||||||
|
else: |
||||||
|
context.set_code(grpc.StatusCode.INVALID_ARGUMENT) |
||||||
|
context.set_details('Something is wrong with your request!') |
||||||
|
return services_pb2.Down() |
||||||
|
|
||||||
|
def UnStre(self, request, context): |
||||||
|
if _application_common.UNARY_STREAM_REQUEST != request: |
||||||
|
context.set_code(grpc.StatusCode.INVALID_ARGUMENT) |
||||||
|
context.set_details('Something is wrong with your request!') |
||||||
|
return |
||||||
|
yield services_pb2.Strange() |
||||||
|
|
||||||
|
def StreUn(self, request_iterator, context): |
||||||
|
context.send_initial_metadata(( |
||||||
|
('server_application_metadata_key', 'Hi there!',),)) |
||||||
|
for request in request_iterator: |
||||||
|
if request != _application_common.STREAM_UNARY_REQUEST: |
||||||
|
context.set_code(grpc.StatusCode.INVALID_ARGUMENT) |
||||||
|
context.set_details('Something is wrong with your request!') |
||||||
|
return services_pb2.Strange() |
||||||
|
elif not context.is_active(): |
||||||
|
return services_pb2.Strange() |
||||||
|
else: |
||||||
|
return _application_common.STREAM_UNARY_RESPONSE |
||||||
|
|
||||||
|
def StreStre(self, request_iterator, context): |
||||||
|
for request in request_iterator: |
||||||
|
if request != _application_common.STREAM_STREAM_REQUEST: |
||||||
|
context.set_code(grpc.StatusCode.INVALID_ARGUMENT) |
||||||
|
context.set_details('Something is wrong with your request!') |
||||||
|
return |
||||||
|
elif not context.is_active(): |
||||||
|
return |
||||||
|
else: |
||||||
|
yield _application_common.STREAM_STREAM_RESPONSE |
||||||
|
yield _application_common.STREAM_STREAM_RESPONSE |
@ -0,0 +1,169 @@ |
|||||||
|
# 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 time |
||||||
|
import unittest |
||||||
|
|
||||||
|
import grpc |
||||||
|
import grpc_testing |
||||||
|
|
||||||
|
from tests.testing import _application_common |
||||||
|
from tests.testing import _application_testing_common |
||||||
|
from tests.testing import _server_application |
||||||
|
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 FirstServiceServicerTest(unittest.TestCase): |
||||||
|
|
||||||
|
def setUp(self): |
||||||
|
self._real_time = grpc_testing.strict_real_time() |
||||||
|
self._fake_time = grpc_testing.strict_fake_time(time.time()) |
||||||
|
servicer = _server_application.FirstServiceServicer() |
||||||
|
descriptors_to_servicers = { |
||||||
|
_application_testing_common.FIRST_SERVICE: servicer |
||||||
|
} |
||||||
|
self._real_time_server = grpc_testing.server_from_dictionary( |
||||||
|
descriptors_to_servicers, self._real_time) |
||||||
|
self._fake_time_server = grpc_testing.server_from_dictionary( |
||||||
|
descriptors_to_servicers, self._fake_time) |
||||||
|
|
||||||
|
def test_successful_unary_unary(self): |
||||||
|
rpc = self._real_time_server.invoke_unary_unary( |
||||||
|
_application_testing_common.FIRST_SERVICE_UNUN, (), |
||||||
|
_application_common.UNARY_UNARY_REQUEST, None) |
||||||
|
initial_metadata = rpc.initial_metadata() |
||||||
|
response, trailing_metadata, code, details = rpc.termination() |
||||||
|
|
||||||
|
self.assertEqual(_application_common.UNARY_UNARY_RESPONSE, response) |
||||||
|
self.assertIs(code, grpc.StatusCode.OK) |
||||||
|
|
||||||
|
def test_successful_unary_stream(self): |
||||||
|
rpc = self._real_time_server.invoke_unary_stream( |
||||||
|
_application_testing_common.FIRST_SERVICE_UNSTRE, (), |
||||||
|
_application_common.UNARY_STREAM_REQUEST, None) |
||||||
|
initial_metadata = rpc.initial_metadata() |
||||||
|
trailing_metadata, code, details = rpc.termination() |
||||||
|
|
||||||
|
self.assertIs(code, grpc.StatusCode.OK) |
||||||
|
|
||||||
|
def test_successful_stream_unary(self): |
||||||
|
rpc = self._real_time_server.invoke_stream_unary( |
||||||
|
_application_testing_common.FIRST_SERVICE_STREUN, (), None) |
||||||
|
rpc.send_request(_application_common.STREAM_UNARY_REQUEST) |
||||||
|
rpc.send_request(_application_common.STREAM_UNARY_REQUEST) |
||||||
|
rpc.send_request(_application_common.STREAM_UNARY_REQUEST) |
||||||
|
rpc.requests_closed() |
||||||
|
initial_metadata = rpc.initial_metadata() |
||||||
|
response, trailing_metadata, code, details = rpc.termination() |
||||||
|
|
||||||
|
self.assertEqual(_application_common.STREAM_UNARY_RESPONSE, response) |
||||||
|
self.assertIs(code, grpc.StatusCode.OK) |
||||||
|
|
||||||
|
def test_successful_stream_stream(self): |
||||||
|
rpc = self._real_time_server.invoke_stream_stream( |
||||||
|
_application_testing_common.FIRST_SERVICE_STRESTRE, (), None) |
||||||
|
rpc.send_request(_application_common.STREAM_STREAM_REQUEST) |
||||||
|
initial_metadata = rpc.initial_metadata() |
||||||
|
responses = [ |
||||||
|
rpc.take_response(), |
||||||
|
rpc.take_response(), |
||||||
|
] |
||||||
|
rpc.send_request(_application_common.STREAM_STREAM_REQUEST) |
||||||
|
rpc.send_request(_application_common.STREAM_STREAM_REQUEST) |
||||||
|
responses.extend([ |
||||||
|
rpc.take_response(), |
||||||
|
rpc.take_response(), |
||||||
|
rpc.take_response(), |
||||||
|
rpc.take_response(), |
||||||
|
]) |
||||||
|
rpc.requests_closed() |
||||||
|
trailing_metadata, code, details = rpc.termination() |
||||||
|
|
||||||
|
for response in responses: |
||||||
|
self.assertEqual(_application_common.STREAM_STREAM_RESPONSE, |
||||||
|
response) |
||||||
|
self.assertIs(code, grpc.StatusCode.OK) |
||||||
|
|
||||||
|
def test_server_rpc_idempotence(self): |
||||||
|
rpc = self._real_time_server.invoke_unary_unary( |
||||||
|
_application_testing_common.FIRST_SERVICE_UNUN, (), |
||||||
|
_application_common.UNARY_UNARY_REQUEST, None) |
||||||
|
first_initial_metadata = rpc.initial_metadata() |
||||||
|
second_initial_metadata = rpc.initial_metadata() |
||||||
|
third_initial_metadata = rpc.initial_metadata() |
||||||
|
first_termination = rpc.termination() |
||||||
|
second_termination = rpc.termination() |
||||||
|
third_termination = rpc.termination() |
||||||
|
|
||||||
|
for later_initial_metadata in (second_initial_metadata, |
||||||
|
third_initial_metadata,): |
||||||
|
self.assertEqual(first_initial_metadata, later_initial_metadata) |
||||||
|
response = first_termination[0] |
||||||
|
terminal_metadata = first_termination[1] |
||||||
|
code = first_termination[2] |
||||||
|
details = first_termination[3] |
||||||
|
for later_termination in (second_termination, third_termination,): |
||||||
|
self.assertEqual(response, later_termination[0]) |
||||||
|
self.assertEqual(terminal_metadata, later_termination[1]) |
||||||
|
self.assertIs(code, later_termination[2]) |
||||||
|
self.assertEqual(details, later_termination[3]) |
||||||
|
self.assertEqual(_application_common.UNARY_UNARY_RESPONSE, response) |
||||||
|
self.assertIs(code, grpc.StatusCode.OK) |
||||||
|
|
||||||
|
def test_misbehaving_client_unary_unary(self): |
||||||
|
rpc = self._real_time_server.invoke_unary_unary( |
||||||
|
_application_testing_common.FIRST_SERVICE_UNUN, (), |
||||||
|
_application_common.ERRONEOUS_UNARY_UNARY_REQUEST, None) |
||||||
|
initial_metadata = rpc.initial_metadata() |
||||||
|
response, trailing_metadata, code, details = rpc.termination() |
||||||
|
|
||||||
|
self.assertIsNot(code, grpc.StatusCode.OK) |
||||||
|
|
||||||
|
def test_infinite_request_stream_real_time(self): |
||||||
|
rpc = self._real_time_server.invoke_stream_unary( |
||||||
|
_application_testing_common.FIRST_SERVICE_STREUN, (), |
||||||
|
_application_common.INFINITE_REQUEST_STREAM_TIMEOUT) |
||||||
|
rpc.send_request(_application_common.STREAM_UNARY_REQUEST) |
||||||
|
rpc.send_request(_application_common.STREAM_UNARY_REQUEST) |
||||||
|
rpc.send_request(_application_common.STREAM_UNARY_REQUEST) |
||||||
|
initial_metadata = rpc.initial_metadata() |
||||||
|
self._real_time.sleep_for( |
||||||
|
_application_common.INFINITE_REQUEST_STREAM_TIMEOUT * 2) |
||||||
|
rpc.send_request(_application_common.STREAM_UNARY_REQUEST) |
||||||
|
response, trailing_metadata, code, details = rpc.termination() |
||||||
|
|
||||||
|
self.assertIs(code, grpc.StatusCode.DEADLINE_EXCEEDED) |
||||||
|
|
||||||
|
def test_infinite_request_stream_fake_time(self): |
||||||
|
rpc = self._fake_time_server.invoke_stream_unary( |
||||||
|
_application_testing_common.FIRST_SERVICE_STREUN, (), |
||||||
|
_application_common.INFINITE_REQUEST_STREAM_TIMEOUT) |
||||||
|
rpc.send_request(_application_common.STREAM_UNARY_REQUEST) |
||||||
|
rpc.send_request(_application_common.STREAM_UNARY_REQUEST) |
||||||
|
rpc.send_request(_application_common.STREAM_UNARY_REQUEST) |
||||||
|
initial_metadata = rpc.initial_metadata() |
||||||
|
self._fake_time.sleep_for( |
||||||
|
_application_common.INFINITE_REQUEST_STREAM_TIMEOUT * 2) |
||||||
|
rpc.send_request(_application_common.STREAM_UNARY_REQUEST) |
||||||
|
response, trailing_metadata, code, details = rpc.termination() |
||||||
|
|
||||||
|
self.assertIs(code, grpc.StatusCode.DEADLINE_EXCEEDED) |
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__': |
||||||
|
unittest.main(verbosity=2) |
@ -1,44 +1,569 @@ |
|||||||
# This configuration was generated by `rubocop --auto-gen-config` |
# This configuration was generated by |
||||||
# on 2015-05-22 13:23:34 -0700 using RuboCop version 0.30.1. |
# `rubocop --auto-gen-config` |
||||||
|
# on 2017-09-04 17:00:36 +0200 using RuboCop version 0.49.1. |
||||||
# The point is for the user to remove these configuration records |
# The point is for the user to remove these configuration records |
||||||
# one by one as the offenses are removed from the code base. |
# one by one as the offenses are removed from the code base. |
||||||
# Note that changes in the inspected code, or installation of new |
# Note that changes in the inspected code, or installation of new |
||||||
# versions of RuboCop, may require this file to be generated again. |
# versions of RuboCop, may require this file to be generated again. |
||||||
|
|
||||||
# Offense count: 30 |
# Offense count: 3 |
||||||
Metrics/AbcSize: |
# Cop supports --auto-correct. |
||||||
Max: 38 |
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentOneStep, IndentationWidth. |
||||||
|
# SupportedStyles: case, end |
||||||
|
Layout/CaseIndentation: |
||||||
|
Exclude: |
||||||
|
- 'tools/platform_check.rb' |
||||||
|
|
||||||
|
# Offense count: 1 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
Layout/CommentIndentation: |
||||||
|
Exclude: |
||||||
|
- 'qps/client.rb' |
||||||
|
|
||||||
|
# Offense count: 1 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
Layout/EmptyLineAfterMagicComment: |
||||||
|
Exclude: |
||||||
|
- 'tools/grpc-tools.gemspec' |
||||||
|
|
||||||
|
# Offense count: 33 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: AllowAdjacentOneLineDefs, NumberOfEmptyLines. |
||||||
|
Layout/EmptyLineBetweenDefs: |
||||||
|
Exclude: |
||||||
|
- 'qps/client.rb' |
||||||
|
- 'qps/histogram.rb' |
||||||
|
- 'qps/proxy-worker.rb' |
||||||
|
- 'qps/server.rb' |
||||||
|
- 'qps/worker.rb' |
||||||
|
|
||||||
|
# Offense count: 1 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
Layout/EmptyLines: |
||||||
|
Exclude: |
||||||
|
- 'qps/qps-common.rb' |
||||||
|
|
||||||
|
# Offense count: 8 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: EnforcedStyle, SupportedStyles. |
||||||
|
# SupportedStyles: empty_lines, empty_lines_except_namespace, empty_lines_special, no_empty_lines |
||||||
|
Layout/EmptyLinesAroundClassBody: |
||||||
|
Exclude: |
||||||
|
- 'pb/grpc/testing/duplicate/echo_duplicate_services_pb.rb' |
||||||
|
- 'pb/grpc/testing/metrics_services_pb.rb' |
||||||
|
- 'pb/src/proto/grpc/testing/test_services_pb.rb' |
||||||
|
- 'qps/src/proto/grpc/testing/proxy-service_services_pb.rb' |
||||||
|
- 'qps/src/proto/grpc/testing/services_services_pb.rb' |
||||||
|
|
||||||
|
# Offense count: 28 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: AllowForAlignment, ForceEqualSignAlignment. |
||||||
|
Layout/ExtraSpacing: |
||||||
|
Enabled: false |
||||||
|
|
||||||
|
# Offense count: 1 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: EnforcedStyle, SupportedStyles. |
||||||
|
# SupportedStyles: normal, rails |
||||||
|
Layout/IndentationConsistency: |
||||||
|
Exclude: |
||||||
|
- 'pb/grpc/health/checker.rb' |
||||||
|
|
||||||
|
# Offense count: 1 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: Width, IgnoredPatterns. |
||||||
|
Layout/IndentationWidth: |
||||||
|
Exclude: |
||||||
|
- 'pb/grpc/health/checker.rb' |
||||||
|
|
||||||
|
# Offense count: 1 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: EnforcedStyle, SupportedStyles. |
||||||
|
# SupportedStyles: symmetrical, new_line, same_line |
||||||
|
Layout/MultilineHashBraceLayout: |
||||||
|
Exclude: |
||||||
|
- 'spec/generic/active_call_spec.rb' |
||||||
|
|
||||||
|
# Offense count: 70 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: EnforcedStyle, SupportedStyles. |
||||||
|
# SupportedStyles: symmetrical, new_line, same_line |
||||||
|
Layout/MultilineMethodCallBraceLayout: |
||||||
|
Enabled: false |
||||||
|
|
||||||
|
# Offense count: 2 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: EnforcedStyle, SupportedStyles, IndentationWidth. |
||||||
|
# SupportedStyles: aligned, indented, indented_relative_to_receiver |
||||||
|
Layout/MultilineMethodCallIndentation: |
||||||
|
Exclude: |
||||||
|
- 'spec/generic/rpc_desc_spec.rb' |
||||||
|
|
||||||
|
# Offense count: 1 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: EnforcedStyle, SupportedStyles. |
||||||
|
# SupportedStyles: symmetrical, new_line, same_line |
||||||
|
Layout/MultilineMethodDefinitionBraceLayout: |
||||||
|
Exclude: |
||||||
|
- 'spec/generic/client_stub_spec.rb' |
||||||
|
|
||||||
|
# Offense count: 5 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
Layout/SpaceAfterColon: |
||||||
|
Exclude: |
||||||
|
- 'lib/grpc/generic/rpc_server.rb' |
||||||
|
|
||||||
|
# Offense count: 7 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
Layout/SpaceAfterComma: |
||||||
|
Exclude: |
||||||
|
- 'qps/client.rb' |
||||||
|
|
||||||
|
# Offense count: 27 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: AllowForAlignment. |
||||||
|
Layout/SpaceAroundOperators: |
||||||
|
Exclude: |
||||||
|
- 'qps/client.rb' |
||||||
|
- 'qps/histogram.rb' |
||||||
|
- 'qps/proxy-worker.rb' |
||||||
|
- 'qps/server.rb' |
||||||
|
- 'spec/generic/active_call_spec.rb' |
||||||
|
- 'spec/generic/rpc_server_spec.rb' |
||||||
|
|
||||||
|
# Offense count: 1 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces, SpaceBeforeBlockParameters. |
||||||
|
# SupportedStyles: space, no_space |
||||||
|
# SupportedStylesForEmptyBraces: space, no_space |
||||||
|
Layout/SpaceInsideBlockBraces: |
||||||
|
Exclude: |
||||||
|
- 'stress/stress_client.rb' |
||||||
|
|
||||||
|
# Offense count: 4 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
Layout/SpaceInsideBrackets: |
||||||
|
Exclude: |
||||||
|
- 'tools/bin/grpc_tools_ruby_protoc' |
||||||
|
- 'tools/bin/grpc_tools_ruby_protoc_plugin' |
||||||
|
|
||||||
|
# Offense count: 2 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: EnforcedStyle, SupportedStyles, EnforcedStyleForEmptyBraces, SupportedStylesForEmptyBraces. |
||||||
|
# SupportedStyles: space, no_space, compact |
||||||
|
# SupportedStylesForEmptyBraces: space, no_space |
||||||
|
Layout/SpaceInsideHashLiteralBraces: |
||||||
|
Exclude: |
||||||
|
- 'qps/server.rb' |
||||||
|
|
||||||
|
# Offense count: 6 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
Layout/SpaceInsidePercentLiteralDelimiters: |
||||||
|
Exclude: |
||||||
|
- 'spec/generic/client_stub_spec.rb' |
||||||
|
- 'tools/grpc-tools.gemspec' |
||||||
|
|
||||||
# Offense count: 3 |
# Offense count: 3 |
||||||
# Configuration parameters: CountComments. |
# Cop supports --auto-correct. |
||||||
Metrics/ClassLength: |
Layout/Tab: |
||||||
Max: 200 |
Exclude: |
||||||
|
- 'pb/grpc/health/checker.rb' |
||||||
|
- 'qps/client.rb' |
||||||
|
|
||||||
|
# Offense count: 1 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
Layout/TrailingWhitespace: |
||||||
|
Exclude: |
||||||
|
- 'qps/worker.rb' |
||||||
|
|
||||||
|
# Offense count: 1 |
||||||
|
Lint/IneffectiveAccessModifier: |
||||||
|
Exclude: |
||||||
|
- 'lib/grpc/generic/active_call.rb' |
||||||
|
|
||||||
|
# Offense count: 4 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
Lint/PercentStringArray: |
||||||
|
Exclude: |
||||||
|
- 'spec/client_server_spec.rb' |
||||||
|
- 'spec/generic/active_call_spec.rb' |
||||||
|
- 'spec/generic/client_stub_spec.rb' |
||||||
|
|
||||||
|
# Offense count: 4 |
||||||
|
Lint/ScriptPermission: |
||||||
|
Exclude: |
||||||
|
- 'qps/client.rb' |
||||||
|
- 'qps/histogram.rb' |
||||||
|
- 'qps/qps-common.rb' |
||||||
|
- 'qps/server.rb' |
||||||
|
|
||||||
|
# Offense count: 2 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: IgnoreEmptyBlocks, AllowUnusedKeywordArguments. |
||||||
|
Lint/UnusedBlockArgument: |
||||||
|
Exclude: |
||||||
|
- 'qps/client.rb' |
||||||
|
|
||||||
|
# Offense count: 2 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: AllowUnusedKeywordArguments, IgnoreEmptyMethods. |
||||||
|
Lint/UnusedMethodArgument: |
||||||
|
Exclude: |
||||||
|
- 'qps/client.rb' |
||||||
|
|
||||||
|
# Offense count: 1 |
||||||
|
# Configuration parameters: ContextCreatingMethods, MethodCreatingMethods. |
||||||
|
Lint/UselessAccessModifier: |
||||||
|
Exclude: |
||||||
|
- 'lib/grpc/logconfig.rb' |
||||||
|
|
||||||
|
# Offense count: 1 |
||||||
|
Lint/UselessAssignment: |
||||||
|
Exclude: |
||||||
|
- 'qps/client.rb' |
||||||
|
|
||||||
# Offense count: 35 |
# Offense count: 4 |
||||||
|
Lint/Void: |
||||||
|
Exclude: |
||||||
|
- 'stress/metrics_server.rb' |
||||||
|
- 'stress/stress_client.rb' |
||||||
|
|
||||||
|
# Offense count: 53 |
||||||
|
Metrics/AbcSize: |
||||||
|
Max: 57 |
||||||
|
|
||||||
|
# Offense count: 81 |
||||||
|
# Configuration parameters: CountComments, ExcludedMethods. |
||||||
|
Metrics/BlockLength: |
||||||
|
Max: 715 |
||||||
|
|
||||||
|
# Offense count: 82 |
||||||
|
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, IgnoredPatterns. |
||||||
|
# URISchemes: http, https |
||||||
|
Metrics/LineLength: |
||||||
|
Max: 141 |
||||||
|
|
||||||
|
# Offense count: 82 |
||||||
# Configuration parameters: CountComments. |
# Configuration parameters: CountComments. |
||||||
Metrics/MethodLength: |
Metrics/MethodLength: |
||||||
Max: 36 |
Max: 54 |
||||||
|
|
||||||
# Offense count: 7 |
# Offense count: 5 |
||||||
# Configuration parameters: CountKeywordArgs. |
# Configuration parameters: CountKeywordArgs. |
||||||
Metrics/ParameterLists: |
Metrics/ParameterLists: |
||||||
Max: 8 |
Max: 7 |
||||||
|
|
||||||
|
# Offense count: 1 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
Performance/RedundantBlockCall: |
||||||
|
Exclude: |
||||||
|
- 'spec/generic/client_stub_spec.rb' |
||||||
|
|
||||||
|
# Offense count: 5 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: MaxKeyValuePairs. |
||||||
|
Performance/RedundantMerge: |
||||||
|
Exclude: |
||||||
|
- 'spec/generic/active_call_spec.rb' |
||||||
|
- 'spec/generic/client_stub_spec.rb' |
||||||
|
|
||||||
|
# Offense count: 8 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
Performance/TimesMap: |
||||||
|
Exclude: |
||||||
|
- 'spec/channel_spec.rb' |
||||||
|
- 'spec/client_server_spec.rb' |
||||||
|
- 'spec/server_spec.rb' |
||||||
|
|
||||||
|
# Offense count: 7 |
||||||
|
Style/AccessorMethodName: |
||||||
|
Exclude: |
||||||
|
- 'qps/server.rb' |
||||||
|
- 'stress/metrics_server.rb' |
||||||
|
- 'stress/stress_client.rb' |
||||||
|
|
||||||
|
# Offense count: 2 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: EnforcedStyle, SupportedStyles. |
||||||
|
# SupportedStyles: prefer_alias, prefer_alias_method |
||||||
|
Style/Alias: |
||||||
|
Exclude: |
||||||
|
- 'lib/grpc/generic/rpc_server.rb' |
||||||
|
- 'lib/grpc/notifier.rb' |
||||||
|
|
||||||
|
# Offense count: 7 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: EnforcedStyle, SupportedStyles, ProceduralMethods, FunctionalMethods, IgnoredMethods. |
||||||
|
# SupportedStyles: line_count_based, semantic, braces_for_chaining |
||||||
|
# ProceduralMethods: benchmark, bm, bmbm, create, each_with_object, measure, new, realtime, tap, with_object |
||||||
|
# FunctionalMethods: let, let!, subject, watch |
||||||
|
# IgnoredMethods: lambda, proc, it |
||||||
|
Style/BlockDelimiters: |
||||||
|
Exclude: |
||||||
|
- 'qps/client.rb' |
||||||
|
- 'qps/proxy-worker.rb' |
||||||
|
- 'qps/server.rb' |
||||||
|
- 'qps/worker.rb' |
||||||
|
|
||||||
|
# Offense count: 2 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
Style/ClassMethods: |
||||||
|
Exclude: |
||||||
|
- 'tools/platform_check.rb' |
||||||
|
|
||||||
|
# Offense count: 2 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: EnforcedStyle, SupportedStyles, SingleLineConditionsOnly, IncludeTernaryExpressions. |
||||||
|
# SupportedStyles: assign_to_condition, assign_inside_condition |
||||||
|
Style/ConditionalAssignment: |
||||||
|
Exclude: |
||||||
|
- 'lib/grpc/generic/rpc_server.rb' |
||||||
|
- 'lib/grpc/generic/service.rb' |
||||||
|
|
||||||
|
# Offense count: 19 |
||||||
|
Style/Documentation: |
||||||
|
Exclude: |
||||||
|
- 'spec/**/*' |
||||||
|
- 'test/**/*' |
||||||
|
- 'pb/grpc/testing/duplicate/echo_duplicate_services_pb.rb' |
||||||
|
- 'pb/grpc/testing/metrics_services_pb.rb' |
||||||
|
- 'pb/src/proto/grpc/testing/test_pb.rb' |
||||||
|
- 'qps/client.rb' |
||||||
|
- 'qps/histogram.rb' |
||||||
|
- 'qps/proxy-worker.rb' |
||||||
|
- 'qps/server.rb' |
||||||
|
- 'qps/src/proto/grpc/testing/proxy-service_services_pb.rb' |
||||||
|
- 'qps/src/proto/grpc/testing/services_pb.rb' |
||||||
|
- 'qps/src/proto/grpc/testing/services_services_pb.rb' |
||||||
|
- 'qps/worker.rb' |
||||||
|
- 'stress/metrics_server.rb' |
||||||
|
- 'stress/stress_client.rb' |
||||||
|
- 'tools/platform_check.rb' |
||||||
|
|
||||||
# Offense count: 9 |
# Offense count: 8 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: EnforcedStyle, SupportedStyles. |
||||||
|
# SupportedStyles: compact, expanded |
||||||
|
Style/EmptyMethod: |
||||||
|
Exclude: |
||||||
|
- 'bin/noproto_server.rb' |
||||||
|
- 'lib/grpc/logconfig.rb' |
||||||
|
- 'spec/generic/rpc_desc_spec.rb' |
||||||
|
|
||||||
|
# Offense count: 2 |
||||||
|
# Configuration parameters: ExpectMatchingDefinition, Regex, IgnoreExecutableScripts, AllowedAcronyms. |
||||||
|
# AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS |
||||||
|
Style/FileName: |
||||||
|
Exclude: |
||||||
|
- 'qps/src/proto/grpc/testing/proxy-service_pb.rb' |
||||||
|
- 'qps/src/proto/grpc/testing/proxy-service_services_pb.rb' |
||||||
|
|
||||||
|
# Offense count: 12 |
||||||
# Configuration parameters: AllowedVariables. |
# Configuration parameters: AllowedVariables. |
||||||
Style/GlobalVars: |
Style/GlobalVars: |
||||||
Enabled: false |
Exclude: |
||||||
|
- 'ext/grpc/extconf.rb' |
||||||
|
|
||||||
|
# Offense count: 3 |
||||||
|
# Configuration parameters: MinBodyLength. |
||||||
|
Style/GuardClause: |
||||||
|
Exclude: |
||||||
|
- 'lib/grpc/generic/bidi_call.rb' |
||||||
|
- 'lib/grpc/generic/rpc_server.rb' |
||||||
|
- 'qps/client.rb' |
||||||
|
|
||||||
|
# Offense count: 1 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: EnforcedStyle, SupportedStyles, UseHashRocketsWithSymbolValues, PreferHashRocketsForNonAlnumEndingSymbols. |
||||||
|
# SupportedStyles: ruby19, hash_rockets, no_mixed_keys, ruby19_no_mixed_keys |
||||||
|
Style/HashSyntax: |
||||||
|
Exclude: |
||||||
|
- 'stress/metrics_server.rb' |
||||||
|
|
||||||
|
# Offense count: 1 |
||||||
|
Style/IfInsideElse: |
||||||
|
Exclude: |
||||||
|
- 'lib/grpc/generic/rpc_desc.rb' |
||||||
|
|
||||||
|
# Offense count: 4 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: MaxLineLength. |
||||||
|
Style/IfUnlessModifier: |
||||||
|
Exclude: |
||||||
|
- 'ext/grpc/extconf.rb' |
||||||
|
- 'qps/histogram.rb' |
||||||
|
- 'stress/stress_client.rb' |
||||||
|
|
||||||
|
# Offense count: 1 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
Style/MethodCallWithoutArgsParentheses: |
||||||
|
Exclude: |
||||||
|
- 'qps/client.rb' |
||||||
|
|
||||||
|
# Offense count: 3 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
Style/MultilineIfModifier: |
||||||
|
Exclude: |
||||||
|
- 'lib/grpc/generic/bidi_call.rb' |
||||||
|
- 'lib/grpc/generic/client_stub.rb' |
||||||
|
- 'spec/spec_helper.rb' |
||||||
|
|
||||||
|
# Offense count: 7 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
Style/MutableConstant: |
||||||
|
Exclude: |
||||||
|
- 'ext/grpc/extconf.rb' |
||||||
|
- 'lib/grpc/version.rb' |
||||||
|
- 'spec/compression_options_spec.rb' |
||||||
|
- 'spec/generic/active_call_spec.rb' |
||||||
|
- 'tools/version.rb' |
||||||
|
|
||||||
# Offense count: 1 |
# Offense count: 1 |
||||||
# Configuration parameters: EnforcedStyle, MinBodyLength, SupportedStyles. |
# Cop supports --auto-correct. |
||||||
Style/Next: |
Style/NegatedWhile: |
||||||
|
Exclude: |
||||||
|
- 'qps/client.rb' |
||||||
|
|
||||||
|
# Offense count: 1 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: AutoCorrect, EnforcedStyle, SupportedStyles. |
||||||
|
# SupportedStyles: predicate, comparison |
||||||
|
Style/NumericPredicate: |
||||||
|
Exclude: |
||||||
|
- 'spec/**/*' |
||||||
|
- 'ext/grpc/extconf.rb' |
||||||
|
|
||||||
|
# Offense count: 7 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
Style/ParallelAssignment: |
||||||
|
Exclude: |
||||||
|
- 'bin/math_server.rb' |
||||||
|
- 'lib/grpc/generic/rpc_server.rb' |
||||||
|
- 'spec/generic/client_stub_spec.rb' |
||||||
|
- 'spec/generic/rpc_desc_spec.rb' |
||||||
|
- 'spec/generic/rpc_server_pool_spec.rb' |
||||||
|
- 'spec/generic/rpc_server_spec.rb' |
||||||
|
|
||||||
|
# Offense count: 8 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: PreferredDelimiters. |
||||||
|
Style/PercentLiteralDelimiters: |
||||||
|
Exclude: |
||||||
|
- 'end2end/grpc_class_init_driver.rb' |
||||||
|
- 'spec/client_server_spec.rb' |
||||||
|
- 'spec/generic/active_call_spec.rb' |
||||||
|
- 'spec/generic/client_stub_spec.rb' |
||||||
|
- 'tools/grpc-tools.gemspec' |
||||||
|
|
||||||
|
# Offense count: 3 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: EnforcedStyle, SupportedStyles. |
||||||
|
# SupportedStyles: compact, exploded |
||||||
|
Style/RaiseArgs: |
||||||
|
Exclude: |
||||||
|
- 'stress/metrics_server.rb' |
||||||
|
|
||||||
|
# Offense count: 4 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
Style/RedundantParentheses: |
||||||
|
Exclude: |
||||||
|
- 'lib/grpc/generic/rpc_server.rb' |
||||||
|
- 'qps/client.rb' |
||||||
|
- 'qps/proxy-worker.rb' |
||||||
|
- 'spec/generic/rpc_desc_spec.rb' |
||||||
|
|
||||||
|
# Offense count: 5 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: AllowMultipleReturnValues. |
||||||
|
Style/RedundantReturn: |
||||||
|
Exclude: |
||||||
|
- 'end2end/grpc_class_init_client.rb' |
||||||
|
|
||||||
|
# Offense count: 77 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: EnforcedStyle, SupportedStyles. |
||||||
|
# SupportedStyles: only_raise, only_fail, semantic |
||||||
|
Style/SignalException: |
||||||
Enabled: false |
Enabled: false |
||||||
|
|
||||||
# Offense count: 2 |
# Offense count: 2 |
||||||
# Configuration parameters: Methods. |
# Cop supports --auto-correct. |
||||||
Style/SingleLineBlockParams: |
# Configuration parameters: EnforcedStyle, SupportedStyles. |
||||||
Enabled: false |
# SupportedStyles: use_perl_names, use_english_names |
||||||
|
Style/SpecialGlobalVars: |
||||||
|
Exclude: |
||||||
|
- 'ext/grpc/extconf.rb' |
||||||
|
- 'stress/stress_client.rb' |
||||||
|
|
||||||
|
# Offense count: 189 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: EnforcedStyle, SupportedStyles, ConsistentQuotesInMultiline. |
||||||
|
# SupportedStyles: single_quotes, double_quotes |
||||||
|
Style/StringLiterals: |
||||||
|
Exclude: |
||||||
|
- 'pb/grpc/testing/metrics_pb.rb' |
||||||
|
- 'pb/src/proto/grpc/testing/empty_pb.rb' |
||||||
|
- 'pb/src/proto/grpc/testing/messages_pb.rb' |
||||||
|
- 'qps/proxy-worker.rb' |
||||||
|
- 'qps/server.rb' |
||||||
|
- 'qps/src/proto/grpc/testing/control_pb.rb' |
||||||
|
- 'qps/src/proto/grpc/testing/messages_pb.rb' |
||||||
|
- 'qps/src/proto/grpc/testing/payloads_pb.rb' |
||||||
|
- 'qps/src/proto/grpc/testing/proxy-service_pb.rb' |
||||||
|
- 'qps/src/proto/grpc/testing/stats_pb.rb' |
||||||
|
- 'qps/worker.rb' |
||||||
|
|
||||||
# Offense count: 1 |
# Offense count: 1 |
||||||
Style/StructInheritance: |
Style/StructInheritance: |
||||||
Enabled: false |
Exclude: |
||||||
|
- 'lib/grpc/generic/rpc_desc.rb' |
||||||
|
|
||||||
|
# Offense count: 10 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: MinSize, SupportedStyles. |
||||||
|
# SupportedStyles: percent, brackets |
||||||
|
Style/SymbolArray: |
||||||
|
EnforcedStyle: brackets |
||||||
|
|
||||||
|
# Offense count: 2 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: IgnoredMethods. |
||||||
|
# IgnoredMethods: respond_to, define_method |
||||||
|
Style/SymbolProc: |
||||||
|
Exclude: |
||||||
|
- 'qps/client.rb' |
||||||
|
- 'stress/stress_client.rb' |
||||||
|
|
||||||
|
# Offense count: 6 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: AllowNamedUnderscoreVariables. |
||||||
|
Style/TrailingUnderscoreVariable: |
||||||
|
Exclude: |
||||||
|
- 'spec/channel_credentials_spec.rb' |
||||||
|
- 'spec/server_credentials_spec.rb' |
||||||
|
|
||||||
|
# Offense count: 3 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
# Configuration parameters: ExactNameMatch, AllowPredicates, AllowDSLWriters, IgnoreClassMethods, Whitelist. |
||||||
|
# Whitelist: to_ary, to_a, to_c, to_enum, to_h, to_hash, to_i, to_int, to_io, to_open, to_path, to_proc, to_r, to_regexp, to_str, to_s, to_sym |
||||||
|
Style/TrivialAccessors: |
||||||
|
Exclude: |
||||||
|
- 'qps/histogram.rb' |
||||||
|
|
||||||
|
# Offense count: 3 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
Style/UnneededInterpolation: |
||||||
|
Exclude: |
||||||
|
- 'pb/grpc/health/checker.rb' |
||||||
|
|
||||||
|
# Offense count: 1 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
Style/YodaCondition: |
||||||
|
Exclude: |
||||||
|
- 'stress/stress_client.rb' |
||||||
|
|
||||||
|
# Offense count: 2 |
||||||
|
# Cop supports --auto-correct. |
||||||
|
Style/ZeroLengthPredicate: |
||||||
|
Exclude: |
||||||
|
- 'lib/grpc/generic/rpc_server.rb' |
||||||
|
@ -0,0 +1,148 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* 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 <stdbool.h> |
||||||
|
#include <stdio.h> |
||||||
|
#include <string.h> |
||||||
|
|
||||||
|
#include "src/core/lib/security/transport/security_connector.h" |
||||||
|
#include "src/core/tsi/fake_transport_security.h" |
||||||
|
#include "test/core/tsi/transport_security_test_lib.h" |
||||||
|
#include "test/core/util/test_config.h" |
||||||
|
|
||||||
|
#include <grpc/grpc.h> |
||||||
|
#include <grpc/support/alloc.h> |
||||||
|
#include <grpc/support/log.h> |
||||||
|
|
||||||
|
typedef struct fake_tsi_test_fixture { |
||||||
|
tsi_test_fixture base; |
||||||
|
} fake_tsi_test_fixture; |
||||||
|
|
||||||
|
static void fake_test_setup_handshakers(tsi_test_fixture *fixture) { |
||||||
|
fixture->client_handshaker = |
||||||
|
tsi_create_fake_handshaker(true /* is_client. */); |
||||||
|
fixture->server_handshaker = |
||||||
|
tsi_create_fake_handshaker(false /* is_client. */); |
||||||
|
} |
||||||
|
|
||||||
|
static void validate_handshaker_peers(tsi_handshaker_result *result) { |
||||||
|
GPR_ASSERT(result != NULL); |
||||||
|
tsi_peer peer; |
||||||
|
GPR_ASSERT(tsi_handshaker_result_extract_peer(result, &peer) == TSI_OK); |
||||||
|
const tsi_peer_property *property = |
||||||
|
tsi_peer_get_property_by_name(&peer, TSI_CERTIFICATE_TYPE_PEER_PROPERTY); |
||||||
|
GPR_ASSERT(property != NULL); |
||||||
|
GPR_ASSERT(memcmp(property->value.data, TSI_FAKE_CERTIFICATE_TYPE, |
||||||
|
property->value.length) == 0); |
||||||
|
tsi_peer_destruct(&peer); |
||||||
|
} |
||||||
|
|
||||||
|
static void fake_test_check_handshaker_peers(tsi_test_fixture *fixture) { |
||||||
|
validate_handshaker_peers(fixture->client_result); |
||||||
|
validate_handshaker_peers(fixture->server_result); |
||||||
|
} |
||||||
|
|
||||||
|
static void fake_test_destruct(tsi_test_fixture *fixture) {} |
||||||
|
|
||||||
|
static const struct tsi_test_fixture_vtable vtable = { |
||||||
|
fake_test_setup_handshakers, fake_test_check_handshaker_peers, |
||||||
|
fake_test_destruct}; |
||||||
|
|
||||||
|
static tsi_test_fixture *fake_tsi_test_fixture_create() { |
||||||
|
fake_tsi_test_fixture *fake_fixture = gpr_zalloc(sizeof(*fake_fixture)); |
||||||
|
tsi_test_fixture_init(&fake_fixture->base); |
||||||
|
fake_fixture->base.vtable = &vtable; |
||||||
|
return &fake_fixture->base; |
||||||
|
} |
||||||
|
|
||||||
|
void fake_tsi_test_do_handshake_tiny_handshake_buffer() { |
||||||
|
tsi_test_fixture *fixture = fake_tsi_test_fixture_create(); |
||||||
|
fixture->handshake_buffer_size = TSI_TEST_TINY_HANDSHAKE_BUFFER_SIZE; |
||||||
|
tsi_test_do_handshake(fixture); |
||||||
|
tsi_test_fixture_destroy(fixture); |
||||||
|
} |
||||||
|
|
||||||
|
void fake_tsi_test_do_handshake_small_handshake_buffer() { |
||||||
|
tsi_test_fixture *fixture = fake_tsi_test_fixture_create(); |
||||||
|
fixture->handshake_buffer_size = TSI_TEST_SMALL_HANDSHAKE_BUFFER_SIZE; |
||||||
|
tsi_test_do_handshake(fixture); |
||||||
|
tsi_test_fixture_destroy(fixture); |
||||||
|
} |
||||||
|
|
||||||
|
void fake_tsi_test_do_handshake() { |
||||||
|
tsi_test_fixture *fixture = fake_tsi_test_fixture_create(); |
||||||
|
tsi_test_do_handshake(fixture); |
||||||
|
tsi_test_fixture_destroy(fixture); |
||||||
|
} |
||||||
|
|
||||||
|
void fake_tsi_test_do_round_trip_for_all_configs() { |
||||||
|
unsigned int *bit_array = |
||||||
|
gpr_zalloc(sizeof(unsigned int) * TSI_TEST_NUM_OF_ARGUMENTS); |
||||||
|
const unsigned int mask = 1U << (TSI_TEST_NUM_OF_ARGUMENTS - 1); |
||||||
|
for (unsigned int val = 0; val < TSI_TEST_NUM_OF_COMBINATIONS; val++) { |
||||||
|
unsigned int v = val; |
||||||
|
for (unsigned int ind = 0; ind < TSI_TEST_NUM_OF_ARGUMENTS; ind++) { |
||||||
|
bit_array[ind] = (v & mask) ? 1 : 0; |
||||||
|
v <<= 1; |
||||||
|
} |
||||||
|
tsi_test_fixture *fixture = fake_tsi_test_fixture_create(); |
||||||
|
fake_tsi_test_fixture *fake_fixture = (fake_tsi_test_fixture *)fixture; |
||||||
|
tsi_test_frame_protector_config_destroy(fake_fixture->base.config); |
||||||
|
fake_fixture->base.config = tsi_test_frame_protector_config_create( |
||||||
|
bit_array[0], bit_array[1], bit_array[2], bit_array[3], bit_array[4], |
||||||
|
bit_array[5], bit_array[6], bit_array[7]); |
||||||
|
tsi_test_do_round_trip(&fake_fixture->base); |
||||||
|
tsi_test_fixture_destroy(fixture); |
||||||
|
} |
||||||
|
gpr_free(bit_array); |
||||||
|
} |
||||||
|
|
||||||
|
void fake_tsi_test_do_round_trip_odd_buffer_size() { |
||||||
|
const size_t odd_sizes[] = {1025, 2051, 4103, 8207, 16409}; |
||||||
|
const size_t size = sizeof(odd_sizes) / sizeof(size_t); |
||||||
|
for (size_t ind1 = 0; ind1 < size; ind1++) { |
||||||
|
for (size_t ind2 = 0; ind2 < size; ind2++) { |
||||||
|
for (size_t ind3 = 0; ind3 < size; ind3++) { |
||||||
|
for (size_t ind4 = 0; ind4 < size; ind4++) { |
||||||
|
for (size_t ind5 = 0; ind5 < size; ind5++) { |
||||||
|
tsi_test_fixture *fixture = fake_tsi_test_fixture_create(); |
||||||
|
fake_tsi_test_fixture *fake_fixture = |
||||||
|
(fake_tsi_test_fixture *)fixture; |
||||||
|
tsi_test_frame_protector_config_set_buffer_size( |
||||||
|
fake_fixture->base.config, odd_sizes[ind1], odd_sizes[ind2], |
||||||
|
odd_sizes[ind3], odd_sizes[ind4], odd_sizes[ind5]); |
||||||
|
tsi_test_do_round_trip(&fake_fixture->base); |
||||||
|
tsi_test_fixture_destroy(fixture); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, char **argv) { |
||||||
|
grpc_test_init(argc, argv); |
||||||
|
grpc_init(); |
||||||
|
fake_tsi_test_do_handshake_tiny_handshake_buffer(); |
||||||
|
fake_tsi_test_do_handshake_small_handshake_buffer(); |
||||||
|
fake_tsi_test_do_handshake(); |
||||||
|
fake_tsi_test_do_round_trip_for_all_configs(); |
||||||
|
fake_tsi_test_do_round_trip_odd_buffer_size(); |
||||||
|
grpc_shutdown(); |
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,558 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* 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 <stdbool.h> |
||||||
|
#include <stdio.h> |
||||||
|
#include <string.h> |
||||||
|
|
||||||
|
#include "src/core/lib/iomgr/load_file.h" |
||||||
|
#include "src/core/lib/security/transport/security_connector.h" |
||||||
|
#include "src/core/tsi/ssl_transport_security.h" |
||||||
|
#include "src/core/tsi/transport_security_adapter.h" |
||||||
|
#include "test/core/tsi/transport_security_test_lib.h" |
||||||
|
#include "test/core/util/test_config.h" |
||||||
|
|
||||||
|
#include <grpc/grpc.h> |
||||||
|
#include <grpc/support/alloc.h> |
||||||
|
#include <grpc/support/log.h> |
||||||
|
#include <grpc/support/string_util.h> |
||||||
|
|
||||||
|
#define SSL_TSI_TEST_ALPN1 "foo" |
||||||
|
#define SSL_TSI_TEST_ALPN2 "toto" |
||||||
|
#define SSL_TSI_TEST_ALPN3 "baz" |
||||||
|
#define SSL_TSI_TEST_ALPN_NUM 2 |
||||||
|
#define SSL_TSI_TEST_SERVER_KEY_CERT_PAIRS_NUM 2 |
||||||
|
#define SSL_TSI_TEST_BAD_SERVER_KEY_CERT_PAIRS_NUM 1 |
||||||
|
#define SSL_TSI_TEST_CREDENTIALS_DIR "src/core/tsi/test_creds/" |
||||||
|
|
||||||
|
typedef enum AlpnMode { |
||||||
|
NO_ALPN, |
||||||
|
ALPN_CLIENT_NO_SERVER, |
||||||
|
ALPN_SERVER_NO_CLIENT, |
||||||
|
ALPN_CLIENT_SERVER_OK, |
||||||
|
ALPN_CLIENT_SERVER_MISMATCH |
||||||
|
} AlpnMode; |
||||||
|
|
||||||
|
typedef struct ssl_alpn_lib { |
||||||
|
AlpnMode alpn_mode; |
||||||
|
char **server_alpn_protocols; |
||||||
|
char **client_alpn_protocols; |
||||||
|
uint16_t num_server_alpn_protocols; |
||||||
|
uint16_t num_client_alpn_protocols; |
||||||
|
} ssl_alpn_lib; |
||||||
|
|
||||||
|
typedef struct ssl_key_cert_lib { |
||||||
|
bool use_bad_server_cert; |
||||||
|
bool use_bad_client_cert; |
||||||
|
char *root_cert; |
||||||
|
tsi_ssl_pem_key_cert_pair *server_pem_key_cert_pairs; |
||||||
|
tsi_ssl_pem_key_cert_pair *bad_server_pem_key_cert_pairs; |
||||||
|
tsi_ssl_pem_key_cert_pair client_pem_key_cert_pair; |
||||||
|
tsi_ssl_pem_key_cert_pair bad_client_pem_key_cert_pair; |
||||||
|
uint16_t server_num_key_cert_pairs; |
||||||
|
uint16_t bad_server_num_key_cert_pairs; |
||||||
|
} ssl_key_cert_lib; |
||||||
|
|
||||||
|
typedef struct ssl_tsi_test_fixture { |
||||||
|
tsi_test_fixture base; |
||||||
|
ssl_key_cert_lib *key_cert_lib; |
||||||
|
ssl_alpn_lib *alpn_lib; |
||||||
|
bool force_client_auth; |
||||||
|
char *server_name_indication; |
||||||
|
tsi_ssl_server_handshaker_factory *server_handshaker_factory; |
||||||
|
tsi_ssl_client_handshaker_factory *client_handshaker_factory; |
||||||
|
} ssl_tsi_test_fixture; |
||||||
|
|
||||||
|
static void ssl_test_setup_handshakers(tsi_test_fixture *fixture) { |
||||||
|
ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; |
||||||
|
GPR_ASSERT(ssl_fixture != NULL); |
||||||
|
GPR_ASSERT(ssl_fixture->key_cert_lib != NULL); |
||||||
|
GPR_ASSERT(ssl_fixture->alpn_lib != NULL); |
||||||
|
ssl_key_cert_lib *key_cert_lib = ssl_fixture->key_cert_lib; |
||||||
|
ssl_alpn_lib *alpn_lib = ssl_fixture->alpn_lib; |
||||||
|
/* Create client handshaker factory. */ |
||||||
|
tsi_ssl_pem_key_cert_pair *client_key_cert_pair = NULL; |
||||||
|
if (ssl_fixture->force_client_auth) { |
||||||
|
client_key_cert_pair = key_cert_lib->use_bad_client_cert |
||||||
|
? &key_cert_lib->bad_client_pem_key_cert_pair |
||||||
|
: &key_cert_lib->client_pem_key_cert_pair; |
||||||
|
} |
||||||
|
char **client_alpn_protocols = NULL; |
||||||
|
uint16_t num_client_alpn_protocols = 0; |
||||||
|
if (alpn_lib->alpn_mode == ALPN_CLIENT_NO_SERVER || |
||||||
|
alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_OK || |
||||||
|
alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_MISMATCH) { |
||||||
|
client_alpn_protocols = alpn_lib->client_alpn_protocols; |
||||||
|
num_client_alpn_protocols = alpn_lib->num_client_alpn_protocols; |
||||||
|
} |
||||||
|
GPR_ASSERT(tsi_create_ssl_client_handshaker_factory( |
||||||
|
client_key_cert_pair, key_cert_lib->root_cert, NULL, |
||||||
|
(const char **)client_alpn_protocols, |
||||||
|
num_client_alpn_protocols, |
||||||
|
&ssl_fixture->client_handshaker_factory) == TSI_OK); |
||||||
|
/* Create server handshaker factory. */ |
||||||
|
char **server_alpn_protocols = NULL; |
||||||
|
uint16_t num_server_alpn_protocols = 0; |
||||||
|
if (alpn_lib->alpn_mode == ALPN_SERVER_NO_CLIENT || |
||||||
|
alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_OK || |
||||||
|
alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_MISMATCH) { |
||||||
|
server_alpn_protocols = alpn_lib->server_alpn_protocols; |
||||||
|
num_server_alpn_protocols = alpn_lib->num_server_alpn_protocols; |
||||||
|
if (alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_MISMATCH) { |
||||||
|
num_server_alpn_protocols--; |
||||||
|
} |
||||||
|
} |
||||||
|
GPR_ASSERT(tsi_create_ssl_server_handshaker_factory( |
||||||
|
key_cert_lib->use_bad_server_cert |
||||||
|
? key_cert_lib->bad_server_pem_key_cert_pairs |
||||||
|
: key_cert_lib->server_pem_key_cert_pairs, |
||||||
|
key_cert_lib->use_bad_server_cert |
||||||
|
? key_cert_lib->bad_server_num_key_cert_pairs |
||||||
|
: key_cert_lib->server_num_key_cert_pairs, |
||||||
|
key_cert_lib->root_cert, ssl_fixture->force_client_auth, NULL, |
||||||
|
(const char **)server_alpn_protocols, |
||||||
|
num_server_alpn_protocols, |
||||||
|
&ssl_fixture->server_handshaker_factory) == TSI_OK); |
||||||
|
/* Create server and client handshakers. */ |
||||||
|
tsi_handshaker *client_handshaker = NULL; |
||||||
|
GPR_ASSERT(tsi_ssl_client_handshaker_factory_create_handshaker( |
||||||
|
ssl_fixture->client_handshaker_factory, |
||||||
|
ssl_fixture->server_name_indication, |
||||||
|
&client_handshaker) == TSI_OK); |
||||||
|
ssl_fixture->base.client_handshaker = |
||||||
|
tsi_create_adapter_handshaker(client_handshaker); |
||||||
|
tsi_handshaker *server_handshaker = NULL; |
||||||
|
GPR_ASSERT(tsi_ssl_server_handshaker_factory_create_handshaker( |
||||||
|
ssl_fixture->server_handshaker_factory, &server_handshaker) == |
||||||
|
TSI_OK); |
||||||
|
ssl_fixture->base.server_handshaker = |
||||||
|
tsi_create_adapter_handshaker(server_handshaker); |
||||||
|
} |
||||||
|
|
||||||
|
static void check_alpn(ssl_tsi_test_fixture *ssl_fixture, |
||||||
|
const tsi_peer *peer) { |
||||||
|
GPR_ASSERT(ssl_fixture != NULL); |
||||||
|
GPR_ASSERT(ssl_fixture->alpn_lib != NULL); |
||||||
|
ssl_alpn_lib *alpn_lib = ssl_fixture->alpn_lib; |
||||||
|
const tsi_peer_property *alpn_property = |
||||||
|
tsi_peer_get_property_by_name(peer, TSI_SSL_ALPN_SELECTED_PROTOCOL); |
||||||
|
if (alpn_lib->alpn_mode != ALPN_CLIENT_SERVER_OK) { |
||||||
|
GPR_ASSERT(alpn_property == NULL); |
||||||
|
} else { |
||||||
|
GPR_ASSERT(alpn_property != NULL); |
||||||
|
const char *expected_match = "baz"; |
||||||
|
GPR_ASSERT(memcmp(alpn_property->value.data, expected_match, |
||||||
|
alpn_property->value.length) == 0); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static const tsi_peer_property * |
||||||
|
check_basic_authenticated_peer_and_get_common_name(const tsi_peer *peer) { |
||||||
|
const tsi_peer_property *cert_type_property = |
||||||
|
tsi_peer_get_property_by_name(peer, TSI_CERTIFICATE_TYPE_PEER_PROPERTY); |
||||||
|
GPR_ASSERT(cert_type_property != NULL); |
||||||
|
GPR_ASSERT(memcmp(cert_type_property->value.data, TSI_X509_CERTIFICATE_TYPE, |
||||||
|
cert_type_property->value.length) == 0); |
||||||
|
const tsi_peer_property *property = tsi_peer_get_property_by_name( |
||||||
|
peer, TSI_X509_SUBJECT_COMMON_NAME_PEER_PROPERTY); |
||||||
|
GPR_ASSERT(property != NULL); |
||||||
|
return property; |
||||||
|
} |
||||||
|
|
||||||
|
void check_server0_peer(tsi_peer *peer) { |
||||||
|
const tsi_peer_property *property = |
||||||
|
check_basic_authenticated_peer_and_get_common_name(peer); |
||||||
|
const char *expected_match = "*.test.google.com.au"; |
||||||
|
GPR_ASSERT(memcmp(property->value.data, expected_match, |
||||||
|
property->value.length) == 0); |
||||||
|
GPR_ASSERT(tsi_peer_get_property_by_name( |
||||||
|
peer, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == |
||||||
|
NULL); |
||||||
|
GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "foo.test.google.com.au") == 1); |
||||||
|
GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "bar.test.google.com.au") == 1); |
||||||
|
GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "bar.test.google.blah") == 0); |
||||||
|
GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "foo.bar.test.google.com.au") == |
||||||
|
0); |
||||||
|
GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "test.google.com.au") == 0); |
||||||
|
tsi_peer_destruct(peer); |
||||||
|
} |
||||||
|
|
||||||
|
static bool check_subject_alt_name(tsi_peer *peer, const char *name) { |
||||||
|
for (size_t i = 0; i < peer->property_count; i++) { |
||||||
|
const tsi_peer_property *prop = &peer->properties[i]; |
||||||
|
if (strcmp(prop->name, TSI_X509_SUBJECT_ALTERNATIVE_NAME_PEER_PROPERTY) == |
||||||
|
0) { |
||||||
|
if (memcmp(prop->value.data, name, prop->value.length) == 0) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
void check_server1_peer(tsi_peer *peer) { |
||||||
|
const tsi_peer_property *property = |
||||||
|
check_basic_authenticated_peer_and_get_common_name(peer); |
||||||
|
const char *expected_match = "*.test.google.com"; |
||||||
|
GPR_ASSERT(memcmp(property->value.data, expected_match, |
||||||
|
property->value.length) == 0); |
||||||
|
GPR_ASSERT(check_subject_alt_name(peer, "*.test.google.fr") == 1); |
||||||
|
GPR_ASSERT(check_subject_alt_name(peer, "waterzooi.test.google.be") == 1); |
||||||
|
GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "foo.test.google.fr") == 1); |
||||||
|
GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "bar.test.google.fr") == 1); |
||||||
|
GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "waterzooi.test.google.be") == 1); |
||||||
|
GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "foo.test.youtube.com") == 1); |
||||||
|
GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "bar.foo.test.google.com") == 0); |
||||||
|
GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "test.google.fr") == 0); |
||||||
|
GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "tartines.test.google.be") == 0); |
||||||
|
GPR_ASSERT(tsi_ssl_peer_matches_name(peer, "tartines.youtube.com") == 0); |
||||||
|
tsi_peer_destruct(peer); |
||||||
|
} |
||||||
|
|
||||||
|
static void check_client_peer(ssl_tsi_test_fixture *ssl_fixture, |
||||||
|
tsi_peer *peer) { |
||||||
|
GPR_ASSERT(ssl_fixture != NULL); |
||||||
|
GPR_ASSERT(ssl_fixture->alpn_lib != NULL); |
||||||
|
ssl_alpn_lib *alpn_lib = ssl_fixture->alpn_lib; |
||||||
|
if (!ssl_fixture->force_client_auth) { |
||||||
|
GPR_ASSERT(peer->property_count == |
||||||
|
(alpn_lib->alpn_mode == ALPN_CLIENT_SERVER_OK ? 1 : 0)); |
||||||
|
} else { |
||||||
|
const tsi_peer_property *property = |
||||||
|
check_basic_authenticated_peer_and_get_common_name(peer); |
||||||
|
const char *expected_match = "testclient"; |
||||||
|
GPR_ASSERT(memcmp(property->value.data, expected_match, |
||||||
|
property->value.length) == 0); |
||||||
|
} |
||||||
|
tsi_peer_destruct(peer); |
||||||
|
} |
||||||
|
|
||||||
|
static void ssl_test_check_handshaker_peers(tsi_test_fixture *fixture) { |
||||||
|
ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; |
||||||
|
GPR_ASSERT(ssl_fixture != NULL); |
||||||
|
GPR_ASSERT(ssl_fixture->key_cert_lib != NULL); |
||||||
|
ssl_key_cert_lib *key_cert_lib = ssl_fixture->key_cert_lib; |
||||||
|
tsi_peer peer; |
||||||
|
bool expect_success = |
||||||
|
!(key_cert_lib->use_bad_server_cert || |
||||||
|
(key_cert_lib->use_bad_client_cert && ssl_fixture->force_client_auth)); |
||||||
|
if (expect_success) { |
||||||
|
GPR_ASSERT(tsi_handshaker_result_extract_peer( |
||||||
|
ssl_fixture->base.client_result, &peer) == TSI_OK); |
||||||
|
check_alpn(ssl_fixture, &peer); |
||||||
|
|
||||||
|
if (ssl_fixture->server_name_indication != NULL) { |
||||||
|
check_server1_peer(&peer); |
||||||
|
} else { |
||||||
|
check_server0_peer(&peer); |
||||||
|
} |
||||||
|
} else { |
||||||
|
GPR_ASSERT(ssl_fixture->base.client_result == NULL); |
||||||
|
} |
||||||
|
if (expect_success) { |
||||||
|
GPR_ASSERT(tsi_handshaker_result_extract_peer( |
||||||
|
ssl_fixture->base.server_result, &peer) == TSI_OK); |
||||||
|
check_alpn(ssl_fixture, &peer); |
||||||
|
check_client_peer(ssl_fixture, &peer); |
||||||
|
} else { |
||||||
|
GPR_ASSERT(ssl_fixture->base.server_result == NULL); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static void ssl_test_pem_key_cert_pair_destroy(tsi_ssl_pem_key_cert_pair kp) { |
||||||
|
gpr_free((void *)kp.private_key); |
||||||
|
gpr_free((void *)kp.cert_chain); |
||||||
|
} |
||||||
|
|
||||||
|
static void ssl_test_destruct(tsi_test_fixture *fixture) { |
||||||
|
ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; |
||||||
|
if (ssl_fixture == NULL) { |
||||||
|
return; |
||||||
|
} |
||||||
|
/* Destroy ssl_alpn_lib. */ |
||||||
|
ssl_alpn_lib *alpn_lib = ssl_fixture->alpn_lib; |
||||||
|
for (size_t i = 0; i < alpn_lib->num_server_alpn_protocols; i++) { |
||||||
|
gpr_free(alpn_lib->server_alpn_protocols[i]); |
||||||
|
} |
||||||
|
gpr_free(alpn_lib->server_alpn_protocols); |
||||||
|
for (size_t i = 0; i < alpn_lib->num_client_alpn_protocols; i++) { |
||||||
|
gpr_free(alpn_lib->client_alpn_protocols[i]); |
||||||
|
} |
||||||
|
gpr_free(alpn_lib->client_alpn_protocols); |
||||||
|
gpr_free(alpn_lib); |
||||||
|
/* Destroy ssl_key_cert_lib. */ |
||||||
|
ssl_key_cert_lib *key_cert_lib = ssl_fixture->key_cert_lib; |
||||||
|
for (size_t i = 0; i < key_cert_lib->server_num_key_cert_pairs; i++) { |
||||||
|
ssl_test_pem_key_cert_pair_destroy( |
||||||
|
key_cert_lib->server_pem_key_cert_pairs[i]); |
||||||
|
} |
||||||
|
gpr_free(key_cert_lib->server_pem_key_cert_pairs); |
||||||
|
for (size_t i = 0; i < key_cert_lib->bad_server_num_key_cert_pairs; i++) { |
||||||
|
ssl_test_pem_key_cert_pair_destroy( |
||||||
|
key_cert_lib->bad_server_pem_key_cert_pairs[i]); |
||||||
|
} |
||||||
|
gpr_free(key_cert_lib->bad_server_pem_key_cert_pairs); |
||||||
|
ssl_test_pem_key_cert_pair_destroy(key_cert_lib->client_pem_key_cert_pair); |
||||||
|
ssl_test_pem_key_cert_pair_destroy( |
||||||
|
key_cert_lib->bad_client_pem_key_cert_pair); |
||||||
|
gpr_free(key_cert_lib->root_cert); |
||||||
|
gpr_free(key_cert_lib); |
||||||
|
/* Destroy others. */ |
||||||
|
tsi_ssl_server_handshaker_factory_destroy( |
||||||
|
ssl_fixture->server_handshaker_factory); |
||||||
|
tsi_ssl_client_handshaker_factory_destroy( |
||||||
|
ssl_fixture->client_handshaker_factory); |
||||||
|
} |
||||||
|
|
||||||
|
static const struct tsi_test_fixture_vtable vtable = { |
||||||
|
ssl_test_setup_handshakers, ssl_test_check_handshaker_peers, |
||||||
|
ssl_test_destruct}; |
||||||
|
|
||||||
|
static char *load_file(const char *dir_path, const char *file_name) { |
||||||
|
char *file_path = |
||||||
|
gpr_zalloc(sizeof(char) * (strlen(dir_path) + strlen(file_name) + 1)); |
||||||
|
memcpy(file_path, dir_path, strlen(dir_path)); |
||||||
|
memcpy(file_path + strlen(dir_path), file_name, strlen(file_name)); |
||||||
|
grpc_slice slice; |
||||||
|
GPR_ASSERT(grpc_load_file(file_path, 1, &slice) == GRPC_ERROR_NONE); |
||||||
|
char *data = grpc_slice_to_c_string(slice); |
||||||
|
grpc_slice_unref(slice); |
||||||
|
gpr_free(file_path); |
||||||
|
return data; |
||||||
|
} |
||||||
|
|
||||||
|
static tsi_test_fixture *ssl_tsi_test_fixture_create() { |
||||||
|
ssl_tsi_test_fixture *ssl_fixture = gpr_zalloc(sizeof(*ssl_fixture)); |
||||||
|
tsi_test_fixture_init(&ssl_fixture->base); |
||||||
|
ssl_fixture->base.test_unused_bytes = false; |
||||||
|
ssl_fixture->base.vtable = &vtable; |
||||||
|
/* Create ssl_key_cert_lib. */ |
||||||
|
ssl_key_cert_lib *key_cert_lib = gpr_zalloc(sizeof(*key_cert_lib)); |
||||||
|
key_cert_lib->use_bad_server_cert = false; |
||||||
|
key_cert_lib->use_bad_client_cert = false; |
||||||
|
key_cert_lib->server_num_key_cert_pairs = |
||||||
|
SSL_TSI_TEST_SERVER_KEY_CERT_PAIRS_NUM; |
||||||
|
key_cert_lib->bad_server_num_key_cert_pairs = |
||||||
|
SSL_TSI_TEST_BAD_SERVER_KEY_CERT_PAIRS_NUM; |
||||||
|
key_cert_lib->server_pem_key_cert_pairs = |
||||||
|
gpr_malloc(sizeof(tsi_ssl_pem_key_cert_pair) * |
||||||
|
key_cert_lib->server_num_key_cert_pairs); |
||||||
|
key_cert_lib->bad_server_pem_key_cert_pairs = |
||||||
|
gpr_malloc(sizeof(tsi_ssl_pem_key_cert_pair) * |
||||||
|
key_cert_lib->bad_server_num_key_cert_pairs); |
||||||
|
key_cert_lib->server_pem_key_cert_pairs[0].private_key = |
||||||
|
load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "server0.key"); |
||||||
|
key_cert_lib->server_pem_key_cert_pairs[0].cert_chain = |
||||||
|
load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "server0.pem"); |
||||||
|
key_cert_lib->server_pem_key_cert_pairs[1].private_key = |
||||||
|
load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "server1.key"); |
||||||
|
key_cert_lib->server_pem_key_cert_pairs[1].cert_chain = |
||||||
|
load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "server1.pem"); |
||||||
|
key_cert_lib->bad_server_pem_key_cert_pairs[0].private_key = |
||||||
|
load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "badserver.key"); |
||||||
|
key_cert_lib->bad_server_pem_key_cert_pairs[0].cert_chain = |
||||||
|
load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "badserver.pem"); |
||||||
|
key_cert_lib->client_pem_key_cert_pair.private_key = |
||||||
|
load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "client.key"); |
||||||
|
key_cert_lib->client_pem_key_cert_pair.cert_chain = |
||||||
|
load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "client.pem"); |
||||||
|
key_cert_lib->bad_client_pem_key_cert_pair.private_key = |
||||||
|
load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "badclient.key"); |
||||||
|
key_cert_lib->bad_client_pem_key_cert_pair.cert_chain = |
||||||
|
load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "badclient.pem"); |
||||||
|
key_cert_lib->root_cert = load_file(SSL_TSI_TEST_CREDENTIALS_DIR, "ca.pem"); |
||||||
|
ssl_fixture->key_cert_lib = key_cert_lib; |
||||||
|
/* Create ssl_alpn_lib. */ |
||||||
|
ssl_alpn_lib *alpn_lib = gpr_zalloc(sizeof(*alpn_lib)); |
||||||
|
alpn_lib->server_alpn_protocols = |
||||||
|
gpr_zalloc(sizeof(char *) * SSL_TSI_TEST_ALPN_NUM); |
||||||
|
alpn_lib->client_alpn_protocols = |
||||||
|
gpr_zalloc(sizeof(char *) * SSL_TSI_TEST_ALPN_NUM); |
||||||
|
alpn_lib->server_alpn_protocols[0] = gpr_strdup(SSL_TSI_TEST_ALPN1); |
||||||
|
alpn_lib->server_alpn_protocols[1] = gpr_strdup(SSL_TSI_TEST_ALPN3); |
||||||
|
alpn_lib->client_alpn_protocols[0] = gpr_strdup(SSL_TSI_TEST_ALPN2); |
||||||
|
alpn_lib->client_alpn_protocols[1] = gpr_strdup(SSL_TSI_TEST_ALPN3); |
||||||
|
alpn_lib->num_server_alpn_protocols = SSL_TSI_TEST_ALPN_NUM; |
||||||
|
alpn_lib->num_client_alpn_protocols = SSL_TSI_TEST_ALPN_NUM; |
||||||
|
alpn_lib->alpn_mode = NO_ALPN; |
||||||
|
ssl_fixture->alpn_lib = alpn_lib; |
||||||
|
ssl_fixture->base.vtable = &vtable; |
||||||
|
ssl_fixture->server_name_indication = NULL; |
||||||
|
ssl_fixture->force_client_auth = false; |
||||||
|
return &ssl_fixture->base; |
||||||
|
} |
||||||
|
|
||||||
|
void ssl_tsi_test_do_handshake_tiny_handshake_buffer() { |
||||||
|
tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); |
||||||
|
fixture->handshake_buffer_size = TSI_TEST_TINY_HANDSHAKE_BUFFER_SIZE; |
||||||
|
tsi_test_do_handshake(fixture); |
||||||
|
tsi_test_fixture_destroy(fixture); |
||||||
|
} |
||||||
|
|
||||||
|
void ssl_tsi_test_do_handshake_small_handshake_buffer() { |
||||||
|
tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); |
||||||
|
fixture->handshake_buffer_size = TSI_TEST_SMALL_HANDSHAKE_BUFFER_SIZE; |
||||||
|
tsi_test_do_handshake(fixture); |
||||||
|
tsi_test_fixture_destroy(fixture); |
||||||
|
} |
||||||
|
|
||||||
|
void ssl_tsi_test_do_handshake() { |
||||||
|
tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); |
||||||
|
tsi_test_do_handshake(fixture); |
||||||
|
tsi_test_fixture_destroy(fixture); |
||||||
|
} |
||||||
|
|
||||||
|
void ssl_tsi_test_do_handshake_with_client_authentication() { |
||||||
|
tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); |
||||||
|
ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; |
||||||
|
ssl_fixture->force_client_auth = true; |
||||||
|
tsi_test_do_handshake(fixture); |
||||||
|
tsi_test_fixture_destroy(fixture); |
||||||
|
} |
||||||
|
|
||||||
|
void ssl_tsi_test_do_handshake_with_server_name_indication_exact_domain() { |
||||||
|
/* server1 cert contains "waterzooi.test.google.be" in SAN. */ |
||||||
|
tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); |
||||||
|
ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; |
||||||
|
ssl_fixture->server_name_indication = "waterzooi.test.google.be"; |
||||||
|
tsi_test_do_handshake(fixture); |
||||||
|
tsi_test_fixture_destroy(fixture); |
||||||
|
} |
||||||
|
|
||||||
|
void ssl_tsi_test_do_handshake_with_server_name_indication_wild_star_domain() { |
||||||
|
/* server1 cert contains "*.test.google.fr" in SAN. */ |
||||||
|
tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); |
||||||
|
ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; |
||||||
|
ssl_fixture->server_name_indication = "juju.test.google.fr"; |
||||||
|
tsi_test_do_handshake(fixture); |
||||||
|
tsi_test_fixture_destroy(fixture); |
||||||
|
} |
||||||
|
|
||||||
|
void ssl_tsi_test_do_handshake_with_bad_server_cert() { |
||||||
|
tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); |
||||||
|
ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; |
||||||
|
ssl_fixture->key_cert_lib->use_bad_server_cert = true; |
||||||
|
tsi_test_do_handshake(fixture); |
||||||
|
tsi_test_fixture_destroy(fixture); |
||||||
|
} |
||||||
|
|
||||||
|
void ssl_tsi_test_do_handshake_with_bad_client_cert() { |
||||||
|
tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); |
||||||
|
ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; |
||||||
|
ssl_fixture->key_cert_lib->use_bad_client_cert = true; |
||||||
|
ssl_fixture->force_client_auth = true; |
||||||
|
tsi_test_do_handshake(fixture); |
||||||
|
tsi_test_fixture_destroy(fixture); |
||||||
|
} |
||||||
|
|
||||||
|
void ssl_tsi_test_do_handshake_alpn_client_no_server() { |
||||||
|
tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); |
||||||
|
ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; |
||||||
|
ssl_fixture->alpn_lib->alpn_mode = ALPN_CLIENT_NO_SERVER; |
||||||
|
tsi_test_do_handshake(fixture); |
||||||
|
tsi_test_fixture_destroy(fixture); |
||||||
|
} |
||||||
|
|
||||||
|
void ssl_tsi_test_do_handshake_alpn_server_no_client() { |
||||||
|
tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); |
||||||
|
ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; |
||||||
|
ssl_fixture->alpn_lib->alpn_mode = ALPN_SERVER_NO_CLIENT; |
||||||
|
tsi_test_do_handshake(fixture); |
||||||
|
tsi_test_fixture_destroy(fixture); |
||||||
|
} |
||||||
|
|
||||||
|
void ssl_tsi_test_do_handshake_alpn_client_server_mismatch() { |
||||||
|
tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); |
||||||
|
ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; |
||||||
|
ssl_fixture->alpn_lib->alpn_mode = ALPN_CLIENT_SERVER_MISMATCH; |
||||||
|
tsi_test_do_handshake(fixture); |
||||||
|
tsi_test_fixture_destroy(fixture); |
||||||
|
} |
||||||
|
|
||||||
|
void ssl_tsi_test_do_handshake_alpn_client_server_ok() { |
||||||
|
tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); |
||||||
|
ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; |
||||||
|
ssl_fixture->alpn_lib->alpn_mode = ALPN_CLIENT_SERVER_OK; |
||||||
|
tsi_test_do_handshake(fixture); |
||||||
|
tsi_test_fixture_destroy(fixture); |
||||||
|
} |
||||||
|
|
||||||
|
void ssl_tsi_test_do_round_trip_for_all_configs() { |
||||||
|
unsigned int *bit_array = |
||||||
|
gpr_zalloc(sizeof(unsigned int) * TSI_TEST_NUM_OF_ARGUMENTS); |
||||||
|
const unsigned int mask = 1U << (TSI_TEST_NUM_OF_ARGUMENTS - 1); |
||||||
|
for (unsigned int val = 0; val < TSI_TEST_NUM_OF_COMBINATIONS; val++) { |
||||||
|
unsigned int v = val; |
||||||
|
for (unsigned int ind = 0; ind < TSI_TEST_NUM_OF_ARGUMENTS; ind++) { |
||||||
|
bit_array[ind] = (v & mask) ? 1 : 0; |
||||||
|
v <<= 1; |
||||||
|
} |
||||||
|
tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); |
||||||
|
ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; |
||||||
|
tsi_test_frame_protector_config_destroy(ssl_fixture->base.config); |
||||||
|
ssl_fixture->base.config = tsi_test_frame_protector_config_create( |
||||||
|
bit_array[0], bit_array[1], bit_array[2], bit_array[3], bit_array[4], |
||||||
|
bit_array[5], bit_array[6], bit_array[7]); |
||||||
|
tsi_test_do_round_trip(&ssl_fixture->base); |
||||||
|
tsi_test_fixture_destroy(fixture); |
||||||
|
} |
||||||
|
gpr_free(bit_array); |
||||||
|
} |
||||||
|
|
||||||
|
void ssl_tsi_test_do_round_trip_odd_buffer_size() { |
||||||
|
const size_t odd_sizes[] = {1025, 2051, 4103, 8207, 16409}; |
||||||
|
const size_t size = sizeof(odd_sizes) / sizeof(size_t); |
||||||
|
for (size_t ind1 = 0; ind1 < size; ind1++) { |
||||||
|
for (size_t ind2 = 0; ind2 < size; ind2++) { |
||||||
|
for (size_t ind3 = 0; ind3 < size; ind3++) { |
||||||
|
for (size_t ind4 = 0; ind4 < size; ind4++) { |
||||||
|
for (size_t ind5 = 0; ind5 < size; ind5++) { |
||||||
|
tsi_test_fixture *fixture = ssl_tsi_test_fixture_create(); |
||||||
|
ssl_tsi_test_fixture *ssl_fixture = (ssl_tsi_test_fixture *)fixture; |
||||||
|
tsi_test_frame_protector_config_set_buffer_size( |
||||||
|
ssl_fixture->base.config, odd_sizes[ind1], odd_sizes[ind2], |
||||||
|
odd_sizes[ind3], odd_sizes[ind4], odd_sizes[ind5]); |
||||||
|
tsi_test_do_round_trip(&ssl_fixture->base); |
||||||
|
tsi_test_fixture_destroy(fixture); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, char **argv) { |
||||||
|
grpc_test_init(argc, argv); |
||||||
|
grpc_init(); |
||||||
|
ssl_tsi_test_do_handshake_tiny_handshake_buffer(); |
||||||
|
ssl_tsi_test_do_handshake_small_handshake_buffer(); |
||||||
|
ssl_tsi_test_do_handshake(); |
||||||
|
ssl_tsi_test_do_handshake_with_client_authentication(); |
||||||
|
ssl_tsi_test_do_handshake_with_server_name_indication_exact_domain(); |
||||||
|
ssl_tsi_test_do_handshake_with_server_name_indication_wild_star_domain(); |
||||||
|
ssl_tsi_test_do_handshake_with_bad_server_cert(); |
||||||
|
ssl_tsi_test_do_handshake_with_bad_client_cert(); |
||||||
|
ssl_tsi_test_do_handshake_alpn_client_no_server(); |
||||||
|
ssl_tsi_test_do_handshake_alpn_server_no_client(); |
||||||
|
ssl_tsi_test_do_handshake_alpn_client_server_mismatch(); |
||||||
|
ssl_tsi_test_do_handshake_alpn_client_server_ok(); |
||||||
|
ssl_tsi_test_do_round_trip_for_all_configs(); |
||||||
|
ssl_tsi_test_do_round_trip_odd_buffer_size(); |
||||||
|
grpc_shutdown(); |
||||||
|
return 0; |
||||||
|
} |
@ -0,0 +1,550 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* 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 <stdio.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <string.h> |
||||||
|
|
||||||
|
#include <grpc/grpc.h> |
||||||
|
#include <grpc/support/alloc.h> |
||||||
|
#include <grpc/support/log.h> |
||||||
|
#include "src/core/lib/security/transport/tsi_error.h" |
||||||
|
#include "test/core/tsi/transport_security_test_lib.h" |
||||||
|
|
||||||
|
typedef struct handshaker_args { |
||||||
|
tsi_test_fixture *fixture; |
||||||
|
unsigned char *handshake_buffer; |
||||||
|
size_t handshake_buffer_size; |
||||||
|
bool is_client; |
||||||
|
bool transferred_data; |
||||||
|
bool appended_unused_bytes; |
||||||
|
grpc_error *error; |
||||||
|
} handshaker_args; |
||||||
|
|
||||||
|
static handshaker_args *handshaker_args_create(tsi_test_fixture *fixture, |
||||||
|
bool is_client) { |
||||||
|
GPR_ASSERT(fixture != NULL); |
||||||
|
GPR_ASSERT(fixture->config != NULL); |
||||||
|
handshaker_args *args = gpr_zalloc(sizeof(*args)); |
||||||
|
args->fixture = fixture; |
||||||
|
args->handshake_buffer_size = fixture->handshake_buffer_size; |
||||||
|
args->handshake_buffer = gpr_zalloc(args->handshake_buffer_size); |
||||||
|
args->is_client = is_client; |
||||||
|
args->error = GRPC_ERROR_NONE; |
||||||
|
return args; |
||||||
|
} |
||||||
|
|
||||||
|
static void handshaker_args_destroy(handshaker_args *args) { |
||||||
|
gpr_free(args->handshake_buffer); |
||||||
|
GRPC_ERROR_UNREF(args->error); |
||||||
|
gpr_free(args); |
||||||
|
} |
||||||
|
|
||||||
|
static void do_handshaker_next(handshaker_args *args); |
||||||
|
|
||||||
|
static void setup_handshakers(tsi_test_fixture *fixture) { |
||||||
|
GPR_ASSERT(fixture != NULL); |
||||||
|
GPR_ASSERT(fixture->vtable != NULL); |
||||||
|
GPR_ASSERT(fixture->vtable->setup_handshakers != NULL); |
||||||
|
fixture->vtable->setup_handshakers(fixture); |
||||||
|
} |
||||||
|
|
||||||
|
static void check_unused_bytes(tsi_test_fixture *fixture) { |
||||||
|
tsi_handshaker_result *result_with_unused_bytes = |
||||||
|
fixture->has_client_finished_first ? fixture->server_result |
||||||
|
: fixture->client_result; |
||||||
|
tsi_handshaker_result *result_without_unused_bytes = |
||||||
|
fixture->has_client_finished_first ? fixture->client_result |
||||||
|
: fixture->server_result; |
||||||
|
const unsigned char *bytes = NULL; |
||||||
|
size_t bytes_size = 0; |
||||||
|
GPR_ASSERT(tsi_handshaker_result_get_unused_bytes( |
||||||
|
result_with_unused_bytes, &bytes, &bytes_size) == TSI_OK); |
||||||
|
GPR_ASSERT(bytes_size == strlen(TSI_TEST_UNUSED_BYTES)); |
||||||
|
GPR_ASSERT(memcmp(bytes, TSI_TEST_UNUSED_BYTES, bytes_size) == 0); |
||||||
|
GPR_ASSERT(tsi_handshaker_result_get_unused_bytes( |
||||||
|
result_without_unused_bytes, &bytes, &bytes_size) == TSI_OK); |
||||||
|
GPR_ASSERT(bytes_size == 0); |
||||||
|
GPR_ASSERT(bytes == NULL); |
||||||
|
} |
||||||
|
|
||||||
|
static void check_handshake_results(tsi_test_fixture *fixture) { |
||||||
|
GPR_ASSERT(fixture != NULL); |
||||||
|
GPR_ASSERT(fixture->vtable != NULL); |
||||||
|
GPR_ASSERT(fixture->vtable->check_handshaker_peers != NULL); |
||||||
|
/* Check handshaker peers. */ |
||||||
|
fixture->vtable->check_handshaker_peers(fixture); |
||||||
|
/* Check unused bytes. */ |
||||||
|
if (fixture->test_unused_bytes) { |
||||||
|
if (fixture->server_result != NULL && fixture->client_result != NULL) { |
||||||
|
check_unused_bytes(fixture); |
||||||
|
} |
||||||
|
fixture->bytes_written_to_server_channel = 0; |
||||||
|
fixture->bytes_written_to_client_channel = 0; |
||||||
|
fixture->bytes_read_from_client_channel = 0; |
||||||
|
fixture->bytes_read_from_server_channel = 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static void send_bytes_to_peer(tsi_test_fixture *fixture, |
||||||
|
const unsigned char *buf, size_t buf_size, |
||||||
|
bool is_client) { |
||||||
|
GPR_ASSERT(fixture != NULL); |
||||||
|
GPR_ASSERT(buf != NULL); |
||||||
|
uint8_t *channel = |
||||||
|
is_client ? fixture->server_channel : fixture->client_channel; |
||||||
|
GPR_ASSERT(channel != NULL); |
||||||
|
size_t *bytes_written = is_client ? &fixture->bytes_written_to_server_channel |
||||||
|
: &fixture->bytes_written_to_client_channel; |
||||||
|
GPR_ASSERT(bytes_written != NULL); |
||||||
|
GPR_ASSERT(*bytes_written + buf_size <= TSI_TEST_DEFAULT_CHANNEL_SIZE); |
||||||
|
/* Write data to channel. */ |
||||||
|
memcpy(channel + *bytes_written, buf, buf_size); |
||||||
|
*bytes_written += buf_size; |
||||||
|
} |
||||||
|
|
||||||
|
static void maybe_append_unused_bytes(handshaker_args *args) { |
||||||
|
GPR_ASSERT(args != NULL); |
||||||
|
GPR_ASSERT(args->fixture != NULL); |
||||||
|
tsi_test_fixture *fixture = args->fixture; |
||||||
|
if (fixture->test_unused_bytes && !args->appended_unused_bytes) { |
||||||
|
args->appended_unused_bytes = true; |
||||||
|
send_bytes_to_peer(fixture, (const unsigned char *)TSI_TEST_UNUSED_BYTES, |
||||||
|
strlen(TSI_TEST_UNUSED_BYTES), args->is_client); |
||||||
|
if (fixture->client_result != NULL && fixture->server_result == NULL) { |
||||||
|
fixture->has_client_finished_first = true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
static void receive_bytes_from_peer(tsi_test_fixture *fixture, |
||||||
|
unsigned char **buf, size_t *buf_size, |
||||||
|
bool is_client) { |
||||||
|
GPR_ASSERT(fixture != NULL); |
||||||
|
GPR_ASSERT(*buf != NULL); |
||||||
|
GPR_ASSERT(buf_size != NULL); |
||||||
|
uint8_t *channel = |
||||||
|
is_client ? fixture->client_channel : fixture->server_channel; |
||||||
|
GPR_ASSERT(channel != NULL); |
||||||
|
size_t *bytes_read = is_client ? &fixture->bytes_read_from_client_channel |
||||||
|
: &fixture->bytes_read_from_server_channel; |
||||||
|
size_t *bytes_written = is_client ? &fixture->bytes_written_to_client_channel |
||||||
|
: &fixture->bytes_written_to_server_channel; |
||||||
|
GPR_ASSERT(bytes_read != NULL); |
||||||
|
GPR_ASSERT(bytes_written != NULL); |
||||||
|
size_t to_read = *buf_size < *bytes_written - *bytes_read |
||||||
|
? *buf_size |
||||||
|
: *bytes_written - *bytes_read; |
||||||
|
/* Read data from channel. */ |
||||||
|
memcpy(*buf, channel + *bytes_read, to_read); |
||||||
|
*buf_size = to_read; |
||||||
|
*bytes_read += to_read; |
||||||
|
} |
||||||
|
|
||||||
|
static void send_message_to_peer(tsi_test_fixture *fixture, |
||||||
|
tsi_frame_protector *protector, |
||||||
|
bool is_client) { |
||||||
|
/* Initialization. */ |
||||||
|
GPR_ASSERT(fixture != NULL); |
||||||
|
GPR_ASSERT(fixture->config != NULL); |
||||||
|
GPR_ASSERT(protector != NULL); |
||||||
|
tsi_test_frame_protector_config *config = fixture->config; |
||||||
|
unsigned char *protected_buffer = gpr_zalloc(config->protected_buffer_size); |
||||||
|
size_t message_size = |
||||||
|
is_client ? config->client_message_size : config->server_message_size; |
||||||
|
uint8_t *message = |
||||||
|
is_client ? config->client_message : config->server_message; |
||||||
|
GPR_ASSERT(message != NULL); |
||||||
|
const unsigned char *message_bytes = (const unsigned char *)message; |
||||||
|
tsi_result result = TSI_OK; |
||||||
|
/* Do protect and send protected data to peer. */ |
||||||
|
while (message_size > 0 && result == TSI_OK) { |
||||||
|
size_t protected_buffer_size_to_send = config->protected_buffer_size; |
||||||
|
size_t processed_message_size = message_size; |
||||||
|
/* Do protect. */ |
||||||
|
result = tsi_frame_protector_protect( |
||||||
|
protector, message_bytes, &processed_message_size, protected_buffer, |
||||||
|
&protected_buffer_size_to_send); |
||||||
|
GPR_ASSERT(result == TSI_OK); |
||||||
|
/* Send protected data to peer. */ |
||||||
|
send_bytes_to_peer(fixture, protected_buffer, protected_buffer_size_to_send, |
||||||
|
is_client); |
||||||
|
message_bytes += processed_message_size; |
||||||
|
message_size -= processed_message_size; |
||||||
|
/* Flush if we're done. */ |
||||||
|
if (message_size == 0) { |
||||||
|
size_t still_pending_size; |
||||||
|
do { |
||||||
|
protected_buffer_size_to_send = config->protected_buffer_size; |
||||||
|
result = tsi_frame_protector_protect_flush( |
||||||
|
protector, protected_buffer, &protected_buffer_size_to_send, |
||||||
|
&still_pending_size); |
||||||
|
GPR_ASSERT(result == TSI_OK); |
||||||
|
send_bytes_to_peer(fixture, protected_buffer, |
||||||
|
protected_buffer_size_to_send, is_client); |
||||||
|
} while (still_pending_size > 0 && result == TSI_OK); |
||||||
|
GPR_ASSERT(result == TSI_OK); |
||||||
|
} |
||||||
|
} |
||||||
|
GPR_ASSERT(result == TSI_OK); |
||||||
|
gpr_free(protected_buffer); |
||||||
|
} |
||||||
|
|
||||||
|
static void receive_message_from_peer(tsi_test_fixture *fixture, |
||||||
|
tsi_frame_protector *protector, |
||||||
|
unsigned char *message, |
||||||
|
size_t *bytes_received, bool is_client) { |
||||||
|
/* Initialization. */ |
||||||
|
GPR_ASSERT(fixture != NULL); |
||||||
|
GPR_ASSERT(protector != NULL); |
||||||
|
GPR_ASSERT(message != NULL); |
||||||
|
GPR_ASSERT(bytes_received != NULL); |
||||||
|
GPR_ASSERT(fixture->config != NULL); |
||||||
|
tsi_test_frame_protector_config *config = fixture->config; |
||||||
|
size_t read_offset = 0; |
||||||
|
size_t message_offset = 0; |
||||||
|
size_t read_from_peer_size = 0; |
||||||
|
tsi_result result = TSI_OK; |
||||||
|
bool done = false; |
||||||
|
unsigned char *read_buffer = gpr_zalloc(config->read_buffer_allocated_size); |
||||||
|
unsigned char *message_buffer = |
||||||
|
gpr_zalloc(config->message_buffer_allocated_size); |
||||||
|
/* Do unprotect on data received from peer. */ |
||||||
|
while (!done && result == TSI_OK) { |
||||||
|
/* Receive data from peer. */ |
||||||
|
if (read_from_peer_size == 0) { |
||||||
|
read_from_peer_size = config->read_buffer_allocated_size; |
||||||
|
receive_bytes_from_peer(fixture, &read_buffer, &read_from_peer_size, |
||||||
|
is_client); |
||||||
|
read_offset = 0; |
||||||
|
} |
||||||
|
if (read_from_peer_size == 0) { |
||||||
|
done = true; |
||||||
|
} |
||||||
|
/* Do unprotect. */ |
||||||
|
size_t message_buffer_size; |
||||||
|
do { |
||||||
|
message_buffer_size = config->message_buffer_allocated_size; |
||||||
|
size_t processed_size = read_from_peer_size; |
||||||
|
result = tsi_frame_protector_unprotect( |
||||||
|
protector, read_buffer + read_offset, &processed_size, message_buffer, |
||||||
|
&message_buffer_size); |
||||||
|
GPR_ASSERT(result == TSI_OK); |
||||||
|
if (message_buffer_size > 0) { |
||||||
|
memcpy(message + message_offset, message_buffer, message_buffer_size); |
||||||
|
message_offset += message_buffer_size; |
||||||
|
} |
||||||
|
read_offset += processed_size; |
||||||
|
read_from_peer_size -= processed_size; |
||||||
|
} while ((read_from_peer_size > 0 || message_buffer_size > 0) && |
||||||
|
result == TSI_OK); |
||||||
|
GPR_ASSERT(result == TSI_OK); |
||||||
|
} |
||||||
|
GPR_ASSERT(result == TSI_OK); |
||||||
|
*bytes_received = message_offset; |
||||||
|
gpr_free(read_buffer); |
||||||
|
gpr_free(message_buffer); |
||||||
|
} |
||||||
|
|
||||||
|
grpc_error *on_handshake_next_done(tsi_result result, void *user_data, |
||||||
|
const unsigned char *bytes_to_send, |
||||||
|
size_t bytes_to_send_size, |
||||||
|
tsi_handshaker_result *handshaker_result) { |
||||||
|
handshaker_args *args = (handshaker_args *)user_data; |
||||||
|
GPR_ASSERT(args != NULL); |
||||||
|
GPR_ASSERT(args->fixture != NULL); |
||||||
|
tsi_test_fixture *fixture = args->fixture; |
||||||
|
grpc_error *error = GRPC_ERROR_NONE; |
||||||
|
/* Read more data if we need to. */ |
||||||
|
if (result == TSI_INCOMPLETE_DATA) { |
||||||
|
GPR_ASSERT(bytes_to_send_size == 0); |
||||||
|
return error; |
||||||
|
} |
||||||
|
if (result != TSI_OK) { |
||||||
|
return grpc_set_tsi_error_result( |
||||||
|
GRPC_ERROR_CREATE_FROM_STATIC_STRING("Handshake failed"), result); |
||||||
|
} |
||||||
|
/* Update handshaker result. */ |
||||||
|
if (handshaker_result != NULL) { |
||||||
|
tsi_handshaker_result **result_to_write = |
||||||
|
args->is_client ? &fixture->client_result : &fixture->server_result; |
||||||
|
GPR_ASSERT(*result_to_write == NULL); |
||||||
|
*result_to_write = handshaker_result; |
||||||
|
} |
||||||
|
/* Send data to peer, if needed. */ |
||||||
|
if (bytes_to_send_size > 0) { |
||||||
|
send_bytes_to_peer(args->fixture, bytes_to_send, bytes_to_send_size, |
||||||
|
args->is_client); |
||||||
|
args->transferred_data = true; |
||||||
|
} |
||||||
|
if (handshaker_result != NULL) { |
||||||
|
maybe_append_unused_bytes(args); |
||||||
|
} |
||||||
|
return error; |
||||||
|
} |
||||||
|
|
||||||
|
static void on_handshake_next_done_wrapper( |
||||||
|
tsi_result result, void *user_data, const unsigned char *bytes_to_send, |
||||||
|
size_t bytes_to_send_size, tsi_handshaker_result *handshaker_result) { |
||||||
|
handshaker_args *args = (handshaker_args *)user_data; |
||||||
|
args->error = on_handshake_next_done(result, user_data, bytes_to_send, |
||||||
|
bytes_to_send_size, handshaker_result); |
||||||
|
} |
||||||
|
|
||||||
|
static bool is_handshake_finished_properly(handshaker_args *args) { |
||||||
|
GPR_ASSERT(args != NULL); |
||||||
|
GPR_ASSERT(args->fixture != NULL); |
||||||
|
tsi_test_fixture *fixture = args->fixture; |
||||||
|
if ((args->is_client && fixture->client_result != NULL) || |
||||||
|
(!args->is_client && fixture->server_result != NULL)) { |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
static void do_handshaker_next(handshaker_args *args) { |
||||||
|
/* Initialization. */ |
||||||
|
GPR_ASSERT(args != NULL); |
||||||
|
GPR_ASSERT(args->fixture != NULL); |
||||||
|
tsi_test_fixture *fixture = args->fixture; |
||||||
|
tsi_handshaker *handshaker = |
||||||
|
args->is_client ? fixture->client_handshaker : fixture->server_handshaker; |
||||||
|
if (is_handshake_finished_properly(args)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
tsi_handshaker_result *handshaker_result = NULL; |
||||||
|
unsigned char *bytes_to_send = NULL; |
||||||
|
size_t bytes_to_send_size = 0; |
||||||
|
/* Receive data from peer, if available. */ |
||||||
|
size_t buf_size = args->handshake_buffer_size; |
||||||
|
receive_bytes_from_peer(args->fixture, &args->handshake_buffer, &buf_size, |
||||||
|
args->is_client); |
||||||
|
if (buf_size > 0) { |
||||||
|
args->transferred_data = true; |
||||||
|
} |
||||||
|
/* Peform handshaker next. */ |
||||||
|
tsi_result result = tsi_handshaker_next( |
||||||
|
handshaker, args->handshake_buffer, buf_size, |
||||||
|
(const unsigned char **)&bytes_to_send, &bytes_to_send_size, |
||||||
|
&handshaker_result, &on_handshake_next_done_wrapper, args); |
||||||
|
if (result != TSI_ASYNC) { |
||||||
|
args->error = on_handshake_next_done(result, args, bytes_to_send, |
||||||
|
bytes_to_send_size, handshaker_result); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void tsi_test_do_handshake(tsi_test_fixture *fixture) { |
||||||
|
/* Initializaiton. */ |
||||||
|
setup_handshakers(fixture); |
||||||
|
handshaker_args *client_args = |
||||||
|
handshaker_args_create(fixture, true /* is_client */); |
||||||
|
handshaker_args *server_args = |
||||||
|
handshaker_args_create(fixture, false /* is_client */); |
||||||
|
/* Do handshake. */ |
||||||
|
do { |
||||||
|
client_args->transferred_data = false; |
||||||
|
server_args->transferred_data = false; |
||||||
|
do_handshaker_next(client_args); |
||||||
|
if (client_args->error != GRPC_ERROR_NONE) { |
||||||
|
break; |
||||||
|
} |
||||||
|
do_handshaker_next(server_args); |
||||||
|
if (server_args->error != GRPC_ERROR_NONE) { |
||||||
|
break; |
||||||
|
} |
||||||
|
GPR_ASSERT(client_args->transferred_data || server_args->transferred_data); |
||||||
|
} while (fixture->client_result == NULL || fixture->server_result == NULL); |
||||||
|
/* Verify handshake results. */ |
||||||
|
check_handshake_results(fixture); |
||||||
|
/* Cleanup. */ |
||||||
|
handshaker_args_destroy(client_args); |
||||||
|
handshaker_args_destroy(server_args); |
||||||
|
} |
||||||
|
|
||||||
|
void tsi_test_do_round_trip(tsi_test_fixture *fixture) { |
||||||
|
/* Initialization. */ |
||||||
|
GPR_ASSERT(fixture != NULL); |
||||||
|
GPR_ASSERT(fixture->config != NULL); |
||||||
|
tsi_test_frame_protector_config *config = fixture->config; |
||||||
|
tsi_frame_protector *client_frame_protector = NULL; |
||||||
|
tsi_frame_protector *server_frame_protector = NULL; |
||||||
|
/* Perform handshake. */ |
||||||
|
tsi_test_do_handshake(fixture); |
||||||
|
/* Create frame protectors.*/ |
||||||
|
size_t client_max_output_protected_frame_size = |
||||||
|
config->client_max_output_protected_frame_size; |
||||||
|
GPR_ASSERT(tsi_handshaker_result_create_frame_protector( |
||||||
|
fixture->client_result, |
||||||
|
client_max_output_protected_frame_size == 0 |
||||||
|
? NULL |
||||||
|
: &client_max_output_protected_frame_size, |
||||||
|
&client_frame_protector) == TSI_OK); |
||||||
|
size_t server_max_output_protected_frame_size = |
||||||
|
config->server_max_output_protected_frame_size; |
||||||
|
GPR_ASSERT(tsi_handshaker_result_create_frame_protector( |
||||||
|
fixture->server_result, |
||||||
|
server_max_output_protected_frame_size == 0 |
||||||
|
? NULL |
||||||
|
: &server_max_output_protected_frame_size, |
||||||
|
&server_frame_protector) == TSI_OK); |
||||||
|
/* Client sends a message to server. */ |
||||||
|
send_message_to_peer(fixture, client_frame_protector, true /* is_client */); |
||||||
|
unsigned char *server_received_message = |
||||||
|
gpr_zalloc(TSI_TEST_DEFAULT_CHANNEL_SIZE); |
||||||
|
size_t server_received_message_size = 0; |
||||||
|
receive_message_from_peer( |
||||||
|
fixture, server_frame_protector, server_received_message, |
||||||
|
&server_received_message_size, false /* is_client */); |
||||||
|
GPR_ASSERT(config->client_message_size == server_received_message_size); |
||||||
|
GPR_ASSERT(memcmp(config->client_message, server_received_message, |
||||||
|
server_received_message_size) == 0); |
||||||
|
/* Server sends a message to client. */ |
||||||
|
send_message_to_peer(fixture, server_frame_protector, false /* is_client */); |
||||||
|
unsigned char *client_received_message = |
||||||
|
gpr_zalloc(TSI_TEST_DEFAULT_CHANNEL_SIZE); |
||||||
|
size_t client_received_message_size = 0; |
||||||
|
receive_message_from_peer( |
||||||
|
fixture, client_frame_protector, client_received_message, |
||||||
|
&client_received_message_size, true /* is_client */); |
||||||
|
GPR_ASSERT(config->server_message_size == client_received_message_size); |
||||||
|
GPR_ASSERT(memcmp(config->server_message, client_received_message, |
||||||
|
client_received_message_size) == 0); |
||||||
|
/* Destroy server and client frame protectors. */ |
||||||
|
tsi_frame_protector_destroy(client_frame_protector); |
||||||
|
tsi_frame_protector_destroy(server_frame_protector); |
||||||
|
gpr_free(server_received_message); |
||||||
|
gpr_free(client_received_message); |
||||||
|
} |
||||||
|
|
||||||
|
static unsigned char *generate_random_message(size_t size) { |
||||||
|
size_t i; |
||||||
|
unsigned char chars[] = "abcdefghijklmnopqrstuvwxyz1234567890"; |
||||||
|
unsigned char *output = gpr_zalloc(sizeof(unsigned char) * size); |
||||||
|
for (i = 0; i < size - 1; ++i) { |
||||||
|
output[i] = chars[rand() % (int)(sizeof(chars) - 1)]; |
||||||
|
} |
||||||
|
return output; |
||||||
|
} |
||||||
|
|
||||||
|
tsi_test_frame_protector_config *tsi_test_frame_protector_config_create( |
||||||
|
bool use_default_read_buffer_allocated_size, |
||||||
|
bool use_default_message_buffer_allocated_size, |
||||||
|
bool use_default_protected_buffer_size, bool use_default_client_message, |
||||||
|
bool use_default_server_message, |
||||||
|
bool use_default_client_max_output_protected_frame_size, |
||||||
|
bool use_default_server_max_output_protected_frame_size, |
||||||
|
bool use_default_handshake_buffer_size) { |
||||||
|
tsi_test_frame_protector_config *config = gpr_zalloc(sizeof(*config)); |
||||||
|
/* Set the value for read_buffer_allocated_size. */ |
||||||
|
config->read_buffer_allocated_size = |
||||||
|
use_default_read_buffer_allocated_size |
||||||
|
? TSI_TEST_DEFAULT_BUFFER_SIZE |
||||||
|
: TSI_TEST_SMALL_READ_BUFFER_ALLOCATED_SIZE; |
||||||
|
/* Set the value for message_buffer_allocated_size. */ |
||||||
|
config->message_buffer_allocated_size = |
||||||
|
use_default_message_buffer_allocated_size |
||||||
|
? TSI_TEST_DEFAULT_BUFFER_SIZE |
||||||
|
: TSI_TEST_SMALL_MESSAGE_BUFFER_ALLOCATED_SIZE; |
||||||
|
/* Set the value for protected_buffer_size. */ |
||||||
|
config->protected_buffer_size = use_default_protected_buffer_size |
||||||
|
? TSI_TEST_DEFAULT_PROTECTED_BUFFER_SIZE |
||||||
|
: TSI_TEST_SMALL_PROTECTED_BUFFER_SIZE; |
||||||
|
/* Set the value for client message. */ |
||||||
|
config->client_message_size = use_default_client_message |
||||||
|
? TSI_TEST_BIG_MESSAGE_SIZE |
||||||
|
: TSI_TEST_SMALL_MESSAGE_SIZE; |
||||||
|
config->client_message = |
||||||
|
use_default_client_message |
||||||
|
? generate_random_message(TSI_TEST_BIG_MESSAGE_SIZE) |
||||||
|
: generate_random_message(TSI_TEST_SMALL_MESSAGE_SIZE); |
||||||
|
/* Set the value for server message. */ |
||||||
|
config->server_message_size = use_default_server_message |
||||||
|
? TSI_TEST_BIG_MESSAGE_SIZE |
||||||
|
: TSI_TEST_SMALL_MESSAGE_SIZE; |
||||||
|
config->server_message = |
||||||
|
use_default_server_message |
||||||
|
? generate_random_message(TSI_TEST_BIG_MESSAGE_SIZE) |
||||||
|
: generate_random_message(TSI_TEST_SMALL_MESSAGE_SIZE); |
||||||
|
/* Set the value for client max_output_protected_frame_size.
|
||||||
|
If it is 0, we pass NULL to tsi_handshaker_result_create_frame_protector(), |
||||||
|
which then uses default protected frame size for it. */ |
||||||
|
config->client_max_output_protected_frame_size = |
||||||
|
use_default_client_max_output_protected_frame_size |
||||||
|
? 0 |
||||||
|
: TSI_TEST_SMALL_CLIENT_MAX_OUTPUT_PROTECTED_FRAME_SIZE; |
||||||
|
/* Set the value for server max_output_protected_frame_size.
|
||||||
|
If it is 0, we pass NULL to tsi_handshaker_result_create_frame_protector(), |
||||||
|
which then uses default protected frame size for it. */ |
||||||
|
config->server_max_output_protected_frame_size = |
||||||
|
use_default_server_max_output_protected_frame_size |
||||||
|
? 0 |
||||||
|
: TSI_TEST_SMALL_SERVER_MAX_OUTPUT_PROTECTED_FRAME_SIZE; |
||||||
|
return config; |
||||||
|
} |
||||||
|
|
||||||
|
void tsi_test_frame_protector_config_set_buffer_size( |
||||||
|
tsi_test_frame_protector_config *config, size_t read_buffer_allocated_size, |
||||||
|
size_t message_buffer_allocated_size, size_t protected_buffer_size, |
||||||
|
size_t client_max_output_protected_frame_size, |
||||||
|
size_t server_max_output_protected_frame_size) { |
||||||
|
GPR_ASSERT(config != NULL); |
||||||
|
config->read_buffer_allocated_size = read_buffer_allocated_size; |
||||||
|
config->message_buffer_allocated_size = message_buffer_allocated_size; |
||||||
|
config->protected_buffer_size = protected_buffer_size; |
||||||
|
config->client_max_output_protected_frame_size = |
||||||
|
client_max_output_protected_frame_size; |
||||||
|
config->server_max_output_protected_frame_size = |
||||||
|
server_max_output_protected_frame_size; |
||||||
|
} |
||||||
|
|
||||||
|
void tsi_test_frame_protector_config_destroy( |
||||||
|
tsi_test_frame_protector_config *config) { |
||||||
|
GPR_ASSERT(config != NULL); |
||||||
|
gpr_free(config->client_message); |
||||||
|
gpr_free(config->server_message); |
||||||
|
gpr_free(config); |
||||||
|
} |
||||||
|
|
||||||
|
void tsi_test_fixture_init(tsi_test_fixture *fixture) { |
||||||
|
fixture->config = tsi_test_frame_protector_config_create( |
||||||
|
true, true, true, true, true, true, true, true); |
||||||
|
fixture->handshake_buffer_size = TSI_TEST_DEFAULT_BUFFER_SIZE; |
||||||
|
fixture->client_channel = gpr_zalloc(TSI_TEST_DEFAULT_CHANNEL_SIZE); |
||||||
|
fixture->server_channel = gpr_zalloc(TSI_TEST_DEFAULT_CHANNEL_SIZE); |
||||||
|
fixture->bytes_written_to_client_channel = 0; |
||||||
|
fixture->bytes_written_to_server_channel = 0; |
||||||
|
fixture->bytes_read_from_client_channel = 0; |
||||||
|
fixture->bytes_read_from_server_channel = 0; |
||||||
|
fixture->test_unused_bytes = true; |
||||||
|
fixture->has_client_finished_first = false; |
||||||
|
} |
||||||
|
|
||||||
|
void tsi_test_fixture_destroy(tsi_test_fixture *fixture) { |
||||||
|
GPR_ASSERT(fixture != NULL); |
||||||
|
tsi_test_frame_protector_config_destroy(fixture->config); |
||||||
|
tsi_handshaker_destroy(fixture->client_handshaker); |
||||||
|
tsi_handshaker_destroy(fixture->server_handshaker); |
||||||
|
tsi_handshaker_result_destroy(fixture->client_result); |
||||||
|
tsi_handshaker_result_destroy(fixture->server_result); |
||||||
|
gpr_free(fixture->client_channel); |
||||||
|
gpr_free(fixture->server_channel); |
||||||
|
GPR_ASSERT(fixture->vtable != NULL); |
||||||
|
GPR_ASSERT(fixture->vtable->destruct != NULL); |
||||||
|
fixture->vtable->destruct(fixture); |
||||||
|
gpr_free(fixture); |
||||||
|
} |
@ -0,0 +1,165 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* 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_TEST_CORE_TSI_TRANSPORT_SECURITY_TEST_LIB_H_ |
||||||
|
#define GRPC_TEST_CORE_TSI_TRANSPORT_SECURITY_TEST_LIB_H_ |
||||||
|
|
||||||
|
#include "src/core/tsi/transport_security_interface.h" |
||||||
|
|
||||||
|
#define TSI_TEST_TINY_HANDSHAKE_BUFFER_SIZE 32 |
||||||
|
#define TSI_TEST_SMALL_HANDSHAKE_BUFFER_SIZE 128 |
||||||
|
#define TSI_TEST_SMALL_READ_BUFFER_ALLOCATED_SIZE 41 |
||||||
|
#define TSI_TEST_SMALL_PROTECTED_BUFFER_SIZE 37 |
||||||
|
#define TSI_TEST_SMALL_MESSAGE_BUFFER_ALLOCATED_SIZE 42 |
||||||
|
#define TSI_TEST_SMALL_CLIENT_MAX_OUTPUT_PROTECTED_FRAME_SIZE 39 |
||||||
|
#define TSI_TEST_SMALL_SERVER_MAX_OUTPUT_PROTECTED_FRAME_SIZE 43 |
||||||
|
#define TSI_TEST_DEFAULT_BUFFER_SIZE 4096 |
||||||
|
#define TSI_TEST_DEFAULT_PROTECTED_BUFFER_SIZE 16384 |
||||||
|
#define TSI_TEST_DEFAULT_CHANNEL_SIZE 32768 |
||||||
|
#define TSI_TEST_BIG_MESSAGE_SIZE 17000 |
||||||
|
#define TSI_TEST_SMALL_MESSAGE_SIZE 10 |
||||||
|
#define TSI_TEST_NUM_OF_ARGUMENTS 8 |
||||||
|
#define TSI_TEST_NUM_OF_COMBINATIONS 256 |
||||||
|
#define TSI_TEST_UNUSED_BYTES "HELLO GOOGLE" |
||||||
|
|
||||||
|
/* --- tsi_test_fixture object ---
|
||||||
|
The tests for specific TSI implementations should create their own |
||||||
|
custom "subclass" of this fixture, which wraps all information |
||||||
|
that will be used to test correctness of TSI handshakes and frame |
||||||
|
protect/unprotect operations with respect to TSI implementations. */ |
||||||
|
typedef struct tsi_test_fixture tsi_test_fixture; |
||||||
|
|
||||||
|
/* --- tsi_test_frame_protector_config object ---
|
||||||
|
|
||||||
|
This object is used to configure different parameters of TSI frame protector |
||||||
|
APIs. */ |
||||||
|
typedef struct tsi_test_frame_protector_config tsi_test_frame_protector_config; |
||||||
|
|
||||||
|
/* V-table for tsi_test_fixture operations that are implemented differently in
|
||||||
|
different TSI implementations. */ |
||||||
|
typedef struct tsi_test_fixture_vtable { |
||||||
|
void (*setup_handshakers)(tsi_test_fixture *fixture); |
||||||
|
void (*check_handshaker_peers)(tsi_test_fixture *fixture); |
||||||
|
void (*destruct)(tsi_test_fixture *fixture); |
||||||
|
} tranport_security_test_vtable; |
||||||
|
|
||||||
|
struct tsi_test_fixture { |
||||||
|
const struct tsi_test_fixture_vtable *vtable; |
||||||
|
/* client/server TSI handshaker used to perform TSI handshakes, and will get
|
||||||
|
instantiated during the call to setup_handshakers. */ |
||||||
|
tsi_handshaker *client_handshaker; |
||||||
|
tsi_handshaker *server_handshaker; |
||||||
|
/* client/server TSI handshaker results used to store the result of TSI
|
||||||
|
handshake. If the handshake fails, the result will store NULL upon |
||||||
|
finishing the handshake. */ |
||||||
|
tsi_handshaker_result *client_result; |
||||||
|
tsi_handshaker_result *server_result; |
||||||
|
/* size of buffer used to store data received from the peer. */ |
||||||
|
size_t handshake_buffer_size; |
||||||
|
/* simulated channels between client and server. If the server (client)
|
||||||
|
wants to send data to the client (server), he will write data to |
||||||
|
client_channel (server_channel), which will be read by client (server). */ |
||||||
|
uint8_t *client_channel; |
||||||
|
uint8_t *server_channel; |
||||||
|
/* size of data written to the client/server channel. */ |
||||||
|
size_t bytes_written_to_client_channel; |
||||||
|
size_t bytes_written_to_server_channel; |
||||||
|
/* size of data read from the client/server channel */ |
||||||
|
size_t bytes_read_from_client_channel; |
||||||
|
size_t bytes_read_from_server_channel; |
||||||
|
/* tsi_test_frame_protector_config instance */ |
||||||
|
tsi_test_frame_protector_config *config; |
||||||
|
/* a flag indicating if client has finished TSI handshake first (i.e., before
|
||||||
|
server). |
||||||
|
The flag should be referred if and only if TSI handshake finishes |
||||||
|
successfully. */ |
||||||
|
bool has_client_finished_first; |
||||||
|
/* a flag indicating whether to test tsi_handshaker_result_get_unused_bytes()
|
||||||
|
for TSI implementation. This field is true by default, and false |
||||||
|
for SSL TSI implementation due to grpc issue #12164 |
||||||
|
(https://github.com/grpc/grpc/issues/12164).
|
||||||
|
*/ |
||||||
|
bool test_unused_bytes; |
||||||
|
}; |
||||||
|
|
||||||
|
struct tsi_test_frame_protector_config { |
||||||
|
/* size of buffer used to store protected frames to be unprotected. */ |
||||||
|
size_t read_buffer_allocated_size; |
||||||
|
/* size of buffer used to store bytes resulted from unprotect operations. */ |
||||||
|
size_t message_buffer_allocated_size; |
||||||
|
/* size of buffer used to store frames resulted from protect operations. */ |
||||||
|
size_t protected_buffer_size; |
||||||
|
/* size of client/server maximum frame size. */ |
||||||
|
size_t client_max_output_protected_frame_size; |
||||||
|
size_t server_max_output_protected_frame_size; |
||||||
|
/* pointer that points to client/server message to be protected. */ |
||||||
|
uint8_t *client_message; |
||||||
|
uint8_t *server_message; |
||||||
|
/* size of client/server message. */ |
||||||
|
size_t client_message_size; |
||||||
|
size_t server_message_size; |
||||||
|
}; |
||||||
|
|
||||||
|
/* This method creates a tsi_test_frame_protector_config instance. Each
|
||||||
|
parameter of this function is a boolean value indicating whether to set the |
||||||
|
corresponding parameter with a default value or not. If it's false, it will |
||||||
|
be set with a specific value which is usually much smaller than the default. |
||||||
|
Both values are defined with #define directive. */ |
||||||
|
tsi_test_frame_protector_config *tsi_test_frame_protector_config_create( |
||||||
|
bool use_default_read_buffer_allocated_size, |
||||||
|
bool use_default_message_buffer_allocated_size, |
||||||
|
bool use_default_protected_buffer_size, bool use_default_client_message, |
||||||
|
bool use_default_server_message, |
||||||
|
bool use_default_client_max_output_protected_frame_size, |
||||||
|
bool use_default_server_max_output_protected_frame_size, |
||||||
|
bool use_default_handshake_buffer_size); |
||||||
|
|
||||||
|
/* This method sets different buffer and frame sizes of a
|
||||||
|
tsi_test_frame_protector_config instance with user provided values. */ |
||||||
|
void tsi_test_frame_protector_config_set_buffer_size( |
||||||
|
tsi_test_frame_protector_config *config, size_t read_buffer_allocated_size, |
||||||
|
size_t message_buffer_allocated_size, size_t protected_buffer_size, |
||||||
|
size_t client_max_output_protected_frame_size, |
||||||
|
size_t server_max_output_protected_frame_size); |
||||||
|
|
||||||
|
/* This method destroys a tsi_test_frame_protector_config instance. */ |
||||||
|
void tsi_test_frame_protector_config_destroy( |
||||||
|
tsi_test_frame_protector_config *config); |
||||||
|
|
||||||
|
/* This method initializes members of tsi_test_fixture instance.
|
||||||
|
Note that the struct instance should be allocated before making |
||||||
|
this call. */ |
||||||
|
void tsi_test_fixture_init(tsi_test_fixture *fixture); |
||||||
|
|
||||||
|
/* This method destroys a tsi_test_fixture instance. Note that the
|
||||||
|
fixture intance must be dynamically allocated and will be freed by |
||||||
|
this function. */ |
||||||
|
void tsi_test_fixture_destroy(tsi_test_fixture *fixture); |
||||||
|
|
||||||
|
/* This method performs a full TSI handshake between a client and a server.
|
||||||
|
Note that the test library will implement the new TSI handshaker API to |
||||||
|
perform handshakes. */ |
||||||
|
void tsi_test_do_handshake(tsi_test_fixture *fixture); |
||||||
|
|
||||||
|
/* This method performs a round trip test between the client and the server.
|
||||||
|
That is, the client sends a protected message to a server who receives the |
||||||
|
message, and unprotects it. The same operation is triggered again with |
||||||
|
the client and server switching its role. */ |
||||||
|
void tsi_test_do_round_trip(tsi_test_fixture *fixture); |
||||||
|
|
||||||
|
#endif // GRPC_TEST_CORE_TSI_TRANSPORT_SECURITY_TEST_LIB_H_
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue