Merge pull request #19747 from rmstar/cronetexpt

Add C++ Cronet end2end tests
pull/19781/head
rmstar 6 years ago committed by GitHub
commit 7bdf369b89
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 42
      src/cpp/Protobuf-C++.podspec
  2. 125
      src/objective-c/!ProtoCompiler-gRPCCppPlugin.podspec
  3. 127
      templates/src/objective-c/!ProtoCompiler-gRPCCppPlugin.podspec.template
  4. 569
      test/cpp/ios/CronetTests/CppCronetEnd2EndTests.mm
  5. 81
      test/cpp/ios/CronetTests/TestHelper.h
  6. 198
      test/cpp/ios/CronetTests/TestHelper.mm
  7. 24
      test/cpp/ios/Info.plist
  8. 102
      test/cpp/ios/Podfile
  9. 98
      test/cpp/ios/RemoteTestClientCpp/RemoteTestCpp.podspec
  10. 594
      test/cpp/ios/Tests.xcodeproj/project.pbxproj
  11. 95
      test/cpp/ios/Tests.xcodeproj/xcshareddata/xcschemes/CronetTests.xcscheme
  12. 40
      test/cpp/ios/build_tests.sh
  13. 34
      test/cpp/ios/run_tests.sh
  14. 31
      tools/internal_ci/macos/grpc_basictests_cpp_ios.cfg
  15. 8
      tools/run_tests/run_tests.py

@ -0,0 +1,42 @@
Pod::Spec.new do |s|
s.name = 'Protobuf-C++'
s.version = '3.8.0'
s.summary = 'Protocol Buffers v3 runtime library for C++.'
s.homepage = 'https://github.com/google/protobuf'
s.license = '3-Clause BSD License'
s.authors = { 'The Protocol Buffers contributors' => 'protobuf@googlegroups.com' }
s.cocoapods_version = '>= 1.0'
s.source = { :git => 'https://github.com/google/protobuf.git',
:tag => "v#{s.version}" }
s.source_files = 'src/google/protobuf/*.{h,cc,inc}',
'src/google/protobuf/stubs/*.{h,cc}',
'src/google/protobuf/io/*.{h,cc}',
'src/google/protobuf/util/*.{h,cc}',
'src/google/protobuf/util/internal/*.{h,cc}'
# Excluding all the tests in the directories above
s.exclude_files = 'src/google/**/*_test.{h,cc,inc}',
'src/google/**/*_unittest.{h,cc}',
'src/google/protobuf/test_util*.{h,cc}',
'src/google/protobuf/map_lite_test_util.{h,cc}',
'src/google/protobuf/map_test_util*.{h,cc,inc}'
s.header_mappings_dir = 'src'
s.ios.deployment_target = '7.0'
s.osx.deployment_target = '10.9'
s.tvos.deployment_target = '9.0'
s.watchos.deployment_target = '2.0'
s.pod_target_xcconfig = {
# Do not let src/google/protobuf/stubs/time.h override system API
'USE_HEADERMAP' => 'NO',
'ALWAYS_SEARCH_USER_PATHS' => 'NO',
# Configure tool is not being used for Xcode. When building, assume pthread is supported.
'GCC_PREPROCESSOR_DEFINITIONS' => '"$(inherited)" "HAVE_PTHREAD=1"',
}
end

