Repository navigation
[Better Tests] Add error injection and runtime overrides for GCE metadata fake values - #5481
Merged
IvanBM18 merged 5 commits intoOct 6, 2026
Conversation
This was referenced Sep 22, 2026
IvanBM18
force-pushed
the
better-tests/03-metadata-emulator-faults
branch
9 times, most recently
from
September 23, 2026 17:03
249bcd5 to
ad95910
Compare
IvanBM18
force-pushed
the
better-tests/03-metadata-emulator-faults
branch
from
September 23, 2026 17:07
ad95910 to
df96aa0
Compare
IvanBM18
force-pushed
the
better-tests/03-metadata-emulator-faults
branch
from
September 23, 2026 17:09
df96aa0 to
d60eea1
Compare
IvanBM18
commented
Sep 23, 2026
IvanBM18
force-pushed
the
better-tests/03-metadata-emulator-faults
branch
from
September 23, 2026 18:05
d60eea1 to
8e0ed8c
Compare
IvanBM18
force-pushed
the
better-tests/03-metadata-emulator-faults
branch
from
September 23, 2026 18:12
8e0ed8c to
f69b6e1
Compare
IvanBM18
changed the base branch from
better-tests/02-metadata-emulator-core
to
better-tests/02a-metadata-emulator-tests
September 23, 2026 18:13
This was referenced Sep 23, 2026
IvanBM18
force-pushed
the
better-tests/03-metadata-emulator-faults
branch
2 times, most recently
from
September 24, 2026 06:11
f89d3c4 to
4600042
Compare
IvanBM18
force-pushed
the
better-tests/03-metadata-emulator-faults
branch
from
September 24, 2026 06:19
4600042 to
1b3a73f
Compare
IvanBM18
added this pull request to stack #5497
September 25, 2026 01:44
IvanBM18
force-pushed
the
better-tests/03-metadata-emulator-faults
branch
from
September 30, 2026 20:43
b0dbe2d to
7872b59
Compare
IvanBM18
force-pushed
the
better-tests/03-metadata-emulator-faults
branch
from
October 2, 2026 17:12
d221062 to
2efdf40
Compare
IvanBM18
commented
Oct 2, 2026
| Config.base_url = self.admin_url | ||
| Mappings.create_mapping(mapping) | ||
|
|
||
| def _all_mappings(self) -> list[Mapping]: |
Collaborator
Author
There was a problem hiding this comment.
Removed because the only caller was _remove_existing_faults_for_path(), which is now part of the common logic in WireMockFaultInjector
dylanjew
approved these changes
Oct 2, 2026
IvanBM18
commented
Oct 2, 2026
| } | ||
|
|
||
|
|
||
| class FaultInjector(abc.ABC): |
Collaborator
Author
There was a problem hiding this comment.
Created this baseclas in case in the future we need to inject fault to a fake/proxy api, that doesn't follow the wireMock which i see as a possibility, since Wiremock has the restriction that responses are static for the matching given path + payload.
decoNR
approved these changes
Oct 6, 2026
…#5517) Bug: b/555379018 ## Overview The following Pr stack focuses in the creation of a swarming API fake to be used by the integration tests suite. For this purpose, we perform a small refactor in the swarming package, focused on making some constants public so that they can be reused in our fake api, as well as some general adjustments in the API initialization so that we can give it http paths. ## Changes - Creates `constants.py` which consists of swarming related constants - Now the swarming server url must be given including `https://` or `https://` this way we give the api the flexiblity of using non secure urls such as ones coming from localhost. - There are following changes in the swarming config in the [config repo](https://clusterfuzz-config-472119376969.us-central1.sourcemanager.dev/clusterfuzz-testing/clusterfuzz-config/pulls/387) ## Tests - Added UT for the new validation in the API
'Fault' was an unclear and overly specific term. 'Error' is the more general and widely understood word for what the injector does: make the emulator answer with an HTTP error status (optionally after a delay). - wiremock_faults.py -> wiremock_errors.py - FaultInjector / WireMockFaultInjector -> ErrorInjector / WireMockErrorInjector - inject_fault / clear_faults -> inject_error / clear_errors - fault_injector ctor arg -> error_injector - WireMock mapping metadata keys 'fault' / 'fault_path' -> 'error' / 'error_path'
IvanBM18
force-pushed
the
better-tests/03-metadata-emulator-faults
branch
from
October 6, 2026 22:19
0841a3b to
3547bc8
Compare
IvanBM18
added a commit
that referenced
this pull request
Oct 6, 2026
Bug: b/555370359 We can redirect `google-auth` metadata requests to a local emulator via the `GCE_METADATA_HOST` environment variable, but ClusterFuzz's own `compute_metadata.py` previously hardcoded `metadata.google.internal` and port `80`. Reading `GCE_METADATA_HOST` and parsing optional ports allows local integration tests to run a metadata emulator on an ephemeral unprivileged port without root privileges or `/etc/hosts` changes. ## Changes - Update `_METADATA_SERVER` in `compute_metadata.py` to read `GCE_METADATA_HOST` from the environment, falling back to `metadata.google.internal`. - Add unit tests in covering `_metadata_host_port()`, `is_gce()` on non-default ports, and `GCE_METADATA_HOST` overrides. ### 📚 Stacked PRs | Step | PR | Title | Base Branch | | :---: | :--- | :--- | :--- | | 0 | #5475 | `[Better Tests] Adds new test dependencies` | `master` | | **1** | **#5479** | **`[Better Tests] Support GCE_METADATA_HOST with port in compute_metadata`** *(👉 This PR)* | `better-test/dependencies` | | 2 | #5485 | `[Better Tests] Add GCE metadata emulator worker fixtures` | `better-tests/01-compute-metadata-host` | | 3 | #5480 | `[Better Tests] Add the WireMock GCE metadata emulator` | `better-tests/01a-metadata-emulator-configs` | | 4 | #5486 | `[Better Tests] Bootstrap and cover the GCE metadata emulator` | `better-tests/02-metadata-emulator-core` | | 5 | #5481 | `[Better Tests] Add fault injection and runtime overrides to metadata emulator` | `better-tests/02a-metadata-emulator-tests` |
IvanBM18
added a commit
that referenced
this pull request
Oct 6, 2026
Bug: b/555370359 Split out of #5480, which had grown to 821 lines across the fixtures, the emulator that serves them, and the tests that exercise it. This PR is the data half: the JSON configs the GCE metadata emulator seeds itself from. Each config describes one worker identity, so a test can pick whether it runs trusted or untrusted by picking which fixture answers on the default address. The shape of `metadata` mirrors the real metadata server's hierarchy, so a config can be retrieved by reading a live instance: ``` curl -H 'Metadata-Flavor: Google' \ 'http://metadata.google.internal/computeMetadata/v1/?recursive=true' | jq ``` ## Changes - Add `local/emulators/configs/tworker.json`: the trusted worker identity, with its service account email, scopes, a fake access token, and the project and instance metadata a tworker reads. - Add `local/emulators/configs/uworker.json`: the untrusted counterpart, so both can run side by side and be shown to stay distinct. - Add `local/emulators/configs/template.json`: an annotated reference for writing a new config. It is documentation rather than a loadable fixture, so it keeps its `//` comments; nothing parses it. `tworker.json` and `uworker.json` are plain JSON and are the only two loaded. Nothing reads these yet. The emulator that serves them is #5480, next in the stack. ### 📚 Stacked PRs | Step | PR | Title | Base Branch | | :---: | :--- | :--- | :--- | | 0 | #5475 | `[Better Tests] Adds new test dependencies` | `master` | | 1 | #5479 | `[Better Tests] Support GCE_METADATA_HOST with port in compute_metadata` | `better-test/dependencies` | | **2** | **#5485** | **`[Better Tests] Add GCE metadata emulator worker fixtures`** *(👉 This PR)* | `better-tests/01-compute-metadata-host` | | 3 | #5480 | `[Better Tests] Add the WireMock GCE metadata emulator` | `better-tests/01a-metadata-emulator-configs` | | 4 | #5486 | `[Better Tests] Bootstrap and cover the GCE metadata emulator` | `better-tests/02-metadata-emulator-core` | | 5 | #5481 | `[Better Tests] Add fault injection and runtime overrides to metadata emulator` | `better-tests/02a-metadata-emulator-tests` |
IvanBM18
added a commit
that referenced
this pull request
Oct 6, 2026
Bug: b/555370359
Creates a GCE metadata emulator for our future integration test suite,
built on Testcontainers and WireMock. It lets tests resolve credentials
and read instance and project metadata without a real GCE host or a
local `gcloud` login, and lets them distinguish a trusted from an
untrusted environment.
`google-auth` and our vendored `oauth2client` evaluate the
`GCE_METADATA_*` environment variables once, at import time, and bake
the resulting URL in. Importing this module therefore claims two
loopback addresses up front; the addresses never move, only what listens
on them does. A test picks its in-process identity by picking which
fixture answers on the default address:
```python
with gce_metadata_emulator.trusted_as_default() as tworker:
...
with gce_metadata_emulator.untrusted_as_default() as uworker:
...
with gce_metadata_emulator.trusted_untrusted_pair() as (tworker, uworker):
... # uworker sits on the secondary address
```
Nothing is patched to make that work. An emulator on the secondary
address is reachable through the client its context manager yields, or
by handing its env to a child process:
```python
subprocess.run(argv, env={**os.environ, **uworker.env})
```
This emulator was based off the pre-existing [local emulator go
wrap](https://github.com/google/clusterfuzz/blob/master/local/emulators/metadata.go)
+ what is detailed at the [GCP metadata server
docs](https://docs.cloud.google.com/compute/docs/metadata/overview)
## Changes
- Add `gce_metadata_emulator.py`, a WireMock Testcontainer fake GCE
metadata server. Supports:
- Serving fake service account credentials, so a test can tell a trusted
from an untrusted environment.
- Serving project- and instance-scoped metadata values, including
attribute shadowing, seeded from the JSON configs added in #5485.
- Rejecting requests that omit `Metadata-Flavor: Google`, the way the
real server does.
- Failing loudly when two emulators want the same address.
The tests covering all of this land in #5486, next in the stack.
### 📚 Stacked PRs
| Step | PR | Title | Base Branch |
| :---: | :--- | :--- | :--- |
| 0 | #5475 | `[Better Tests] Adds new test dependencies` | `master` |
| 1 | #5479 | `[Better Tests] Support GCE_METADATA_HOST with port in
compute_metadata` | `better-test/dependencies` |
| 2 | #5485 | `[Better Tests] Add GCE metadata emulator worker fixtures`
| `better-tests/01-compute-metadata-host` |
| **3** | **#5480** | **`[Better Tests] Add the WireMock GCE metadata
emulator`** *(👉 This PR)* | `better-tests/01a-metadata-emulator-configs`
|
| 4 | #5486 | `[Better Tests] Bootstrap and cover the GCE metadata
emulator` | `better-tests/02-metadata-emulator-core` |
| 5 | #5481 | `[Better Tests] Add fault injection and runtime overrides
to metadata emulator` | `better-tests/02a-metadata-emulator-tests` |
IvanBM18
added a commit
that referenced
this pull request
Oct 6, 2026
Bug: b/555370359 Split out of #5480. This PR wires the GCE metadata emulator added in #5480 into the test runner, and covers it. ## Note - This is the first of many integration test modules, for this purpose, it uses `pytest` library instead of `unittest`, this requires different syntax for asserting, but files & methods naming is basically the same. - This is a experimental integration test module, still a standalone, we require to wire a couple of things with a butler command to allow easy execution of this kind of tests like we do with unit test, this will be done in a subsequent bug: b/540876792 - Documentation will be created in b/555424439 once we have our first set of integration test suites & the butler command is ready to run them - I aim to create documentation & guidelines to be created based off this first tests and overall the discussion we have in the PRs for them, so feel free to push back on even the smallest details, nothing is set in stone! ## Changes - Adds `gce_metadata_emulator_test.py`, skipped right now because its experimental, just in case this ends in the CI process before we intended to. ## Tests - `GceMetadataEmulatorTest` an integration test for how some common workflows behave using the new emulator, runs a trusted and an untrusted emulator side by side and verifies: - `GceMetadataEmulatorUntrustedDefaultTest` puts a metadata server that returns uworker on the default address and verifies that all resolve to the untrusted identity. To run it: ``` PYTHONPATH=src:src/third_party pytest test_suites/fixtures/gce_metadata_server_test.py ``` We need to later include them in `butler.py` so that we can: - Run them smoothly - Don't require to do the imports manually But theres already a bug for that, and the purpose of this is not creating the butler setup but to create an emulator for other tests. ### 📚 Stacked PRs | Step | PR | Title | Base Branch | | :---: | :--- | :--- | :--- | | 0 | #5475 | `[Better Tests] Adds new test dependencies` | `master` | | 1 | #5479 | `[Better Tests] Support GCE_METADATA_HOST with port in compute_metadata` | `better-test/dependencies` | | 2 | #5485 | `[Better Tests] Add GCE metadata emulator worker fixtures` | `better-tests/01-compute-metadata-host` | | 3 | #5480 | `[Better Tests] Add the WireMock GCE metadata emulator` | `better-tests/01a-metadata-emulator-configs` | | **4** | **#5486** | **`[Better Tests] Bootstrap and cover the GCE metadata emulator`** *(👉 This PR)* | `better-tests/02-metadata-emulator-core` | | 5 | #5481 | `[Better Tests] Add fault injection and runtime overrides to metadata emulator` | `better-tests/02a-metadata-emulator-tests` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bug: b/555370359
Following the parent PR, this one introduces changes for our emulator so that we can force it to fail either constantly, or on demand, this opens a ton of possibilities for integration tests, this is technically also a new feature, but to simplify reviews i moved this one to a separate PR.
With this changes it now simulates transient GCE metadata server failures (such as HTTP 500s or latency spikes) and mutate instance/project attributes dynamically during a test without restarting the WireMock container. Using WireMock stateful scenarios allows injecting faults that automatically expire after N requests so retry decorators (such as
@retry.wraponcompute_metadata.get()) can be tested deterministically.Changes
_runtime_instance_attributessoset_project_attribute()does not overwrite attributes shadowed at runtime, and reset them inclear_faults().📚 Stacked PRs
[Better Tests] Adds new test dependenciesmaster[Better Tests] Support GCE_METADATA_HOST with port in compute_metadatabetter-test/dependencies[Better Tests] Add GCE metadata emulator worker fixturesbetter-tests/01-compute-metadata-host[Better Tests] Add the WireMock GCE metadata emulatorbetter-tests/01a-metadata-emulator-configs[Better Tests] Bootstrap and cover the GCE metadata emulatorbetter-tests/02-metadata-emulator-core[Better Tests] Add fault injection and runtime overrides to metadata emulator(👉 This PR)better-tests/02a-metadata-emulator-tests