GcpCompute is built to be tested without GCP, credentials, or the network.
Two seams make that possible:
req_options: [adapter: fun]—Req's native adapter option lets you answer requests from an in-memory routing table instead of the wire.GcpCompute.TokenProvider.Static—GcpCompute.Config.local/1defaults to it, so no Goth and no real token are required.
A minimal stubbed config
config =
GcpCompute.Config.local!(
project: "test-project",
zone: "us-central1-a",
req_options: [
retry: false,
adapter: fn request ->
response =
case {request.method, request.url.path} do
{:get, "/compute/v1/projects/test-project/zones/us-central1-a/instances/w"} ->
%Req.Response{status: 200, body: %{"name" => "w", "status" => "RUNNING"}}
_ ->
%Req.Response{status: 404, body: %{"error" => %{"code" => 404}}}
end
{request, response}
end
]
)
{:ok, instance} = GcpCompute.get_instance(config, "w")The adapter returns {request, %Req.Response{}} — and the response body is an
already-decoded map (no JSON round-trip needed).
A reusable routing-table helper
The library's own test suite uses a small helper,
test/support/req_stub.ex,
that turns a %{ {method, path} => response } map into a config:
config =
GcpCompute.ReqStub.config(%{
{:post, "/compute/v1/projects/test-project/zones/us-central1-a/instances"} =>
{200, GcpCompute.ReqStub.operation("op-1", "PENDING")},
{:post, "/compute/v1/projects/test-project/zones/us-central1-a/operations/op-1/wait"} =>
{200, GcpCompute.ReqStub.operation("op-1", "DONE")},
{:get, "/compute/v1/projects/test-project/zones/us-central1-a/instances/worker-1"} =>
{200, GcpCompute.ReqStub.instance("worker-1")}
})
assert {:ok, %GcpCompute.Instance{name: "worker-1"}} =
GcpCompute.insert_instance_and_wait(config, name: "worker-1", machine_type: "e2-micro")Copy it into your own test/support/ if you build on top of GcpCompute.
Simulating failures
- API error — return a non-2xx status with the Google error envelope; it
becomes
{:error, %GcpCompute.Error{reason: :api_error, status: 403}}. - Transport error — return an exception from the adapter (e.g.
%Mint.TransportError{reason: :econnrefused}); it becomes{:error, %GcpCompute.Error{reason: :transport}}. - Token failure — set
token_provider: {GcpCompute.TokenProvider.Static, fn -> {:error, :no_creds} end}; the call short-circuits with{:error, %GcpCompute.Error{reason: :token_fetch_failed}}before any request is made.
Asserting telemetry
:telemetry.attach("t", [:gcp_compute, :request, :stop], &handler/4, self())
# ... make a call ...
assert_receive {:telemetry, _measurements, %{method: :get, result: :ok}}