@ -0,0 +1,125 @@
# This file has been automatically generated from a template file.
# Please make modifications to
# `templates/src/objective-c/!ProtoCompiler-gRPCCppPlugin.podspec.template`
# instead. This file can be regenerated from the template by running
# `tools/buildgen/generate_projects.sh`.
# CocoaPods podspec for the gRPC Proto Compiler Plugin
#
# Copyright 2019, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Pod::Spec.new do |s|
# This pod is only a utility that will be used by other pods _at install time_ (not at compile
# time). Other pods can access it in their `prepare_command` script, under <pods_root>/<pod name>.
# Because CocoaPods installs pods in alphabetical order, beginning this pod's name with an
# exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed
# before them.
s.name = '!ProtoCompiler-gRPCCppPlugin'
v = '1.23.0-dev'
s.version = v
s.summary = 'The gRPC ProtoC plugin generates C++ files from .proto services.'
s.description = <<-DESC
This podspec only downloads the gRPC protoc plugin so that local pods generating protos can use
it in their invocation of protoc, as part of their prepare_command.
DESC
s.homepage = 'https://grpc.io'
s.license = {
:type => 'Apache License, Version 2.0',
:text => <<-LICENSE
Copyright 2019, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
LICENSE
}
s.authors = { 'The gRPC contributors' => 'grpc-packages@google.com' }
repo = 'grpc/grpc'
file = "grpc_cpp_plugin-#{v}-macos-x86_64.zip"
s.source = {
:http => "https://github.com/#{repo}/releases/download/v#{v}/#{file}",
# TODO(jcanizales): Add sha1 or sha256
# :sha1 => '??',
}
repo_root = '../..'
plugin = 'grpc_cpp_plugin'
s.preserve_paths = plugin
# Restrict the protoc version to the one supported by this plugin.
s.dependency '!ProtoCompiler', '3.8.0'
# For the Protobuf dependency not to complain:
s.ios.deployment_target = '7.0'
s.osx.deployment_target = '10.9'
s.tvos.deployment_target = '10.0'
s.watchos.deployment_target = '2.0'
# This is only for local development of the plugin: If the Podfile brings this pod from a local
# directory using `:path`, CocoaPods won't download the zip file and so the plugin won't be
# present in this pod's directory. We use that knowledge to check for the existence of the file
# and, if absent, compile the plugin from the local sources.
s.prepare_command = <<-CMD
if [ ! -f #{plugin} ]; then
cd #{repo_root}
# This will build the plugin and put it in #{repo_root}/bins/opt.
#
# TODO(jcanizales): I reckon make will try to use locally-installed libprotoc (headers and
# library binary) if found, which _we do not want_. Find a way for this to always use the
# sources in the repo.
make #{plugin}
cd -
fi
CMD
end

@ -0,0 +1,127 @@
%YAML 1.2
--- |
# This file has been automatically generated from a template file.
# Please make modifications to
# `templates/src/objective-c/!ProtoCompiler-gRPCCppPlugin.podspec.template`
# instead. This file can be regenerated from the template by running
# `tools/buildgen/generate_projects.sh`.
# CocoaPods podspec for the gRPC Proto Compiler Plugin
#
# Copyright 2019, Google Inc.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are
# met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above
# copyright notice, this list of conditions and the following disclaimer
# in the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Google Inc. nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Pod::Spec.new do |s|
# This pod is only a utility that will be used by other pods _at install time_ (not at compile
# time). Other pods can access it in their `prepare_command` script, under <pods_root>/<pod name>.
# Because CocoaPods installs pods in alphabetical order, beginning this pod's name with an
# exclamation mark ensures that other "regular" pods will be able to find it as it'll be installed
# before them.
s.name = '!ProtoCompiler-gRPCCppPlugin'
v = '${settings.version}'
s.version = v
s.summary = 'The gRPC ProtoC plugin generates C++ files from .proto services.'
s.description = <<-DESC
This podspec only downloads the gRPC protoc plugin so that local pods generating protos can use
it in their invocation of protoc, as part of their prepare_command.
DESC
s.homepage = 'https://grpc.io'
s.license = {
:type => 'Apache License, Version 2.0',
:text => <<-LICENSE
Copyright 2019, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
LICENSE
}
s.authors = { 'The gRPC contributors' => 'grpc-packages@google.com' }
repo = 'grpc/grpc'
file = "grpc_cpp_plugin-#{v}-macos-x86_64.zip"
s.source = {
:http => "https://github.com/#{repo}/releases/download/v#{v}/#{file}",
# TODO(jcanizales): Add sha1 or sha256
# :sha1 => '??',
}
repo_root = '../..'
plugin = 'grpc_cpp_plugin'
s.preserve_paths = plugin
# Restrict the protoc version to the one supported by this plugin.
s.dependency '!ProtoCompiler', '3.8.0'
# For the Protobuf dependency not to complain:
s.ios.deployment_target = '7.0'
s.osx.deployment_target = '10.9'
s.tvos.deployment_target = '10.0'
s.watchos.deployment_target = '2.0'
# This is only for local development of the plugin: If the Podfile brings this pod from a local
# directory using `:path`, CocoaPods won't download the zip file and so the plugin won't be
# present in this pod's directory. We use that knowledge to check for the existence of the file
# and, if absent, compile the plugin from the local sources.
s.prepare_command = <<-CMD
if [ ! -f #{plugin} ]; then
cd #{repo_root}
# This will build the plugin and put it in #{repo_root}/bins/opt.
#
# TODO(jcanizales): I reckon make will try to use locally-installed libprotoc (headers and
# library binary) if found, which _we do not want_. Find a way for this to always use the
# sources in the repo.
make #{plugin}
cd -
fi
CMD
end

@ -0,0 +1,569 @@
/*
*
* Copyright 2019 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 <Cronet/Cronet.h>
#import <XCTest/XCTest.h>
#import <grpc/grpc_cronet.h>
#import <grpcpp/create_channel.h>
#import <grpcpp/impl/codegen/client_context.h>
#import <grpcpp/impl/codegen/config.h>
#import <grpcpp/resource_quota.h>
#import <grpcpp/security/cronet_credentials.h>
#import <grpcpp/server_builder.h>
#import <grpcpp/server_context.h>
#import <grpcpp/support/client_interceptor.h>
#import <src/proto/grpc/testing/echo.grpc.pb.h>
#import "TestHelper.h"
#import "test/core/end2end/data/ssl_test_data.h"
#import <map>
#import <sstream>
#import <thread>
#import <vector>
using namespace grpc::testing;
using std::chrono::system_clock;
using grpc::Status;
using grpc::ServerContext;
using grpc::ClientContext;
@interface CppCronetEnd2EndTests : XCTestCase
@end
@implementation CppCronetEnd2EndTests {
std::unique_ptr<grpc::Server> _server;
TestServiceImpl _service;
TestServiceImpl _foo_service;
}
// The setUp() function is run before the test cases run and only run once
+ (void)setUp {
[super setUp];
configureCronet();
}
- (void)startServer {
if (_server) {
// server is already running
return;
}
grpc::ServerBuilder builder;
grpc::SslServerCredentialsOptions ssl_opts;
ssl_opts.pem_root_certs = "";
grpc::SslServerCredentialsOptions::PemKeyCertPair pkcp = {test_server1_key, test_server1_cert};
ssl_opts.pem_key_cert_pairs.push_back(pkcp);
auto server_creds = SslServerCredentials(ssl_opts);
builder.AddListeningPort("localhost:5000", server_creds);
builder.RegisterService(&_service);
builder.RegisterService("foo.test.youtube.com", &_foo_service);
_server = builder.BuildAndStart();
}
- (void)stopServer {
_server.reset();
}
- (void)restartServer {
[self stopServer];
[self startServer];
}
- (void)setUp {
[self startServer];
}
- (void)sendRPCWithStub:(EchoTestService::Stub*)stub
numRPCs:(int)num_rpcs
withBinaryMetadata:(BOOL)with_binary_metadata {
EchoRequest request;
EchoResponse response;
request.set_message("Hello hello hello hello");
for (int i = 0; i < num_rpcs; ++i) {
ClientContext context;
if (with_binary_metadata) {
char bytes[8] = {'\0', '\1', '\2', '\3', '\4', '\5', '\6', static_cast<char>(i)};
context.AddMetadata("custom-bin", grpc::string(bytes, 8));
}
context.set_compression_algorithm(GRPC_COMPRESS_GZIP);
Status s = stub->Echo(&context, request, &response);
XCTAssertEqual(response.message(), request.message());
XCTAssertTrue(s.ok());
}
}
- (std::shared_ptr<::grpc::Channel>)getChannel {
stream_engine* cronetEngine = [Cronet getGlobalEngine];
auto cronetChannelCredentials = grpc::CronetChannelCredentials(cronetEngine);
grpc::ChannelArguments args;
args.SetSslTargetNameOverride("foo.test.google.fr");
args.SetUserAgentPrefix("custom_prefix");
args.SetString(GRPC_ARG_SECONDARY_USER_AGENT_STRING, "end2end_test");
auto channel = grpc::CreateCustomChannel("127.0.0.1:5000", cronetChannelCredentials, args);
return channel;
}
- (std::shared_ptr<::grpc::Channel>)getChannelWithInterceptors:
(std::vector<std::unique_ptr<grpc::experimental::ClientInterceptorFactoryInterface>>)creators {
stream_engine* cronetEngine = [Cronet getGlobalEngine];
auto cronetChannelCredentials = grpc::CronetChannelCredentials(cronetEngine);
grpc::ChannelArguments args;
args.SetSslTargetNameOverride("foo.test.google.fr");
args.SetUserAgentPrefix("custom_prefix");
args.SetString(GRPC_ARG_SECONDARY_USER_AGENT_STRING, "end2end_test");
auto channel = grpc::experimental::CreateCustomChannelWithInterceptors(
"127.0.01:5000", cronetChannelCredentials, args, std::move(creators));
return channel;
}
- (std::unique_ptr<EchoTestService::Stub>)getStub {
auto channel = [self getChannel];
auto stub = EchoTestService::NewStub(channel);
return stub;
}
- (void)testUserAgent {
ClientContext context;
EchoRequest request;
EchoResponse response;
request.set_message("Hello");
request.mutable_param()->set_echo_metadata(true);
auto stub = [self getStub];
Status s = stub->Echo(&context, request, &response);
XCTAssertTrue(s.ok());
const auto& trailing_metadata = context.GetServerTrailingMetadata();
auto iter = trailing_metadata.find("user-agent");
XCTAssert(iter->second.starts_with("custom_prefix grpc-c++"));
}
- (void)testMultipleRPCs {
auto stub = [self getStub];
std::vector<std::thread> threads;
threads.reserve(10);
for (int i = 0; i < 10; ++i) {
threads.emplace_back(
[self, &stub]() { [self sendRPCWithStub:stub.get() numRPCs:10 withBinaryMetadata:NO]; });
}
for (int i = 0; i < 10; ++i) {
threads[i].join();
}
}
- (void)testMultipleRPCsWithBinaryMetadata {
auto stub = [self getStub];
std::vector<std::thread> threads;
threads.reserve(10);
for (int i = 0; i < 10; ++i) {
threads.emplace_back(
[self, &stub]() { [self sendRPCWithStub:stub.get() numRPCs:10 withBinaryMetadata:YES]; });
}
for (int i = 0; i < 10; ++i) {
threads[i].join();
}
}
- (void)testEmptyBinaryMetadata {
EchoRequest request;
EchoResponse response;
request.set_message("Hello hello hello hello");
ClientContext context;
context.AddMetadata("custom-bin", "");
auto stub = [self getStub];
Status s = stub->Echo(&context, request, &response);
XCTAssertEqual(response.message(), request.message());
XCTAssertTrue(s.ok());
}
- (void)testReconnectChannel {
auto stub = [self getStub];
[self sendRPCWithStub:stub.get() numRPCs:1 withBinaryMetadata:NO];
[self restartServer];
[self sendRPCWithStub:stub.get() numRPCs:1 withBinaryMetadata:NO];
}
- (void)testRequestStreamOneRequest {
auto stub = [self getStub];
EchoRequest request;
EchoResponse response;
ClientContext context;
auto stream = stub->RequestStream(&context, &response);
request.set_message("hello");
XCTAssertTrue(stream->Write(request));
stream->WritesDone();
Status s = stream->Finish();
XCTAssertEqual(response.message(), request.message());
XCTAssertTrue(s.ok());
XCTAssertTrue(context.debug_error_string().empty());
}
- (void)testRequestStreamOneRequestWithCoalescingApi {
auto stub = [self getStub];
EchoRequest request;
EchoResponse response;
ClientContext context;
context.set_initial_metadata_corked(true);
auto stream = stub->RequestStream(&context, &response);
request.set_message("hello");
XCTAssertTrue(stream->Write(request));
stream->WritesDone();
Status s = stream->Finish();
XCTAssertEqual(response.message(), request.message());
XCTAssertTrue(s.ok());
}
- (void)testRequestStreamTwoRequests {
auto stub = [self getStub];
EchoRequest request;
EchoResponse response;
ClientContext context;
auto stream = stub->RequestStream(&context, &response);
request.set_message("hello");
XCTAssertTrue(stream->Write(request));
XCTAssertTrue(stream->Write(request));
stream->WritesDone();
Status s = stream->Finish();
XCTAssertEqual(response.message(), "hellohello");
XCTAssertTrue(s.ok());
}
- (void)testResponseStream {
auto stub = [self getStub];
EchoRequest request;
EchoResponse response;
ClientContext context;
request.set_message("hello");
auto stream = stub->ResponseStream(&context, request);
for (int i = 0; i < kServerDefaultResponseStreamsToSend; ++i) {
XCTAssertTrue(stream->Read(&response));
XCTAssertEqual(response.message(), request.message() + grpc::to_string(i));
}
XCTAssertFalse(stream->Read(&response));
Status s = stream->Finish();
XCTAssertTrue(s.ok());
}
- (void)testBidiStream {
auto stub = [self getStub];
EchoRequest request;
EchoResponse response;
ClientContext context;
grpc::string msg("hello");
auto stream = stub->BidiStream(&context);
for (int i = 0; i < kServerDefaultResponseStreamsToSend; ++i) {
request.set_message(msg + grpc::to_string(i));
XCTAssertTrue(stream->Write(request));
XCTAssertTrue(stream->Read(&response));
XCTAssertEqual(response.message(), request.message());
}
stream->WritesDone();
XCTAssertFalse(stream->Read(&response));
XCTAssertFalse(stream->Read(&response));
Status s = stream->Finish();
XCTAssertTrue(s.ok());
}
- (void)testBidiStreamWithCoalescingApi {
auto stub = [self getStub];
EchoRequest request;
EchoResponse response;
ClientContext context;
context.AddMetadata(kServerFinishAfterNReads, "3");
context.set_initial_metadata_corked(true);
grpc::string msg("hello");
auto stream = stub->BidiStream(&context);
request.set_message(msg + "0");
XCTAssertTrue(stream->Write(request));
XCTAssertTrue(stream->Read(&response));
XCTAssertEqual(response.message(), request.message());
request.set_message(msg + "1");
XCTAssertTrue(stream->Write(request));
XCTAssertTrue(stream->Read(&response));
XCTAssertEqual(response.message(), request.message());
request.set_message(msg + "2");
stream->WriteLast(request, grpc::WriteOptions());
XCTAssertTrue(stream->Read(&response));
XCTAssertEqual(response.message(), request.message());
XCTAssertFalse(stream->Read(&response));
XCTAssertFalse(stream->Read(&response));
Status s = stream->Finish();
XCTAssertTrue(s.ok());
}
- (void)testCancelBeforeStart {
auto stub = [self getStub];
EchoRequest request;
EchoResponse response;
ClientContext context;
request.set_message("hello");
context.TryCancel();
Status s = stub->Echo(&context, request, &response);
XCTAssertEqual("", response.message());
XCTAssertEqual(grpc::StatusCode::CANCELLED, s.error_code());
}
- (void)testClientCancelsRequestStream {
auto stub = [self getStub];
EchoRequest request;
EchoResponse response;
ClientContext context;
request.set_message("hello");
auto stream = stub->RequestStream(&context, &response);
XCTAssertTrue(stream->Write(request));
XCTAssertTrue(stream->Write(request));
context.TryCancel();
Status s = stream->Finish();
XCTAssertEqual(grpc::StatusCode::CANCELLED, s.error_code());
XCTAssertEqual(response.message(), "");
}
- (void)testClientCancelsResponseStream {
auto stub = [self getStub];
EchoRequest request;
EchoResponse response;
ClientContext context;
request.set_message("hello");
auto stream = stub->ResponseStream(&context, request);
XCTAssertTrue(stream->Read(&response));
XCTAssertEqual(response.message(), request.message() + "0");
XCTAssertTrue(stream->Read(&response));
XCTAssertEqual(response.message(), request.message() + "1");
context.TryCancel();
// The cancellation races with responses, so there might be zero or
// one responses pending, read till failure
if (stream->Read(&response)) {
XCTAssertEqual(response.message(), request.message() + "2");
// Since we have cancelled, we expect the next attempt to read to fail
XCTAssertFalse(stream->Read(&response));
}
}
- (void)testlClientCancelsBidiStream {
auto stub = [self getStub];
EchoRequest request;
EchoResponse response;
ClientContext context;
grpc::string msg("hello");
auto stream = stub->BidiStream(&context);
request.set_message(msg + "0");
XCTAssertTrue(stream->Write(request));
XCTAssertTrue(stream->Read(&response));
XCTAssertEqual(response.message(), request.message());
request.set_message(msg + "1");
XCTAssertTrue(stream->Write(request));
context.TryCancel();
// The cancellation races with responses, so there might be zero or
// one responses pending, read till failure
if (stream->Read(&response)) {
XCTAssertEqual(response.message(), request.message());
// Since we have cancelled, we expect the next attempt to read to fail
XCTAssertFalse(stream->Read(&response));
}
Status s = stream->Finish();
XCTAssertEqual(grpc::StatusCode::CANCELLED, s.error_code());
}
- (void)testNonExistingService {
auto channel = [self getChannel];
auto stub = grpc::testing::UnimplementedEchoService::NewStub(channel);
EchoRequest request;
EchoResponse response;
request.set_message("Hello");
ClientContext context;
Status s = stub->Unimplemented(&context, request, &response);
XCTAssertEqual(grpc::StatusCode::UNIMPLEMENTED, s.error_code());
XCTAssertEqual("", s.error_message());
}
- (void)testBinaryTrailer {
auto stub = [self getStub];
EchoRequest request;
EchoResponse response;
ClientContext context;
request.mutable_param()->set_echo_metadata(true);
DebugInfo* info = request.mutable_param()->mutable_debug_info();
info->add_stack_entries("stack_entry_1");
info->add_stack_entries("stack_entry_2");
info->add_stack_entries("stack_entry_3");
info->set_detail("detailed debug info");
grpc::string expected_string = info->SerializeAsString();
request.set_message("Hello");
Status s = stub->Echo(&context, request, &response);
XCTAssertFalse(s.ok());
auto trailers = context.GetServerTrailingMetadata();
XCTAssertEqual(1u, trailers.count(kDebugInfoTrailerKey));
auto iter = trailers.find(kDebugInfoTrailerKey);
XCTAssertEqual(expected_string, iter->second);
// Parse the returned trailer into a DebugInfo proto.
DebugInfo returned_info;
XCTAssertTrue(returned_info.ParseFromString(ToString(iter->second)));
}
- (void)testExpectError {
auto stub = [self getStub];
std::vector<ErrorStatus> expected_status;
expected_status.emplace_back();
expected_status.back().set_code(13); // INTERNAL
// No Error message or details
expected_status.emplace_back();
expected_status.back().set_code(13); // INTERNAL
expected_status.back().set_error_message("text error message");
expected_status.back().set_binary_error_details("text error details");
expected_status.emplace_back();
expected_status.back().set_code(13); // INTERNAL
expected_status.back().set_error_message("text error message");
expected_status.back().set_binary_error_details("\x0\x1\x2\x3\x4\x5\x6\x8\x9\xA\xB");
for (auto iter = expected_status.begin(); iter != expected_status.end(); ++iter) {
EchoRequest request;
EchoResponse response;
ClientContext context;
request.set_message("Hello");
auto* error = request.mutable_param()->mutable_expected_error();
error->set_code(iter->code());
error->set_error_message(iter->error_message());
error->set_binary_error_details(iter->binary_error_details());
Status s = stub->Echo(&context, request, &response);
XCTAssertFalse(s.ok());
XCTAssertEqual(iter->code(), s.error_code());
XCTAssertEqual(iter->error_message(), s.error_message());
XCTAssertEqual(iter->binary_error_details(), s.error_details());
XCTAssertTrue(context.debug_error_string().find("created") != std::string::npos);
XCTAssertTrue(context.debug_error_string().find("file") != std::string::npos);
XCTAssertTrue(context.debug_error_string().find("line") != std::string::npos);
XCTAssertTrue(context.debug_error_string().find("status") != std::string::npos);
XCTAssertTrue(context.debug_error_string().find("13") != std::string::npos);
}
}
- (void)testRpcDeadlineExpires {
auto stub = [self getStub];
EchoRequest request;
EchoResponse response;
request.set_message("Hello");
request.mutable_param()->set_skip_cancelled_check(true);
// Let server sleep for 40 ms first to guarantee expiry.
request.mutable_param()->set_server_sleep_us(40 * 1000);
ClientContext context;
std::chrono::system_clock::time_point deadline =
std::chrono::system_clock::now() + std::chrono::milliseconds(1);
context.set_deadline(deadline);
Status s = stub->Echo(&context, request, &response);
XCTAssertEqual(grpc::StatusCode::DEADLINE_EXCEEDED, s.error_code());
}
- (void)testRpcLongDeadline {
auto stub = [self getStub];
EchoRequest request;
EchoResponse response;
request.set_message("Hello");
ClientContext context;
std::chrono::system_clock::time_point deadline =
std::chrono::system_clock::now() + std::chrono::hours(1);
context.set_deadline(deadline);
Status s = stub->Echo(&context, request, &response);
XCTAssertEqual(response.message(), request.message());
XCTAssertTrue(s.ok());
}
- (void)testEchoDeadlineForNoDeadlineRpc {
auto stub = [self getStub];
EchoRequest request;
EchoResponse response;
request.set_message("Hello");
request.mutable_param()->set_echo_deadline(true);
ClientContext context;
Status s = stub->Echo(&context, request, &response);
XCTAssertEqual(response.message(), request.message());
XCTAssertTrue(s.ok());
XCTAssertEqual(response.param().request_deadline(), gpr_inf_future(GPR_CLOCK_REALTIME).tv_sec);
}
- (void)testPeer {
auto stub = [self getStub];
EchoRequest request;
EchoResponse response;
request.set_message("Hello");
ClientContext context;
Status s = stub->Echo(&context, request, &response);
XCTAssertTrue(s.ok());
XCTAssertTrue(CheckIsLocalhost(context.peer()));
}
- (void)testClientInterceptor {
DummyInterceptor::Reset();
std::vector<std::unique_ptr<grpc::experimental::ClientInterceptorFactoryInterface>> creators;
// Add 20 dummy interceptors
for (auto i = 0; i < 20; i++) {
creators.push_back(std::unique_ptr<DummyInterceptorFactory>(new DummyInterceptorFactory()));
}
auto channel = [self getChannelWithInterceptors:std::move(creators)];
auto stub = EchoTestService::NewStub(channel);
EchoRequest request;
EchoResponse response;
ClientContext context;
request.set_message("Hello");
Status s = stub->Echo(&context, request, &response);
XCTAssertTrue(s.ok());
XCTAssertEqual(DummyInterceptor::GetNumTimesRun(), 20);
}
@end

@ -0,0 +1,81 @@
/*
*
* Copyright 2019 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 TESTHELPER_H
#define TESTHELPER_H
#import <XCTest/XCTest.h>
#import <map>
#import <sstream>
#import <grpc/support/time.h>
#import <grpcpp/impl/codegen/config.h>
#import <grpcpp/impl/codegen/string_ref.h>
#import <grpcpp/support/client_interceptor.h>
#import <src/proto/grpc/testing/echo.grpc.pb.h>
const char* const kServerFinishAfterNReads = "server_finish_after_n_reads";
const char* const kServerResponseStreamsToSend = "server_responses_to_send";
const int kServerDefaultResponseStreamsToSend = 3;
const char* const kDebugInfoTrailerKey = "debug-info-bin";
grpc::string ToString(const grpc::string_ref& r);
void configureCronet(void);
bool CheckIsLocalhost(const grpc::string& addr);
class DummyInterceptor : public grpc::experimental::Interceptor {
public:
DummyInterceptor() {}
virtual void Intercept(grpc::experimental::InterceptorBatchMethods* methods);
static void Reset();
static int GetNumTimesRun();
private:
static std::atomic<int> num_times_run_;
static std::atomic<int> num_times_run_reverse_;
};
class DummyInterceptorFactory
: public grpc::experimental::ClientInterceptorFactoryInterface {
public:
virtual grpc::experimental::Interceptor* CreateClientInterceptor(
grpc::experimental::ClientRpcInfo* info) override {
return new DummyInterceptor();
}
};
class TestServiceImpl : public grpc::testing::EchoTestService::Service {
public:
grpc::Status Echo(grpc::ServerContext* context,
const grpc::testing::EchoRequest* request,
grpc::testing::EchoResponse* response);
grpc::Status RequestStream(
grpc::ServerContext* context,
grpc::ServerReader<grpc::testing::EchoRequest>* reader,
grpc::testing::EchoResponse* response);
grpc::Status ResponseStream(
grpc::ServerContext* context, const grpc::testing::EchoRequest* request,
grpc::ServerWriter<grpc::testing::EchoResponse>* writer);
grpc::Status BidiStream(
grpc::ServerContext* context,
grpc::ServerReaderWriter<grpc::testing::EchoResponse,
grpc::testing::EchoRequest>* stream);
};
#endif /* TESTHELPER_H */

@ -0,0 +1,198 @@
/*
*
* Copyright 2019 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 "TestHelper.h"
#import <Cronet/Cronet.h>
#import <grpcpp/impl/codegen/config.h>
#import <grpcpp/impl/codegen/string_ref.h>
using std::chrono::system_clock;
using grpc::testing::EchoRequest;
using grpc::testing::EchoResponse;
using grpc::testing::EchoTestService;
using grpc::ServerContext;
using grpc::Status;
std::atomic<int> DummyInterceptor::num_times_run_;
std::atomic<int> DummyInterceptor::num_times_run_reverse_;
grpc::string ToString(const grpc::string_ref& r) { return grpc::string(r.data(), r.size()); }
void configureCronet(void) {
static dispatch_once_t configureCronet;
dispatch_once(&configureCronet, ^{
[Cronet setHttp2Enabled:YES];
[Cronet setSslKeyLogFileName:@"Documents/key"];
[Cronet enableTestCertVerifierForTesting];
NSURL* url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] lastObject];
[Cronet start];
[Cronet startNetLogToFile:@"cronet_netlog.json" logBytes:YES];
});
}
bool CheckIsLocalhost(const grpc::string& addr) {
const grpc::string kIpv6("[::1]:");
const grpc::string kIpv4MappedIpv6("[::ffff:127.0.0.1]:");
const grpc::string kIpv4("127.0.0.1:");
return addr.substr(0, kIpv4.size()) == kIpv4 ||
addr.substr(0, kIpv4MappedIpv6.size()) == kIpv4MappedIpv6 ||
addr.substr(0, kIpv6.size()) == kIpv6;
}
int GetIntValueFromMetadataHelper(const char* key,
const std::multimap<grpc::string_ref, grpc::string_ref>& metadata,
int default_value) {
if (metadata.find(key) != metadata.end()) {
std::istringstream iss(ToString(metadata.find(key)->second));
iss >> default_value;
}
return default_value;
}
int GetIntValueFromMetadata(const char* key,
const std::multimap<grpc::string_ref, grpc::string_ref>& metadata,
int default_value) {
return GetIntValueFromMetadataHelper(key, metadata, default_value);
}
// When echo_deadline is requested, deadline seen in the ServerContext is set in
// the response in seconds.
void MaybeEchoDeadline(ServerContext* context, const EchoRequest* request, EchoResponse* response) {
if (request->has_param() && request->param().echo_deadline()) {
gpr_timespec deadline = gpr_inf_future(GPR_CLOCK_REALTIME);
if (context->deadline() != system_clock::time_point::max()) {
grpc::Timepoint2Timespec(context->deadline(), &deadline);
}
response->mutable_param()->set_request_deadline(deadline.tv_sec);
}
}
Status TestServiceImpl::Echo(ServerContext* context, const EchoRequest* request,
EchoResponse* response) {
// A bit of sleep to make sure that short deadline tests fail
if (request->has_param() && request->param().server_sleep_us() > 0) {
gpr_sleep_until(
gpr_time_add(gpr_now(GPR_CLOCK_MONOTONIC),
gpr_time_from_micros(request->param().server_sleep_us(), GPR_TIMESPAN)));
}
if (request->has_param() && request->param().has_expected_error()) {
const auto& error = request->param().expected_error();
return Status(static_cast<grpc::StatusCode>(error.code()), error.error_message(),
error.binary_error_details());
}
if (request->has_param() && request->param().echo_metadata()) {
const std::multimap<grpc::string_ref, grpc::string_ref>& client_metadata =
context->client_metadata();
for (std::multimap<grpc::string_ref, grpc::string_ref>::const_iterator iter =
client_metadata.begin();
iter != client_metadata.end(); ++iter) {
context->AddTrailingMetadata(ToString(iter->first), ToString(iter->second));
}
// Terminate rpc with error and debug info in trailer.
if (request->param().debug_info().stack_entries_size() ||
!request->param().debug_info().detail().empty()) {
grpc::string serialized_debug_info = request->param().debug_info().SerializeAsString();
context->AddTrailingMetadata(kDebugInfoTrailerKey, serialized_debug_info);
return Status::CANCELLED;
}
}
response->set_message(request->message());
MaybeEchoDeadline(context, request, response);
return Status::OK;
}
Status TestServiceImpl::RequestStream(ServerContext* context,
grpc::ServerReader<EchoRequest>* reader,
EchoResponse* response) {
EchoRequest request;
response->set_message("");
int num_msgs_read = 0;
while (reader->Read(&request)) {
response->mutable_message()->append(request.message());
++num_msgs_read;
}
return Status::OK;
}
Status TestServiceImpl::ResponseStream(ServerContext* context, const EchoRequest* request,
grpc::ServerWriter<EchoResponse>* writer) {
EchoResponse response;
int server_responses_to_send =
GetIntValueFromMetadata(kServerResponseStreamsToSend, context->client_metadata(),
kServerDefaultResponseStreamsToSend);
for (int i = 0; i < server_responses_to_send; i++) {
response.set_message(request->message() + grpc::to_string(i));
if (i == server_responses_to_send - 1) {
writer->WriteLast(response, grpc::WriteOptions());
} else {
writer->Write(response);
}
}
return Status::OK;
}
Status TestServiceImpl::BidiStream(ServerContext* context,
grpc::ServerReaderWriter<EchoResponse, EchoRequest>* stream) {
EchoRequest request;
EchoResponse response;
// kServerFinishAfterNReads suggests after how many reads, the server should
// write the last message and send status (coalesced using WriteLast)
int server_write_last =
GetIntValueFromMetadata(kServerFinishAfterNReads, context->client_metadata(), 0);
int read_counts = 0;
while (stream->Read(&request)) {
read_counts++;
response.set_message(request.message());
if (read_counts == server_write_last) {
stream->WriteLast(response, grpc::WriteOptions());
} else {
stream->Write(response);
}
}
return Status::OK;
}
void DummyInterceptor::Intercept(grpc::experimental::InterceptorBatchMethods* methods) {
if (methods->QueryInterceptionHookPoint(
grpc::experimental::InterceptionHookPoints::PRE_SEND_INITIAL_METADATA)) {
num_times_run_++;
} else if (methods->QueryInterceptionHookPoint(
grpc::experimental::InterceptionHookPoints::POST_RECV_INITIAL_METADATA)) {
num_times_run_reverse_++;
}
methods->Proceed();
}
void DummyInterceptor::Reset() {
num_times_run_.store(0);
num_times_run_reverse_.store(0);
}
int DummyInterceptor::GetNumTimesRun() {
NSCAssert(num_times_run_.load() == num_times_run_reverse_.load(),
@"Interceptor must run same number of times in both directions");
return num_times_run_.load();
}

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>gRPC.$(PRODUCT_NAME:rfc1034identifier)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

@ -0,0 +1,102 @@
source 'https://github.com/CocoaPods/Specs.git'
install! 'cocoapods', :deterministic_uuids => false
# Location of gRPC's repo root relative to this file.
GRPC_LOCAL_SRC = '../../..'
target 'CronetTests' do
platform :ios, '8.0'
pod 'Protobuf', :path => "#{GRPC_LOCAL_SRC}/third_party/protobuf", :inhibit_warnings => true
pod '!ProtoCompiler', :path => "#{GRPC_LOCAL_SRC}/src/objective-c"
pod '!ProtoCompiler-gRPCCppPlugin', :path => "#{GRPC_LOCAL_SRC}/src/objective-c"
pod 'Protobuf-C++', :podspec => "#{GRPC_LOCAL_SRC}/src/cpp", :inhibit_warnings => true
pod 'BoringSSL-GRPC', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c", :inhibit_warnings => true
pod 'gRPC-Core', :path => GRPC_LOCAL_SRC
pod 'gRPC-C++', :path => GRPC_LOCAL_SRC
pod 'gRPC-C++/Protobuf', :path => GRPC_LOCAL_SRC
pod 'RemoteTestCpp', :path => "RemoteTestClientCpp", :inhibit_warnings => true
pod 'gRPC-Core/Cronet-Implementation', :path => GRPC_LOCAL_SRC
pod 'CronetFramework', :podspec => "#{GRPC_LOCAL_SRC}/src/objective-c"
pod 'gRPC-Core/Tests', :path => GRPC_LOCAL_SRC, :inhibit_warnings => true
end
# gRPC-Core.podspec needs to be modified to be successfully used for local development. A Podfile's
# pre_install hook lets us do that. The block passed to it runs after the podspecs are downloaded
# and before they are installed in the user project.
#
# This podspec searches for the gRPC core library headers under "$(PODS_ROOT)/gRPC-Core", where
# Cocoapods normally places the downloaded sources. When doing local development of the libraries,
# though, Cocoapods just takes the sources from whatever directory was specified using `:path`, and
# doesn't copy them under $(PODS_ROOT). When using static libraries, one can sometimes rely on the
# symbolic links to the pods headers that Cocoapods creates under "$(PODS_ROOT)/Headers". But those
# aren't created when using dynamic frameworks. So our solution is to modify the podspec on the fly
# to point at the local directory where the sources are.
#
# TODO(jcanizales): Send a PR to Cocoapods to get rid of this need.
pre_install do |installer|
# This is the gRPC-Core podspec object, as initialized by its podspec file.
grpc_core_spec = installer.pod_targets.find{|t| t.name.start_with?('gRPC-Core')}.root_spec
# Copied from gRPC-Core.podspec, except for the adjusted src_root:
src_root = "$(PODS_ROOT)/../#{GRPC_LOCAL_SRC}"
grpc_core_spec.pod_target_xcconfig = {
'GRPC_SRC_ROOT' => src_root,
'HEADER_SEARCH_PATHS' => '"$(inherited)" "$(GRPC_SRC_ROOT)/include"',
'USER_HEADER_SEARCH_PATHS' => '"$(GRPC_SRC_ROOT)"',
# If we don't set these two settings, `include/grpc/support/time.h` and
# `src/core/lib/gpr/string.h` shadow the system `<time.h>` and `<string.h>`, breaking the
# build.
'USE_HEADERMAP' => 'NO',
'ALWAYS_SEARCH_USER_PATHS' => 'NO',
}
end
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['GCC_TREAT_WARNINGS_AS_ERRORS'] = 'YES'
end
# CocoaPods creates duplicated library targets of gRPC-Core when the test targets include
# non-default subspecs of gRPC-Core. All of these library targets start with prefix 'gRPC-Core'
# and require the same error suppresion.
if target.name.start_with?('gRPC-Core')
target.build_configurations.each do |config|
# TODO(zyc): Remove this setting after the issue is resolved
# GPR_UNREACHABLE_CODE causes "Control may reach end of non-void
# function" warning
config.build_settings['GCC_WARN_ABOUT_RETURN_TYPE'] = 'NO'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = '$(inherited) COCOAPODS=1 GRPC_CRONET_WITH_PACKET_COALESCING=1 GRPC_CFSTREAM=1'
end
end
# Activate Cronet for the dedicated build configuration 'Cronet', which will be used solely by
# the test target 'InteropTestsRemoteWithCronet'
# Activate GRPCCall+InternalTests functions for the dedicated build configuration 'Test', which will
# be used by all test targets using it.
if /gRPC-(mac|i)OS/.match(target.name)
target.build_configurations.each do |config|
if config.name == 'Cronet'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = '$(inherited) COCOAPODS=1 GRPC_COMPILE_WITH_CRONET=1 GRPC_TEST_OBJC=1'
elsif config.name == 'Test'
config.build_settings['GCC_PREPROCESSOR_DEFINITIONS'] = '$(inherited) COCOAPODS=1 GRPC_TEST_OBJC=1'
end
end
end
# Enable NSAssert on gRPC
if /(gRPC|ProtoRPC|RxLibrary)-(mac|i)OS/.match(target.name)
target.build_configurations.each do |config|
if config.name != 'Release'
config.build_settings['ENABLE_NS_ASSERTIONS'] = 'YES'
end
end
end
end
end

@ -0,0 +1,98 @@
Pod::Spec.new do |s|
s.name = "RemoteTestCpp"
s.version = "0.0.1"
s.license = "Apache License, Version 2.0"
s.authors = { 'gRPC contributors' => 'grpc-io@googlegroups.com' }
s.homepage = "https://grpc.io/"
s.summary = "RemoteTest example"
s.source = { :git => 'https://github.com/grpc/grpc.git' }
s.ios.deployment_target = '7.1'
s.osx.deployment_target = '10.9'
# Run protoc with the C++ and gRPC plugins to generate protocol messages and gRPC clients.
s.dependency "!ProtoCompiler-gRPCCppPlugin"
s.dependency "Protobuf-C++"
s.dependency "gRPC-C++"
s.source_files = "src/proto/grpc/testing/*.pb.{h,cc}"
s.header_mappings_dir = "RemoteTestCpp"
s.requires_arc = false
repo_root = '../../../..'
config = ENV['CONFIG'] || 'opt'
bin_dir = "#{repo_root}/bins/#{config}"
protoc = "#{bin_dir}/protobuf/protoc"
well_known_types_dir = "#{repo_root}/third_party/protobuf/src"
plugin = "#{bin_dir}/grpc_cpp_plugin"
proto_dir = "#{repo_root}/src/proto/grpc/testing"
s.prepare_command = <<-CMD
if [ -f #{protoc} ]; then
#{protoc} \
--plugin=protoc-gen-grpc=#{plugin} \
--cpp_out=. \
--grpc_out=. \
-I #{repo_root} \
-I #{proto_dir} \
-I #{well_known_types_dir} \
#{proto_dir}/echo.proto
#{protoc} \
--plugin=protoc-gen-grpc=#{plugin} \
--cpp_out=. \
--grpc_out=. \
-I #{repo_root} \
-I #{proto_dir} \
-I #{well_known_types_dir} \
#{proto_dir}/echo_messages.proto
#{protoc} \
--plugin=protoc-gen-grpc=#{plugin} \
--cpp_out=. \
--grpc_out=. \
-I #{repo_root} \
-I #{proto_dir} \
-I #{well_known_types_dir} \
#{proto_dir}/simple_messages.proto
else
# protoc was not found bin_dir, use installed version instead
if ! [ -x "$(command -v protoc)" ]; then
(>&2 echo "\nERROR: protoc not found")
exit 1
fi
(>&2 echo "\nWARNING: Using installed version of protoc. It might be incompatible with gRPC")
protoc \
--plugin=protoc-gen-grpc=#{plugin} \
--cpp_out=. \
--grpc_out=. \
-I #{repo_root} \
-I #{proto_dir} \
-I #{well_known_types_dir} \
#{proto_dir}/echo.proto
protoc \
--plugin=protoc-gen-grpc=#{plugin} \
--cpp_out=. \
--grpc_out=. \
-I #{repo_root} \
-I #{proto_dir} \
-I #{well_known_types_dir} \
#{proto_dir}/echo_messages.proto
protoc \
--plugin=protoc-gen-grpc=#{plugin} \
--cpp_out=. \
--grpc_out=. \
-I #{repo_root} \
-I #{proto_dir} \
-I #{well_known_types_dir} \
#{proto_dir}/simple_messages.proto
fi
CMD
s.pod_target_xcconfig = {
# This is needed by all pods that depend on Protobuf:
'GCC_PREPROCESSOR_DEFINITIONS' => '$(inherited) GPB_USE_PROTOBUF_FRAMEWORK_IMPORTS=1 GPB_GRPC_FORWARD_DECLARE_MESSAGE_PROTO=1',
# This is needed by all pods that depend on gRPC-RxLibrary:
'CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES' => 'YES',
}
end

@ -0,0 +1,594 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
B02C351522E8E5FE00708B55 /* TestHelper.mm in Sources */ = {isa = PBXBuildFile; fileRef = B02C351322E8E5FE00708B55 /* TestHelper.mm */; };
B0B151E622D7DFCA00C4BFE0 /* CppCronetEnd2EndTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = B0B151E522D7DFCA00C4BFE0 /* CppCronetEnd2EndTests.mm */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
00DA7762CD572056A66501B3 /* Pods-CronetTests.cronet.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CronetTests.cronet.xcconfig"; path = "Pods/Target Support Files/Pods-CronetTests/Pods-CronetTests.cronet.xcconfig"; sourceTree = "<group>"; };
5E7F485922775B15006656AD /* CronetTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CronetTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
5E7F486622776AD8006656AD /* Cronet.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cronet.framework; path = Pods/CronetFramework/Cronet.framework; sourceTree = "<group>"; };
635697D81B14FC11007A7283 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
7B0DE0EC5EB517A302CD4698 /* Pods-CronetTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CronetTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-CronetTests/Pods-CronetTests.release.xcconfig"; sourceTree = "<group>"; };
B02C351322E8E5FE00708B55 /* TestHelper.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = TestHelper.mm; sourceTree = "<group>"; };
B02C351422E8E5FE00708B55 /* TestHelper.h */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; path = TestHelper.h; sourceTree = "<group>"; };
B0B151E522D7DFCA00C4BFE0 /* CppCronetEnd2EndTests.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; path = CppCronetEnd2EndTests.mm; sourceTree = "<group>"; };
CDB4E9D8890B97B6FAF35A4F /* Pods-CronetTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CronetTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-CronetTests/Pods-CronetTests.debug.xcconfig"; sourceTree = "<group>"; };
ED8BB10304E81C38CAE911C2 /* Pods-CronetTests.test.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-CronetTests.test.xcconfig"; path = "Pods/Target Support Files/Pods-CronetTests/Pods-CronetTests.test.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
5E7F485622775B15006656AD /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
136D535E19727099B941D7B1 /* Frameworks */ = {
isa = PBXGroup;
children = (
5E7F486622776AD8006656AD /* Cronet.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
51E4650F34F854F41FF053B3 /* Pods */ = {
isa = PBXGroup;
children = (
CDB4E9D8890B97B6FAF35A4F /* Pods-CronetTests.debug.xcconfig */,
ED8BB10304E81C38CAE911C2 /* Pods-CronetTests.test.xcconfig */,
00DA7762CD572056A66501B3 /* Pods-CronetTests.cronet.xcconfig */,
7B0DE0EC5EB517A302CD4698 /* Pods-CronetTests.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
5E7F485A22775B15006656AD /* CronetTests */ = {
isa = PBXGroup;
children = (
B0B151E522D7DFCA00C4BFE0 /* CppCronetEnd2EndTests.mm */,
B02C351322E8E5FE00708B55 /* TestHelper.mm */,
B02C351422E8E5FE00708B55 /* TestHelper.h */,
);
path = CronetTests;
sourceTree = "<group>";
};
635697BE1B14FC11007A7283 = {
isa = PBXGroup;
children = (
635697C91B14FC11007A7283 /* Tests */,
5E7F485A22775B15006656AD /* CronetTests */,
635697C81B14FC11007A7283 /* Products */,
51E4650F34F854F41FF053B3 /* Pods */,
136D535E19727099B941D7B1 /* Frameworks */,
);
sourceTree = "<group>";
};
635697C81B14FC11007A7283 /* Products */ = {
isa = PBXGroup;
children = (
5E7F485922775B15006656AD /* CronetTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
635697C91B14FC11007A7283 /* Tests */ = {
isa = PBXGroup;
children = (
635697D71B14FC11007A7283 /* Supporting Files */,
);
name = Tests;
sourceTree = SOURCE_ROOT;
};
635697D71B14FC11007A7283 /* Supporting Files */ = {
isa = PBXGroup;
children = (
635697D81B14FC11007A7283 /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
5E7F485822775B15006656AD /* CronetTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 5E7F485E22775B15006656AD /* Build configuration list for PBXNativeTarget "CronetTests" */;
buildPhases = (
CCAEC0F23E05489651A07D53 /* [CP] Check Pods Manifest.lock */,
5E7F485522775B15006656AD /* Sources */,
5E7F485622775B15006656AD /* Frameworks */,
5E7F485722775B15006656AD /* Resources */,
292EA42A76AC7933A37235FD /* [CP] Embed Pods Frameworks */,
30AFD6F6FC40B9923632A866 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
);
name = CronetTests;
productName = CronetTests;
productReference = 5E7F485922775B15006656AD /* CronetTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
635697BF1B14FC11007A7283 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0630;
ORGANIZATIONNAME = gRPC;
TargetAttributes = {
5E7F485822775B15006656AD = {
CreatedOnToolsVersion = 10.1;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = 635697C21B14FC11007A7283 /* Build configuration list for PBXProject "Tests" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
English,
en,
);
mainGroup = 635697BE1B14FC11007A7283;
productRefGroup = 635697C81B14FC11007A7283 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
5E7F485822775B15006656AD /* CronetTests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
5E7F485722775B15006656AD /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
292EA42A76AC7933A37235FD /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-CronetTests/Pods-CronetTests-frameworks.sh",
"${PODS_ROOT}/CronetFramework/Cronet.framework",
);
name = "[CP] Embed Pods Frameworks";
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Cronet.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CronetTests/Pods-CronetTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
30AFD6F6FC40B9923632A866 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-CronetTests/Pods-CronetTests-resources.sh",
"${PODS_CONFIGURATION_BUILD_DIR}/gRPC-C++/gRPCCertificates-Cpp.bundle",
);
name = "[CP] Copy Pods Resources";
outputPaths = (
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/gRPCCertificates-Cpp.bundle",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-CronetTests/Pods-CronetTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
CCAEC0F23E05489651A07D53 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-CronetTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
5E7F485522775B15006656AD /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
B0B151E622D7DFCA00C4BFE0 /* CppCronetEnd2EndTests.mm in Sources */,
B02C351522E8E5FE00708B55 /* TestHelper.mm in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
5E1228981E4D400F00E8504F /* Test */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
"GRPC_TEST_OBJC=1",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
name = Test;
};
5E7F485F22775B15006656AD /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = CDB4E9D8890B97B6FAF35A4F /* Pods-CronetTests.debug.xcconfig */;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_TESTABILITY = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Pods/CronetFramework",
);
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_WARN_INHIBIT_ALL_WARNINGS = YES;
INFOPLIST_FILE = Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CronetTests;
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
USER_HEADER_SEARCH_PATHS = ../../..;
};
name = Debug;
};
5E7F486022775B15006656AD /* Test */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = ED8BB10304E81C38CAE911C2 /* Pods-CronetTests.test.xcconfig */;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Pods/CronetFramework",
);
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_WARN_INHIBIT_ALL_WARNINGS = YES;
INFOPLIST_FILE = Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CronetTests;
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
USER_HEADER_SEARCH_PATHS = ../../..;
};
name = Test;
};
5E7F486122775B15006656AD /* Cronet */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 00DA7762CD572056A66501B3 /* Pods-CronetTests.cronet.xcconfig */;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Pods/CronetFramework",
);
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_WARN_INHIBIT_ALL_WARNINGS = YES;
INFOPLIST_FILE = Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CronetTests;
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
USER_HEADER_SEARCH_PATHS = ../../..;
};
name = Cronet;
};
5E7F486222775B15006656AD /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 7B0DE0EC5EB517A302CD4698 /* Pods-CronetTests.release.xcconfig */;
buildSettings = {
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PROJECT_DIR)/Pods/CronetFramework",
);
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_WARN_INHIBIT_ALL_WARNINGS = YES;
INFOPLIST_FILE = Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = io.grpc.CronetTests;
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
USER_HEADER_SEARCH_PATHS = ../../..;
};
name = Release;
};
5EC3C7A01D4FC18C000330E2 /* Cronet */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
"GRPC_TEST_OBJC=1",
"GRPC_COMPILE_WITH_CRONET=1",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
name = Cronet;
};
635697D91B14FC11007A7283 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
name = Debug;
};
635697DA1B14FC11007A7283 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_NO_COMMON_BLOCKS = YES;
GCC_TREAT_WARNINGS_AS_ERRORS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.3;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
5E7F485E22775B15006656AD /* Build configuration list for PBXNativeTarget "CronetTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
5E7F485F22775B15006656AD /* Debug */,
5E7F486022775B15006656AD /* Test */,
5E7F486122775B15006656AD /* Cronet */,
5E7F486222775B15006656AD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
635697C21B14FC11007A7283 /* Build configuration list for PBXProject "Tests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
635697D91B14FC11007A7283 /* Debug */,
5E1228981E4D400F00E8504F /* Test */,
5EC3C7A01D4FC18C000330E2 /* Cronet */,
635697DA1B14FC11007A7283 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 635697BF1B14FC11007A7283 /* Project object */;
}

