Skip to main content

Mock Google Cloud Platform services in your tests - the moto for GCP.

Project description

🐦 drongo

Mock Google Cloud Platform services in your tests - the moto for GCP.

CI License: Apache 2.0 Python 3.10+ Typed


drongo lets you test code that talks to Google Cloud without touching the network, running an emulator, or paying for real resources. It stands up an in-memory, in-process fake of GCP service APIs and transparently intercepts the requests your google-cloud client libraries make.

If you've used moto for AWS, drongo will feel immediately familiar - that's on purpose.

Why "drongo"? boto (the AWS SDK) is named after the boto, the Amazon river dolphin, and moto mocks boto. The drongo is a bird famed for vocal mimicry: the fork-tailed drongo copies other animals' alarm calls to fool them into dropping their food. That is exactly what a mock does, so drongo does it for Google Cloud. 🐦

Features

  • 🎯 One decorator - @mock_gcp patches every supported service, just like @mock_aws.
  • 🔌 Flexible - use it as a decorator, a context manager, a class decorator, or a unittest.TestCase mixin.
  • 🧠 In-memory & fast - no Docker, no emulators, no sockets; tests run in milliseconds.
  • 🌐 Standalone server - drongo server speaks real HTTP so SDKs in any language can point at it.
  • 🧪 pytest-native - a drongo fixture is auto-registered on install.
  • 🧩 Extensible - adding a service is models.py + responses.py + urls.py, the same shape as moto.
  • Typed - ships py.typed, checked with mypy.

Installation

pip install drongo

drongo does not depend on the google-cloud client libraries - you bring your own (google-cloud-storage, google-cloud-secret-manager, …). It mocks whatever you already use.

Quickstart

from drongo import mock_gcp


@mock_gcp
def test_upload_download():
    from google.cloud import storage

    client = storage.Client(project="my-project")
    bucket = client.create_bucket("my-bucket")

    bucket.blob("hello.txt").upload_from_string(
        "hello drongo", content_type="text/plain"
    )

    assert bucket.blob("hello.txt").download_as_text() == "hello drongo"
    assert [b.name for b in client.list_blobs("my-bucket")] == ["hello.txt"]

No credentials, no network, no emulator. storage.Client() works with or without arguments - drongo supplies anonymous credentials and a default project while a mock scope is active.

Every way to invoke it (all like moto)

from drongo import mock_gcp


# 1. Bare decorator
@mock_gcp
def test_a(): ...


# 2. Called decorator
@mock_gcp()
def test_b(): ...


# 3. Context manager
def test_c():
    with mock_gcp():
        ...


# 4. Class decorator (plain class or unittest.TestCase)
@mock_gcp
class TestSuite:
    def test_d(self): ...

pytest fixture

def test_with_fixture(drongo):
    from google.cloud import storage

    storage.Client(project="p").create_bucket("b")

    # Inspect raw backend state, moto-style.
    assert "b" in drongo.backend("storage").buckets

Secret Manager

Construct the client with the REST transport so drongo can intercept it:

from drongo import mock_gcp


@mock_gcp
def test_secret():
    from google.cloud import secretmanager

    client = secretmanager.SecretManagerServiceClient(transport="rest")
    secret = client.create_secret(
        request={
            "parent": "projects/my-project",
            "secret_id": "api-key",
            "secret": {"replication": {"automatic": {}}},
        }
    )
    client.add_secret_version(
        request={"parent": secret.name, "payload": {"data": b"s3cr3t"}}
    )

    accessed = client.access_secret_version(
        request={"name": f"{secret.name}/versions/latest"}
    )
    assert accessed.payload.data == b"s3cr3t"

Standalone server mode

Run drongo as a real HTTP server - the same trick as moto_server - so non-Python SDKs, or the google libraries in emulator mode, can use it:

drongo server --port 9090
export STORAGE_EMULATOR_HOST=http://localhost:9090
from google.cloud import storage
from google.auth.credentials import AnonymousCredentials

client = storage.Client(project="p", credentials=AnonymousCredentials())
client.create_bucket("b")  # served by the drongo server over HTTP

Supported services

Service Transport Coverage
Cloud Storage JSON API (default) buckets, objects, multipart/simple/resumable uploads, downloads (incl. Range), list w/ prefix & delimiter, copy/rewrite, metadata
Secret Manager REST (transport="rest") secrets, versions, access, enable/disable/destroy, list

More services are on the roadmap. Adding one is intentionally mechanical - see docs/contributing-a-service.md.

How it works

drongo mirrors moto's architecture, adapted from AWS/botocore to GCP's REST+JSON APIs:

  • mock_gcp starts a reentrant controller that (a) activates the responses HTTP interception layer and (b) patches google.auth.default to return anonymous credentials.
  • Each service ships a models.py (in-memory state), a responses.py (a BaseResponse subclass with one method per API call), and a urls.py (url_bases + url_paths) - the same trio moto uses.
  • Backends are sharded through a BackendDict keyed by project (moto keys by account + region). Globally-namespaced resources like buckets share one backend, exactly as moto special-cases S3.
  • The standalone server replays those same route tables over a real socket.

See docs/architecture.md for the full tour.

Roadmap

  • Pub/Sub
  • Firestore
  • BigQuery
  • Cloud Tasks
  • Resource Manager (projects)
  • gRPC transport interception (currently REST/JSON)

Want one sooner? Open an issue or contribute it - see below.

Contributing

Contributions are very welcome! Adding a service is a great first PR. Start with CONTRIBUTING.md and docs/contributing-a-service.md.

git clone https://github.com/proxyroot/drongo
cd drongo
make install   # editable install + dev tools
make check     # ruff + mypy + pytest

License

Apache License 2.0 - the same license as moto.

Acknowledgements

drongo is heavily inspired by moto and owes its design to that project. It is not affiliated with or endorsed by Google or the moto maintainers.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

drongo-0.1.0.tar.gz (32.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

drongo-0.1.0-py3-none-any.whl (36.0 kB view details)

Uploaded Python 3

File details

Details for the file drongo-0.1.0.tar.gz.

File metadata

  • Download URL: drongo-0.1.0.tar.gz
  • Upload date:
  • Size: 32.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for drongo-0.1.0.tar.gz
Algorithm Hash digest
SHA256 1c49d80341f7ca31f66c955f147d852c4dba246b1632fd1385a47302806b27c1
MD5 504abe653f9418790feee83b3857c1d1
BLAKE2b-256 cdb197bfe5f6ac3556fe88ccb010d32c0987e82711bae351fdf2fec2c6c2d250

See more details on using hashes here.

Provenance

The following attestation bundles were made for drongo-0.1.0.tar.gz:

Publisher: release.yml on proxyroot/drongo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file drongo-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: drongo-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 36.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for drongo-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 3a8b19128ad74af8fa4563e75343c7750be6a77694d869beda1a5dad2031237d
MD5 67d9aaec06f7c3520165f03338a58e7e
BLAKE2b-256 ec37f244204bee652f462774f085e0cc6686b49a6e9882952c0a0cc3b405241c

See more details on using hashes here.

Provenance

The following attestation bundles were made for drongo-0.1.0-py3-none-any.whl:

Publisher: release.yml on proxyroot/drongo

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page