TrustWeave Test Templates
This guide explains how to use the comprehensive in-memory test templates for TrustWeave integration tests.
Overview
The TrustWeave test templates provide complete, working examples of common TrustWeave workflows using only in-memory components. These templates serve as:
- Reference implementations for common use cases
- Starting points for creating new integration tests
- Validation that workflows work correctly with in-memory components
- Examples for adapting to specific configurations (AWS KMS, Ethereum DID, etc.)
Location
The test templates are located in:
1
trust/src/test/kotlin/org/trustweave/integration/InMemoryTrustWeaveIntegrationTest.kt
Key Pattern: Extract Key ID from DID Document
CRITICAL: All templates follow this essential pattern:
- Create DID - This generates a key and stores it in the DID document
- Extract Key ID - Get the key ID from the DID document’s verification method
- Use Extracted Key - Use that key ID when issuing credentials
This ensures proof verification succeeds because the DID document contains the correct verification method.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import org.trustweave.trust.types.DidCreationResult
import org.trustweave.credential.results.IssuanceResult
import org.trustweave.testkit.services.*
import org.trustweave.trust.types.getOrThrowDid
import org.trustweave.trust.types.getOrThrow
import org.trustweave.credential.results.getOrThrow
import org.trustweave.did.resolver.DidResolutionResult
import org.trustweave.did.resolver.errorMessage
import org.trustweave.did.identifiers.extractKeyId
// Step 1: Create DID (generates key and stores in DID document)
val didResult = trustWeave.createDid {
method(DidMethods.KEY)
algorithm(KeyAlgorithms.ED25519)
}
val issuerDid = didResult.getOrThrowDid()
// Step 2: Extract key ID from DID document
val issuerDidDoc = when (val res = trustWeave.configuration.didRegistry.resolve(issuerDid.value)) {
is DidResolutionResult.Success -> res.document
else -> throw IllegalStateException(res.errorMessage ?: "Failed to resolve issuer DID")
}
val keyId = issuerDidDoc.verificationMethod.firstOrNull()?.extractKeyId()
?: throw IllegalStateException("No verification method in issuer DID")
// Step 3: Use extracted key ID for signing
val credential = trustWeave.issue {
credential { /* ... */ }
signedBy(issuerDid) // Key ID automatically resolved from DID
}.getOrThrow()
// For tests, you can use getOrThrowDid() / getOrThrow():
// val issuerDid = trustWeave.createDid { ... }.getOrThrowDid()
// val credential = trustWeave.issue { ... }.getOrThrow()
Available Templates
1. Complete In-Memory Workflow Template
Test: test complete in-memory workflow template
Demonstrates:
- Basic credential issuance and verification
- Trust registry configuration
- Complete verification with all checks
Use Case: Starting point for most integration tests
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import org.trustweave.testkit.services.*
@Test
fun `test complete in-memory workflow template`() = runBlocking {
val kms = InMemoryKeyManagementService()
val trustWeave = TrustWeave.build {
keys {
custom(kms)
signer { data, keyId -> kms.sign(keyId, data) }
}
did { method(DidMethods.KEY) {} }
trust { provider(IN_MEMORY) }
}
// Create DIDs, extract key IDs, issue credential, verify
// ... (see template for full implementation)
}
2. Credential Revocation Workflow Template
Test: test credential revocation workflow template
Demonstrates:
- Issue credential with revocation support
- Revoke credential
- Verify revocation status
Use Case: Testing revocation functionality
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import org.trustweave.credential.results.IssuanceResult
import org.trustweave.credential.results.VerificationResult
import org.trustweave.testkit.services.*
@Test
fun `test credential revocation workflow template`() = runBlocking {
val trustWeave = TrustWeave.build {
// ... setup with revocation provider
revocation { provider(IN_MEMORY) }
}
// Issue credential with revocation
val issuanceResult = trustWeave.issue {
credential { /* ... */ }
signedBy(issuerDid = issuerDid, keyId = keyId)
withRevocation() // Enable revocation status list
}
val credential = when (issuanceResult) {
is IssuanceResult.Success -> issuanceResult.credential
is IssuanceResult.Failure -> throw IllegalStateException(
"Failed to issue credential: ${issuanceResult.allErrors.joinToString()}"
)
}
// Or use getOrThrow() in tests:
// val credential = trustWeave.issue { ... }.getOrThrow()
// Revoke credential
trustWeave.revoke {
credential(credential.id!!)
statusList(statusListId)
}
// Verify revocation
val result = trustWeave.verify {
credential(credential)
checkRevocation()
}
assertTrue(result is VerificationResult.Invalid.Revoked)
}
3. Wallet Storage Workflow Template
Test: test wallet storage workflow template
Demonstrates:
- Create wallet
- Store credentials
- Retrieve credentials
- Query credentials
Use Case: Testing wallet operations
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import org.trustweave.trust.types.WalletCreationResult
@Test
fun `test wallet storage workflow template`() = runBlocking {
// Create wallet
val walletResult = trustWeave.wallet {
id("holder-wallet-1")
holder(holderDid)
inMemory()
enableOrganization()
enablePresentation()
}
val wallet = when (walletResult) {
is WalletCreationResult.Success -> walletResult.wallet
else -> throw IllegalStateException("Failed to create wallet: ${walletResult.reason}")
}
// Or use getOrThrow() in tests:
// val wallet = trustWeave.wallet { ... }.getOrThrow()
// Store credential
credential.storeIn(wallet)
// Retrieve credential
val retrieved = wallet.get(credential.id!!)
// Query credentials
val credentials = wallet.query {
byType("TestCredential")
valid()
}
}
4. Verifiable Presentation Workflow Template
Test: test verifiable presentation workflow template
Demonstrates:
- Store multiple credentials in wallet
- Create verifiable presentation
- Sign presentation with holder’s key
Use Case: Testing presentation creation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Imports: presentationResult, getOrThrow (org.trustweave.trust.types)
@Test
fun `test verifiable presentation workflow template`() = runBlocking {
credential1.storeIn(wallet)
credential2.storeIn(wallet)
val vp = trustWeave.presentationResult {
credentials(credential1, credential2)
holder(holderDid.value)
challenge("challenge-123")
domain("example.com")
}.getOrThrow()
}
5. DID Update Workflow Template
Test: test DID update workflow template
Demonstrates:
- Create DID
- Update DID (add keys, services)
- Issue credential with updated DID
Use Case: Testing DID document updates
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import org.trustweave.trust.types.DidCreationResult
import org.trustweave.testkit.services.*
@Test
fun `test DID update workflow template`() = runBlocking {
// Create DID
val didResult = trustWeave.createDid { /* ... */ }
val issuerDid = when (didResult) {
is DidCreationResult.Success -> didResult.did
is DidCreationResult.Failure -> {
val msg = when (didResult) {
is DidCreationResult.Failure.MethodNotRegistered ->
"method ${didResult.method} not registered; available: ${didResult.availableMethods.joinToString()}"
is DidCreationResult.Failure.KeyGenerationFailed -> didResult.reason
is DidCreationResult.Failure.DocumentCreationFailed -> didResult.reason
is DidCreationResult.Failure.InvalidConfiguration -> didResult.reason
is DidCreationResult.Failure.Other -> didResult.reason
}
throw IllegalStateException("Failed to create DID: $msg")
}
}
// Generate new key
val newKey = kms.generateKey("Ed25519")
trustWeave.updateDid {
did(issuerDid.value)
method(DidMethods.KEY)
addKey {
id("${issuerDid.value}#key-2")
type("Ed25519VerificationKey2020")
publicKeyJwk(newKey.publicKeyJwk ?: emptyMap())
}
}
// Issue credential with updated DID
// ... (see template for full implementation)
}
6. Blockchain Anchoring Workflow Template
Test: test blockchain anchoring workflow template
Demonstrates:
- Configure blockchain anchor
- Issue credential with anchoring
- Verify anchor
Use Case: Testing blockchain anchoring
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import org.trustweave.testkit.services.*
@Test
fun `test blockchain anchoring workflow template`() = runBlocking {
val trustWeave = TrustWeave.build {
// ... setup
anchor {
chain("testnet:inMemory") {
provider(IN_MEMORY) // Use in-memory anchor client
}
}
credentials {
defaultChain("testnet:inMemory")
}
}
// Issue credential with anchoring
val issuanceResult = trustWeave.issue {
credential { /* ... */ }
signedBy(issuerDid = issuerDid, keyId = keyId)
anchor("testnet:inMemory")
}
val credential = when (issuanceResult) {
is IssuanceResult.Success -> issuanceResult.credential
is IssuanceResult.Failure -> throw IllegalStateException(
"Failed to issue credential: ${issuanceResult.allErrors.joinToString()}"
)
}
// Cryptographic verification (anchoring is checked separately via `trustWeave.blockchains` / anchor ref on the credential)
trustWeave.verify {
credential(credential)
checkRevocation()
}
}
7. Smart Contract Workflow Template
Test: test smart contract workflow template
Demonstrates:
- Issue contract as verifiable credential
- Anchor contract to blockchain
- Verify contract credential
Use Case: Testing smart contract workflows
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Test
fun `test smart contract workflow template`() = runBlocking {
// Issue contract as credential
val issuanceResult = trustWeave.issue {
credential {
type(CredentialType.Custom("SmartContractCredential"), CredentialType.VerifiableCredential)
// ... contract details
}
signedBy(issuerDid = issuerDid, keyId = keyId)
anchor("testnet:inMemory")
}
val contractCredential = when (issuanceResult) {
is IssuanceResult.Success -> issuanceResult.credential
is IssuanceResult.Failure -> throw IllegalStateException(
"Failed to issue credential: ${issuanceResult.allErrors.joinToString()}"
)
}
// Verify contract credential (use `trustWeave.blockchains.read` if you need to assert on-chain anchor data)
trustWeave.verify {
credential(contractCredential)
checkRevocation()
}
}
8. External Services Template
Test: test with external services template
Demonstrates:
- Using
@RequiresPluginannotation - Automatic test skipping when credentials unavailable
- Testing with real external services
Use Case: Testing with AWS KMS, Ethereum DID, etc.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import org.trustweave.testkit.services.*
@Test
@RequiresPlugin("aws-kms", "ethr-did") // List all required plugins
fun `test with external services template`() = runBlocking {
// This test will be automatically skipped if AWS credentials
// or Ethereum RPC URL are not available
val trustWeave = TrustWeave.build {
keys { provider("aws-kms") } // Requires AWS credentials
did { method(ETHR) {} } // Requires ETHEREUM_RPC_URL
trust { provider(IN_MEMORY) }
}
// Test implementation here...
// If you reach here, all required env vars are available
}
Adapting Templates for Specific Configurations
To adapt a template for a specific configuration (e.g., AWS KMS, Ethereum DID):
- Copy the template test
- Replace in-memory components with your specific providers
- Add
@RequiresPluginannotation with required plugins - Follow the same key extraction pattern
Example: Adapting for AWS KMS and Ethereum DID
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import org.trustweave.trust.types.DidCreationResult
import org.trustweave.did.resolver.DidResolutionResult
import org.trustweave.did.resolver.errorMessage
import org.trustweave.credential.results.IssuanceResult
import org.trustweave.credential.results.VerificationResult
import org.trustweave.testkit.services.*
@Test
@RequiresPlugin("aws-kms", "ethr-did")
fun `test workflow with AWS KMS and Ethereum DID`() = runBlocking {
val trustWeave = TrustWeave.build {
keys { provider("aws-kms") } // AWS KMS instead of in-memory
did { method(ETHR) {} } // Ethereum DID instead of key DID
trust { provider(IN_MEMORY) }
}
// Same pattern: create DID, extract key ID, issue credential
val didResult = trustWeave.createDid {
method(ETHR)
algorithm(KeyAlgorithms.ED25519)
}
val issuerDid = when (didResult) {
is DidCreationResult.Success -> didResult.did
is DidCreationResult.Failure -> {
val msg = when (didResult) {
is DidCreationResult.Failure.MethodNotRegistered ->
"method ${didResult.method} not registered; available: ${didResult.availableMethods.joinToString()}"
is DidCreationResult.Failure.KeyGenerationFailed -> didResult.reason
is DidCreationResult.Failure.DocumentCreationFailed -> didResult.reason
is DidCreationResult.Failure.InvalidConfiguration -> didResult.reason
is DidCreationResult.Failure.Other -> didResult.reason
}
throw IllegalStateException("Failed to create DID: $msg")
}
}
// Extract key ID (same pattern)
val issuerDidDoc = when (val res = trustWeave.configuration.didRegistry.resolve(issuerDid.value)) {
is DidResolutionResult.Success -> res.document
else -> throw IllegalStateException(res.errorMessage ?: "Failed to resolve issuer DID")
}
val keyId = issuerDidDoc.verificationMethod.firstOrNull()?.extractKeyId()
?: throw IllegalStateException("No verification method in issuer DID")
// Issue credential (same pattern)
val issuanceResult = trustWeave.issue {
credential { /* ... */ }
signedBy(issuerDid = issuerDid, keyId = keyId) // Same pattern!
}
val credential = when (issuanceResult) {
is IssuanceResult.Success -> issuanceResult.credential
is IssuanceResult.Failure -> throw IllegalStateException(
"Failed to issue credential: ${issuanceResult.allErrors.joinToString()}"
)
}
// Verify (same pattern)
val result = trustWeave.verify {
credential(credential)
requireTrust(requireNotNull(trustWeave.configuration.trustRegistry))
}
assertTrue(result is VerificationResult.Valid)
}
Common Patterns
Pattern 1: Extract Key ID from DID Document
1
2
3
4
5
6
7
8
9
10
11
import org.trustweave.did.identifiers.extractKeyId
import org.trustweave.did.resolver.DidResolutionResult
import org.trustweave.did.resolver.errorMessage
val issuerDidDoc = when (val res = trustWeave.configuration.didRegistry.resolve(issuerDid)) {
is DidResolutionResult.Success -> res.document
else -> throw IllegalStateException(res.errorMessage ?: "Failed to resolve issuer DID")
}
val keyId = issuerDidDoc.verificationMethod.firstOrNull()?.extractKeyId()
?: throw IllegalStateException("No verification method in issuer DID")
Pattern 2: Issue Credential with Extracted Key
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
val issuanceResult = trustWeave.issue {
credential {
id("https://example.com/credential-1")
type("TestCredential")
issuer(issuerDid)
subject {
id(holderDid)
"test" to "value"
}
issued(Instant.now())
}
signedBy(issuerDid = issuerDid, keyId = keyId) // Use extracted key ID
}
val credential = when (issuanceResult) {
is IssuanceResult.Success -> issuanceResult.credential
is IssuanceResult.Failure -> throw IllegalStateException(
"Failed to issue credential: ${issuanceResult.allErrors.joinToString()}"
)
}
// In tests, use getOrThrow():
// val credential = trustWeave.issue { ... }.getOrThrow()
Pattern 3: Verify Credential with All Checks
1
2
3
4
5
6
7
8
9
10
import org.trustweave.credential.results.VerificationResult
val result = trustWeave.verify {
credential(credential)
requireTrust(requireNotNull(trustWeave.configuration.trustRegistry))
checkExpiration()
checkRevocation()
}
assertTrue(result is VerificationResult.Valid, "Credential should verify")
Best Practices
- Always Extract Key ID from DID Document - Never generate a new key separately
- Use In-Memory Components First - Validate workflow with in-memory components before testing with external services
- Add
@RequiresPluginfor External Services - Automatically skip tests when credentials unavailable - Follow Template Structure - Use templates as starting points, maintain consistent patterns
- Test All Workflow Steps - Issue, verify, revoke, update, etc.
- Use Descriptive Test Names - Use backtick names like
`test workflow description`()
Troubleshooting
Issue: Proof Verification Fails
Problem: proofValid is false in verification result
Solution: Ensure you’re extracting the key ID from the DID document, not generating a new key:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import org.trustweave.did.resolver.DidResolutionResult
import org.trustweave.did.resolver.errorMessage
// Wrong: generating a new key
val newKey = kms.generateKey("Ed25519")
val issuanceResult1 = trustWeave.issue {
signedBy(issuerDid = issuerDid, keyId = newKey.id.value) // Key not in DID document!
}
// Wrong key id typically surfaces as IssuanceResult.Failure.AdapterError or InvalidRequest
// Correct: extract key from DID document
val issuerDidDoc = when (val res = trustWeave.configuration.didRegistry.resolve(issuerDid.value)) {
is DidResolutionResult.Success -> res.document
else -> throw IllegalStateException(res.errorMessage ?: "Failed to resolve issuer DID")
}
val keyId = issuerDidDoc.verificationMethod.firstOrNull()?.extractKeyId()
?: throw IllegalStateException("No verification method in issuer DID")
val issuanceResult2 = trustWeave.issue {
signedBy(issuerDid = issuerDid, keyId = keyId) // Key matches DID document!
}
val credential = when (issuanceResult2) {
is IssuanceResult.Success -> issuanceResult2.credential
else -> throw IllegalStateException(
"Failed to issue credential: ${issuanceResult2.allErrors.joinToString()}"
)
}
Issue: Revocation Check Not Working
Problem: notRevoked is always true even after revocation
Solution: Ensure statusListManager is configured and passed to verifier:
1
2
3
4
5
6
7
8
9
10
11
import org.trustweave.testkit.services.*
val trustWeave = TrustWeave.build {
// ... setup
revocation { provider(IN_MEMORY) } // Must configure revocation provider
}
// VerificationDsl automatically passes statusListManager to verifier
val result = trustWeave.verify {
credential(credential)
checkRevocation() // Must enable revocation check
}
Issue: Presentation creation fails
Problem: PresentationResult.Failure.AdapterNotReady or proof errors.
Solution: Configure CredentialService on TrustWeave.build { ... } and use trustWeave.presentationResult { ... } (see Create presentations).
Next Steps
- Test Patterns](test-patterns.md) - Common test patterns
- Integration Testing](integration-testing.md) - Integration test best practices
- Plugin Credential Handling](plugin-credential-handling.md) - Handling external service credentials
- TrustWeave-testkit Module](../../modules/trustweave-testkit.md) - Testkit components overview