@ -0,0 +1,95 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1010"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5E7F485822775B15006656AD"
BuildableName = "CronetTests.xctest"
BlueprintName = "CronetTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Cronet"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5E7F485822775B15006656AD"
BuildableName = "CronetTests.xctest"
BlueprintName = "CronetTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
<SkippedTests>
<Test
Identifier = "InteropTests">
</Test>
</SkippedTests>
</TestableReference>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Cronet"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5E7F485822775B15006656AD"
BuildableName = "CronetTests.xctest"
BlueprintName = "CronetTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Cronet"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "5E7F485822775B15006656AD"
BuildableName = "CronetTests.xctest"
BlueprintName = "CronetTests"
ReferencedContainer = "container:Tests.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Cronet">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

@ -0,0 +1,40 @@
#!/bin/bash
# Copyright 2019 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.
# Don't run this script standalone. Instead, run from the repository root:
# ./tools/run_tests/run_tests.py -l objc
set -e
# CocoaPods requires the terminal to be using UTF-8 encoding.
export LANG=en_US.UTF-8
cd "$(dirname "$0")"
hash pod 2>/dev/null || { echo >&2 "Cocoapods needs to be installed."; exit 1; }
hash xcodebuild 2>/dev/null || {
echo >&2 "XCode command-line tools need to be installed."
exit 1
}
# clean the directory
rm -rf Pods
rm -rf Tests.xcworkspace
rm -f Podfile.lock
rm -rf RemoteTestClientCpp/src
echo "TIME: $(date)"
pod install

