Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,5 @@ cmake-build-*/
# Ignore staging files for the ci/kokoro/install builds
ci/kokoro/install/ccache-contents/

google/cloud/storage/testbench/__pycache__/
google/cloud/storage/testbench/*.pyc
google/cloud/storage/emulator/**/__pycache__/
google/cloud/storage/emulator/**/*.pyc
2 changes: 1 addition & 1 deletion ci/kokoro/docker/Dockerfile.fedora
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ RUN dnf makecache && \
# the container's /etc/passwd file.
RUN echo 'root:' | chpasswd

# Install the Python modules needed to run the storage testbench
# Install the Python modules needed to run the storage emulator
RUN pip3 install --upgrade pip
RUN pip3 install setuptools wheel
RUN pip3 install git+git://github.com/googleapis/python-storage@8cf6c62a96ba3fff7e5028d931231e28e5029f1c
Expand Down
2 changes: 1 addition & 1 deletion ci/kokoro/docker/Dockerfile.fedora-install
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ RUN pip3 install cmake_format==0.6.8
# Install black to automatically format the Python files.
RUN pip3 install black==19.3b0

# Install the Python modules needed to run the storage testbench
# Install the Python modules needed to run the storage emulator
RUN dnf makecache && dnf install -y python3-devel
RUN pip3 install setuptools wheel
RUN pip3 install git+git://github.com/googleapis/python-storage@8cf6c62a96ba3fff7e5028d931231e28e5029f1c
Expand Down
2 changes: 1 addition & 1 deletion ci/kokoro/docker/Dockerfile.fedora-libcxx-msan
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ RUN dnf makecache && \
# the container's /etc/passwd file.
RUN echo 'root:' | chpasswd

# Install the Python modules needed to run the storage testbench
# Install the Python modules needed to run the storage emulator
RUN pip3 install --upgrade pip
RUN pip3 install setuptools wheel
RUN pip3 install git+git://github.com/googleapis/python-storage@8cf6c62a96ba3fff7e5028d931231e28e5029f1c
Expand Down
4 changes: 2 additions & 2 deletions google/cloud/storage/benchmarks/throughput_experiment_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ bool ProductionOnly(ApiName api) {
}

