Skip to main content

Crate cloud_sdk_testkit

Crate cloud_sdk_testkit 

Source
Expand description

provider-neutral no_std testkit for cloud-sdk.
Deterministic mock transport, bounded response fixtures, and adversarial corpora.


cloud-sdk Rust crate overview

§cloud-sdk-testkit

Provider-neutral testing support for the main cloud-sdk crate and its provider crates. The default graph is no_std, allocation-free, network-free, filesystem-free, and runtime-free.

[dev-dependencies]
cloud-sdk = "0.20.0"
cloud-sdk-testkit = "0.15.2"

§Mock Transport

use cloud_sdk::Method;
use cloud_sdk::transport::{BlockingTransport, RequestTarget, TransportRequest};
use cloud_sdk_testkit::{
    ExpectedRequest, FixtureBody, MockExchange, MockTransport, ResponseFixture,
};

let Ok(target) = RequestTarget::new("/servers?page=1") else {
    return;
};
let Ok(body) = FixtureBody::new(br#"{"servers":[]}"#) else {
    return;
};
let exchanges = [MockExchange::new(
    ExpectedRequest::new(Method::Get, target),
    ResponseFixture::success(body),
)];
let mut transport = MockTransport::new(&exchanges);
let mut output = [0_u8; 64];

let Ok(response) = transport.send(
    TransportRequest::new(Method::Get, target),
    &mut output,
) else {
    return;
};

assert_eq!(response.status().get(), 200);
assert_eq!(response.body(), br#"{"servers":[]}"#);
assert!(transport.is_complete());

The same mock implements the executor-neutral async contract without adding a runtime dependency:

use cloud_sdk::Method;
use cloud_sdk::transport::{AsyncTransport, RequestTarget, TransportRequest};
use cloud_sdk_testkit::{
    ExpectedRequest, FixtureBody, MockExchange, MockTransport, ResponseFixture,
};

let Ok(target) = RequestTarget::new("/servers/42") else { return };
let Ok(body) = FixtureBody::new(br#"{"id":42}"#) else { return };
let exchanges = [MockExchange::new(
    ExpectedRequest::new(Method::Get, target),
    ResponseFixture::success(body),
)];
let mut transport = MockTransport::new(&exchanges);
let mut output = [0_u8; 32];
let Ok(response) = AsyncTransport::send(
    &mut transport,
    TransportRequest::new(Method::Get, target),
    &mut output,
).await else { return };

assert_eq!(response.body(), br#"{"id":42}"#);

Each exchange is consumed only after the request matches and the complete response body fits. Method, target, body, exhaustion, and response-capacity failures are distinct and payload-free. Debug output redacts request targets, request bodies, and response bodies.

§Fixture Builders

ResponseFixture builds deterministic success, paginated, action, rate-limit, and error responses. PaginationFixture, ActionFixture, and RateLimitFixture reject incoherent metadata before a fixture can be used. Use ResponseFixture::with_rate_limit to attach validated transport metadata to paginated, action, success, or error responses.

FixtureBody supports borrowed bytes and compact repeated-byte bodies up to 8 MiB plus one byte. Writes preflight capacity and leave undersized destination buffers unchanged.

§Adversarial Corpus

adversarial_corpus() returns reusable cases for:

  • malformed JSON;
  • additive unknown fields;
  • missing required fields;
  • an oversized response represented without an 8 MiB static allocation;
  • invalid pagination metadata;
  • an invalid action state and progress value.

Provider crates consume applicable cases in their own parser tests. The Hetzner Serde boundary exercises this corpus without making the testkit depend on cloud-sdk-hetzner.

§Security Notes

This crate is test infrastructure, not a production transport. Exact request matching uses ordinary byte equality and must not be exposed as a remote secret comparison oracle. Authentication, base URLs, headers, timeout policy, TLS, retry behavior, and secret ownership remain responsibilities of concrete transport adapters.

The testkit stores only borrowed expectations and fixture bodies. Callers must keep borrowed data alive and must still sanitize secret-bearing test buffers when their threat model requires it.

Structs§

ActionFixture
Action metadata for polling tests.
AdversarialFixture
Named adversarial response body.
ExpectedRequest
Expected request fields for one mock exchange.
MockExchange
One expected request and deterministic response.
MockTransport
Ordered no-allocation mock implementation of BlockingTransport.
PaginationFixture
Pagination metadata for a deterministic response.
RateLimitFixture
Rate-limit metadata fixture.
ResponseFixture
Provider-neutral response body plus optional interpreted metadata.

Enums§

ActionState
Provider-neutral action lifecycle fixture.
AdversarialKind
Adversarial response category.
FixtureBody
Borrowed or compact repeated-byte fixture body.
FixtureBodyError
Fixture body construction or write error.
FixtureKind
Fixture response category.
FixtureMetadataError
Fixture metadata validation error.
MockError
Deterministic mock transport failure.
ResponseFixtureError
Response fixture construction error.

Constants§

DEFAULT_RESPONSE_LIMIT
Common response limit used by the initial provider response boundary.
MAX_FIXTURE_BODY_BYTES
Maximum fixture body length, including one byte beyond the common 8 MiB response-policy ceiling for oversized-input tests.

Functions§

adversarial_corpus
Creates the fixed six-case adversarial response corpus.