Trust Layer Test Templates
This guide explains how to use the comprehensive in-memory test templates for trust layer integration tests.
Overview
The trust layer 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
core/TrustWeave-trust/src/test/kotlin/com/geoknoesis/TrustWeave/integration/InMemoryTrustLayerIntegrationTest.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
import com.trustweave.trust.types.DidCreationResult
import com.trustweave.trust.types.IssuanceResult
import com.trustweave.testkit.getOrFail
// Step 1: Create DID (generates key and stores in DID document)
val didResult = trustLayer.createDid {
method(DidMethods.KEY)
algorithm(KeyAlgorithms.ED25519)
}
val issuerDid = when (didResult) {
is DidCreationResult.Success -> didResult.did
else -> throw IllegalStateException("Failed to create DID: ${didResult.reason}")
}
// Step 2: Extract key ID from DID document
val issuerDidDoc = trustLayer.dsl().getConfig().registries.didRegistry.resolve(issuerDid.value)?.document
?: throw IllegalStateException("Failed to resolve issuer DID")
val keyId = issuerDidDoc.verificationMethod.firstOrNull()?.id?.substringAfter("#")
?: throw IllegalStateException("No verification method in issuer DID")
// Step 3: Use extracted key ID for signing
val issuanceResult = trustLayer.issue {
credential { /* ... */ }
signedBy(issuerDid = issuerDid.value, keyId = keyId) // MUST match key in DID document
}
val credential = when (issuanceResult) {
is IssuanceResult.Success -> issuanceResult.credential
else -> throw IllegalStateException("Failed to issue credential: ${issuanceResult.reason}")
}
// For tests, you can use getOrFail() helper:
// val issuerDid = trustLayer.createDid { ... }.getOrFail()
// val credential = trustLayer.issue { ... }.getOrFail()
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
@Test
fun `test complete in-memory workflow template`() = runBlocking {
val kms = InMemoryKeyManagementService()
val trustLayer = trustLayer {
keys {
custom(kms)
signer { data, keyId -> kms.sign(keyId, data) }
}
did { method(DidMethods.KEY) {} }
trust { provider("inMemory") }
}
// 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
@Test
fun `test credential revocation workflow template`() = runBlocking {
val trustLayer = trustLayer {
// ... setup with revocation provider
revocation { provider("inMemory") }
}
// Issue credential with revocation
val issuanceResult = trustLayer.issue {
credential { /* ... */ }
signedBy(issuerDid = issuerDid.value, keyId = keyId)
withRevocation() // Enable revocation status list
}
val credential = when (issuanceResult) {
is IssuanceResult.Success -> issuanceResult.credential
else -> throw IllegalStateException("Failed to issue credential: ${issuanceResult.reason}")
}
// Or use getOrFail() in tests:
// val credential = trustLayer.issue { ... }.getOrFail()
// Revoke credential
trustLayer.revoke {
credential(credential.id!!)
statusList(statusListId)
}
// Verify revocation
val result = trustLayer.verify {
credential(credential)
checkRevocation()
}
assertFalse(result.notRevoked)
}
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
@Test
fun `test wallet storage workflow template`() = runBlocking {
// Create wallet
import com.trustweave.trust.types.WalletCreationResult
import com.trustweave.testkit.getOrFail
val walletResult = trustLayer.wallet {
id("holder-wallet-1")
holder(holderDid.value)
inMemory()
enableOrganization()
enablePresentation()
}
val wallet = when (walletResult) {
is WalletCreationResult.Success -> walletResult.wallet
else -> throw IllegalStateException("Failed to create wallet: ${walletResult.reason}")
}
// Or use getOrFail() in tests:
// val wallet = trustLayer.wallet { ... }.getOrFail()
// 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
15
16
17
18
19
20
21
22
23
@Test
fun `test verifiable presentation workflow template`() = runBlocking {
// Store credentials
credential1.storeIn(wallet)
credential2.storeIn(wallet)
// Get proof generator from trust layer
val issuer = trustLayer.dsl().getIssuer()
val proofGenerator = /* extract from issuer */
val presentationService = PresentationService(
proofGenerator = proofGenerator,
proofRegistry = trustLayer.dsl().getConfig().registries.proofRegistry
)
// Create presentation
val presentation = presentation(presentationService) {
credentials(credential1, credential2)
holder(holderDid)
keyId(holderKeyId)
challenge("challenge-123")
domain("example.com")
}
}
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
@Test
fun `test DID update workflow template`() = runBlocking {
// Create DID
val didResult = trustLayer.createDid { /* ... */ }
val issuerDid = when (didResult) {
is DidCreationResult.Success -> didResult.did
else -> throw IllegalStateException("Failed to create DID: ${didResult.reason}")
}
// Generate new key
val newKey = kms.generateKey("Ed25519")
// Update DID
import com.trustweave.trust.types.DidUpdateResult
val updateResult = trustLayer.updateDid {
did(issuerDid.value)
method(DidMethods.KEY)
addKey {
id("${issuerDid.value}#key-2")
type("Ed25519VerificationKey2020")
publicKeyJwk(newKey.publicKeyJwk ?: emptyMap())
}
}
when (updateResult) {
is DidUpdateResult.Success -> { /* Success */ }
else -> throw IllegalStateException("Failed to update DID: ${updateResult.reason}")
}
// 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
@Test
fun `test blockchain anchoring workflow template`() = runBlocking {
val trustLayer = trustLayer {
// ... setup
anchor {
chain("testnet:inMemory") {
provider("inMemory") // Use in-memory anchor client
}
}
credentials {
defaultChain("testnet:inMemory")
}
}
// Issue credential with anchoring
val issuanceResult = trustLayer.issue {
credential { /* ... */ }
signedBy(issuerDid = issuerDid.value, keyId = keyId)
anchor("testnet:inMemory")
}
val credential = when (issuanceResult) {
is IssuanceResult.Success -> issuanceResult.credential
else -> throw IllegalStateException("Failed to issue credential: ${issuanceResult.reason}")
}
// Verify anchor
val result = trustLayer.verify {
credential(credential)
verifyAnchor("testnet:inMemory")
}
}
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
@Test
fun `test smart contract workflow template`() = runBlocking {
// Issue contract as credential
val issuanceResult = trustLayer.issue {
credential {
type(CredentialType.Custom("SmartContractCredential"), CredentialType.VerifiableCredential)
// ... contract details
}
signedBy(issuerDid = issuerDid.value, keyId = keyId)
anchor("testnet:inMemory")
}
val contractCredential = when (issuanceResult) {
is IssuanceResult.Success -> issuanceResult.credential
else -> throw IllegalStateException("Failed to issue credential: ${issuanceResult.reason}")
}
// Verify contract
val result = trustLayer.verify {
credential(contractCredential)
verifyAnchor("testnet:inMemory")
}
}
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
@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 trustLayer = trustLayer {
keys { provider("aws-kms") } // Requires AWS credentials
did { method("ethr") {} } // Requires ETHEREUM_RPC_URL
trust { provider("inMemory") }
}
// 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
@Test
@RequiresPlugin("aws-kms", "ethr-did")
fun `test workflow with AWS KMS and Ethereum DID`() = runBlocking {
val trustLayer = trustLayer {
keys { provider("aws-kms") } // AWS KMS instead of in-memory
did { method("ethr") {} } // Ethereum DID instead of key DID
trust { provider("inMemory") }
}
// Same pattern: create DID, extract key ID, issue credential
val didResult = trustLayer.createDid {
method("ethr")
algorithm(KeyAlgorithms.ED25519)
}
val issuerDid = when (didResult) {
is DidCreationResult.Success -> didResult.did
else -> throw IllegalStateException("Failed to create DID: ${didResult.reason}")
}
// Extract key ID (same pattern)
val issuerDidDoc = trustLayer.dsl().getConfig().registries.didRegistry.resolve(issuerDid.value)?.document
?: throw IllegalStateException("Failed to resolve issuer DID")
val keyId = issuerDidDoc.verificationMethod.firstOrNull()?.id?.substringAfter("#")
?: throw IllegalStateException("No verification method in issuer DID")
// Issue credential (same pattern)
val issuanceResult = trustLayer.issue {
credential { /* ... */ }
signedBy(issuerDid = issuerDid.value, keyId = keyId) // Same pattern!
}
val credential = when (issuanceResult) {
is IssuanceResult.Success -> issuanceResult.credential
else -> throw IllegalStateException("Failed to issue credential: ${issuanceResult.reason}")
}
// Verify (same pattern)
val result = trustLayer.verify {
credential(credential)
checkTrustRegistry()
}
assertTrue(result.valid)
}
Common Patterns
Pattern 1: Extract Key ID from DID Document
1
2
3
4
5
val issuerDidDoc = trustLayer.dsl().getConfig().registries.didRegistry.resolve(issuerDid)?.document
?: throw IllegalStateException("Failed to resolve issuer DID")
val keyId = issuerDidDoc.verificationMethod.firstOrNull()?.id?.substringAfter("#")
?: 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
val issuanceResult = trustLayer.issue {
credential {
id("https://example.com/credential-1")
type("TestCredential")
issuer(issuerDid.value)
subject {
id(holderDid.value)
"test" to "value"
}
issued(Instant.now())
}
signedBy(issuerDid = issuerDid.value, keyId = keyId) // Use extracted key ID
}
val credential = when (issuanceResult) {
is IssuanceResult.Success -> issuanceResult.credential
else -> throw IllegalStateException("Failed to issue credential: ${issuanceResult.reason}")
}
// In tests, use getOrFail():
// val credential = trustLayer.issue { ... }.getOrFail()
Pattern 3: Verify Credential with All Checks
1
2
3
4
5
6
7
8
9
10
11
val result = trustLayer.verify {
credential(credential)
checkTrustRegistry()
checkExpiration()
checkRevocation()
}
assertTrue(result.proofValid, "Proof should be valid")
assertTrue(result.issuerValid, "Issuer DID should resolve")
assertTrue(result.trustRegistryValid, "Issuer should be trusted")
assertTrue(result.valid, "Credential should be valid")
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
// ❌ WRONG: Generating new key
val newKey = kms.generateKey("Ed25519")
val issuanceResult1 = trustLayer.issue {
signedBy(issuerDid = issuerDid.value, keyId = newKey.id) // Key not in DID document!
}
// This will fail with IssuanceResult.Failure.KeyNotFound
// ✅ CORRECT: Extract key from DID document
val issuerDidDoc = trustLayer.dsl().getConfig().registries.didRegistry.resolve(issuerDid.value)?.document
?: throw IllegalStateException("Failed to resolve issuer DID")
val keyId = issuerDidDoc.verificationMethod.firstOrNull()?.id?.substringAfter("#")
?: throw IllegalStateException("No verification method in issuer DID")
val issuanceResult2 = trustLayer.issue {
signedBy(issuerDid = issuerDid.value, keyId = keyId) // Key matches DID document!
}
val credential = when (issuanceResult2) {
is IssuanceResult.Success -> issuanceResult2.credential
else -> throw IllegalStateException("Failed to issue credential: ${issuanceResult2.reason}")
}
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
val trustLayer = trustLayer {
// ... setup
revocation { provider("inMemory") } // Must configure revocation provider
}
// VerificationDsl automatically passes statusListManager to verifier
val result = trustLayer.verify {
credential(credential)
checkRevocation() // Must enable revocation check
}
Issue: Presentation Creation Fails
Problem: IllegalArgumentException: No proof generator registered
Solution: Create PresentationService with proof generator from trust layer:
1
2
3
4
5
6
7
8
9
10
val issuer = trustLayer.dsl().getIssuer()
val proofGenerator = /* extract from issuer */
val presentationService = PresentationService(
proofGenerator = proofGenerator,
proofRegistry = trustLayer.dsl().getConfig().registries.proofRegistry
)
val presentation = presentation(presentationService) {
// ... presentation configuration
}
Next Steps
- Test Patterns - Common test patterns
- Integration Testing - Integration test best practices
- Plugin Credential Handling - Handling external service credentials
- TrustWeave-testkit Module - Testkit components overview