Conformance and smoke tests#
Two standalone test binaries ship with the Thumbnail Service, each with its own job. The smoke test proves a deployment came up after an install or upgrade and stops at the first failure; it runs as a Helm test hook from the service image. The conformance test certifies a running deployment against the published REST and gRPC contract — every case runs so one invocation reports the full extent of any non-conformance — and is published to NGC as its own image and Helm chart so customers can run it against their own deployments.
Neither test asserts that a requested thumbnail was actually generated. Generation is asynchronous work on the worker, and both tests deliberately stop at the immediate API response.
Smoke test#
The smoke test executes a compact end-to-end API flow against the REST surface:
Health check —
GET /health.Associate a synthetic thumbnail with the configured source file —
POST /v1alpha/associations.Read the source file’s thumbnails back and verify the association is returned —
GET /v1alpha/thumbnails.Remove the association —
DELETE /v1alpha/associations.
It exits 0 when every check passes and 1 when any mandatory check fails. Because it never calls CreateThumbnails, the source file it is pointed at does not need to exist in storage — the association endpoints only write and read metadata keyed on an address.
Running the smoke test as a Helm hook#
The chart renders an opt-in Job annotated for the test, post-install, and post-upgrade hooks. It runs /app/thumbnail-smoke-test from the service image, so no separate image is needed:
smokeTest:
enabled: true
sourceFile: "https://acct.blob.core.windows.net/assets/smoke/source-image.png"
waitRetries: 10
waitInterval: 5
requestTimeout: 15
ttlSecondsAfterFinished: 1800
# run the hook against an installed release
helm test thumbnail-service -n storage-apis
# inspect the Job's output
kubectl logs -n storage-apis job/thumbnail-service-smoke-test
Value |
Default |
Description |
|---|---|---|
|
|
Render the smoke-test Job. |
|
|
Optional overrides; each falls back to the service image and the root |
|
|
Explicit API base URL. Empty uses the in-cluster Service, |
|
|
Dedicated ServiceAccount; empty uses the service’s. |
|
|
Source address the test associates against. |
|
|
Readiness retries and the interval between them, in seconds. |
|
|
Per-request timeout, in seconds. |
|
|
Completed Job cleanup TTL; |
|
|
Additional Job annotations (hook keys are stripped), pod annotations, and pod labels. |
|
requests |
Container resources; matches the orchestrator’s own defaults, since the test exercises the same REST/gRPC surface. |
In access-token-file identity mode the Job runs the same provisioner sidecar as the service and reads the token from the shared volume; in client-credentials mode it mounts the same Secret. See Outbound service identity.
Running the smoke test directly#
# against a port-forwarded or externally reachable REST endpoint
thumbnail-smoke-test \
--service-url http://localhost:3000 \
--source-file https://acct.blob.core.windows.net/assets/smoke/source-image.png \
--auth-token "$BEARER_TOKEN"
Argument |
Environment variable |
Default |
|---|---|---|
|
|
required |
|
|
empty |
|
|
empty — a raw bearer string, or JSON with an |
|
|
required |
|
|
|
|
|
|
|
|
|
Conformance test#
The conformance test is a black-box suite: it validates wire paths, status codes, response shapes, and the documented error mapping of a deployed Thumbnail Service on both transports. It runs every independent case, prints a [PASS]/[FAIL] line per case tagged [REST] or [gRPC], and ends with a summary of pass/fail counts and per-case timing. The process exits 0 only when every selected case passed; a failure or a skip exits 1.
The image nvcr.io/nvidia/omniverse/thumbnail-conformance-test and the chart thumbnail-conformance-test are built and published to NGC by CI but are never run automatically against a live deployment — you run them when you want to certify one.
Before you run it#
--rest-urlis required for every suite, including gRPC-only runs. Before any case runs, the suite fetches the served OpenAPI document from/api-docs/openapi.json, readsspecifications.maxItems, and compares it with the independently documented bound of1000. Only a match allows the over-bound probe (advertised + 1specifications). A lower or higher advertised value fails naming both numbers and sends no probe; a missing or malformed document makes the run unverifiable with a nonzero exit. Nothing is ever tested at the bound — that could enqueue 1,000 conversions.--source-filemust be an object that really exists in storage. The associate, read, and disassociate cases pass against any address, butCreateThumbnailsresolves the source with a storageStat, so its acceptance cases fail with404/NOT_FOUNDunless the address resolves. The summary then names--source-fileas the cause rather than reporting a bare failure count.The run leaves generated thumbnails behind. Three acceptance cases per transport — a valid specification with omitted quality, PNG quality
200, and GIF quality200— can generate real thumbnails, and the suite cannot remove them: the destination is rendered by the deployment’s ownTHUMBNAIL_PATH_TEMPLATEfrom values the suite does not have, finding it would mean waiting on asynchronous generation, andDisassociateThumbnailremoves metadata without deleting a blob. Point--source-fileat a test object in a location where leftover artifacts are acceptable.Against a non-conformant deployment, the bound case can make the source unreadable. A deployment that accepts the over-bound probe may write one association per specification onto
--source-file; past enough entries, storage refuses to return the metadata in one response and every laterGET /v1alpha/thumbnailsandDELETE /v1alpha/associationsfor that address fails with502. Against a conformant deployment the request is refused with400/INVALID_ARGUMENTand nothing is written. Pick a source you are willing to lose; a default--test-suite=allrun exercises this case once per transport.
Parameters#
CLI flag |
Environment variable |
Required |
Description |
|---|---|---|---|
|
|
Every suite, including |
HTTP base URL, for example |
|
|
For |
gRPC endpoint, for example |
|
|
No |
Enable TLS on the gRPC channel. Default |
|
|
No |
|
|
|
Yes |
Existing storage object the suite associates against and generates from. |
|
|
No |
REST path polled by the readiness wait. Default |
|
|
No |
Per-request timeout (humantime). Default |
|
|
No |
Readiness retry count. Default |
|
|
No |
Interval between readiness retries (humantime). Default |
Authentication modes#
Provide a bearer token through exactly one of the following, or omit all three to run unauthenticated — valid only against a deployment whose storage does not enforce authorization:
Direct bearer token —
--bearer-token/BEARER_TOKEN.Access-token file —
--access-token-file/ACCESS_TOKEN_FILE, a JSON file with anaccess_tokenfield as written by a token-provisioner sidecar. Read once at startup.OAuth2 client credentials via OpenID Connect discovery —
--oauth2-openid-configuration-uri,--oauth2-client-id,--oauth2-client-secret(or--oauth2-client-secret-file), and--oauth2-client-scope. The token endpoint is resolved from the discovery document.
What the suite covers#
Every request-level rejection is asserted on both transports, because the two are supposed to agree about which requests are legal and a suite that tested different things on each side could not detect them diverging.
Case |
REST |
gRPC |
|---|---|---|
Associate a thumbnail, read it back, disassociate it |
|
|
Disassociate again (idempotent) |
|
|
Associate with a blank |
|
|
Associate with no |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Health |
|
standard |
Readiness is checked on every selected transport before its cases — REST through --ready-path, gRPC through the standard health service — within --wait-retries and --wait-interval. In an all run, failed REST readiness prevents the REST cases but preserves gRPC coverage when the OpenAPI preflight and gRPC readiness succeed; the overall run still fails.
Run faults versus contract failures#
A misconfigured run and a non-conformant deployment produce the same failure count, so the summary adds a [WARN] block per cause naming the flag to change and the cases it accounts for. Classified faults, none of which certify conformance:
--source-filedid not resolve — a404that carries the API’sErrorResponsebody, so the route exists and the object does not.Credentials were rejected —
401orUNAUTHENTICATED.Access was denied —
403orPERMISSION_DENIED; check caller permissions and token scopes for the API and the source, this does not mean the token is invalid.The endpoint is not serving this API — a
404without theErrorResponsebody, orUNIMPLEMENTEDover gRPC.Client timeout — an incomplete observation naming
--http-timeout, distinct from a server-returned error.Unverifiable OpenAPI contract — names
/api-docs/openapi.jsonand--rest-url.
Association cases whose prerequisite failed are reported as skipped with their reason. Skips are excluded from the pass count and prevent certification even when nothing else failed.
Running the conformance chart#
The thumbnail-conformance-test chart renders a one-shot Job and a ServiceAccount. Install it on demand into the namespace that can reach the deployment under test:
conformanceTest:
restUrl: "http://thumbnail-service.storage-apis.svc.cluster.local:3000"
grpcUrl: "http://thumbnail-service.storage-apis.svc.cluster.local:50051"
testSuite: "all"
sourceFile: "https://acct.blob.core.windows.net/assets/conformance/source.png"
httpTimeout: "30s"
waitRetries: 10
waitInterval: "5s"
# Exactly one serviceIdentity mode, or none for an unauthenticated deployment
serviceIdentity:
bearerToken:
enabled: true
secretRef:
name: "thumbnail-conformance-token"
key: "BEARER_TOKEN"
conformance-values.yaml
# pull the chart from NGC
helm fetch https://helm.ngc.nvidia.com/nvidia/omniverse/charts/thumbnail-conformance-test-{VERSION}.tgz --username='$oauthtoken' --password=${NGC_API_KEY}
tar -xvf thumbnail-conformance-test-{VERSION}.tgz
# render and run
helm template conformance ./thumbnail-conformance-test -f conformance-values.yaml
helm install conformance ./thumbnail-conformance-test -f conformance-values.yaml --namespace storage-apis
# read the verdict; the Job has backoffLimit 0 and is cleaned up after 600 seconds
kubectl logs -n storage-apis job/conformance-thumbnail-conformance-test
restUrl and sourceFile are required at render time; grpcUrl is required unless testSuite is rest. At most one authentication block may be set — a Secret-backed bearer token, client credentials, or an access-token file — and none is valid against a deployment that runs without storage authorization. The chart’s post-install notes repeat the over-bound cost disclosure above.
Running the conformance test directly#
thumbnail-conformance-test \
--rest-url http://localhost:3000 \
--grpc-url http://localhost:50051 \
--source-file "https://acct.blob.core.windows.net/assets/conformance/source.png" \
--bearer-token "$BEARER_TOKEN"
See also#
Thumbnail Service Configuration — installing the release the tests run against, and the manual end-to-end verification that does prove a thumbnail was generated.
Authenticating with an OpenID Connect Identity Provider — the identity modes both tests share with the service.
Association metadata and queries — why an over-bound acceptance writes one association per specification onto the source.
Troubleshooting — interpreting
401,403, and404outcomes.