TEST_P(ThroughputExperimentIntegrationTest, Upload) {
if (UsingTestbench() && ProductionOnly(GetParam())) GTEST_SKIP();
if (UsingEmulator() && ProductionOnly(GetParam())) GTEST_SKIP();

auto client = MakeIntegrationTestClient();
ASSERT_STATUS_OK(client);
Expand Down Expand Up @@ -71,7 +71,7 @@ TEST_P(ThroughputExperimentIntegrationTest, Upload) {
}

TEST_P(ThroughputExperimentIntegrationTest, Download) {
if (UsingTestbench() && ProductionOnly(GetParam())) GTEST_SKIP();
if (UsingEmulator() && ProductionOnly(GetParam())) GTEST_SKIP();

auto client = MakeIntegrationTestClient();
ASSERT_STATUS_OK(client);
Expand Down
22 changes: 11 additions & 11 deletions google/cloud/storage/ci/run_integration_tests_emulator_bazel.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ if [[ "$exit_status" -ne 0 ]]; then
exit "${exit_status}"
fi

# Configure run_testbench_utils.sh to run the GCS testbench.
source "${PROJECT_ROOT}/google/cloud/storage/tools/run_testbench_utils.sh"
# Configure run_emulator_utils.sh to run the GCS emulator.
source "${PROJECT_ROOT}/google/cloud/storage/tools/run_emulator_utils.sh"

# These can only run against production
production_only_targets=(
Expand All @@ -54,13 +54,13 @@ production_only_targets=(
--test_tag_filters="integration-test" -- \
"${production_only_targets[@]}"

# `start_testbench` creates unsightly *.log files in the current directory
# `start_emulator` creates unsightly *.log files in the current directory
# (which is ${PROJECT_ROOT}) and we cannot use a subshell because we want the
# environment variables that it sets.
pushd "${HOME}" >/dev/null
# Start the testbench on a fixed port, otherwise the Bazel cache gets
# Start the emulator on a fixed port, otherwise the Bazel cache gets
# invalidated on each run.
start_testbench 8585 8000
start_emulator 8585 8000
popd >/dev/null

excluded_targets=(
Expand All @@ -78,32 +78,32 @@ done
# `storage_bucket_samples` binary is missing the examples that use said bucket
# are missing too.
EMULATOR_SHA=$(git ls-files google/cloud/storage/emulator | sort | cat | sha256sum)
testbench_args=(
"--test_env=CLOUD_STORAGE_TESTBENCH_ENDPOINT=${CLOUD_STORAGE_TESTBENCH_ENDPOINT}"
emulator_args=(
"--test_env=CLOUD_STORAGE_EMULATOR_ENDPOINT=${CLOUD_STORAGE_EMULATOR_ENDPOINT}"
"--test_env=CLOUD_STORAGE_GRPC_ENDPOINT=${CLOUD_STORAGE_GRPC_ENDPOINT}"
"--test_env=HTTPBIN_ENDPOINT=${HTTPBIN_ENDPOINT}"
"--test_env=GOOGLE_CLOUD_CPP_STORAGE_TEST_HMAC_SERVICE_ACCOUNT=fake-service-account-sign@example.com"
"--test_env=GOOGLE_CLOUD_CPP_AUTO_RUN_EXAMPLES=yes"
"--test_env=EMULATOR_SHA=${EMULATOR_SHA}"
)
"${BAZEL_BIN}" run "${bazel_test_args[@]}" "${testbench_args[@]}" \
"${BAZEL_BIN}" run "${bazel_test_args[@]}" "${emulator_args[@]}" \
"//google/cloud/storage/examples:storage_bucket_samples" \
-- create-bucket-for-project \
"${GOOGLE_CLOUD_CPP_STORAGE_TEST_DESTINATION_BUCKET_NAME}" \
"${GOOGLE_CLOUD_PROJECT}" >/dev/null

# We need to forward some environment variables suitable for running against
# the testbench. Note that the HMAC service account is completely invalid and
# the emulator. Note that the HMAC service account is completely invalid and
# it is not unique to each test, neither is a problem when using the emulator.
"${BAZEL_BIN}" "${BAZEL_VERB}" "${bazel_test_args[@]}" "${testbench_args[@]}" \
"${BAZEL_BIN}" "${BAZEL_VERB}" "${bazel_test_args[@]}" "${emulator_args[@]}" \
--test_tag_filters="integration-test" -- \
"//google/cloud/storage/...:all" \
"${excluded_targets[@]}"
exit_status=$?

if [[ "$exit_status" -ne 0 ]]; then
source "${PROJECT_ROOT}/ci/define-dump-log.sh"
dump_log "${HOME}/testbench.log"
dump_log "${HOME}/gcs_emulator.log"
fi

exit "${exit_status}"
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ shift
ctest_args=("$@")

# Configure run_emulators_utils.sh to find the instance admin emulator.
source "${PROJECT_ROOT}/google/cloud/storage/tools/run_testbench_utils.sh"
source "${PROJECT_ROOT}/google/cloud/storage/tools/run_emulator_utils.sh"

# Use the same configuration parameters as we use for testing against
# production. Easier to maintain just one copy.
Expand All @@ -43,7 +43,7 @@ export GOOGLE_CLOUD_CPP_STORAGE_TEST_SIGNING_KEYFILE="${PROJECT_ROOT}/google/clo
export GOOGLE_CLOUD_CPP_STORAGE_TEST_SIGNING_CONFORMANCE_FILENAME="${PROJECT_ROOT}/google/cloud/storage/tests/v4_signatures.json"

cd "${BINARY_DIR}"
start_testbench
start_emulator

# GOOGLE_CLOUD_CPP_STORAGE_TEST_BUCKET_NAME is automatically created, but we
# need to create the *DESTINATION_BUCKET_NAME too. Note that when the
Expand All @@ -59,12 +59,12 @@ fi
ctest -R "^storage_" "${ctest_args[@]}"
exit_status=$?

kill_testbench
kill_emulator
trap '' EXIT

if [[ "$exit_status" -ne 0 ]]; then
source "${PROJECT_ROOT}/ci/define-dump-log.sh"
dump_log "${HOME}/testbench.log"
dump_log "${HOME}/emulator.log"
fi

exit "${exit_status}"
26 changes: 15 additions & 11 deletions google/cloud/storage/client_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,29 @@ using ::google::cloud::internal::GetEnv;

namespace internal {

absl::optional<std::string> GetEmulator() {
auto emulator = GetEnv("CLOUD_STORAGE_EMULATOR_ENDPOINT");
if (emulator) return emulator;
return GetEnv("CLOUD_STORAGE_TESTBENCH_ENDPOINT");
}

std::string JsonEndpoint(ClientOptions const& options) {
return GetEnv("CLOUD_STORAGE_TESTBENCH_ENDPOINT")
.value_or(options.endpoint_) +
"/storage/" + options.version();
return GetEmulator().value_or(options.endpoint_) + "/storage/" +
options.version();
}

std::string JsonUploadEndpoint(ClientOptions const& options) {
return GetEnv("CLOUD_STORAGE_TESTBENCH_ENDPOINT")
.value_or(options.endpoint_) +
"/upload/storage/" + options.version();
return GetEmulator().value_or(options.endpoint_) + "/upload/storage/" +
options.version();
}

std::string XmlEndpoint(ClientOptions const& options) {
return GetEnv("CLOUD_STORAGE_TESTBENCH_ENDPOINT").value_or(options.endpoint_);
return GetEmulator().value_or(options.endpoint_);
}

std::string IamEndpoint(ClientOptions const& options) {
auto testbench = GetEnv("CLOUD_STORAGE_TESTBENCH_ENDPOINT");
if (testbench) return *testbench + "/iamapi";
auto emulator = GetEmulator();
if (emulator) return *emulator + "/iamapi";
return options.iam_endpoint();
}

Expand All @@ -59,7 +63,7 @@ std::string IamEndpoint(ClientOptions const& options) {
namespace {
StatusOr<std::shared_ptr<oauth2::Credentials>> StorageDefaultCredentials(
ChannelOptions const& channel_options) {
auto emulator = cloud::internal::GetEnv("CLOUD_STORAGE_TESTBENCH_ENDPOINT");
auto emulator = internal::GetEmulator();
if (emulator.has_value()) {
return StatusOr<std::shared_ptr<oauth2::Credentials>>(
oauth2::CreateAnonymousCredentials());
Expand Down Expand Up @@ -126,7 +130,7 @@ ClientOptions::ClientOptions(std::shared_ptr<oauth2::Credentials> credentials,
download_stall_timeout_(
GOOGLE_CLOUD_CPP_STORAGE_DEFAULT_DOWNLOAD_STALL_TIMEOUT),
channel_options_(std::move(channel_options)) {
auto emulator = GetEnv("CLOUD_STORAGE_TESTBENCH_ENDPOINT");
auto emulator = internal::GetEmulator();
if (emulator.has_value()) {
endpoint_ = *emulator;
iam_endpoint_ = *emulator + "/iamapi";
Expand Down
4 changes: 2 additions & 2 deletions google/cloud/storage/client_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class ChannelOptions {
*
* By default, several environment variables are read to configure the client:
*
* - `CLOUD_STORAGE_TESTBENCH_ENDPOINT`: if set, use this http endpoint to
* - `CLOUD_STORAGE_EMULATOR_ENDPOINT`: if set, use this http endpoint to
* make all http requests instead of the production GCS service. Also,
* if set, the `CreateDefaultClientOptions()` function will use an
* `AnonymousCredentials` object instead of loading Application Default
Expand All @@ -82,7 +82,7 @@ class ClientOptions {
* Creates a `ClientOptions` with Google Application Default %Credentials.
*
* If Application Default %Credentials could not be loaded, this returns a
* `Status` with failure details. If the `CLOUD_STORAGE_TESTBENCH_ENDPOINT`
* `Status` with failure details. If the `CLOUD_STORAGE_EMULATOR_ENDPOINT`
* environment variable is set, this function instead uses an
* `AnonymousCredentials` to configure the client.
*/
Expand Down
24 changes: 20 additions & 4 deletions google/cloud/storage/client_options_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ class ClientOptionsTest : public ::testing::Test {
public:
ClientOptionsTest()
: enable_tracing_("CLOUD_STORAGE_ENABLE_TRACING", {}),
endpoint_("CLOUD_STORAGE_TESTBENCH_ENDPOINT", {}),
endpoint_("CLOUD_STORAGE_EMULATOR_ENDPOINT", {}),
old_endpoint_("CLOUD_STORAGE_TESTBENCH_ENDPOINT", {}),
generator_(std::random_device{}()) {}

std::string CreateRandomFileName() {
Expand All @@ -46,6 +47,7 @@ class ClientOptionsTest : public ::testing::Test {
protected:
testing_util::ScopedEnvironment enable_tracing_;
testing_util::ScopedEnvironment endpoint_;
testing_util::ScopedEnvironment old_endpoint_;
google::cloud::internal::DefaultPRNG generator_;
};

Expand Down Expand Up @@ -124,7 +126,7 @@ TEST_F(ClientOptionsTest, EnableHttp) {
}

TEST_F(ClientOptionsTest, EndpointsDefault) {
testing_util::ScopedEnvironment endpoint("CLOUD_STORAGE_TESTBENCH_ENDPOINT",
testing_util::ScopedEnvironment endpoint("CLOUD_STORAGE_EMULATOR_ENDPOINT",
{});
ClientOptions options(oauth2::CreateAnonymousCredentials());
EXPECT_EQ("https://storage.googleapis.com", options.endpoint());
Expand All @@ -137,7 +139,7 @@ TEST_F(ClientOptionsTest, EndpointsDefault) {
}

TEST_F(ClientOptionsTest, EndpointsOverride) {
testing_util::ScopedEnvironment endpoint("CLOUD_STORAGE_TESTBENCH_ENDPOINT",
testing_util::ScopedEnvironment endpoint("CLOUD_STORAGE_EMULATOR_ENDPOINT",
{});
ClientOptions options(oauth2::CreateAnonymousCredentials());
options.set_endpoint("http://127.0.0.1.nip.io:1234");
Expand All @@ -151,7 +153,21 @@ TEST_F(ClientOptionsTest, EndpointsOverride) {
internal::IamEndpoint(options));
}

TEST_F(ClientOptionsTest, EndpointsTestBench) {
TEST_F(ClientOptionsTest, EndpointsEmulator) {
testing_util::ScopedEnvironment endpoint("CLOUD_STORAGE_EMULATOR_ENDPOINT",
"http://localhost:1234");
ClientOptions options(oauth2::CreateAnonymousCredentials());
EXPECT_EQ("http://localhost:1234", options.endpoint());
EXPECT_EQ("http://localhost:1234/storage/v1",
internal::JsonEndpoint(options));
EXPECT_EQ("http://localhost:1234/upload/storage/v1",
internal::JsonUploadEndpoint(options));
EXPECT_EQ("http://localhost:1234", internal::XmlEndpoint(options));
EXPECT_EQ("http://localhost:1234/iamapi", internal::IamEndpoint(options));
}

TEST_F(ClientOptionsTest, OldEndpointsEmulator) {
google::cloud::internal::UnsetEnv("CLOUD_STORAGE_EMULATOR_ENDPOINT");
testing_util::ScopedEnvironment endpoint("CLOUD_STORAGE_TESTBENCH_ENDPOINT",
"http://localhost:1234");
ClientOptions options(oauth2::CreateAnonymousCredentials());
Expand Down
5 changes: 4 additions & 1 deletion google/cloud/storage/doc/storage-main.dox
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,12 @@ which should give you a taste of the Cloud Storage C++ client library API.

- `CLOUD_STORAGE_ENABLE_TRACING=raw-client,http` enables all logging.

- `CLOUD_STORAGE_TESTBENCH_ENDPOINT=...` override the default endpoint used by
- `CLOUD_STORAGE_EMULATOR_ENDPOINT=...` override the default endpoint used by
the library, intended for testing only.

- `CLOUD_STORAGE_TESTBENCH_ENDPOINT=...` **DEPRECATED**
please use `CLOUD_STORAGE_EMULATOR_ENDPOINT` instead.

### Experimental

- `GOOGLE_CLOUD_CPP_STORAGE_REST_CONFIG=...` configuration for the REST
Expand Down
19 changes: 11 additions & 8 deletions google/cloud/storage/emulator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,42 +32,45 @@ curl "http://localhost:9000/start_grpc?port=8000"
For `google-cloud-cpp`, please set the following enviroment variable

```bash
CLOUD_STORAGE_TESTBENCH_ENDPOINT=http://localhost:9000 # For JSON and XML API
CLOUD_STORAGE_EMULATOR_ENDPOINT=http://localhost:9000 # For JSON and XML API
CLOUD_STORAGE_GRPC_ENDPOINT=localhost:8000 # For gRPC API
```

## Force Failures

You can force the following failures by using the `x-goog-testbench-instructions` header.
You can force the following failures by using the `x-goog-emulator-instructions` header.
The `x-goog-testbench-instructions` header is deprecated, but supported for
backwards compatibility and provides the same functionality as
`x-goog-emulator-instructions`, please change your code to use `x-goog-emulator-instructions` instead.

### return-broken-stream

Set request headers with `x-goog-testbench-instructions: return-broken-stream`.
Set request headers with `x-goog-emulator-instructions: return-broken-stream`.
Emulator will fail after sending 1024*1024 bytes.

### return-corrupted-data

Set request headers with `x-goog-testbench-instructions: return-corrupted-data`.
Set request headers with `x-goog-emulator-instructions: return-corrupted-data`.
Emulator will return corrupted data.

### stall-always

Set request headers with `x-goog-testbench-instructions: stall-always`.
Set request headers with `x-goog-emulator-instructions: stall-always`.
Emulator will stall at the beginning.

### stall-at-256KiB

Set request headers with `x-goog-testbench-instructions: stall-at-256KiB`.
Set request headers with `x-goog-emulator-instructions: stall-at-256KiB`.
Emulator will stall at 256KiB bytes.

### return-503-after-256K

Set request headers with `x-goog-testbench-instructions: return-503-after-256K`.
Set request headers with `x-goog-emulator-instructions: return-503-after-256K`.
Emulator will return a `HTTP 503` after sending 256KiB bytes.

### return-503-after-256K/retry-N

Set request headers with `x-goog-testbench-instructions: return-503-after-256K/retry-1` up to `x-goog-testbench-instructions: return-503-after-256K/retry-N`.
Set request headers with `x-goog-emulator-instructions: return-503-after-256K/retry-1` up to `x-goog-emulator-instructions: return-503-after-256K/retry-N`.

For N==1 and N==2 behave like `return-305-after-256K`, for `N>=3` ignore the
failure instruction and return successfully. This is used to test failures during
Expand Down
8 changes: 4 additions & 4 deletions google/cloud/storage/emulator/emulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -686,10 +686,10 @@ def resumable_upload_chunk(bucket_name):
False,
None,
)
blob.metadata.metadata["x_testbench_transfer_encoding"] = ":".join(
blob.metadata.metadata["x_emulator_transfer_encoding"] = ":".join(
upload.transfer
)
blob.metadata.metadata["x_testbench_upload"] = "resumable"
blob.metadata.metadata["x_emulator_upload"] = "resumable"
db.insert_object(upload.request, bucket_name, blob, None)
projection = utils.common.extract_projection(
upload.request, CommonEnums.Projection.NO_ACL, None
Expand Down Expand Up @@ -734,10 +734,10 @@ def resumable_upload_chunk(bucket_name):
None,
upload.rest_only,
)
blob.metadata.metadata["x_testbench_transfer_encoding"] = ":".join(
blob.metadata.metadata["x_emulator_transfer_encoding"] = ":".join(
upload.transfer
)
blob.metadata.metadata["x_testbench_upload"] = "resumable"
blob.metadata.metadata["x_emulator_upload"] = "resumable"
db.insert_object(upload.request, bucket_name, blob, None)
projection = utils.common.extract_projection(
upload.request, CommonEnums.Projection.NO_ACL, None
Expand Down
Loading