mirror of https://github.com/grpc/grpc.git
commit
f44f0bc592
70 changed files with 1263 additions and 184 deletions
@ -0,0 +1,28 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* Copyright 2018 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_GPR_ALLOC_H |
||||||
|
#define GRPC_CORE_LIB_GPR_ALLOC_H |
||||||
|
|
||||||
|
#include <grpc/support/port_platform.h> |
||||||
|
|
||||||
|
/// Given a size, round up to the next multiple of sizeof(void*).
|
||||||
|
#define GPR_ROUND_UP_TO_ALIGNMENT_SIZE(x) \ |
||||||
|
(((x) + GPR_MAX_ALIGNMENT - 1u) & ~(GPR_MAX_ALIGNMENT - 1u)) |
||||||
|
|
||||||
|
#endif /* GRPC_CORE_LIB_GPR_ALLOC_H */ |
@ -0,0 +1,92 @@ |
|||||||
|
|
||||||
|
# gRPC iOS Network Transition Behaviors |
||||||
|
Network connectivity on an iOS device may transition between cellular, WIFI, or |
||||||
|
no network connectivity. This document describes how these network changes |
||||||
|
should be handled by gRPC and current known issues. |
||||||
|
|
||||||
|
## Expected Network Transition Behaviors |
||||||
|
The expected gRPC iOS channel and network transition behaviors are: |
||||||
|
* Channel connection to a particular host is established at the time of |
||||||
|
starting the first call to the channel and remains connected for future calls |
||||||
|
to the same host. |
||||||
|
* If the underlying connection to the remote host is broken, the channel is |
||||||
|
disconnected and enters TRANSIENT\_FAILURE state. |
||||||
|
* A channel is broken if the channel connection is no longer viable. This |
||||||
|
happens when |
||||||
|
* The network interface is no longer available, e.g. WiFi or cellular |
||||||
|
interface is turned off or goes offline, airplane mode turned on, etc; |
||||||
|
* The underlying TCP connection is no longer valid, e.g. WiFi connects to |
||||||
|
another hotspot, cellular data switched from LTE to 4G, etc; |
||||||
|
* A network interface more preferable by the OS is valid, e.g. WiFi gets |
||||||
|
connected when the channel is already connected via cellular. |
||||||
|
* A channel in TRANSIENT\_FAILURE state attempts reconnection on start of the |
||||||
|
next call to the same host, but only after a certain backoff period (see |
||||||
|
corresponding |
||||||
|
[doc](https://github.com/grpc/grpc/blob/master/doc/connection-backoff.md)). |
||||||
|
During the backoff period, any call to the same host will wait until the |
||||||
|
first of the following events occur: |
||||||
|
* Connection succeeded; calls will be made using this channel; |
||||||
|
* Conncetion failed; calls will be failed and return UNAVAILABLE status code; |
||||||
|
* The call's deadline is reached; the call will fail and return |
||||||
|
DEADLINE\_EXCEEDED status code. |
||||||
|
The length of backoff period of a channel is reset whenever a connection |
||||||
|
attempt is successful. |
||||||
|
|
||||||
|
## Implementations |
||||||
|
### gRPC iOS with TCP Sockets |
||||||
|
gRPC's default implementation is to use TCP sockets for networking. It turns |
||||||
|
out that although Apple supports this type of usage, it is [not recommended by |
||||||
|
Apple](https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/SocketsAndStreams/SocketsAndStreams.html) |
||||||
|
and has some issues described below. |
||||||
|
|
||||||
|
#### Issues with TCP Sockets |
||||||
|
The TCP sockets on iOS is flawed in that it does not reflect the viability of |
||||||
|
the channel connection. Particularly, we observed the following issues when |
||||||
|
using TCP sockets: |
||||||
|
* When a TCP socket connection is established on cellular data and WiFi |
||||||
|
becomes available, the TCP socket neither return an error event nor continue |
||||||
|
sending/receiving data on it, but still accepts write on it. |
||||||
|
* A TCP socket does not report certain events that happen in the |
||||||
|
background. When a TCP connection breaks in the background for the reason |
||||||
|
like WiFi connects to another hotspot, the socket neither return an error nor |
||||||
|
continue sending/receiving data on it, but still accepts write on it. |
||||||
|
In both situations, the user will see the call hang for an extended period of |
||||||
|
time before the TCP socket times out. |
||||||
|
|
||||||
|
#### gRPC iOS library's resolution to TCP socket issues |
||||||
|
We introduced |
||||||
|
[`ConnectivityMonitor`](https://developer.apple.com/library/archive/documentation/NetworkingInternetWeb/Conceptual/NetworkingOverview/SocketsAndStreams/SocketsAndStreams.html) |
||||||
|
in gRPC iOS library v0.14.0 to alleviate these issues in TCP sockets, |
||||||
|
which changes the network transition behaviors a bit. |
||||||
|
|
||||||
|
We classify network connectivity state of the device into three categories |
||||||
|
based on flags obtained from `SCNetworkReachability` API: |
||||||
|
|
||||||
|
| Reachable | ConnectionRequired | IsWWAN | **Category** | |
||||||
|
|:---------:|:------------------:|:------:|:------------:| |
||||||
|
| 0 | X | X | None | |
||||||
|
| X | 1 | X | None | |
||||||
|
| 1 | 0 | 0 | WiFi | |
||||||
|
| 1 | 0 | 1 | Cellular | |
||||||
|
|
||||||
|
Whenever there is a transition of network between two of these categories, all |
||||||
|
previously existing channels are assumed to be broken and are actively |
||||||
|
destroyed. If there is an unfinished call, the call should return with status |
||||||
|
code `UNAVAILABLE`. |
||||||
|
|
||||||
|
`ConnectivityMonitor` is able to detect the scenario of the first issue above |
||||||
|
and actively destroy the channels. However, the second issue is not resolvable. |
||||||
|
To solve that issue the best solution is to switch to CFStream implementation |
||||||
|
which eliminates all of them. |
||||||
|
|
||||||
|
### gRPC iOS with CFStream |
||||||
|
gRPC iOS with CFStream implementation (introduced in v1.13.0) uses Apple's |
||||||
|
networking API to make connections. It resolves the issues with TCP sockets |
||||||
|
mentioned above. Users are recommended to use this implementation rather than |
||||||
|
TCP socket implementation. The detailed behavior of streams in CFStream is not |
||||||
|
documented by Apple, but our experiments show that it accords to the expected |
||||||
|
behaviors. With CFStream implementation, an event is always received when the |
||||||
|
underlying connection is no longer viable. For more detailed information and |
||||||
|
usages of CFStream implementation, refer to the |
||||||
|
[user guide](https://github.com/grpc/grpc/blob/master/src/objective-c/README-CFSTREAM.md). |
||||||
|
|
@ -0,0 +1,32 @@ |
|||||||
|
[![Cocoapods](https://img.shields.io/cocoapods/v/gRPC.svg)](https://cocoapods.org/pods/gRPC) |
||||||
|
# gRPC Objective-C with CFStream |
||||||
|
|
||||||
|
gRPC Objective-C library now provides the option to use Apple's CFStream API (rather than TCP |
||||||
|
sockets) for networking. Using CFStream resolves a bunch of network connectivity transition issues |
||||||
|
(see the [doc](https://github.com/grpc/grpc/blob/master/src/objective-c/NetworkTransitionBehavior.md) |
||||||
|
for more information). |
||||||
|
|
||||||
|
CFStream integration is now in experimental state. You will need explicit opt-in to use it to get |
||||||
|
the benefits of resolving the issues above. We expect to make CFStream the default networking |
||||||
|
interface that gRPC uses when it is ready for production. |
||||||
|
|
||||||
|
## Usage |
||||||
|
If you use gRPC following the instructions in |
||||||
|
[README.md](https://github.com/grpc/grpc/blob/master/src/objective-c/README.md): |
||||||
|
- Simply replace the |
||||||
|
dependency on `gRPC-ProtoRPC` with `gRPC-ProtoRPC/CFStream`. The build system will take care of |
||||||
|
everything else and switch networking to CFStream. |
||||||
|
|
||||||
|
If your project directly depends on podspecs other than `gRPC-ProtoRPC` (e.g. `gRPC` or |
||||||
|
`gRPC-Core`): |
||||||
|
|
||||||
|
- Make your projects depend on subspecs corresponding to CFStream in each gRPC podspec. For |
||||||
|
`gRPC-Core`, you will need to make sure that the completion queue you create is of type |
||||||
|
`GRPC_CQ_NON_POLLING`. This is expected to be fixed soon so that you do not have to modify the |
||||||
|
completion queue type. |
||||||
|
|
||||||
|
## Notes |
||||||
|
|
||||||
|
- Currently we do not support platforms other than iOS, although it is likely that this integration |
||||||
|
can run on MacOS targets with Apple's compiler. |
||||||
|
- Let us know if you meet any issue by filing issue and ping @muxi. |
@ -0,0 +1,19 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
int main(void) {} |
@ -0,0 +1,19 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
int main(void) {} |
@ -0,0 +1,19 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* 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. |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
int main(void) {} |
@ -0,0 +1,115 @@ |
|||||||
|
/*
|
||||||
|
* |
||||||
|
* Copyright 2018 gRPC authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
* |
||||||
|
*/ |
||||||
|
#include "src/core/lib/iomgr/port.h" |
||||||
|
|
||||||
|
/* This test only relevant on linux systems where epoll() is available */ |
||||||
|
#if defined(GRPC_LINUX_EPOLL_CREATE1) && defined(GRPC_LINUX_EVENTFD) |
||||||
|
#include "src/core/lib/iomgr/ev_epollex_linux.h" |
||||||
|
|
||||||
|
#include <grpc/grpc.h> |
||||||
|
#include <string.h> |
||||||
|
#include <sys/eventfd.h> |
||||||
|
|
||||||
|
#include "test/core/util/test_config.h" |
||||||
|
|
||||||
|
static void pollset_destroy(void* ps, grpc_error* error) { |
||||||
|
grpc_pollset_destroy(static_cast<grpc_pollset*>(ps)); |
||||||
|
gpr_free(ps); |
||||||
|
} |
||||||
|
|
||||||
|
// This test is added to cover the case found in bug:
|
||||||
|
// https://github.com/grpc/grpc/issues/15760
|
||||||
|
static void test_pollable_owner_fd() { |
||||||
|
grpc_core::ExecCtx exec_ctx; |
||||||
|
int ev_fd1; |
||||||
|
int ev_fd2; |
||||||
|
grpc_fd* grpc_fd1; |
||||||
|
grpc_fd* grpc_fd2; |
||||||
|
grpc_pollset* ps; |
||||||
|
gpr_mu* mu; |
||||||
|
|
||||||
|
// == Create two grpc_fds ==
|
||||||
|
// All we need is two file descriptors. Doesn't matter what type. We use
|
||||||
|
// eventfd type here for the purpose of this test
|
||||||
|
ev_fd1 = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); |
||||||
|
ev_fd2 = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC); |
||||||
|
if (ev_fd1 < 0 || ev_fd2 < 0) { |
||||||
|
gpr_log(GPR_ERROR, "Error in creating event fds for the test"); |
||||||
|
return; |
||||||
|
} |
||||||
|
grpc_fd1 = grpc_fd_create(ev_fd1, "epollex-test-fd1", false); |
||||||
|
grpc_fd2 = grpc_fd_create(ev_fd2, "epollex-test-fd2", false); |
||||||
|
grpc_core::ExecCtx::Get()->Flush(); |
||||||
|
|
||||||
|
// == Create a pollset ==
|
||||||
|
ps = static_cast<grpc_pollset*>(gpr_zalloc(grpc_pollset_size())); |
||||||
|
grpc_pollset_init(ps, &mu); |
||||||
|
grpc_core::ExecCtx::Get()->Flush(); |
||||||
|
|
||||||
|
// == Add fd1 to pollset ==
|
||||||
|
grpc_pollset_add_fd(ps, grpc_fd1); |
||||||
|
grpc_core::ExecCtx::Get()->Flush(); |
||||||
|
|
||||||
|
// == Destroy fd1 ==
|
||||||
|
grpc_fd_orphan(grpc_fd1, nullptr, nullptr, "test fd1 orphan"); |
||||||
|
grpc_core::ExecCtx::Get()->Flush(); |
||||||
|
|
||||||
|
// = Add fd2 to pollset ==
|
||||||
|
//
|
||||||
|
// Before https://github.com/grpc/grpc/issues/15760, the following line caused
|
||||||
|
// unexpected behavior (The previous grpc_pollset_add_fd(ps, grpc_fd1) created
|
||||||
|
// an underlying structure in epollex that held a reference to grpc_fd1 which
|
||||||
|
// was being accessed here even after grpc_fd_orphan(grpc_fd1) was called
|
||||||
|
grpc_pollset_add_fd(ps, grpc_fd2); |
||||||
|
grpc_core::ExecCtx::Get()->Flush(); |
||||||
|
|
||||||
|
// == Destroy fd2 ==
|
||||||
|
grpc_fd_orphan(grpc_fd2, nullptr, nullptr, "test fd2 orphan"); |
||||||
|
grpc_core::ExecCtx::Get()->Flush(); |
||||||
|
|
||||||
|
// == Destroy pollset
|
||||||
|
grpc_closure ps_destroy_closure; |
||||||
|
GRPC_CLOSURE_INIT(&ps_destroy_closure, pollset_destroy, ps, |
||||||
|
grpc_schedule_on_exec_ctx); |
||||||
|
grpc_pollset_shutdown(ps, &ps_destroy_closure); |
||||||
|
grpc_core::ExecCtx::Get()->Flush(); |
||||||
|
} |
||||||
|
|
||||||
|
int main(int argc, char** argv) { |
||||||
|
const char* poll_strategy = nullptr; |
||||||
|
grpc_test_init(argc, argv); |
||||||
|
grpc_init(); |
||||||
|
{ |
||||||
|
grpc_core::ExecCtx exec_ctx; |
||||||
|
poll_strategy = grpc_get_poll_strategy_name(); |
||||||
|
if (poll_strategy != nullptr && strcmp(poll_strategy, "epollex") == 0) { |
||||||
|
test_pollable_owner_fd(); |
||||||
|
} else { |
||||||
|
gpr_log(GPR_INFO, |
||||||
|
"Skipping the test. The test is only relevant for 'epollex' " |
||||||
|
"strategy. and the current strategy is: '%s'", |
||||||
|
poll_strategy); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
grpc_shutdown(); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
#else /* defined(GRPC_LINUX_EPOLL_CREATE1) && defined(GRPC_LINUX_EVENTFD) */ |
||||||
|
int main(int argc, char** argv) { return 0; } |
||||||
|
#endif |
@ -0,0 +1 @@ |
|||||||
|
Subproject commit 6599cac0965be8e5a835ab7a5684bbef033d5ad0 |
@ -0,0 +1 @@ |
|||||||
|
Subproject commit 9245d481eb3e890f708ff2d7dadf2a10c04748ba |
@ -0,0 +1,19 @@ |
|||||||
|
#!/usr/bin/env bash |
||||||
|
# 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. |
||||||
|
|
||||||
|
export UPLOAD_TEST_RESULTS=true |
||||||
|
EXTRA_FLAGS="--copt=-gmlt --strip=never --copt=-fsanitize=address --linkopt=-fsanitize=address --test_timeout=3600" |
||||||
|
github/grpc/tools/internal_ci/linux/grpc_bazel_on_foundry_base.sh "${EXTRA_FLAGS}" |
||||||
|
|
@ -0,0 +1,68 @@ |
|||||||
|
#!/usr/bin/env bash |
||||||
|
# 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. |
||||||
|
|
||||||
|
set -ex |
||||||
|
|
||||||
|
# A temporary solution to give Kokoro credentials. |
||||||
|
# The file name 4321_grpc-testing-service needs to match auth_credential in |
||||||
|
# the build config. |
||||||
|
# TODO: Use keystore. |
||||||
|
mkdir -p ${KOKORO_KEYSTORE_DIR} |
||||||
|
cp ${KOKORO_GFILE_DIR}/GrpcTesting-d0eeee2db331.json ${KOKORO_KEYSTORE_DIR}/4321_grpc-testing-service |
||||||
|
|
||||||
|
temp_dir=$(mktemp -d) |
||||||
|
ln -f "${KOKORO_GFILE_DIR}/bazel-rc-0.14.0rc5" ${temp_dir}/bazel |
||||||
|
chmod 755 "${KOKORO_GFILE_DIR}/bazel-rc-0.14.0rc5" |
||||||
|
export PATH="${temp_dir}:${PATH}" |
||||||
|
# This should show ${temp_dir}/bazel |
||||||
|
which bazel |
||||||
|
chmod +x "${KOKORO_GFILE_DIR}/bazel_wrapper.py" |
||||||
|
|
||||||
|
# change to grpc repo root |
||||||
|
cd $(dirname $0)/../../../.. |
||||||
|
|
||||||
|
source tools/internal_ci/helper_scripts/prepare_build_linux_rc |
||||||
|
|
||||||
|
"${KOKORO_GFILE_DIR}/bazel_wrapper.py" \ |
||||||
|
--host_jvm_args=-Dbazel.DigestFunction=SHA256 \ |
||||||
|
test --jobs="200" \ |
||||||
|
--test_timeout="3600,3600,3600,3600" \ |
||||||
|
--test_output=errors \ |
||||||
|
--verbose_failures=true \ |
||||||
|
--keep_going \ |
||||||
|
--remote_accept_cached=true \ |
||||||
|
--spawn_strategy=remote \ |
||||||
|
--remote_local_fallback=false \ |
||||||
|
--remote_timeout=3600 \ |
||||||
|
--strategy=Javac=remote \ |
||||||
|
--strategy=Closure=remote \ |
||||||
|
--genrule_strategy=remote \ |
||||||
|
--experimental_strict_action_env=true \ |
||||||
|
--experimental_remote_platform_override='properties:{name:"container-image" value:"docker://gcr.io/cloud-marketplace/google/rbe-ubuntu16-04@sha256:59bf0e191a6b5cc1ab62c2224c810681d1326bad5a27b1d36c9f40113e79da7f" }' \ |
||||||
|
--define GRPC_PORT_ISOLATED_RUNTIME=1 \ |
||||||
|
--copt=-gmlt \ |
||||||
|
--strip=never \ |
||||||
|
--copt=-fsanitize=undefined \ |
||||||
|
--linkopt=-fsanitize=undefined \ |
||||||
|
--crosstool_top=@com_github_bazelbuild_bazeltoolchains//configs/experimental/ubuntu16_04_clang/1.0/bazel_0.13.0/ubsan:toolchain \ |
||||||
|
--action_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1 \ |
||||||
|
--extra_toolchains=@com_github_bazelbuild_bazeltoolchains//configs/ubuntu16_04_clang/1.0/bazel_0.13.0/cpp:cc-toolchain-clang-x86_64-default \ |
||||||
|
--extra_execution_platforms=@com_github_bazelbuild_bazeltoolchains//configs/ubuntu16_04_clang/1.0:rbe_ubuntu1604 \ |
||||||
|
-- //test/... || FAILED="true" |
||||||
|
|
||||||
|
if [ "$FAILED" != "" ] |
||||||
|
then |
||||||
|
exit 1 |
||||||
|
fi |
Loading…
Reference in new issue