Technology Compatibility Kit for the Decentralized Claims Protocol
- dcp-tck
The Technology Compatibility Kit (TCK) for the Decentralized Claims Protocol (DCP) is a set of tests that asserts compliance with the Decentralized Claims Protocol Specification.
It consists of a series of tests for each of the subsections of the specification, i.e. Verifiable Presentation Protocol (VPP) and Credential Issuance Protocol (CIP).
In addition, tests are grouped according to the system under test (SUT). For example, the Credential Service has to complete the Verifiable Presentation Protocol tests as well as the Credential Issuance Protocol tests, while the Issuer Service only has to complete the Credential Issuance Protocol tests.
The following matrix shows the SUTs and the tests they have to complete:
| SuT | Verifiable Presentation Protocol | Credential Issuance Protocol |
|---|---|---|
| Credential Service | Yes | Yes |
| Issuer Service | No | Yes |
| Verifier | Yes | No |
Test are grouped into packages according to the system under test (SUT) and the protocol they are testing:
org.eclipse.dataspacetck.dcp.verification.presentation.csfor the Verifiable Presentation Protocol tests targeting the Credential Serviceorg.eclipse.dataspacetck.dcp.verification.presentation.verifierfor the Verifiable Presentation Protocol tests targeting the verifierorg.eclipse.dataspacetck.dcp.verification.issuance.csfor the Credential Issuance Protocol tests targeting the Credential Serviceorg.eclipse.dataspacetck.dcp.verification.issuance.issuerfor the Credential Issuance Protocol tests targeting the Issuer Service
These are referred to as test classes.
The test setup and configuration differs slightly between various test packages, but there are a few general things to consider.
- reachability: the system under test (SUT) must be running and reachable via the network. If a SUT consists of several microservices, it is permitted to only launch the microservices that are required for the tests. For example, if you want to test the VPP, then only the microservice that processes Presentation Queries is required.
This includes tests from the *.presentation.cs and the *.issuance.cs package.
For these tests the SecureTokenService must be running and reachable via the network. The TCK - acting as the verifier -
will use the SecureTokenService to obtain ID Tokens for Presentation Query messages. The SUT must be prepared in such a
way that
there is a valid clientId/clientSecret with which ID tokens can be obtained. This will be used as configuration for
the TCK.
The TCK dynamically generates two test credentials for every test case and attempts to load them into the SUT by sending
a CredentialMessage to the
SUT's Storage API.
This means, the SuT must accept the test credentials on that API endpoint, otherwise all tests will fail.
The following configuration is supported by the TCK:
| Property | Description | Example | Required by TCK |
|---|---|---|---|
dataspacetck.callback.address |
this is the loopback address of the TCK, for example to resolve test DID documents |
http://localhost:8080 |
yes |
dataspacetck.did.holder |
the DID of the holder (i.e. the CredentialService). The holder's DID document must be resolvable at this URL |
did:web:localhost%3A4711:holder |
for VPP tests |
dataspacetck.sts.url |
the URL of the SecureTokenService of the holder not including the /token path element.This is used to create ID Tokens for Presentation Query messages |
http://loclahost:8923/api/sts |
for VPP tests |
dataspacetck.sts.client.id |
the client ID for making token requests against the SecureTokenService. | some-client-id |
for VPP tests |
dataspacetck.sts.client.secret |
the client secret for making token requests against the SecureTokenService | 5up3r$3cr3t |
for VPP tests |
dataspacetck.credentials.correlation.id |
the correlation ID for the issuance of the test credentials. Some implementations may reject rogue (uncorrelated) CredentialMessages,so this correlation ID provides a way to establish correlation. If omitted, a random UUID is generated by the TCK |
some-correlation-id |
no |
Test packages:
"org.eclipse.dataspacetck.dcp.verification.presentation.cs", "org.eclipse.dataspacetck.dcp.verification.issuance.cs"
This includes tests from the *.issuance.issuer package.
See 2.1.1
As part of the test suite, the TCK will issue credentials via the SUT's Storage API and send credential offers via the SUT's Credential Offer API. Any prelimiary setup such as priming a database must happen before executing the tests.
The following configuration is supported by the TCK:
| Property | Description | Example | Required by TCK |
|---|---|---|---|
dataspacetck.callback.address |
this is the loopback address of the TCK, for example to resolve test DID documents |
http://localhost:8080 |
yes |
dataspacetck.did.issuer |
the DID of the issuer service (i.e. the SUT). The issuer's DID document must be resolvable at this URL |
did:web:localhost%3A4711:holder |
for VPP tests |
dataspacetck.sts.url |
the URL of the SecureTokenService of the holder not including the /token path element.This is used to create ID Tokens for Presentation Query messages |
http://loclahost:8923/api/sts |
for VPP tests |
dataspacetck.sts.client.id |
the client ID for making token requests against the SecureTokenService. | some-client-id |
for VPP tests |
dataspacetck.sts.client.secret |
the client secret for making token requests against the SecureTokenService | 5up3r$3cr3t |
for VPP tests |
dataspacetck.credentials.correlation.id |
the correlation ID for the issuance of the test credentials. Some implementations may reject rogue (uncorrelated) CredentialMessages,so this correlation ID provides a way to establish correlation. If omitted, a random UUID is generated by the TCK |
some-correlation-id |
no |
Test package: "org.eclipse.dataspacetck.dcp.verification.issuance.issuer"
This includes tests from the *.presentation.cs package.
The verifier must expose a special endpoint called a "trigger endpoint", which is used by the TCK to initiate the DCP Presentation Flow. Because DCP does not specify this, any arbitrary endpoint can be used that fulfills these requirements:
- it must be a
POSTendpoint - it must not validate the request body (a default request body is used, see below for details)
- it must accept
Content-Type: application/jsonheader - it must parse the authorization token from the
Auhorization: Bearer <JWT>header - it must respond with HTTP 2xx if the authorization token was validated successfully
- it must respond with HTTP 4xx otherwise
request body: the TCK sends a DSP Catalog Request Message as its default message body, even if the trigger endpoint is overridden ( see section 2.3.2). The reason for this is, that if a SUT also implements DSP, no extra endpoint must be exposed.
The trigger endpoint is a possibility for the TCK to initiate the DCP flow.
- default scope: the TCK acts as the CredentialService and expects Presentation Query messages that contain exactly
the
org.eclipse.dspace.dcp.vc.type:MembershipCredential:readscope. Sending additional scopes or sending an empty array will result in a failed test. - generate SI tokens: The verifier is expected to generate (or have generated) valid SI tokens as per the DCP specification. If this functionality is handled by other systems, they need to be accessible to the SUT.
- resolve DID documents: the verifier must host a DID document that contains all required information, in particular
a
verificationMethodthat contains the public key of the key pair used to sign tokens.
The TCK supports the following configuration values:
| Property | Description | Example | Required by TCK |
|---|---|---|---|
dataspacetck.callback.address |
this is the loopback address of the TCK, for example to resolve test DID documents |
http://localhost:8080 |
yes |
dataspacetck.did.verifier |
the DID of the verifier (i.e. the SUT). The verifier's DID document must be resolvable at this URL |
did:web:localhost%3A4711:verifier |
for VPP tests |
dataspacetck.did.thirdparty |
the DID of the third-party, i.e. an unauthorized/invalid entity. This DID document must be resolvable at this URL |
did:web:localhost%3A4711:verifier |
for VPP tests |
dataspacetck.vpp.trigger.endpoint |
A URL that the TCK can use to kick off the Presentation Flow. | http://localhost:8083/api/protocol/2025/1/catalog/request |
yes |
dataspacetck.revocation.type |
The type of revocation list to use. Must be either "bitstringstatuslist" (default) or "revocationlist2020". |
bitstringstatuslist |
no |
Test package: "org.eclipse.dataspacetck.dcp.verification.presentation.verifier"
This section is valid for all test classes, but the configuration values shown below must be adapted for each test class. It explains how the TCK can be executed against the SUT.
The recommended way is to run the TCK using the official Docker image. Although not required, using Testcontainers is a very convenient way to run the TCK container. When the container is started, it will automatically execute the TCK tests against the system under test using HTTP.
However, there are a few crucial things to note particularly regarding Docker networking. By default, the host system gains access to services inside the container by exposing ports. In the case of the TCK, the port mapping must be fixed, otherwise DID resolution may fail.
In addition to host->container communication, the TCK runtime must have network access to the host system, to send messages to the system under test. To achieve this, three things are required:
- configuring an additional host:
host.docker.internal=host-gateway - using
host.docker.internalfor all URLs on the host system - using
0.0.0.0instead oflocalhostfor URLs inside the container
@DisplayName("Testing the Verifiable Presentation Protocol using TCK and Testcontainers")
@Test
void runVppTestsWithDocker() {
var config = Map.of(
// insert your required configuration here, check in previous chapters
);
try (var tckContainer = new GenericContainer<>("eclipsedataspacetck/dcp-tck-runtime:latest")
.withExtraHost("host.docker.internal", "host-gateway")
.withExposedPorts(8080)
.withEnv(config)
) {
tckContainer.setPortBindings(List.of("8080:8080"));
tckContainer.start();
var latch = new CountDownLatch(1);
var hasFailed = new AtomicBoolean(false);
tckContainer.followOutput(outputFrame -> {
monitor.info(outputFrame.getUtf8String());
if (outputFrame.getUtf8String().toLowerCase().contains("there were failing tests")) {
hasFailed.set(true);
}
if (outputFrame.getUtf8String().toLowerCase().contains("test run complete")) {
latch.countDown();
}
});
assertThat(latch.await(1, TimeUnit.MINUTES)).isTrue();
assertThat(hasFailed.get()).describedAs("There were failing TCK tests, please check the log output above").isFalse();
}
}The example above presumes that the TCK's callback endpoint is reachable at port 8080. This is also the mapped docker
port.
Furthermore, according to the configuration shown above, the TCK expects to find the verifier's DID document at
http://localhost:9876/verifier/did.json.
All DCP implementations that can make use of the JUnit 5 platform can launch the TCK directly from a JUnit test case. It is important to note that even though both the SuT and the TCK run in the same process, all communication still happens over HTTP. The TCK can simply be run programmatically from a JUnit test:
@BeforeEach
void setup() {
startSystemUnderTest();
configureSystemUnderTest();
}
@DisplayName("Testing the Verifiable Presentation Protocol using TCK")
@Test
void runVppTests() {
var result = TckRuntime.Builder.newInstance()
.properties(Map.of(
// insert your required configuration here, check in previous chapters
))
.monitor(monitor)
.addPackage("org.eclipse.dataspacetck.dcp.verification.presentation.verifier")
.build()
.execute();
if (!result.getFailures().isEmpty()) {
var failures = result.getFailures().stream()
.map(f -> "- " + f.getTestIdentifier().getDisplayName() + " (" + f.getException() + ")")
.collect(Collectors.joining("\n"));
Assertions.fail(result.getTotalFailureCount() + " TCK test cases failed:\n" + failures);
}
}The following Maven dependencies are required:
org.eclipse.dataspacetck.dcp:dcp-testcases:<VERSION>: for the test casesorg.eclipse.dataspacetck.dsp:tck-runtime:<VERSION>: to launch the TCK from JUnitorg.eclipse.dataspacetck.dsp:core:<VERSION>: for the ConsoleMonitororg.eclipse.dataspacetck.dcp:dcp-system:<VERSION>: for the launcher that runs the TCK test casesorg.junit.platform:junit-platform-launcher:<JUNIT_VERSION>
If neither of the above options is suitable, the TCK can also be run from the command line, either using the Docker image or building from source and executing the JAR file manually.
docker pull eclipsedataspacetck/dcp-tck-runtime:latest
# not shown here: start and configure your system-under-test
docker run --rm \
--add-host "host.docker.internal:host-gateway" \
-p "8080:8080" \
-e "DATASPACETCK_DID_HOLDER=did:web:host.docker.internal%3A4711:holder" \
-e "DATASPACETCK_CALLBACK_ADDRESS=http://0.0.0.0:8080" \
-e "DATASPACETCK_LAUNCHER=org.eclipse.dataspacetck.dcp.system.DcpSystemLauncher" \
-e "DATASPACETCK_STS_URL=http://host.docker.internal:8923/api/sts" \
-e "DATASPACETCK_CLIENT_ID=some-client-id" \
-e "DATASPACETCK_CLIENT_SECRET=5up3r$3cr3t" \
-e "DATASPACETCK_CREDENTIALS_CORRELATION_ID=my-correlation-id" \
eclipsedataspacetck/dcp-tck-runtime:latestthis will start the TCK and run all tests and print the test results to the console.
When building from source you will need git, Java 17 or higher and Gradle 8.0 or higher available on your system.
git clone https://github.com/eclipse-dataspacetck/dcp-tck.git
./gradlew shadowJar
# not shown here: start and configure your system-under-test
java -Ddataspacetck.callback.address="http://localhost:8080" \
-Ddataspacetck.did.holder="did:web:localhost%3A4711:holder" \
-Ddataspacetck.launcher="org.eclipse.dataspacetck.dcp.system.DcpSystemLauncher" \
-Ddataspacetck.sts.url="http://localhost:8923/api/sts" \
-Ddataspacetck.sts.client.id="some-client-id" \
-Ddataspacetck.sts.client.secret="5up3r$3cr3t" \
-Ddataspacetck.credentials.correlation.id="my-correlation-id" \
-jar dcp-tck/build/libs/dcp-tck-runtime.jarIf you believe there is a bug in the TCK or there is an invalid test assertion, please file a bug here.