Skip to content

Commit 2a3cb35

Browse files
committed
Add basic testing
1 parent 76d61bb commit 2a3cb35

File tree

7 files changed

+124
-37
lines changed

7 files changed

+124
-37
lines changed

access-grant/src/main/java/com/inrupt/client/accessgrant/AccessGrantClient.java

Lines changed: 32 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
import java.io.IOException;
3939
import java.io.InputStream;
4040
import java.io.UncheckedIOException;
41+
import java.lang.reflect.Type;
4142
import java.net.URI;
4243
import java.time.Duration;
4344
import java.time.Instant;
@@ -123,6 +124,7 @@ public class AccessGrantClient {
123124
private static final Set<String> ACCESS_GRANT_TYPES = getAccessGrantTypes();
124125
private static final Set<String> ACCESS_REQUEST_TYPES = getAccessRequestTypes();
125126
private static final Set<String> ACCESS_DENIAL_TYPES = getAccessDenialTypes();
127+
private static final Type JSON_TYPE_REF = new HashMap<String, Object>(){}.getClass().getGenericSuperclass();
126128

127129
private final Client client;
128130
private final ClientCache<URI, Metadata> metadataCache;
@@ -319,8 +321,7 @@ public CompletionStage<AccessCredentialVerification> verify(final AccessCredenti
319321
final Map<String, Object> presentation = new HashMap<>();
320322

321323
try (final InputStream is = new ByteArrayInputStream(credential.serialize().getBytes(UTF_8))) {
322-
final Map<String, Object> data = jsonService.fromJson(is,
323-
new HashMap<String, Object>(){}.getClass().getGenericSuperclass());
324+
final Map<String, Object> data = jsonService.fromJson(is, JSON_TYPE_REF);
324325
Utils.getCredentialsFromPresentation(data, credential.getTypes()).stream().findFirst()
325326
.ifPresent(c -> presentation.put(VERIFIABLE_CREDENTIAL, c));
326327
} catch (final IOException ex) {
@@ -424,38 +425,45 @@ static String getPageQueryParam(final URI uri) {
424425
return null;
425426
}
426427

427-
@SuppressWarnings("unchecked")
428428
<T extends AccessCredential> List<T> processFilterResponseBody(final InputStream input,
429429
final Set<String> validTypes, final Class<T> clazz) throws IOException {
430430

431431
final List<T> page = new ArrayList<>();
432-
final Map<String, Object> data = jsonService.fromJson(input,
433-
new HashMap<String, Object>(){}.getClass().getGenericSuperclass());
434-
System.out.println("JSON: " + data);
435-
Utils.asSet(data.get("items")).ifPresent(items -> {
432+
final Map<String, Object> data = jsonService.fromJson(input, JSON_TYPE_REF);
433+
Utils.asList(data.get("items")).ifPresent(items -> {
436434
for (final Object item : items) {
437-
Utils.asMap(item).ifPresent(credential ->
435+
Utils.asMap(item).ifPresent(credential -> {
438436
Utils.asSet(credential.get(TYPE)).ifPresent(types -> {
439437
types.retainAll(validTypes);
440438
if (!types.isEmpty()) {
441439
final Map<String, Object> presentation = new HashMap<>();
442440
presentation.put(CONTEXT, Arrays.asList(VC_CONTEXT_URI));
443441
presentation.put(TYPE, Arrays.asList("VerifiablePresentation"));
444442
presentation.put(VERIFIABLE_CREDENTIAL, Arrays.asList(credential));
445-
if (AccessGrant.class.equals(clazz)) {
446-
page.add((T) AccessGrant.of(new String(serialize(presentation), UTF_8)));
447-
} else if (AccessRequest.class.equals(clazz)) {
448-
page.add((T) AccessRequest.of(new String(serialize(presentation), UTF_8)));
449-
} else if (AccessDenial.class.equals(clazz)) {
450-
page.add((T) AccessDenial.of(new String(serialize(presentation), UTF_8)));
443+
final T c = cast(presentation, clazz);
444+
if (c != null) {
445+
page.add(c);
451446
}
452447
}
453-
}));
448+
});
449+
});
454450
}
455451
});
456452
return page;
457453
}
458454

455+
@SuppressWarnings("unchecked")
456+
<T extends AccessCredential> T cast(final Map<String, Object> data, final Class<T> clazz) {
457+
if (AccessGrant.class.equals(clazz)) {
458+
return (T) AccessGrant.of(new String(serialize(data), UTF_8));
459+
} else if (AccessRequest.class.equals(clazz)) {
460+
return (T) AccessRequest.of(new String(serialize(data), UTF_8));
461+
} else if (AccessDenial.class.equals(clazz)) {
462+
return (T) AccessDenial.of(new String(serialize(data), UTF_8));
463+
}
464+
return null;
465+
}
466+
459467
/**
460468
* Perform an Access Credentials query and returns 0 to N matching access credentials.
461469
*
@@ -606,11 +614,9 @@ public <T extends AccessCredential> CompletionStage<T> fetch(final URI identifie
606614
});
607615
}
608616

609-
@SuppressWarnings("unchecked")
610617
<T extends AccessCredential> T processVerifiableCredential(final InputStream input, final Set<String> validTypes,
611618
final Class<T> clazz) throws IOException {
612-
final Map<String, Object> data = jsonService.fromJson(input,
613-
new HashMap<String, Object>(){}.getClass().getGenericSuperclass());
619+
final Map<String, Object> data = jsonService.fromJson(input, JSON_TYPE_REF);
614620
final Set<String> types = Utils.asSet(data.get(TYPE)).orElseThrow(() ->
615621
new AccessGrantException("Invalid Access Grant: no 'type' field"));
616622
types.retainAll(validTypes);
@@ -619,22 +625,17 @@ <T extends AccessCredential> T processVerifiableCredential(final InputStream inp
619625
presentation.put(CONTEXT, Arrays.asList(VC_CONTEXT_URI));
620626
presentation.put(TYPE, Arrays.asList("VerifiablePresentation"));
621627
presentation.put(VERIFIABLE_CREDENTIAL, Arrays.asList(data));
622-
if (AccessGrant.class.isAssignableFrom(clazz)) {
623-
return (T) AccessGrant.of(new String(serialize(presentation), UTF_8));
624-
} else if (AccessRequest.class.isAssignableFrom(clazz)) {
625-
return (T) AccessRequest.of(new String(serialize(presentation), UTF_8));
626-
} else if (AccessDenial.class.isAssignableFrom(clazz)) {
627-
return (T) AccessDenial.of(new String(serialize(presentation), UTF_8));
628+
final T credential = cast(presentation, clazz);
629+
if (credential != null) {
630+
return credential;
628631
}
629632
}
630633
throw new AccessGrantException("Invalid Access Grant: missing supported type");
631634
}
632635

633-
@SuppressWarnings("unchecked")
634636
<T extends AccessCredential> List<T> processQueryResponse(final InputStream input, final Set<String> validTypes,
635637
final Class<T> clazz) throws IOException {
636-
final Map<String, Object> data = jsonService.fromJson(input,
637-
new HashMap<String, Object>(){}.getClass().getGenericSuperclass());
638+
final Map<String, Object> data = jsonService.fromJson(input, JSON_TYPE_REF);
638639
final List<T> grants = new ArrayList<>();
639640
for (final Object item : getCredentials(data)) {
640641
Utils.asMap(item).ifPresent(credential ->
@@ -645,12 +646,9 @@ <T extends AccessCredential> List<T> processQueryResponse(final InputStream inpu
645646
presentation.put(CONTEXT, Arrays.asList(VC_CONTEXT_URI));
646647
presentation.put(TYPE, Arrays.asList("VerifiablePresentation"));
647648
presentation.put(VERIFIABLE_CREDENTIAL, Arrays.asList(credential));
648-
if (AccessGrant.class.equals(clazz)) {
649-
grants.add((T) AccessGrant.of(new String(serialize(presentation), UTF_8)));
650-
} else if (AccessRequest.class.equals(clazz)) {
651-
grants.add((T) AccessRequest.of(new String(serialize(presentation), UTF_8)));
652-
} else if (AccessDenial.class.equals(clazz)) {
653-
grants.add((T) AccessDenial.of(new String(serialize(presentation), UTF_8)));
649+
final T c = cast(presentation, clazz);
650+
if (c != null) {
651+
grants.add(c);
654652
}
655653
}
656654
}));
@@ -672,8 +670,7 @@ CompletionStage<Metadata> v1Metadata() {
672670
try (final InputStream input = res.body()) {
673671
final int httpStatus = res.statusCode();
674672
if (isSuccess(httpStatus)) {
675-
final Map<String, Object> data = jsonService.fromJson(input,
676-
new HashMap<String, Object>(){}.getClass().getGenericSuperclass());
673+
final Map<String, Object> data = jsonService.fromJson(input, JSON_TYPE_REF);
677674
return data;
678675
}
679676
throw new AccessGrantException(

access-grant/src/main/java/com/inrupt/client/accessgrant/Utils.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,15 @@ public static Optional<Map<String, Object>> asMap(final Object value) {
8484
return Optional.empty();
8585
}
8686

87+
public static Optional<List<Object>> asList(final Object value) {
88+
if (value instanceof List) {
89+
@SuppressWarnings("unchecked")
90+
final List<Object> v = (List<Object>) value;
91+
return Optional.of(v);
92+
}
93+
return Optional.empty();
94+
}
95+
8796
public static Optional<Set<String>> asSet(final Object value) {
8897
if (value != null) {
8998
final Set<String> data = new HashSet<>();

access-grant/src/test/java/com/inrupt/client/accessgrant/AccessGrantClientTest.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,26 @@ void testGrantAccessNoAuth() {
390390
assertInstanceOf(AccessGrantException.class, err.getCause());
391391
}
392392

393+
@Test
394+
void testQueryCredential() {
395+
final Map<String, Object> claims = new HashMap<>();
396+
claims.put("webid", WEBID);
397+
claims.put("sub", SUB);
398+
claims.put("iss", ISS);
399+
claims.put("azp", AZP);
400+
final String token = generateIdToken(claims);
401+
final AccessGrantClient client = agClient.session(OpenIdSession.ofIdToken(token));
402+
403+
final URI resource = URI.create("https://storage.example/e973cc3d-5c28-4a10-98c5-e40079289358/a/b/c");
404+
405+
final CredentialFilter<AccessGrant> filter = CredentialFilter.newBuilder().build(AccessGrant.class);
406+
407+
final CredentialResult<AccessGrant> results = client.query(filter)
408+
.toCompletableFuture().join();
409+
410+
assertEquals(1, results.getItems().size());
411+
}
412+
393413
@Test
394414
void testQueryGrant() {
395415
final Map<String, Object> claims = new HashMap<>();

access-grant/src/test/java/com/inrupt/client/accessgrant/CredentialFilterTest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,20 @@ void testCredentialEmptyFilterBuilder() {
5959
assertEquals(expectedUri, filter.asURI(BASE_URL));
6060
}
6161

62+
@Test
63+
void testCredentialInvalidPageSizeFilterBuilder() {
64+
final CredentialFilter<AccessDenial> filter = CredentialFilter.newBuilder()
65+
.pageSize(-10)
66+
.build(AccessDenial.class);
67+
assertEquals(20, filter.getPageSize());
68+
assertEquals(AccessDenial.class, filter.getCredentialType());
69+
70+
final URI expectedUri = URIBuilder.newBuilder(BASE_URL)
71+
.queryParam("type", "SolidAccessDenial")
72+
.queryParam("pageSize", "20").build();
73+
assertEquals(expectedUri, filter.asURI(BASE_URL));
74+
}
75+
6276
@Test
6377
void testCredentialExcessivePageSizeFilterBuilder() {
6478
final CredentialFilter<AccessDenial> filter = CredentialFilter.newBuilder()

access-grant/src/test/java/com/inrupt/client/accessgrant/MockAccessGrantServer.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,20 @@ private void setupMocks() {
173173
.withStatus(401)
174174
.withHeader("WWW-Authenticate", "Bearer,DPoP algs=\"ES256\"")));
175175

176+
wireMockServer.stubFor(get(urlEqualTo("/query?type=SolidAccessGrant&pageSize=20"))
177+
.atPriority(1)
178+
.withHeader("Authorization", containing("Bearer eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9."))
179+
.willReturn(aResponse()
180+
.withStatus(200)
181+
.withHeader(CONTENT_TYPE, APPLICATION_JSON)
182+
.withBody(getResource("/query_endpoint_response.json", wireMockServer.baseUrl()))));
183+
184+
wireMockServer.stubFor(get(urlEqualTo("/query?type=SolidAccessGrant&pageSize=20"))
185+
.atPriority(2)
186+
.willReturn(aResponse()
187+
.withStatus(401)
188+
.withHeader("WWW-Authenticate", "Bearer,DPoP algs=\"ES256\"")));
189+
176190
wireMockServer.stubFor(get(urlMatching("/not-found.*"))
177191
.willReturn(aResponse()
178192
.withStatus(404)));
@@ -374,7 +388,5 @@ private static String getResource(final String path) {
374388
private static String getResource(final String path, final String baseUrl) {
375389
return getResource(path).replace("{{baseUrl}}", baseUrl);
376390
}
377-
378-
379391
}
380392

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
{
2+
"items": [{
3+
"@context":[
4+
"https://www.w3.org/2018/credentials/v1",
5+
"https://w3id.org/security/suites/ed25519-2020/v1",
6+
"https://w3id.org/vc-revocation-list-2020/v1",
7+
"https://schema.inrupt.com/credentials/v2.jsonld"],
8+
"id":"{{baseUrl}}/access-grant-1",
9+
"type":["VerifiableCredential","SolidAccessGrant"],
10+
"issuer":"{{baseUrl}}",
11+
"expirationDate":"2022-08-27T12:00:00Z",
12+
"issuanceDate":"2022-08-25T20:34:05.153Z",
13+
"credentialStatus":{
14+
"id":"https://accessgrant.example/status/CVAM#2832",
15+
"revocationListCredential":"https://accessgrant.example/status/CVAM",
16+
"revocationListIndex":"2832",
17+
"type":"RevocationList2020Status"},
18+
"credentialSubject":{
19+
"id":"https://id.example/grantor",
20+
"providedConsent":{
21+
"mode":["Read"],
22+
"hasStatus":"https://w3id.org/GConsent#ConsentStatusExplicitlyGiven",
23+
"isProvidedTo":"https://id.example/grantee",
24+
"forPurpose":["https://purpose.example/Purpose1"],
25+
"forPersonalData":["https://storage.example/e973cc3d-5c28-4a10-98c5-e40079289358/"]}},
26+
"proof":{
27+
"created":"2022-08-25T20:34:05.236Z",
28+
"proofPurpose":"assertionMethod",
29+
"proofValue":"nIeQF44XVik7onnAbdkbp8xxJ2C8JoTw6-VtCkAzxuWYRFsSfYpft5MuAJaivyeKDmaK82Lj_YsME2xgL2WIBQ",
30+
"type":"Ed25519Signature2020",
31+
"verificationMethod":"https://accessgrant.example/key/1e332728-4af5-46e4-a5db-4f7b89e3f378"}
32+
}]
33+
}
34+

access-grant/src/test/resources/vc-configuration.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
],
66
"derivationService": "{{baseUrl}}/derive",
77
"issuerService": "{{baseUrl}}/issue",
8+
"queryService": "{{baseUrl}}/query",
89
"statusService": "{{baseUrl}}/status",
910
"supportedSignatureTypes": [
1011
"Ed25519Signature2020"

0 commit comments

Comments
 (0)