@ -0,0 +1,34 @@
#!/bin/bash
# Copyright 2019 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.
# Don't run this script standalone. Instead, run from the repository root:
# ./tools/run_tests/run_tests.py -l c++
set -ev
cd "$(dirname "$0")"
set -o pipefail
XCODEBUILD_FILTER='(^CompileC |^Ld |^ *[^ ]*clang |^ *cd |^ *export |^Libtool |^ *[^ ]*libtool |^CpHeader |^ *builtin-copy )'
xcodebuild \
-workspace Tests.xcworkspace \
-scheme CronetTests \
-destination name="iPhone 8" \
test \
| egrep -v "$XCODEBUILD_FILTER" \
| egrep -v '^$' -

@ -0,0 +1,31 @@
# Copyright 2019 The 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.
# Config file for the internal CI (in protobuf text format)
# Location of the continuous shell script in repository.
build_file: "grpc/tools/internal_ci/macos/grpc_run_tests_matrix.sh"
gfile_resources: "/bigstore/grpc-testing-secrets/gcp_credentials/GrpcTesting-d0eeee2db331.json"
timeout_mins: 120
action {
define_artifacts {
regex: "**/*sponge_log.*"
regex: "github/grpc/reports/**"
}
}
env_vars {
key: "RUN_TESTS_FLAGS"
value: "-f basictests macos objc opt --internal_ci -j 1 --inner_jobs 4 --bq_result_table aggregate_results --extra_args -r ios-cpp-test-.*"
}

@ -1130,6 +1130,13 @@ class ObjCLanguage(object):
environ={
'SCHEME': 'CronetTests'
}))
out.append(
self.config.job_spec(
['test/cpp/ios/run_tests.sh'],
timeout_seconds=20 * 60,
shortname='ios-cpp-test-cronet',
cpu_cost=1e6,
environ=_FORCE_ENVIRON_FOR_WRAPPERS))
out.append(
self.config.job_spec(
['src/objective-c/tests/run_one_test.sh'],
@ -1156,6 +1163,7 @@ class ObjCLanguage(object):
return [
['src/objective-c/tests/build_tests.sh'],
['test/core/iomgr/ios/CFStreamTests/build_tests.sh'],
['test/cpp/ios/build_tests.sh'],
]
def post_tests_steps(self):

Loading…
Cancel
Save