
A Crossplane testing framework that leverages crossplane render and crossplane beta validate commands to test if Compositions render correctly against Claims or XRs, and if the rendered manifests validate against their schemas.
To bridge the testing gap between function-level testing and full e2e testing: you can run render and validate locally with real Compositions and Functions, without a live cluster or real resource creation. It was originally developed by Elastic, where it is currently being used for mock/integration testing of a large infrastructure.
crossplane render using various combinations of XRs/Claims, Compositions and Functions, and assert on the output.crossplane beta validate.Yes. xprin runs entirely locally in a mock environment. It does not create or modify real resources; it only runs crossplane render and crossplane beta validate on the inputs you provide, so you can safely point at production data.
To extend coverage, by creating as many test cases we need without having to provide testdata for each one of them.
The testsuite files are in YAML
tests:
- name: "Successful test with hooks, validation, and assertions"
patches:
xrd: ../../aws/xrd.yaml
inputs:
xr: ../../aws/xr.yaml
composition: ../../aws/composition.yaml
functions: ../../aws/functions.yaml
observed-resources: ../../aws/observed
crds:
- ../../aws/xrd.yaml
- ../../aws/crossplane.yaml
hooks:
pre-test:
- name: "this is a pre-test hook"
run: echo "hello"
post-test:
- name: "this is a post-test hook"
run: echo "bye"
assertions:
xprin:
- name: "Number of resources"
type: "Count"
value: 3
- name: "SecurityGroup should exist"
type: "Exists"
resource: "SecurityGroup/platform-aws-sg"
diff:
- name: "Full render matches golden (using diff)"
expected: golden_full_render.yaml
The output is similar to go test
➜ xprin test simple_test_xprin.yaml -v --show-render --show-validate --show-assertions --show-hooks
=== RUN Successful test with hooks, validation, and assertions
--- PASS: Successful test with hooks, validation, and assertions (1.31s)
Pre-test Hooks:
[✓] this is a pre-test hook
hello
Render:
├── XAWSInfrastructure/platform-aws
├── Cluster/platform-aws-rds
└── SecurityGroup/platform-aws-sg
Validate:
[✓] aws.example.com/v1, Kind=XAWSInfrastructure, platform-aws validated successfully
[✓] rds.aws.upbound.io/v1beta1, Kind=Cluster, platform-aws-rds validated successfully
[✓] ec2.aws.upbound.io/v1beta1, Kind=SecurityGroup, platform-aws-sg validated successfully
Total 3 resources: 0 missing schemas, 3 success cases, 0 failure cases
Assertions:
[✓] Number of resources - found 3 resources (as expected)
[✓] SecurityGroup should exist - resources found: SecurityGroup/platform-aws-sg
[✓] Full render matches golden (using diff) - files match
Total: 3 assertions, 3 successful, 0 failed, 0 errors
Post-test Hooks:
[✓] this is a post-test hook
bye
PASS
ok examples/mytests/0_e2e/used_in_readme_xprin.yaml 1.314s
See Getting Started and Examples for more.
Crossplane + πριν, before Crossplane! (backstory)
When xprin runs a test case, it follows this specific sequence:
xprin-helpers convert-claim-to-xrxprin-helpers patch-xrcrossplane render with the XR, Composition, and Functionscrossplane beta validate on the rendered outputid, copy outputs to artifacts directory for cross-test referencesVisual flow (high-level steps):
flowchart TD
A["Setup
Pre-test Hooks"] --> B[Convert Claim to XR]
A --> C[Patch XR]
B --> D[Render]
C --> D
D --> E[Validate]
D --> F[Assertions]
E --> G[Post-test Hooks
Export Artifacts]
F --> G
style A fill:#3b82f6,stroke:#1e40af,stroke-width:2px,color:#fff
style B fill:#f97316,stroke:#c2410c,stroke-width:2px,color:#fff
style C fill:#f97316,stroke:#c2410c,stroke-width:2px,color:#fff
style D fill:#a855f7,stroke:#7e22ce,stroke-width:2px,color:#fff
style E fill:#a855f7,stroke:#7e22ce,stroke-width:2px,color:#fff
style F fill:#10b981,stroke:#047857,stroke-width:2px,color:#fff
style G fill:#3b82f6,stroke:#1e40af,stroke-width:2px,color:#fff
For the full flow with decision points and optional steps, see How It Works.
The flow ensures that:
- Pre-test hooks can set up the environment, patch inputs or validate them before processing
- Claims are automatically converted to XRs for compatibility with crossplane render
- XRs can be enhanced with defaults and connection secrets before rendering
- The rendered output is validated against schemas if CRDs are available
- Assertions validate rendered resources declaratively (count, existence, field checks) after validation
- Post-test hooks can clean up and perform additional validation after assertions
- Test outputs can be exported as artifacts (when id is set) and referenced by later tests via .Tests.{test-id} template variables for test chaining
# Test Compositions
xprin test <targets>
# Check dependencies and configuration
xprin check
# Show version
xprin version
xprin-helpers: Helper utilities for converting Claims to XRs and patching XRs - convert-claim-to-xr: Convert Claims to XRs - patch-xr: Apply patches to XRs
See Installation for detailed requirements. At minimum: Crossplane CLI and Docker daemon.
—
$ claude mcp add xprin \
-- python -m otcore.mcp_server <graph>