From 23ccfa5ff6a14105c0c3a23feb913ae292965695 Mon Sep 17 00:00:00 2001 From: Dmitri Sidorov Date: Thu, 30 May 2024 17:35:50 +0200 Subject: [PATCH 01/12] email reminder notification --- .../domain/model/enums/CredentialStatus.java | 3 +- .../service/CredentialProcedureService.java | 4 ++ .../DeferredCredentialMetadataService.java | 1 + .../domain/service/NotificationService.java | 7 +++ .../impl/CredentialProcedureServiceImpl.java | 19 +++++++ ...DeferredCredentialMetadataServiceImpl.java | 11 +++++ .../service/impl/NotificationServiceImpl.java | 49 +++++++++++++++++++ .../issuer/domain/util/CredentialStatus.java | 18 ------- .../controller/NotificationController.java | 26 ++++++++++ .../CredentialProcedureRepository.java | 3 ++ 10 files changed, 122 insertions(+), 19 deletions(-) create mode 100644 src/main/java/es/in2/issuer/domain/service/NotificationService.java create mode 100644 src/main/java/es/in2/issuer/domain/service/impl/NotificationServiceImpl.java delete mode 100644 src/main/java/es/in2/issuer/domain/util/CredentialStatus.java create mode 100644 src/main/java/es/in2/issuer/infrastructure/controller/NotificationController.java diff --git a/src/main/java/es/in2/issuer/domain/model/enums/CredentialStatus.java b/src/main/java/es/in2/issuer/domain/model/enums/CredentialStatus.java index 4d130faf6..99d99778d 100644 --- a/src/main/java/es/in2/issuer/domain/model/enums/CredentialStatus.java +++ b/src/main/java/es/in2/issuer/domain/model/enums/CredentialStatus.java @@ -2,8 +2,9 @@ public enum CredentialStatus { WITHDRAWN, - VALID, ISSUED, + PEND_DOWNLOAD, + VALID, REVOKED, EXPIRED } diff --git a/src/main/java/es/in2/issuer/domain/service/CredentialProcedureService.java b/src/main/java/es/in2/issuer/domain/service/CredentialProcedureService.java index bd520a5d8..da5b1f13c 100644 --- a/src/main/java/es/in2/issuer/domain/service/CredentialProcedureService.java +++ b/src/main/java/es/in2/issuer/domain/service/CredentialProcedureService.java @@ -11,12 +11,16 @@ public interface CredentialProcedureService { Mono getCredentialTypeByProcedureId(String procedureId); + Mono getCredentialStatusByProcedureId(String procedureId); + Mono updateDecodedCredentialByProcedureId(String procedureId, String credential, String format); Mono getDecodedCredentialByProcedureId(String procedureId); Mono getMandateeEmailFromDecodedCredentialByProcedureId(String procedureId); + Mono getMandateeFirstNameFromDecodedCredentialByProcedureId(String procedureId); + Mono getMandatorEmailFromDecodedCredentialByProcedureId(String procedureId); Flux getAllIssuedCredentialByOrganizationIdentifier(String organizationIdentifier); diff --git a/src/main/java/es/in2/issuer/domain/service/DeferredCredentialMetadataService.java b/src/main/java/es/in2/issuer/domain/service/DeferredCredentialMetadataService.java index b5b00ec81..d34074b81 100644 --- a/src/main/java/es/in2/issuer/domain/service/DeferredCredentialMetadataService.java +++ b/src/main/java/es/in2/issuer/domain/service/DeferredCredentialMetadataService.java @@ -5,6 +5,7 @@ public interface DeferredCredentialMetadataService { Mono createDeferredCredentialMetadata(String procedureId); + Mono updateTransactionCodeInDeferredCredentialMetadata(String procedureId); Mono getProcedureIdByTransactionCode(String transactionCode); Mono getProcedureIdByAuthServerNonce(String authServerNonce); Mono updateAuthServerNonceByTransactionCode(String transactionCode, String authServerNonce); diff --git a/src/main/java/es/in2/issuer/domain/service/NotificationService.java b/src/main/java/es/in2/issuer/domain/service/NotificationService.java new file mode 100644 index 000000000..39241badf --- /dev/null +++ b/src/main/java/es/in2/issuer/domain/service/NotificationService.java @@ -0,0 +1,7 @@ +package es.in2.issuer.domain.service; + +import reactor.core.publisher.Mono; + +public interface NotificationService { + Mono sendNotification(String processId,String procedureId); +} diff --git a/src/main/java/es/in2/issuer/domain/service/impl/CredentialProcedureServiceImpl.java b/src/main/java/es/in2/issuer/domain/service/impl/CredentialProcedureServiceImpl.java index 6e34ba8d4..2c093405c 100644 --- a/src/main/java/es/in2/issuer/domain/service/impl/CredentialProcedureServiceImpl.java +++ b/src/main/java/es/in2/issuer/domain/service/impl/CredentialProcedureServiceImpl.java @@ -91,6 +91,11 @@ public Mono getDecodedCredentialByProcedureId(String procedureId) { .flatMap(credentialProcedure -> Mono.just(credentialProcedure.getCredentialDecoded())); } + @Override + public Mono getCredentialStatusByProcedureId(String procedureId) { + return credentialProcedureRepository.findCredentialStatusByProcedureId(UUID.fromString(procedureId)); + } + @Override public Mono getMandateeEmailFromDecodedCredentialByProcedureId(String procedureId) { return credentialProcedureRepository.findById(UUID.fromString(procedureId)) @@ -105,6 +110,20 @@ public Mono getMandateeEmailFromDecodedCredentialByProcedureId(String pr }); } + @Override + public Mono getMandateeFirstNameFromDecodedCredentialByProcedureId(String procedureId) { + return credentialProcedureRepository.findById(UUID.fromString(procedureId)) + .flatMap(credentialProcedure -> { + try { + JsonNode credential = objectMapper.readTree(credentialProcedure.getCredentialDecoded()); + return Mono.just(credential.get("vc").get("credentialSubject").get("mandate").get("mandatee").get("first_name").toString()); + } catch (JsonProcessingException e) { + return Mono.error(new RuntimeException()); + } + + }); + } + @Override public Mono getMandatorEmailFromDecodedCredentialByProcedureId(String procedureId) { return credentialProcedureRepository.findById(UUID.fromString(procedureId)) diff --git a/src/main/java/es/in2/issuer/domain/service/impl/DeferredCredentialMetadataServiceImpl.java b/src/main/java/es/in2/issuer/domain/service/impl/DeferredCredentialMetadataServiceImpl.java index 153620a65..2df4a2a21 100644 --- a/src/main/java/es/in2/issuer/domain/service/impl/DeferredCredentialMetadataServiceImpl.java +++ b/src/main/java/es/in2/issuer/domain/service/impl/DeferredCredentialMetadataServiceImpl.java @@ -64,6 +64,17 @@ public Mono createDeferredCredentialMetadata(String procedureId) { }); } + @Override + public Mono updateTransactionCodeInDeferredCredentialMetadata(String procedureId) { + return deferredCredentialMetadataRepository.findByProcedureId(UUID.fromString(procedureId)) + .flatMap(existingDeferredCredentialMetadata -> generateCustomNonce() + .flatMap(nonce -> cacheStore.add(nonce, nonce) + .then(Mono.just(nonce)) + .doOnNext(existingDeferredCredentialMetadata::setTransactionCode)) + .flatMap(newNonce -> deferredCredentialMetadataRepository.save(existingDeferredCredentialMetadata) + .then(Mono.just(newNonce)))); + } + @Override public Mono getProcedureIdByTransactionCode(String transactionCode) { return deferredCredentialMetadataRepository.findByTransactionCode(transactionCode) diff --git a/src/main/java/es/in2/issuer/domain/service/impl/NotificationServiceImpl.java b/src/main/java/es/in2/issuer/domain/service/impl/NotificationServiceImpl.java new file mode 100644 index 000000000..085cd678c --- /dev/null +++ b/src/main/java/es/in2/issuer/domain/service/impl/NotificationServiceImpl.java @@ -0,0 +1,49 @@ +package es.in2.issuer.domain.service.impl; + +import es.in2.issuer.domain.service.CredentialProcedureService; +import es.in2.issuer.domain.service.DeferredCredentialMetadataService; +import es.in2.issuer.domain.service.EmailService; +import es.in2.issuer.domain.service.NotificationService; +import es.in2.issuer.infrastructure.config.AppConfig; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import reactor.core.publisher.Mono; + +import static es.in2.issuer.domain.model.enums.CredentialStatus.PEND_DOWNLOAD; +import static es.in2.issuer.domain.model.enums.CredentialStatus.WITHDRAWN; + +@Slf4j +@Service +@RequiredArgsConstructor +public class NotificationServiceImpl implements NotificationService { + + private final AppConfig appConfig; + private final EmailService emailService; + private final CredentialProcedureService credentialProcedureService; + private final DeferredCredentialMetadataService deferredCredentialMetadataService; + + @Override + public Mono sendNotification(String processId, String procedureId) { + return credentialProcedureService.getCredentialStatusByProcedureId(procedureId) + .flatMap(status -> credentialProcedureService.getMandateeEmailFromDecodedCredentialByProcedureId(procedureId) + .flatMap(email -> credentialProcedureService.getMandateeFirstNameFromDecodedCredentialByProcedureId(procedureId) + .flatMap(firstName -> { + if (status.equals(WITHDRAWN.toString())) { + return deferredCredentialMetadataService.updateTransactionCodeInDeferredCredentialMetadata(procedureId) + .flatMap(newTransactionCode -> emailService.sendTransactionCodeForCredentialOffer( + email, + "Credential Offer", + appConfig.getIssuerUiExternalDomain() + "/credential-offer?transaction_code=" + newTransactionCode, + firstName + )); + } else if (status.equals(PEND_DOWNLOAD.toString())) { + return emailService.sendCredentialSignedNotification(email, "Credential Ready", firstName); + } else { + return Mono.empty(); + } + }) + ) + ); + } +} diff --git a/src/main/java/es/in2/issuer/domain/util/CredentialStatus.java b/src/main/java/es/in2/issuer/domain/util/CredentialStatus.java deleted file mode 100644 index d2acfdd9f..000000000 --- a/src/main/java/es/in2/issuer/domain/util/CredentialStatus.java +++ /dev/null @@ -1,18 +0,0 @@ -package es.in2.issuer.domain.util; - -import lombok.Getter; - -@Getter -public enum CredentialStatus { - ISSUED("issued"), - VALID("valid"), - REVOKED("revoked"), - EXPIRED("expired"); - - private final String name; - - CredentialStatus(String name) { - this.name = name; - } - -} diff --git a/src/main/java/es/in2/issuer/infrastructure/controller/NotificationController.java b/src/main/java/es/in2/issuer/infrastructure/controller/NotificationController.java new file mode 100644 index 000000000..0ace358e1 --- /dev/null +++ b/src/main/java/es/in2/issuer/infrastructure/controller/NotificationController.java @@ -0,0 +1,26 @@ +package es.in2.issuer.infrastructure.controller; + +import es.in2.issuer.domain.service.NotificationService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import reactor.core.publisher.Mono; + +import java.util.UUID; + +@Slf4j +@RestController +@RequestMapping("/api/v1/notifications") +@RequiredArgsConstructor +public class NotificationController { + + private final NotificationService notificationService; + + @PostMapping + @ResponseStatus(HttpStatus.NO_CONTENT) + public Mono sendEmailNotification(@RequestParam("procedure_id") String procedureId) { + String processId = UUID.randomUUID().toString(); + return notificationService.sendNotification(processId, procedureId); + } +} diff --git a/src/main/java/es/in2/issuer/infrastructure/repository/CredentialProcedureRepository.java b/src/main/java/es/in2/issuer/infrastructure/repository/CredentialProcedureRepository.java index 8ad000580..4fd35efa3 100644 --- a/src/main/java/es/in2/issuer/infrastructure/repository/CredentialProcedureRepository.java +++ b/src/main/java/es/in2/issuer/infrastructure/repository/CredentialProcedureRepository.java @@ -2,6 +2,7 @@ import es.in2.issuer.domain.model.entities.CredentialProcedure; import es.in2.issuer.domain.model.enums.CredentialStatus; +import org.springframework.data.r2dbc.repository.Query; import org.springframework.data.repository.reactive.ReactiveCrudRepository; import org.springframework.stereotype.Repository; import reactor.core.publisher.Flux; @@ -14,5 +15,7 @@ public interface CredentialProcedureRepository extends ReactiveCrudRepository findByCredentialStatusAndOrganizationIdentifier(CredentialStatus credentialStatus, String organizationIdentifier); Flux findAllByOrganizationIdentifier(String organizationIdentifier); Mono findByProcedureIdAndOrganizationIdentifier(UUID procedureId, String organizationIdentifier); + @Query("SELECT credential_status FROM credentials.credential_procedure WHERE procedure_id = :procedureId") + Mono findCredentialStatusByProcedureId(UUID procedureId); Mono findByCredentialId(UUID credentialId); } From cc099e96a64dd95d7015b8d6e487c298bddd3b90 Mon Sep 17 00:00:00 2001 From: Dmitri Sidorov Date: Fri, 31 May 2024 09:17:06 +0200 Subject: [PATCH 02/12] add pend_download status into flow --- .../DeferredCredentialMetadataDeferredResponse.java | 2 +- .../domain/service/CredentialProcedureService.java | 2 ++ .../impl/CredentialProcedureServiceImpl.java | 13 ++++++++++++- .../impl/DeferredCredentialMetadataServiceImpl.java | 1 + .../impl/VerifiableCredentialServiceImpl.java | 12 ++++++------ .../repository/CredentialProcedureRepository.java | 1 + 6 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/main/java/es/in2/issuer/domain/model/dto/DeferredCredentialMetadataDeferredResponse.java b/src/main/java/es/in2/issuer/domain/model/dto/DeferredCredentialMetadataDeferredResponse.java index 020ceb957..e74cbd825 100644 --- a/src/main/java/es/in2/issuer/domain/model/dto/DeferredCredentialMetadataDeferredResponse.java +++ b/src/main/java/es/in2/issuer/domain/model/dto/DeferredCredentialMetadataDeferredResponse.java @@ -5,8 +5,8 @@ @Builder public record DeferredCredentialMetadataDeferredResponse( String id, + String procedureId, String transactionId, - String vc ) { } diff --git a/src/main/java/es/in2/issuer/domain/service/CredentialProcedureService.java b/src/main/java/es/in2/issuer/domain/service/CredentialProcedureService.java index da5b1f13c..f1d14f745 100644 --- a/src/main/java/es/in2/issuer/domain/service/CredentialProcedureService.java +++ b/src/main/java/es/in2/issuer/domain/service/CredentialProcedureService.java @@ -29,5 +29,7 @@ public interface CredentialProcedureService { Mono getProcedureDetailByProcedureIdAndOrganizationId(String organizationIdentifier, String procedureId); + Mono updateCredentialProcedureCredentialStatusToValidByProcedureId(String procedureId); + Mono updatedEncodedCredentialByCredentialId(String encodedCredential, String credentialId); } diff --git a/src/main/java/es/in2/issuer/domain/service/impl/CredentialProcedureServiceImpl.java b/src/main/java/es/in2/issuer/domain/service/impl/CredentialProcedureServiceImpl.java index 2c093405c..d7e6fd735 100644 --- a/src/main/java/es/in2/issuer/domain/service/impl/CredentialProcedureServiceImpl.java +++ b/src/main/java/es/in2/issuer/domain/service/impl/CredentialProcedureServiceImpl.java @@ -168,12 +168,23 @@ public Mono updatedEncodedCredentialByCredentialId(String encodedCredent return credentialProcedureRepository.findByCredentialId(UUID.fromString(credentialId)) .flatMap(credentialProcedure -> { credentialProcedure.setCredentialEncoded(encodedCredential); - credentialProcedure.setCredentialStatus(CredentialStatus.VALID); + credentialProcedure.setCredentialStatus(CredentialStatus.PEND_DOWNLOAD); return credentialProcedureRepository.save(credentialProcedure) .then(Mono.just(credentialProcedure.getProcedureId().toString())); }); } + @Override + public Mono updateCredentialProcedureCredentialStatusToValidByProcedureId(String procedureId) { + return credentialProcedureRepository.findByProcedureId(UUID.fromString(procedureId)) + .flatMap(credentialProcedure -> { + credentialProcedure.setCredentialStatus(CredentialStatus.VALID); + return credentialProcedureRepository.save(credentialProcedure) + .doOnSuccess(result -> log.info("Updated credential")) + .then(); + }); + } + @Override public Mono getAllProceduresBasicInfoByOrganizationId(String organizationIdentifier) { return credentialProcedureRepository.findAllByOrganizationIdentifier(organizationIdentifier) diff --git a/src/main/java/es/in2/issuer/domain/service/impl/DeferredCredentialMetadataServiceImpl.java b/src/main/java/es/in2/issuer/domain/service/impl/DeferredCredentialMetadataServiceImpl.java index 2df4a2a21..980ed95ba 100644 --- a/src/main/java/es/in2/issuer/domain/service/impl/DeferredCredentialMetadataServiceImpl.java +++ b/src/main/java/es/in2/issuer/domain/service/impl/DeferredCredentialMetadataServiceImpl.java @@ -128,6 +128,7 @@ public Mono getVcByTransactionId(Str return Mono.just(DeferredCredentialMetadataDeferredResponse.builder() .vc(deferredCredentialMetadata.getVc()) .id(deferredCredentialMetadata.getId().toString()) + .procedureId(deferredCredentialMetadata.getProcedureId().toString()) .build()); } else { diff --git a/src/main/java/es/in2/issuer/domain/service/impl/VerifiableCredentialServiceImpl.java b/src/main/java/es/in2/issuer/domain/service/impl/VerifiableCredentialServiceImpl.java index a4a0b9768..a515662db 100644 --- a/src/main/java/es/in2/issuer/domain/service/impl/VerifiableCredentialServiceImpl.java +++ b/src/main/java/es/in2/issuer/domain/service/impl/VerifiableCredentialServiceImpl.java @@ -53,22 +53,22 @@ public Mono generateVc(String processId, String vcType, LEARCredentialRe // return objectMapper.writeValueAsString(constructFinalObjectNode(vcTemplateNode, subjectDid, issuerDid, uuid, nowInstant, expiration)); // }); // } + @Override public Mono generateDeferredCredentialResponse(String processId, DeferredCredentialRequest deferredCredentialRequest) { return deferredCredentialMetadataService.getVcByTransactionId(deferredCredentialRequest.transactionId()) .flatMap(deferredCredentialMetadataDeferredResponse -> { - if (deferredCredentialMetadataDeferredResponse.vc() != null){ - return deferredCredentialMetadataService.deleteDeferredCredentialMetadataById(deferredCredentialMetadataDeferredResponse.id()) + if (deferredCredentialMetadataDeferredResponse.vc() != null) { + return credentialProcedureService.updateCredentialProcedureCredentialStatusToValidByProcedureId(deferredCredentialMetadataDeferredResponse.procedureId()) + .then(deferredCredentialMetadataService.deleteDeferredCredentialMetadataById(deferredCredentialMetadataDeferredResponse.id())) .then(Mono.just(VerifiableCredentialResponse.builder() .credential(deferredCredentialMetadataDeferredResponse.vc()) .build())); - } - else { + } else { return Mono.just(VerifiableCredentialResponse.builder() - .transactionId(deferredCredentialMetadataDeferredResponse.transactionId()) + .transactionId(deferredCredentialMetadataDeferredResponse.transactionId()) .build()); } - }); } diff --git a/src/main/java/es/in2/issuer/infrastructure/repository/CredentialProcedureRepository.java b/src/main/java/es/in2/issuer/infrastructure/repository/CredentialProcedureRepository.java index 4fd35efa3..6fa25c524 100644 --- a/src/main/java/es/in2/issuer/infrastructure/repository/CredentialProcedureRepository.java +++ b/src/main/java/es/in2/issuer/infrastructure/repository/CredentialProcedureRepository.java @@ -18,4 +18,5 @@ public interface CredentialProcedureRepository extends ReactiveCrudRepository findCredentialStatusByProcedureId(UUID procedureId); Mono findByCredentialId(UUID credentialId); + Mono findByProcedureId(UUID procedureId); } From 37ffeceea9338a6184d70f72af7a9b81145592dd Mon Sep 17 00:00:00 2001 From: Dmitri Sidorov Date: Fri, 31 May 2024 11:29:02 +0200 Subject: [PATCH 03/12] update organizationId fetching in controller --- CHANGELOG.md | 6 ++++ build.gradle | 2 +- .../domain/service/AccessTokenService.java | 3 +- .../service/impl/AccessTokenServiceImpl.java | 31 ++++++++++++++++--- .../infrastructure/config/SecurityConfig.java | 1 + .../controller/CredentialController.java | 2 +- .../CredentialManagementController.java | 18 ++++++----- .../service/AccessTokenServiceImplTest.java | 21 +++++++------ 8 files changed, 59 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2799d4d65..9c86ab52b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased]: v0.7.0 +- LEARCredential compliance. + +## [Unreleased]: v0.6.0 +- DOME profile compliance. + ## [Unreleased]: v0.5.0 - Deferred credential emission. - tx_code support for PIN. diff --git a/build.gradle b/build.gradle index f079cad59..970e62c3a 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ plugins { } group = 'es.in2' -version = '0.7.0' +version = '0.8.0' java { sourceCompatibility = '17' diff --git a/src/main/java/es/in2/issuer/domain/service/AccessTokenService.java b/src/main/java/es/in2/issuer/domain/service/AccessTokenService.java index e82855b45..a54d6d2af 100644 --- a/src/main/java/es/in2/issuer/domain/service/AccessTokenService.java +++ b/src/main/java/es/in2/issuer/domain/service/AccessTokenService.java @@ -4,5 +4,6 @@ public interface AccessTokenService { Mono getCleanBearerToken(String authorizationHeader); - Mono getUserIdFromHeader(String authorizationHeader); + Mono getUserId(String authorizationHeader); + Mono getOrganizationId(String authorizationHeader); } diff --git a/src/main/java/es/in2/issuer/domain/service/impl/AccessTokenServiceImpl.java b/src/main/java/es/in2/issuer/domain/service/impl/AccessTokenServiceImpl.java index 102e632cd..e05b0fe1a 100644 --- a/src/main/java/es/in2/issuer/domain/service/impl/AccessTokenServiceImpl.java +++ b/src/main/java/es/in2/issuer/domain/service/impl/AccessTokenServiceImpl.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.nimbusds.jwt.SignedJWT; +import es.in2.issuer.domain.exception.InvalidTokenException; import es.in2.issuer.domain.service.AccessTokenService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -18,12 +19,17 @@ public class AccessTokenServiceImpl implements AccessTokenService { @Override public Mono getCleanBearerToken(String authorizationHeader) { return Mono.just(authorizationHeader) - .filter(header -> header.startsWith(BEARER_PREFIX)) - .map(header -> header.replace(BEARER_PREFIX, "").trim()) - .switchIfEmpty(Mono.error(new IllegalArgumentException("Invalid"))); + .flatMap(header -> { + if (header.startsWith(BEARER_PREFIX)) { + return Mono.just(header.replace(BEARER_PREFIX, "").trim()); + } else { + return Mono.just(header); + } + }); } + @Override - public Mono getUserIdFromHeader(String authorizationHeader) { + public Mono getUserId(String authorizationHeader) { return getCleanBearerToken(authorizationHeader) .flatMap(token -> { try { @@ -34,6 +40,21 @@ public Mono getUserIdFromHeader(String authorizationHeader) { return Mono.error(e); } }) - .switchIfEmpty(Mono.error(new IllegalArgumentException("Invalid"))); + .switchIfEmpty(Mono.error(new InvalidTokenException())); + } + + @Override + public Mono getOrganizationId(String authorizationHeader) { + return getCleanBearerToken(authorizationHeader) + .flatMap(token -> { + try { + SignedJWT parsedVcJwt = SignedJWT.parse(token); + JsonNode jsonObject = new ObjectMapper().readTree(parsedVcJwt.getPayload().toString()); + return Mono.just(jsonObject.get("organizationIdentifier").asText()); + } catch (ParseException | JsonProcessingException e) { + return Mono.error(e); + } + }) + .switchIfEmpty(Mono.error(new InvalidTokenException())); } } diff --git a/src/main/java/es/in2/issuer/infrastructure/config/SecurityConfig.java b/src/main/java/es/in2/issuer/infrastructure/config/SecurityConfig.java index 9d7d8545d..46134ed16 100644 --- a/src/main/java/es/in2/issuer/infrastructure/config/SecurityConfig.java +++ b/src/main/java/es/in2/issuer/infrastructure/config/SecurityConfig.java @@ -63,6 +63,7 @@ public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) .pathMatchers(HttpMethod.POST, "/api/v1/credentials").permitAll() .pathMatchers(HttpMethod.GET, "/api/v1/credential-offer/**").permitAll() .pathMatchers(HttpMethod.GET, "/api/v1/procedures/**").permitAll() + .pathMatchers(HttpMethod.POST, "/api/v1/notifications").permitAll() .anyExchange().authenticated() ).csrf(ServerHttpSecurity.CsrfSpec::disable) .oauth2ResourceServer(oauth2ResourceServer -> diff --git a/src/main/java/es/in2/issuer/infrastructure/controller/CredentialController.java b/src/main/java/es/in2/issuer/infrastructure/controller/CredentialController.java index cc044488f..8fb6e471b 100644 --- a/src/main/java/es/in2/issuer/infrastructure/controller/CredentialController.java +++ b/src/main/java/es/in2/issuer/infrastructure/controller/CredentialController.java @@ -84,7 +84,7 @@ public Mono getCredential(@RequestHeader(HttpHeade @ResponseStatus(HttpStatus.CREATED) public Mono createVerifiableCredentials(@RequestHeader(HttpHeaders.AUTHORIZATION) String authorizationHeader, @RequestBody BatchCredentialRequest batchCredentialRequest) { return accessTokenService.getCleanBearerToken(authorizationHeader) - .flatMap(token -> accessTokenService.getUserIdFromHeader(authorizationHeader) + .flatMap(token -> accessTokenService.getUserId(authorizationHeader) .flatMap(userId -> verifiableCredentialIssuanceWorkflow.generateVerifiableCredentialBatchResponse(userId, batchCredentialRequest, token))) .doOnNext(result -> log.info("VerifiableCredentialController - createVerifiableCredential()")); } diff --git a/src/main/java/es/in2/issuer/infrastructure/controller/CredentialManagementController.java b/src/main/java/es/in2/issuer/infrastructure/controller/CredentialManagementController.java index 442e62315..638d89c02 100644 --- a/src/main/java/es/in2/issuer/infrastructure/controller/CredentialManagementController.java +++ b/src/main/java/es/in2/issuer/infrastructure/controller/CredentialManagementController.java @@ -2,9 +2,11 @@ import es.in2.issuer.domain.model.dto.CredentialDetails; import es.in2.issuer.domain.model.dto.CredentialProcedures; +import es.in2.issuer.domain.service.AccessTokenService; import es.in2.issuer.domain.service.CredentialProcedureService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; @@ -17,20 +19,22 @@ public class CredentialManagementController { private final CredentialProcedureService credentialProcedureService; + private final AccessTokenService accessTokenService; @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) - public Mono getAllProcedures(@RequestHeader(value = "X-SSL-Client-Cert") String clientCert) { - log.debug(clientCert); - return credentialProcedureService.getAllProceduresBasicInfoByOrganizationId(clientCert); + public Mono getAllProcedures(@RequestHeader(HttpHeaders.AUTHORIZATION) String authorizationHeader) { + return accessTokenService.getOrganizationId(authorizationHeader) + .flatMap(credentialProcedureService::getAllProceduresBasicInfoByOrganizationId) + .doOnNext(result -> log.info("CredentialManagementController - getAllProcedures()")); } @GetMapping(value = "/{procedure_id}/credential-decoded", produces = MediaType.APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) - public Mono getProcedures(@PathVariable("procedure_id") String procedureId, - @RequestHeader(value = "X-SSL-Client-Cert") String clientCert) { - log.debug(clientCert); - return credentialProcedureService.getProcedureDetailByProcedureIdAndOrganizationId(clientCert, procedureId); + public Mono getProcedure(@RequestHeader(HttpHeaders.AUTHORIZATION) String authorizationHeader, @PathVariable("procedure_id") String procedureId) { + return accessTokenService.getOrganizationId(authorizationHeader) + .flatMap(organizationId -> credentialProcedureService.getProcedureDetailByProcedureIdAndOrganizationId(organizationId, procedureId)) + .doOnNext(result -> log.info("CredentialManagementController - getProcedure()")); } } diff --git a/src/test/java/es/in2/issuer/domain/service/AccessTokenServiceImplTest.java b/src/test/java/es/in2/issuer/domain/service/AccessTokenServiceImplTest.java index 2eae57f9e..95db860cc 100644 --- a/src/test/java/es/in2/issuer/domain/service/AccessTokenServiceImplTest.java +++ b/src/test/java/es/in2/issuer/domain/service/AccessTokenServiceImplTest.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.nimbusds.jose.Payload; import com.nimbusds.jwt.SignedJWT; +import es.in2.issuer.domain.exception.InvalidTokenException; import es.in2.issuer.domain.service.impl.AccessTokenServiceImpl; import org.junit.jupiter.api.Test; import org.mockito.MockedStatic; @@ -31,14 +32,14 @@ void testGetCleanBearerToken_Valid() { .verifyComplete(); } - @Test - void testGetCleanBearerToken_Invalid() { - String invalidHeader = "invalidToken123"; - Mono result = service.getCleanBearerToken(invalidHeader); - StepVerifier.create(result) - .expectError(IllegalArgumentException.class) - .verify(); - } +// @Test +// void testGetCleanBearerToken_Invalid() { +// String invalidHeader = "invalidToken123"; +// Mono result = service.getCleanBearerToken(invalidHeader); +// StepVerifier.create(result) +// .expectError(InvalidTokenException.class) +// .verify(); +// } @Test void testGetUserIdFromHeader_Valid() throws Exception { @@ -55,7 +56,7 @@ void testGetUserIdFromHeader_Valid() throws Exception { JsonNode payloadJson = mapper.readTree(jwtPayload); when(mockSignedJwt.getPayload()).thenReturn(new Payload(payloadJson.toString())); - Mono result = service.getUserIdFromHeader(validHeader); + Mono result = service.getUserId(validHeader); StepVerifier.create(result) .expectNext(expectedUserId) @@ -71,7 +72,7 @@ void testGetUserIdFromHeader_ThrowsParseException() { mockedJwtStatic.when(() -> SignedJWT.parse(anyString())) .thenThrow(new ParseException("Invalid token", 0)); - Mono result = service.getUserIdFromHeader(invalidHeader); + Mono result = service.getUserId(invalidHeader); StepVerifier.create(result) .expectError(ParseException.class) From 69289eabbc68edf0828a759364836c17a03923bf Mon Sep 17 00:00:00 2001 From: Dmitri Sidorov Date: Mon, 3 Jun 2024 10:38:02 +0200 Subject: [PATCH 04/12] some fixes for smtp server support --- .../impl/DeferredCredentialWorkflowImpl.java | 4 ++-- .../VerifiableCredentialIssuanceWorkflowImpl.java | 4 ++-- .../impl/CredentialProcedureServiceImpl.java | 6 +++--- .../domain/service/impl/EmailServiceImpl.java | 10 +++++----- .../java/es/in2/issuer/domain/util/Constants.java | 2 +- src/main/resources/application.yml | 13 ++++++++----- 6 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/main/java/es/in2/issuer/application/workflow/impl/DeferredCredentialWorkflowImpl.java b/src/main/java/es/in2/issuer/application/workflow/impl/DeferredCredentialWorkflowImpl.java index 4e86d2f3e..b396fa726 100644 --- a/src/main/java/es/in2/issuer/application/workflow/impl/DeferredCredentialWorkflowImpl.java +++ b/src/main/java/es/in2/issuer/application/workflow/impl/DeferredCredentialWorkflowImpl.java @@ -45,8 +45,8 @@ public Mono updateSignedCredentials(SignedCredentials signedCredentials) { // Parse the credential and extract the ID JsonNode credentialNode = objectMapper.readTree(payload); String credentialId = credentialNode.get("vc").get("id").asText(); - String email = credentialNode.get("vc").get("credentialSubject").get("mandate").get("mandatee").get("email").toString(); - String firstName = credentialNode.get("vc").get("credentialSubject").get("mandate").get("mandatee").get("first_name").toString(); + String email = credentialNode.get("vc").get("credentialSubject").get("mandate").get("mandatee").get("email").asText(); + String firstName = credentialNode.get("vc").get("credentialSubject").get("mandate").get("mandatee").get("first_name").asText(); // Update the credential in the database return credentialProcedureService.updatedEncodedCredentialByCredentialId(jwt, credentialId) .flatMap(procedureId -> deferredCredentialMetadataService.updateVcByProcedureId(jwt, procedureId)) diff --git a/src/main/java/es/in2/issuer/application/workflow/impl/VerifiableCredentialIssuanceWorkflowImpl.java b/src/main/java/es/in2/issuer/application/workflow/impl/VerifiableCredentialIssuanceWorkflowImpl.java index 49635987a..904059480 100644 --- a/src/main/java/es/in2/issuer/application/workflow/impl/VerifiableCredentialIssuanceWorkflowImpl.java +++ b/src/main/java/es/in2/issuer/application/workflow/impl/VerifiableCredentialIssuanceWorkflowImpl.java @@ -46,8 +46,8 @@ public class VerifiableCredentialIssuanceWorkflowImpl implements VerifiableCrede public Mono completeWithdrawLearCredentialProcess(String processId, String type, LEARCredentialRequest learCredentialRequest) { return verifiableCredentialService.generateVc(processId, type, learCredentialRequest) .flatMap(transactionCode -> { - String email = learCredentialRequest.credential().get("mandatee").get("email").toString(); - String firstName = learCredentialRequest.credential().get("mandatee").get("first_name").toString(); + String email = learCredentialRequest.credential().get("mandatee").get("email").asText(); + String firstName = learCredentialRequest.credential().get("mandatee").get("first_name").asText(); return emailService.sendTransactionCodeForCredentialOffer(email, "Credential Offer", appConfig.getIssuerUiExternalDomain() + "/credential-offer?transaction_code=" + transactionCode, firstName); }); diff --git a/src/main/java/es/in2/issuer/domain/service/impl/CredentialProcedureServiceImpl.java b/src/main/java/es/in2/issuer/domain/service/impl/CredentialProcedureServiceImpl.java index d7e6fd735..691a1e388 100644 --- a/src/main/java/es/in2/issuer/domain/service/impl/CredentialProcedureServiceImpl.java +++ b/src/main/java/es/in2/issuer/domain/service/impl/CredentialProcedureServiceImpl.java @@ -102,7 +102,7 @@ public Mono getMandateeEmailFromDecodedCredentialByProcedureId(String pr .flatMap(credentialProcedure -> { try { JsonNode credential = objectMapper.readTree(credentialProcedure.getCredentialDecoded()); - return Mono.just(credential.get("vc").get("credentialSubject").get("mandate").get("mandatee").get("email").toString()); + return Mono.just(credential.get("vc").get("credentialSubject").get("mandate").get("mandatee").get("email").asText()); } catch (JsonProcessingException e) { return Mono.error(new RuntimeException()); } @@ -116,7 +116,7 @@ public Mono getMandateeFirstNameFromDecodedCredentialByProcedureId(Strin .flatMap(credentialProcedure -> { try { JsonNode credential = objectMapper.readTree(credentialProcedure.getCredentialDecoded()); - return Mono.just(credential.get("vc").get("credentialSubject").get("mandate").get("mandatee").get("first_name").toString()); + return Mono.just(credential.get("vc").get("credentialSubject").get("mandate").get("mandatee").get("first_name").asText()); } catch (JsonProcessingException e) { return Mono.error(new RuntimeException()); } @@ -130,7 +130,7 @@ public Mono getMandatorEmailFromDecodedCredentialByProcedureId(String pr .flatMap(credentialProcedure -> { try { JsonNode credential = objectMapper.readTree(credentialProcedure.getCredentialDecoded()); - return Mono.just(credential.get("vc").get("credentialSubject").get("mandate").get("mandator").get("emailAddress").toString()); + return Mono.just(credential.get("vc").get("credentialSubject").get("mandate").get("mandator").get("emailAddress").asText()); } catch (JsonProcessingException e) { return Mono.error(new RuntimeException()); } diff --git a/src/main/java/es/in2/issuer/domain/service/impl/EmailServiceImpl.java b/src/main/java/es/in2/issuer/domain/service/impl/EmailServiceImpl.java index 8845fc3f2..49ba9bdde 100644 --- a/src/main/java/es/in2/issuer/domain/service/impl/EmailServiceImpl.java +++ b/src/main/java/es/in2/issuer/domain/service/impl/EmailServiceImpl.java @@ -12,7 +12,7 @@ import reactor.core.publisher.Mono; import reactor.core.scheduler.Schedulers; -import static es.in2.issuer.domain.util.Constants.NO_REPLAY_EMAIL; +import static es.in2.issuer.domain.util.Constants.FROM_EMAIL; import static es.in2.issuer.domain.util.Constants.UTF_8; @Slf4j @@ -27,7 +27,7 @@ public Mono sendPin(String to, String subject, String pin) { return Mono.fromCallable(() -> { MimeMessage mimeMessage = javaMailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, UTF_8); - helper.setFrom(NO_REPLAY_EMAIL); + helper.setFrom(FROM_EMAIL); helper.setTo(to); helper.setSubject(subject); @@ -49,7 +49,7 @@ public Mono sendTransactionCodeForCredentialOffer(String to, String subjec return Mono.fromCallable(() -> { MimeMessage mimeMessage = javaMailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, UTF_8); - helper.setFrom(NO_REPLAY_EMAIL); + helper.setFrom(FROM_EMAIL); helper.setTo(to); helper.setSubject(subject); @@ -69,7 +69,7 @@ public Mono sendPendingCredentialNotification(String to, String subject) { return Mono.fromCallable(() -> { MimeMessage mimeMessage = javaMailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, UTF_8); - helper.setFrom(NO_REPLAY_EMAIL); + helper.setFrom(FROM_EMAIL); helper.setTo(to); helper.setSubject(subject); @@ -91,7 +91,7 @@ public Mono sendCredentialSignedNotification(String to, String subject, St return Mono.fromCallable(() -> { MimeMessage mimeMessage = javaMailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true, "UTF-8"); - helper.setFrom(NO_REPLAY_EMAIL); + helper.setFrom(FROM_EMAIL); helper.setTo(to); helper.setSubject(subject); diff --git a/src/main/java/es/in2/issuer/domain/util/Constants.java b/src/main/java/es/in2/issuer/domain/util/Constants.java index 407835f78..2ac7465b3 100644 --- a/src/main/java/es/in2/issuer/domain/util/Constants.java +++ b/src/main/java/es/in2/issuer/domain/util/Constants.java @@ -32,7 +32,7 @@ private Constants() { public static final String BEARER_PREFIX = "Bearer "; public static final String ENGLISH = "en"; public static final String UTF_8 = "UTF-8"; - public static final String NO_REPLAY_EMAIL = "noreply@example.com"; + public static final String FROM_EMAIL = "digitalidentitysupport@dome-marketplace.eu"; public static final String CONTENT_TYPE = "Content-Type"; public static final String CONTENT_TYPE_APPLICATION_JSON = "application/json"; public static final String CONTENT_TYPE_URL_ENCODED_FORM = "application/x-www-form-urlencoded"; diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 11c56a1ea..6329042a0 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -13,13 +13,16 @@ spring: url: "jdbc:postgresql://localhost:5434/issuer" locations: classpath:db/migration mail: - host: localhost - port: 1025 + host: + port: username: password: - properties.mail.smtp: - auth: false - starttls.enable: false + properties: + mail: + smtp: + auth: + starttls.enable: + ssl.trust: # Spring Logging Configuration logging: From 34f013ce4ca315c81b06ad504e9abc97a1facbb4 Mon Sep 17 00:00:00 2001 From: Dmitri Sidorov Date: Mon, 3 Jun 2024 16:55:35 +0200 Subject: [PATCH 05/12] organizationId from current session for new credential --- .../domain/service/AccessTokenService.java | 1 + .../service/impl/AccessTokenServiceImpl.java | 26 +++++++++++++++++++ .../LEARCredentialEmployeeFactory.java | 19 +++++++++----- src/main/resources/application-dev.yml | 1 + src/main/resources/application-prod.yml | 1 + src/main/resources/application-test.yml | 1 + src/main/resources/application.yml | 10 +++---- 7 files changed, 46 insertions(+), 13 deletions(-) diff --git a/src/main/java/es/in2/issuer/domain/service/AccessTokenService.java b/src/main/java/es/in2/issuer/domain/service/AccessTokenService.java index a54d6d2af..88b825126 100644 --- a/src/main/java/es/in2/issuer/domain/service/AccessTokenService.java +++ b/src/main/java/es/in2/issuer/domain/service/AccessTokenService.java @@ -6,4 +6,5 @@ public interface AccessTokenService { Mono getCleanBearerToken(String authorizationHeader); Mono getUserId(String authorizationHeader); Mono getOrganizationId(String authorizationHeader); + Mono getOrganizationIdFromCurrentSession(); } diff --git a/src/main/java/es/in2/issuer/domain/service/impl/AccessTokenServiceImpl.java b/src/main/java/es/in2/issuer/domain/service/impl/AccessTokenServiceImpl.java index e05b0fe1a..400f09b56 100644 --- a/src/main/java/es/in2/issuer/domain/service/impl/AccessTokenServiceImpl.java +++ b/src/main/java/es/in2/issuer/domain/service/impl/AccessTokenServiceImpl.java @@ -7,6 +7,8 @@ import es.in2.issuer.domain.exception.InvalidTokenException; import es.in2.issuer.domain.service.AccessTokenService; import lombok.extern.slf4j.Slf4j; +import org.springframework.security.core.context.ReactiveSecurityContextHolder; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import org.springframework.stereotype.Service; import reactor.core.publisher.Mono; @@ -57,4 +59,28 @@ public Mono getOrganizationId(String authorizationHeader) { }) .switchIfEmpty(Mono.error(new InvalidTokenException())); } + + @Override + public Mono getOrganizationIdFromCurrentSession() { + return getTokenFromCurrentSession() + .flatMap(this::getCleanBearerToken) + .flatMap(token -> { + try { + SignedJWT parsedVcJwt = SignedJWT.parse(token); + JsonNode jsonObject = new ObjectMapper().readTree(parsedVcJwt.getPayload().toString()); + return Mono.just(jsonObject.get("organizationIdentifier").asText()); + } catch (ParseException | JsonProcessingException e) { + return Mono.error(e); + } + }) + .switchIfEmpty(Mono.error(new InvalidTokenException())); + } + + private Mono getTokenFromCurrentSession() { + return ReactiveSecurityContextHolder.getContext() + .map(ctx -> { + JwtAuthenticationToken token = (JwtAuthenticationToken) ctx.getAuthentication(); + return token.getToken().getTokenValue(); + }); + } } diff --git a/src/main/java/es/in2/issuer/domain/util/factory/LEARCredentialEmployeeFactory.java b/src/main/java/es/in2/issuer/domain/util/factory/LEARCredentialEmployeeFactory.java index d7ebdf488..89d459185 100644 --- a/src/main/java/es/in2/issuer/domain/util/factory/LEARCredentialEmployeeFactory.java +++ b/src/main/java/es/in2/issuer/domain/util/factory/LEARCredentialEmployeeFactory.java @@ -6,6 +6,7 @@ import es.in2.issuer.domain.model.dto.CredentialProcedureCreationRequest; import es.in2.issuer.domain.model.dto.LEARCredentialEmployee; import es.in2.issuer.domain.model.dto.LEARCredentialEmployeeJwtPayload; +import es.in2.issuer.domain.service.AccessTokenService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -25,6 +26,7 @@ public class LEARCredentialEmployeeFactory { private final ObjectMapper objectMapper; + private final AccessTokenService accessTokenService; public Mono mapCredentialAndBindMandateeIdInToTheCredential(String learCredential, String mandateeId) { LEARCredentialEmployeeJwtPayload baseLearCredentialEmployee = mapStringToLEARCredentialEmployee(learCredential); @@ -155,13 +157,16 @@ private Mono convertLEARCredentialEmployeeInToString(LEARCredentialEmplo } private Mono buildCredentialProcedureCreationRequest(String decodedCredential, LEARCredentialEmployeeJwtPayload learCredentialEmployeeJwtPayload) { - return Mono.just( - CredentialProcedureCreationRequest.builder() - .credentialId(learCredentialEmployeeJwtPayload.learCredentialEmployee().id()) - .organizationIdentifier(learCredentialEmployeeJwtPayload.learCredentialEmployee().credentialSubject().mandate().mandator().organizationIdentifier()) - .credentialDecoded(decodedCredential) - .build() - ); + return accessTokenService.getOrganizationIdFromCurrentSession() + .flatMap(organizationId -> + Mono.just( + CredentialProcedureCreationRequest.builder() + .credentialId(learCredentialEmployeeJwtPayload.learCredentialEmployee().id()) + .organizationIdentifier(organizationId) + .credentialDecoded(decodedCredential) + .build() + ) + ); } } diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml index c9e0ae0c5..db3181d87 100644 --- a/src/main/resources/application-dev.yml +++ b/src/main/resources/application-dev.yml @@ -20,6 +20,7 @@ spring: properties.mail.smtp: auth: false starttls.enable: false + ssl.trust: # Spring Logging Configuration logging: diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml index 0b9feebdb..ee96e1dec 100644 --- a/src/main/resources/application-prod.yml +++ b/src/main/resources/application-prod.yml @@ -20,6 +20,7 @@ spring: properties.mail.smtp: auth: false starttls.enable: false + ssl.trust: # Spring Logging Configuration logging: diff --git a/src/main/resources/application-test.yml b/src/main/resources/application-test.yml index 85e80dcef..7e011606d 100644 --- a/src/main/resources/application-test.yml +++ b/src/main/resources/application-test.yml @@ -20,6 +20,7 @@ spring: properties.mail.smtp: auth: false starttls.enable: false + ssl.trust: # Spring Logging Configuration logging: diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 6329042a0..bc4888f82 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -17,12 +17,10 @@ spring: port: username: password: - properties: - mail: - smtp: - auth: - starttls.enable: - ssl.trust: + properties.mail.smtp: + auth: + starttls.enable: + ssl.trust: # Spring Logging Configuration logging: From ef193ba928cd5b232b8c542045140fa5c93dbf0d Mon Sep 17 00:00:00 2001 From: Dmitri Sidorov Manko <159002112+dmitriin2@users.noreply.github.com> Date: Mon, 3 Jun 2024 20:14:25 +0200 Subject: [PATCH 06/12] fix payload generation(iss, sub, and date format) --- .../dto/LEARCredentialEmployeeJwtPayload.java | 6 +-- .../LEARCredentialEmployeeFactory.java | 47 +++++++++++++------ 2 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/main/java/es/in2/issuer/domain/model/dto/LEARCredentialEmployeeJwtPayload.java b/src/main/java/es/in2/issuer/domain/model/dto/LEARCredentialEmployeeJwtPayload.java index 8c4b2f40f..150744ea4 100644 --- a/src/main/java/es/in2/issuer/domain/model/dto/LEARCredentialEmployeeJwtPayload.java +++ b/src/main/java/es/in2/issuer/domain/model/dto/LEARCredentialEmployeeJwtPayload.java @@ -9,16 +9,16 @@ public record LEARCredentialEmployeeJwtPayload( String subject, @JsonProperty("nbf") - String notValidBefore, + Long notValidBefore, @JsonProperty("iss") String issuer, @JsonProperty("exp") - String expirationTime, + Long expirationTime, @JsonProperty("iat") - String issuedAt, + Long issuedAt, @JsonProperty("vc") LEARCredentialEmployee learCredentialEmployee, diff --git a/src/main/java/es/in2/issuer/domain/util/factory/LEARCredentialEmployeeFactory.java b/src/main/java/es/in2/issuer/domain/util/factory/LEARCredentialEmployeeFactory.java index 89d459185..b96300b3d 100644 --- a/src/main/java/es/in2/issuer/domain/util/factory/LEARCredentialEmployeeFactory.java +++ b/src/main/java/es/in2/issuer/domain/util/factory/LEARCredentialEmployeeFactory.java @@ -13,6 +13,8 @@ import reactor.core.publisher.Mono; import java.time.Instant; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.time.temporal.ChronoUnit; import java.util.List; import java.util.UUID; @@ -104,15 +106,20 @@ private Mono buildLEARCredentialEmployeeJwtPay LEARCredentialEmployeeJwtPayload.builder() .JwtId(UUID.randomUUID().toString()) .learCredentialEmployee(learCredentialEmployee) - .expirationTime(learCredentialEmployee.expirationDate()) - .issuedAt(learCredentialEmployee.issuanceDate()) - .notValidBefore(learCredentialEmployee.validFrom()) + .expirationTime(parseDateToUnixTime(learCredentialEmployee.expirationDate())) + .issuedAt(parseDateToUnixTime(learCredentialEmployee.issuanceDate())) + .notValidBefore(parseDateToUnixTime(learCredentialEmployee.validFrom())) .issuer(learCredentialEmployee.issuer()) .subject(learCredentialEmployee.credentialSubject().mandate().mandatee().id()) .build() ); } + private long parseDateToUnixTime(String date) { + ZonedDateTime zonedDateTime = ZonedDateTime.parse(date, DateTimeFormatter.ISO_ZONED_DATE_TIME); + return zonedDateTime.toInstant().getEpochSecond(); + } + private Mono bindMandateeIdToLearCredentialEmployee(LEARCredentialEmployeeJwtPayload baseLearCredentialEmployee, String mandateeId) { return Mono.just( LEARCredentialEmployeeJwtPayload.builder().learCredentialEmployee( @@ -139,10 +146,11 @@ private Mono bindMandateeIdToLearCredentialEmp .build()) .build()) .build()) - .subject(baseLearCredentialEmployee.subject()) + .subject(mandateeId) .JwtId(baseLearCredentialEmployee.JwtId()) .expirationTime(baseLearCredentialEmployee.expirationTime()) .issuedAt(baseLearCredentialEmployee.issuedAt()) + .issuer(baseLearCredentialEmployee.issuer()) .notValidBefore(baseLearCredentialEmployee.notValidBefore()) .build()); } @@ -157,16 +165,27 @@ private Mono convertLEARCredentialEmployeeInToString(LEARCredentialEmplo } private Mono buildCredentialProcedureCreationRequest(String decodedCredential, LEARCredentialEmployeeJwtPayload learCredentialEmployeeJwtPayload) { - return accessTokenService.getOrganizationIdFromCurrentSession() - .flatMap(organizationId -> - Mono.just( - CredentialProcedureCreationRequest.builder() - .credentialId(learCredentialEmployeeJwtPayload.learCredentialEmployee().id()) - .organizationIdentifier(organizationId) - .credentialDecoded(decodedCredential) - .build() - ) - ); + return Mono.just( + CredentialProcedureCreationRequest.builder() + .credentialId(learCredentialEmployeeJwtPayload.learCredentialEmployee().id()) + .organizationIdentifier(learCredentialEmployeeJwtPayload.learCredentialEmployee().credentialSubject().mandate().mandator().organizationIdentifier()) + .credentialDecoded(decodedCredential) + .build() + ); } + //TODO: metodo que implemente la extracción del organizationIdentifier desde la sessión (reemplaza al buildCredentialProcedureCreationRequest()) +// private Mono buildCredentialProcedureCreationRequest(String decodedCredential, LEARCredentialEmployeeJwtPayload learCredentialEmployeeJwtPayload) { +// return accessTokenService.getOrganizationIdFromCurrentSession() +// .flatMap(organizationId -> +// Mono.just( +// CredentialProcedureCreationRequest.builder() +// .credentialId(learCredentialEmployeeJwtPayload.learCredentialEmployee().id()) +// .organizationIdentifier(organizationId) +// .credentialDecoded(decodedCredential) +// .build() +// ) +// ); +// } + } From 4c39fca4e6294aad65ed0e9732702a285dda53dc Mon Sep 17 00:00:00 2001 From: Dmitri Sidorov Manko <159002112+dmitriin2@users.noreply.github.com> Date: Tue, 4 Jun 2024 08:24:38 +0200 Subject: [PATCH 07/12] temporary unsecure deferred-credntials endpoints --- .../es/in2/issuer/infrastructure/config/SecurityConfig.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/es/in2/issuer/infrastructure/config/SecurityConfig.java b/src/main/java/es/in2/issuer/infrastructure/config/SecurityConfig.java index 46134ed16..0fa3393a6 100644 --- a/src/main/java/es/in2/issuer/infrastructure/config/SecurityConfig.java +++ b/src/main/java/es/in2/issuer/infrastructure/config/SecurityConfig.java @@ -64,6 +64,8 @@ public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) .pathMatchers(HttpMethod.GET, "/api/v1/credential-offer/**").permitAll() .pathMatchers(HttpMethod.GET, "/api/v1/procedures/**").permitAll() .pathMatchers(HttpMethod.POST, "/api/v1/notifications").permitAll() + .pathMatchers(HttpMethod.POST, "/api/v1/deferred-credentials").permitAll() + .pathMatchers(HttpMethod.GET, "/api/v1/deferred-credentials").permitAll() .anyExchange().authenticated() ).csrf(ServerHttpSecurity.CsrfSpec::disable) .oauth2ResourceServer(oauth2ResourceServer -> From 07053d4e08e9b736ea916fd1c08b44e6df9871ce Mon Sep 17 00:00:00 2001 From: Dmitri Sidorov Manko <159002112+dmitriin2@users.noreply.github.com> Date: Tue, 4 Jun 2024 16:39:02 +0200 Subject: [PATCH 08/12] securized endpoints, did:elsi prefix for issuer, notification endpoint pathvariable --- .../es/in2/issuer/domain/util/Constants.java | 2 +- .../LEARCredentialEmployeeFactory.java | 36 +++++++------------ .../infrastructure/config/SecurityConfig.java | 9 +---- .../controller/NotificationController.java | 5 +-- 4 files changed, 17 insertions(+), 35 deletions(-) diff --git a/src/main/java/es/in2/issuer/domain/util/Constants.java b/src/main/java/es/in2/issuer/domain/util/Constants.java index 2ac7465b3..7b2edede0 100644 --- a/src/main/java/es/in2/issuer/domain/util/Constants.java +++ b/src/main/java/es/in2/issuer/domain/util/Constants.java @@ -36,5 +36,5 @@ private Constants() { public static final String CONTENT_TYPE = "Content-Type"; public static final String CONTENT_TYPE_APPLICATION_JSON = "application/json"; public static final String CONTENT_TYPE_URL_ENCODED_FORM = "application/x-www-form-urlencoded"; - + public static final String DID_ELSI = "did:elsi:"; } diff --git a/src/main/java/es/in2/issuer/domain/util/factory/LEARCredentialEmployeeFactory.java b/src/main/java/es/in2/issuer/domain/util/factory/LEARCredentialEmployeeFactory.java index b96300b3d..46130138b 100644 --- a/src/main/java/es/in2/issuer/domain/util/factory/LEARCredentialEmployeeFactory.java +++ b/src/main/java/es/in2/issuer/domain/util/factory/LEARCredentialEmployeeFactory.java @@ -19,8 +19,7 @@ import java.util.List; import java.util.UUID; -import static es.in2.issuer.domain.util.Constants.LEAR_CREDENTIAL_EMPLOYEE; -import static es.in2.issuer.domain.util.Constants.VERIFIABLE_CREDENTIAL; +import static es.in2.issuer.domain.util.Constants.*; @Component @RequiredArgsConstructor @@ -84,7 +83,7 @@ private Mono buildFinalLearCredentialEmployee(LEARCreden .validFrom(currentTime.toString()) .id(UUID.randomUUID().toString()) .type(List.of(LEAR_CREDENTIAL_EMPLOYEE, VERIFIABLE_CREDENTIAL)) - .issuer(baseLearCredentialEmployee.mandate().mandator().organizationIdentifier()) + .issuer(DID_ELSI + baseLearCredentialEmployee.mandate().mandator().organizationIdentifier()) .credentialSubject(LEARCredentialEmployee.CredentialSubject.builder() .mandate(LEARCredentialEmployee.CredentialSubject.Mandate.builder() .id(UUID.randomUUID().toString()) @@ -165,27 +164,16 @@ private Mono convertLEARCredentialEmployeeInToString(LEARCredentialEmplo } private Mono buildCredentialProcedureCreationRequest(String decodedCredential, LEARCredentialEmployeeJwtPayload learCredentialEmployeeJwtPayload) { - return Mono.just( - CredentialProcedureCreationRequest.builder() - .credentialId(learCredentialEmployeeJwtPayload.learCredentialEmployee().id()) - .organizationIdentifier(learCredentialEmployeeJwtPayload.learCredentialEmployee().credentialSubject().mandate().mandator().organizationIdentifier()) - .credentialDecoded(decodedCredential) - .build() - ); + return accessTokenService.getOrganizationIdFromCurrentSession() + .flatMap(organizationId -> + Mono.just( + CredentialProcedureCreationRequest.builder() + .credentialId(learCredentialEmployeeJwtPayload.learCredentialEmployee().id()) + .organizationIdentifier(organizationId) + .credentialDecoded(decodedCredential) + .build() + ) + ); } - //TODO: metodo que implemente la extracción del organizationIdentifier desde la sessión (reemplaza al buildCredentialProcedureCreationRequest()) -// private Mono buildCredentialProcedureCreationRequest(String decodedCredential, LEARCredentialEmployeeJwtPayload learCredentialEmployeeJwtPayload) { -// return accessTokenService.getOrganizationIdFromCurrentSession() -// .flatMap(organizationId -> -// Mono.just( -// CredentialProcedureCreationRequest.builder() -// .credentialId(learCredentialEmployeeJwtPayload.learCredentialEmployee().id()) -// .organizationIdentifier(organizationId) -// .credentialDecoded(decodedCredential) -// .build() -// ) -// ); -// } - } diff --git a/src/main/java/es/in2/issuer/infrastructure/config/SecurityConfig.java b/src/main/java/es/in2/issuer/infrastructure/config/SecurityConfig.java index 0fa3393a6..40a54deaf 100644 --- a/src/main/java/es/in2/issuer/infrastructure/config/SecurityConfig.java +++ b/src/main/java/es/in2/issuer/infrastructure/config/SecurityConfig.java @@ -56,16 +56,9 @@ public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) .authorizeExchange(exchanges -> exchanges .pathMatchers(getSwaggerPaths()).permitAll() .pathMatchers(PUBLIC_HEALTH).permitAll() - //.pathMatchers(PUBLIC_CREDENTIAL_OFFER).permitAll() + .pathMatchers(PUBLIC_CREDENTIAL_OFFER).permitAll() .pathMatchers(PUBLIC_DISCOVERY_ISSUER).permitAll() .pathMatchers(PUBLIC_DISCOVERY_AUTH_SERVER).permitAll() - //TODO: securizar este endpoint - .pathMatchers(HttpMethod.POST, "/api/v1/credentials").permitAll() - .pathMatchers(HttpMethod.GET, "/api/v1/credential-offer/**").permitAll() - .pathMatchers(HttpMethod.GET, "/api/v1/procedures/**").permitAll() - .pathMatchers(HttpMethod.POST, "/api/v1/notifications").permitAll() - .pathMatchers(HttpMethod.POST, "/api/v1/deferred-credentials").permitAll() - .pathMatchers(HttpMethod.GET, "/api/v1/deferred-credentials").permitAll() .anyExchange().authenticated() ).csrf(ServerHttpSecurity.CsrfSpec::disable) .oauth2ResourceServer(oauth2ResourceServer -> diff --git a/src/main/java/es/in2/issuer/infrastructure/controller/NotificationController.java b/src/main/java/es/in2/issuer/infrastructure/controller/NotificationController.java index 0ace358e1..59e044b56 100644 --- a/src/main/java/es/in2/issuer/infrastructure/controller/NotificationController.java +++ b/src/main/java/es/in2/issuer/infrastructure/controller/NotificationController.java @@ -4,6 +4,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; import reactor.core.publisher.Mono; @@ -17,9 +18,9 @@ public class NotificationController { private final NotificationService notificationService; - @PostMapping + @PostMapping(value = "/{procedure_id}", produces = MediaType.APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.NO_CONTENT) - public Mono sendEmailNotification(@RequestParam("procedure_id") String procedureId) { + public Mono sendEmailNotification(@PathVariable("procedure_id") String procedureId) { String processId = UUID.randomUUID().toString(); return notificationService.sendNotification(processId, procedureId); } From 9a8d2fff9fefa1df5a30cb3ea6ec3c9713d740a7 Mon Sep 17 00:00:00 2001 From: Dmitri Sidorov Manko <159002112+dmitriin2@users.noreply.github.com> Date: Wed, 5 Jun 2024 10:51:44 +0200 Subject: [PATCH 09/12] add @context to credential --- .../es/in2/issuer/domain/model/dto/LEARCredentialEmployee.java | 1 + src/main/java/es/in2/issuer/domain/util/Constants.java | 3 +++ .../domain/util/factory/LEARCredentialEmployeeFactory.java | 2 ++ 3 files changed, 6 insertions(+) diff --git a/src/main/java/es/in2/issuer/domain/model/dto/LEARCredentialEmployee.java b/src/main/java/es/in2/issuer/domain/model/dto/LEARCredentialEmployee.java index 056346204..be2a80030 100644 --- a/src/main/java/es/in2/issuer/domain/model/dto/LEARCredentialEmployee.java +++ b/src/main/java/es/in2/issuer/domain/model/dto/LEARCredentialEmployee.java @@ -7,6 +7,7 @@ @Builder public record LEARCredentialEmployee( + @JsonProperty("@context") List context, @JsonProperty("id") String id, @JsonProperty("type") List type, @JsonProperty("credentialSubject") CredentialSubject credentialSubject, diff --git a/src/main/java/es/in2/issuer/domain/util/Constants.java b/src/main/java/es/in2/issuer/domain/util/Constants.java index 7b2edede0..baf90b36a 100644 --- a/src/main/java/es/in2/issuer/domain/util/Constants.java +++ b/src/main/java/es/in2/issuer/domain/util/Constants.java @@ -1,5 +1,7 @@ package es.in2.issuer.domain.util; +import java.util.List; + public class Constants { private Constants() { @@ -37,4 +39,5 @@ private Constants() { public static final String CONTENT_TYPE_APPLICATION_JSON = "application/json"; public static final String CONTENT_TYPE_URL_ENCODED_FORM = "application/x-www-form-urlencoded"; public static final String DID_ELSI = "did:elsi:"; + public static final List CREDENTIAL_CONTEXT = List.of("https://www.w3.org/ns/credentials/v2","https://dome-marketplace.eu/2022/credentials/learcredential/v1"); } diff --git a/src/main/java/es/in2/issuer/domain/util/factory/LEARCredentialEmployeeFactory.java b/src/main/java/es/in2/issuer/domain/util/factory/LEARCredentialEmployeeFactory.java index 46130138b..3ca29713c 100644 --- a/src/main/java/es/in2/issuer/domain/util/factory/LEARCredentialEmployeeFactory.java +++ b/src/main/java/es/in2/issuer/domain/util/factory/LEARCredentialEmployeeFactory.java @@ -82,6 +82,7 @@ private Mono buildFinalLearCredentialEmployee(LEARCreden .issuanceDate(currentTime.toString()) .validFrom(currentTime.toString()) .id(UUID.randomUUID().toString()) + .context(CREDENTIAL_CONTEXT) .type(List.of(LEAR_CREDENTIAL_EMPLOYEE, VERIFIABLE_CREDENTIAL)) .issuer(DID_ELSI + baseLearCredentialEmployee.mandate().mandator().organizationIdentifier()) .credentialSubject(LEARCredentialEmployee.CredentialSubject.builder() @@ -127,6 +128,7 @@ private Mono bindMandateeIdToLearCredentialEmp .issuanceDate(baseLearCredentialEmployee.learCredentialEmployee().issuanceDate()) .validFrom(baseLearCredentialEmployee.learCredentialEmployee().validFrom()) .id(baseLearCredentialEmployee.learCredentialEmployee().id()) + .context(baseLearCredentialEmployee.learCredentialEmployee().context()) .type(baseLearCredentialEmployee.learCredentialEmployee().type()) .issuer(baseLearCredentialEmployee.issuer()) .credentialSubject(LEARCredentialEmployee.CredentialSubject.builder() From 428705c119fcdf4fa27e73aad4e992b78dde21c8 Mon Sep 17 00:00:00 2001 From: Dmitri Sidorov Manko <159002112+dmitriin2@users.noreply.github.com> Date: Mon, 10 Jun 2024 17:39:20 +0200 Subject: [PATCH 10/12] mutual tls WIP --- .../domain/service/CertificateService.java | 8 ++ .../service/impl/CertificateServiceImpl.java | 78 +++++++++++++++++++ .../infrastructure/config/SecurityConfig.java | 2 + .../DeferredCredentialController.java | 10 ++- 4 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 src/main/java/es/in2/issuer/domain/service/CertificateService.java create mode 100644 src/main/java/es/in2/issuer/domain/service/impl/CertificateServiceImpl.java diff --git a/src/main/java/es/in2/issuer/domain/service/CertificateService.java b/src/main/java/es/in2/issuer/domain/service/CertificateService.java new file mode 100644 index 000000000..c846317b1 --- /dev/null +++ b/src/main/java/es/in2/issuer/domain/service/CertificateService.java @@ -0,0 +1,8 @@ +package es.in2.issuer.domain.service; + +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +public interface CertificateService { + Mono getOrganizationIdFromCertificate(ServerWebExchange exchange); +} diff --git a/src/main/java/es/in2/issuer/domain/service/impl/CertificateServiceImpl.java b/src/main/java/es/in2/issuer/domain/service/impl/CertificateServiceImpl.java new file mode 100644 index 000000000..04f49e2be --- /dev/null +++ b/src/main/java/es/in2/issuer/domain/service/impl/CertificateServiceImpl.java @@ -0,0 +1,78 @@ +package es.in2.issuer.domain.service.impl; + +import es.in2.issuer.domain.service.AccessTokenService; +import es.in2.issuer.domain.service.CertificateService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.x500.AttributeTypeAndValue; +import org.bouncycastle.asn1.x500.RDN; +import org.bouncycastle.asn1.x500.X500Name; +import org.springframework.stereotype.Service; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +import javax.security.auth.x500.X500Principal; +import java.io.ByteArrayInputStream; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Base64; + +@Slf4j +@Service +@RequiredArgsConstructor +public class CertificateServiceImpl implements CertificateService { + private final AccessTokenService accessTokenService; + + @Override + public Mono getOrganizationIdFromCertificate(ServerWebExchange exchange){ + return extractClientCertificate(exchange) + .flatMap(this::extractOrganizationIdFromCert); + //.flatMap(accessTokenService::getOrganizationId); + } + + public Mono extractClientCertificate(ServerWebExchange exchange) { + return Mono.justOrEmpty(exchange.getRequest().getHeaders().getFirst("X-Client-Cert")) + .flatMap(encodedCert -> { + try { + // Decode the Base64 encoded certificate + byte[] decodedBytes = Base64.getDecoder().decode(encodedCert); + + // Convert bytes to X509Certificate + CertificateFactory factory = CertificateFactory.getInstance("X.509"); + X509Certificate certificate = (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(decodedBytes)); + + // Return the certificate wrapped in a Mono + return Mono.just(certificate); + } catch (CertificateException | IllegalArgumentException e) { + // Handle errors by returning a Mono.error + return Mono.error(new RuntimeException("Invalid certificate format", e)); + } + }); + } + + private Mono validateCertWithAuthServer (X509Certificate cert){ + // call to keycloak to get a token + return Mono.just("test"); + } + + private Mono extractOrganizationIdFromCert(X509Certificate cert) { + return Mono.fromCallable(() -> { + X500Principal principal = cert.getSubjectX500Principal(); + X500Name x500Name = new X500Name(principal.getName()); + + // OID for the attribute we are looking for (2.5.4.97) + ASN1ObjectIdentifier organizationIdentifierOID = new ASN1ObjectIdentifier("2.5.4.97"); + + for (RDN rdn : x500Name.getRDNs(organizationIdentifierOID)) { + for (AttributeTypeAndValue atv : rdn.getTypesAndValues()) { + if (atv.getType().equals(organizationIdentifierOID)) { + return atv.getValue().toString(); + } + } + } + throw new RuntimeException("Organization ID not found in the certificate"); + }); + } +} diff --git a/src/main/java/es/in2/issuer/infrastructure/config/SecurityConfig.java b/src/main/java/es/in2/issuer/infrastructure/config/SecurityConfig.java index 40a54deaf..8c4b797c2 100644 --- a/src/main/java/es/in2/issuer/infrastructure/config/SecurityConfig.java +++ b/src/main/java/es/in2/issuer/infrastructure/config/SecurityConfig.java @@ -59,6 +59,8 @@ public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) .pathMatchers(PUBLIC_CREDENTIAL_OFFER).permitAll() .pathMatchers(PUBLIC_DISCOVERY_ISSUER).permitAll() .pathMatchers(PUBLIC_DISCOVERY_AUTH_SERVER).permitAll() + .pathMatchers(HttpMethod.POST, "/api/v1/deferred-credentials").permitAll() + .pathMatchers(HttpMethod.GET, "/api/v1/deferred-credentials").permitAll() .anyExchange().authenticated() ).csrf(ServerHttpSecurity.CsrfSpec::disable) .oauth2ResourceServer(oauth2ResourceServer -> diff --git a/src/main/java/es/in2/issuer/infrastructure/controller/DeferredCredentialController.java b/src/main/java/es/in2/issuer/infrastructure/controller/DeferredCredentialController.java index f144daea4..4c49e2abd 100644 --- a/src/main/java/es/in2/issuer/infrastructure/controller/DeferredCredentialController.java +++ b/src/main/java/es/in2/issuer/infrastructure/controller/DeferredCredentialController.java @@ -3,11 +3,13 @@ import es.in2.issuer.application.workflow.DeferredCredentialWorkflow; import es.in2.issuer.domain.model.dto.PendingCredentials; import es.in2.issuer.domain.model.dto.SignedCredentials; +import es.in2.issuer.domain.service.CertificateService; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.*; +import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; @Slf4j @@ -17,13 +19,13 @@ public class DeferredCredentialController { private final DeferredCredentialWorkflow deferredCredentialWorkflow; + private final CertificateService certificateService; @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) - public Mono getUnsignedCredentials(@RequestHeader(value = "X-SSL-Client-Cert") String clientCert) { - // todo: implement clientCert validation through Keycloak before executing the following code - log.debug(clientCert); - return deferredCredentialWorkflow.getPendingCredentialsByOrganizationId(clientCert); + public Mono getUnsignedCredentials(ServerWebExchange exchange) { + return certificateService.getOrganizationIdFromCertificate(exchange) + .flatMap(deferredCredentialWorkflow::getPendingCredentialsByOrganizationId); } @PostMapping(produces = MediaType.APPLICATION_JSON_VALUE) From ef0ca6a7323e2a6014d1d88d12d308400d91c660 Mon Sep 17 00:00:00 2001 From: Dmitri Sidorov Manko <159002112+dmitriin2@users.noreply.github.com> Date: Tue, 11 Jun 2024 17:21:17 +0200 Subject: [PATCH 11/12] organizationid from certificate deferred-credentials --- .../domain/service/CertificateService.java | 2 +- .../service/impl/CertificateServiceImpl.java | 18 ++++++++++++------ .../DeferredCredentialController.java | 5 +++-- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/main/java/es/in2/issuer/domain/service/CertificateService.java b/src/main/java/es/in2/issuer/domain/service/CertificateService.java index c846317b1..9a6751b3e 100644 --- a/src/main/java/es/in2/issuer/domain/service/CertificateService.java +++ b/src/main/java/es/in2/issuer/domain/service/CertificateService.java @@ -4,5 +4,5 @@ import reactor.core.publisher.Mono; public interface CertificateService { - Mono getOrganizationIdFromCertificate(ServerWebExchange exchange); + Mono getOrganizationIdFromCertificate(String cert); } diff --git a/src/main/java/es/in2/issuer/domain/service/impl/CertificateServiceImpl.java b/src/main/java/es/in2/issuer/domain/service/impl/CertificateServiceImpl.java index 04f49e2be..ee9aec92b 100644 --- a/src/main/java/es/in2/issuer/domain/service/impl/CertificateServiceImpl.java +++ b/src/main/java/es/in2/issuer/domain/service/impl/CertificateServiceImpl.java @@ -26,18 +26,24 @@ public class CertificateServiceImpl implements CertificateService { private final AccessTokenService accessTokenService; @Override - public Mono getOrganizationIdFromCertificate(ServerWebExchange exchange){ - return extractClientCertificate(exchange) + public Mono getOrganizationIdFromCertificate(String cert){ + return extractClientCertificate(cert) .flatMap(this::extractOrganizationIdFromCert); //.flatMap(accessTokenService::getOrganizationId); } - public Mono extractClientCertificate(ServerWebExchange exchange) { - return Mono.justOrEmpty(exchange.getRequest().getHeaders().getFirst("X-Client-Cert")) + public Mono extractClientCertificate(String cert) { + return Mono.justOrEmpty(cert) .flatMap(encodedCert -> { try { - // Decode the Base64 encoded certificate - byte[] decodedBytes = Base64.getDecoder().decode(encodedCert); + // Clean the certificate by removing PEM headers and any whitespace or newlines + String cleanedCert = encodedCert + .replaceAll("-----BEGIN CERTIFICATE-----", "") + .replaceAll("-----END CERTIFICATE-----", "") + .replaceAll("\\s+", ""); // Remove any whitespace + + // Decode the cleaned Base64 encoded certificate + byte[] decodedBytes = Base64.getDecoder().decode(cleanedCert); // Convert bytes to X509Certificate CertificateFactory factory = CertificateFactory.getInstance("X.509"); diff --git a/src/main/java/es/in2/issuer/infrastructure/controller/DeferredCredentialController.java b/src/main/java/es/in2/issuer/infrastructure/controller/DeferredCredentialController.java index 4c49e2abd..fa6c6a4ba 100644 --- a/src/main/java/es/in2/issuer/infrastructure/controller/DeferredCredentialController.java +++ b/src/main/java/es/in2/issuer/infrastructure/controller/DeferredCredentialController.java @@ -23,8 +23,9 @@ public class DeferredCredentialController { @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) - public Mono getUnsignedCredentials(ServerWebExchange exchange) { - return certificateService.getOrganizationIdFromCertificate(exchange) + public Mono getUnsignedCredentials(@RequestHeader(value = "X-SSL-Client-Cert") String clientCert) { + // todo: implement clientCert validation through Keycloak before executing the following code + return certificateService.getOrganizationIdFromCertificate(clientCert) .flatMap(deferredCredentialWorkflow::getPendingCredentialsByOrganizationId); } From 9624ec6342d18ccbc5c936882dd3cd6bd237062e Mon Sep 17 00:00:00 2001 From: "@juanmartinin2" <154328203+juanmartinin2@users.noreply.github.com> Date: Fri, 21 Jun 2024 09:05:44 +0200 Subject: [PATCH 12/12] Feature/credentials-management-tests (#22) * Firsts basic tests + commented test fix * util package coverage > 80% * Infrastructure->Properties package coverage > 80% * Infrastructure->controller package coverage > 80% * Created test for workflows package * Reorganization of model test files + new tests * Domain->Entities package coverage > 80% + last branch merge * Domain->Factory package coverage > 80% * Tests for AuthServerConfig class + sonarlint issues fix * New tests for config package * test for verifiableCredentialService * Service tests + use of @ExtendWith instead of MockitoAnnotations * test for CredentialProcedureService * New service tests * Plugins and dependencies updates + Sonar corrections * DTO package path correction --------- Co-authored-by: RubenModamioGarcia Co-authored-by: Dmitri Sidorov Manko <159002112+dmitriin2@users.noreply.github.com> --- build.gradle | 303 ++++----- .../templates/LEARCredentialEmployee.json | 3 +- ...edentialOfferIssuanceWorkflowImplTest.java | 134 ++-- .../DeferredCredentialWorkflowImplTest.java | 148 ++++ ...ableCredentialIssuanceServiceImplTest.java | 535 +++++++-------- .../model/dto/AuthServerNonceRequestTest.java | 42 ++ .../dto/AuthorizationServerMetadataTest.java | 34 + .../model/dto/BatchCredentialRequestTest.java | 48 ++ .../dto/BatchCredentialResponseTest.java | 52 ++ .../model/{ => dto}/CommitCredentialTest.java | 5 +- .../dto/CredentialConfigurationTest.java | 82 +++ .../model/dto/CredentialDetailsTest.java | 72 ++ .../CredentialErrorResponseTest.java | 5 +- .../CredentialIssuerMetadataTest.java | 5 +- ...redentialProcedureCreationRequestTest.java | 71 ++ .../model/dto/CredentialProceduresTest.java | 72 ++ .../{ => dto}/CredentialRequestTest.java | 7 +- .../{ => dto}/CustomCredentialOfferTest.java | 6 +- ...redentialMetadataDeferredResponseTest.java | 80 +++ .../dto/DeferredCredentialRequestTest.java | 34 + .../{ => dto}/GlobalErrorMessageTest.java | 5 +- .../domain/model/{ => dto}/GrantTest.java | 7 +- .../LEARCredentialEmployeeJwtPayloadTest.java | 138 ++++ .../model/dto/LEARCredentialEmployeeTest.java | 60 ++ .../model/dto/LEARCredentialRequestTest.java | 40 ++ .../dto/NonceValidationResponseTest.java | 34 + .../model/dto/PendingCredentialsTest.java | 52 ++ .../model/dto/PreAuthCodeResponseTest.java | 42 ++ .../model/dto/ProcedureBasicInfoTest.java | 83 +++ .../domain/model/{ => dto}/ProofTest.java | 5 +- .../{ => dto}/SignatureConfigurationTest.java | 5 +- .../model/{ => dto}/SignatureRequestTest.java | 6 +- .../model/dto/SignedCredentialsTest.java | 52 ++ .../model/{ => dto}/SignedDataTest.java | 5 +- .../{ => dto}/SubjectDataResponseTest.java | 5 +- .../domain/model/dto/VcTemplateTest.java | 59 ++ .../VerifiableCredentialJWTTest.java | 5 +- .../VerifiableCredentialResponseTest.java | 16 +- .../{ => dto}/VerifiableCredentialTest.java | 5 +- .../entities/CredentialProcedureTest.java | 90 +++ .../DeferredCredentialMetadataTest.java | 82 +++ .../service/AccessTokenServiceImplTest.java | 164 ++++- ...edentialIssuerMetadataServiceImplTest.java | 115 ++-- ...ntialOfferCacheStorageServiceImplTest.java | 10 +- .../CredentialProcedureServiceImplTest.java | 633 ++++++++++++++++++ ...rredCredentialMetadataServiceImplTest.java | 428 ++++++------ .../domain/service/EmailServiceImplTest.java | 87 +++ .../IssuerApiClientTokenServiceImplTest.java | 150 +++++ .../service/NotificationServiceImplTest.java | 102 +++ .../RemoteSignatureServiceImplTest.java | 254 +++---- .../VerifiableCredentialServiceImplTest.java | 423 ++++++++---- .../domain/util/EndpointsConstantsTest.java | 19 + .../in2/issuer/domain/util/HttpUtilsTest.java | 72 +- .../es/in2/issuer/domain/util/UtilsTest.java | 32 + .../util/factory/CredentialFactoryTest.java | 94 +++ .../LEARCredentialEmployeeFactoryTest.java | 108 +++ .../infrastructure/config/AppConfigTest.java | 179 +++-- .../config/AuthServerConfigTest.java | 158 +++++ .../config/AzureAppConfigConfigTest.java | 12 +- .../config/CacheStoreConfigTest.java | 51 ++ .../config/OpenAppConfigTest.java | 16 +- .../config/RemoteSignatureConfigTest.java | 79 +++ .../config/SecurityConfigTest.java | 114 ---- .../config/SwaggerConfigTest.java | 52 +- .../adapter/AzureConfigAdapterTest.java | 14 +- ...zureConfigurationSettingExceptionTest.java | 15 + .../ConfigAdapterFactoryExceptionTest.java | 14 + .../factory/ConfigAdapterFactoryTest.java | 116 ++-- .../properties/ApiConfigPropertiesTest.java | 39 -- .../config/properties/ApiPropertiesTest.java | 20 + .../properties/AuthServerPropertiesTest.java | 22 + .../properties/AzurePropertiesTest.java | 16 + .../properties/IssuerUiPropertiesTest.java | 15 + .../properties/OpenApiPropertiesTest.java | 25 + .../RemoteSignaturePropertiesTest.java | 17 + .../controller/CredentialControllerTest.java | 116 ++++ .../CredentialManagementControllerTest.java | 81 +++ .../CredentialOfferControllerTest.java | 153 ++--- .../DeferredCredentialControllerTest.java | 65 ++ ...erredCredentialMetadataControllerTest.java | 153 ++--- .../GlobalExceptionHandlerTest.java | 41 +- .../NotificationControllerTest.java | 38 ++ .../VerifiableCredentialControllerTest.java | 98 --- 83 files changed, 5202 insertions(+), 1742 deletions(-) create mode 100644 src/test/java/es/in2/issuer/application/workflow/impl/DeferredCredentialWorkflowImplTest.java create mode 100644 src/test/java/es/in2/issuer/domain/model/dto/AuthServerNonceRequestTest.java create mode 100644 src/test/java/es/in2/issuer/domain/model/dto/AuthorizationServerMetadataTest.java create mode 100644 src/test/java/es/in2/issuer/domain/model/dto/BatchCredentialRequestTest.java create mode 100644 src/test/java/es/in2/issuer/domain/model/dto/BatchCredentialResponseTest.java rename src/test/java/es/in2/issuer/domain/model/{ => dto}/CommitCredentialTest.java (93%) create mode 100644 src/test/java/es/in2/issuer/domain/model/dto/CredentialConfigurationTest.java create mode 100644 src/test/java/es/in2/issuer/domain/model/dto/CredentialDetailsTest.java rename src/test/java/es/in2/issuer/domain/model/{ => dto}/CredentialErrorResponseTest.java (92%) rename src/test/java/es/in2/issuer/domain/model/{ => dto}/CredentialIssuerMetadataTest.java (95%) create mode 100644 src/test/java/es/in2/issuer/domain/model/dto/CredentialProcedureCreationRequestTest.java create mode 100644 src/test/java/es/in2/issuer/domain/model/dto/CredentialProceduresTest.java rename src/test/java/es/in2/issuer/domain/model/{ => dto}/CredentialRequestTest.java (88%) rename src/test/java/es/in2/issuer/domain/model/{ => dto}/CustomCredentialOfferTest.java (96%) create mode 100644 src/test/java/es/in2/issuer/domain/model/dto/DeferredCredentialMetadataDeferredResponseTest.java create mode 100644 src/test/java/es/in2/issuer/domain/model/dto/DeferredCredentialRequestTest.java rename src/test/java/es/in2/issuer/domain/model/{ => dto}/GlobalErrorMessageTest.java (95%) rename src/test/java/es/in2/issuer/domain/model/{ => dto}/GrantTest.java (91%) create mode 100644 src/test/java/es/in2/issuer/domain/model/dto/LEARCredentialEmployeeJwtPayloadTest.java create mode 100644 src/test/java/es/in2/issuer/domain/model/dto/LEARCredentialEmployeeTest.java create mode 100644 src/test/java/es/in2/issuer/domain/model/dto/LEARCredentialRequestTest.java create mode 100644 src/test/java/es/in2/issuer/domain/model/dto/NonceValidationResponseTest.java create mode 100644 src/test/java/es/in2/issuer/domain/model/dto/PendingCredentialsTest.java create mode 100644 src/test/java/es/in2/issuer/domain/model/dto/PreAuthCodeResponseTest.java create mode 100644 src/test/java/es/in2/issuer/domain/model/dto/ProcedureBasicInfoTest.java rename src/test/java/es/in2/issuer/domain/model/{ => dto}/ProofTest.java (93%) rename src/test/java/es/in2/issuer/domain/model/{ => dto}/SignatureConfigurationTest.java (94%) rename src/test/java/es/in2/issuer/domain/model/{ => dto}/SignatureRequestTest.java (89%) create mode 100644 src/test/java/es/in2/issuer/domain/model/dto/SignedCredentialsTest.java rename src/test/java/es/in2/issuer/domain/model/{ => dto}/SignedDataTest.java (92%) rename src/test/java/es/in2/issuer/domain/model/{ => dto}/SubjectDataResponseTest.java (92%) create mode 100644 src/test/java/es/in2/issuer/domain/model/dto/VcTemplateTest.java rename src/test/java/es/in2/issuer/domain/model/{ => dto}/VerifiableCredentialJWTTest.java (91%) rename src/test/java/es/in2/issuer/domain/model/{ => dto}/VerifiableCredentialResponseTest.java (71%) rename src/test/java/es/in2/issuer/domain/model/{ => dto}/VerifiableCredentialTest.java (95%) create mode 100644 src/test/java/es/in2/issuer/domain/model/entities/CredentialProcedureTest.java create mode 100644 src/test/java/es/in2/issuer/domain/model/entities/DeferredCredentialMetadataTest.java create mode 100644 src/test/java/es/in2/issuer/domain/service/CredentialProcedureServiceImplTest.java create mode 100644 src/test/java/es/in2/issuer/domain/service/EmailServiceImplTest.java create mode 100644 src/test/java/es/in2/issuer/domain/service/IssuerApiClientTokenServiceImplTest.java create mode 100644 src/test/java/es/in2/issuer/domain/service/NotificationServiceImplTest.java create mode 100644 src/test/java/es/in2/issuer/domain/util/EndpointsConstantsTest.java create mode 100644 src/test/java/es/in2/issuer/domain/util/UtilsTest.java create mode 100644 src/test/java/es/in2/issuer/domain/util/factory/CredentialFactoryTest.java create mode 100644 src/test/java/es/in2/issuer/domain/util/factory/LEARCredentialEmployeeFactoryTest.java create mode 100644 src/test/java/es/in2/issuer/infrastructure/config/AuthServerConfigTest.java create mode 100644 src/test/java/es/in2/issuer/infrastructure/config/CacheStoreConfigTest.java create mode 100644 src/test/java/es/in2/issuer/infrastructure/config/RemoteSignatureConfigTest.java delete mode 100644 src/test/java/es/in2/issuer/infrastructure/config/SecurityConfigTest.java create mode 100644 src/test/java/es/in2/issuer/infrastructure/config/adapter/exception/AzureConfigurationSettingExceptionTest.java create mode 100644 src/test/java/es/in2/issuer/infrastructure/config/adapter/exception/ConfigAdapterFactoryExceptionTest.java delete mode 100644 src/test/java/es/in2/issuer/infrastructure/config/properties/ApiConfigPropertiesTest.java create mode 100644 src/test/java/es/in2/issuer/infrastructure/config/properties/ApiPropertiesTest.java create mode 100644 src/test/java/es/in2/issuer/infrastructure/config/properties/AuthServerPropertiesTest.java create mode 100644 src/test/java/es/in2/issuer/infrastructure/config/properties/AzurePropertiesTest.java create mode 100644 src/test/java/es/in2/issuer/infrastructure/config/properties/IssuerUiPropertiesTest.java create mode 100644 src/test/java/es/in2/issuer/infrastructure/config/properties/OpenApiPropertiesTest.java create mode 100644 src/test/java/es/in2/issuer/infrastructure/config/properties/RemoteSignaturePropertiesTest.java create mode 100644 src/test/java/es/in2/issuer/infrastructure/controller/CredentialControllerTest.java create mode 100644 src/test/java/es/in2/issuer/infrastructure/controller/CredentialManagementControllerTest.java create mode 100644 src/test/java/es/in2/issuer/infrastructure/controller/DeferredCredentialControllerTest.java create mode 100644 src/test/java/es/in2/issuer/infrastructure/controller/NotificationControllerTest.java delete mode 100644 src/test/java/es/in2/issuer/infrastructure/controller/VerifiableCredentialControllerTest.java diff --git a/build.gradle b/build.gradle index 970e62c3a..35d576592 100644 --- a/build.gradle +++ b/build.gradle @@ -1,210 +1,215 @@ plugins { - id 'java' - id 'org.springframework.boot' version '3.2.5' - id 'io.spring.dependency-management' version '1.1.4' - id 'jacoco' - id 'org.sonarqube' version '5.0.0.4638' - id 'checkstyle' - id 'org.owasp.dependencycheck' version '9.1.0' - id 'com.github.ben-manes.versions' version "0.51.0" - id 'se.patrikerdes.use-latest-versions' version '0.2.18' + id 'java' + id 'org.springframework.boot' version '3.3.0' + id 'io.spring.dependency-management' version '1.1.5' + id 'jacoco' + id 'org.sonarqube' version '5.0.0.4638' + id 'checkstyle' + id 'org.owasp.dependencycheck' version '9.2.0' + id 'com.github.ben-manes.versions' version "0.51.0" + id 'se.patrikerdes.use-latest-versions' version '0.2.18' } group = 'es.in2' -version = '0.8.0' +version = '1.1.0' java { - sourceCompatibility = '17' + sourceCompatibility = '17' } jacoco { - toolVersion = "0.8.11" + toolVersion = "0.8.11" } checkstyle { - configFile = file("${rootDir}/config/checkstyle/checkstyle.xml") + configFile = file("${rootDir}/config/checkstyle/checkstyle.xml") } checkstyleMain { - source ='src/main/java' + source = 'src/main/java' } checkstyleTest { - source ='src/test/java' + source = 'src/test/java' } sonar { - properties { - property "sonar.projectName", "Issuer API" - property "sonar.projectKey", "in2workspace_credential-issuer" - property "sonar.organization", "in2workspace" - property "sonar.host.url", "https://sonarcloud.io" - property "sonar.coverage.exclusions", - "src/main/java/es/in2/issuer/IssuerApiApplication.java, " - } + properties { + property "sonar.projectName", "Issuer API" + property "sonar.projectKey", "in2workspace_credential-issuer" + property "sonar.organization", "in2workspace" + property "sonar.host.url", "https://sonarcloud.io" + property "sonar.coverage.exclusions", + "src/main/java/es/in2/issuer/IssuerApiApplication.java, " + + "src/main/java/es/in2/desmos/infrastructure/config/FlywayConfig.java, " + + "src/main/java/es/in2/desmos/infrastructure/config/SecurityConfig.java, " + + } } configurations { - compileOnly { - extendsFrom annotationProcessor - } + compileOnly { + extendsFrom annotationProcessor + } } repositories { - mavenCentral() + mavenCentral() } ext { - set('springCloudVersion', "2023.0.0") + set('springCloudVersion', "2023.0.0") } dependencies { - // Spring - implementation 'org.springframework.boot:spring-boot-starter-webflux' - implementation 'org.springframework.boot:spring-boot-starter-actuator' - implementation 'org.springframework.boot:spring-boot-starter-validation' - implementation 'org.springframework.boot:spring-boot-starter-security' - implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server' - implementation 'org.springframework.boot:spring-boot-starter-mail:3.2.5' - implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.2.5' - - // EUDI Wallet libraries - implementation 'eu.europa.ec.eudi:eudi-lib-jvm-openid4vci-kt:0.1.3' - - // JSON - implementation 'com.fasterxml.jackson.core:jackson-databind' - implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310' - implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.0' - implementation 'com.fasterxml.jackson.core:jackson-annotations:2.17.0' - implementation 'com.fasterxml.jackson.core:jackson-core:2.17.0' - - // CBOR implementation - implementation 'com.upokecenter:cbor:4.5.2' - implementation 'com.augustcellars.cose:cose-java:1.1.0' - implementation 'org.apache.commons:commons-compress:1.26.1' - implementation 'io.github.ehn-digital-green-development:base45:0.0.3' - - // Proof decoding - implementation 'io.github.novacrypto:Base58:2022.01.17' - - // Persistence - implementation 'org.springframework.boot:spring-boot-starter-data-r2dbc' - implementation 'org.springframework:spring-jdbc' - runtimeOnly 'org.postgresql:r2dbc-postgresql' - runtimeOnly 'org.postgresql:postgresql' - implementation 'org.flywaydb:flyway-core' - - // In-Memory Persistence - implementation 'com.google.guava:guava:33.1.0-jre' - - // DevTools - developmentOnly 'org.springframework.boot:spring-boot-devtools' - implementation 'org.jetbrains:annotations:24.1.0' - implementation 'com.google.code.findbugs:jsr305:3.0.2' - compileOnly 'org.projectlombok:lombok' - annotationProcessor 'org.projectlombok:lombok' - - // Nimbus JWT - implementation 'com.nimbusds:nimbus-jose-jwt:9.38-rc3' - implementation 'io.jsonwebtoken:jjwt-api:0.12.3' - runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.5' - runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.5' - - // AZURE - implementation('com.azure.spring:spring-cloud-azure-starter-appconfiguration:5.7.0') - implementation('com.azure.spring:spring-cloud-azure-starter-keyvault-secrets:5.7.0') - - // Documentation - implementation 'org.springdoc:springdoc-openapi-starter-webflux-ui:2.5.0' - - // Logback - implementation 'net.logstash.logback:logstash-logback-encoder:7.4' - - // Monitoring - implementation 'io.micrometer:micrometer-tracing-bridge-brave' - runtimeOnly 'io.micrometer:micrometer-registry-prometheus' - - // Resilience - implementation 'org.springframework.cloud:spring-cloud-starter-circuitbreaker-reactor-resilience4j' - - // Unit Testing - testImplementation 'org.springframework.boot:spring-boot-starter-test' - testImplementation 'org.springframework.security:spring-security-test' - testImplementation 'io.projectreactor:reactor-test' - testImplementation 'org.springframework.boot:spring-boot-starter-aop' - testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.2' - testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.10.2' - testImplementation 'io.projectreactor:reactor-test' - testImplementation 'io.mockk:mockk:1.13.10' - testImplementation 'org.mockito:mockito-inline:5.2.0' - testImplementation 'com.squareup.okhttp3:mockwebserver:4.12.0' - testImplementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.17.0-rc1' - - // Integration Test - testImplementation 'org.springframework.boot:spring-boot-testcontainers' - testImplementation 'org.testcontainers:junit-jupiter' + // Spring + implementation 'org.springframework.boot:spring-boot-starter-webflux' + implementation 'org.springframework.boot:spring-boot-starter-actuator' + implementation 'org.springframework.boot:spring-boot-starter-validation' + implementation 'org.springframework.boot:spring-boot-starter-security' + implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server' + implementation 'org.springframework.boot:spring-boot-starter-mail:3.3.0' + implementation 'org.springframework.boot:spring-boot-starter-thymeleaf:3.3.0' + + // EUDI Wallet libraries + implementation 'eu.europa.ec.eudi:eudi-lib-jvm-openid4vci-kt:0.1.3' + + // JSON + implementation 'com.fasterxml.jackson.core:jackson-databind' + implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.1' + implementation 'com.fasterxml.jackson.core:jackson-annotations:2.17.1' + implementation 'com.fasterxml.jackson.core:jackson-core:2.17.1' + + // CBOR implementation + implementation 'com.upokecenter:cbor:4.5.4' + implementation 'com.augustcellars.cose:cose-java:1.1.0' + implementation 'org.apache.commons:commons-compress:1.26.2' + implementation 'io.github.ehn-digital-green-development:base45:0.0.3' + + // Proof decoding + implementation 'io.github.novacrypto:Base58:2022.01.17' + + // Persistence + implementation 'org.springframework.boot:spring-boot-starter-data-r2dbc' + implementation 'org.springframework:spring-jdbc' + runtimeOnly 'org.postgresql:r2dbc-postgresql' + runtimeOnly 'org.postgresql:postgresql' + implementation 'org.flywaydb:flyway-core' + + // In-Memory Persistence + implementation 'com.google.guava:guava:33.2.1-jre' + + // DevTools + developmentOnly 'org.springframework.boot:spring-boot-devtools' + implementation 'org.jetbrains:annotations:24.1.0' + implementation 'com.google.code.findbugs:jsr305:3.0.2' + compileOnly 'org.projectlombok:lombok' + annotationProcessor 'org.projectlombok:lombok' + + // Nimbus JWT + implementation 'com.nimbusds:nimbus-jose-jwt:9.40' + implementation 'io.jsonwebtoken:jjwt-api:0.12.5' + runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.5' + runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.5' + + // AZURE + implementation('com.azure.spring:spring-cloud-azure-starter-appconfiguration:5.7.0') + implementation('com.azure.spring:spring-cloud-azure-starter-keyvault-secrets:5.7.0') + + // Documentation + implementation 'org.springdoc:springdoc-openapi-starter-webflux-ui:2.5.0' + + // Logback + implementation 'net.logstash.logback:logstash-logback-encoder:7.4' + + // Monitoring + implementation 'io.micrometer:micrometer-tracing-bridge-brave' + runtimeOnly 'io.micrometer:micrometer-registry-prometheus' + + // Resilience + implementation 'org.springframework.cloud:spring-cloud-starter-circuitbreaker-reactor-resilience4j' + + // Unit Testing + testImplementation 'org.springframework.boot:spring-boot-starter-test' + testImplementation 'org.springframework.security:spring-security-test' + testImplementation 'io.projectreactor:reactor-test' + testImplementation 'org.springframework.boot:spring-boot-starter-aop' + testImplementation 'org.junit.jupiter:junit-jupiter-api:5.10.2' + testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.10.2' + testImplementation 'io.projectreactor:reactor-test' + testImplementation 'io.mockk:mockk:1.13.11' + testImplementation 'org.mockito:mockito-inline:5.2.0' + testImplementation 'com.squareup.okhttp3:mockwebserver:4.12.0' + testImplementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.17.1' + + // Integration Test + testImplementation 'org.springframework.boot:spring-boot-testcontainers' + testImplementation 'org.testcontainers:junit-jupiter' } dependencyManagement { - imports { - mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" - } + imports { + mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" + } } configurations.configureEach { - exclude module: 'slf4j-simple' + exclude module: 'slf4j-simple' } tasks.named('compileJava') { - inputs.files(tasks.named('processResources')) + inputs.files(tasks.named('processResources')) } tasks.named('test') { - useJUnitPlatform() - finalizedBy(tasks.jacocoTestReport) + useJUnitPlatform() + finalizedBy(tasks.jacocoTestReport) } tasks.jacocoTestReport { - dependsOn(tasks.test) - reports { - xml.required.set(true) - csv.required.set(false) - html.outputLocation.set(layout.buildDirectory.dir("jacocoHtml")) - } - classDirectories.setFrom(files(classDirectories.files.collect { - fileTree(dir: it, exclude: [ - "**/IssuerApiApplication.class", - "**/IssuerVciBackendApplication**", - "**/CredentialResponseErrorCodes**", - "**/configurations/**", - "**/handler/**", - "**/**Serializer**/**", - "**/enums/**", - "**/Constants**" - ]) - })) + dependsOn(tasks.test) + reports { + xml.required.set(true) + csv.required.set(false) + html.outputLocation.set(layout.buildDirectory.dir("jacocoHtml")) + } + classDirectories.setFrom(files(classDirectories.files.collect { + fileTree(dir: it, exclude: [ + "**/IssuerApiApplication.class", + "**/IssuerVciBackendApplication**", + "**/CredentialResponseErrorCodes**", + "**/configurations/**", + "**/handler/**", + "**/**Serializer**/**", + "**/enums/**", + "**/Constants**", + "**/infrastructure/config/FlywayConfig.class", + "**/infrastructure/config/SecurityConfig.class" + ]) + })) } tasks.register('printVersion') { - doLast { - println version - } + doLast { + println version + } } tasks.register('printProjectName') { - doLast { - println rootProject.name - } + doLast { + println rootProject.name + } } def isNonStable = { String version -> - def stableKeyword = ['RELEASE', 'FINAL', 'GA'].any { it -> version.toUpperCase().contains(it) } - def regex = /^[0-9,.v-]+(-r)?$/ - return !stableKeyword && !(version ==~ regex) + def stableKeyword = ['RELEASE', 'FINAL', 'GA'].any { it -> version.toUpperCase().contains(it) } + def regex = /^[0-9,.v-]+(-r)?$/ + return !stableKeyword && !(version ==~ regex) } tasks.named("dependencyUpdates").configure { - rejectVersionIf { - isNonStable(it.candidate.version) - } + rejectVersionIf { + isNonStable(it.candidate.version) + } } \ No newline at end of file diff --git a/src/main/resources/credentials/templates/LEARCredentialEmployee.json b/src/main/resources/credentials/templates/LEARCredentialEmployee.json index 8e8cefef9..87c410f26 100644 --- a/src/main/resources/credentials/templates/LEARCredentialEmployee.json +++ b/src/main/resources/credentials/templates/LEARCredentialEmployee.json @@ -15,7 +15,6 @@ "id": "did:key:zDnaeei6HxVe7ibR3mZmXa9SZgWs8UBj1FiTuwEKwmnChdUAu", "email": "oriol.canades@in2.es", "first_name": "Oriol", - "gender": "M", "last_name": "Canadés", "mobile_phone": "+34666336699" }, @@ -57,6 +56,6 @@ }, "expirationDate": "2025-04-02 09:23:22.637345122 +0000 UTC", "issuanceDate": "2024-04-02 09:23:22.637345122 +0000 UTC", - "issuer": "did:web:in2.es", + "issuer": "did:elsi:VATES-B60645900", "validFrom": "2024-04-02 09:23:22.637345122 +0000 UTC" } \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/application/workflow/impl/CredentialOfferIssuanceWorkflowImplTest.java b/src/test/java/es/in2/issuer/application/workflow/impl/CredentialOfferIssuanceWorkflowImplTest.java index 048c19de2..bd35eb772 100644 --- a/src/test/java/es/in2/issuer/application/workflow/impl/CredentialOfferIssuanceWorkflowImplTest.java +++ b/src/test/java/es/in2/issuer/application/workflow/impl/CredentialOfferIssuanceWorkflowImplTest.java @@ -1,10 +1,11 @@ package es.in2.issuer.application.workflow.impl; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import es.in2.issuer.domain.model.dto.CustomCredentialOffer; -import es.in2.issuer.domain.service.CredentialOfferCacheStorageService; -import es.in2.issuer.domain.service.EmailService; -import es.in2.issuer.domain.service.CredentialSchemaService; +import es.in2.issuer.domain.model.dto.Grant; +import es.in2.issuer.domain.model.dto.PreAuthCodeResponse; +import es.in2.issuer.domain.service.*; import es.in2.issuer.domain.service.impl.CredentialOfferServiceImpl; import es.in2.issuer.infrastructure.config.AuthServerConfig; import es.in2.issuer.infrastructure.config.WebClientConfig; @@ -13,9 +14,21 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpStatus; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.ExchangeFunction; +import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; +import java.util.List; +import java.util.Map; + +import static es.in2.issuer.domain.util.Constants.CONTENT_TYPE; +import static es.in2.issuer.domain.util.Constants.CONTENT_TYPE_APPLICATION_JSON; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) @@ -34,7 +47,11 @@ class CredentialOfferIssuanceWorkflowImplTest { private CredentialOfferCacheStorageService credentialOfferCacheStorageService; @Mock - private CredentialSchemaService credentialSchemaService; + private CredentialProcedureService credentialProcedureService; + @Mock + private DeferredCredentialMetadataService deferredCredentialMetadataService; + @Mock + private IssuerApiClientTokenService issuerApiClientTokenService; @Mock private WebClientConfig webClientConfig; @@ -55,53 +72,66 @@ void testGetCredentialOffer() { assertEquals(credentialOffer, result.block()); } -// @Test -// void testBuildCredentialOfferUri() throws JsonProcessingException { -// String token = "dummyToken"; -// String credentialType = "dummyType"; -// String nonce = "dummyNonce"; -// String getPreAuthCodeUri = "https://iam.example.com/PreAuthCodeUri"; -// String credentialOfferUri = "dummyCredentialOfferUri"; -// CustomCredentialOffer credentialOffer = CustomCredentialOffer.builder().build(); -// when(vcSchemaService.isSupportedVcSchema(credentialType)).thenReturn(Mono.just(true)); -// -// List> headers = new ArrayList<>(); -// headers.add(new AbstractMap.SimpleEntry<>(HttpHeaders.AUTHORIZATION, "Bearer " + token)); -// headers.add(new AbstractMap.SimpleEntry<>(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE)); -// -// GenericIamAdapter adapter = mock(GenericIamAdapter.class); -// when(iamAdapterFactory.getAdapter()).thenReturn(adapter); -// when(adapter.getPreAuthCodeUri()).thenReturn(getPreAuthCodeUri); -// -// // Ensure the JSON is valid and corresponds to a Grant object -// String jsonString = "{\"pre-authorized_code\":\"your_pre_authorized_code_here\"}"; -// ExchangeFunction exchangeFunction = mock(ExchangeFunction.class); -// -// // Create a mock ClientResponse for a successful response -// ClientResponse clientResponse = ClientResponse.create(HttpStatus.OK) -// .header("Content-Type", "application/json") -// .body(jsonString) -// .build(); -// -// // Stub the exchange function to return the mock ClientResponse -// when(exchangeFunction.exchange(any())).thenReturn(Mono.just(clientResponse)); -// -// WebClient webClient = WebClient.builder().exchangeFunction(exchangeFunction).build(); -// when(webClientConfig.centralizedWebClient()).thenReturn(webClient); -// -// // Mock objectMapper to return a non-null Grant -// Grant mockGrant = Grant.builder().build(); // Assume Grant is a simple class, adjust accordingly -// PreAuthCodeResponse preAuthCodeResponse = PreAuthCodeResponse.builder().grant(mockGrant).pin("1234").build(); -// when(objectMapper.readValue(jsonString, PreAuthCodeResponse.class)).thenReturn(preAuthCodeResponse); -// -// when(emailService.sendPin(any(), any(), any())).thenReturn(Mono.empty()); -// -// when(credentialOfferService.buildCustomCredentialOffer(credentialType, mockGrant)).thenReturn(Mono.just(credentialOffer)); -// when(credentialOfferCacheStorageService.saveCustomCredentialOffer(credentialOffer)).thenReturn(Mono.just(nonce)); -// when(credentialOfferService.createCredentialOfferUri(nonce)).thenReturn(Mono.just(credentialOfferUri)); -// -// Mono result = credentialOfferIssuanceService.buildCredentialOfferUri(token, credentialType); -// assertEquals(credentialOfferUri, result.block()); -// } + @Test + void testBuildCredentialOfferUri() throws JsonProcessingException { + String processId = "1234"; + String transactionCode = "4321"; + String procedureId = "uuid1234"; + String credentialType = "VerifiableCredential"; + String accessToken = "ey1234"; + String nonce = "nonce"; + String credentialOfferUri = "https://example.com/1234"; + String mail = "user@gmail.com"; + + PreAuthCodeResponse preAuthCodeResponse = PreAuthCodeResponse.builder() + .grant(Grant.builder() + .preAuthorizedCode("1234") + .txCode(Grant.TxCode.builder() + .length(4) + .build()) + .build() + ) + .build(); + CustomCredentialOffer credentialOffer = CustomCredentialOffer.builder() + .credentialConfigurationIds(List.of(credentialType)) + .credentialIssuer("https://issuer.com") + .grants(Map.of( "pre-authorized_code",preAuthCodeResponse.grant())) + .build(); + + when(deferredCredentialMetadataService.validateTransactionCode(transactionCode)).thenReturn(Mono.empty()); + when(deferredCredentialMetadataService.getProcedureIdByTransactionCode(transactionCode)).thenReturn(Mono.just(procedureId)); + when(credentialProcedureService.getCredentialTypeByProcedureId(procedureId)).thenReturn(Mono.just(credentialType)); + + when(authServerConfig.getPreAuthCodeUri()).thenReturn("https://example.com"); + when(issuerApiClientTokenService.getClientToken()).thenReturn(Mono.just(accessToken)); + + ExchangeFunction exchangeFunction = mock(ExchangeFunction.class); + + // Create a mock ClientResponse for a successful response + ClientResponse clientResponse = ClientResponse.create(HttpStatus.OK) + .header(CONTENT_TYPE, CONTENT_TYPE_APPLICATION_JSON) + .body("PreAuthorizedCode") + .build(); + + // Stub the exchange function to return the mock ClientResponse + when(exchangeFunction.exchange(any())).thenReturn(Mono.just(clientResponse)); + WebClient webClient = WebClient.builder().exchangeFunction(exchangeFunction).build(); + when(webClientConfig.commonWebClient()).thenReturn(webClient); + + when(objectMapper.readValue("PreAuthorizedCode", PreAuthCodeResponse.class)).thenReturn(preAuthCodeResponse); + when(deferredCredentialMetadataService.updateAuthServerNonceByTransactionCode(transactionCode,preAuthCodeResponse.grant().preAuthorizedCode())) + .thenReturn(Mono.empty()); + when(credentialOfferService.buildCustomCredentialOffer(credentialType,preAuthCodeResponse.grant())).thenReturn(Mono.just(credentialOffer)); + when(credentialOfferCacheStorageService.saveCustomCredentialOffer(credentialOffer)).thenReturn(Mono.just(nonce)); + + when(credentialOfferService.createCredentialOfferUri(nonce)).thenReturn(Mono.just(credentialOfferUri)); + when(credentialProcedureService.getMandateeEmailFromDecodedCredentialByProcedureId(procedureId)).thenReturn(Mono.just(mail)); + + when(emailService.sendPin(mail,"Pin Code", preAuthCodeResponse.pin())).thenReturn(Mono.empty()); + + StepVerifier.create(credentialOfferIssuanceService.buildCredentialOfferUri(processId,transactionCode)) + .expectNext(credentialOfferUri) + .verifyComplete(); + } } \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/application/workflow/impl/DeferredCredentialWorkflowImplTest.java b/src/test/java/es/in2/issuer/application/workflow/impl/DeferredCredentialWorkflowImplTest.java new file mode 100644 index 000000000..98ed2cdd0 --- /dev/null +++ b/src/test/java/es/in2/issuer/application/workflow/impl/DeferredCredentialWorkflowImplTest.java @@ -0,0 +1,148 @@ +package es.in2.issuer.application.workflow.impl; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import es.in2.issuer.domain.model.dto.PendingCredentials; +import es.in2.issuer.domain.model.dto.SignedCredentials; +import es.in2.issuer.domain.service.CredentialProcedureService; +import es.in2.issuer.domain.service.DeferredCredentialMetadataService; +import es.in2.issuer.domain.service.EmailService; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.util.List; + +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.when; + + +@ExtendWith(MockitoExtension.class) +class DeferredCredentialWorkflowImplTest { + @Mock + private CredentialProcedureService credentialProcedureService; + @Mock + private DeferredCredentialMetadataService deferredCredentialMetadataService; + @Mock + private ObjectMapper objectMapper; + @Mock + private EmailService emailService; + + @InjectMocks + private DeferredCredentialWorkflowImpl deferredCredentialWorkflow; + + @Test + void getPendingCredentialsByOrganizationId(){ + String organizationId = "4321"; + String expectedCredential = "Credential1"; + PendingCredentials expectedPendingCredentials = PendingCredentials.builder() + .credentials(List.of(PendingCredentials.CredentialPayload.builder() + .credential(expectedCredential) + .build())) + .build(); + + when(credentialProcedureService.getAllIssuedCredentialByOrganizationIdentifier(organizationId)).thenReturn(Flux.just(expectedCredential)); + + StepVerifier.create(deferredCredentialWorkflow.getPendingCredentialsByOrganizationId(organizationId)) + .expectNext(expectedPendingCredentials) + .verifyComplete(); + } + + @Test + void updateSignedCredentials() throws JsonProcessingException { + String credential = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; + String expectedEmail = "juan.perez@mail.com"; + String expectedFirstName = "Juan"; + String expectedId = "390ecd06-4e56-483a-b550-18d93a4bf9e3"; + String procedureId = "1234"; + List credentials = List.of(SignedCredentials.SignedCredential.builder() + .credential(credential) + .build() + ); + + SignedCredentials signedCredentials = SignedCredentials.builder() + .credentials(credentials) + .build(); + + String json = """ + { + "sub": "did:key:zDnaewZjPbFqyGvXVf5JuGCuSfTxXyFrKqoVrBFTQh17pqRbA", + "nbf": 1717579652, + "iss": "did:elsi:example", + "exp": 1720171652, + "iat": 1717579652, + "vc": { + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://dome-marketplace.eu/2022/credentials/learcredential/v1" + ], + "id": "390ecd06-4e56-483a-b550-18d93a4bf9e3", + "type": [ + "LEARCredentialEmployee", + "VerifiableCredential" + ], + "credentialSubject": { + "mandate": { + "id": "836d631b-755b-4755-b3a9-30d21c2b001c", + "life_span": { + "end_date_time": "2024-07-05T09:27:32.129565867Z", + "start_date_time": "2024-06-05T09:27:32.129565867Z" + }, + "mandatee": { + "id": "did:key:zDnaewZjPbFqyGvXVf5JuGCuSfTxXyFrKqoVrBFTQh17pqRbA", + "email": "juan.perez@mail.com", + "first_name": "Juan", + "last_name": "Perez", + "mobile_phone": "+34 662233445" + }, + "mandator": { + "commonName": "IN2", + "country": "ES", + "emailAddress": "rrhh@in2.es", + "organization": "IN2, Ingeniería de la Información, S.L.", + "organizationIdentifier": "VATES-B60645900", + "serialNumber": "B60645900" + }, + "power": [ + { + "id": "1483fd39-22ce-4e99-813e-331ed8bb5d79", + "tmf_action": "Execute", + "tmf_domain": "Dome", + "tmf_function": "Onboarding", + "tmf_type": "Domain" + } + ] + } + }, + "expirationDate": "2024-07-05T09:27:32.129565867Z", + "issuanceDate": "2024-06-05T09:27:32.129565867Z", + "issuer": "did:elsi:example", + "validFrom": "2024-06-05T09:27:32.129565867Z" + }, + "jti": "d5576eb1-2184-42f0-93af-b14cf92a4e02" + } + """; + ObjectMapper objectMapper2 = new ObjectMapper(); + JsonNode jsonNode = objectMapper2.readTree(json); + + when(objectMapper.readTree(anyString())).thenReturn(jsonNode); + + when(credentialProcedureService.updatedEncodedCredentialByCredentialId(signedCredentials.credentials().get(0).credential(),expectedId)) + .thenReturn(Mono.just(procedureId)); + + when(deferredCredentialMetadataService.updateVcByProcedureId(credential,procedureId)) + .thenReturn(Mono.empty()); + + when(emailService.sendCredentialSignedNotification(expectedEmail,"Credential Ready",expectedFirstName)) + .thenReturn(Mono.empty()); + + StepVerifier.create(deferredCredentialWorkflow.updateSignedCredentials(signedCredentials)) + .verifyComplete(); + } +} diff --git a/src/test/java/es/in2/issuer/application/workflow/impl/VerifiableCredentialIssuanceServiceImplTest.java b/src/test/java/es/in2/issuer/application/workflow/impl/VerifiableCredentialIssuanceServiceImplTest.java index 1f5fdc57b..df0a086c7 100644 --- a/src/test/java/es/in2/issuer/application/workflow/impl/VerifiableCredentialIssuanceServiceImplTest.java +++ b/src/test/java/es/in2/issuer/application/workflow/impl/VerifiableCredentialIssuanceServiceImplTest.java @@ -1,300 +1,235 @@ -//package es.in2.issuer.application.service.impl; -// -// -//import es.in2.issuer.domain.model.entities.CredentialProcedure; -//import es.in2.issuer.domain.exception.InvalidOrMissingProofException; -//import es.in2.issuer.domain.exception.UserDoesNotExistException; -//import es.in2.issuer.domain.model.*; -//import es.in2.issuer.domain.service.*; -//import es.in2.issuer.infrastructure.config.AppConfiguration; -//import org.junit.jupiter.api.BeforeEach; -//import org.junit.jupiter.api.Test; -//import org.junit.jupiter.api.extension.ExtendWith; -//import org.mockito.InjectMocks; -//import org.mockito.Mock; -//import org.mockito.junit.jupiter.MockitoExtension; -//import org.springframework.core.io.Resource; -//import org.springframework.test.util.ReflectionTestUtils; -//import reactor.core.publisher.Mono; -//import reactor.test.StepVerifier; -// -//import java.io.ByteArrayInputStream; -//import java.io.IOException; -//import java.nio.charset.StandardCharsets; -//import java.time.Instant; -//import java.util.List; -//import java.util.UUID; -// -//import static es.in2.issuer.domain.util.Constants.CWT_VC; -//import static es.in2.issuer.domain.util.Constants.JWT_VC; -//import static org.junit.jupiter.api.Assertions.assertEquals; -//import static org.mockito.ArgumentMatchers.eq; -//import static org.mockito.Mockito.*; -// -//@ExtendWith(MockitoExtension.class) -//class VerifiableCredentialIssuanceServiceImplTest { -// -// @Mock -// private RemoteSignatureService remoteSignatureService; -// @Mock -// private AuthenticSourcesRemoteService authenticSourcesRemoteService; -// @Mock -// private VerifiableCredentialService verifiableCredentialService; -// @Mock -// private AppConfiguration appConfiguration; -// @Mock -// private ProofValidationService proofValidationService; -// @Mock -// private CredentialManagementService credentialManagementService; -// @InjectMocks -// private VerifiableCredentialIssuanceServiceImpl service; -// -// String templateContent = """ -// { -// "type": [ -// "VerifiableCredential", -// "LEARCredential" -// ], -// "@context": [ -// "https://www.w3.org/2018/credentials/v1", -// "https://issueridp.dev.in2.es/2022/credentials/learcredential/v1" -// ], -// "id": "urn:uuid:84f6fe0b-7cc8-460e-bb54-f805f0984202", -// "issuer": { -// "id": "did:elsi:VATES-Q0801175A" -// }, -// "issuanceDate": "2024-03-08T18:27:46Z", -// "issued": "2024-03-08T18:27:46Z", -// "validFrom": "2024-03-08T18:27:46Z", -// "expirationDate": "2024-04-07T18:27:45Z", -// "credentialSubject": {} -// }"""; -// -// @BeforeEach -// public void setUp() throws IOException { -// Resource mockResource = mock(Resource.class); -// lenient().when(mockResource.getInputStream()).thenReturn(new ByteArrayInputStream(templateContent.getBytes(StandardCharsets.UTF_8))); -// -// ReflectionTestUtils.setField(service, "learCredentialTemplate", mockResource); -// } -// -// @Test -// void testGenerateVerifiableCredentialResponse() throws UserDoesNotExistException{ -// String did = "did:key:zDnaen23wM76gpiSLHku4bFDbssVS9sty9x3K7yVqjbSdTPWC"; -// String jwtProof = "eyJraWQiOiJkaWQ6a2V5OnpEbmFlbjIzd003NmdwaVNMSGt1NGJGRGJzc1ZTOXN0eTl4M0s3eVZxamJTZFRQV0MjekRuYWVuMjN3TTc2Z3BpU0xIa3U0YkZEYnNzVlM5c3R5OXgzSzd5VnFqYlNkVFBXQyIsInR5cCI6Im9wZW5pZDR2Y2ktcHJvb2Yrand0IiwiYWxnIjoiRVMyNTYifQ.eyJpc3MiOiJkaWQ6a2V5OnpEbmFlbjIzd003NmdwaVNMSGt1NGJGRGJzc1ZTOXN0eTl4M0s3eVZxamJTZFRQV0MiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjgwNzEiLCJleHAiOjE3MTI5MTcwNDAsImlhdCI6MTcxMjA1MzA0MCwibm9uY2UiOiI4OVh4bXdMMlJtR2wyUlp1LU1UU3lRPT0ifQ.DdaaNm4vTn60njLtAQ7Q5oGsQILfA-5h9-sv4MBcVyNBAfSrUUajZqlUukT-5Bx8EqocSvf0RIFRHLcvO9_LMg"; -// String userId = "user123"; -// String token = "dummyToken"; -// String unsignedCredential = "unsignedCredential"; -// String transactionId = "1234"; -// CredentialRequest credentialRequest = CredentialRequest.builder() -// .proof( -// Proof.builder().proofType("jwt").jwt(jwtProof).build()) -// .format(JWT_VC) -// .build(); -// VerifiableCredentialResponse expectedResponse = VerifiableCredentialResponse.builder() -// .credential(unsignedCredential) -// .transactionId(transactionId) -// .cNonce("89XxmwL2RmGl2RZu-MTSyQ==") -// .cNonceExpiresIn(600) -// .build(); -// -// when(proofValidationService.isProofValid(jwtProof, token)).thenReturn(Mono.just(true)); -// when(authenticSourcesRemoteService.getUserFromLocalFile()).thenReturn(Mono.just("userData")); -// when(appConfiguration.getIssuerDid()).thenReturn("did:example:issuer"); -// when(verifiableCredentialService.retrieveVcAndBindMandateeId( -// eq(templateContent),eq(did),eq("did:example:issuer"),eq("userData"),any(Instant.class)) -// ) -// .thenReturn(Mono.just(unsignedCredential)); -// when(credentialManagementService.commitCredential(unsignedCredential, userId,credentialRequest.format())).thenReturn(Mono.just(transactionId)); -// -// StepVerifier.create(service.generateVerifiableCredentialResponse(userId, credentialRequest, token)) -// .assertNext(response -> assertEquals(expectedResponse, response)) -// .verifyComplete(); -// -// } -// -// @Test -// void generateVerifiableCredentialResponse_InvalidProof() { -// String userId = "user123"; -// String token = "dummyToken"; -// CredentialRequest credentialRequest = CredentialRequest.builder() -// .proof( -// Proof.builder().proofType("jwt").jwt("invalidProof").build()) -// .format(JWT_VC) -// .build(); -// -// // Mock the proof validation to return false indicating the proof is invalid -// when(proofValidationService.isProofValid(credentialRequest.proof().jwt(), token)).thenReturn(Mono.just(false)); -// -// // Execute the method under test -// Mono response = service.generateVerifiableCredentialResponse(userId, credentialRequest, token); -// -// // Verify that an error is emitted and it is of type InvalidOrMissingProofException -// StepVerifier.create(response) -// .expectErrorMatches(throwable -> throwable instanceof InvalidOrMissingProofException && throwable.getMessage().contains("Invalid proof")) -// .verify(); -// -// // Verify interactions -// verify(proofValidationService).isProofValid(credentialRequest.proof().jwt(), token); -// // Ensure no other processes are initiated due to invalid proof -// verifyNoMoreInteractions(authenticSourcesRemoteService, verifiableCredentialService, credentialManagementService); -// } -// -// -// @Test -// void generateBatchVerifiableCredentialResponse_Success() throws UserDoesNotExistException { -// String did = "did:key:zDnaen23wM76gpiSLHku4bFDbssVS9sty9x3K7yVqjbSdTPWC"; -// String jwtProof = "eyJraWQiOiJkaWQ6a2V5OnpEbmFlbjIzd003NmdwaVNMSGt1NGJGRGJzc1ZTOXN0eTl4M0s3eVZxamJTZFRQV0MjekRuYWVuMjN3TTc2Z3BpU0xIa3U0YkZEYnNzVlM5c3R5OXgzSzd5VnFqYlNkVFBXQyIsInR5cCI6Im9wZW5pZDR2Y2ktcHJvb2Yrand0IiwiYWxnIjoiRVMyNTYifQ.eyJpc3MiOiJkaWQ6a2V5OnpEbmFlbjIzd003NmdwaVNMSGt1NGJGRGJzc1ZTOXN0eTl4M0s3eVZxamJTZFRQV0MiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjgwNzEiLCJleHAiOjE3MTI5MTcwNDAsImlhdCI6MTcxMjA1MzA0MCwibm9uY2UiOiI4OVh4bXdMMlJtR2wyUlp1LU1UU3lRPT0ifQ.DdaaNm4vTn60njLtAQ7Q5oGsQILfA-5h9-sv4MBcVyNBAfSrUUajZqlUukT-5Bx8EqocSvf0RIFRHLcvO9_LMg"; -// String unsignedCredential = "unsignedCredential"; -// -// // Define your test input here -// String username = "testUser"; -// String transactionId = "1234"; -// CredentialRequest request = new CredentialRequest(JWT_VC, new CredentialDefinition(List.of("")),new Proof("type",jwtProof)); -// BatchCredentialRequest batchCredentialRequest = new BatchCredentialRequest(List.of(request)); -// String token = "testToken"; -// VerifiableCredentialResponse expectedResponse = VerifiableCredentialResponse.builder() -// .credential(unsignedCredential) -// .transactionId(transactionId) -// .cNonce("89XxmwL2RmGl2RZu-MTSyQ==") -// .cNonceExpiresIn(600) -// .build(); -// BatchCredentialResponse expectedResponses = BatchCredentialResponse.builder() -// .credentialResponses(List.of( -// BatchCredentialResponse.CredentialResponse -// .builder() -// .credential(expectedResponse.credential()) -// .build())) -// .build(); -// -// when(proofValidationService.isProofValid(jwtProof, token)).thenReturn(Mono.just(true)); -// when(authenticSourcesRemoteService.getUserFromLocalFile()).thenReturn(Mono.just("userData")); -// when(appConfiguration.getIssuerDid()).thenReturn("did:example:issuer"); -// when(verifiableCredentialService.retrieveVcAndBindMandateeId( -// eq(templateContent),eq(did),eq("did:example:issuer"),eq("userData"),any(Instant.class)) -// ) -// .thenReturn(Mono.just(unsignedCredential)); -// when(credentialManagementService.commitCredential(unsignedCredential, username,batchCredentialRequest.credentialRequests().get(0).format())).thenReturn(Mono.just(transactionId)); -// -// // Test the method -// Mono result = service.generateVerifiableCredentialBatchResponse(username, batchCredentialRequest, token); -// -// // Verify the output -// StepVerifier.create(result) -// .assertNext(response -> assertEquals(expectedResponses, response)) -// .verifyComplete(); -// -// } -// -// @Test -// void generateVerifiableCredentialDeferredResponse_NotSigned() { -// String userId = "user123"; -// String token = "dummyToken"; -// String transactionId = "1234"; -// CredentialProcedure deferredCredential = CredentialProcedure.builder().credentialSigned(null).transactionId(transactionId).build(); -// -// when(credentialManagementService.getDeferredCredentialByTransactionId(transactionId)) -// .thenReturn(Mono.just(deferredCredential)); -// when(credentialManagementService.updateTransactionId(transactionId)) -// .thenReturn(Mono.just("4321")); -// -// VerifiableCredentialResponse expectedResponse = VerifiableCredentialResponse.builder() -// .transactionId("4321") -// .build(); -// -// StepVerifier.create(service.generateVerifiableCredentialDeferredResponse(userId, new DeferredCredentialRequest(transactionId), token)) -// .assertNext(response -> assertEquals(expectedResponse, response)) -// .verifyComplete(); -// } -// -// @Test -// void generateVerifiableCredentialDeferredResponse_Signed() { -// String userId = "user123"; -// String token = "dummyToken"; -// String transactionId = "1234"; -// String credential = "signed credential"; -// CredentialProcedure deferredCredential = CredentialProcedure.builder().credentialSigned(credential).transactionId(transactionId).build(); -// -// -// when(credentialManagementService.getDeferredCredentialByTransactionId(transactionId)) -// .thenReturn(Mono.just(deferredCredential)); -// when(credentialManagementService.deleteCredentialDeferred(transactionId)) -// .thenReturn(Mono.empty()); -// -// VerifiableCredentialResponse expectedResponse = VerifiableCredentialResponse.builder() -// .credential(credential) -// .build(); -// -// StepVerifier.create(service.generateVerifiableCredentialDeferredResponse(userId, new DeferredCredentialRequest(transactionId), token)) -// .assertNext(response -> assertEquals(expectedResponse, response)) -// .verifyComplete(); -// } -// -// @Test -// void signDeferredCredential_Success() { -// String unsignedCredential = "unsignedCredential"; -// String userId = "user123"; -// UUID credentialId = UUID.randomUUID(); -// String token = "dummyToken"; -// String signedCredential = "signedCredentialData"; -// -// when(verifiableCredentialService.generateDeferredCredentialResponse(unsignedCredential)) -// .thenReturn(Mono.just("vcPayload")); -// when(remoteSignatureService.sign(any(SignatureRequest.class), eq(token))) -// .thenReturn(Mono.just(new SignedData(SignatureType.JADES,signedCredential))); -// when(credentialManagementService.updateCredential(signedCredential, credentialId, userId)) -// .thenReturn(Mono.empty()); -// -// StepVerifier.create(service.signDeferredCredential(unsignedCredential, userId, credentialId, token)) -// .verifyComplete(); -// } -// -// @Test -// void signCredentialOnRequestedFormat_JWT_Success() { -// String unsignedCredential = "unsignedCredential"; -// String userId = "user123"; -// UUID credentialId = UUID.randomUUID(); -// String token = "dummyToken"; -// String signedCredential = "signedJWTData"; -// -// when(remoteSignatureService.sign(any(SignatureRequest.class), eq(token))) -// .thenReturn(Mono.just(new SignedData(SignatureType.JADES,signedCredential))); -// -// StepVerifier.create(service.signCredentialOnRequestedFormat(unsignedCredential, JWT_VC, userId, credentialId, token)) -// .assertNext(signedData -> assertEquals(signedCredential, signedData)) -// .verifyComplete(); -// } -// -// @Test -// void signCredentialOnRequestedFormat_CWT_Success() { -// String unsignedCredential = "{\"data\":\"data\"}"; -// String userId = "user123"; -// UUID credentialId = UUID.randomUUID(); -// String token = "dummyToken"; -// String signedCredential = "eyJkYXRhIjoiZGF0YSJ9"; -// String signedResult = "6BFWTLRH9.Q5$VAFLGV*M7:43S0"; -// -// when(remoteSignatureService.sign(any(SignatureRequest.class), eq(token))) -// .thenReturn(Mono.just(new SignedData(SignatureType.COSE, signedCredential))); -// -// -// StepVerifier.create(service.signCredentialOnRequestedFormat(unsignedCredential, CWT_VC, userId, credentialId, token)) -// .assertNext(signedData -> assertEquals(signedResult, signedData)) -// .verifyComplete(); -// } -// -// @Test -// void signCredentialOnRequestedFormat_UnsupportedFormat() { -// String unsignedCredential = "unsignedCredential"; -// String userId = "user123"; -// UUID credentialId = UUID.randomUUID(); -// String token = "dummyToken"; -// String unsupportedFormat = "unsupportedFormat"; -// -// StepVerifier.create(service.signCredentialOnRequestedFormat(unsignedCredential, unsupportedFormat, userId, credentialId, token)) -// .expectError(IllegalArgumentException.class) -// .verify(); -// } -// -// -//} \ No newline at end of file +package es.in2.issuer.application.workflow.impl; + + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import es.in2.issuer.domain.exception.InvalidOrMissingProofException; +import es.in2.issuer.domain.model.dto.*; +import es.in2.issuer.domain.model.enums.SignatureType; +import es.in2.issuer.domain.service.*; +import es.in2.issuer.infrastructure.config.AppConfig; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.util.UUID; + +import static es.in2.issuer.domain.util.Constants.CWT_VC; +import static es.in2.issuer.domain.util.Constants.JWT_VC; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class VerifiableCredentialIssuanceServiceImplTest { + @Mock + private RemoteSignatureService remoteSignatureService; + + @Mock + private VerifiableCredentialService verifiableCredentialService; + + @Mock + private AppConfig appConfig; + + @Mock + private ProofValidationService proofValidationService; + + @Mock + private EmailService emailService; + + @Mock + private CredentialProcedureService credentialProcedureService; + + @Mock + private DeferredCredentialMetadataService deferredCredentialMetadataService; + + @InjectMocks + private VerifiableCredentialIssuanceWorkflowImpl verifiableCredentialIssuanceWorkflow; + + @Test + void completeWithdrawLearCredentialProcessSuccess() throws JsonProcessingException { + String processId = "1234"; + String type = "LEARCredentialEmployee"; + String json = """ + { + "life_span": { + "end_date_time": "2025-04-02 09:23:22.637345122 +0000 UTC", + "start_date_time": "2024-04-02 09:23:22.637345122 +0000 UTC" + }, + "mandatee": { + "email": "example@in2.es", + "first_name": "Jhon", + "last_name": "Doe", + "mobile_phone": "+34666336699" + }, + "mandator": { + "commonName": "IN2", + "country": "ES", + "emailAddress": "rrhh@in2.es", + "organization": "IN2, Ingeniería de la Información, S.L.", + "organizationIdentifier": "VATES-B60645900", + "serialNumber": "B60645900" + }, + "power": [ + { + "id": "6b8f3137-a57a-46a5-97e7-1117a20142fv", + "tmf_domain": "DOME", + "tmf_function": "DomePlatform", + "tmf_type": "Domain", + "tmf_action": [ + "Operator", + "Customer", + "Provider" + ] + }, + { + "id": "6b8f3137-a57a-46a5-97e7-1117a20142fb", + "tmf_action": "Execute", + "tmf_domain": "DOME", + "tmf_function": "Onboarding", + "tmf_type": "Domain" + }, + { + "id": "ad9b1509-60ea-47d4-9878-18b581d8e19b", + "tmf_action": [ + "Create", + "Update" + ], + "tmf_domain": "DOME", + "tmf_function": "ProductOffering", + "tmf_type": "Domain" + } + ] + } + """; + ObjectMapper objectMapper = new ObjectMapper(); + JsonNode jsonNode = objectMapper.readTree(json); + LEARCredentialRequest learCredentialRequest = LEARCredentialRequest.builder().credential(jsonNode).build(); + String transactionCode = "4321"; + String issuerUIExternalDomain = "https://issuer-ui.com"; + + when(verifiableCredentialService.generateVc(processId,type,learCredentialRequest)).thenReturn(Mono.just(transactionCode)); + when(appConfig.getIssuerUiExternalDomain()).thenReturn(issuerUIExternalDomain); + when(emailService.sendTransactionCodeForCredentialOffer("example@in2.es","Credential Offer",issuerUIExternalDomain + "/credential-offer?transaction_code=" + transactionCode, "Jhon")).thenReturn(Mono.empty()); + + StepVerifier.create(verifiableCredentialIssuanceWorkflow.completeWithdrawLearCredentialProcess(processId,type,learCredentialRequest)) + .verifyComplete(); + } + + @Test + void generateVerifiableCredentialResponseSuccess(){ + String processId = "1234"; + CredentialRequest credentialRequest = CredentialRequest.builder() + .format(JWT_VC) + .proof(Proof.builder() + .proofType("jwt") + .jwt("eyJraWQiOiJkaWQ6a2V5OnpEbmFlbjIzd003NmdwaVNMSGt1NGJGRGJzc1ZTOXN0eTl4M0s3eVZxamJTZFRQV0MjekRuYWVuMjN3TTc2Z3BpU0xIa3U0YkZEYnNzVlM5c3R5OXgzSzd5VnFqYlNkVFBXQyIsInR5cCI6Im9wZW5pZDR2Y2ktcHJvb2Yrand0IiwiYWxnIjoiRVMyNTYifQ.eyJpc3MiOiJkaWQ6a2V5OnpEbmFlbjIzd003NmdwaVNMSGt1NGJGRGJzc1ZTOXN0eTl4M0s3eVZxamJTZFRQV0MiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjgwNzEiLCJleHAiOjE3MTI5MTcwNDAsImlhdCI6MTcxMjA1MzA0MCwibm9uY2UiOiI4OVh4bXdMMlJtR2wyUlp1LU1UU3lRPT0ifQ.DdaaNm4vTn60njLtAQ7Q5oGsQILfA-5h9-sv4MBcVyNBAfSrUUajZqlUukT-5Bx8EqocSvf0RIFRHLcvO9_LMg") + .build()) + .build(); + String token = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIyQ1ltNzdGdGdRNS1uU2stU3p4T2VYYUVOUTRoSGRkNkR5U2NYZzJFaXJjIn0.eyJleHAiOjE3MTAyNDM2MzIsImlhdCI6MTcxMDI0MzMzMiwiYXV0aF90aW1lIjoxNzEwMjQwMTczLCJqdGkiOiJmY2NhNzU5MS02NzQyLTRjMzAtOTQ5Yy1lZTk3MDcxOTY3NTYiLCJpc3MiOiJodHRwczovL2tleWNsb2FrLXByb3ZpZGVyLmRvbWUuZml3YXJlLmRldi9yZWFsbXMvZG9tZSIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJlMmEwNjZmNS00YzAwLTQ5NTYtYjQ0NC03ZWE1ZTE1NmUwNWQiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJhY2NvdW50LWNvbnNvbGUiLCJzZXNzaW9uX3N0YXRlIjoiYzFhMTUyYjYtNWJhNy00Y2M4LWFjOTktN2Q2ZTllODIyMjk2IiwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyJdfX0sInNjb3BlIjoib3BlbmlkIGVtYWlsIHByb2ZpbGUiLCJzaWQiOiJjMWExNTJiNi01YmE3LTRjYzgtYWM5OS03ZDZlOWU4MjIyOTYiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsIm5hbWUiOiJQcm92aWRlciBMZWFyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoicHJvdmlkZXItbGVhciIsImdpdmVuX25hbWUiOiJQcm92aWRlciIsImZhbWlseV9uYW1lIjoiTGVhciJ9.F8vTSNAMc5Fmi-KO0POuaMIxcjdpWxNqfXH3NVdQP18RPKGI5eJr5AGN-yKYncEEzkM5_H28abJc1k_lx7RjnERemqesY5RwoBpTl9_CzdSFnIFbroNOAY4BGgiU-9Md9JsLrENk5Na_uNV_Q85_72tmRpfESqy5dMVoFzWZHj2LwV5dji2n17yf0BjtaWailHdwbnDoSqQab4IgYsExhUkCLCtZ3O418BG9nrSvP-BLQh_EvU3ry4NtnnWxwi5rNk4wzT4j8rxLEAJpMMv-5Ew0z7rbFX3X3UW9WV9YN9eV79-YrmxOksPYahFQwNUXPckCXnM48ZHZ42B0H4iOiA"; + String jti = "fcca7591-6742-4c30-949c-ee9707196756"; + String did = "did:key:zDnaen23wM76gpiSLHku4bFDbssVS9sty9x3K7yVqjbSdTPWC"; + VerifiableCredentialResponse verifiableCredentialResponse = VerifiableCredentialResponse.builder() + .credential("credential") + .transactionId("4321") + .build(); + String procedureId = "123456"; + String mandatorEmail = "jhon@gmail.com"; + + when(proofValidationService.isProofValid(credentialRequest.proof().jwt(), token)).thenReturn(Mono.just(true)); + when(verifiableCredentialService.buildCredentialResponse(processId,did,jti,credentialRequest.format())).thenReturn(Mono.just(verifiableCredentialResponse)); + when(deferredCredentialMetadataService.getProcedureIdByAuthServerNonce(jti)).thenReturn(Mono.just(procedureId)); + when(credentialProcedureService.getMandatorEmailFromDecodedCredentialByProcedureId(procedureId)).thenReturn(Mono.just(mandatorEmail)); + when(emailService.sendPendingCredentialNotification(mandatorEmail,"Pending Credential")).thenReturn(Mono.empty()); + + StepVerifier.create(verifiableCredentialIssuanceWorkflow.generateVerifiableCredentialResponse(processId,credentialRequest, token)) + .expectNext(verifiableCredentialResponse) + .verifyComplete(); + } + + @Test + void generateVerifiableCredentialResponseFailedProofException(){ + String processId = "1234"; + CredentialRequest credentialRequest = CredentialRequest.builder() + .format(JWT_VC) + .proof(Proof.builder() + .proofType("jwt") + .jwt("eyJraWQiOiJkaWQ6a2V5OnpEbmFlbjIzd003NmdwaVNMSGt1NGJGRGJzc1ZTOXN0eTl4M0s3eVZxamJTZFRQV0MjekRuYWVuMjN3TTc2Z3BpU0xIa3U0YkZEYnNzVlM5c3R5OXgzSzd5VnFqYlNkVFBXQyIsInR5cCI6Im9wZW5pZDR2Y2ktcHJvb2Yrand0IiwiYWxnIjoiRVMyNTYifQ.eyJpc3MiOiJkaWQ6a2V5OnpEbmFlbjIzd003NmdwaVNMSGt1NGJGRGJzc1ZTOXN0eTl4M0s3eVZxamJTZFRQV0MiLCJhdWQiOiJodHRwOi8vbG9jYWxob3N0OjgwNzEiLCJleHAiOjE3MTI5MTcwNDAsImlhdCI6MTcxMjA1MzA0MCwibm9uY2UiOiI4OVh4bXdMMlJtR2wyUlp1LU1UU3lRPT0ifQ.DdaaNm4vTn60njLtAQ7Q5oGsQILfA-5h9-sv4MBcVyNBAfSrUUajZqlUukT-5Bx8EqocSvf0RIFRHLcvO9_LMg") + .build()) + .build(); + String token = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIyQ1ltNzdGdGdRNS1uU2stU3p4T2VYYUVOUTRoSGRkNkR5U2NYZzJFaXJjIn0.eyJleHAiOjE3MTAyNDM2MzIsImlhdCI6MTcxMDI0MzMzMiwiYXV0aF90aW1lIjoxNzEwMjQwMTczLCJqdGkiOiJmY2NhNzU5MS02NzQyLTRjMzAtOTQ5Yy1lZTk3MDcxOTY3NTYiLCJpc3MiOiJodHRwczovL2tleWNsb2FrLXByb3ZpZGVyLmRvbWUuZml3YXJlLmRldi9yZWFsbXMvZG9tZSIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiJlMmEwNjZmNS00YzAwLTQ5NTYtYjQ0NC03ZWE1ZTE1NmUwNWQiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJhY2NvdW50LWNvbnNvbGUiLCJzZXNzaW9uX3N0YXRlIjoiYzFhMTUyYjYtNWJhNy00Y2M4LWFjOTktN2Q2ZTllODIyMjk2IiwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyJdfX0sInNjb3BlIjoib3BlbmlkIGVtYWlsIHByb2ZpbGUiLCJzaWQiOiJjMWExNTJiNi01YmE3LTRjYzgtYWM5OS03ZDZlOWU4MjIyOTYiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsIm5hbWUiOiJQcm92aWRlciBMZWFyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoicHJvdmlkZXItbGVhciIsImdpdmVuX25hbWUiOiJQcm92aWRlciIsImZhbWlseV9uYW1lIjoiTGVhciJ9.F8vTSNAMc5Fmi-KO0POuaMIxcjdpWxNqfXH3NVdQP18RPKGI5eJr5AGN-yKYncEEzkM5_H28abJc1k_lx7RjnERemqesY5RwoBpTl9_CzdSFnIFbroNOAY4BGgiU-9Md9JsLrENk5Na_uNV_Q85_72tmRpfESqy5dMVoFzWZHj2LwV5dji2n17yf0BjtaWailHdwbnDoSqQab4IgYsExhUkCLCtZ3O418BG9nrSvP-BLQh_EvU3ry4NtnnWxwi5rNk4wzT4j8rxLEAJpMMv-5Ew0z7rbFX3X3UW9WV9YN9eV79-YrmxOksPYahFQwNUXPckCXnM48ZHZ42B0H4iOiA"; + + when(proofValidationService.isProofValid(credentialRequest.proof().jwt(), token)).thenReturn(Mono.just(false)); + + StepVerifier.create(verifiableCredentialIssuanceWorkflow.generateVerifiableCredentialResponse(processId,credentialRequest, token)) + .expectError(InvalidOrMissingProofException.class) + .verify(); + } + + @Test + void bindAccessTokenByPreAuthorizedCodeSuccess(){ + String processId = "1234"; + AuthServerNonceRequest authServerNonceRequest = AuthServerNonceRequest.builder() + .accessToken("ey1234") + .preAuthorizedCode("4321") + .build(); + + when(verifiableCredentialService.bindAccessTokenByPreAuthorizedCode(processId,authServerNonceRequest.accessToken(),authServerNonceRequest.preAuthorizedCode())) + .thenReturn(Mono.empty()); + StepVerifier.create(verifiableCredentialIssuanceWorkflow.bindAccessTokenByPreAuthorizedCode(processId,authServerNonceRequest)) + .verifyComplete(); + } + + @Test + void signCredentialOnRequestedFormat_JWT_Success() { + String unsignedCredential = "unsignedCredential"; + String userId = "user123"; + UUID credentialId = UUID.randomUUID(); + String token = "dummyToken"; + String signedCredential = "signedJWTData"; + + when(remoteSignatureService.sign(any(SignatureRequest.class), eq(token))) + .thenReturn(Mono.just(new SignedData(SignatureType.JADES,signedCredential))); + + StepVerifier.create(verifiableCredentialIssuanceWorkflow.signCredentialOnRequestedFormat(unsignedCredential, JWT_VC, userId, credentialId, token)) + .assertNext(signedData -> assertEquals(signedCredential, signedData)) + .verifyComplete(); + } + @Test + void signCredentialOnRequestedFormat_CWT_Success() { + String unsignedCredential = "{\"data\":\"data\"}"; + String userId = "user123"; + UUID credentialId = UUID.randomUUID(); + String token = "dummyToken"; + String signedCredential = "eyJkYXRhIjoiZGF0YSJ9"; + String signedResult = "6BFWTLRH9.Q5$VAFLGV*M7:43S0"; + + when(remoteSignatureService.sign(any(SignatureRequest.class), eq(token))) + .thenReturn(Mono.just(new SignedData(SignatureType.COSE, signedCredential))); + + + StepVerifier.create(verifiableCredentialIssuanceWorkflow.signCredentialOnRequestedFormat(unsignedCredential, CWT_VC, userId, credentialId, token)) + .assertNext(signedData -> assertEquals(signedResult, signedData)) + .verifyComplete(); + } + + @Test + void signCredentialOnRequestedFormat_UnsupportedFormat() { + String unsignedCredential = "unsignedCredential"; + String userId = "user123"; + UUID credentialId = UUID.randomUUID(); + String token = "dummyToken"; + String unsupportedFormat = "unsupportedFormat"; + + StepVerifier.create(verifiableCredentialIssuanceWorkflow.signCredentialOnRequestedFormat(unsignedCredential, unsupportedFormat, userId, credentialId, token)) + .expectError(IllegalArgumentException.class) + .verify(); + } + +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/dto/AuthServerNonceRequestTest.java b/src/test/java/es/in2/issuer/domain/model/dto/AuthServerNonceRequestTest.java new file mode 100644 index 000000000..c4f7bdbe2 --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/model/dto/AuthServerNonceRequestTest.java @@ -0,0 +1,42 @@ +package es.in2.issuer.domain.model.dto; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class AuthServerNonceRequestTest { + + @Test + void testConstructorAndGetters() { + // Arrange + String expectedPreAuthorizedCode = "123456"; + String expectedAccessToken = "token123"; + + // Act + AuthServerNonceRequest request = new AuthServerNonceRequest( + expectedPreAuthorizedCode, + expectedAccessToken + ); + + // Assert + assertEquals(expectedPreAuthorizedCode, request.preAuthorizedCode()); + assertEquals(expectedAccessToken, request.accessToken()); + } + + @Test + void testSetters() { + // Arrange + String newPreAuthorizedCode = "654321"; + String newAccessToken = "token654"; + + // Act + AuthServerNonceRequest request = AuthServerNonceRequest.builder() + .preAuthorizedCode(newPreAuthorizedCode) + .accessToken(newAccessToken) + .build(); + + // Assert + assertEquals(newPreAuthorizedCode, request.preAuthorizedCode()); + assertEquals(newAccessToken, request.accessToken()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/dto/AuthorizationServerMetadataTest.java b/src/test/java/es/in2/issuer/domain/model/dto/AuthorizationServerMetadataTest.java new file mode 100644 index 000000000..59322f4ed --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/model/dto/AuthorizationServerMetadataTest.java @@ -0,0 +1,34 @@ +package es.in2.issuer.domain.model.dto; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class AuthorizationServerMetadataTest { + + @Test + void testConstructorAndGetters() { + // Arrange + String expectedTokenEndpoint = "https://example.com/token"; + + // Act + AuthorizationServerMetadata metadata = new AuthorizationServerMetadata(expectedTokenEndpoint); + + // Assert + assertEquals(expectedTokenEndpoint, metadata.tokenEndpoint()); + } + + @Test + void testSetters() { + // Arrange + String newTokenEndpoint = "https://newexample.com/token"; + + // Act + AuthorizationServerMetadata metadata = AuthorizationServerMetadata.builder() + .tokenEndpoint(newTokenEndpoint) + .build(); + + // Assert + assertEquals(newTokenEndpoint, metadata.tokenEndpoint()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/dto/BatchCredentialRequestTest.java b/src/test/java/es/in2/issuer/domain/model/dto/BatchCredentialRequestTest.java new file mode 100644 index 000000000..a1f55ec98 --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/model/dto/BatchCredentialRequestTest.java @@ -0,0 +1,48 @@ +package es.in2.issuer.domain.model.dto; + +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class BatchCredentialRequestTest { + + @Test + void testConstructorAndGetters() { + // Arrange + String expectedFormat = "sampleFormat"; + Proof expectedProof = new Proof("jwt_vc_json", "sampleJwt"); + CredentialDefinition expectedCredentialDefinition = new CredentialDefinition(List.of("type")); + List expectedCredentialRequests = List.of( + new CredentialRequest(expectedFormat, expectedCredentialDefinition, expectedProof), + new CredentialRequest(expectedFormat, expectedCredentialDefinition, expectedProof) + ); + + // Act + BatchCredentialRequest batchRequest = new BatchCredentialRequest(expectedCredentialRequests); + + // Assert + assertEquals(expectedCredentialRequests, batchRequest.credentialRequests()); + } + + @Test + void testSetters() { + // Arrange + String expectedFormat = "sampleFormat"; + Proof expectedProof = new Proof("jwt_vc_json", "sampleJwt"); + CredentialDefinition expectedCredentialDefinition = new CredentialDefinition(List.of("type")); + List newCredentialRequests = List.of( + new CredentialRequest(expectedFormat, expectedCredentialDefinition, expectedProof), + new CredentialRequest(expectedFormat, expectedCredentialDefinition, expectedProof) + ); + + // Act + BatchCredentialRequest batchRequest = BatchCredentialRequest.builder() + .credentialRequests(newCredentialRequests) + .build(); + + // Assert + assertEquals(newCredentialRequests, batchRequest.credentialRequests()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/dto/BatchCredentialResponseTest.java b/src/test/java/es/in2/issuer/domain/model/dto/BatchCredentialResponseTest.java new file mode 100644 index 000000000..94f3deb5b --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/model/dto/BatchCredentialResponseTest.java @@ -0,0 +1,52 @@ +package es.in2.issuer.domain.model.dto; + +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class BatchCredentialResponseTest { + + @Test + void testConstructorAndGetters() { + // Arrange + BatchCredentialResponse.CredentialResponse expectedCredentialResponse = new BatchCredentialResponse.CredentialResponse("sampleCredential"); + List expectedCredentialResponses = List.of(expectedCredentialResponse); + + // Act + BatchCredentialResponse batchCredentialResponse = new BatchCredentialResponse(expectedCredentialResponses); + + // Assert + assertEquals(expectedCredentialResponses, batchCredentialResponse.credentialResponses()); + } + + @Test + void testSetters() { + // Arrange + BatchCredentialResponse.CredentialResponse newCredentialResponse = new BatchCredentialResponse.CredentialResponse("newSampleCredential"); + List newCredentialResponses = List.of(newCredentialResponse); + + // Act + BatchCredentialResponse batchCredentialResponse = BatchCredentialResponse.builder() + .credentialResponses(newCredentialResponses) + .build(); + + // Assert + assertEquals(newCredentialResponses, batchCredentialResponse.credentialResponses()); + } + + @Test + void lombokGeneratedMethodsTest() { + // Arrange + BatchCredentialResponse.CredentialResponse expectedCredentialResponse = new BatchCredentialResponse.CredentialResponse("sampleCredential"); + List expectedCredentialResponses = List.of(expectedCredentialResponse); + + BatchCredentialResponse response1 = new BatchCredentialResponse(expectedCredentialResponses); + BatchCredentialResponse response2 = new BatchCredentialResponse(expectedCredentialResponses); + + // Assert + assertEquals(response1, response2); + assertEquals(response1.hashCode(), response2.hashCode()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/CommitCredentialTest.java b/src/test/java/es/in2/issuer/domain/model/dto/CommitCredentialTest.java similarity index 93% rename from src/test/java/es/in2/issuer/domain/model/CommitCredentialTest.java rename to src/test/java/es/in2/issuer/domain/model/dto/CommitCredentialTest.java index a616da8e0..80b18d6e9 100644 --- a/src/test/java/es/in2/issuer/domain/model/CommitCredentialTest.java +++ b/src/test/java/es/in2/issuer/domain/model/dto/CommitCredentialTest.java @@ -1,6 +1,5 @@ -package es.in2.issuer.domain.model; +package es.in2.issuer.domain.model.dto; -import es.in2.issuer.domain.model.dto.CommitCredential; import org.junit.jupiter.api.Test; import java.util.Date; @@ -38,4 +37,4 @@ void lombokGeneratedMethodsTest() { assertEquals(dto1.hashCode(), dto2.hashCode()); // Tests hashCode() method generated by Lombok } -} +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/dto/CredentialConfigurationTest.java b/src/test/java/es/in2/issuer/domain/model/dto/CredentialConfigurationTest.java new file mode 100644 index 000000000..0b05f38e6 --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/model/dto/CredentialConfigurationTest.java @@ -0,0 +1,82 @@ +package es.in2.issuer.domain.model.dto; + +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class CredentialConfigurationTest { + + @Test + void testConstructorAndGetters() { + // Arrange + String expectedFormat = "format"; + List expectedCryptographicBindingMethodsSupported = List.of("method1", "method2"); + List expectedCredentialSigningAlgValuesSupported = List.of("alg1", "alg2"); + CredentialDefinition expectedCredentialDefinition = new CredentialDefinition(List.of("type")); + + // Act + CredentialConfiguration credentialConfiguration = new CredentialConfiguration( + expectedFormat, + expectedCryptographicBindingMethodsSupported, + expectedCredentialSigningAlgValuesSupported, + expectedCredentialDefinition + ); + + // Assert + assertEquals(expectedFormat, credentialConfiguration.format()); + assertEquals(expectedCryptographicBindingMethodsSupported, credentialConfiguration.cryptographicBindingMethodsSupported()); + assertEquals(expectedCredentialSigningAlgValuesSupported, credentialConfiguration.credentialSigningAlgValuesSupported()); + assertEquals(expectedCredentialDefinition, credentialConfiguration.credentialDefinition()); + } + + @Test + void testSetters() { + // Arrange + String newFormat = "newFormat"; + List newCryptographicBindingMethodsSupported = List.of("newMethod1", "newMethod2"); + List newCredentialSigningAlgValuesSupported = List.of("newAlg1", "newAlg2"); + CredentialDefinition newCredentialDefinition = new CredentialDefinition(List.of("type")); + + // Act + CredentialConfiguration credentialConfiguration = CredentialConfiguration.builder() + .format(newFormat) + .cryptographicBindingMethodsSupported(newCryptographicBindingMethodsSupported) + .credentialSigningAlgValuesSupported(newCredentialSigningAlgValuesSupported) + .credentialDefinition(newCredentialDefinition) + .build(); + + // Assert + assertEquals(newFormat, credentialConfiguration.format()); + assertEquals(newCryptographicBindingMethodsSupported, credentialConfiguration.cryptographicBindingMethodsSupported()); + assertEquals(newCredentialSigningAlgValuesSupported, credentialConfiguration.credentialSigningAlgValuesSupported()); + assertEquals(newCredentialDefinition, credentialConfiguration.credentialDefinition()); + } + + @Test + void lombokGeneratedMethodsTest() { + // Arrange + String expectedFormat = "format"; + List expectedCryptographicBindingMethodsSupported = List.of("method1", "method2"); + List expectedCredentialSigningAlgValuesSupported = List.of("alg1", "alg2"); + CredentialDefinition expectedCredentialDefinition = new CredentialDefinition(List.of("type")); + + CredentialConfiguration config1 = new CredentialConfiguration( + expectedFormat, + expectedCryptographicBindingMethodsSupported, + expectedCredentialSigningAlgValuesSupported, + expectedCredentialDefinition + ); + CredentialConfiguration config2 = new CredentialConfiguration( + expectedFormat, + expectedCryptographicBindingMethodsSupported, + expectedCredentialSigningAlgValuesSupported, + expectedCredentialDefinition + ); + + // Assert + assertEquals(config1, config2); + assertEquals(config1.hashCode(), config2.hashCode()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/dto/CredentialDetailsTest.java b/src/test/java/es/in2/issuer/domain/model/dto/CredentialDetailsTest.java new file mode 100644 index 000000000..5200a0de5 --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/model/dto/CredentialDetailsTest.java @@ -0,0 +1,72 @@ +package es.in2.issuer.domain.model.dto; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; + +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class CredentialDetailsTest { + + ObjectMapper objectMapper = new ObjectMapper(); + + @Test + void testConstructorAndGetters() { + // Arrange + UUID uuid = UUID.randomUUID(); + String expectedCredentialStatus = "Valid"; + String expectedCredentialJson = "{\"key\": \"value\"}"; + JsonNode jsonNode = null; + try { + jsonNode = objectMapper.readTree(expectedCredentialJson); + } catch (Exception e) { + e.printStackTrace(); + } + + // Act + CredentialDetails credentialDetails = new CredentialDetails(uuid, expectedCredentialStatus, jsonNode); + + // Assert + assertEquals(uuid, credentialDetails.procedureId()); + assertEquals(expectedCredentialStatus, credentialDetails.credentialStatus()); + assertEquals(jsonNode, credentialDetails.credential()); + } + + @Test + void testSetters() throws JsonProcessingException { + // Arrange + UUID uuid = UUID.randomUUID(); + String newCredentialStatus = "Revoked"; + JsonNode jsonNode = objectMapper.readTree("{\"key\": \"value\"}"); + + // Act + CredentialDetails credentialDetails = CredentialDetails.builder() + .procedureId(uuid) + .credentialStatus(newCredentialStatus) + .credential(jsonNode) + .build(); + + // Assert + assertEquals(uuid, credentialDetails.procedureId()); + assertEquals(newCredentialStatus, credentialDetails.credentialStatus()); + assertEquals(jsonNode, credentialDetails.credential()); + } + + @Test + void lombokGeneratedMethodsTest() throws JsonProcessingException { + // Arrange + UUID uuid = UUID.randomUUID(); + String expectedCredentialStatus = "Valid"; + JsonNode jsonNode = objectMapper.readTree("{\"key\": \"value\"}"); + + CredentialDetails credentialDetails = new CredentialDetails(uuid, expectedCredentialStatus, jsonNode); + CredentialDetails credentialDetails2 = new CredentialDetails(uuid, expectedCredentialStatus, jsonNode); + + // Assert + assertEquals(credentialDetails, credentialDetails2); + assertEquals(credentialDetails.hashCode(), credentialDetails2.hashCode()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/CredentialErrorResponseTest.java b/src/test/java/es/in2/issuer/domain/model/dto/CredentialErrorResponseTest.java similarity index 92% rename from src/test/java/es/in2/issuer/domain/model/CredentialErrorResponseTest.java rename to src/test/java/es/in2/issuer/domain/model/dto/CredentialErrorResponseTest.java index a2820ecfc..9dfc8433b 100644 --- a/src/test/java/es/in2/issuer/domain/model/CredentialErrorResponseTest.java +++ b/src/test/java/es/in2/issuer/domain/model/dto/CredentialErrorResponseTest.java @@ -1,6 +1,5 @@ -package es.in2.issuer.domain.model; +package es.in2.issuer.domain.model.dto; -import es.in2.issuer.domain.model.dto.CredentialErrorResponse; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -32,4 +31,4 @@ void lombokGeneratedMethodsTest() { assertEquals(error1.hashCode(), error2.hashCode()); // Tests hashCode() method generated by Lombok } -} +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/CredentialIssuerMetadataTest.java b/src/test/java/es/in2/issuer/domain/model/dto/CredentialIssuerMetadataTest.java similarity index 95% rename from src/test/java/es/in2/issuer/domain/model/CredentialIssuerMetadataTest.java rename to src/test/java/es/in2/issuer/domain/model/dto/CredentialIssuerMetadataTest.java index 43e790e38..d63a70dc2 100644 --- a/src/test/java/es/in2/issuer/domain/model/CredentialIssuerMetadataTest.java +++ b/src/test/java/es/in2/issuer/domain/model/dto/CredentialIssuerMetadataTest.java @@ -1,6 +1,5 @@ -package es.in2.issuer.domain.model; +package es.in2.issuer.domain.model.dto; -import es.in2.issuer.domain.model.dto.CredentialIssuerMetadata; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -57,4 +56,4 @@ void lombokGeneratedMethodsTest() { assertEquals(metadata1.hashCode(), metadata2.hashCode()); // Tests hashCode() method generated by Lombok } -} +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/dto/CredentialProcedureCreationRequestTest.java b/src/test/java/es/in2/issuer/domain/model/dto/CredentialProcedureCreationRequestTest.java new file mode 100644 index 000000000..4312e563d --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/model/dto/CredentialProcedureCreationRequestTest.java @@ -0,0 +1,71 @@ +package es.in2.issuer.domain.model.dto; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class CredentialProcedureCreationRequestTest { + + @Test + void testConstructorAndGetters() { + // Arrange + String expectedCredentialId = "123456"; + String expectedOrganizationIdentifier = "org123"; + String expectedCredentialDecoded = "Decoded Credential"; + + // Act + CredentialProcedureCreationRequest request = new CredentialProcedureCreationRequest( + expectedCredentialId, + expectedOrganizationIdentifier, + expectedCredentialDecoded + ); + + // Assert + assertEquals(expectedCredentialId, request.credentialId()); + assertEquals(expectedOrganizationIdentifier, request.organizationIdentifier()); + assertEquals(expectedCredentialDecoded, request.credentialDecoded()); + } + + @Test + void testSetters() { + // Arrange + String newCredentialId = "654321"; + String newOrganizationIdentifier = "org654"; + String newCredentialDecoded = "New Decoded Credential"; + + // Act + CredentialProcedureCreationRequest request = CredentialProcedureCreationRequest.builder() + .credentialId(newCredentialId) + .organizationIdentifier(newOrganizationIdentifier) + .credentialDecoded(newCredentialDecoded) + .build(); + + // Assert + assertEquals(newCredentialId, request.credentialId()); + assertEquals(newOrganizationIdentifier, request.organizationIdentifier()); + assertEquals(newCredentialDecoded, request.credentialDecoded()); + } + + @Test + void lombokGeneratedMethodsTest() { + // Arrange + String expectedCredentialId = "123456"; + String expectedOrganizationIdentifier = "org123"; + String expectedCredentialDecoded = "Decoded Credential"; + + CredentialProcedureCreationRequest request1 = new CredentialProcedureCreationRequest( + expectedCredentialId, + expectedOrganizationIdentifier, + expectedCredentialDecoded + ); + CredentialProcedureCreationRequest request2 = new CredentialProcedureCreationRequest( + expectedCredentialId, + expectedOrganizationIdentifier, + expectedCredentialDecoded + ); + + // Assert + assertEquals(request1, request2); + assertEquals(request1.hashCode(), request2.hashCode()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/dto/CredentialProceduresTest.java b/src/test/java/es/in2/issuer/domain/model/dto/CredentialProceduresTest.java new file mode 100644 index 000000000..172ea3166 --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/model/dto/CredentialProceduresTest.java @@ -0,0 +1,72 @@ +package es.in2.issuer.domain.model.dto; + +import org.junit.jupiter.api.Test; + +import java.sql.Timestamp; +import java.util.List; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class CredentialProceduresTest { + + @Test + void testConstructorAndGetters() { + // Arrange + ProcedureBasicInfo procedureBasicInfo = new ProcedureBasicInfo( + UUID.randomUUID(), + "John Doe", + "In Progress", + Timestamp.valueOf("2023-01-01 12:00:00") + ); + CredentialProcedures.CredentialProcedure credentialProcedure = new CredentialProcedures.CredentialProcedure(procedureBasicInfo); + List expectedCredentialProcedures = List.of(credentialProcedure); + + // Act + CredentialProcedures credentialProcedures = new CredentialProcedures(expectedCredentialProcedures); + + // Assert + assertEquals(expectedCredentialProcedures, credentialProcedures.credentialProcedures()); + } + + @Test + void testSetters() { + // Arrange + ProcedureBasicInfo procedureBasicInfo = new ProcedureBasicInfo( + UUID.randomUUID(), + "Jane Doe", + "Completed", + Timestamp.valueOf("2024-01-01 12:00:00") + ); + CredentialProcedures.CredentialProcedure credentialProcedure = new CredentialProcedures.CredentialProcedure(procedureBasicInfo); + List newCredentialProcedures = List.of(credentialProcedure); + + // Act + CredentialProcedures credentialProcedures = CredentialProcedures.builder() + .credentialProcedures(newCredentialProcedures) + .build(); + + // Assert + assertEquals(newCredentialProcedures, credentialProcedures.credentialProcedures()); + } + + @Test + void lombokGeneratedMethodsTest() { + // Arrange + ProcedureBasicInfo procedureBasicInfo = new ProcedureBasicInfo( + UUID.randomUUID(), + "John Doe", + "In Progress", + Timestamp.valueOf("2023-01-01 12:00:00") + ); + CredentialProcedures.CredentialProcedure credentialProcedure = new CredentialProcedures.CredentialProcedure(procedureBasicInfo); + List expectedCredentialProcedures = List.of(credentialProcedure); + + CredentialProcedures credentialProcedures1 = new CredentialProcedures(expectedCredentialProcedures); + CredentialProcedures credentialProcedures2 = new CredentialProcedures(expectedCredentialProcedures); + + // Assert + assertEquals(credentialProcedures1, credentialProcedures2); + assertEquals(credentialProcedures1.hashCode(), credentialProcedures2.hashCode()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/CredentialRequestTest.java b/src/test/java/es/in2/issuer/domain/model/dto/CredentialRequestTest.java similarity index 88% rename from src/test/java/es/in2/issuer/domain/model/CredentialRequestTest.java rename to src/test/java/es/in2/issuer/domain/model/dto/CredentialRequestTest.java index 4199aac47..18f5276f4 100644 --- a/src/test/java/es/in2/issuer/domain/model/CredentialRequestTest.java +++ b/src/test/java/es/in2/issuer/domain/model/dto/CredentialRequestTest.java @@ -1,8 +1,5 @@ -package es.in2.issuer.domain.model; +package es.in2.issuer.domain.model.dto; -import es.in2.issuer.domain.model.dto.CredentialDefinition; -import es.in2.issuer.domain.model.dto.CredentialRequest; -import es.in2.issuer.domain.model.dto.Proof; import org.junit.jupiter.api.Test; import java.util.List; @@ -38,4 +35,4 @@ void lombokGeneratedMethodsTest() { assertEquals(dto1.hashCode(), dto2.hashCode()); // Tests hashCode() method generated by Lombok } -} +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/CustomCredentialOfferTest.java b/src/test/java/es/in2/issuer/domain/model/dto/CustomCredentialOfferTest.java similarity index 96% rename from src/test/java/es/in2/issuer/domain/model/CustomCredentialOfferTest.java rename to src/test/java/es/in2/issuer/domain/model/dto/CustomCredentialOfferTest.java index 6fdb5683c..c24446c83 100644 --- a/src/test/java/es/in2/issuer/domain/model/CustomCredentialOfferTest.java +++ b/src/test/java/es/in2/issuer/domain/model/dto/CustomCredentialOfferTest.java @@ -1,7 +1,5 @@ -package es.in2.issuer.domain.model; +package es.in2.issuer.domain.model.dto; -import es.in2.issuer.domain.model.dto.CustomCredentialOffer; -import es.in2.issuer.domain.model.dto.Grant; import org.junit.jupiter.api.Test; import java.util.HashMap; @@ -78,4 +76,4 @@ void lombokGeneratedMethodsTest() { assertEquals(offer1.hashCode(), offer2.hashCode()); // Tests hashCode() method generated by Lombok } -} +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/dto/DeferredCredentialMetadataDeferredResponseTest.java b/src/test/java/es/in2/issuer/domain/model/dto/DeferredCredentialMetadataDeferredResponseTest.java new file mode 100644 index 000000000..51ac9b264 --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/model/dto/DeferredCredentialMetadataDeferredResponseTest.java @@ -0,0 +1,80 @@ +package es.in2.issuer.domain.model.dto; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class DeferredCredentialMetadataDeferredResponseTest { + + @Test + void testConstructorAndGetters() { + // Arrange + String expectedId = "id123"; + String expectedProcedureId = "procedure123"; + String expectedTransactionId = "transaction123"; + String expectedVc = "vc123"; + + // Act + DeferredCredentialMetadataDeferredResponse deferredCredentialMetadataDeferredResponse = new DeferredCredentialMetadataDeferredResponse( + expectedId, + expectedProcedureId, + expectedTransactionId, + expectedVc + ); + + // Assert + assertEquals(expectedId, deferredCredentialMetadataDeferredResponse.id()); + assertEquals(expectedProcedureId, deferredCredentialMetadataDeferredResponse.procedureId()); + assertEquals(expectedTransactionId, deferredCredentialMetadataDeferredResponse.transactionId()); + assertEquals(expectedVc, deferredCredentialMetadataDeferredResponse.vc()); + } + + @Test + void testSetters() { + // Arrange + String newId = "newId123"; + String newProcedureId = "newProcedure123"; + String newTransactionId = "newTransaction123"; + String newVc = "newVc123"; + + // Act + DeferredCredentialMetadataDeferredResponse deferredCredentialMetadataDeferredResponse = DeferredCredentialMetadataDeferredResponse.builder() + .id(newId) + .procedureId(newProcedureId) + .transactionId(newTransactionId) + .vc(newVc) + .build(); + + // Assert + assertEquals(newId, deferredCredentialMetadataDeferredResponse.id()); + assertEquals(newProcedureId, deferredCredentialMetadataDeferredResponse.procedureId()); + assertEquals(newTransactionId, deferredCredentialMetadataDeferredResponse.transactionId()); + assertEquals(newVc, deferredCredentialMetadataDeferredResponse.vc()); + } + + @Test + void lombokGeneratedMethodsTest() { + // Arrange + String expectedId = "id123"; + String expectedProcedureId = "procedure123"; + String expectedTransactionId = "transaction123"; + String expectedVc = "vc123"; + + DeferredCredentialMetadataDeferredResponse deferredCredentialMetadataDeferredResponse = new DeferredCredentialMetadataDeferredResponse( + expectedId, + expectedProcedureId, + expectedTransactionId, + expectedVc + ); + DeferredCredentialMetadataDeferredResponse deferredCredentialMetadataDeferredResponse2 = new DeferredCredentialMetadataDeferredResponse( + expectedId, + expectedProcedureId, + expectedTransactionId, + expectedVc + ); + + // Assert + assertEquals(deferredCredentialMetadataDeferredResponse, deferredCredentialMetadataDeferredResponse2); + assertEquals(deferredCredentialMetadataDeferredResponse.hashCode(), deferredCredentialMetadataDeferredResponse2.hashCode()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/dto/DeferredCredentialRequestTest.java b/src/test/java/es/in2/issuer/domain/model/dto/DeferredCredentialRequestTest.java new file mode 100644 index 000000000..d961e3593 --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/model/dto/DeferredCredentialRequestTest.java @@ -0,0 +1,34 @@ +package es.in2.issuer.domain.model.dto; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class DeferredCredentialRequestTest { + + @Test + void testConstructorAndGetters() { + // Arrange + String expectedTransactionId = "958e84cf-888b-488a-bf30-7f3b14f70699"; + + // Act + DeferredCredentialRequest deferredCredentialRequest = new DeferredCredentialRequest(expectedTransactionId); + + // Assert + assertEquals(expectedTransactionId, deferredCredentialRequest.transactionId()); + } + + @Test + void testSetters() { + // Arrange + String newTransactionId = "newTransactionId"; + + // Act + DeferredCredentialRequest deferredCredentialRequest = DeferredCredentialRequest.builder() + .transactionId(newTransactionId) + .build(); + + // Assert + assertEquals(newTransactionId, deferredCredentialRequest.transactionId()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/GlobalErrorMessageTest.java b/src/test/java/es/in2/issuer/domain/model/dto/GlobalErrorMessageTest.java similarity index 95% rename from src/test/java/es/in2/issuer/domain/model/GlobalErrorMessageTest.java rename to src/test/java/es/in2/issuer/domain/model/dto/GlobalErrorMessageTest.java index 2a35b87fd..de9164403 100644 --- a/src/test/java/es/in2/issuer/domain/model/GlobalErrorMessageTest.java +++ b/src/test/java/es/in2/issuer/domain/model/dto/GlobalErrorMessageTest.java @@ -1,6 +1,5 @@ -package es.in2.issuer.domain.model; +package es.in2.issuer.domain.model.dto; -import es.in2.issuer.domain.model.dto.GlobalErrorMessage; import org.junit.jupiter.api.Test; import java.time.LocalDateTime; @@ -56,4 +55,4 @@ void lombokGeneratedMethodsTest() { assertEquals(error1.hashCode(), error2.hashCode()); // Tests hashCode() method generated by Lombok } -} +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/GrantTest.java b/src/test/java/es/in2/issuer/domain/model/dto/GrantTest.java similarity index 91% rename from src/test/java/es/in2/issuer/domain/model/GrantTest.java rename to src/test/java/es/in2/issuer/domain/model/dto/GrantTest.java index 9596142f7..705552ab9 100644 --- a/src/test/java/es/in2/issuer/domain/model/GrantTest.java +++ b/src/test/java/es/in2/issuer/domain/model/dto/GrantTest.java @@ -1,6 +1,5 @@ -package es.in2.issuer.domain.model; +package es.in2.issuer.domain.model.dto; -import es.in2.issuer.domain.model.dto.Grant; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -25,7 +24,7 @@ void testSetters() { Grant grant = Grant.builder().preAuthorizedCode("5678").txCode(Grant.TxCode.builder().length(6).build()).build(); // Assert assertEquals("5678", grant.preAuthorizedCode()); - assertEquals(6,grant.txCode().length()); + assertEquals(6, grant.txCode().length()); } @Test @@ -41,4 +40,4 @@ void lombokGeneratedMethodsTest() { assertEquals(grant1.hashCode(), grant2.hashCode()); // Tests hashCode() method generated by Lombok } -} +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/dto/LEARCredentialEmployeeJwtPayloadTest.java b/src/test/java/es/in2/issuer/domain/model/dto/LEARCredentialEmployeeJwtPayloadTest.java new file mode 100644 index 000000000..87550e404 --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/model/dto/LEARCredentialEmployeeJwtPayloadTest.java @@ -0,0 +1,138 @@ +package es.in2.issuer.domain.model.dto; + +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class LEARCredentialEmployeeJwtPayloadTest { + + List expectedContext = List.of("context1", "context2"); + String expectedId = "id"; + List expectedType = List.of("type1", "type2"); + LEARCredentialEmployee.CredentialSubject credentialSubject = getCredentialSubject(); + String expectedExpirationDate = "expirationDate"; + String expectedIssuanceDate = "issuanceDate"; + String expectedIssuer = "issuer"; + String expectedValidFrom = "validFrom"; + LEARCredentialEmployee learCredentialEmployee = LEARCredentialEmployee.builder() + .context(expectedContext) + .id(expectedId) + .type(expectedType) + .credentialSubject(credentialSubject) + .expirationDate(expectedExpirationDate) + .issuanceDate(expectedIssuanceDate) + .issuer(expectedIssuer) + .validFrom(expectedValidFrom) + .build(); + + private static LEARCredentialEmployee.@NotNull CredentialSubject getCredentialSubject() { + LEARCredentialEmployee.CredentialSubject.Mandate.LifeSpan lifeSpan = new LEARCredentialEmployee.CredentialSubject.Mandate.LifeSpan("2024-01-01T00:00:00", "2024-12-31T23:59:59"); + LEARCredentialEmployee.CredentialSubject.Mandate.Mandatee mandatee = new LEARCredentialEmployee.CredentialSubject.Mandate.Mandatee("mandateeId", "email", "firstName", "lastName", "123456789"); + LEARCredentialEmployee.CredentialSubject.Mandate mandate = getMandate(lifeSpan, mandatee); + return new LEARCredentialEmployee.CredentialSubject(mandate); + } + + private static LEARCredentialEmployee.CredentialSubject.@NotNull Mandate getMandate(LEARCredentialEmployee.CredentialSubject.Mandate.LifeSpan lifeSpan, LEARCredentialEmployee.CredentialSubject.Mandate.Mandatee mandatee) { + LEARCredentialEmployee.CredentialSubject.Mandate.Mandator mandator = new LEARCredentialEmployee.CredentialSubject.Mandate.Mandator("commonName", "country", "emailAddress", "organization", "organizationIdentifier", "serialNumber"); + List powerList = Collections.singletonList(new LEARCredentialEmployee.CredentialSubject.Mandate.Power("powerId", "tmfAction", "tmfDomain", "tmfFunction", "tmfType")); + return new LEARCredentialEmployee.CredentialSubject.Mandate("mandateId", lifeSpan, mandatee, mandator, powerList); + } + + @Test + void testConstructorAndGetters() { + // Arrange + String subject = "subject"; + Long expectedNotValidBefore = 1622548800L; + String issuer = "issuer"; + Long expectedExpirationTime = 1625130800L; + Long expectedIssuedAt = 1622548800L; + LEARCredentialEmployee learCredentialEmployee1 = learCredentialEmployee; + String expectedJwtId = "jwtId"; + + // Act + LEARCredentialEmployeeJwtPayload payload = new LEARCredentialEmployeeJwtPayload( + subject, + expectedNotValidBefore, + issuer, + expectedExpirationTime, + expectedIssuedAt, + learCredentialEmployee1, + expectedJwtId + ); + + // Assert + assertEquals(subject, payload.subject()); + assertEquals(expectedNotValidBefore, payload.notValidBefore()); + assertEquals(issuer, payload.issuer()); + assertEquals(expectedExpirationTime, payload.expirationTime()); + assertEquals(expectedIssuedAt, payload.issuedAt()); + assertEquals(learCredentialEmployee1, payload.learCredentialEmployee()); + assertEquals(expectedJwtId, payload.JwtId()); + } + + @Test + void testSetters() { + // Arrange + String newSubject = "newSubject"; + Long newNotValidBefore = 1622548801L; + String newIssuer = "newIssuer"; + Long newExpirationTime = 1625130801L; + Long newIssuedAt = 1622548801L; + LEARCredentialEmployee learCredentialEmployee1 = learCredentialEmployee; + String newJwtId = "newJwtId"; + + // Act + LEARCredentialEmployeeJwtPayload payload = LEARCredentialEmployeeJwtPayload.builder() + .subject(newSubject) + .notValidBefore(newNotValidBefore) + .issuer(newIssuer) + .expirationTime(newExpirationTime) + .issuedAt(newIssuedAt) + .learCredentialEmployee(learCredentialEmployee1) + .JwtId(newJwtId) + .build(); + + // Assert + assertEquals(newSubject, payload.subject()); + assertEquals(newNotValidBefore, payload.notValidBefore()); + assertEquals(newIssuer, payload.issuer()); + assertEquals(newExpirationTime, payload.expirationTime()); + assertEquals(newIssuedAt, payload.issuedAt()); + assertEquals(learCredentialEmployee1, payload.learCredentialEmployee()); + assertEquals(newJwtId, payload.JwtId()); + } + + @Test + void lombokGeneratedMethodsTest() { + // Arrange + String subject = "subject"; + Long expectedNotValidBefore = 1622548800L; + String issuer = "issuer"; + LEARCredentialEmployeeJwtPayload learCredentialEmployeeJwtPayload = getLearCredentialEmployeeJwtPayload(subject, expectedNotValidBefore, issuer); + + // Assert + assertEquals(learCredentialEmployeeJwtPayload.hashCode(), learCredentialEmployeeJwtPayload.hashCode()); + } + + private @NotNull LEARCredentialEmployeeJwtPayload getLearCredentialEmployeeJwtPayload(String expectedSubject, Long expectedNotValidBefore, String expectedIssuer) { + Long expectedExpirationTime = 1625130800L; + Long expectedIssuedAt = 1622548800L; + LEARCredentialEmployee learCredentialEmployee1 = learCredentialEmployee; + String jwtId = "jwtId"; + + return new LEARCredentialEmployeeJwtPayload( + expectedSubject, + expectedNotValidBefore, + expectedIssuer, + expectedExpirationTime, + expectedIssuedAt, + learCredentialEmployee1, + jwtId + ); + } + +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/dto/LEARCredentialEmployeeTest.java b/src/test/java/es/in2/issuer/domain/model/dto/LEARCredentialEmployeeTest.java new file mode 100644 index 000000000..135022de8 --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/model/dto/LEARCredentialEmployeeTest.java @@ -0,0 +1,60 @@ +package es.in2.issuer.domain.model.dto; + +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; + +import java.util.Collections; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class LEARCredentialEmployeeTest { + + private static LEARCredentialEmployee.@NotNull CredentialSubject getCredentialSubject() { + LEARCredentialEmployee.CredentialSubject.Mandate.LifeSpan lifeSpan = new LEARCredentialEmployee.CredentialSubject.Mandate.LifeSpan("2024-01-01T00:00:00", "2024-12-31T23:59:59"); + LEARCredentialEmployee.CredentialSubject.Mandate.Mandatee mandatee = new LEARCredentialEmployee.CredentialSubject.Mandate.Mandatee("mandateeId", "email", "firstName", "lastName", "123456789"); + LEARCredentialEmployee.CredentialSubject.Mandate mandate = getMandate(lifeSpan, mandatee); + return new LEARCredentialEmployee.CredentialSubject(mandate); + } + + private static LEARCredentialEmployee.CredentialSubject.@NotNull Mandate getMandate(LEARCredentialEmployee.CredentialSubject.Mandate.LifeSpan lifeSpan, LEARCredentialEmployee.CredentialSubject.Mandate.Mandatee mandatee) { + LEARCredentialEmployee.CredentialSubject.Mandate.Mandator mandator = new LEARCredentialEmployee.CredentialSubject.Mandate.Mandator("commonName", "country", "emailAddress", "organization", "organizationIdentifier", "serialNumber"); + List powerList = Collections.singletonList(new LEARCredentialEmployee.CredentialSubject.Mandate.Power("powerId", "tmfAction", "tmfDomain", "tmfFunction", "tmfType")); + return new LEARCredentialEmployee.CredentialSubject.Mandate("mandateId", lifeSpan, mandatee, mandator, powerList); + } + + @Test + void testConstructorAndGetters() { + //Arrange + List expectedContext = List.of("context1", "context2"); + String expectedId = "id"; + List expectedType = List.of("type1", "type2"); + LEARCredentialEmployee.CredentialSubject credentialSubject = getCredentialSubject(); + String expectedExpirationDate = "expirationDate"; + String expectedIssuanceDate = "issuanceDate"; + String expectedIssuer = "issuer"; + String expectedValidFrom = "validFrom"; + + LEARCredentialEmployee credentialEmployee = LEARCredentialEmployee.builder() + .context(expectedContext) + .id(expectedId) + .type(expectedType) + .credentialSubject(credentialSubject) + .expirationDate(expectedExpirationDate) + .issuanceDate(expectedIssuanceDate) + .issuer(expectedIssuer) + .validFrom(expectedValidFrom) + .build(); + + // Act & Assert + assertEquals(expectedContext, credentialEmployee.context()); + assertEquals(expectedId, credentialEmployee.id()); + assertEquals(expectedType, credentialEmployee.type()); + assertEquals(credentialSubject, credentialEmployee.credentialSubject()); + assertEquals(expectedExpirationDate, credentialEmployee.expirationDate()); + assertEquals(expectedIssuanceDate, credentialEmployee.issuanceDate()); + assertEquals(expectedIssuer, credentialEmployee.issuer()); + assertEquals(expectedValidFrom, credentialEmployee.validFrom()); + } + +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/dto/LEARCredentialRequestTest.java b/src/test/java/es/in2/issuer/domain/model/dto/LEARCredentialRequestTest.java new file mode 100644 index 000000000..1032d3f4d --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/model/dto/LEARCredentialRequestTest.java @@ -0,0 +1,40 @@ +package es.in2.issuer.domain.model.dto; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class LEARCredentialRequestTest { + + ObjectMapper objectMapper = new ObjectMapper(); + + @Test + void testConstructorAndGetters() { + // Arrange + ObjectNode objectNode = objectMapper.createObjectNode(); + objectNode.put("key", "value"); + + // Act + LEARCredentialRequest learCredentialRequest = new LEARCredentialRequest(objectNode); + + // Assert + assertEquals(objectNode, learCredentialRequest.credential()); + } + + @Test + void testSetters() { + // Arrange + ObjectNode objectNode = objectMapper.createObjectNode(); + objectNode.put("newKey", "newValue"); + + // Act + LEARCredentialRequest learCredentialRequest = LEARCredentialRequest.builder() + .credential(objectNode) + .build(); + + // Assert + assertEquals(objectNode, learCredentialRequest.credential()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/dto/NonceValidationResponseTest.java b/src/test/java/es/in2/issuer/domain/model/dto/NonceValidationResponseTest.java new file mode 100644 index 000000000..fb42f010e --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/model/dto/NonceValidationResponseTest.java @@ -0,0 +1,34 @@ +package es.in2.issuer.domain.model.dto; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class NonceValidationResponseTest { + + @Test + void testConstructorAndGetters() { + // Arrange + Boolean expectedIsNonceValid = true; + + // Act + NonceValidationResponse nonceValidationResponse = new NonceValidationResponse(expectedIsNonceValid); + + // Assert + assertEquals(expectedIsNonceValid, nonceValidationResponse.isNonceValid()); + } + + @Test + void testSetters() { + // Arrange + Boolean newIsNonceValid = false; + + // Act + NonceValidationResponse nonceValidationResponse = NonceValidationResponse.builder() + .isNonceValid(newIsNonceValid) + .build(); + + // Assert + assertEquals(newIsNonceValid, nonceValidationResponse.isNonceValid()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/dto/PendingCredentialsTest.java b/src/test/java/es/in2/issuer/domain/model/dto/PendingCredentialsTest.java new file mode 100644 index 000000000..e4b93f982 --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/model/dto/PendingCredentialsTest.java @@ -0,0 +1,52 @@ +package es.in2.issuer.domain.model.dto; + +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class PendingCredentialsTest { + + @Test + void testConstructorAndGetters() { + // Arrange + PendingCredentials.CredentialPayload credentialPayload = new PendingCredentials.CredentialPayload("sampleCredential"); + List credentialPayloadList = List.of(credentialPayload); + + // Act + PendingCredentials pendingCredentials = new PendingCredentials(credentialPayloadList); + + // Assert + assertEquals(credentialPayloadList, pendingCredentials.credentials()); + } + + @Test + void testSetters() { + // Arrange + PendingCredentials.CredentialPayload credentialPayload = new PendingCredentials.CredentialPayload("newSampleCredential"); + List credentialPayloadList = List.of(credentialPayload); + + // Act + PendingCredentials pendingCredentials = PendingCredentials.builder() + .credentials(credentialPayloadList) + .build(); + + // Assert + assertEquals(credentialPayloadList, pendingCredentials.credentials()); + } + + @Test + void lombokGeneratedMethodsTest() { + // Arrange + PendingCredentials.CredentialPayload credentialPayload = new PendingCredentials.CredentialPayload("sampleCredential"); + List credentialPayloadList = List.of(credentialPayload); + + PendingCredentials pendingCredentials1 = new PendingCredentials(credentialPayloadList); + PendingCredentials pendingCredentials2 = new PendingCredentials(credentialPayloadList); + + // Assert + assertEquals(pendingCredentials1, pendingCredentials2); + assertEquals(pendingCredentials1.hashCode(), pendingCredentials2.hashCode()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/dto/PreAuthCodeResponseTest.java b/src/test/java/es/in2/issuer/domain/model/dto/PreAuthCodeResponseTest.java new file mode 100644 index 000000000..d80425bd0 --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/model/dto/PreAuthCodeResponseTest.java @@ -0,0 +1,42 @@ +package es.in2.issuer.domain.model.dto; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class PreAuthCodeResponseTest { + + @Test + void testConstructorAndGetters() { + // Arrange + Grant grant = new Grant("type", new Grant.TxCode(4, "numeric", "description")); + String expectedPin = "1234"; + + // Act + PreAuthCodeResponse preAuthCodeResponse = new PreAuthCodeResponse( + grant, + expectedPin + ); + + // Assert + assertEquals(grant, preAuthCodeResponse.grant()); + assertEquals(expectedPin, preAuthCodeResponse.pin()); + } + + @Test + void testSetters() { + // Arrange + Grant grant = new Grant("newType", new Grant.TxCode(5, "newNumeric", "newDescription")); + String newPin = "5678"; + + // Act + PreAuthCodeResponse preAuthCodeResponse = PreAuthCodeResponse.builder() + .grant(grant) + .pin(newPin) + .build(); + + // Assert + assertEquals(grant, preAuthCodeResponse.grant()); + assertEquals(newPin, preAuthCodeResponse.pin()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/dto/ProcedureBasicInfoTest.java b/src/test/java/es/in2/issuer/domain/model/dto/ProcedureBasicInfoTest.java new file mode 100644 index 000000000..6618742d4 --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/model/dto/ProcedureBasicInfoTest.java @@ -0,0 +1,83 @@ +package es.in2.issuer.domain.model.dto; + +import org.junit.jupiter.api.Test; + +import java.sql.Timestamp; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class ProcedureBasicInfoTest { + + @Test + void testConstructorAndGetters() { + // Arrange + UUID uuid = UUID.randomUUID(); + String expectedFullName = "John Doe"; + String expectedStatus = "In Progress"; + Timestamp timestamp = Timestamp.valueOf("2023-01-01 12:00:00"); + + // Act + ProcedureBasicInfo procedureBasicInfo = new ProcedureBasicInfo( + uuid, + expectedFullName, + expectedStatus, + timestamp + ); + + // Assert + assertEquals(uuid, procedureBasicInfo.procedureId()); + assertEquals(expectedFullName, procedureBasicInfo.fullName()); + assertEquals(expectedStatus, procedureBasicInfo.status()); + assertEquals(timestamp, procedureBasicInfo.updated()); + } + + @Test + void testSetters() { + // Arrange + UUID uuid = UUID.randomUUID(); + String newFullName = "Jane Doe"; + String newStatus = "Completed"; + Timestamp timestamp = Timestamp.valueOf("2024-01-01 12:00:00"); + + // Act + ProcedureBasicInfo procedureBasicInfo = ProcedureBasicInfo.builder() + .procedureId(uuid) + .fullName(newFullName) + .status(newStatus) + .updated(timestamp) + .build(); + + // Assert + assertEquals(uuid, procedureBasicInfo.procedureId()); + assertEquals(newFullName, procedureBasicInfo.fullName()); + assertEquals(newStatus, procedureBasicInfo.status()); + assertEquals(timestamp, procedureBasicInfo.updated()); + } + + @Test + void lombokGeneratedMethodsTest() { + // Arrange + UUID uuid = UUID.randomUUID(); + String expectedFullName = "John Doe"; + String expectedStatus = "In Progress"; + Timestamp timestamp = Timestamp.valueOf("2023-01-01 12:00:00"); + + ProcedureBasicInfo procedureBasicInfo1 = new ProcedureBasicInfo( + uuid, + expectedFullName, + expectedStatus, + timestamp + ); + ProcedureBasicInfo procedureBasicInfo2 = new ProcedureBasicInfo( + uuid, + expectedFullName, + expectedStatus, + timestamp + ); + + // Assert + assertEquals(procedureBasicInfo1, procedureBasicInfo2); + assertEquals(procedureBasicInfo1.hashCode(), procedureBasicInfo2.hashCode()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/ProofTest.java b/src/test/java/es/in2/issuer/domain/model/dto/ProofTest.java similarity index 93% rename from src/test/java/es/in2/issuer/domain/model/ProofTest.java rename to src/test/java/es/in2/issuer/domain/model/dto/ProofTest.java index 704aa1dfa..04cf709e5 100644 --- a/src/test/java/es/in2/issuer/domain/model/ProofTest.java +++ b/src/test/java/es/in2/issuer/domain/model/dto/ProofTest.java @@ -1,6 +1,5 @@ -package es.in2.issuer.domain.model; +package es.in2.issuer.domain.model.dto; -import es.in2.issuer.domain.model.dto.Proof; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -32,4 +31,4 @@ void lombokGeneratedMethodsTest() { assertEquals(dto1.hashCode(), dto2.hashCode()); // Tests hashCode() method generated by Lombok } -} +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/SignatureConfigurationTest.java b/src/test/java/es/in2/issuer/domain/model/dto/SignatureConfigurationTest.java similarity index 94% rename from src/test/java/es/in2/issuer/domain/model/SignatureConfigurationTest.java rename to src/test/java/es/in2/issuer/domain/model/dto/SignatureConfigurationTest.java index 897ea47b4..c457a2524 100644 --- a/src/test/java/es/in2/issuer/domain/model/SignatureConfigurationTest.java +++ b/src/test/java/es/in2/issuer/domain/model/dto/SignatureConfigurationTest.java @@ -1,6 +1,5 @@ -package es.in2.issuer.domain.model; +package es.in2.issuer.domain.model.dto; -import es.in2.issuer.domain.model.dto.SignatureConfiguration; import es.in2.issuer.domain.model.enums.SignatureType; import org.junit.jupiter.api.Test; @@ -40,4 +39,4 @@ void lombokGeneratedMethodsTest() { assertEquals(config1.hashCode(), config2.hashCode()); // Tests hashCode() method generated by Lombok } -} +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/SignatureRequestTest.java b/src/test/java/es/in2/issuer/domain/model/dto/SignatureRequestTest.java similarity index 89% rename from src/test/java/es/in2/issuer/domain/model/SignatureRequestTest.java rename to src/test/java/es/in2/issuer/domain/model/dto/SignatureRequestTest.java index 9dd506e0a..b2ff49d71 100644 --- a/src/test/java/es/in2/issuer/domain/model/SignatureRequestTest.java +++ b/src/test/java/es/in2/issuer/domain/model/dto/SignatureRequestTest.java @@ -1,7 +1,5 @@ -package es.in2.issuer.domain.model; +package es.in2.issuer.domain.model.dto; -import es.in2.issuer.domain.model.dto.SignatureConfiguration; -import es.in2.issuer.domain.model.dto.SignatureRequest; import es.in2.issuer.domain.model.enums.SignatureType; import org.junit.jupiter.api.Test; @@ -34,4 +32,4 @@ void lombokGeneratedMethodsTest() { assertEquals(request1.hashCode(), request2.hashCode()); // Tests hashCode() method generated by Lombok } -} +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/dto/SignedCredentialsTest.java b/src/test/java/es/in2/issuer/domain/model/dto/SignedCredentialsTest.java new file mode 100644 index 000000000..47442b4fa --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/model/dto/SignedCredentialsTest.java @@ -0,0 +1,52 @@ +package es.in2.issuer.domain.model.dto; + +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class SignedCredentialsTest { + + @Test + void testConstructorAndGetters() { + // Arrange + SignedCredentials.SignedCredential sampleCredential = new SignedCredentials.SignedCredential("sampleCredential"); + List signedCredentialList = List.of(sampleCredential); + + // Act + SignedCredentials signedCredentials = new SignedCredentials(signedCredentialList); + + // Assert + assertEquals(signedCredentialList, signedCredentials.credentials()); + } + + @Test + void testSetters() { + // Arrange + SignedCredentials.SignedCredential sampleCredential = new SignedCredentials.SignedCredential("newSampleCredential"); + List signedCredentialList = List.of(sampleCredential); + + // Act + SignedCredentials signedCredentials = SignedCredentials.builder() + .credentials(signedCredentialList) + .build(); + + // Assert + assertEquals(signedCredentialList, signedCredentials.credentials()); + } + + @Test + void lombokGeneratedMethodsTest() { + // Arrange + SignedCredentials.SignedCredential sampleCredential = new SignedCredentials.SignedCredential("sampleCredential"); + List signedCredentialList = List.of(sampleCredential); + + SignedCredentials signedCredentials1 = new SignedCredentials(signedCredentialList); + SignedCredentials signedCredentials2 = new SignedCredentials(signedCredentialList); + + // Assert + assertEquals(signedCredentials1, signedCredentials2); + assertEquals(signedCredentials1.hashCode(), signedCredentials2.hashCode()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/SignedDataTest.java b/src/test/java/es/in2/issuer/domain/model/dto/SignedDataTest.java similarity index 92% rename from src/test/java/es/in2/issuer/domain/model/SignedDataTest.java rename to src/test/java/es/in2/issuer/domain/model/dto/SignedDataTest.java index 2fdc85cb1..f70b272f2 100644 --- a/src/test/java/es/in2/issuer/domain/model/SignedDataTest.java +++ b/src/test/java/es/in2/issuer/domain/model/dto/SignedDataTest.java @@ -1,6 +1,5 @@ -package es.in2.issuer.domain.model; +package es.in2.issuer.domain.model.dto; -import es.in2.issuer.domain.model.dto.SignedData; import es.in2.issuer.domain.model.enums.SignatureType; import org.junit.jupiter.api.Test; @@ -33,4 +32,4 @@ void lombokGeneratedMethodsTest() { assertEquals(data1.hashCode(), data2.hashCode()); // Tests hashCode() method generated by Lombok } -} +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/SubjectDataResponseTest.java b/src/test/java/es/in2/issuer/domain/model/dto/SubjectDataResponseTest.java similarity index 92% rename from src/test/java/es/in2/issuer/domain/model/SubjectDataResponseTest.java rename to src/test/java/es/in2/issuer/domain/model/dto/SubjectDataResponseTest.java index eabb183af..58a1c447c 100644 --- a/src/test/java/es/in2/issuer/domain/model/SubjectDataResponseTest.java +++ b/src/test/java/es/in2/issuer/domain/model/dto/SubjectDataResponseTest.java @@ -1,6 +1,5 @@ -package es.in2.issuer.domain.model; +package es.in2.issuer.domain.model.dto; -import es.in2.issuer.domain.model.dto.SubjectDataResponse; import org.junit.jupiter.api.Test; import java.util.HashMap; @@ -33,4 +32,4 @@ void lombokGeneratedMethodsTest() { assertEquals(dto1.hashCode(), dto2.hashCode()); // Tests hashCode() method generated by Lombok } -} +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/dto/VcTemplateTest.java b/src/test/java/es/in2/issuer/domain/model/dto/VcTemplateTest.java new file mode 100644 index 000000000..bfec7ff1a --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/model/dto/VcTemplateTest.java @@ -0,0 +1,59 @@ +package es.in2.issuer.domain.model.dto; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class VcTemplateTest { + + @Test + void testConstructorAndGetters() { + // Arrange + Boolean expectedMutable = true; + String expectedName = "Template"; + String expectedTemplate = "Template content"; + + // Act + VcTemplate vcTemplate = new VcTemplate(expectedMutable, expectedName, expectedTemplate); + + // Assert + assertEquals(expectedMutable, vcTemplate.mutable()); + assertEquals(expectedName, vcTemplate.name()); + assertEquals(expectedTemplate, vcTemplate.template()); + } + + @Test + void testSetters() { + // Arrange + Boolean newMutable = false; + String newName = "New Template"; + String newTemplate = "New Template content"; + + // Act + VcTemplate vcTemplate = VcTemplate.builder() + .mutable(newMutable) + .name(newName) + .template(newTemplate) + .build(); + + // Assert + assertEquals(newMutable, vcTemplate.mutable()); + assertEquals(newName, vcTemplate.name()); + assertEquals(newTemplate, vcTemplate.template()); + } + + @Test + void lombokGeneratedMethodsTest() { + // Arrange + Boolean expectedMutable = true; + String expectedName = "Template"; + String expectedTemplate = "Template content"; + + VcTemplate vcTemplate1 = new VcTemplate(expectedMutable, expectedName, expectedTemplate); + VcTemplate vcTemplate2 = new VcTemplate(expectedMutable, expectedName, expectedTemplate); + + // Assert + assertEquals(vcTemplate1, vcTemplate2); + assertEquals(vcTemplate1.hashCode(), vcTemplate2.hashCode()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/VerifiableCredentialJWTTest.java b/src/test/java/es/in2/issuer/domain/model/dto/VerifiableCredentialJWTTest.java similarity index 91% rename from src/test/java/es/in2/issuer/domain/model/VerifiableCredentialJWTTest.java rename to src/test/java/es/in2/issuer/domain/model/dto/VerifiableCredentialJWTTest.java index 3138f5bb2..b560f9716 100644 --- a/src/test/java/es/in2/issuer/domain/model/VerifiableCredentialJWTTest.java +++ b/src/test/java/es/in2/issuer/domain/model/dto/VerifiableCredentialJWTTest.java @@ -1,6 +1,5 @@ -package es.in2.issuer.domain.model; +package es.in2.issuer.domain.model.dto; -import es.in2.issuer.domain.model.dto.VerifiableCredentialJWT; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -37,4 +36,4 @@ void lombokGeneratedMethodsTest() { assertEquals(jwt1.hashCode(), jwt2.hashCode()); // Tests hashCode() method generated by Lombok } -} +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/VerifiableCredentialResponseTest.java b/src/test/java/es/in2/issuer/domain/model/dto/VerifiableCredentialResponseTest.java similarity index 71% rename from src/test/java/es/in2/issuer/domain/model/VerifiableCredentialResponseTest.java rename to src/test/java/es/in2/issuer/domain/model/dto/VerifiableCredentialResponseTest.java index eaf20cab0..cd89ff0dc 100644 --- a/src/test/java/es/in2/issuer/domain/model/VerifiableCredentialResponseTest.java +++ b/src/test/java/es/in2/issuer/domain/model/dto/VerifiableCredentialResponseTest.java @@ -1,9 +1,7 @@ -package es.in2.issuer.domain.model; +package es.in2.issuer.domain.model.dto; -import es.in2.issuer.domain.model.dto.VerifiableCredentialResponse; import org.junit.jupiter.api.Test; - import static org.junit.jupiter.api.Assertions.assertEquals; class VerifiableCredentialResponseTest { @@ -11,12 +9,12 @@ class VerifiableCredentialResponseTest { @Test void testConstructorAndGetters() { // Arrange - String transactionId= "1234"; + String transactionId = "1234"; String expectedCredential = "LUpixVCWJk0eOt4CXQe1NXK....WZwmhmn9OQp6YxX0a2L"; String expectedCNonce = "fGFF7UkhLA"; int expectedCNonceExpiresIn = 35; // Act - VerifiableCredentialResponse responseDTO = new VerifiableCredentialResponse(expectedCredential,transactionId ,expectedCNonce, expectedCNonceExpiresIn); + VerifiableCredentialResponse responseDTO = new VerifiableCredentialResponse(expectedCredential, transactionId, expectedCNonce, expectedCNonceExpiresIn); // Assert assertEquals(expectedCredential, responseDTO.credential()); } @@ -24,16 +22,16 @@ void testConstructorAndGetters() { @Test void lombokGeneratedMethodsTest() { // Arrange - String transactionId= "1234"; + String transactionId = "1234"; String expectedCredential = "LUpixVCWJk0eOt4CXQe1NXK....WZwmhmn9OQp6YxX0a2L"; String expectedCNonce = "fGFF7UkhLA"; int expectedCNonceExpiresIn = 35; // Act - VerifiableCredentialResponse dto1 = new VerifiableCredentialResponse(expectedCredential, transactionId,expectedCNonce, expectedCNonceExpiresIn); - VerifiableCredentialResponse dto2 = new VerifiableCredentialResponse(expectedCredential, transactionId,expectedCNonce, expectedCNonceExpiresIn); + VerifiableCredentialResponse dto1 = new VerifiableCredentialResponse(expectedCredential, transactionId, expectedCNonce, expectedCNonceExpiresIn); + VerifiableCredentialResponse dto2 = new VerifiableCredentialResponse(expectedCredential, transactionId, expectedCNonce, expectedCNonceExpiresIn); // Assert assertEquals(dto1, dto2); // Tests equals() method generated by Lombok assertEquals(dto1.hashCode(), dto2.hashCode()); // Tests hashCode() method generated by Lombok } -} +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/VerifiableCredentialTest.java b/src/test/java/es/in2/issuer/domain/model/dto/VerifiableCredentialTest.java similarity index 95% rename from src/test/java/es/in2/issuer/domain/model/VerifiableCredentialTest.java rename to src/test/java/es/in2/issuer/domain/model/dto/VerifiableCredentialTest.java index d308e4ca2..8a74c65ec 100644 --- a/src/test/java/es/in2/issuer/domain/model/VerifiableCredentialTest.java +++ b/src/test/java/es/in2/issuer/domain/model/dto/VerifiableCredentialTest.java @@ -1,6 +1,5 @@ -package es.in2.issuer.domain.model; +package es.in2.issuer.domain.model.dto; -import es.in2.issuer.domain.model.dto.VerifiableCredential; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -52,4 +51,4 @@ void lombokGeneratedMethodsTest() { assertEquals(dto1.hashCode(), dto2.hashCode()); // Tests hashCode() method generated by Lombok } -} +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/entities/CredentialProcedureTest.java b/src/test/java/es/in2/issuer/domain/model/entities/CredentialProcedureTest.java new file mode 100644 index 000000000..dcea53b14 --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/model/entities/CredentialProcedureTest.java @@ -0,0 +1,90 @@ +package es.in2.issuer.domain.model.entities; + +import es.in2.issuer.domain.model.enums.CredentialStatus; +import org.junit.jupiter.api.Test; + +import java.sql.Timestamp; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class CredentialProcedureTest { + + @Test + void testCredentialProcedure() { + UUID procedureId = UUID.randomUUID(); + UUID credentialId = UUID.randomUUID(); + String credentialFormat = "testFormat"; + String credentialDecoded = "testDecoded"; + String credentialEncoded = "testEncoded"; + CredentialStatus credentialStatus = CredentialStatus.VALID; + String organizationIdentifier = "testOrganizationIdentifier"; + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); + + CredentialProcedure credentialProcedure = CredentialProcedure.builder() + .procedureId(procedureId) + .credentialId(credentialId) + .credentialFormat(credentialFormat) + .credentialDecoded(credentialDecoded) + .credentialEncoded(credentialEncoded) + .credentialStatus(credentialStatus) + .organizationIdentifier(organizationIdentifier) + .updatedAt(timestamp) + .build(); + + assertEquals(procedureId, credentialProcedure.getProcedureId()); + assertEquals(credentialId, credentialProcedure.getCredentialId()); + assertEquals(credentialFormat, credentialProcedure.getCredentialFormat()); + assertEquals(credentialDecoded, credentialProcedure.getCredentialDecoded()); + assertEquals(credentialEncoded, credentialProcedure.getCredentialEncoded()); + assertEquals(credentialStatus, credentialProcedure.getCredentialStatus()); + assertEquals(organizationIdentifier, credentialProcedure.getOrganizationIdentifier()); + assertEquals(timestamp, credentialProcedure.getUpdatedAt()); + } + + @Test + void testSettersAndGetters() { + CredentialProcedure credentialProcedure = new CredentialProcedure(); + UUID procedureId = UUID.randomUUID(); + UUID credentialId = UUID.randomUUID(); + String credentialFormat = "format"; + String credentialDecoded = "decoded"; + String credentialEncoded = "encoded"; + CredentialStatus credentialStatus = CredentialStatus.VALID; + String organizationIdentifier = "orgId"; + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); + + credentialProcedure.setProcedureId(procedureId); + credentialProcedure.setCredentialId(credentialId); + credentialProcedure.setCredentialFormat(credentialFormat); + credentialProcedure.setCredentialDecoded(credentialDecoded); + credentialProcedure.setCredentialEncoded(credentialEncoded); + credentialProcedure.setCredentialStatus(credentialStatus); + credentialProcedure.setOrganizationIdentifier(organizationIdentifier); + credentialProcedure.setUpdatedAt(timestamp); + + assertEquals(procedureId, credentialProcedure.getProcedureId()); + assertEquals(credentialId, credentialProcedure.getCredentialId()); + assertEquals(credentialFormat, credentialProcedure.getCredentialFormat()); + assertEquals(credentialDecoded, credentialProcedure.getCredentialDecoded()); + assertEquals(credentialEncoded, credentialProcedure.getCredentialEncoded()); + assertEquals(credentialStatus, credentialProcedure.getCredentialStatus()); + assertEquals(organizationIdentifier, credentialProcedure.getOrganizationIdentifier()); + assertEquals(timestamp, credentialProcedure.getUpdatedAt()); + } + + @Test + void testToString() { + CredentialProcedure credentialProcedure = CredentialProcedure.builder().build(); + + String expected = "CredentialProcedure(procedureId=" + credentialProcedure.getProcedureId() + + ", credentialId=" + credentialProcedure.getCredentialId() + + ", credentialFormat=" + credentialProcedure.getCredentialFormat() + + ", credentialDecoded=" + credentialProcedure.getCredentialDecoded() + + ", credentialEncoded=" + credentialProcedure.getCredentialEncoded() + + ", credentialStatus=" + credentialProcedure.getCredentialStatus() + + ", organizationIdentifier=" + credentialProcedure.getOrganizationIdentifier() + + ", updatedAt=" + credentialProcedure.getUpdatedAt() + ")"; + assertEquals(expected, credentialProcedure.toString()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/model/entities/DeferredCredentialMetadataTest.java b/src/test/java/es/in2/issuer/domain/model/entities/DeferredCredentialMetadataTest.java new file mode 100644 index 000000000..eabf971bd --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/model/entities/DeferredCredentialMetadataTest.java @@ -0,0 +1,82 @@ +package es.in2.issuer.domain.model.entities; + +import org.junit.jupiter.api.Test; + +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class DeferredCredentialMetadataTest { + + @Test + void testDeferredCredentialMetadata() { + UUID uuid = UUID.randomUUID(); + String transactionCode = "testTransactionCode"; + String authServerNonce = "testAuthServerNonce"; + String transactionId = "testTransactionId"; + UUID procedureId = UUID.randomUUID(); + String vc = "testVc"; + String vcFormat = "testVcFormat"; + + DeferredCredentialMetadata deferredCredentialMetadata = DeferredCredentialMetadata.builder() + .id(uuid) + .transactionCode(transactionCode) + .authServerNonce(authServerNonce) + .transactionId(transactionId) + .procedureId(procedureId) + .vc(vc) + .vcFormat(vcFormat) + .build(); + + assertEquals(uuid, deferredCredentialMetadata.getId()); + assertEquals(transactionCode, deferredCredentialMetadata.getTransactionCode()); + assertEquals(authServerNonce, deferredCredentialMetadata.getAuthServerNonce()); + assertEquals(transactionId, deferredCredentialMetadata.getTransactionId()); + assertEquals(procedureId, deferredCredentialMetadata.getProcedureId()); + assertEquals(vc, deferredCredentialMetadata.getVc()); + assertEquals(vcFormat, deferredCredentialMetadata.getVcFormat()); + } + + @Test + void testSettersAndGetters() { + DeferredCredentialMetadata deferredCredentialMetadata = new DeferredCredentialMetadata(); + + UUID uuid = UUID.randomUUID(); + String transactionCode = "transactionCode"; + String authServerNonce = "authServerNonce"; + String transactionId = "transactionId"; + UUID procedureId = UUID.randomUUID(); + String vc = "vc"; + String vcFormat = "vcFormat"; + + deferredCredentialMetadata.setId(uuid); + deferredCredentialMetadata.setTransactionCode(transactionCode); + deferredCredentialMetadata.setAuthServerNonce(authServerNonce); + deferredCredentialMetadata.setTransactionId(transactionId); + deferredCredentialMetadata.setProcedureId(procedureId); + deferredCredentialMetadata.setVc(vc); + deferredCredentialMetadata.setVcFormat(vcFormat); + + assertEquals(uuid, deferredCredentialMetadata.getId()); + assertEquals(transactionCode, deferredCredentialMetadata.getTransactionCode()); + assertEquals(authServerNonce, deferredCredentialMetadata.getAuthServerNonce()); + assertEquals(transactionId, deferredCredentialMetadata.getTransactionId()); + assertEquals(procedureId, deferredCredentialMetadata.getProcedureId()); + assertEquals(vc, deferredCredentialMetadata.getVc()); + assertEquals(vcFormat, deferredCredentialMetadata.getVcFormat()); + } + + @Test + void testToString() { + DeferredCredentialMetadata deferredCredentialMetadata = DeferredCredentialMetadata.builder().build(); + + String expected = "DeferredCredentialMetadata(id=" + deferredCredentialMetadata.getId() + + ", transactionCode=" + deferredCredentialMetadata.getTransactionCode() + + ", authServerNonce=" + deferredCredentialMetadata.getAuthServerNonce() + + ", transactionId=" + deferredCredentialMetadata.getTransactionId() + + ", procedureId=" + deferredCredentialMetadata.getProcedureId() + + ", vc=" + deferredCredentialMetadata.getVc() + + ", vcFormat=" + deferredCredentialMetadata.getVcFormat() + ")"; + assertEquals(expected, deferredCredentialMetadata.toString()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/service/AccessTokenServiceImplTest.java b/src/test/java/es/in2/issuer/domain/service/AccessTokenServiceImplTest.java index 95db860cc..41a580cd9 100644 --- a/src/test/java/es/in2/issuer/domain/service/AccessTokenServiceImplTest.java +++ b/src/test/java/es/in2/issuer/domain/service/AccessTokenServiceImplTest.java @@ -2,44 +2,58 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import com.nimbusds.jose.JWSHeader; import com.nimbusds.jose.Payload; +import com.nimbusds.jwt.JWTClaimsSet; import com.nimbusds.jwt.SignedJWT; import es.in2.issuer.domain.exception.InvalidTokenException; import es.in2.issuer.domain.service.impl.AccessTokenServiceImpl; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; import org.mockito.MockedStatic; -import org.mockito.Mockito; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.security.core.context.ReactiveSecurityContextHolder; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextImpl; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; import java.text.ParseException; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; +@ExtendWith(MockitoExtension.class) class AccessTokenServiceImplTest { private static final String BEARER = "Bearer "; - private final AccessTokenServiceImpl service = new AccessTokenServiceImpl(); + + @Mock + private SignedJWT mockSignedJwt; + @InjectMocks + private AccessTokenServiceImpl accessTokenServiceImpl; @Test void testGetCleanBearerToken_Valid() { String validHeader = "Bearer validToken123"; - Mono result = service.getCleanBearerToken(validHeader); + Mono result = accessTokenServiceImpl.getCleanBearerToken(validHeader); StepVerifier.create(result) .expectNext("validToken123") .verifyComplete(); } -// @Test -// void testGetCleanBearerToken_Invalid() { -// String invalidHeader = "invalidToken123"; -// Mono result = service.getCleanBearerToken(invalidHeader); -// StepVerifier.create(result) -// .expectError(InvalidTokenException.class) -// .verify(); -// } + @Test + void testGetCleanBearerToken_Invalid() { + String invalidHeader = "invalidToken123"; + Mono result = accessTokenServiceImpl.getCleanBearerToken(invalidHeader); + StepVerifier.create(result) + .expectNext(invalidHeader) + .verifyComplete(); + } @Test void testGetUserIdFromHeader_Valid() throws Exception { @@ -47,16 +61,16 @@ void testGetUserIdFromHeader_Valid() throws Exception { String expectedUserId = "userId123"; String jwtPayload = "{\"sub\":\"" + expectedUserId + "\"}"; - try (MockedStatic mockedJwtStatic = Mockito.mockStatic(SignedJWT.class)) { - SignedJWT mockSignedJwt = mock(SignedJWT.class); - mockedJwtStatic.when(() -> SignedJWT.parse(anyString())).thenReturn(mockSignedJwt); - when(mockSignedJwt.getPayload()).thenReturn(new Payload(jwtPayload)); + try (MockedStatic mockedJwtStatic = mockStatic(SignedJWT.class)) { + SignedJWT signedJWT = mock(SignedJWT.class); + mockedJwtStatic.when(() -> SignedJWT.parse(anyString())).thenReturn(signedJWT); + when(signedJWT.getPayload()).thenReturn(new Payload(jwtPayload)); ObjectMapper mapper = new ObjectMapper(); JsonNode payloadJson = mapper.readTree(jwtPayload); - when(mockSignedJwt.getPayload()).thenReturn(new Payload(payloadJson.toString())); + when(signedJWT.getPayload()).thenReturn(new Payload(payloadJson.toString())); - Mono result = service.getUserId(validHeader); + Mono result = accessTokenServiceImpl.getUserId(validHeader); StepVerifier.create(result) .expectNext(expectedUserId) @@ -68,15 +82,123 @@ void testGetUserIdFromHeader_Valid() throws Exception { void testGetUserIdFromHeader_ThrowsParseException() { String invalidHeader = "Bearer invalidToken"; - try (MockedStatic mockedJwtStatic = Mockito.mockStatic(SignedJWT.class)) { + try (MockedStatic mockedJwtStatic = mockStatic(SignedJWT.class)) { mockedJwtStatic.when(() -> SignedJWT.parse(anyString())) .thenThrow(new ParseException("Invalid token", 0)); - Mono result = service.getUserId(invalidHeader); + Mono result = accessTokenServiceImpl.getUserId(invalidHeader); + + StepVerifier.create(result) + .expectError(ParseException.class) + .verify(); + } + } + + @Test + void testGetOrganizationId_ValidToken() { + String validJwtToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdhbml6YXRpb25JZGVudGlmaWVyIjoib3JnMTIzIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; + String expectedOrganizationId = "org123"; + String jwtPayload = "{\"organizationIdentifier\":\"" + expectedOrganizationId + "\"}"; + + try (MockedStatic mockedJwtStatic = mockStatic(SignedJWT.class)) { + mockedJwtStatic.when(() -> SignedJWT.parse(anyString())).thenReturn(mockSignedJwt); + when(mockSignedJwt.getPayload()).thenReturn(new Payload(jwtPayload)); + + Mono result = accessTokenServiceImpl.getOrganizationId("Bearer " + validJwtToken); + + StepVerifier.create(result) + .expectNext(expectedOrganizationId) + .verifyComplete(); + } + } + + @Test + void testGetOrganizationId_InvalidToken() { + String invalidJwtToken = "invalid-jwt-token"; + + try (MockedStatic mockedJwtStatic = mockStatic(SignedJWT.class)) { + mockedJwtStatic.when(() -> SignedJWT.parse(anyString())).thenThrow(new ParseException("Invalid token", 0)); + + Mono result = accessTokenServiceImpl.getOrganizationId("Bearer " + invalidJwtToken); + + StepVerifier.create(result) + .expectError(ParseException.class) + .verify(); + } + } + + @Test + void testGetOrganizationIdFromCurrentSession_ValidToken() throws ParseException { + String validJwtToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJvcmdhbml6YXRpb25JZGVudGlmaWVyIjoib3JnMTIzIn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; + String expectedOrganizationId = "org123"; + String jwtPayload = "{\"organizationIdentifier\":\"" + expectedOrganizationId + "\"}"; + + Jwt jwt = Jwt.withTokenValue(validJwtToken).header("alg", "HS256").claim("organizationIdentifier", expectedOrganizationId).build(); + JwtAuthenticationToken jwtAuthenticationToken = new JwtAuthenticationToken(jwt); + SecurityContext securityContext = new SecurityContextImpl(jwtAuthenticationToken); + + try (MockedStatic mockedContextHolder = mockStatic(ReactiveSecurityContextHolder.class); + MockedStatic mockedJwtStatic = mockStatic(SignedJWT.class)) { + + mockedContextHolder.when(ReactiveSecurityContextHolder::getContext) + .thenReturn(Mono.just(securityContext)); + + // Create a JWSHeader and JWTClaimsSet from the payload + JWSHeader jwsHeader = new JWSHeader.Builder(JWSHeader.parse("{\"alg\":\"HS256\"}")).build(); + JWTClaimsSet jwtClaimsSet = JWTClaimsSet.parse(jwtPayload); + SignedJWT signedJWT = new SignedJWT(jwsHeader, jwtClaimsSet); + + mockedJwtStatic.when(() -> SignedJWT.parse(validJwtToken)).thenReturn(signedJWT); + + Mono result = accessTokenServiceImpl.getOrganizationIdFromCurrentSession(); + + StepVerifier.create(result) + .expectNext(expectedOrganizationId) + .verifyComplete(); + } + } + + @Test + void testGetOrganizationIdFromCurrentSession_InvalidToken() { + String invalidJwtToken = "invalid-jwt-token"; + + // Creamos un JWT con una reclamación mínima + Jwt jwt = Jwt.withTokenValue(invalidJwtToken) + .header("alg", "none") + .claim("sub", "subject") + .build(); + + JwtAuthenticationToken jwtAuthenticationToken = new JwtAuthenticationToken(jwt); + SecurityContext securityContext = new SecurityContextImpl(jwtAuthenticationToken); + + try (MockedStatic mockedContextHolder = mockStatic(ReactiveSecurityContextHolder.class); + MockedStatic mockedJwtStatic = mockStatic(SignedJWT.class)) { + + mockedContextHolder.when(ReactiveSecurityContextHolder::getContext) + .thenReturn(Mono.just(securityContext)); + + mockedJwtStatic.when(() -> SignedJWT.parse(invalidJwtToken)).thenThrow(new ParseException("Invalid token", 0)); + + Mono result = accessTokenServiceImpl.getOrganizationIdFromCurrentSession(); StepVerifier.create(result) .expectError(ParseException.class) .verify(); } } + + + @Test + void testGetOrganizationIdFromCurrentSession_EmptyToken() { + try (MockedStatic mockedContextHolder = mockStatic(ReactiveSecurityContextHolder.class)) { + mockedContextHolder.when(ReactiveSecurityContextHolder::getContext) + .thenReturn(Mono.empty()); + + Mono result = accessTokenServiceImpl.getOrganizationIdFromCurrentSession(); + + StepVerifier.create(result) + .expectError(InvalidTokenException.class) + .verify(); + } + } } \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/service/CredentialIssuerMetadataServiceImplTest.java b/src/test/java/es/in2/issuer/domain/service/CredentialIssuerMetadataServiceImplTest.java index 61d0fcf39..1b82882f4 100644 --- a/src/test/java/es/in2/issuer/domain/service/CredentialIssuerMetadataServiceImplTest.java +++ b/src/test/java/es/in2/issuer/domain/service/CredentialIssuerMetadataServiceImplTest.java @@ -1,52 +1,63 @@ -//package es.in2.issuer.domain.service; -// -//import es.in2.issuer.domain.service.impl.CredentialIssuerMetadataServiceImpl; -//import es.in2.issuer.domain.util.HttpUtils; -//import es.in2.issuer.infrastructure.config.AppConfig; -//import org.junit.jupiter.api.Test; -//import org.junit.jupiter.api.extension.ExtendWith; -//import org.mockito.InjectMocks; -//import org.mockito.Mock; -//import org.mockito.MockedStatic; -//import org.mockito.Mockito; -//import org.mockito.junit.jupiter.MockitoExtension; -//import reactor.test.StepVerifier; -// -//import static es.in2.issuer.domain.util.HttpUtils.ensureUrlHasProtocol; -//import static org.junit.jupiter.api.Assertions.assertEquals; -//import static org.junit.jupiter.api.Assertions.assertNotNull; -//import static org.mockito.Mockito.verify; -//import static org.mockito.Mockito.when; -// -//@ExtendWith(MockitoExtension.class) -//class CredentialIssuerMetadataServiceImplTest { -// -// @Mock -// private AppConfig appConfig; -// -// @InjectMocks -// private CredentialIssuerMetadataServiceImpl service; -// -// @Test -// void testGenerateOpenIdCredentialIssuer() { -// try (MockedStatic ignored = Mockito.mockStatic(HttpUtils.class)) { -// String issuerUrl = "https://example.com"; -// -// when(appConfig.getIssuerApiExternalDomain()).thenReturn(issuerUrl); -// when(ensureUrlHasProtocol(issuerUrl)).thenReturn(issuerUrl); -// // Verify results -// StepVerifier.create(service.generateOpenIdCredentialIssuer()) -// .assertNext(metadata -> { -// assertEquals("https://example.com", metadata.credentialIssuer()); -// assertEquals("https://example.com/api/v1/vc/credential", metadata.credentialEndpoint()); -// assertEquals("https://example.com/api/v1/vc/batch_credential", metadata.batchCredentialEndpoint()); -// assertNotNull(metadata.credentialConfigurationsSupported()); -// }) -// .verifyComplete(); -// -// // Verify interactions -// verify(appConfig).getIssuerApiExternalDomain(); -// } -// } -// -//} +package es.in2.issuer.domain.service; + +import es.in2.issuer.domain.model.dto.CredentialConfiguration; +import es.in2.issuer.domain.model.dto.CredentialDefinition; +import es.in2.issuer.domain.model.dto.CredentialIssuerMetadata; +import es.in2.issuer.domain.service.impl.CredentialIssuerMetadataServiceImpl; +import es.in2.issuer.domain.util.Constants; +import es.in2.issuer.domain.util.EndpointsConstants; +import es.in2.issuer.infrastructure.config.AppConfig; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.lenient; + +@ExtendWith(MockitoExtension.class) +class CredentialIssuerMetadataServiceImplTest { + + private final String issuerApiExternalDomain = "http://example.com"; + + @Mock + private AppConfig appConfig; + + @InjectMocks + private CredentialIssuerMetadataServiceImpl credentialIssuerMetadataService; + + @BeforeEach + void setup() { + lenient().when(appConfig.getIssuerApiExternalDomain()).thenReturn(issuerApiExternalDomain); + } + + @Test + void testGenerateOpenIdCredentialIssuer() { + Mono credentialIssuerMetadataMono = credentialIssuerMetadataService.generateOpenIdCredentialIssuer(); + + StepVerifier.create(credentialIssuerMetadataMono) + .assertNext(metadata -> { + assertEquals(issuerApiExternalDomain, metadata.credentialIssuer(), "Credential Issuer"); + assertEquals(issuerApiExternalDomain + EndpointsConstants.CREDENTIAL, metadata.credentialEndpoint(), "Credential Endpoint"); + assertEquals(issuerApiExternalDomain + EndpointsConstants.CREDENTIAL_BATCH, metadata.batchCredentialEndpoint(), "Batch Credential Endpoint"); + assertEquals(issuerApiExternalDomain + EndpointsConstants.CREDENTIAL_DEFERRED, metadata.deferredCredentialEndpoint(), "Deferred Credential Endpoint"); + + CredentialConfiguration config = metadata.credentialConfigurationsSupported().get(Constants.LEAR_CREDENTIAL_EMPLOYEE); + assertNotNull(config); + assertEquals(Constants.JWT_VC_JSON, config.format(), "Format"); + assertTrue(config.cryptographicBindingMethodsSupported().isEmpty(), "Cryptographic Binding Methods Supported"); + assertTrue(config.credentialSigningAlgValuesSupported().isEmpty(), "Credential Signing Alg Values Supported"); + + CredentialDefinition definition = config.credentialDefinition(); + assertNotNull(definition); + assertEquals(List.of(Constants.LEAR_CREDENTIAL, Constants.VERIFIABLE_CREDENTIAL), definition.type(), "Credential Definition Types"); + }) + .verifyComplete(); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/service/CredentialOfferCacheStorageServiceImplTest.java b/src/test/java/es/in2/issuer/domain/service/CredentialOfferCacheStorageServiceImplTest.java index c49c06d73..0c99a5ee0 100644 --- a/src/test/java/es/in2/issuer/domain/service/CredentialOfferCacheStorageServiceImplTest.java +++ b/src/test/java/es/in2/issuer/domain/service/CredentialOfferCacheStorageServiceImplTest.java @@ -4,11 +4,11 @@ import es.in2.issuer.domain.model.dto.CustomCredentialOffer; import es.in2.issuer.domain.service.impl.CredentialOfferCacheStorageServiceImpl; import es.in2.issuer.infrastructure.repository.CacheStore; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.jupiter.MockitoExtension; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; @@ -17,6 +17,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.*; +@ExtendWith(MockitoExtension.class) class CredentialOfferCacheStorageServiceImplTest { @Mock @@ -25,11 +26,6 @@ class CredentialOfferCacheStorageServiceImplTest { @InjectMocks private CredentialOfferCacheStorageServiceImpl service; - @BeforeEach - void setUp() { - MockitoAnnotations.openMocks(this); - } - @Test void testSaveCustomCredentialOffer() { CustomCredentialOffer offer = CustomCredentialOffer.builder().build(); // You should populate it as necessary diff --git a/src/test/java/es/in2/issuer/domain/service/CredentialProcedureServiceImplTest.java b/src/test/java/es/in2/issuer/domain/service/CredentialProcedureServiceImplTest.java new file mode 100644 index 000000000..89cc22418 --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/service/CredentialProcedureServiceImplTest.java @@ -0,0 +1,633 @@ +package es.in2.issuer.domain.service; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import es.in2.issuer.domain.model.dto.CredentialDetails; +import es.in2.issuer.domain.model.dto.CredentialProcedureCreationRequest; +import es.in2.issuer.domain.model.dto.CredentialProcedures; +import es.in2.issuer.domain.model.entities.CredentialProcedure; +import es.in2.issuer.domain.model.enums.CredentialStatus; +import es.in2.issuer.domain.service.impl.CredentialProcedureServiceImpl; +import es.in2.issuer.infrastructure.repository.CredentialProcedureRepository; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.sql.Timestamp; +import java.time.Instant; +import java.util.List; +import java.util.UUID; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class CredentialProcedureServiceImplTest { + + @Mock + private CredentialProcedureRepository credentialProcedureRepository; + + @InjectMocks + private CredentialProcedureServiceImpl credentialProcedureService; + + @Mock + private ObjectMapper objectMapper; + + @Test + void createCredentialProcedure_shouldSaveProcedureAndReturnProcedureId() { + // Given + String credentialId = UUID.randomUUID().toString(); + String organizationIdentifier = "org-123"; + String credentialDecoded = "{\"vc\":{\"type\":[\"VerifiableCredential\"]}}"; + String expectedProcedureId = UUID.randomUUID().toString(); + + CredentialProcedureCreationRequest request = CredentialProcedureCreationRequest.builder() + .credentialId(credentialId) + .organizationIdentifier(organizationIdentifier) + .credentialDecoded(credentialDecoded) + .build(); + + CredentialProcedure savedCredentialProcedure = CredentialProcedure.builder() + .procedureId(UUID.fromString(expectedProcedureId)) + .credentialId(UUID.fromString(credentialId)) + .credentialStatus(CredentialStatus.WITHDRAWN) + .credentialDecoded(credentialDecoded) + .organizationIdentifier(organizationIdentifier) + .updatedAt(new Timestamp(Instant.now().toEpochMilli())) + .build(); + + // When + when(credentialProcedureRepository.save(any(CredentialProcedure.class))) + .thenReturn(Mono.just(savedCredentialProcedure)); + + // Execute + Mono result = credentialProcedureService.createCredentialProcedure(request); + + // Then + StepVerifier.create(result) + .expectNext(expectedProcedureId) + .verifyComplete(); + } + + @Test + void getCredentialTypeByProcedureId_shouldReturnNonDefaultType() throws Exception { + // Given + String procedureId = UUID.randomUUID().toString(); + String credentialDecoded = "{\"vc\":{\"type\":[\"VerifiableCredential\", \"TestType\"]}}"; + + CredentialProcedure credentialProcedure = new CredentialProcedure(); + credentialProcedure.setProcedureId(UUID.fromString(procedureId)); + credentialProcedure.setCredentialDecoded(credentialDecoded); + + JsonNode credentialNode = new ObjectMapper().readTree(credentialDecoded); + + // When + when(credentialProcedureRepository.findById(any(UUID.class))) + .thenReturn(Mono.just(credentialProcedure)); + when(objectMapper.readTree(credentialDecoded)) + .thenReturn(credentialNode); + + // Execute + Mono result = credentialProcedureService.getCredentialTypeByProcedureId(procedureId); + + // Then + StepVerifier.create(result) + .expectNext("TestType") + .verifyComplete(); + } + + @Test + void getCredentialTypeByProcedureId_shouldReturnEmptyIfOnlyDefaultTypesPresent() throws Exception { + // Given + String procedureId = UUID.randomUUID().toString(); + String credentialDecoded = "{\"vc\":{\"type\":[\"VerifiableCredential\", \"VerifiableAttestation\"]}}"; + + CredentialProcedure credentialProcedure = new CredentialProcedure(); + credentialProcedure.setProcedureId(UUID.fromString(procedureId)); + credentialProcedure.setCredentialDecoded(credentialDecoded); + + JsonNode credentialNode = new ObjectMapper().readTree(credentialDecoded); + + // When + when(credentialProcedureRepository.findById(any(UUID.class))) + .thenReturn(Mono.just(credentialProcedure)); + when(objectMapper.readTree(credentialDecoded)) + .thenReturn(credentialNode); + + // Execute + Mono result = credentialProcedureService.getCredentialTypeByProcedureId(procedureId); + + // Then + StepVerifier.create(result) + .expectNextCount(0) + .verifyComplete(); + } + + @Test + void getCredentialTypeByProcedureId_shouldReturnErrorIfTypeMissing() throws Exception { + // Given + String procedureId = UUID.randomUUID().toString(); + String credentialDecoded = "{\"vc\":{}}"; + + CredentialProcedure credentialProcedure = new CredentialProcedure(); + credentialProcedure.setProcedureId(UUID.fromString(procedureId)); + credentialProcedure.setCredentialDecoded(credentialDecoded); + + JsonNode credentialNode = new ObjectMapper().readTree(credentialDecoded); + + // When + when(credentialProcedureRepository.findById(any(UUID.class))) + .thenReturn(Mono.just(credentialProcedure)); + when(objectMapper.readTree(credentialDecoded)) + .thenReturn(credentialNode); + + // Execute + Mono result = credentialProcedureService.getCredentialTypeByProcedureId(procedureId); + + // Then + StepVerifier.create(result) + .expectErrorMatches(throwable -> throwable instanceof RuntimeException && + throwable.getMessage().equals("The credential type is missing")) + .verify(); + } + + @Test + void getCredentialTypeByProcedureId_shouldReturnErrorIfJsonProcessingExceptionOccurs() throws Exception { + // Given + String procedureId = UUID.randomUUID().toString(); + String invalidCredentialDecoded = "{\"vc\":{\"type\":[\"VerifiableCredential\", \"TestType\"}"; // Invalid JSON + + CredentialProcedure credentialProcedure = new CredentialProcedure(); + credentialProcedure.setProcedureId(UUID.fromString(procedureId)); + credentialProcedure.setCredentialDecoded(invalidCredentialDecoded); + + // When + when(credentialProcedureRepository.findById(any(UUID.class))) + .thenReturn(Mono.just(credentialProcedure)); + when(objectMapper.readTree(invalidCredentialDecoded)) + .thenThrow(new RuntimeException("Invalid JSON")); + + // Execute + Mono result = credentialProcedureService.getCredentialTypeByProcedureId(procedureId); + + // Then + StepVerifier.create(result) + .expectErrorMatches(throwable -> throwable instanceof RuntimeException) + .verify(); + } + + @Test + void updateDecodedCredentialByProcedureId_shouldUpdateAndSaveCredentialProcedure() { + // Given + String procedureId = UUID.randomUUID().toString(); + String newCredential = "{\"vc\":{\"type\":[\"NewCredentialType\"]}}"; + String newFormat = "json"; + + CredentialProcedure existingCredentialProcedure = new CredentialProcedure(); + existingCredentialProcedure.setProcedureId(UUID.fromString(procedureId)); + existingCredentialProcedure.setCredentialDecoded("{\"vc\":{\"type\":[\"OldCredentialType\"]}}"); + existingCredentialProcedure.setCredentialStatus(CredentialStatus.WITHDRAWN); + existingCredentialProcedure.setCredentialFormat("old_format"); + existingCredentialProcedure.setUpdatedAt(new Timestamp(Instant.now().toEpochMilli())); + + // When + when(credentialProcedureRepository.findById(any(UUID.class))) + .thenReturn(Mono.just(existingCredentialProcedure)); + when(credentialProcedureRepository.save(any(CredentialProcedure.class))) + .thenReturn(Mono.just(existingCredentialProcedure)); + + // Execute + Mono result = credentialProcedureService.updateDecodedCredentialByProcedureId(procedureId, newCredential, newFormat); + + // Then + StepVerifier.create(result) + .verifyComplete(); + + verify(credentialProcedureRepository, times(1)).findById(UUID.fromString(procedureId)); + verify(credentialProcedureRepository, times(1)).save(existingCredentialProcedure); + + assert existingCredentialProcedure.getCredentialDecoded().equals(newCredential); + assert existingCredentialProcedure.getCredentialFormat().equals(newFormat); + assert existingCredentialProcedure.getCredentialStatus() == CredentialStatus.ISSUED; + assert existingCredentialProcedure.getUpdatedAt().before(new Timestamp(Instant.now().toEpochMilli() + 1000)); // Ensures the updated timestamp is recent + } + + @Test + void updateDecodedCredentialByProcedureId_shouldHandleProcedureNotFound() { + // Given + String procedureId = UUID.randomUUID().toString(); + String newCredential = "{\"vc\":{\"type\":[\"NewCredentialType\"]}}"; + String newFormat = "json"; + + // When + when(credentialProcedureRepository.findById(any(UUID.class))) + .thenReturn(Mono.empty()); + + // Execute + Mono result = credentialProcedureService.updateDecodedCredentialByProcedureId(procedureId, newCredential, newFormat); + + // Then + StepVerifier.create(result) + .verifyComplete(); + + verify(credentialProcedureRepository, times(1)).findById(UUID.fromString(procedureId)); + verify(credentialProcedureRepository, times(0)).save(any(CredentialProcedure.class)); + } + + @Test + void getDecodedCredentialByProcedureId_shouldReturnDecodedCredential() { + // Given + String procedureId = UUID.randomUUID().toString(); + String expectedDecodedCredential = "{\"vc\":{\"type\":[\"TestCredentialType\"]}}"; + + CredentialProcedure credentialProcedure = new CredentialProcedure(); + credentialProcedure.setProcedureId(UUID.fromString(procedureId)); + credentialProcedure.setCredentialDecoded(expectedDecodedCredential); + + // When + when(credentialProcedureRepository.findById(any(UUID.class))) + .thenReturn(Mono.just(credentialProcedure)); + + // Execute + Mono result = credentialProcedureService.getDecodedCredentialByProcedureId(procedureId); + + // Then + StepVerifier.create(result) + .expectNext(expectedDecodedCredential) + .verifyComplete(); + } + + @Test + void getCredentialStatusByProcedureId_shouldReturnCredentialStatus() { + // Given + String procedureId = UUID.randomUUID().toString(); + CredentialStatus expectedStatus = CredentialStatus.ISSUED; + + // When + when(credentialProcedureRepository.findCredentialStatusByProcedureId(any(UUID.class))) + .thenReturn(Mono.just(expectedStatus.name())); + + // Execute + Mono result = credentialProcedureService.getCredentialStatusByProcedureId(procedureId); + + // Then + StepVerifier.create(result) + .expectNext(expectedStatus.name()) + .verifyComplete(); + } + + @Test + void getMandateeEmailFromDecodedCredentialByProcedureId_shouldReturnMandateeEmail() throws Exception { + // Given + String procedureId = UUID.randomUUID().toString(); + String expectedEmail = "mandatee@example.com"; + String credentialDecoded = "{\"vc\":{\"credentialSubject\":{\"mandate\":{\"mandatee\":{\"email\":\"" + expectedEmail + "\"}}}}}"; + + CredentialProcedure credentialProcedure = new CredentialProcedure(); + credentialProcedure.setProcedureId(UUID.fromString(procedureId)); + credentialProcedure.setCredentialDecoded(credentialDecoded); + + JsonNode credentialNode = new ObjectMapper().readTree(credentialDecoded); + + // When + when(credentialProcedureRepository.findById(any(UUID.class))) + .thenReturn(Mono.just(credentialProcedure)); + when(objectMapper.readTree(credentialDecoded)) + .thenReturn(credentialNode); + + // Execute + Mono result = credentialProcedureService.getMandateeEmailFromDecodedCredentialByProcedureId(procedureId); + + // Then + StepVerifier.create(result) + .expectNext(expectedEmail) + .verifyComplete(); + } + + @Test + void getMandateeFirstNameFromDecodedCredentialByProcedureId_shouldReturnMandateeFirstName() throws Exception { + // Given + String procedureId = UUID.randomUUID().toString(); + String expectedFirstName = "John"; + String credentialDecoded = "{\"vc\":{\"credentialSubject\":{\"mandate\":{\"mandatee\":{\"first_name\":\"" + expectedFirstName + "\"}}}}}"; + + CredentialProcedure credentialProcedure = new CredentialProcedure(); + credentialProcedure.setProcedureId(UUID.fromString(procedureId)); + credentialProcedure.setCredentialDecoded(credentialDecoded); + + JsonNode credentialNode = new ObjectMapper().readTree(credentialDecoded); + + // When + when(credentialProcedureRepository.findById(any(UUID.class))) + .thenReturn(Mono.just(credentialProcedure)); + when(objectMapper.readTree(credentialDecoded)) + .thenReturn(credentialNode); + + // Execute + Mono result = credentialProcedureService.getMandateeFirstNameFromDecodedCredentialByProcedureId(procedureId); + + // Then + StepVerifier.create(result) + .expectNext(expectedFirstName) + .verifyComplete(); + } + + @Test + void getMandatorEmailFromDecodedCredentialByProcedureId_shouldReturnMandatorEmail() throws Exception { + // Given + String procedureId = UUID.randomUUID().toString(); + String expectedEmail = "mandator@example.com"; + String credentialDecoded = "{\"vc\":{\"credentialSubject\":{\"mandate\":{\"mandator\":{\"emailAddress\":\"" + expectedEmail + "\"}}}}}"; + + CredentialProcedure credentialProcedure = new CredentialProcedure(); + credentialProcedure.setProcedureId(UUID.fromString(procedureId)); + credentialProcedure.setCredentialDecoded(credentialDecoded); + + JsonNode credentialNode = new ObjectMapper().readTree(credentialDecoded); + + // When + when(credentialProcedureRepository.findById(any(UUID.class))) + .thenReturn(Mono.just(credentialProcedure)); + when(objectMapper.readTree(credentialDecoded)) + .thenReturn(credentialNode); + + // Execute + Mono result = credentialProcedureService.getMandatorEmailFromDecodedCredentialByProcedureId(procedureId); + + // Then + StepVerifier.create(result) + .expectNext(expectedEmail) + .verifyComplete(); + } + + @Test + void getAllIssuedCredentialByOrganizationIdentifier_shouldReturnAllIssuedCredentials() { + // Given + String organizationIdentifier = "org-123"; + String credential1Decoded = "{\"vc\":{\"type\":[\"TestCredentialType1\"]}}"; + String credential2Decoded = "{\"vc\":{\"type\":[\"TestCredentialType2\"]}}"; + + CredentialProcedure credentialProcedure1 = new CredentialProcedure(); + credentialProcedure1.setCredentialDecoded(credential1Decoded); + credentialProcedure1.setCredentialStatus(CredentialStatus.ISSUED); + credentialProcedure1.setOrganizationIdentifier(organizationIdentifier); + + CredentialProcedure credentialProcedure2 = new CredentialProcedure(); + credentialProcedure2.setCredentialDecoded(credential2Decoded); + credentialProcedure2.setCredentialStatus(CredentialStatus.ISSUED); + credentialProcedure2.setOrganizationIdentifier(organizationIdentifier); + + List issuedCredentials = List.of(credentialProcedure1, credentialProcedure2); + + // When + when(credentialProcedureRepository.findByCredentialStatusAndOrganizationIdentifier( + CredentialStatus.ISSUED, organizationIdentifier)) + .thenReturn(Flux.fromIterable(issuedCredentials)); + + // Execute + Flux result = credentialProcedureService.getAllIssuedCredentialByOrganizationIdentifier(organizationIdentifier); + + // Then + StepVerifier.create(result) + .expectNext(credential1Decoded) + .expectNext(credential2Decoded) + .verifyComplete(); + } + + @Test + void getAllIssuedCredentialByOrganizationIdentifier_shouldHandleNoIssuedCredentialsFound() { + // Given + String organizationIdentifier = "org-456"; + + // When + when(credentialProcedureRepository.findByCredentialStatusAndOrganizationIdentifier( + CredentialStatus.ISSUED, organizationIdentifier)) + .thenReturn(Flux.empty()); + + // Execute + Flux result = credentialProcedureService.getAllIssuedCredentialByOrganizationIdentifier(organizationIdentifier); + + // Then + StepVerifier.create(result) + .expectNextCount(0) + .verifyComplete(); + } + + @Test + void getProcedureDetailByProcedureIdAndOrganizationId_shouldReturnCredentialDetails() throws Exception { + // Given + String procedureId = UUID.randomUUID().toString(); + String organizationIdentifier = "org-123"; + String credentialDecoded = "{\"vc\":{\"type\":[\"TestCredentialType\"]}}"; + UUID expectedProcedureId = UUID.fromString(procedureId); + CredentialStatus status = CredentialStatus.ISSUED; + + CredentialProcedure credentialProcedure = new CredentialProcedure(); + credentialProcedure.setProcedureId(expectedProcedureId); + credentialProcedure.setCredentialDecoded(credentialDecoded); + credentialProcedure.setCredentialStatus(status); + credentialProcedure.setOrganizationIdentifier(organizationIdentifier); + + JsonNode credentialNode = new ObjectMapper().readTree(credentialDecoded); + + // When + when(credentialProcedureRepository.findByProcedureIdAndOrganizationIdentifier(any(UUID.class), any(String.class))) + .thenReturn(Mono.just(credentialProcedure)); + when(objectMapper.readTree(credentialDecoded)) + .thenReturn(credentialNode); + + // Execute + Mono result = credentialProcedureService.getProcedureDetailByProcedureIdAndOrganizationId(organizationIdentifier, procedureId); + + // Then + StepVerifier.create(result) + .expectNextMatches(details -> + details.procedureId().equals(expectedProcedureId) && + details.credentialStatus().equals(status.name()) && + details.credential().equals(credentialNode)) + .verifyComplete(); + } + + @Test + void getProcedureDetailByProcedureIdAndOrganizationId_shouldHandleJsonProcessingException() throws Exception { + // Given + String procedureId = UUID.randomUUID().toString(); + String organizationIdentifier = "org-123"; + String invalidCredentialDecoded = "{\"vc\":{\"type\":[\"TestCredentialType\"}"; // Malformed JSON + + CredentialProcedure credentialProcedure = new CredentialProcedure(); + credentialProcedure.setProcedureId(UUID.fromString(procedureId)); + credentialProcedure.setCredentialDecoded(invalidCredentialDecoded); + credentialProcedure.setOrganizationIdentifier(organizationIdentifier); + + // When + when(credentialProcedureRepository.findByProcedureIdAndOrganizationIdentifier(any(UUID.class), any(String.class))) + .thenReturn(Mono.just(credentialProcedure)); + when(objectMapper.readTree(invalidCredentialDecoded)) + .thenThrow(new JsonParseException(null, "Error parsing credential")); + + // Execute + Mono result = credentialProcedureService.getProcedureDetailByProcedureIdAndOrganizationId(organizationIdentifier, procedureId); + + // Then + StepVerifier.create(result) + .expectErrorMatches(throwable -> throwable instanceof JsonParseException) + .verify(); + } + + @Test + void updatedEncodedCredentialByCredentialId_shouldUpdateAndReturnProcedureId() { + // Given + String credentialId = UUID.randomUUID().toString(); + String newEncodedCredential = "newEncodedCredential"; + UUID procedureId = UUID.randomUUID(); + + CredentialProcedure existingCredentialProcedure = new CredentialProcedure(); + existingCredentialProcedure.setProcedureId(procedureId); + existingCredentialProcedure.setCredentialId(UUID.fromString(credentialId)); + existingCredentialProcedure.setCredentialEncoded("oldEncodedCredential"); + existingCredentialProcedure.setCredentialStatus(CredentialStatus.ISSUED); + + // When + when(credentialProcedureRepository.findByCredentialId(any(UUID.class))) + .thenReturn(Mono.just(existingCredentialProcedure)); + when(credentialProcedureRepository.save(any(CredentialProcedure.class))) + .thenReturn(Mono.just(existingCredentialProcedure)); + + // Execute + Mono result = credentialProcedureService.updatedEncodedCredentialByCredentialId(newEncodedCredential, credentialId); + + // Then + StepVerifier.create(result) + .expectNext(procedureId.toString()) + .verifyComplete(); + + verify(credentialProcedureRepository, times(1)).findByCredentialId(UUID.fromString(credentialId)); + verify(credentialProcedureRepository, times(1)).save(existingCredentialProcedure); + + assert existingCredentialProcedure.getCredentialEncoded().equals(newEncodedCredential); + assert existingCredentialProcedure.getCredentialStatus() == CredentialStatus.PEND_DOWNLOAD; + } + + @Test + void updateCredentialProcedureCredentialStatusToValidByProcedureId_shouldUpdateStatusToValid() { + // Given + String procedureId = UUID.randomUUID().toString(); + UUID uuidProcedureId = UUID.fromString(procedureId); + + CredentialProcedure existingCredentialProcedure = new CredentialProcedure(); + existingCredentialProcedure.setProcedureId(uuidProcedureId); + existingCredentialProcedure.setCredentialStatus(CredentialStatus.ISSUED); + + // When + when(credentialProcedureRepository.findByProcedureId(any(UUID.class))) + .thenReturn(Mono.just(existingCredentialProcedure)); + when(credentialProcedureRepository.save(any(CredentialProcedure.class))) + .thenReturn(Mono.just(existingCredentialProcedure)); + + // Execute + Mono result = credentialProcedureService.updateCredentialProcedureCredentialStatusToValidByProcedureId(procedureId); + + // Then + StepVerifier.create(result) + .verifyComplete(); + + verify(credentialProcedureRepository, times(1)).findByProcedureId(uuidProcedureId); + verify(credentialProcedureRepository, times(1)).save(existingCredentialProcedure); + + assert existingCredentialProcedure.getCredentialStatus() == CredentialStatus.VALID; + } + + @Test + void getAllProceduresBasicInfoByOrganizationId_shouldReturnBasicInfoForAllProcedures() throws Exception { + // Given + String organizationIdentifier = "org-123"; + String credentialDecoded1 = "{\"vc\":{\"credentialSubject\":{\"mandate\":{\"mandatee\":{\"first_name\":\"John\", \"last_name\":\"Doe\"}}}}}"; + String credentialDecoded2 = "{\"vc\":{\"credentialSubject\":{\"mandate\":{\"mandatee\":{\"first_name\":\"Jane\", \"last_name\":\"Smith\"}}}}}"; + + UUID procedureId1 = UUID.randomUUID(); + UUID procedureId2 = UUID.randomUUID(); + Timestamp updated1 = Timestamp.from(Instant.now()); + Timestamp updated2 = Timestamp.from(Instant.now().minusSeconds(3600)); + + CredentialProcedure credentialProcedure1 = new CredentialProcedure(); + credentialProcedure1.setProcedureId(procedureId1); + credentialProcedure1.setCredentialDecoded(credentialDecoded1); + credentialProcedure1.setCredentialStatus(CredentialStatus.ISSUED); + credentialProcedure1.setOrganizationIdentifier(organizationIdentifier); + credentialProcedure1.setUpdatedAt(updated1); + + CredentialProcedure credentialProcedure2 = new CredentialProcedure(); + credentialProcedure2.setProcedureId(procedureId2); + credentialProcedure2.setCredentialDecoded(credentialDecoded2); + credentialProcedure2.setCredentialStatus(CredentialStatus.WITHDRAWN); + credentialProcedure2.setOrganizationIdentifier(organizationIdentifier); + credentialProcedure2.setUpdatedAt(updated2); + + List procedures = List.of(credentialProcedure1, credentialProcedure2); + + JsonNode credentialNode1 = new ObjectMapper().readTree(credentialDecoded1); + JsonNode credentialNode2 = new ObjectMapper().readTree(credentialDecoded2); + + // When + when(credentialProcedureRepository.findAllByOrganizationIdentifier(any(String.class))) + .thenReturn(Flux.fromIterable(procedures)); + when(objectMapper.readTree(credentialDecoded1)).thenReturn(credentialNode1); + when(objectMapper.readTree(credentialDecoded2)).thenReturn(credentialNode2); + + // Execute + Mono result = credentialProcedureService.getAllProceduresBasicInfoByOrganizationId(organizationIdentifier); + + // Then + StepVerifier.create(result) + .expectNextMatches(credentialProcedures -> { + List credentialProcedureList = credentialProcedures.credentialProcedures(); + return credentialProcedureList.size() == 2 && + credentialProcedureList.get(0).credentialProcedure().procedureId().equals(procedureId1) && + credentialProcedureList.get(0).credentialProcedure().fullName().equals("John Doe") && + credentialProcedureList.get(0).credentialProcedure().status().equals(CredentialStatus.ISSUED.name()) && + credentialProcedureList.get(0).credentialProcedure().updated().equals(updated1) && + credentialProcedureList.get(1).credentialProcedure().procedureId().equals(procedureId2) && + credentialProcedureList.get(1).credentialProcedure().fullName().equals("Jane Smith") && + credentialProcedureList.get(1).credentialProcedure().status().equals(CredentialStatus.WITHDRAWN.name()) && + credentialProcedureList.get(1).credentialProcedure().updated().equals(updated2); + }) + .verifyComplete(); + } + + @Test + void getAllProceduresBasicInfoByOrganizationId_shouldHandleJsonProcessingException() throws Exception { + // Given + String organizationIdentifier = "org-123"; + String malformedJson = "{\"vc\":{\"credentialSubject\":{\"mandate\":{\"mandatee\":{\"first_name\":\"John\"}}}}"; // Malformed JSON + + UUID procedureId = UUID.randomUUID(); + Timestamp updated = Timestamp.from(Instant.now()); + + CredentialProcedure credentialProcedure = new CredentialProcedure(); + credentialProcedure.setProcedureId(procedureId); + credentialProcedure.setCredentialDecoded(malformedJson); + credentialProcedure.setOrganizationIdentifier(organizationIdentifier); + credentialProcedure.setUpdatedAt(updated); + + // When + when(credentialProcedureRepository.findAllByOrganizationIdentifier(any(String.class))) + .thenReturn(Flux.just(credentialProcedure)); + when(objectMapper.readTree(malformedJson)) + .thenThrow(new JsonParseException(null, "Error parsing credential")); + + // Execute + Mono result = credentialProcedureService.getAllProceduresBasicInfoByOrganizationId(organizationIdentifier); + + // Then + StepVerifier.create(result) + .expectErrorMatches(throwable -> throwable instanceof JsonParseException) + .verify(); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/service/DeferredCredentialMetadataServiceImplTest.java b/src/test/java/es/in2/issuer/domain/service/DeferredCredentialMetadataServiceImplTest.java index 89ed54c52..db02538d6 100644 --- a/src/test/java/es/in2/issuer/domain/service/DeferredCredentialMetadataServiceImplTest.java +++ b/src/test/java/es/in2/issuer/domain/service/DeferredCredentialMetadataServiceImplTest.java @@ -1,189 +1,239 @@ -//package es.in2.issuer.domain.service; -// -//import com.fasterxml.jackson.core.JsonProcessingException; -//import com.fasterxml.jackson.core.type.TypeReference; -//import com.fasterxml.jackson.databind.ObjectMapper; -//import es.in2.issuer.domain.model.entities.CredentialProcedure; -//import es.in2.issuer.domain.model.entities.DeferredCredentialMetadata; -//import es.in2.issuer.infrastructure.repository.DeferredCredentialMetadataRepository; -//import es.in2.issuer.infrastructure.repository.CredentialProcedureRepository; -//import es.in2.issuer.domain.service.impl.CredentialManagementServiceImpl; -//import es.in2.issuer.domain.util.CredentialStatus; -//import org.junit.jupiter.api.BeforeEach; -//import org.junit.jupiter.api.Test; -//import org.junit.jupiter.api.extension.ExtendWith; -//import org.mockito.InjectMocks; -//import org.mockito.Mock; -//import org.mockito.junit.jupiter.MockitoExtension; -//import org.springframework.data.domain.Sort; -//import reactor.core.publisher.Flux; -//import reactor.core.publisher.Mono; -//import reactor.test.StepVerifier; -// -//import java.sql.Timestamp; -//import java.util.Map; -//import java.util.UUID; -// -//import static es.in2.issuer.domain.util.Constants.JWT_VC; -//import static org.mockito.ArgumentMatchers.any; -//import static org.mockito.ArgumentMatchers.eq; -//import static org.mockito.Mockito.verify; -//import static org.mockito.Mockito.when; -// -//@ExtendWith(MockitoExtension.class) -//class DeferredCredentialMetadataServiceImplTest { -// -// @Mock -// private CredentialProcedureRepository credentialProcedureRepository; -// -// @Mock -// private DeferredCredentialMetadataRepository deferredCredentialMetadataRepository; -// -// @Mock -// private ObjectMapper objectMapper; -// -// @Mock -// private VerifiableCredentialService verifiableCredentialService; -// -// @InjectMocks -// private CredentialManagementServiceImpl credentialManagementService; -// -// private final String userId = "user-id"; -// private final String credential = "{\"example\": \"data\"}"; -// private final String format = "json"; -// private DeferredCredentialMetadata deferredCredentialMetadata; -// private CredentialProcedure credentialProcedure; -// -// @BeforeEach -// void setUp() { -// deferredCredentialMetadata = new DeferredCredentialMetadata(); -// deferredCredentialMetadata.setId(UUID.randomUUID()); -// deferredCredentialMetadata.setUserId(userId); -// deferredCredentialMetadata.setCredentialDecoded(credential); -// deferredCredentialMetadata.setCredentialFormat(format); -// deferredCredentialMetadata.setCredentialStatus("ISSUED"); -// deferredCredentialMetadata.setModifiedAt(new Timestamp(System.currentTimeMillis())); -// -// credentialProcedure = new CredentialProcedure(); -// credentialProcedure.setId(UUID.randomUUID()); -// credentialProcedure.setCredentialId(deferredCredentialMetadata.getId()); -// credentialProcedure.setTransactionId("transaction-id"); -// } -// -// @Test -// void testCommitCredential() { -// when(credentialProcedureRepository.save(any(DeferredCredentialMetadata.class))).thenReturn(Mono.just(deferredCredentialMetadata)); -// when(deferredCredentialMetadataRepository.save(any(CredentialProcedure.class))).thenReturn(Mono.just(credentialProcedure)); -// -// StepVerifier.create(credentialManagementService.commitCredential(credential, userId, format)) -// .expectNextMatches(transactionId -> !transactionId.isEmpty()) -// .verifyComplete(); -// -// verify(credentialProcedureRepository).save(any(DeferredCredentialMetadata.class)); -// verify(deferredCredentialMetadataRepository).save(any(CredentialProcedure.class)); -// } -// -// @Test -// void testUpdateCredential() { -// UUID credentialId = deferredCredentialMetadata.getId(); -// String credential = "some_encoded_credential_data"; -// -// when(credentialProcedureRepository.findByIdAndUserId(credentialId, userId)).thenReturn(Mono.just(deferredCredentialMetadata)); -// -// when(credentialProcedureRepository.save(any(DeferredCredentialMetadata.class))).thenReturn(Mono.just(deferredCredentialMetadata)); -// -// when(deferredCredentialMetadataRepository.findByCredentialId(credentialId)).thenReturn(Mono.just(new CredentialProcedure())); -// -// when(deferredCredentialMetadataRepository.save(any(CredentialProcedure.class))).thenReturn(Mono.just(new CredentialProcedure())); -// -// StepVerifier.create(credentialManagementService.updateCredential(testCredential, credentialId, userId)) -// .verifyComplete(); -// -// verify(credentialProcedureRepository).findByIdAndUserId(credentialId, userId); -// verify(credentialProcedureRepository).save(any(DeferredCredentialMetadata.class)); -// verify(deferredCredentialMetadataRepository).findByCredentialId(credentialId); -// verify(deferredCredentialMetadataRepository).save(any(CredentialProcedure.class)); -// } -// -// @Test -// void testUpdateTransactionId() { -// when(deferredCredentialMetadataRepository.findByTransactionId("transaction-id")).thenReturn(Mono.just(credentialProcedure)); -// when(deferredCredentialMetadataRepository.save(any(CredentialProcedure.class))).thenReturn(Mono.just(credentialProcedure)); -// -// StepVerifier.create(credentialManagementService.updateTransactionId("transaction-id")) -// .expectNextMatches(newTransactionId -> !newTransactionId.isEmpty()) -// .verifyComplete(); -// -// verify(deferredCredentialMetadataRepository).findByTransactionId("transaction-id"); -// verify(deferredCredentialMetadataRepository).save(any(CredentialProcedure.class)); -// } -// -// @Test -// void testDeleteCredentialDeferred() { -// when(deferredCredentialMetadataRepository.findByTransactionId("transaction-id")).thenReturn(Mono.just(credentialProcedure)); -// when(deferredCredentialMetadataRepository.delete(credentialProcedure)).thenReturn(Mono.empty()); -// -// StepVerifier.create(credentialManagementService.deleteCredentialDeferred("transaction-id")) -// .verifyComplete(); -// -// verify(deferredCredentialMetadataRepository).findByTransactionId("transaction-id"); -// verify(deferredCredentialMetadataRepository).delete(credentialProcedure); -// } -// -// @Test -// void getCredentialsTest() throws JsonProcessingException { -// UUID credentialId = UUID.randomUUID(); -// String testUserId = "user123"; -// String jsonCredential = "{\"name\": \"John Doe\"}"; -// Map parsedCredential = Map.of("name", "John Doe"); -// -// DeferredCredentialMetadata cm = new DeferredCredentialMetadata(); -// cm.setId(credentialId); -// cm.setUserId(testUserId); -// cm.setCredentialDecoded(jsonCredential); -// cm.setCredentialStatus(CredentialStatus.ISSUED.getName()); -// cm.setCredentialFormat(JWT_VC); -// cm.setModifiedAt(new Timestamp(System.currentTimeMillis())); -// -// -// when(credentialProcedureRepository.findByUserIdOrderByModifiedAtDesc(eq(userId), any())) -// .thenReturn(Flux.just(cm)); -// when(objectMapper.readValue(eq(cm.getCredentialDecoded()), any(TypeReference.class))) -// .thenReturn(parsedCredential); -// -// StepVerifier.create(credentialManagementService.getCredentials(testUserId, 0, 10, "modifiedAt", Sort.Direction.DESC)) -// .expectNextMatches(item -> item.credential().get("name").equals("John Doe")) -// .verifyComplete(); -// -// verify(credentialProcedureRepository).findByUserIdOrderByModifiedAtDesc(eq(userId), any()); -// } -// -// @Test -// void getCredentialTest() throws JsonProcessingException { -// UUID credentialId = UUID.randomUUID(); -// String credentialTestUserId = "user123"; -// String jsonCredential = "{\"name\": \"John Doe\"}"; -// Map parsedCredential = Map.of("name", "John Doe"); -// -// DeferredCredentialMetadata cm = new DeferredCredentialMetadata(); -// cm.setId(credentialId); -// cm.setUserId(credentialTestUserId); -// cm.setCredentialDecoded(jsonCredential); -// cm.setCredentialStatus(CredentialStatus.ISSUED.getName()); -// cm.setCredentialFormat(JWT_VC); -// cm.setModifiedAt(new Timestamp(System.currentTimeMillis())); -// -// when(credentialProcedureRepository.findByIdAndUserId(credentialId, userId)) -// .thenReturn(Mono.just(cm)); -// when(objectMapper.readValue(eq(cm.getCredentialDecoded()), any(TypeReference.class))) -// .thenReturn(parsedCredential); -// -// -// StepVerifier.create(credentialManagementService.getCredential(credentialId, credentialTestUserId)) -// .expectNextMatches(item -> item.credential().get("name").equals("John Doe")) -// .verifyComplete(); -// -// verify(credentialProcedureRepository).findByIdAndUserId(credentialId, userId); -// } -//} -// +package es.in2.issuer.domain.service; + +import es.in2.issuer.domain.model.entities.DeferredCredentialMetadata; +import es.in2.issuer.domain.service.impl.DeferredCredentialMetadataServiceImpl; +import es.in2.issuer.domain.util.Utils; +import es.in2.issuer.infrastructure.repository.CacheStore; +import es.in2.issuer.infrastructure.repository.DeferredCredentialMetadataRepository; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.junit.jupiter.MockitoExtension; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.util.Objects; +import java.util.UUID; + +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class DeferredCredentialMetadataServiceImplTest { + + @Mock + private DeferredCredentialMetadataRepository deferredCredentialMetadataRepository; + + @Mock + private CacheStore cacheStore; + + @InjectMocks + private DeferredCredentialMetadataServiceImpl deferredCredentialMetadataService; + + @Test + void testValidateTransactionCode_Success() { + // Arrange + String transactionCode = "transaction-code"; + when(cacheStore.get(transactionCode)).thenReturn(Mono.just(transactionCode)); + doNothing().when(cacheStore).delete(transactionCode); + + // Act + StepVerifier.create(deferredCredentialMetadataService.validateTransactionCode(transactionCode)) + .verifyComplete(); + + // Assert + verify(cacheStore, times(1)).get(transactionCode); + verify(cacheStore, times(1)).delete(transactionCode); + } + + @Test + void testUpdateAuthServerNonceByAuthServerNonce_Success() { + // Arrange + String accessToken = "access-token"; + String preAuthCode = "pre-auth-code"; + DeferredCredentialMetadata deferredCredentialMetadata = new DeferredCredentialMetadata(); + when(deferredCredentialMetadataRepository.findByAuthServerNonce(preAuthCode)).thenReturn(Mono.just(deferredCredentialMetadata)); + when(deferredCredentialMetadataRepository.save(deferredCredentialMetadata)).thenReturn(Mono.just(deferredCredentialMetadata)); + + // Act + StepVerifier.create(deferredCredentialMetadataService.updateAuthServerNonceByAuthServerNonce(accessToken, preAuthCode)) + .verifyComplete(); + + // Assert + verify(deferredCredentialMetadataRepository, times(1)).findByAuthServerNonce(preAuthCode); + verify(deferredCredentialMetadataRepository, times(1)).save(deferredCredentialMetadata); + } + + @Test + void testCreateDeferredCredentialMetadata_Success() { + // Arrange + String procedureId = UUID.randomUUID().toString(); + String nonce = "nonce"; + String transactionCode = "transaction-code"; + + try (MockedStatic mockUtils = mockStatic(Utils.class)) { + mockUtils.when(Utils::generateCustomNonce).thenReturn(Mono.just(nonce)); + } + when(cacheStore.add(anyString(), anyString())).thenReturn(Mono.just(transactionCode)); + when(deferredCredentialMetadataRepository.save(any(DeferredCredentialMetadata.class))).thenReturn(Mono.just(new DeferredCredentialMetadata())); + + // Act + StepVerifier.create(deferredCredentialMetadataService.createDeferredCredentialMetadata(procedureId)) + .expectNext(transactionCode) + .verifyComplete(); + + // Assert + verify(cacheStore, times(1)).add(anyString(), anyString()); + verify(deferredCredentialMetadataRepository, times(1)).save(any(DeferredCredentialMetadata.class)); + } + + @Test + void testUpdateTransactionCodeInDeferredCredentialMetadata_Success() { + // Arrange + String procedureId = UUID.randomUUID().toString(); + String nonce = "nonce"; + DeferredCredentialMetadata deferredCredentialMetadata = new DeferredCredentialMetadata(); + when(deferredCredentialMetadataRepository.findByProcedureId(UUID.fromString(procedureId))).thenReturn(Mono.just(deferredCredentialMetadata)); + try (MockedStatic mockUtils = mockStatic(Utils.class)) { + mockUtils.when(Utils::generateCustomNonce).thenReturn(Mono.just(nonce)); + } + when(cacheStore.add(anyString(), anyString())).thenReturn(Mono.just(nonce)); + when(deferredCredentialMetadataRepository.save(any(DeferredCredentialMetadata.class))).thenReturn(Mono.just(deferredCredentialMetadata)); + + // Act + StepVerifier.create(deferredCredentialMetadataService.updateTransactionCodeInDeferredCredentialMetadata(procedureId)) + .expectNextMatches(Objects::nonNull) + .verifyComplete(); + + // Assert + verify(deferredCredentialMetadataRepository, times(1)).findByProcedureId(UUID.fromString(procedureId)); + verify(cacheStore, times(1)).add(anyString(), anyString()); + verify(deferredCredentialMetadataRepository, times(1)).save(any(DeferredCredentialMetadata.class)); + } + + @Test + void testGetProcedureIdByTransactionCode_Success() { + // Arrange + String transactionCode = "transaction-code"; + DeferredCredentialMetadata deferredCredentialMetadata = new DeferredCredentialMetadata(); + deferredCredentialMetadata.setProcedureId(UUID.randomUUID()); + when(deferredCredentialMetadataRepository.findByTransactionCode(transactionCode)).thenReturn(Mono.just(deferredCredentialMetadata)); + + // Act + StepVerifier.create(deferredCredentialMetadataService.getProcedureIdByTransactionCode(transactionCode)) + .expectNext(deferredCredentialMetadata.getProcedureId().toString()) + .verifyComplete(); + + // Assert + verify(deferredCredentialMetadataRepository, times(1)).findByTransactionCode(transactionCode); + } + + @Test + void testGetProcedureIdByAuthServerNonce_Success() { + // Arrange + String authServerNonce = "auth-server-nonce"; + DeferredCredentialMetadata deferredCredentialMetadata = new DeferredCredentialMetadata(); + deferredCredentialMetadata.setProcedureId(UUID.randomUUID()); + when(deferredCredentialMetadataRepository.findByAuthServerNonce(authServerNonce)).thenReturn(Mono.just(deferredCredentialMetadata)); + + // Act + StepVerifier.create(deferredCredentialMetadataService.getProcedureIdByAuthServerNonce(authServerNonce)) + .expectNext(deferredCredentialMetadata.getProcedureId().toString()) + .verifyComplete(); + + // Assert + verify(deferredCredentialMetadataRepository, times(1)).findByAuthServerNonce(authServerNonce); + } + + @Test + void testUpdateAuthServerNonceByTransactionCode_Success() { + // Arrange + String transactionCode = "transaction-code"; + String authServerNonce = "auth-server-nonce"; + DeferredCredentialMetadata deferredCredentialMetadata = new DeferredCredentialMetadata(); + when(deferredCredentialMetadataRepository.findByTransactionCode(transactionCode)).thenReturn(Mono.just(deferredCredentialMetadata)); + when(deferredCredentialMetadataRepository.save(deferredCredentialMetadata)).thenReturn(Mono.just(deferredCredentialMetadata)); + + // Act + StepVerifier.create(deferredCredentialMetadataService.updateAuthServerNonceByTransactionCode(transactionCode, authServerNonce)) + .verifyComplete(); + + // Assert + verify(deferredCredentialMetadataRepository, times(1)).findByTransactionCode(transactionCode); + verify(deferredCredentialMetadataRepository, times(1)).save(deferredCredentialMetadata); + } + + @Test + void testUpdateDeferredCredentialMetadataByAuthServerNonce_Success() { + // Arrange + String authServerNonce = "auth-server-nonce"; + String format = "format"; + DeferredCredentialMetadata deferredCredentialMetadata = new DeferredCredentialMetadata(); + when(deferredCredentialMetadataRepository.findByAuthServerNonce(authServerNonce)).thenReturn(Mono.just(deferredCredentialMetadata)); + when(deferredCredentialMetadataRepository.save(deferredCredentialMetadata)).thenReturn(Mono.just(deferredCredentialMetadata)); + + // Act + StepVerifier.create(deferredCredentialMetadataService.updateDeferredCredentialMetadataByAuthServerNonce(authServerNonce, format)) + .expectNextMatches(Objects::nonNull) + .verifyComplete(); + + // Assert + verify(deferredCredentialMetadataRepository, times(1)).findByAuthServerNonce(authServerNonce); + verify(deferredCredentialMetadataRepository, times(1)).save(deferredCredentialMetadata); + } + + @Test + void testUpdateVcByProcedureId_Success() { + // Arrange + String vc = "vc"; + String procedureId = UUID.randomUUID().toString(); + DeferredCredentialMetadata deferredCredentialMetadata = new DeferredCredentialMetadata(); + when(deferredCredentialMetadataRepository.findByProcedureId(UUID.fromString(procedureId))).thenReturn(Mono.just(deferredCredentialMetadata)); + when(deferredCredentialMetadataRepository.save(deferredCredentialMetadata)).thenReturn(Mono.just(deferredCredentialMetadata)); + + // Act + StepVerifier.create(deferredCredentialMetadataService.updateVcByProcedureId(vc, procedureId)) + .verifyComplete(); + + // Assert + verify(deferredCredentialMetadataRepository, times(1)).findByProcedureId(UUID.fromString(procedureId)); + verify(deferredCredentialMetadataRepository, times(1)).save(deferredCredentialMetadata); + } + + @Test + void testGetVcByTransactionId_Success() { + // Arrange + String transactionId = UUID.randomUUID().toString(); + DeferredCredentialMetadata deferredCredentialMetadata = new DeferredCredentialMetadata(); + deferredCredentialMetadata.setVc("vc"); + deferredCredentialMetadata.setId(UUID.randomUUID()); + deferredCredentialMetadata.setProcedureId(UUID.randomUUID()); + when(deferredCredentialMetadataRepository.findByTransactionId(transactionId)).thenReturn(Mono.just(deferredCredentialMetadata)); + + // Act + StepVerifier.create(deferredCredentialMetadataService.getVcByTransactionId(transactionId)) + .expectNextMatches(response -> response.vc().equals(deferredCredentialMetadata.getVc()) + && response.id().equals(deferredCredentialMetadata.getId().toString()) + && response.procedureId().equals(deferredCredentialMetadata.getProcedureId().toString())) + .verifyComplete(); + + // Assert + verify(deferredCredentialMetadataRepository, times(1)).findByTransactionId(transactionId); + } + + @Test + void testDeleteDeferredCredentialMetadataById_Success() { + // Arrange + String id = UUID.randomUUID().toString(); + when(deferredCredentialMetadataRepository.deleteById(UUID.fromString(id))).thenReturn(Mono.empty()); + + // Act + StepVerifier.create(deferredCredentialMetadataService.deleteDeferredCredentialMetadataById(id)) + .verifyComplete(); + + // Assert + verify(deferredCredentialMetadataRepository, times(1)).deleteById(UUID.fromString(id)); + } + +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/service/EmailServiceImplTest.java b/src/test/java/es/in2/issuer/domain/service/EmailServiceImplTest.java new file mode 100644 index 000000000..e65b94b55 --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/service/EmailServiceImplTest.java @@ -0,0 +1,87 @@ +package es.in2.issuer.domain.service; + +import es.in2.issuer.domain.service.impl.EmailServiceImpl; +import jakarta.mail.internet.MimeMessage; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.mail.javamail.JavaMailSender; +import org.thymeleaf.TemplateEngine; +import org.thymeleaf.context.Context; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class EmailServiceImplTest { + + @Mock + private JavaMailSender javaMailSender; + + @Mock + private TemplateEngine templateEngine; + + @InjectMocks + private EmailServiceImpl emailService; + + @Test + void testSendPin() throws Exception { + MimeMessage mimeMessage = mock(MimeMessage.class); + when(javaMailSender.createMimeMessage()).thenReturn(mimeMessage); + when(templateEngine.process(eq("pin-email"), any(Context.class))).thenReturn("htmlContent"); + + Mono result = emailService.sendPin("to@example.com", "subject", "1234"); + + StepVerifier.create(result) + .verifyComplete(); + + verify(javaMailSender).send(mimeMessage); + } + + @Test + void testSendTransactionCodeForCredentialOffer() throws Exception { + MimeMessage mimeMessage = mock(MimeMessage.class); + when(javaMailSender.createMimeMessage()).thenReturn(mimeMessage); + when(templateEngine.process(eq("transaction-code-email"), any(Context.class))).thenReturn("htmlContent"); + + Mono result = emailService.sendTransactionCodeForCredentialOffer("to@example.com", "subject", "link", "\"John\""); + + StepVerifier.create(result) + .verifyComplete(); + + verify(javaMailSender).send(mimeMessage); + } + + @Test + void testSendPendingCredentialNotification() throws Exception { + MimeMessage mimeMessage = mock(MimeMessage.class); + when(javaMailSender.createMimeMessage()).thenReturn(mimeMessage); + when(templateEngine.process(eq("credential-pending-notification"), any(Context.class))).thenReturn("htmlContent"); + + Mono result = emailService.sendPendingCredentialNotification("to@example.com", "subject"); + + StepVerifier.create(result) + .verifyComplete(); + + verify(javaMailSender).send(mimeMessage); + } + + @Test + void testSendCredentialSignedNotification() throws Exception { + MimeMessage mimeMessage = mock(MimeMessage.class); + when(javaMailSender.createMimeMessage()).thenReturn(mimeMessage); + when(templateEngine.process(eq("credential-signed-notification"), any(Context.class))).thenReturn("htmlContent"); + + Mono result = emailService.sendCredentialSignedNotification("to@example.com", "subject", "\"John\""); + + StepVerifier.create(result) + .verifyComplete(); + + verify(javaMailSender).send(mimeMessage); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/service/IssuerApiClientTokenServiceImplTest.java b/src/test/java/es/in2/issuer/domain/service/IssuerApiClientTokenServiceImplTest.java new file mode 100644 index 000000000..4c53af2b2 --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/service/IssuerApiClientTokenServiceImplTest.java @@ -0,0 +1,150 @@ +package es.in2.issuer.domain.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import es.in2.issuer.domain.exception.PreAuthorizationCodeGetException; +import es.in2.issuer.domain.service.impl.IssuerApiClientTokenServiceImpl; +import es.in2.issuer.infrastructure.config.AuthServerConfig; +import es.in2.issuer.infrastructure.config.WebClientConfig; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpStatus; +import org.springframework.web.reactive.function.client.ClientResponse; +import org.springframework.web.reactive.function.client.WebClient; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.util.Map; +import java.util.function.Function; + +import static es.in2.issuer.domain.util.Constants.CONTENT_TYPE_URL_ENCODED_FORM; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; +import static org.springframework.http.HttpHeaders.CONTENT_TYPE; + +@ExtendWith(MockitoExtension.class) +class IssuerApiClientTokenServiceImplTest { + + @Mock + private AuthServerConfig authServerConfig; + + @Mock + private WebClientConfig webClientConfig; + + @Mock + private WebClient webClient; + + @Mock + private WebClient.RequestBodyUriSpec requestBodyUriSpec; + + @Mock + private WebClient.RequestHeadersSpec requestHeadersSpec; + + @Mock + private ObjectMapper objectMapper; + + @InjectMocks + private IssuerApiClientTokenServiceImpl issuerApiClientTokenService; + + @Test + void testGetClientToken_Success() throws JsonProcessingException { + //Arrange + when(authServerConfig.getAuthServerClientId()).thenReturn("clientId"); + when(authServerConfig.getAuthServerUsername()).thenReturn("username"); + when(authServerConfig.getAuthServerUserPassword()).thenReturn("password"); + when(authServerConfig.getTokenUri()).thenReturn("https://auth.server/token"); + when(webClientConfig.commonWebClient()).thenReturn(webClient); + when(webClient.post()).thenReturn(requestBodyUriSpec); + when(requestBodyUriSpec.uri("https://auth.server/token")).thenReturn(requestBodyUriSpec); + when(requestBodyUriSpec.header(CONTENT_TYPE, CONTENT_TYPE_URL_ENCODED_FORM)).thenReturn(requestBodyUriSpec); + when(requestBodyUriSpec.bodyValue(anyString())).thenReturn(requestHeadersSpec); + + // Configure exchangeToMono to handle the ClientResponse and return a Mono + when(requestHeadersSpec.exchangeToMono(any())).thenAnswer(invocation -> { + Function> responseHandler = invocation.getArgument(0); + ClientResponse clientResponse = mock(ClientResponse.class); + when(clientResponse.statusCode()).thenReturn(HttpStatus.OK); + when(clientResponse.bodyToMono(String.class)).thenReturn(Mono.just("{\"access_token\":\"dummyToken\"}")); + return responseHandler.apply(clientResponse); + }); + when(objectMapper.readValue(anyString(), any(TypeReference.class))).thenReturn(Map.of("access_token", "dummyToken")); + + // Act + Mono result = issuerApiClientTokenService.getClientToken(); + + // Assert + StepVerifier.create(result) + .expectNext("dummyToken") + .verifyComplete(); + } + + @Test + void testGetClientToken_ClientError() { + // Arrange + when(authServerConfig.getAuthServerClientId()).thenReturn("clientId"); + when(authServerConfig.getAuthServerUsername()).thenReturn("username"); + when(authServerConfig.getAuthServerUserPassword()).thenReturn("password"); + when(authServerConfig.getTokenUri()).thenReturn("https://auth.server/token"); + when(webClientConfig.commonWebClient()).thenReturn(webClient); + when(webClient.post()).thenReturn(requestBodyUriSpec); + when(requestBodyUriSpec.uri("https://auth.server/token")).thenReturn(requestBodyUriSpec); + when(requestBodyUriSpec.header(CONTENT_TYPE, CONTENT_TYPE_URL_ENCODED_FORM)).thenReturn(requestBodyUriSpec); + when(requestBodyUriSpec.bodyValue(anyString())).thenReturn(requestHeadersSpec); + + // Configure exchangeToMono to handle the ClientResponse and return a Mono + when(requestHeadersSpec.exchangeToMono(any())).thenAnswer(invocation -> { + Function> responseHandler = invocation.getArgument(0); + ClientResponse clientResponse = mock(ClientResponse.class); + when(clientResponse.statusCode()).thenReturn(HttpStatus.BAD_REQUEST); + return responseHandler.apply(clientResponse); + }); + + // Act + Mono result = issuerApiClientTokenService.getClientToken(); + + // Assert + StepVerifier.create(result) + .expectError(PreAuthorizationCodeGetException.class) + .verify(); + } + + + @Test + void testGetClientToken_JsonProcessingException() throws JsonProcessingException { + when(authServerConfig.getAuthServerClientId()).thenReturn("clientId"); + when(authServerConfig.getAuthServerUsername()).thenReturn("username"); + when(authServerConfig.getAuthServerUserPassword()).thenReturn("password"); + when(authServerConfig.getTokenUri()).thenReturn("https://auth.server/token"); + when(webClientConfig.commonWebClient()).thenReturn(webClient); + when(webClient.post()).thenReturn(requestBodyUriSpec); + when(requestBodyUriSpec.uri("https://auth.server/token")).thenReturn(requestBodyUriSpec); + when(requestBodyUriSpec.header(CONTENT_TYPE, CONTENT_TYPE_URL_ENCODED_FORM)).thenReturn(requestBodyUriSpec); + when(requestBodyUriSpec.bodyValue(anyString())).thenReturn(requestHeadersSpec); + + // Configure exchangeToMono to handle the ClientResponse and return a Mono + when(requestHeadersSpec.exchangeToMono(any())).thenAnswer(invocation -> { + Function> responseHandler = invocation.getArgument(0); + ClientResponse clientResponse = mock(ClientResponse.class); + when(clientResponse.statusCode()).thenReturn(HttpStatus.OK); + when(clientResponse.bodyToMono(String.class)).thenReturn(Mono.just("{\"access_token\":\"dummyToken\"}")); + return responseHandler.apply(clientResponse); + }); + + // Mocking ObjectMapper to throw JsonProcessingException + when(objectMapper.readValue(anyString(), any(TypeReference.class))).thenThrow(new JsonProcessingException("error") { + }); + + // Act + Mono result = issuerApiClientTokenService.getClientToken(); + + // Assert + StepVerifier.create(result) + .expectError(RuntimeException.class) + .verify(); + } + +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/service/NotificationServiceImplTest.java b/src/test/java/es/in2/issuer/domain/service/NotificationServiceImplTest.java new file mode 100644 index 000000000..36488438d --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/service/NotificationServiceImplTest.java @@ -0,0 +1,102 @@ +package es.in2.issuer.domain.service; + +import es.in2.issuer.domain.model.enums.CredentialStatus; +import es.in2.issuer.domain.service.impl.NotificationServiceImpl; +import es.in2.issuer.infrastructure.config.AppConfig; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class NotificationServiceImplTest { + + private final String processId = "processId"; + private final String procedureId = "procedureId"; + private final String email = "test@example.com"; + private final String firstName = "John"; + private final String issuerUiExternalDomain = "http://example.com"; + + @Mock + private AppConfig appConfig; + @Mock + private EmailService emailService; + @Mock + private CredentialProcedureService credentialProcedureService; + @Mock + private DeferredCredentialMetadataService deferredCredentialMetadataService; + @InjectMocks + private NotificationServiceImpl notificationService; + + @BeforeEach + void setup() { + lenient().when(appConfig.getIssuerUiExternalDomain()).thenReturn(issuerUiExternalDomain); + } + + @Test + void testSendNotification_WithWithdrawnStatus() { + String transactionCode = "transactionCode"; + when(credentialProcedureService.getCredentialStatusByProcedureId(procedureId)) + .thenReturn(Mono.just(CredentialStatus.WITHDRAWN.toString())); + when(credentialProcedureService.getMandateeEmailFromDecodedCredentialByProcedureId(procedureId)) + .thenReturn(Mono.just(email)); + when(credentialProcedureService.getMandateeFirstNameFromDecodedCredentialByProcedureId(procedureId)) + .thenReturn(Mono.just(firstName)); + when(deferredCredentialMetadataService.updateTransactionCodeInDeferredCredentialMetadata(procedureId)) + .thenReturn(Mono.just(transactionCode)); + when(emailService.sendTransactionCodeForCredentialOffer(email, "Credential Offer", + issuerUiExternalDomain + "/credential-offer?transaction_code=" + transactionCode, firstName)) + .thenReturn(Mono.empty()); + + Mono result = notificationService.sendNotification(processId, procedureId); + + StepVerifier.create(result) + .verifyComplete(); + + verify(emailService, times(1)).sendTransactionCodeForCredentialOffer(anyString(), anyString(), anyString(), anyString()); + } + + @Test + void testSendNotification_WithPendDownloadStatus() { + when(credentialProcedureService.getCredentialStatusByProcedureId(procedureId)) + .thenReturn(Mono.just(CredentialStatus.PEND_DOWNLOAD.toString())); + when(credentialProcedureService.getMandateeEmailFromDecodedCredentialByProcedureId(procedureId)) + .thenReturn(Mono.just(email)); + when(credentialProcedureService.getMandateeFirstNameFromDecodedCredentialByProcedureId(procedureId)) + .thenReturn(Mono.just(firstName)); + when(emailService.sendCredentialSignedNotification(email, "Credential Ready", firstName)) + .thenReturn(Mono.empty()); + + Mono result = notificationService.sendNotification(processId, procedureId); + + StepVerifier.create(result) + .verifyComplete(); + + verify(emailService, times(1)).sendCredentialSignedNotification(anyString(), anyString(), anyString()); + } + + @Test + void testSendNotification_WithUnhandledStatus() { + when(credentialProcedureService.getCredentialStatusByProcedureId(procedureId)) + .thenReturn(Mono.just("UNHANDLED_STATUS")); + when(credentialProcedureService.getMandateeEmailFromDecodedCredentialByProcedureId(procedureId)) + .thenReturn(Mono.just(email)); + when(credentialProcedureService.getMandateeFirstNameFromDecodedCredentialByProcedureId(procedureId)) + .thenReturn(Mono.just(firstName)); + + Mono result = notificationService.sendNotification(processId, procedureId); + + StepVerifier.create(result) + .verifyComplete(); + + verify(emailService, never()).sendTransactionCodeForCredentialOffer(anyString(), anyString(), anyString(), anyString()); + verify(emailService, never()).sendCredentialSignedNotification(anyString(), anyString(), anyString()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/service/RemoteSignatureServiceImplTest.java b/src/test/java/es/in2/issuer/domain/service/RemoteSignatureServiceImplTest.java index 03c64008b..8fee94e9f 100644 --- a/src/test/java/es/in2/issuer/domain/service/RemoteSignatureServiceImplTest.java +++ b/src/test/java/es/in2/issuer/domain/service/RemoteSignatureServiceImplTest.java @@ -1,164 +1,90 @@ -//package es.in2.issuer.domain.service; -// -//import com.fasterxml.jackson.core.JsonProcessingException; -//import com.fasterxml.jackson.databind.ObjectMapper; -//import es.in2.issuer.domain.model.SignatureConfiguration; -//import es.in2.issuer.domain.model.SignatureRequest; -//import es.in2.issuer.domain.model.enums.SignatureType; -//import es.in2.issuer.domain.model.SignedData; -//import es.in2.issuer.domain.service.impl.RemoteSignatureServiceImpl; -//import es.in2.issuer.domain.util.HttpUtils; -//import es.in2.issuer.infrastructure.config.ApiConfig; -//import es.in2.issuer.infrastructure.config.RemoteSignatureConfig; -//import org.junit.jupiter.api.Test; -//import org.junit.jupiter.api.extension.ExtendWith; -//import org.mockito.InjectMocks; -//import org.mockito.Mock; -//import org.mockito.junit.jupiter.MockitoExtension; -//import org.springframework.http.HttpHeaders; -//import org.springframework.http.MediaType; -//import org.springframework.test.util.ReflectionTestUtils; -//import reactor.core.Exceptions; -//import reactor.core.publisher.Mono; -// -//import java.lang.reflect.InvocationTargetException; -//import java.lang.reflect.Method; -//import java.util.*; -// -//import static org.junit.jupiter.api.Assertions.assertNotNull; -//import static org.junit.jupiter.api.Assertions.assertThrows; -//import static org.mockito.ArgumentMatchers.anyString; -//import static org.mockito.ArgumentMatchers.eq; -//import static org.mockito.Mockito.*; -// -//@ExtendWith(MockitoExtension.class) -//class RemoteSignatureServiceImplTest { -// -// @Mock -// private RemoteSignatureConfig remoteSignatureConfig; -// -// private ApiConfig apiConfig; -// -// @Mock -// private ObjectMapper objectMapper; -// -// @Mock -// private HttpUtils httpUtils; -// -// @InjectMocks -// private RemoteSignatureServiceImpl remoteSignatureService; -// -// @Test -// void testInitializeRemoteSignatureBaseUrl() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { -// lenient().when(remoteSignatureConfig.getRemoteSignatureExternalDomain()).thenReturn(String.valueOf(Mono.just("dummyValue"))); -// -// Method privateMethod = RemoteSignatureServiceImpl.class.getDeclaredMethod("initializeRemoteSignatureBaseUrl"); -// privateMethod.setAccessible(true); -// -// privateMethod.invoke(remoteSignatureService); -// -// verify(remoteSignatureConfig, times(1)).getRemoteSignatureExternalDomain(); -// } -// -// @Test -// void testInitializeRemoteSignatureBaseUrlThrowsError() throws NoSuchMethodException { -// -// Method privateMethod = RemoteSignatureServiceImpl.class.getDeclaredMethod("initializeRemoteSignatureBaseUrl"); -// privateMethod.setAccessible(true); -// -// when(remoteSignatureConfig.getRemoteSignatureExternalDomain()).thenAnswer(invocation -> Mono.error(new RuntimeException("Simulated error"))); -// -// assertThrows(InvocationTargetException.class, () -> privateMethod.invoke(remoteSignatureService)); -// -// verify(remoteSignatureConfig, times(1)).getRemoteSignatureExternalDomain(); -// } -// -// @Test -// void sign_Success() throws JsonProcessingException { -// -// ReflectionTestUtils.setField(remoteSignatureService, "remoteSignatureBaseUrl", "http://baseurl"); -// ReflectionTestUtils.setField(remoteSignatureService, "sign", "/sign"); -// -// SignatureConfiguration signatureConfiguration = new SignatureConfiguration(SignatureType.COSE, new HashMap<>()); -// SignatureRequest signatureRequest = new SignatureRequest(signatureConfiguration, "data"); -// String expectedSignedDataJson = "{\"signature\":\"testSignature\",\"timestamp\":123456789}"; -// SignedData dto = SignedData.builder().build(); -// -// String url = "http://baseurl" + "/api/v1" + "/sign"; -// -// String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; -// List> headers = new ArrayList<>(); -// headers.add(new AbstractMap.SimpleEntry<>(HttpHeaders.AUTHORIZATION, "Bearer " + token)); -// headers.add(new AbstractMap.SimpleEntry<>(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)); -// -// when(objectMapper.writeValueAsString(signatureRequest)).thenReturn("signedSignature"); -// when(objectMapper.readValue(anyString(), eq(SignedData.class))).thenReturn(dto); -// when(httpUtils.postRequest(url, headers, "signedSignature")).thenReturn(Mono.just(expectedSignedDataJson)); -// -// Mono resultMono = remoteSignatureService.sign(signatureRequest, token); -// SignedData result = resultMono.block(); -// -// assertNotNull(result); -// -// verify(httpUtils).postRequest(url, headers, "signedSignature"); -// } -// -// @Test -// void sign_JsonProcessingException_whenObjectMapper_writeValueAsString() throws JsonProcessingException { -// ReflectionTestUtils.setField(remoteSignatureService, "remoteSignatureBaseUrl", "http://baseurl"); -// ReflectionTestUtils.setField(remoteSignatureService, "sign", "/sign"); -// -// SignatureConfiguration signatureConfiguration = new SignatureConfiguration(SignatureType.COSE, new HashMap<>()); -// SignatureRequest signatureRequest = new SignatureRequest(signatureConfiguration, "data"); -// String token = "testToken"; -// when(objectMapper.writeValueAsString(signatureRequest)).thenThrow(new JsonProcessingException("Json processing error") { -// }); -// -// assertThrows(JsonProcessingException.class, () -> { -// try { -// remoteSignatureService.sign(signatureRequest, token).block(); -// } catch (Exception e) { -// throw Exceptions.unwrap(e); -// } -// }); -// -// verifyNoInteractions(httpUtils); -// } -// -// @Test -// void sign_JsonProcessingException_whenObjectMapper_readValue() throws JsonProcessingException { -// // Set up -// ReflectionTestUtils.setField(remoteSignatureService, "remoteSignatureBaseUrl", "http://baseurl"); -// ReflectionTestUtils.setField(remoteSignatureService, "sign", "/sign"); -// -// SignatureConfiguration signatureConfiguration = new SignatureConfiguration(SignatureType.COSE, new HashMap<>()); -// SignatureRequest signatureRequest = new SignatureRequest(signatureConfiguration, "data"); -// String expectedSignedDataJson = "{\"signature\":\"testSignature\",\"timestamp\":123456789}"; -// -// String url = "http://baseurl" + "/api/v1" + "/sign"; -// -// String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; -// List> headers = new ArrayList<>(); -// headers.add(new AbstractMap.SimpleEntry<>(HttpHeaders.AUTHORIZATION, "Bearer " + token)); -// headers.add(new AbstractMap.SimpleEntry<>(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)); -// -// // Set up mocks -// when(objectMapper.writeValueAsString(signatureRequest)).thenReturn("signedSignature"); -// when(objectMapper.readValue(anyString(), eq(SignedData.class))).thenThrow(new JsonProcessingException("Json processing error") { -// }); -// when(httpUtils.postRequest(url, headers, "signedSignature")).thenReturn(Mono.just(expectedSignedDataJson)); -// -// // Assert and verify -// assertThrows(RuntimeException.class, () -> handleSignJsonProcessingError(remoteSignatureService, signatureRequest, token)); -// verify(httpUtils).postRequest(url, headers, "signedSignature"); -// } -// -// private void handleSignJsonProcessingError(RemoteSignatureService remoteSignatureService, SignatureRequest signatureRequest, String token) { -// try { -// remoteSignatureService.sign(signatureRequest, token).block(); -// } catch (Exception e) { -// throw new RuntimeException("Error signing data", e); -// } -// } -// -//} +package es.in2.issuer.domain.service; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import es.in2.issuer.domain.model.dto.SignatureConfiguration; +import es.in2.issuer.domain.model.dto.SignatureRequest; +import es.in2.issuer.domain.model.dto.SignedData; +import es.in2.issuer.domain.model.enums.SignatureType; +import es.in2.issuer.domain.service.impl.RemoteSignatureServiceImpl; +import es.in2.issuer.domain.util.HttpUtils; +import es.in2.issuer.infrastructure.config.RemoteSignatureConfig; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.util.Map; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class RemoteSignatureServiceImplTest { + + @Mock + private ObjectMapper objectMapper; + + @Mock + private HttpUtils httpUtils; + + @Mock + private RemoteSignatureConfig remoteSignatureConfig; + + @InjectMocks + private RemoteSignatureServiceImpl remoteSignatureService; + + private SignatureRequest signatureRequest; + private String token; + private String signatureRemoteServerEndpoint; + private SignatureType signatureType; + + @BeforeEach + void setUp() { + signatureType = SignatureType.COSE; + Map parameters = Map.of("param1", "value1", "param2", "value2"); + SignatureConfiguration signatureConfiguration1 = new SignatureConfiguration(signatureType, parameters); + signatureRequest = new SignatureRequest(signatureConfiguration1, "data"); + token = "dummyToken"; + when(remoteSignatureConfig.getRemoteSignatureExternalDomain()).thenReturn("http://remote-signature.com"); + when(remoteSignatureConfig.getRemoteSignatureSignPath()).thenReturn("/sign"); + signatureRemoteServerEndpoint = "http://remote-signature.com/api/v1/sign"; + } + + @Test + void testSignSuccess() throws JsonProcessingException { + String signatureRequestJSON = "{\"request\":\"data\"}"; + String signedResponse = "{\"signed\":\"data\"}"; + String data = "data"; + SignedData signedData = new SignedData(signatureType, data); + + when(objectMapper.writeValueAsString(signatureRequest)).thenReturn(signatureRequestJSON); + when(httpUtils.postRequest(eq(signatureRemoteServerEndpoint), any(), eq(signatureRequestJSON))) + .thenReturn(Mono.just(signedResponse)); + when(objectMapper.readValue(signedResponse, SignedData.class)).thenReturn(signedData); + + Mono result = remoteSignatureService.sign(signatureRequest, token); + + StepVerifier.create(result) + .expectNext(signedData) + .verifyComplete(); + } + + @Test + void testSignJsonProcessingException() throws JsonProcessingException { + when(objectMapper.writeValueAsString(signatureRequest)).thenThrow(new JsonProcessingException("error") { + }); + + Mono result = remoteSignatureService.sign(signatureRequest, token); + + StepVerifier.create(result) + .expectError(JsonProcessingException.class) + .verify(); + } + +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/service/VerifiableCredentialServiceImplTest.java b/src/test/java/es/in2/issuer/domain/service/VerifiableCredentialServiceImplTest.java index c4390b2ac..2e1c21cf5 100644 --- a/src/test/java/es/in2/issuer/domain/service/VerifiableCredentialServiceImplTest.java +++ b/src/test/java/es/in2/issuer/domain/service/VerifiableCredentialServiceImplTest.java @@ -1,132 +1,291 @@ -//package es.in2.issuer.domain.service; -// -//import com.fasterxml.jackson.core.JsonProcessingException; -//import com.fasterxml.jackson.databind.JsonNode; -//import com.fasterxml.jackson.databind.ObjectMapper; -//import com.fasterxml.jackson.databind.node.ObjectNode; -//import es.in2.issuer.domain.service.impl.VerifiableCredentialServiceImpl; -//import org.junit.jupiter.api.Test; -//import org.junit.jupiter.api.extension.ExtendWith; -//import org.mockito.InjectMocks; -//import org.mockito.Mock; -//import org.mockito.junit.jupiter.MockitoExtension; -//import reactor.test.StepVerifier; -// -//import java.time.Instant; -//import java.util.UUID; -// -//import static org.mockito.ArgumentMatchers.any; -//import static org.mockito.Mockito.when; -// -//@ExtendWith(MockitoExtension.class) -//class VerifiableCredentialServiceImplTest { -// @Mock -// private ObjectMapper objectMapper; -// -// @InjectMocks -// private VerifiableCredentialServiceImpl verifiableCredentialService; -// -// @Test -// void testGenerateVcPayLoad() throws JsonProcessingException { -// String vcTemplate = "{\"issuer\":\"did:example:123\",\"credentialSubject\":{}}"; -// String subjectDid = "did:example:456"; -// String issuerDid = "did:example:123"; -// String userData = "{\"name\":\"John Doe\"}"; -// Instant expiration = Instant.now().plusSeconds(3600); -// -// // Create real ObjectMapper for node creation -// ObjectMapper realMapper = new ObjectMapper(); -// -// // Mocking the template and user data JsonNode -// JsonNode vcTemplateNode = realMapper.createObjectNode().put("issuer", issuerDid); -// JsonNode userDataNode = realMapper.createObjectNode().put("name", "John Doe"); -// -// when(objectMapper.readTree(vcTemplate)).thenReturn(vcTemplateNode); -// when(objectMapper.readTree(userData)).thenReturn(userDataNode); -// -// // Use the real ObjectMapper to avoid issues with creating ObjectNode -// when(objectMapper.createObjectNode()).thenAnswer(invocation -> realMapper.createObjectNode()); -// -// // Mocking final JSON output -// String expectedUuid = UUID.randomUUID().toString(); -// String expectedJson = "{\"sub\":\"" + subjectDid + "\",\"vc\":{\"id\":\"" + expectedUuid + "\"}}"; -// when(objectMapper.writeValueAsString(any())).thenReturn(expectedJson); -// -// StepVerifier.create(verifiableCredentialService.generateVcPayLoad(vcTemplate, subjectDid, issuerDid, userData, expiration)) -// .expectNext(expectedJson) -// .verifyComplete(); -// } -// -// @Test -// void testGenerateDeferredVcPayLoad() throws JsonProcessingException { -// String vcTemplate = """ -// { -// "id": "test-id", -// "issuer": "did:example:123", -// "credentialSubject": { -// "mandate": { -// "mandatee": { -// "id": "did:example:456", -// "name": "Joe" -// } -// } -// }, -// "validFrom": "2024-01-01T00:00:00Z", -// "expirationDate": "2024-01-02T00:00:00Z" -// } -// """; -// -// -// // Create real ObjectMapper for node creation -// ObjectMapper realMapper = new ObjectMapper(); -// -// JsonNode mockVcTemplateNode = realMapper.readTree(vcTemplate); -// when(objectMapper.readTree(vcTemplate)).thenReturn(mockVcTemplateNode); -// -// String expectedJson = "{\"sub\":\"did:example:456\",\"nbf\":\"2024-01-01T00:00:00Z\",\"iss\":\"did:example:123\",\"exp\":\"2024-01-02T00:00:00Z\",\"iat\":\"2024-01-01T00:00:00Z\",\"jti\":\"test-id\",\"vc\":" + vcTemplate + "}"; -// when(objectMapper.writeValueAsString(any())).thenReturn(expectedJson); -// when(objectMapper.createObjectNode()).thenAnswer(invocation -> realMapper.createObjectNode()); -// -// StepVerifier.create(verifiableCredentialService.generateDeferredCredentialResponse(vcTemplate)) -// .expectNext(expectedJson) -// .verifyComplete(); -// } -// -// -// @Test -// void testGenerateVc() throws JsonProcessingException { -// String vcTemplate = "{\"issuer\":\"did:example:123\"}"; -// String subjectDid = "did:example:456"; -// String issuerDid = "did:example:123"; -// String userData = """ -// { -// "mandate": { -// "mandatee": { -// "id": "did:example:456", -// "name": "Joe" -// } -// } -// } -// """; -// Instant expiration = Instant.now().plusSeconds(3600); -// -// ObjectNode mandateeNode = new ObjectMapper().createObjectNode().put("id", "did:example:456"); -// mandateeNode.put("name", "Joe"); -// JsonNode mandateNode = new ObjectMapper().createObjectNode().set("mandatee", mandateeNode); -// JsonNode mockUserDataNode = new ObjectMapper().createObjectNode().set("mandate", mandateNode); -// JsonNode mockVcTemplateNode = new ObjectMapper().createObjectNode().put("issuer", issuerDid); -// -// when(objectMapper.readTree(vcTemplate)).thenReturn(mockVcTemplateNode); -// when(objectMapper.readTree(userData)).thenReturn(mockUserDataNode); -// -// // Set up additional mock for the final serialization -// String expectedJson = "{\"id\":\"urn:uuid:\",\"issuer\":\"did:example:123\",\"issuanceDate\":\"\",\"validFrom\":\"\",\"expirationDate\":\"\",\"credentialSubject\":{\"mandate\":\"did:example:456\",\"name\":\"John Doe\"}}"; -// when(objectMapper.writeValueAsString(any())).thenReturn(expectedJson.replace("", UUID.randomUUID().toString()).replace("", Instant.now().toString())); -// -// StepVerifier.create(verifiableCredentialService.retrieveVcAndBindMandateeId(vcTemplate, subjectDid, issuerDid, userData, expiration)) -// .expectNextMatches(json -> json.contains("John Doe") && json.contains(subjectDid)) -// .verifyComplete(); -// } -// -// -//} \ No newline at end of file +package es.in2.issuer.domain.service; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import es.in2.issuer.domain.model.dto.*; +import es.in2.issuer.domain.service.impl.VerifiableCredentialServiceImpl; +import es.in2.issuer.domain.util.factory.CredentialFactory; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class VerifiableCredentialServiceImplTest { + + private final String processId = "process-id-123"; + private final String preAuthCode = "pre-auth-code-456"; + private final String transactionId = "transaction-id-789"; + private final String deferredResponseId = "deferred-response-id-456"; + private final String procedureId = "procedure-id-321"; + private final String vcValue = "vc-value-123"; + @Mock + private DeferredCredentialMetadataService deferredCredentialMetadataService; + @Mock + private CredentialFactory credentialFactory; + @Mock + private CredentialProcedureService credentialProcedureService; + @Mock + private ObjectMapper objectMapper; + @InjectMocks + private VerifiableCredentialServiceImpl verifiableCredentialServiceImpl; + + @Test + void bindAccessTokenByPreAuthorizedCode_Success() { + // Arrange: Mock the service to return a Mono.empty() + String expectedJti = "expected-jti-value"; + when(deferredCredentialMetadataService.updateAuthServerNonceByAuthServerNonce(expectedJti, preAuthCode)) + .thenReturn(Mono.empty()); + + // Act: Call the method + String validAccessToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJleHBlY3RlZC1qdGktdmFsdWUifQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; + Mono result = verifiableCredentialServiceImpl.bindAccessTokenByPreAuthorizedCode(processId, validAccessToken, preAuthCode); + + // Assert: Verify the interactions and result + StepVerifier.create(result) + .verifyComplete(); + + verify(deferredCredentialMetadataService, times(1)) + .updateAuthServerNonceByAuthServerNonce(expectedJti, preAuthCode); + } + + @Test + void bindAccessTokenByPreAuthorizedCode_InvalidToken_ThrowsException() { + // Arrange: Use an invalid JWT token + String invalidAccessToken = "invalid-token"; + + // Act and Assert + RuntimeException exception = assertThrows(RuntimeException.class, () -> { + verifiableCredentialServiceImpl.bindAccessTokenByPreAuthorizedCode(processId, invalidAccessToken, preAuthCode).block(); + }); + assertNull(exception.getMessage()); + + // Verify that no interaction with deferredCredentialMetadataService happens + verify(deferredCredentialMetadataService, times(0)) + .updateAuthServerNonceByAuthServerNonce(anyString(), anyString()); + } + + @Test + void generateVc_Success() throws Exception { + // Arrange: Create a sample JsonNode for LEARCredentialRequest + JsonNode credentialJsonNode = objectMapper.readTree("{\"credentialId\":\"cred-id-123\", \"organizationIdentifier\":\"org-id-123\", \"credentialDecoded\":\"decoded-credential\"}"); + LEARCredentialRequest learCredentialRequest = LEARCredentialRequest.builder() + .credential(credentialJsonNode) + .build(); + + // Mock the behavior of credentialFactory + CredentialProcedureCreationRequest mockCreationRequest = CredentialProcedureCreationRequest.builder() + .credentialId("cred-id-123") + .organizationIdentifier("org-id-123") + .credentialDecoded("decoded-credential") + .build(); + String vcType = "vc-type-789"; + when(credentialFactory.mapCredentialIntoACredentialProcedureRequest(processId, vcType, credentialJsonNode)) + .thenReturn(Mono.just(mockCreationRequest)); + + // Mock the behavior of credentialProcedureService + String createdProcedureId = "created-procedure-id-456"; + when(credentialProcedureService.createCredentialProcedure(mockCreationRequest)) + .thenReturn(Mono.just(createdProcedureId)); + + // Mock the behavior of deferredCredentialMetadataService + String metadataId = "metadata-id-789"; + when(deferredCredentialMetadataService.createDeferredCredentialMetadata(createdProcedureId)) + .thenReturn(Mono.just(metadataId)); + + // Act: Call the generateVc method + Mono result = verifiableCredentialServiceImpl.generateVc(processId, vcType, learCredentialRequest); + + // Assert: Verify the result + StepVerifier.create(result) + .expectNext(metadataId) + .verifyComplete(); + + // Verify that all the interactions occurred as expected + verify(credentialFactory, times(1)) + .mapCredentialIntoACredentialProcedureRequest(processId, vcType, credentialJsonNode); + + verify(credentialProcedureService, times(1)) + .createCredentialProcedure(mockCreationRequest); + + verify(deferredCredentialMetadataService, times(1)) + .createDeferredCredentialMetadata(createdProcedureId); + } + + @Test + void generateDeferredCredentialResponse_WithVcPresent() { + // Arrange: Create the request and mock response + DeferredCredentialRequest deferredCredentialRequest = DeferredCredentialRequest.builder() + .transactionId(transactionId) + .build(); + + DeferredCredentialMetadataDeferredResponse mockResponseWithVc = DeferredCredentialMetadataDeferredResponse.builder() + .id(deferredResponseId) + .procedureId(procedureId) + .transactionId(transactionId) + .vc(vcValue) + .build(); + + // Mock the service methods + when(deferredCredentialMetadataService.getVcByTransactionId(transactionId)) + .thenReturn(Mono.just(mockResponseWithVc)); + when(credentialProcedureService.updateCredentialProcedureCredentialStatusToValidByProcedureId(procedureId)) + .thenReturn(Mono.empty()); + when(deferredCredentialMetadataService.deleteDeferredCredentialMetadataById(deferredResponseId)) + .thenReturn(Mono.empty()); + + // Act: Call the method + Mono result = verifiableCredentialServiceImpl.generateDeferredCredentialResponse(processId, deferredCredentialRequest); + + // Assert: Verify the result + StepVerifier.create(result) + .expectNextMatches(response -> + response.credential().equals(vcValue) && response.transactionId() == null) + .verifyComplete(); + + // Verify the interactions + verify(deferredCredentialMetadataService, times(1)) + .getVcByTransactionId(transactionId); + verify(credentialProcedureService, times(1)) + .updateCredentialProcedureCredentialStatusToValidByProcedureId((procedureId)); + verify(deferredCredentialMetadataService, times(1)) + .deleteDeferredCredentialMetadataById(deferredResponseId); + } + + @Test + void generateDeferredCredentialResponse_WithVcAbsent() { + // Arrange: Create the request and mock response + DeferredCredentialRequest deferredCredentialRequest = DeferredCredentialRequest.builder() + .transactionId(transactionId) + .build(); + + DeferredCredentialMetadataDeferredResponse mockResponseWithoutVc = DeferredCredentialMetadataDeferredResponse.builder() + .id(deferredResponseId) + .procedureId(procedureId) + .transactionId(transactionId) + .vc(null) // No VC present + .build(); + + // Mock the service methods + when(deferredCredentialMetadataService.getVcByTransactionId(transactionId)) + .thenReturn(Mono.just(mockResponseWithoutVc)); + + // Act: Call the method + Mono result = verifiableCredentialServiceImpl.generateDeferredCredentialResponse(processId, deferredCredentialRequest); + + // Assert: Verify the result + StepVerifier.create(result) + .expectNextMatches(response -> + response.transactionId().equals(transactionId) && response.credential() == null) + .verifyComplete(); + + // Verify the interactions + verify(deferredCredentialMetadataService, times(1)) + .getVcByTransactionId(transactionId); + verify(credentialProcedureService, times(0)) + .updateCredentialProcedureCredentialStatusToValidByProcedureId(anyString()); + verify(deferredCredentialMetadataService, times(0)) + .deleteDeferredCredentialMetadataById(anyString()); + } + + @Test + void buildCredentialResponse_Success() throws Exception { + // Mock the behavior of ObjectMapper to parse the JSON string into JsonNode + when(objectMapper.readTree(anyString())).thenAnswer(invocation -> { + String json = invocation.getArgument(0, String.class); + return new ObjectMapper().readTree(json); // Use a new ObjectMapper to parse the string + }); + + // Mock the behavior of ObjectMapper to convert JsonNode to LEARCredentialEmployee + when(objectMapper.treeToValue(any(JsonNode.class), eq(LEARCredentialEmployee.class))) + .thenAnswer(invocation -> { + JsonNode node = invocation.getArgument(0, JsonNode.class); + return new ObjectMapper().treeToValue(node, LEARCredentialEmployee.class); // Use a new ObjectMapper to do the conversion + }); + + // Mock the behavior of ObjectMapper to convert LEARCredentialEmployee to JSON string + when(objectMapper.writeValueAsString(any(LEARCredentialEmployee.class))) + .thenAnswer(invocation -> { + LEARCredentialEmployee credential = invocation.getArgument(0, LEARCredentialEmployee.class); + return new ObjectMapper().writeValueAsString(credential); // Use a new ObjectMapper to do the conversion + }); + + // Arrange: Mock the service methods + String authServerNonce = "auth-server-nonce-789"; + when(deferredCredentialMetadataService.getProcedureIdByAuthServerNonce(authServerNonce)) + .thenReturn(Mono.just(procedureId)); + + String credentialType = "credential-type-123"; + when(credentialProcedureService.getCredentialTypeByProcedureId(procedureId)) + .thenReturn(Mono.just(credentialType)); + + String decodedCredential = "{\"vc\":{\"@context\":[\"https://www.w3.org/2018/credentials/v1\"],\"id\":\"example-id\",\"type\":[\"VerifiableCredential\",\"LEARCredentialEmployee\"],\"credentialSubject\":{\"mandate\":{\"id\":\"mandate-id\",\"life_span\":{\"end_date_time\":\"2024-12-31T23:59:59Z\",\"start_date_time\":\"2023-01-01T00:00:00Z\"},\"mandatee\":{\"id\":\"mandatee-id\",\"email\":\"mandatee@example.com\",\"first_name\":\"John\",\"last_name\":\"Doe\",\"mobile_phone\":\"+123456789\"},\"mandator\":{\"commonName\":\"Company ABC\",\"country\":\"Country XYZ\",\"emailAddress\":\"mandator@example.com\",\"organization\":\"Org ABC\",\"organizationIdentifier\":\"org-123\",\"serialNumber\":\"1234567890\"},\"power\":[{\"id\":\"power-id\",\"tmf_action\":\"action\",\"tmf_domain\":\"domain\",\"tmf_function\":\"function\",\"tmf_type\":\"type\"}]}}},\"expirationDate\":\"2024-12-31T23:59:59Z\",\"issuanceDate\":\"2023-01-01T00:00:00Z\",\"issuer\":\"did:example:issuer\",\"validFrom\":\"2023-01-01T00:00:00Z\"}}"; + when(credentialProcedureService.getDecodedCredentialByProcedureId(procedureId)) + .thenReturn(Mono.just(decodedCredential)); + + String subjectDid = "did:example:123456789"; + String bindCredential = "{\"vc\":{\"@context\":[\"https://www.w3.org/2018/credentials/v1\"],\"id\":\"example-id\",\"type\":[\"VerifiableCredential\",\"LEARCredentialEmployee\"],\"credentialSubject\":{\"mandate\":{\"id\":\"mandate-id\",\"life_span\":{\"end_date_time\":\"2024-12-31T23:59:59Z\",\"start_date_time\":\"2023-01-01T00:00:00Z\"},\"mandatee\":{\"id\":\"mandatee-id\",\"email\":\"mandatee@example.com\",\"first_name\":\"John\",\"last_name\":\"Doe\",\"mobile_phone\":\"+123456789\"},\"mandator\":{\"commonName\":\"Company ABC\",\"country\":\"Country XYZ\",\"emailAddress\":\"mandator@example.com\",\"organization\":\"Org ABC\",\"organizationIdentifier\":\"org-123\",\"serialNumber\":\"1234567890\"},\"power\":[{\"id\":\"power-id\",\"tmf_action\":\"action\",\"tmf_domain\":\"domain\",\"tmf_function\":\"function\",\"tmf_type\":\"type\"}]}}},\"expirationDate\":\"2024-12-31T23:59:59Z\",\"issuanceDate\":\"2023-01-01T00:00:00Z\",\"issuer\":\"did:example:issuer\",\"validFrom\":\"2023-01-01T00:00:00Z\"}}"; + when(credentialFactory.mapCredentialAndBindMandateeId(processId, credentialType, decodedCredential, subjectDid)) + .thenReturn(Mono.just(bindCredential)); + + String format = "json"; + when(credentialProcedureService.updateDecodedCredentialByProcedureId(procedureId, bindCredential, format)) + .thenReturn(Mono.empty()); + + when(deferredCredentialMetadataService.updateDeferredCredentialMetadataByAuthServerNonce(authServerNonce, format)) + .thenReturn(Mono.just(transactionId)); + + // Act: Call the method + Mono result = verifiableCredentialServiceImpl.buildCredentialResponse(processId, subjectDid, authServerNonce, format); + + // Convert the bindCredential JSON string to LEARCredentialEmployee + JsonNode vcNode = objectMapper.readTree(bindCredential).get("vc"); + LEARCredentialEmployee learCredential = objectMapper.treeToValue(vcNode, LEARCredentialEmployee.class); + + // Log the intermediate LEARCredentialEmployee object for debugging + System.out.println("Parsed LEARCredentialEmployee: " + learCredential); + + // Convert the LEARCredentialEmployee to JSON string for expected value + String expectedCredentialJson = objectMapper.writeValueAsString(learCredential); + + // Log the expected credential JSON for debugging + System.out.println("Expected Credential JSON: " + expectedCredentialJson); + + // Assert: Verify the result + StepVerifier.create(result) + .expectNextMatches(response -> { + // Log the response for debugging + System.out.println("Response: " + response); + return response.credential().equals(expectedCredentialJson) && + response.transactionId().equals(transactionId); + }) + .verifyComplete(); + + // Verify the interactions + verify(deferredCredentialMetadataService, times(1)) + .getProcedureIdByAuthServerNonce(authServerNonce); + + verify(credentialProcedureService, times(1)) + .getCredentialTypeByProcedureId(procedureId); + + verify(credentialProcedureService, times(1)) + .getDecodedCredentialByProcedureId(procedureId); + + verify(credentialFactory, times(1)) + .mapCredentialAndBindMandateeId(processId, credentialType, decodedCredential, subjectDid); + + verify(credentialProcedureService, times(1)) + .updateDecodedCredentialByProcedureId(procedureId, bindCredential, format); + + verify(deferredCredentialMetadataService, times(1)) + .updateDeferredCredentialMetadataByAuthServerNonce(authServerNonce, format); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/util/EndpointsConstantsTest.java b/src/test/java/es/in2/issuer/domain/util/EndpointsConstantsTest.java new file mode 100644 index 000000000..414689d32 --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/util/EndpointsConstantsTest.java @@ -0,0 +1,19 @@ +package es.in2.issuer.domain.util; + +import org.junit.jupiter.api.Test; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +class EndpointsConstantsTest { + @Test + void testPrivateConstructorThrowsException() throws NoSuchMethodException { + Constructor constructor = EndpointsConstants.class.getDeclaredConstructor(); + + constructor.setAccessible(true); + + assertThrows(InvocationTargetException.class, constructor::newInstance); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/util/HttpUtilsTest.java b/src/test/java/es/in2/issuer/domain/util/HttpUtilsTest.java index 6c5f84996..b5e2dbb78 100644 --- a/src/test/java/es/in2/issuer/domain/util/HttpUtilsTest.java +++ b/src/test/java/es/in2/issuer/domain/util/HttpUtilsTest.java @@ -4,22 +4,28 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullSource; import org.junit.jupiter.params.provider.ValueSource; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.web.reactive.function.client.ClientResponse; import org.springframework.web.reactive.function.client.WebClient; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; +import java.util.AbstractMap; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.function.Consumer; +import java.util.function.Function; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -53,9 +59,9 @@ void testGetRequest() { when(webClient.get()).thenReturn(requestHeadersUriSpec); when(requestHeadersUriSpec.uri(url)).thenReturn(requestHeadersSpec); - when(requestHeadersSpec.headers(Mockito.any(Consumer.class))).thenReturn(requestHeadersSpec); + when(requestHeadersSpec.headers(any(Consumer.class))).thenReturn(requestHeadersSpec); when(requestHeadersSpec.retrieve()).thenReturn(responseSpec); - when(responseSpec.onStatus(Mockito.any(), Mockito.any())).thenReturn(responseSpec); + when(responseSpec.onStatus(any(), any())).thenReturn(responseSpec); when(responseSpec.bodyToMono(String.class)).thenReturn(Mono.just(responseBody)); Mono result = httpUtils.getRequest(url, headers); @@ -66,22 +72,30 @@ void testGetRequest() { } @Test - void testGetRequestErrorStatus() throws RuntimeException { + void testGetRequestErrorStatus() { + //Arrange String url = "https://example.com"; List> headers = Collections.emptyList(); WebClient.RequestHeadersUriSpec requestHeadersUriSpec = mock(WebClient.RequestHeadersUriSpec.class); WebClient.RequestHeadersSpec requestHeadersSpec = mock(WebClient.RequestHeadersSpec.class); WebClient.ResponseSpec responseSpec = mock(WebClient.ResponseSpec.class); + ClientResponse clientResponse = mock(ClientResponse.class); when(webClient.get()).thenReturn(requestHeadersUriSpec); when(requestHeadersUriSpec.uri(url)).thenReturn(requestHeadersSpec); - when(requestHeadersSpec.headers(Mockito.any(Consumer.class))).thenReturn(requestHeadersSpec); + when(requestHeadersSpec.headers(any(Consumer.class))).thenReturn(requestHeadersSpec); when(requestHeadersSpec.retrieve()).thenReturn(responseSpec); + when(responseSpec.onStatus(argThat(predicate -> predicate.test(HttpStatus.BAD_REQUEST)), any())).thenAnswer(invocation -> { + Function> function = invocation.getArgument(1); + return function.apply(clientResponse); + }); - assertThrows(RuntimeException.class, () -> httpUtils.getRequest(url, headers)); + // Act & Assert + assertThrows(RuntimeException.class, () -> httpUtils.getRequest(url, headers).block()); } + @Test void testPostRequest() { String url = "https://example.com"; @@ -97,10 +111,10 @@ void testPostRequest() { when(webClient.post()).thenReturn(requestBodyUriSpec); when(requestBodyUriSpec.uri(url)).thenReturn(requestBodySpec); - when(requestBodySpec.headers(Mockito.any())).thenReturn(requestBodySpec); + when(requestBodySpec.headers(any())).thenReturn(requestBodySpec); when(requestBodySpec.bodyValue(body)).thenReturn(requestHeadersSpec); when(requestHeadersSpec.retrieve()).thenReturn(responseSpec); - when(responseSpec.onStatus(Mockito.any(), Mockito.any())).thenReturn(responseSpec); + when(responseSpec.onStatus(any(), any())).thenReturn(responseSpec); when(responseSpec.bodyToMono(String.class)).thenReturn(Mono.just(responseBody)); Mono result = httpUtils.postRequest(url, headers, body); @@ -121,13 +135,19 @@ void testPostRequestErrorStatus() { WebClient.RequestBodySpec requestBodySpec = mock(WebClient.RequestBodySpec.class); WebClient.RequestHeadersSpec requestHeadersSpec = mock(WebClient.RequestHeadersSpec.class); WebClient.ResponseSpec responseSpec = mock(WebClient.ResponseSpec.class); + ClientResponse clientResponse = mock(ClientResponse.class); when(webClient.post()).thenReturn(requestBodyUriSpec); when(requestBodyUriSpec.uri(url)).thenReturn(requestBodySpec); - when(requestBodySpec.headers(Mockito.any())).thenReturn(requestBodySpec); + when(requestBodySpec.headers(any())).thenReturn(requestBodySpec); when(requestBodySpec.bodyValue(body)).thenReturn(requestHeadersSpec); when(requestHeadersSpec.retrieve()).thenReturn(responseSpec); + when(responseSpec.onStatus(argThat(predicate -> predicate.test(HttpStatus.BAD_REQUEST)), any())).thenAnswer(invocation -> { + Function> function = invocation.getArgument(1); + return function.apply(clientResponse); + }); + // Act & Assert assertThrows(RuntimeException.class, () -> httpUtils.postRequest(url, headers, body)); } @@ -147,4 +167,32 @@ void ensureUrlHasProtocol_ReturnsUrlWithHttpsProtocol(String url) { } } -} + @ParameterizedTest + @NullSource + void ensureUrlHasProtocol_NullInput_ReturnsNull(String url) { + // When + String result = HttpUtils.ensureUrlHasProtocol(url); + + // Then + assertNull(result); + } + + @Test + void testPrepareHeadersWithAuth() { + // Arrange + String token = "test-token"; + Map.Entry expectedHeader = new AbstractMap.SimpleEntry<>(HttpHeaders.AUTHORIZATION, "Bearer " + token); + + // Act + Mono>> result = httpUtils.prepareHeadersWithAuth(token); + + // Assert + StepVerifier.create(result) + .assertNext(headers -> { + assertEquals(1, headers.size()); + assertEquals(expectedHeader, headers.get(0)); + }) + .verifyComplete(); + } + +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/util/UtilsTest.java b/src/test/java/es/in2/issuer/domain/util/UtilsTest.java new file mode 100644 index 000000000..4ad558e3d --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/util/UtilsTest.java @@ -0,0 +1,32 @@ +package es.in2.issuer.domain.util; + +import org.junit.jupiter.api.Test; +import reactor.test.StepVerifier; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.Base64; + +import static org.junit.jupiter.api.Assertions.*; + +class UtilsTest { + @Test + void testPrivateConstructorThrowsException() throws NoSuchMethodException { + Constructor constructor = Utils.class.getDeclaredConstructor(); + constructor.setAccessible(true); + InvocationTargetException invocationTargetException = assertThrows(InvocationTargetException.class, constructor::newInstance); + assertInstanceOf(IllegalStateException.class, invocationTargetException.getCause()); + assertEquals("Utility class", invocationTargetException.getCause().getMessage()); + } + + @Test + void testGenerateCustomNonce() { + StepVerifier.create(Utils.generateCustomNonce()) + .assertNext(nonce -> { + assertNotNull(nonce); + assertFalse(nonce.isEmpty()); + assertDoesNotThrow(() -> Base64.getUrlDecoder().decode(nonce)); + }) + .verifyComplete(); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/util/factory/CredentialFactoryTest.java b/src/test/java/es/in2/issuer/domain/util/factory/CredentialFactoryTest.java new file mode 100644 index 000000000..5ebeac86c --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/util/factory/CredentialFactoryTest.java @@ -0,0 +1,94 @@ +package es.in2.issuer.domain.util.factory; + +import com.fasterxml.jackson.databind.JsonNode; +import es.in2.issuer.domain.exception.CredentialTypeUnsupportedException; +import es.in2.issuer.domain.model.dto.CredentialProcedureCreationRequest; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class CredentialFactoryTest { + + @Mock + private LEARCredentialEmployeeFactory learCredentialEmployeeFactory; + + @InjectMocks + private CredentialFactory credentialFactory; + + @Test + void testMapCredentialIntoACredentialProcedureRequest_Success() { + //Arrange + String processId = "processId"; + String credentialType = "LEARCredentialEmployee"; + JsonNode jsonNode = mock(JsonNode.class); + CredentialProcedureCreationRequest credentialProcedureCreationRequest = mock(CredentialProcedureCreationRequest.class); + + when(learCredentialEmployeeFactory.mapAndBuildLEARCredentialEmployee(jsonNode)) + .thenReturn(Mono.just(credentialProcedureCreationRequest)); + + //Act & Assert + StepVerifier.create(credentialFactory.mapCredentialIntoACredentialProcedureRequest(processId, credentialType, jsonNode)) + .expectNext(credentialProcedureCreationRequest) + .verifyComplete(); + + verify(learCredentialEmployeeFactory).mapAndBuildLEARCredentialEmployee(jsonNode); + } + + @Test + void testMapCredentialIntoACredentialProcedureRequest_Failure() { + //Arrange + String processId = "processId"; + String credentialType = "UNSUPPORTED_CREDENTIAL"; + JsonNode jsonNode = mock(JsonNode.class); + + //Act & Assert + StepVerifier.create(credentialFactory.mapCredentialIntoACredentialProcedureRequest(processId, credentialType, jsonNode)) + .expectError(CredentialTypeUnsupportedException.class) + .verify(); + + verify(learCredentialEmployeeFactory, never()).mapAndBuildLEARCredentialEmployee(any()); + } + + @Test + void testMapCredentialAndBindMandateeId_Success() { + //Arrange + String processId = "processId"; + String credentialType = "LEARCredentialEmployee"; + String credential = "credential"; + String mandateeId = "mandateeId"; + String result = "result"; + + when(learCredentialEmployeeFactory.mapCredentialAndBindMandateeIdInToTheCredential(credential, mandateeId)) + .thenReturn(Mono.just(result)); + + //Act & Assert + StepVerifier.create(credentialFactory.mapCredentialAndBindMandateeId(processId, credentialType, credential, mandateeId)) + .expectNext(result) + .verifyComplete(); + + verify(learCredentialEmployeeFactory).mapCredentialAndBindMandateeIdInToTheCredential(credential, mandateeId); + } + + @Test + void testMapCredentialAndBindMandateeId_Failure() { + //Arrange + String processId = "processId"; + String credentialType = "UNSUPPORTED_CREDENTIAL"; + String credential = "credential"; + String mandateeId = "mandateeId"; + + //Act & Assert + StepVerifier.create(credentialFactory.mapCredentialAndBindMandateeId(processId, credentialType, credential, mandateeId)) + .expectError(CredentialTypeUnsupportedException.class) + .verify(); + + verify(learCredentialEmployeeFactory, never()).mapCredentialAndBindMandateeIdInToTheCredential(anyString(), anyString()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/domain/util/factory/LEARCredentialEmployeeFactoryTest.java b/src/test/java/es/in2/issuer/domain/util/factory/LEARCredentialEmployeeFactoryTest.java new file mode 100644 index 000000000..86124b373 --- /dev/null +++ b/src/test/java/es/in2/issuer/domain/util/factory/LEARCredentialEmployeeFactoryTest.java @@ -0,0 +1,108 @@ +package es.in2.issuer.domain.util.factory; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import es.in2.issuer.domain.model.dto.CredentialProcedureCreationRequest; +import es.in2.issuer.domain.model.dto.LEARCredentialEmployee; +import es.in2.issuer.domain.model.dto.LEARCredentialEmployeeJwtPayload; +import es.in2.issuer.domain.service.AccessTokenService; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.util.ArrayList; +import java.util.List; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class LEARCredentialEmployeeFactoryTest { + + @Mock + private ObjectMapper objectMapper; + + @Mock + private AccessTokenService accessTokenService; + + @InjectMocks + private LEARCredentialEmployeeFactory learCredentialEmployeeFactory; + + @Test + void testMapCredentialAndBindMandateeIdInToTheCredential() throws JsonProcessingException { + //Arrange + String learCredential = "validCredentialString"; + String mandateeId = "mandateeId"; + String expectedString = "expectedString"; + LEARCredentialEmployeeJwtPayload learCredentialEmployeeJwtPayload = mock(LEARCredentialEmployeeJwtPayload.class); + LEARCredentialEmployee learCredentialEmployee = mock(LEARCredentialEmployee.class); + LEARCredentialEmployee.CredentialSubject credentialSubject = mock(LEARCredentialEmployee.CredentialSubject.class); + LEARCredentialEmployee.CredentialSubject.Mandate mandate = mock(LEARCredentialEmployee.CredentialSubject.Mandate.class); + LEARCredentialEmployee.CredentialSubject.Mandate.Mandator mandator = mock(LEARCredentialEmployee.CredentialSubject.Mandate.Mandator.class); + LEARCredentialEmployee.CredentialSubject.Mandate.Mandatee mandatee = mock(LEARCredentialEmployee.CredentialSubject.Mandate.Mandatee.class); + + when(objectMapper.readValue(learCredential, LEARCredentialEmployeeJwtPayload.class)).thenReturn(learCredentialEmployeeJwtPayload); + when(learCredentialEmployeeJwtPayload.learCredentialEmployee()).thenReturn(learCredentialEmployee); + when(learCredentialEmployeeJwtPayload.learCredentialEmployee().credentialSubject()).thenReturn(credentialSubject); + when(credentialSubject.mandate()).thenReturn(mandate); + when(mandate.id()).thenReturn("mandateeId"); + when(mandate.mandator()).thenReturn(mandator); + when(mandate.mandatee()).thenReturn(mandatee); + when(mandatee.email()).thenReturn("email"); + when(mandatee.firstName()).thenReturn("firstName"); + when(mandatee.lastName()).thenReturn("lastName"); + when(mandatee.mobilePhone()).thenReturn("mobilePhone"); + when(mandate.power()).thenReturn(List.of(LEARCredentialEmployee.CredentialSubject.Mandate.Power.builder().build())); + when(mandate.lifeSpan()).thenReturn(LEARCredentialEmployee.CredentialSubject.Mandate.LifeSpan.builder().build()); + when(learCredentialEmployeeJwtPayload.JwtId()).thenReturn("jwtId"); + when(learCredentialEmployeeJwtPayload.expirationTime()).thenReturn(0L); + when(learCredentialEmployeeJwtPayload.issuedAt()).thenReturn(0L); + when(learCredentialEmployeeJwtPayload.issuer()).thenReturn("issuer"); + when(learCredentialEmployeeJwtPayload.notValidBefore()).thenReturn(0L); + when(objectMapper.writeValueAsString(any(LEARCredentialEmployeeJwtPayload.class))).thenReturn(expectedString); + + //Act & Assert + StepVerifier.create(learCredentialEmployeeFactory.mapCredentialAndBindMandateeIdInToTheCredential(learCredential, mandateeId)) + .expectNext(expectedString) + .verifyComplete(); + } + + @Test + void testMapAndBuildLEARCredentialEmployee() throws JsonProcessingException { + //Arrange + String json = "{\"test\": \"test\"}"; + JsonNode jsonNode = objectMapper.readTree(json); + LEARCredentialEmployee.CredentialSubject.Mandate mockMandate = mock(LEARCredentialEmployee.CredentialSubject.Mandate.class); + LEARCredentialEmployee.CredentialSubject.Mandate.Mandator mockMandator = mock(LEARCredentialEmployee.CredentialSubject.Mandate.Mandator.class); + LEARCredentialEmployee.CredentialSubject.Mandate.Mandatee mockMandatee = mock(LEARCredentialEmployee.CredentialSubject.Mandate.Mandatee.class); + LEARCredentialEmployee.CredentialSubject.Mandate.Power mockPower = mock(LEARCredentialEmployee.CredentialSubject.Mandate.Power.class); + + List mockPowerList = new ArrayList<>(); + mockPowerList.add(mockPower); + + when(objectMapper.convertValue(jsonNode, LEARCredentialEmployee.CredentialSubject.Mandate.class)) + .thenReturn(mockMandate); + when(mockMandate.mandator()).thenReturn(mockMandator); + when(mockMandator.organizationIdentifier()).thenReturn("orgId"); + when(mockMandate.mandatee()).thenReturn(mockMandatee); + when(mockMandate.power()).thenReturn(mockPowerList); + when(mockMandatee.id()).thenReturn("mandateeId"); + when(objectMapper.writeValueAsString(any(LEARCredentialEmployeeJwtPayload.class))).thenReturn(json); + when(accessTokenService.getOrganizationIdFromCurrentSession()).thenReturn(Mono.just("orgId")); + + // Act + Mono result = learCredentialEmployeeFactory.mapAndBuildLEARCredentialEmployee(jsonNode); + + //Assert + StepVerifier.create(result) + .expectNextCount(1) + .verifyComplete(); + } + +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/infrastructure/config/AppConfigTest.java b/src/test/java/es/in2/issuer/infrastructure/config/AppConfigTest.java index 2fe375d5c..4b5d63617 100644 --- a/src/test/java/es/in2/issuer/infrastructure/config/AppConfigTest.java +++ b/src/test/java/es/in2/issuer/infrastructure/config/AppConfigTest.java @@ -3,110 +3,109 @@ import es.in2.issuer.infrastructure.config.adapter.ConfigAdapter; import es.in2.issuer.infrastructure.config.adapter.factory.ConfigAdapterFactory; import es.in2.issuer.infrastructure.config.properties.ApiProperties; +import es.in2.issuer.infrastructure.config.properties.IssuerUiProperties; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.jupiter.MockitoExtension; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; +@ExtendWith(MockitoExtension.class) class AppConfigTest { @Mock private ConfigAdapterFactory configAdapterFactory; + @Mock + private ConfigAdapter configAdapter; + @Mock private ApiProperties apiProperties; @Mock - private ConfigAdapter configAdapter; + private IssuerUiProperties issuerUiProperties; private AppConfig appConfig; -// @BeforeEach -// public void setUp() { -// MockitoAnnotations.openMocks(this); -// when(configAdapterFactory.getAdapter()).thenReturn(configAdapter); -// appConfig = new AppConfig(configAdapterFactory, apiProperties); -// } - -// @Test -// void testGetKeycloakDomain() { -// String expected = "keycloak-domain"; -// when(apiProperties.iamInternalDomain()).thenReturn("keycloak.domain"); -// when(configAdapter.getConfiguration("keycloak.domain")).thenReturn(expected); -// assertEquals(expected, apiConfig.getIamInternalDomain()); -// } - -// @Test -// void testGetIssuerDomain() { -// String expected = "issuer-domain"; -// when(apiProperties.issuerExternalDomain()).thenReturn("issuer.domain"); -// when(configAdapter.getConfiguration("issuer.domain")).thenReturn(expected); -// assertEquals(expected, apiConfig.getIssuerExternalDomain()); -// } - -// @Test -// void testGetAuthenticSourcesDomain() { -// String expected = "authentic-sources-domain"; -// when(apiProperties.authenticSourcesDomain()).thenReturn("authentic.sources.domain"); -// when(configAdapter.getConfiguration("authentic.sources.domain")).thenReturn(expected); -// assertEquals(expected, apiConfig.getAuthenticSourcesDomain()); -// } - -// @Test -// void testGetKeyVaultDomain() { -// String expected = "key-vault-domain"; -// when(apiProperties.keyVaultDomain()).thenReturn("key.vault.domain"); -// when(configAdapter.getConfiguration("key.vault.domain")).thenReturn(expected); -// assertEquals(expected, apiConfig.getKeyVaultDomain()); -// } - -// @Test -// void testGetRemoteSignatureDomain() { -// String expected = "remote-signature-domain"; -// when(apiProperties.remoteSignatureDomain()).thenReturn("remote.signature.domain"); -// when(configAdapter.getConfiguration("remote.signature.domain")).thenReturn(expected); -// assertEquals(expected, apiConfig.getRemoteSignatureDomain()); -// } - -// @Test -// void testGetIssuerDid() { -// String expected = "issuer-did"; -// when(apiProperties.issuerDid()).thenReturn("issuer.did"); -// when(configAdapter.getConfiguration("issuer.did")).thenReturn(expected); -// assertEquals(expected, apiConfig.getIssuerDid()); -// } - -// @Test -// void testGetJwtDecoderPath() { -// String expected = "jwt-decoder-path"; -// when(apiProperties.jwtDecoderPath()).thenReturn("jwt.decoder.path"); -// when(configAdapter.getConfiguration("jwt.decoder.path")).thenReturn(expected); -// assertEquals(expected, apiConfig.getJwtDecoderPath()); -// } - -// @Test -// void testGetJwtDecoderLocalPath() { -// String expected = "jwt-decoder-local-path"; -// when(apiProperties.jwtDecoderLocalPath()).thenReturn("jwt.decoder.local.path"); -// when(configAdapter.getConfiguration("jwt.decoder.local.path")).thenReturn(expected); -// assertEquals(expected, apiConfig.getJwtDecoderLocalPath()); -// } - -// @Test -// void testGetPreAuthCodeUriTemplate() { -// String expected = "pre-auth-code-uri-template"; -// when(apiProperties.preAuthCodeUriTemplate()).thenReturn("pre.auth.code.uri.template"); -// when(configAdapter.getConfiguration("pre.auth.code.uri.template")).thenReturn(expected); -// assertEquals(expected, apiConfig.getPreAuthCodeUriTemplate()); -// } - -// @Test -// void testGetTokenUriTemplate() { -// String expected = "token-uri-template"; -// when(apiProperties.tokenUriTemplate()).thenReturn("token.uri.template"); -// when(configAdapter.getConfiguration("token.uri.template")).thenReturn(expected); -// assertEquals(expected, apiConfig.getTokenUriTemplate()); -// } - -} + @BeforeEach + void setUp() { + when(configAdapterFactory.getAdapter()).thenReturn(configAdapter); + appConfig = new AppConfig(configAdapterFactory, apiProperties, issuerUiProperties); + } + + @Test + void testGetIssuerApiExternalDomain() { + // Arrange + String expectedDomain = "https://api.example.com"; + when(apiProperties.externalDomain()).thenReturn("api.external.domain"); + when(configAdapter.getConfiguration("api.external.domain")).thenReturn(expectedDomain); + + // Act + String actualDomain = appConfig.getIssuerApiExternalDomain(); + + // Assert + assertEquals(expectedDomain, actualDomain); + } + + @Test + void testGetIssuerUiExternalDomain() { + // Arrange + String expectedDomain = "https://ui.example.com"; + when(issuerUiProperties.externalDomain()).thenReturn("ui.external.domain"); + when(configAdapter.getConfiguration("ui.external.domain")).thenReturn(expectedDomain); + + // Act + String actualDomain = appConfig.getIssuerUiExternalDomain(); + + // Assert + assertEquals(expectedDomain, actualDomain); + } + + @Test + void testGetApiConfigSource() { + // Arrange + String expectedConfigSource = "configSourceValue"; + when(apiProperties.configSource()).thenReturn("api.config.source"); + when(configAdapter.getConfiguration("api.config.source")).thenReturn(expectedConfigSource); + + // Act + String actualConfigSource = appConfig.getApiConfigSource(); + + // Assert + assertEquals(expectedConfigSource, actualConfigSource); + } + + @Test + void testGetCacheLifetimeForCredentialOffer() { + // Arrange + long expectedLifetime = 3600L; + ApiProperties.MemoryCache memoryCache = mock(ApiProperties.MemoryCache.class); + when(apiProperties.cacheLifetime()).thenReturn(memoryCache); + when(memoryCache.credentialOffer()).thenReturn(expectedLifetime); + + // Act + long actualLifetime = appConfig.getCacheLifetimeForCredentialOffer(); + + // Assert + assertEquals(expectedLifetime, actualLifetime); + } + + @Test + void testGetCacheLifetimeForVerifiableCredential() { + // Arrange + long expectedLifetime = 7200L; + ApiProperties.MemoryCache memoryCache = mock(ApiProperties.MemoryCache.class); + when(apiProperties.cacheLifetime()).thenReturn(memoryCache); + when(memoryCache.verifiableCredential()).thenReturn(expectedLifetime); + + // Act + long actualLifetime = appConfig.getCacheLifetimeForVerifiableCredential(); + + // Assert + assertEquals(expectedLifetime, actualLifetime); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/infrastructure/config/AuthServerConfigTest.java b/src/test/java/es/in2/issuer/infrastructure/config/AuthServerConfigTest.java new file mode 100644 index 000000000..d6d9676c6 --- /dev/null +++ b/src/test/java/es/in2/issuer/infrastructure/config/AuthServerConfigTest.java @@ -0,0 +1,158 @@ +package es.in2.issuer.infrastructure.config; + +import es.in2.issuer.infrastructure.config.adapter.ConfigAdapter; +import es.in2.issuer.infrastructure.config.adapter.factory.ConfigAdapterFactory; +import es.in2.issuer.infrastructure.config.properties.AuthServerProperties; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.lenient; + +@ExtendWith(MockitoExtension.class) +class AuthServerConfigTest { + + @Mock + private ConfigAdapter configAdapter; + + @Mock + private ConfigAdapterFactory configAdapterFactory; + + @Mock + private AuthServerProperties authServerProperties; + + private AuthServerConfig authServerConfig; + + @BeforeEach + void setUp() { + AuthServerProperties.Paths paths = new AuthServerProperties.Paths("issuerDid", "jwtDecoderPath", "jwtDecoderLocalPath", "jwtValidatorPath", "preAuthorizedCodePath", "tokenPath", "nonceValidationPath"); + AuthServerProperties.Client client = new AuthServerProperties.Client("clientId", "username", "password"); + + lenient().when(authServerProperties.externalDomain()).thenReturn("externalDomain"); + lenient().when(authServerProperties.internalDomain()).thenReturn("internalDomain"); + lenient().when(authServerProperties.realm()).thenReturn("realm"); + lenient().when(authServerProperties.paths()).thenReturn(paths); + lenient().when(authServerProperties.client()).thenReturn(client); + + // Mock configAdapterFactory behavior to return the mocked configAdapter + lenient().when(configAdapterFactory.getAdapter()).thenReturn(configAdapter); + + // Mock configAdapter behavior + lenient().when(configAdapter.getConfiguration(anyString())).thenAnswer(invocation -> invocation.getArgument(0)); + + // Create authServerConfig after setting up the mocks + authServerConfig = new AuthServerConfig(configAdapterFactory, authServerProperties); + } + + @Test + void testGetAuthServerExternalDomain() { + String result = authServerConfig.getAuthServerExternalDomain(); + assertEquals("externalDomain", result); + } + + @Test + void testGetAuthServerInternalDomain() { + String result = authServerConfig.getAuthServerInternalDomain(); + assertEquals("internalDomain", result); + } + + @Test + void testGetAuthServerClientId() { + String result = authServerConfig.getAuthServerClientId(); + assertEquals("clientId", result); + } + + @Test + void testGetAuthServerUsername() { + String result = authServerConfig.getAuthServerUsername(); + assertEquals("username", result); + } + + @Test + void testGetAuthServerUserPassword() { + String result = authServerConfig.getAuthServerUserPassword(); + assertEquals("password", result); + } + + @Test + void testGetAuthServerRealm() { + String result = authServerConfig.getAuthServerRealm(); + assertEquals("realm", result); + } + + @Test + void testGetAuthServerIssuerDid() { + String result = authServerConfig.getAuthServerIssuerDid(); + assertEquals("issuerDid", result); + } + + @Test + void testGetAuthServerJwtDecoderPath() { + String result = authServerConfig.getAuthServerJwtDecoderPath(); + assertEquals("jwtDecoderPath", result); + } + + @Test + void testGetAuthServerJwtDecoderLocalPath() { + String result = authServerConfig.getAuthServerJwtDecoderLocalPath(); + assertEquals("jwtDecoderLocalPath", result); + } + + @Test + void testGetAuthServerJwtValidatorPath() { + String result = authServerConfig.getAuthServerJwtValidatorPath(); + assertEquals("jwtValidatorPath", result); + } + + @Test + void testGetAuthServerPreAuthorizedCodePath() { + String result = authServerConfig.getAuthServerPreAuthorizedCodePath(); + assertEquals("preAuthorizedCodePath", result); + } + + @Test + void testGetAuthServerTokenPath() { + String result = authServerConfig.getAuthServerTokenPath(); + assertEquals("tokenPath", result); + } + + @Test + void testGetAuthServerNonceValidationPath() { + String result = authServerConfig.getAuthServerNonceValidationPath(); + assertEquals("nonceValidationPath", result); + } + + @Test + void testGetJwtDecoder() { + String result = authServerConfig.getJwtDecoder(); + assertEquals("internalDomainjwtDecoderPath", result); + } + + @Test + void testGetJwtDecoderLocal() { + String result = authServerConfig.getJwtDecoderLocal(); + assertEquals("internalDomainjwtDecoderLocalPath", result); + } + + @Test + void testGetPreAuthCodeUri() { + String result = authServerConfig.getPreAuthCodeUri(); + assertEquals("internalDomainpreAuthorizedCodePath", result); + } + + @Test + void testGetTokenUri() { + String result = authServerConfig.getTokenUri(); + assertEquals("internalDomaintokenPath", result); + } + + @Test + void testGetJwtValidator() { + String result = authServerConfig.getJwtValidator(); + assertEquals("externalDomainjwtValidatorPath", result); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/infrastructure/config/AzureAppConfigConfigTest.java b/src/test/java/es/in2/issuer/infrastructure/config/AzureAppConfigConfigTest.java index 7b7429cf7..bc6c79a14 100644 --- a/src/test/java/es/in2/issuer/infrastructure/config/AzureAppConfigConfigTest.java +++ b/src/test/java/es/in2/issuer/infrastructure/config/AzureAppConfigConfigTest.java @@ -3,15 +3,16 @@ import com.azure.core.credential.TokenCredential; import com.azure.data.appconfiguration.ConfigurationClient; import es.in2.issuer.infrastructure.config.properties.AzureProperties; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.jupiter.MockitoExtension; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.Mockito.*; +@ExtendWith(MockitoExtension.class) class AzureAppConfigConfigTest { @Mock private AzureProperties azureProperties; @@ -19,11 +20,6 @@ class AzureAppConfigConfigTest { @InjectMocks private AzAppConfigurationConfig azAppConfigurationConfig; - @BeforeEach - public void setUp() { - MockitoAnnotations.openMocks(this); - } - @Test void testAzureTokenCredential() { // Execution @@ -47,4 +43,4 @@ void testAzureConfigurationClient() { assertNotNull(configurationClient, "ConfigurationClient should not be null"); verify(azureProperties, times(2)).endpoint(); // Adjusted to expect 2 invocations } -} +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/infrastructure/config/CacheStoreConfigTest.java b/src/test/java/es/in2/issuer/infrastructure/config/CacheStoreConfigTest.java new file mode 100644 index 000000000..9ace5cd1c --- /dev/null +++ b/src/test/java/es/in2/issuer/infrastructure/config/CacheStoreConfigTest.java @@ -0,0 +1,51 @@ +package es.in2.issuer.infrastructure.config; + +import es.in2.issuer.domain.model.dto.CustomCredentialOffer; +import es.in2.issuer.domain.model.dto.VerifiableCredentialJWT; +import es.in2.issuer.infrastructure.repository.CacheStore; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class CacheStoreConfigTest { + + @Mock + private AppConfig appConfig; + + private CacheStoreConfig cacheStoreConfig; + + @BeforeEach + void setUp() { + cacheStoreConfig = new CacheStoreConfig(appConfig); + } + + @Test + void testCacheStoreDefault() { + CacheStore stringCacheStore = cacheStoreConfig.cacheStoreDefault(); + assertNotNull(stringCacheStore); + } + + @Test + void testCacheStoreForVerifiableCredentialJwt() { + long cacheLifetime = 30; + when(appConfig.getCacheLifetimeForVerifiableCredential()).thenReturn(cacheLifetime); + + CacheStore verifiableCredentialJWTCacheStore = cacheStoreConfig.cacheStoreForVerifiableCredentialJwt(); + assertNotNull(verifiableCredentialJWTCacheStore); + } + + @Test + void testCacheStoreForCredentialOffer() { + long cacheLifetime = 60; + when(appConfig.getCacheLifetimeForCredentialOffer()).thenReturn(cacheLifetime); + + CacheStore customCredentialOfferCacheStore = cacheStoreConfig.cacheStoreForCredentialOffer(); + assertNotNull(customCredentialOfferCacheStore); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/infrastructure/config/OpenAppConfigTest.java b/src/test/java/es/in2/issuer/infrastructure/config/OpenAppConfigTest.java index f2ae03c19..0f701c6ed 100644 --- a/src/test/java/es/in2/issuer/infrastructure/config/OpenAppConfigTest.java +++ b/src/test/java/es/in2/issuer/infrastructure/config/OpenAppConfigTest.java @@ -1,6 +1,6 @@ package es.in2.issuer.infrastructure.config; -import es.in2.issuer.infrastructure.config.properties.*; +import es.in2.issuer.infrastructure.config.properties.OpenApiProperties; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Contact; import io.swagger.v3.oas.models.info.Info; @@ -8,13 +8,15 @@ import io.swagger.v3.oas.models.servers.Server; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.jupiter.MockitoExtension; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.Mockito.when; +@ExtendWith(MockitoExtension.class) class OpenAppConfigTest { @Mock @@ -27,23 +29,19 @@ class OpenAppConfigTest { @BeforeEach void setUp() { - MockitoAnnotations.openMocks(this); openApiConfig = new OpenApiConfig(openApiProperties, appConfig); } @Test void testOpenApiConfiguration() { // Mock properties - OpenApiProperties.OpenApiInfoProperties.OpenApiInfoContactProperties contactProperties = new OpenApiProperties.OpenApiInfoProperties.OpenApiInfoContactProperties("test@example.com","John Doe", "http://example.com"); + OpenApiProperties.OpenApiInfoProperties.OpenApiInfoContactProperties contactProperties = new OpenApiProperties.OpenApiInfoProperties.OpenApiInfoContactProperties("test@example.com", "John Doe", "http://example.com"); OpenApiProperties.OpenApiInfoProperties.OpenApiInfoLicenseProperties licenseProperties = new OpenApiProperties.OpenApiInfoProperties.OpenApiInfoLicenseProperties("Apache 2.0", "https://www.apache.org/licenses/LICENSE-2.0"); OpenApiProperties.OpenApiInfoProperties infoProperties = new OpenApiProperties.OpenApiInfoProperties("Test API", "1.0", "Test Description", "http://example.com/tos", contactProperties, licenseProperties); when(openApiProperties.info()).thenReturn(infoProperties); - OpenApiProperties.OpenApiServerProperties serverProperties = new OpenApiProperties.OpenApiServerProperties("Test Server","Test Description"); + OpenApiProperties.OpenApiServerProperties serverProperties = new OpenApiProperties.OpenApiServerProperties("Test Server", "Test Description"); when(openApiProperties.server()).thenReturn(serverProperties); - // Mock app configuration - when(appConfig.getIssuerApiExternalDomain()).thenReturn("example.com"); - // Invoke method to test OpenAPI openAPI = openApiConfig.openApi(); @@ -67,4 +65,4 @@ void testOpenApiConfiguration() { assertNotNull(server); assertEquals("Test Description", server.getDescription()); } -} +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/infrastructure/config/RemoteSignatureConfigTest.java b/src/test/java/es/in2/issuer/infrastructure/config/RemoteSignatureConfigTest.java new file mode 100644 index 000000000..3b68232dd --- /dev/null +++ b/src/test/java/es/in2/issuer/infrastructure/config/RemoteSignatureConfigTest.java @@ -0,0 +1,79 @@ +package es.in2.issuer.infrastructure.config; + +import es.in2.issuer.infrastructure.config.adapter.ConfigAdapter; +import es.in2.issuer.infrastructure.config.adapter.factory.ConfigAdapterFactory; +import es.in2.issuer.infrastructure.config.properties.RemoteSignatureProperties; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class RemoteSignatureConfigTest { + + @Mock + private ConfigAdapterFactory configAdapterFactory; + + @Mock + private ConfigAdapter configAdapter; + + @Mock + private RemoteSignatureProperties remoteSignatureProperties; + + private RemoteSignatureConfig remoteSignatureConfig; + + @BeforeEach + void setUp() { + when(configAdapterFactory.getAdapter()).thenReturn(configAdapter); + remoteSignatureConfig = new RemoteSignatureConfig(configAdapterFactory, remoteSignatureProperties); + } + + @Test + void testGetRemoteSignatureExternalDomain() { + // Arrange + String expectedDomain = "https://signature.example.com"; + when(remoteSignatureProperties.externalDomain()).thenReturn("remote.signature.external.domain"); + when(configAdapter.getConfiguration("remote.signature.external.domain")).thenReturn(expectedDomain); + + // Act + String actualDomain = remoteSignatureConfig.getRemoteSignatureExternalDomain(); + + // Assert + assertEquals(expectedDomain, actualDomain); + } + + @Test + void testGetRemoteSignatureInternalDomain() { + // Arrange + String expectedDomain = "https://internal.signature.example.com"; + when(remoteSignatureProperties.internalDomain()).thenReturn("remote.signature.internal.domain"); + when(configAdapter.getConfiguration("remote.signature.internal.domain")).thenReturn(expectedDomain); + + // Act + String actualDomain = remoteSignatureConfig.getRemoteSignatureInternalDomain(); + + // Assert + assertEquals(expectedDomain, actualDomain); + } + + @Test + void testGetRemoteSignatureSignPath() { + // Arrange + String expectedPath = "/api/sign"; + RemoteSignatureProperties.Paths paths = mock(RemoteSignatureProperties.Paths.class); + when(remoteSignatureProperties.paths()).thenReturn(paths); + when(paths.signPath()).thenReturn("remote.signature.sign.path"); + when(configAdapter.getConfiguration("remote.signature.sign.path")).thenReturn(expectedPath); + + // Act + String actualPath = remoteSignatureConfig.getRemoteSignatureSignPath(); + + // Assert + assertEquals(expectedPath, actualPath); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/infrastructure/config/SecurityConfigTest.java b/src/test/java/es/in2/issuer/infrastructure/config/SecurityConfigTest.java deleted file mode 100644 index af66115b2..000000000 --- a/src/test/java/es/in2/issuer/infrastructure/config/SecurityConfigTest.java +++ /dev/null @@ -1,114 +0,0 @@ -//package es.in2.issuer.infrastructure.config; -// -//import es.in2.issuer.infrastructure.iam.service.GenericIamAdapter; -//import es.in2.issuer.infrastructure.iam.util.IamAdapterFactory; -//import org.junit.jupiter.api.BeforeEach; -//import org.junit.jupiter.api.Test; -//import org.mockito.Mock; -//import org.mockito.MockedStatic; -//import org.mockito.Mockito; -//import org.mockito.MockitoAnnotations; -//import org.springframework.beans.factory.annotation.Autowired; -//import org.springframework.boot.test.context.SpringBootTest; -//import org.springframework.context.ApplicationContext; -//import org.springframework.security.oauth2.jwt.ReactiveJwtDecoder; -//import org.springframework.security.oauth2.jwt.ReactiveJwtDecoders; -//import org.springframework.security.web.server.SecurityWebFilterChain; -// -//import java.lang.reflect.InvocationTargetException; -//import java.lang.reflect.Method; -//import java.util.Arrays; -// -//import static org.junit.jupiter.api.Assertions.*; -//import static org.mockito.ArgumentMatchers.anyString; -//import static org.mockito.Mockito.mock; -//import static org.mockito.Mockito.when; -// -//@SpringBootTest(properties = { -// "app.configs.iamExternalDomain=example.com", -// "app.configs.iamInternalDomain=internal.example.com", -// "app.configs.issuerExternalDomain=issuer.example.com", -// "app.configs.authenticSourcesDomain=sources.example.com", -// "app.configs.keyVaultDomain=vault.example.com", -// "app.configs.remoteSignatureDomain=signature.example.com", -// "app.configs.issuerDid=did:example:issuer", -// "app.configs.jwtDecoderPath=did:example:jwtDecoderPath", -// "app.configs.jwtDecoderLocalPath=did:example:jwtDecoderLocalPath", -// "app.configs.preAuthCodeUriTemplate=/realms/EAAProvider/verifiable-credential/{{did}}/credential-offer", -// "app.configs.tokenUriTemplate=/realms/EAAProvider/verifiable-credential/{{did}}/token" -//}) -//class SecurityConfigTest { -// -// @Mock -// private IamAdapterFactory iamAdapterFactory; -// @Autowired -// private ApplicationContext context; -// -// private SecurityConfig securityConfig; -// -// @BeforeEach -// public void setUp() { -// MockitoAnnotations.openMocks(this); -// GenericIamAdapter mockAdapter = mock(GenericIamAdapter.class); -// when(iamAdapterFactory.getAdapter()).thenReturn(mockAdapter); -// when(iamAdapterFactory.getAdapter().getJwtDecoder()).thenReturn("localhost:9090"); -// when(iamAdapterFactory.getAdapter().getJwtDecoderLocal()).thenReturn("localhost:9090"); -// securityConfig = new SecurityConfig(iamAdapterFactory); -// } -// -// @Test -// void testJwtDecoderLocal() { -// try (MockedStatic mocked = Mockito.mockStatic(ReactiveJwtDecoders.class)) { -// // Mock the static method call -// mocked.when(() -> ReactiveJwtDecoders.fromIssuerLocation(anyString())) -// .thenReturn(mock(ReactiveJwtDecoder.class)); -// -// // Execute the method under test -// ReactiveJwtDecoder jwtDecoder = securityConfig.jwtDecoderLocal(); -// -// // Verify -// assertNotNull(jwtDecoder, "JwtDecoder should not be null for 'local' profile"); -// } -// } -// -// @Test -// void testJwtDecoder() { -// // Test for the non-"local" profile -// ReactiveJwtDecoder jwtDecoder = securityConfig.jwtDecoder(); -// assertNotNull(jwtDecoder, "JwtDecoder should not be null for non-'local' profiles"); -// } -// -// @Test -// void springSecurityFilterChainBeanIsNotNull() { -// SecurityWebFilterChain filterChain = context.getBean(SecurityWebFilterChain.class); -// assertNotNull(filterChain, "The SecurityWebFilterChain bean should not be null"); -// } -// -// @Test -// void testCorsConfigurationSource() { -// var corsConfigurationSource = securityConfig.corsConfigurationSource(); -// assertNotNull(corsConfigurationSource, "CorsConfigurationSource should not be null"); -// } -// -// @Test -// void testGetSwaggerPaths() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { -// SecurityConfig securityConfig = new SecurityConfig(iamAdapterFactory); -// -// // Access the private method -// Method method = SecurityConfig.class.getDeclaredMethod("getSwaggerPaths"); -// method.setAccessible(true); -// -// String[] expected = new String[]{ -// "/swagger-ui/**", -// "/swagger-resources/**", -// "/api-docs/**", -// "/spring-ui/**", -// "/webjars/swagger-ui/**" -// }; -// -// // Invoke the method and check the result -// String[] swaggerPaths = (String[]) method.invoke(securityConfig); -// //assertNotNull(swaggerPaths, "SwaggerPaths should not be null"); -// assertEquals(Arrays.toString(swaggerPaths), Arrays.toString(expected), "Result should match expected"); -// } -//} diff --git a/src/test/java/es/in2/issuer/infrastructure/config/SwaggerConfigTest.java b/src/test/java/es/in2/issuer/infrastructure/config/SwaggerConfigTest.java index 40d745dcc..6e635fcd8 100644 --- a/src/test/java/es/in2/issuer/infrastructure/config/SwaggerConfigTest.java +++ b/src/test/java/es/in2/issuer/infrastructure/config/SwaggerConfigTest.java @@ -1,9 +1,19 @@ package es.in2.issuer.infrastructure.config; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.Paths; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springdoc.core.customizers.OpenApiCustomizer; import org.springdoc.core.models.GroupedOpenApi; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Set; + +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; class SwaggerConfigTest { @@ -27,4 +37,44 @@ void testPrivateApiGroupedOpenApiNotNull() { GroupedOpenApi privateApi = swaggerConfig.privateApi(); assertNotNull(privateApi, "Private API GroupedOpenApi should not be null"); } -} + + @Test + void testTagOpenApiCustomizerRemovesUnwantedTagsWithReflection() throws Exception { + // Arrange + OpenAPI openAPI = new OpenAPI(); + Paths paths = new Paths(); + PathItem pathItem1 = new PathItem(); + Operation operation1 = new Operation(); + operation1.setTags(List.of("Public")); + pathItem1.setGet(operation1); + + PathItem pathItem2 = new PathItem(); + Operation operation2 = new Operation(); + operation2.setTags(List.of("Private")); + pathItem2.setPost(operation2); + + PathItem pathItem3 = new PathItem(); + Operation operation3 = new Operation(); + operation3.setTags(List.of("Other")); + pathItem3.setPut(operation3); + + paths.addPathItem("/path1", pathItem1); + paths.addPathItem("/path2", pathItem2); + paths.addPathItem("/path3", pathItem3); + + openAPI.setPaths(paths); + + Method method = SwaggerConfig.class.getDeclaredMethod("tagOpenApiCustomizer", Set.class); + method.setAccessible(true); + OpenApiCustomizer customizer = (OpenApiCustomizer) method.invoke(swaggerConfig, Set.of(SwaggerConfig.TAG_PUBLIC, SwaggerConfig.TAG_PRIVATE)); + + // Act + customizer.customise(openAPI); + + // Assert + assertNotNull(openAPI.getPaths().get("/path1").getGet(), "Operation with 'Public' tag should not be removed"); + assertNotNull(openAPI.getPaths().get("/path2").getPost(), "Operation with 'Private' tag should not be removed"); + assertFalse(openAPI.getPaths().containsKey("/path3"), "Operation with 'Other' tag should be removed"); + assertFalse(openAPI.getPaths().containsKey("/path3"), "Path with no matching operations should be removed"); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/infrastructure/config/adapter/AzureConfigAdapterTest.java b/src/test/java/es/in2/issuer/infrastructure/config/adapter/AzureConfigAdapterTest.java index 0665727ac..c74753968 100644 --- a/src/test/java/es/in2/issuer/infrastructure/config/adapter/AzureConfigAdapterTest.java +++ b/src/test/java/es/in2/issuer/infrastructure/config/adapter/AzureConfigAdapterTest.java @@ -6,27 +6,25 @@ import es.in2.issuer.infrastructure.config.properties.AzureProperties; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.jupiter.MockitoExtension; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; +@ExtendWith(MockitoExtension.class) class AzureConfigAdapterTest { - @Mock - private ConfigurationClient configurationClient; - private final AzureProperties.AzurePropertiesLabel azurePropertiesLabel = new AzureProperties.AzurePropertiesLabel("DummyLabel"); - private final AzureProperties azureProperties = new AzureProperties("DummyEndpoint", azurePropertiesLabel); - + @Mock + private ConfigurationClient configurationClient; private ConfigAdapter azureConfigAdapter; @BeforeEach void setUp() { - MockitoAnnotations.openMocks(this); azureConfigAdapter = new AzureConfigAdapter(configurationClient, azureProperties); } @@ -43,4 +41,4 @@ void testGetConfiguration() { assertEquals(expectedValue, actualValue); } -} +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/infrastructure/config/adapter/exception/AzureConfigurationSettingExceptionTest.java b/src/test/java/es/in2/issuer/infrastructure/config/adapter/exception/AzureConfigurationSettingExceptionTest.java new file mode 100644 index 000000000..a238fdbd6 --- /dev/null +++ b/src/test/java/es/in2/issuer/infrastructure/config/adapter/exception/AzureConfigurationSettingExceptionTest.java @@ -0,0 +1,15 @@ +package es.in2.issuer.infrastructure.config.adapter.exception; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class AzureConfigurationSettingExceptionTest { + + @Test + void testConstructor() { + String expectedMessage = "sample message"; + AzureConfigurationSettingException exception = new AzureConfigurationSettingException(expectedMessage); + assertEquals(expectedMessage, exception.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/infrastructure/config/adapter/exception/ConfigAdapterFactoryExceptionTest.java b/src/test/java/es/in2/issuer/infrastructure/config/adapter/exception/ConfigAdapterFactoryExceptionTest.java new file mode 100644 index 000000000..ed80dd6e6 --- /dev/null +++ b/src/test/java/es/in2/issuer/infrastructure/config/adapter/exception/ConfigAdapterFactoryExceptionTest.java @@ -0,0 +1,14 @@ +package es.in2.issuer.infrastructure.config.adapter.exception; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class ConfigAdapterFactoryExceptionTest { + @Test + void testConstructor() { + int size = 5; + ConfigAdapterFactoryException exception = new ConfigAdapterFactoryException(size); + assertEquals("Error creating ConfigAdapterFactory. There should be only one ConfigAdapter. Found: " + size, exception.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/infrastructure/config/adapter/factory/ConfigAdapterFactoryTest.java b/src/test/java/es/in2/issuer/infrastructure/config/adapter/factory/ConfigAdapterFactoryTest.java index 33db06758..937c09010 100644 --- a/src/test/java/es/in2/issuer/infrastructure/config/adapter/factory/ConfigAdapterFactoryTest.java +++ b/src/test/java/es/in2/issuer/infrastructure/config/adapter/factory/ConfigAdapterFactoryTest.java @@ -1,47 +1,69 @@ -//package es.in2.issuer.infrastructure.config.adapter.factory; -// -//import es.in2.issuer.infrastructure.config.adapter.exception.ConfigAdapterFactoryException; -//import es.in2.issuer.infrastructure.config.adapter.ConfigAdapter; -//import org.junit.jupiter.api.BeforeEach; -//import org.junit.jupiter.api.Test; -//import org.mockito.Mock; -//import org.mockito.MockitoAnnotations; -// -//import java.util.Collections; -//import java.util.List; -// -//import static org.junit.jupiter.api.Assertions.assertEquals; -//import static org.junit.jupiter.api.Assertions.assertThrows; -// -//class ConfigAdapterFactoryTest { -// -// @Mock -// private ConfigAdapter mockAdapter; -// -// private ConfigAdapterFactory configAdapterFactory; -// -// @BeforeEach -// void setUp() { -// MockitoAnnotations.openMocks(this); -// configAdapterFactory = new ConfigAdapterFactory(Collections.singletonList(mockAdapter)); -// } -// -// @Test -// void getAdapter_Success() { -// ConfigAdapter adapter = configAdapterFactory.getAdapter(); -// assertEquals(mockAdapter, adapter); -// } -// -// @Test -// void getAdapter_ExceptionThrownWhenNoAdapterPresent() { -// configAdapterFactory = new ConfigAdapterFactory(Collections.emptyList()); -// assertThrows(ConfigAdapterFactoryException.class, configAdapterFactory::getAdapter); -// } -// -// @Test -// void getAdapter_ExceptionThrownWhenMultipleAdaptersPresent() { -// List multipleAdapters = List.of(mockAdapter, mockAdapter); -// configAdapterFactory = new ConfigAdapterFactory(multipleAdapters); -// assertThrows(ConfigAdapterFactoryException.class, configAdapterFactory::getAdapter); -// } -//} +package es.in2.issuer.infrastructure.config.adapter.factory; + +import es.in2.issuer.infrastructure.config.adapter.ConfigAdapter; +import es.in2.issuer.infrastructure.config.adapter.impl.AzureConfigAdapter; +import es.in2.issuer.infrastructure.config.adapter.impl.YamlConfigAdapter; +import es.in2.issuer.infrastructure.config.properties.ApiProperties; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class ConfigAdapterFactoryTest { + + @Mock + private ApiProperties apiProperties; + + @Mock + private AzureConfigAdapter azureConfigAdapter; + + @Mock + private YamlConfigAdapter yamlConfigAdapter; + + @InjectMocks + private ConfigAdapterFactory configAdapterFactory; + + @Test + void getAdapter_AzureConfig() { + //Arrange + when(apiProperties.configSource()).thenReturn("azure"); + + // Act + ConfigAdapter configAdapter = configAdapterFactory.getAdapter(); + + // Assert + assertEquals(azureConfigAdapter, configAdapter); + } + + @Test + void getAdapter_YamlConfig() { + //Arrange + when(apiProperties.configSource()).thenReturn("yaml"); + + // Act + ConfigAdapter configAdapter = configAdapterFactory.getAdapter(); + + // Assert + assertEquals(yamlConfigAdapter, configAdapter); + } + + @Test + void getAdapter_InvalidConfig() { + //Arrange + when(apiProperties.configSource()).thenReturn("invalid"); + + // Act & Assert + IllegalArgumentException illegalArgumentException = assertThrows( + IllegalArgumentException.class, + () -> configAdapterFactory.getAdapter() + ); + + assertEquals("Invalid Config Adapter Provider: invalid", illegalArgumentException.getMessage()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/infrastructure/config/properties/ApiConfigPropertiesTest.java b/src/test/java/es/in2/issuer/infrastructure/config/properties/ApiConfigPropertiesTest.java deleted file mode 100644 index 890dda23c..000000000 --- a/src/test/java/es/in2/issuer/infrastructure/config/properties/ApiConfigPropertiesTest.java +++ /dev/null @@ -1,39 +0,0 @@ -//package es.in2.issuer.infrastructure.config.properties; -// -//import org.junit.jupiter.api.Test; -//import org.springframework.boot.context.properties.bind.BindResult; -//import org.springframework.boot.context.properties.bind.Binder; -//import org.springframework.mock.env.MockEnvironment; -// -//import static org.assertj.core.api.Assertions.assertThat; -// -//class ApiConfigPropertiesTest { -// -// @Test -// void bindingProperties() { -// // Setup a MockEnvironment with your properties -// MockEnvironment environment = new MockEnvironment(); -// environment.setProperty("iamInternalDomain", "example.com"); -// environment.setProperty("issuerExternalDomain", "issuer.example.com"); -// environment.setProperty("authenticSourcesDomain", "authsources.example.com"); -// environment.setProperty("keyVaultDomain", "keyvault.example.com"); -// environment.setProperty("remoteSignatureDomain", "remotesignature.example.com"); -// environment.setProperty("issuerDid", "issuer-did"); -// -// // Create a Binder instance -// Binder binder = Binder.get(environment); -// -// // Bind the properties to an AppConfigurationProperties instance -// BindResult bindResult = binder.bind("", ApiProperties.class); -// -// // Assert the properties are correctly bound -// assertThat(bindResult.isBound()).isTrue(); -// ApiProperties apiProperties = bindResult.get(); -//// assertThat(apiProperties.iamInternalDomain()).isEqualTo("example.com"); -//// assertThat(apiProperties.issuerExternalDomain()).isEqualTo("issuer.example.com"); -//// assertThat(apiProperties.authenticSourcesDomain()).isEqualTo("authsources.example.com"); -//// assertThat(apiProperties.keyVaultDomain()).isEqualTo("keyvault.example.com"); -//// assertThat(apiProperties.remoteSignatureDomain()).isEqualTo("remotesignature.example.com"); -//// assertThat(apiProperties.issuerDid()).isEqualTo("issuer-did"); -// } -//} diff --git a/src/test/java/es/in2/issuer/infrastructure/config/properties/ApiPropertiesTest.java b/src/test/java/es/in2/issuer/infrastructure/config/properties/ApiPropertiesTest.java new file mode 100644 index 000000000..29462900c --- /dev/null +++ b/src/test/java/es/in2/issuer/infrastructure/config/properties/ApiPropertiesTest.java @@ -0,0 +1,20 @@ +package es.in2.issuer.infrastructure.config.properties; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class ApiPropertiesTest { + + @Test + void testApiProperties() { + ApiProperties.MemoryCache memoryCache = new ApiProperties.MemoryCache(10L, 10L); + ApiProperties apiProperties = new ApiProperties("externalDomain", "internalDomain", "configSource", memoryCache); + + assertEquals("externalDomain", apiProperties.externalDomain()); + assertEquals("internalDomain", apiProperties.internalDomain()); + assertEquals("configSource", apiProperties.configSource()); + assertEquals(memoryCache, apiProperties.cacheLifetime()); + } + +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/infrastructure/config/properties/AuthServerPropertiesTest.java b/src/test/java/es/in2/issuer/infrastructure/config/properties/AuthServerPropertiesTest.java new file mode 100644 index 000000000..445ef3373 --- /dev/null +++ b/src/test/java/es/in2/issuer/infrastructure/config/properties/AuthServerPropertiesTest.java @@ -0,0 +1,22 @@ +package es.in2.issuer.infrastructure.config.properties; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class AuthServerPropertiesTest { + + @Test + void testAuthServerProperties() { + AuthServerProperties.Paths paths = new AuthServerProperties.Paths("issuerDid", "jwtDecoderPath", "jwtDecoderLocalPath", "jwtValidatorPath", "preAuthorizedCodePath", "tokenPath", "nonceValidationPath"); + AuthServerProperties.Client client = new AuthServerProperties.Client("clientId", "username", "password"); + AuthServerProperties authServerProperties = new AuthServerProperties("provider", "externalDomain", "internalDomain", "realm", paths, client); + + assertEquals("provider", authServerProperties.provider()); + assertEquals("externalDomain", authServerProperties.externalDomain()); + assertEquals("internalDomain", authServerProperties.internalDomain()); + assertEquals("realm", authServerProperties.realm()); + assertEquals(paths, authServerProperties.paths()); + assertEquals(client, authServerProperties.client()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/infrastructure/config/properties/AzurePropertiesTest.java b/src/test/java/es/in2/issuer/infrastructure/config/properties/AzurePropertiesTest.java new file mode 100644 index 000000000..e0eb958fc --- /dev/null +++ b/src/test/java/es/in2/issuer/infrastructure/config/properties/AzurePropertiesTest.java @@ -0,0 +1,16 @@ +package es.in2.issuer.infrastructure.config.properties; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class AzurePropertiesTest { + @Test + void testAzureProperties() { + AzureProperties.AzurePropertiesLabel azurePropertiesLabel = new AzureProperties.AzurePropertiesLabel("global"); + AzureProperties azureProperties = new AzureProperties("endpoint", azurePropertiesLabel); + + assertEquals("endpoint", azureProperties.endpoint()); + assertEquals(azurePropertiesLabel, azureProperties.label()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/infrastructure/config/properties/IssuerUiPropertiesTest.java b/src/test/java/es/in2/issuer/infrastructure/config/properties/IssuerUiPropertiesTest.java new file mode 100644 index 000000000..60adb8634 --- /dev/null +++ b/src/test/java/es/in2/issuer/infrastructure/config/properties/IssuerUiPropertiesTest.java @@ -0,0 +1,15 @@ +package es.in2.issuer.infrastructure.config.properties; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class IssuerUiPropertiesTest { + @Test + void testIssuerUiProperties() { + IssuerUiProperties issuerUiProperties = new IssuerUiProperties("externalDomain", "internalDomain"); + + assertEquals("externalDomain", issuerUiProperties.externalDomain()); + assertEquals("internalDomain", issuerUiProperties.internalDomain()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/infrastructure/config/properties/OpenApiPropertiesTest.java b/src/test/java/es/in2/issuer/infrastructure/config/properties/OpenApiPropertiesTest.java new file mode 100644 index 000000000..9108d204c --- /dev/null +++ b/src/test/java/es/in2/issuer/infrastructure/config/properties/OpenApiPropertiesTest.java @@ -0,0 +1,25 @@ +package es.in2.issuer.infrastructure.config.properties; + +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class OpenApiPropertiesTest { + + private static OpenApiProperties.@NotNull OpenApiInfoProperties getOpenApiInfoProperties() { + OpenApiProperties.OpenApiInfoProperties.OpenApiInfoContactProperties openApiInfoContactProperties = new OpenApiProperties.OpenApiInfoProperties.OpenApiInfoContactProperties("email", "name", "url"); + OpenApiProperties.OpenApiInfoProperties.OpenApiInfoLicenseProperties openApiInfoLicenseProperties = new OpenApiProperties.OpenApiInfoProperties.OpenApiInfoLicenseProperties("name", "url"); + return new OpenApiProperties.OpenApiInfoProperties("title", "version", "description", "termsOfService", openApiInfoContactProperties, openApiInfoLicenseProperties); + } + + @Test + void testOpenApiProperties() { + OpenApiProperties.OpenApiServerProperties openApiServerProperties = new OpenApiProperties.OpenApiServerProperties("url", "description"); + OpenApiProperties.OpenApiInfoProperties openApiInfoProperties = getOpenApiInfoProperties(); + OpenApiProperties openApiProperties = new OpenApiProperties(openApiServerProperties, openApiInfoProperties); + + assertEquals(openApiServerProperties, openApiProperties.server()); + assertEquals(openApiInfoProperties, openApiProperties.info()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/infrastructure/config/properties/RemoteSignaturePropertiesTest.java b/src/test/java/es/in2/issuer/infrastructure/config/properties/RemoteSignaturePropertiesTest.java new file mode 100644 index 000000000..1712da725 --- /dev/null +++ b/src/test/java/es/in2/issuer/infrastructure/config/properties/RemoteSignaturePropertiesTest.java @@ -0,0 +1,17 @@ +package es.in2.issuer.infrastructure.config.properties; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +class RemoteSignaturePropertiesTest { + @Test + void testRemoteSignatureProperties() { + RemoteSignatureProperties.Paths paths = new RemoteSignatureProperties.Paths("signPath"); + RemoteSignatureProperties remoteSignatureProperties = new RemoteSignatureProperties("externalDomain", "internalDomain", paths); + + assertEquals("externalDomain", remoteSignatureProperties.externalDomain()); + assertEquals("internalDomain", remoteSignatureProperties.internalDomain()); + assertEquals(paths, remoteSignatureProperties.paths()); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/infrastructure/controller/CredentialControllerTest.java b/src/test/java/es/in2/issuer/infrastructure/controller/CredentialControllerTest.java new file mode 100644 index 000000000..d6f2ff641 --- /dev/null +++ b/src/test/java/es/in2/issuer/infrastructure/controller/CredentialControllerTest.java @@ -0,0 +1,116 @@ +package es.in2.issuer.infrastructure.controller; + +import es.in2.issuer.application.workflow.VerifiableCredentialIssuanceWorkflow; +import es.in2.issuer.domain.model.dto.*; +import es.in2.issuer.domain.service.AccessTokenService; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class CredentialControllerTest { + + @Mock + private VerifiableCredentialIssuanceWorkflow verifiableCredentialIssuanceWorkflow; + + @Mock + private AccessTokenService accessTokenService; + + @InjectMocks + private CredentialController credentialController; + + @Test + void createWithdrawnLEARCredential() { + String type = "testType"; + LEARCredentialRequest learCredentialRequest = LEARCredentialRequest.builder() + .credential(null) + .build(); + when(verifiableCredentialIssuanceWorkflow.completeWithdrawLearCredentialProcess(anyString(), eq(type), eq(learCredentialRequest))).thenReturn(Mono.empty()); + + Mono result = credentialController.createWithdrawnLEARCredential(type, learCredentialRequest); + + StepVerifier.create(result) + .verifyComplete(); + } + + @Test + void createVerifiableCredential() { + //Arrange + String authorizationHeader = "Bearer testToken"; + CredentialRequest credentialRequest = CredentialRequest.builder() + .format("sampleFormat") + .credentialDefinition(CredentialDefinition.builder().type(List.of("type")).build()) + .build(); + VerifiableCredentialResponse verifiableCredentialResponse = VerifiableCredentialResponse.builder() + .credential("sampleCredential") + .transactionId("sampleTransactionId") + .cNonce("sampleCNonce") + .cNonceExpiresIn(35) + .build(); + when(accessTokenService.getCleanBearerToken(authorizationHeader)).thenReturn(Mono.just("testToken")); + when(verifiableCredentialIssuanceWorkflow.generateVerifiableCredentialResponse(anyString(), eq(credentialRequest), anyString())).thenReturn(Mono.just(verifiableCredentialResponse)); + + Mono result = credentialController.createVerifiableCredential(authorizationHeader, credentialRequest); + + StepVerifier.create(result) + .assertNext(response -> assertEquals(verifiableCredentialResponse, response)) + .verifyComplete(); + } + + @Test + void getCredential() { + String authorizationHeader = "Bearer testToken"; + String newTransactionId = "newTransactionId"; + DeferredCredentialRequest deferredCredentialRequest = DeferredCredentialRequest.builder() + .transactionId(newTransactionId) + .build(); + VerifiableCredentialResponse verifiableCredentialResponse = VerifiableCredentialResponse.builder() + .credential("sampleCredential") + .transactionId("sampleTransactionId") + .cNonce("sampleCNonce") + .cNonceExpiresIn(35) + .build(); + when(verifiableCredentialIssuanceWorkflow.generateVerifiableCredentialDeferredResponse(anyString(), eq(deferredCredentialRequest))).thenReturn(Mono.just(verifiableCredentialResponse)); + + Mono result = credentialController.getCredential(authorizationHeader, deferredCredentialRequest); + + StepVerifier.create(result) + .assertNext(response -> assertEquals(verifiableCredentialResponse, response)) + .verifyComplete(); + } + + @Test + void createVerifiableCredentials() { + String authorizationHeader = "Bearer testToken"; + BatchCredentialResponse.CredentialResponse newCredentialResponse = new BatchCredentialResponse.CredentialResponse("newSampleCredential"); + List newCredentialResponses = List.of(newCredentialResponse); + String expectedFormat = "sampleFormat"; + Proof expectedProof = new Proof("jwt_vc_json", "sampleJwt"); + CredentialDefinition expectedCredentialDefinition = new CredentialDefinition(List.of("type")); + BatchCredentialRequest batchCredentialRequest = new BatchCredentialRequest(List.of(new CredentialRequest(expectedFormat, expectedCredentialDefinition, expectedProof))); + BatchCredentialResponse batchCredentialResponse = BatchCredentialResponse.builder() + .credentialResponses(newCredentialResponses) + .build(); + + when(accessTokenService.getCleanBearerToken(authorizationHeader)).thenReturn(Mono.just("testToken")); + when(accessTokenService.getUserId(authorizationHeader)).thenReturn(Mono.just("testUserId")); + when(verifiableCredentialIssuanceWorkflow.generateVerifiableCredentialBatchResponse(anyString(), eq(batchCredentialRequest), anyString())).thenReturn(Mono.just(batchCredentialResponse)); + + Mono result = credentialController.createVerifiableCredentials(authorizationHeader, batchCredentialRequest); + + StepVerifier.create(result) + .assertNext(response -> assertEquals(batchCredentialResponse, response)) + .verifyComplete(); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/infrastructure/controller/CredentialManagementControllerTest.java b/src/test/java/es/in2/issuer/infrastructure/controller/CredentialManagementControllerTest.java new file mode 100644 index 000000000..eb97be733 --- /dev/null +++ b/src/test/java/es/in2/issuer/infrastructure/controller/CredentialManagementControllerTest.java @@ -0,0 +1,81 @@ +package es.in2.issuer.infrastructure.controller; + +import es.in2.issuer.domain.model.dto.CredentialDetails; +import es.in2.issuer.domain.model.dto.CredentialProcedures; +import es.in2.issuer.domain.model.dto.ProcedureBasicInfo; +import es.in2.issuer.domain.service.AccessTokenService; +import es.in2.issuer.domain.service.CredentialProcedureService; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.sql.Timestamp; +import java.util.List; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class CredentialManagementControllerTest { + + @Mock + private CredentialProcedureService credentialProcedureService; + + @Mock + private AccessTokenService accessTokenService; + + @InjectMocks + private CredentialManagementController credentialManagementController; + + @Test + void getAllProcedures() { + //Arrange + String organizationId = "testOrganizationId"; + ProcedureBasicInfo procedureBasicInfo = ProcedureBasicInfo.builder() + .procedureId(UUID.randomUUID()) + .fullName("testFullName") + .status("testStatus") + .updated(new Timestamp(System.currentTimeMillis())) + .build(); + CredentialProcedures.CredentialProcedure credentialProcedure = new CredentialProcedures.CredentialProcedure(procedureBasicInfo); + CredentialProcedures credentialProcedures = CredentialProcedures.builder().credentialProcedures(List.of(credentialProcedure)).build(); + when(accessTokenService.getOrganizationId(anyString())).thenReturn(Mono.just(organizationId)); + when(credentialProcedureService.getAllProceduresBasicInfoByOrganizationId(organizationId)).thenReturn(Mono.just(credentialProcedures)); + + //Act + Mono result = credentialManagementController.getAllProcedures("Bearer testToken"); + + //Assert + StepVerifier.create(result) + .assertNext(procedures -> assertEquals(credentialProcedures, procedures)) + .verifyComplete(); + } + + @Test + void getProcedure() { + //Arrange + String organizationId = "testOrganizationId"; + String procedureId = "testProcedureId"; + CredentialDetails credentialDetails = CredentialDetails.builder() + .procedureId(UUID.randomUUID()) + .credentialStatus("testCredentialStatus") + .credential(null) + .build(); + when(accessTokenService.getOrganizationId(anyString())).thenReturn(Mono.just(organizationId)); + when(credentialProcedureService.getProcedureDetailByProcedureIdAndOrganizationId(organizationId, procedureId)).thenReturn(Mono.just(credentialDetails)); + + //Act + Mono result = credentialManagementController.getProcedure("Bearer testToken", procedureId); + + //Assert + StepVerifier.create(result) + .assertNext(details -> assertEquals(credentialDetails, details)) + .verifyComplete(); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/infrastructure/controller/CredentialOfferControllerTest.java b/src/test/java/es/in2/issuer/infrastructure/controller/CredentialOfferControllerTest.java index 589fa9270..9dd00c0c8 100644 --- a/src/test/java/es/in2/issuer/infrastructure/controller/CredentialOfferControllerTest.java +++ b/src/test/java/es/in2/issuer/infrastructure/controller/CredentialOfferControllerTest.java @@ -1,75 +1,78 @@ -//package es.in2.issuer.infrastructure.controller; -// -//import es.in2.issuer.application.service.CredentialOfferIssuanceService; -//import es.in2.issuer.domain.model.CustomCredentialOffer; -//import es.in2.issuer.domain.service.AccessTokenService; -//import es.in2.issuer.domain.service.CredentialOfferService; -//import org.junit.jupiter.api.Test; -//import org.junit.jupiter.api.extension.ExtendWith; -//import org.mockito.InjectMocks; -//import org.mockito.Mock; -//import org.mockito.junit.jupiter.MockitoExtension; -//import org.springframework.http.HttpHeaders; -//import org.springframework.http.server.reactive.ServerHttpResponse; -//import org.springframework.web.server.ServerWebExchange; -//import reactor.core.publisher.Mono; -// -//import static org.junit.jupiter.api.Assertions.*; -//import static org.mockito.Mockito.*; -// -//@ExtendWith(MockitoExtension.class) -//class CredentialOfferControllerTest { -// -// @Mock -// private CredentialOfferService credentialOfferService; -// -// @Mock -// private CredentialOfferIssuanceService credentialOfferIssuanceService; -// -// @Mock -// private AccessTokenService accessTokenService; -// -// @InjectMocks -// private CredentialOfferController controller; -// -// @Test -// void testCreateCredentialOfferV1_Success() { -// // Arrange -// String mockTokenString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"; -// String mockCredentialOfferUri = "https://www.example.com/credential-offer?credential_offer_uri=https://www.example.com/offer/123"; -// -// when(accessTokenService.getCleanBearerToken(any())).thenReturn(Mono.just(mockTokenString)); -// when(credentialOfferIssuanceService.buildCredentialOfferUri(mockTokenString, null)) -// .thenReturn(Mono.just(mockCredentialOfferUri)); -// -// // Act -// Mono result = controller.buildCredentialOffer("Bearer "+mockTokenString, null); -// -// // Assert -// result.subscribe(credentialOfferUri -> assertEquals(mockCredentialOfferUri, credentialOfferUri)); -// verify(credentialOfferIssuanceService, times(1)).buildCredentialOfferUri(mockTokenString, null); -// } -// -// @Test -// void testGetCredentialOffer_Success() { -// // Arrange -// String mockCredentialOfferId = "mockCredentialOfferId"; -// CustomCredentialOffer mockCredentialOffer = CustomCredentialOffer.builder().build(); -// -// when(credentialOfferIssuanceService.getCustomCredentialOffer(mockCredentialOfferId)).thenReturn(Mono.just(mockCredentialOffer)); -// -// // Mock -// ServerWebExchange mockExchange = mock(ServerWebExchange.class); -// ServerHttpResponse mockResponse = mock(ServerHttpResponse.class); -// when(mockExchange.getResponse()).thenReturn(mockResponse); -// HttpHeaders mockHeaders = new HttpHeaders(); -// when(mockResponse.getHeaders()).thenReturn(mockHeaders); -// -// // Act -// Mono result = controller.getCredentialOffer(mockCredentialOfferId, mockExchange); -// -// // Assert -// result.subscribe(credentialOffer -> assertEquals(mockCredentialOffer, credentialOffer)); -// verify(credentialOfferIssuanceService, times(1)).getCustomCredentialOffer(mockCredentialOfferId); -// } -//} +package es.in2.issuer.infrastructure.controller; + +import es.in2.issuer.application.workflow.CredentialOfferIssuanceWorkflow; +import es.in2.issuer.domain.model.dto.CustomCredentialOffer; +import es.in2.issuer.domain.model.dto.Grant; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.web.server.MockServerWebExchange; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class CredentialOfferControllerTest { + + @Mock + private CredentialOfferIssuanceWorkflow credentialOfferIssuanceWorkflow; + + @InjectMocks + private CredentialOfferController credentialOfferController; + + @Test + void getCredentialOfferByTransactionCode() { + //Arrange + String transactionCode = "testTransactionCode"; + String credentialOfferUri = "https://www.goodair.com/credential-offer?credential_offer_uri=https://www.goodair.com/credential-offer/5j349k3e3n23j"; + when(credentialOfferIssuanceWorkflow.buildCredentialOfferUri(anyString(), eq(transactionCode))).thenReturn(Mono.just(credentialOfferUri)); + + //Act + Mono result = credentialOfferController.getCredentialOfferByTransactionCode(transactionCode); + + //Assert + StepVerifier.create(result) + .assertNext(uri -> assertEquals(credentialOfferUri, uri)) + .verifyComplete(); + } + + @Test + void getCredentialOffer() { + //Arrange + Grant.TxCode txCode = new Grant.TxCode(5, "input_mode", "description"); + Grant.TxCode txCode2 = new Grant.TxCode(5, "input_mode", "description"); + Map grants = new HashMap<>(); + grants.put("grant1", new Grant("pre-authorized_code", txCode)); + grants.put("grant2", new Grant("pre-authorized_code", txCode2)); + + CustomCredentialOffer customCredentialOffer = CustomCredentialOffer.builder() + .credentialIssuer("https://client-issuer.com") + .credentialConfigurationIds(List.of("UniversityDegree")) + .credentials(List.of(new CustomCredentialOffer.Credential("format", List.of("type")))) + .grants(grants) + .build(); + + String id = "testId"; + + when(credentialOfferIssuanceWorkflow.getCustomCredentialOffer(id)).thenReturn(Mono.just(customCredentialOffer)); + + //Act + Mono result = credentialOfferController.getCredentialOffer(id, MockServerWebExchange.from(MockServerHttpRequest.get("/"))); + + //Assert + StepVerifier.create(result) + .assertNext(offer -> assertEquals(customCredentialOffer, offer)) + .verifyComplete(); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/infrastructure/controller/DeferredCredentialControllerTest.java b/src/test/java/es/in2/issuer/infrastructure/controller/DeferredCredentialControllerTest.java new file mode 100644 index 000000000..430415d7c --- /dev/null +++ b/src/test/java/es/in2/issuer/infrastructure/controller/DeferredCredentialControllerTest.java @@ -0,0 +1,65 @@ +//package es.in2.issuer.infrastructure.controller; +// +//import es.in2.issuer.application.workflow.DeferredCredentialWorkflow; +//import es.in2.issuer.domain.model.dto.PendingCredentials; +//import es.in2.issuer.domain.model.dto.SignedCredentials; +//import es.in2.issuer.domain.service.CertificateService; +//import org.junit.jupiter.api.Test; +//import org.junit.jupiter.api.extension.ExtendWith; +//import org.mockito.InjectMocks; +//import org.mockito.Mock; +//import org.mockito.junit.jupiter.MockitoExtension; +//import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +//import org.springframework.mock.web.server.MockServerWebExchange; +//import reactor.core.publisher.Mono; +//import reactor.test.StepVerifier; +// +//import java.util.List; +// +//import static org.junit.jupiter.api.Assertions.assertEquals; +//import static org.mockito.ArgumentMatchers.any; +//import static org.mockito.Mockito.when; +// +//@ExtendWith(MockitoExtension.class) +//class DeferredCredentialControllerTest { +// +// @Mock +// private DeferredCredentialWorkflow deferredCredentialWorkflow; +// +// @Mock +// private CertificateService certificateService; +// +// @InjectMocks +// private DeferredCredentialController deferredCredentialController; +// +// @Test +// void getUnsignedCredentials() { +// // Arrange +// String organizationId = "testOrganizationId"; +// PendingCredentials pendingCredentials = new PendingCredentials(List.of(new PendingCredentials.CredentialPayload("testCredentialId"))); // replace with actual data +// when(certificateService.getOrganizationIdFromCertificate(any())).thenReturn(Mono.just(organizationId)); +// when(deferredCredentialWorkflow.getPendingCredentialsByOrganizationId(organizationId)).thenReturn(Mono.just(pendingCredentials)); +// +// // Act +// Mono result = deferredCredentialController.getUnsignedCredentials(MockServerWebExchange.from(MockServerHttpRequest.get("/"))); +// +// // Assert +// StepVerifier.create(result) +// .assertNext(credentials -> assertEquals(pendingCredentials, credentials)) +// .verifyComplete(); +// } +// +// @Test +// void updateCredentials() { +// // Arrange +// SignedCredentials signedCredentials = new SignedCredentials(List.of(new SignedCredentials.SignedCredential("testCredentialId"))); +// when(deferredCredentialWorkflow.updateSignedCredentials(signedCredentials)).thenReturn(Mono.empty()); +// +// // Act +// Mono result = deferredCredentialController.updateCredentials("clientCert", signedCredentials); +// +// // Assert +// StepVerifier.create(result) +// .verifyComplete(); +// } +//} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/infrastructure/controller/DeferredCredentialMetadataControllerTest.java b/src/test/java/es/in2/issuer/infrastructure/controller/DeferredCredentialMetadataControllerTest.java index 6ebee2681..48d6f6e0d 100644 --- a/src/test/java/es/in2/issuer/infrastructure/controller/DeferredCredentialMetadataControllerTest.java +++ b/src/test/java/es/in2/issuer/infrastructure/controller/DeferredCredentialMetadataControllerTest.java @@ -1,114 +1,39 @@ -//package es.in2.issuer.infrastructure.controller; -// -//import es.in2.issuer.domain.model.*; -//import es.in2.issuer.domain.service.AccessTokenService; -//import es.in2.issuer.domain.service.CredentialManagementService; -//import org.junit.jupiter.api.Test; -//import org.junit.jupiter.api.extension.ExtendWith; -//import org.mockito.*; -//import org.mockito.junit.jupiter.MockitoExtension; -//import org.springframework.data.domain.Sort; -//import org.springframework.http.HttpHeaders; -//import org.springframework.http.MediaType; -//import org.springframework.test.web.reactive.server.WebTestClient; -//import reactor.core.publisher.Flux; -//import reactor.core.publisher.Mono; -//import reactor.test.StepVerifier; -// -//import java.sql.Timestamp; -//import java.util.Collections; -//import java.util.HashMap; -//import java.util.Map; -//import java.util.UUID; -// -//import static org.junit.jupiter.api.Assertions.*; -//import static org.mockito.Mockito.*; -// -//@ExtendWith(MockitoExtension.class) -//class DeferredCredentialMetadataControllerTest { -// @Mock -// private CredentialManagementService credentialManagementService; -// -// @Mock -// private AccessTokenService accessTokenService; -// -// @InjectMocks -// private CredentialManagementController controller; -// -// @Test -// void testGetCredential(){ -// // Arrange -// UUID credentialId = UUID.fromString("b3787fd6-42a3-47ad-a2f7-26efdc742505"); -// Timestamp credentialModifiedAt = Timestamp.valueOf("2024-04-29 16:41:02.565"); -// Map credential = new HashMap<>(); -// credential.put("key1", "value1"); -// -// //Example Token with claim "sub" : "1234567890" -// String mockTokenString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwicHJlZmVycmVkX3VzZXJuYW1lIjoidXNlcm5hbWUiLCJpYXQiOjE1MTYyMzkwMjJ9.3Ye-IUQRtSkYGVVZSjGqlVtnQNCsAwz_qPgkmgxkleg"; -// CredentialItem mockResponse = new CredentialItem(UUID.fromString("b3787fd6-42a3-47ad-a2f7-26efdc742505"), credential, "jwt_vc_json", "VALID", credentialModifiedAt); -// -// when(accessTokenService.getCleanBearerToken(any())).thenReturn(Mono.just(mockTokenString)); -// when(accessTokenService.getUserIdFromHeader(any())).thenReturn(Mono.just("1234567890")); -// when(credentialManagementService.getCredential(credentialId, "1234567890")) -// .thenReturn(Mono.just(mockResponse)); -// -// // Act -// Mono result = controller.getCredential("Bearer "+mockTokenString, credentialId); -// -// // Assert -// result.subscribe(response -> assertEquals(mockResponse, response)); -// -// verify(credentialManagementService, times(1)) -// .getCredential(credentialId, "1234567890"); -// } -// -// @Test -// void testGetCredentials() { -// // Arrange -// UUID credentialId1 = UUID.fromString("b3787fd6-42a3-47ad-a2f7-26efdc742505"); -// UUID credentialId2 = UUID.fromString("a1987bc9-08f7-4b93-9177-67897b123456"); -// Timestamp timestamp = Timestamp.valueOf("2024-04-29 16:41:02.565"); -// Map credentialDetails = new HashMap<>(); -// credentialDetails.put("key1", "value1"); -// -// CredentialItem credentialItem1 = new CredentialItem(credentialId1, credentialDetails, "jwt_vc_json", "VALID", timestamp); -// CredentialItem credentialItem2 = new CredentialItem(credentialId2, credentialDetails, "jwt_vc_json", "VALID", timestamp); -// -// String mockTokenString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwicHJlZmVycmVkX3VzZXJuYW1lIjoidXNlcm5hbWUiLCJpYXQiOjE1MTYyMzkwMjJ9.3Ye-IUQRtSkYGVVZSjGqlVtnQNCsAwz_qPgkmgxkleg"; -// -// when(accessTokenService.getUserIdFromHeader(any())).thenReturn(Mono.just("1234567890")); -// when(credentialManagementService.getCredentials("1234567890", 0, 10, "modifiedAt", Sort.Direction.DESC)) -// .thenReturn(Flux.just(credentialItem1, credentialItem2)); -// -// // Act -// Flux result = controller.getCredentials("Bearer "+mockTokenString, 0, 10, "modifiedAt", Sort.Direction.DESC); -// -// // Assert -// StepVerifier.create(result) -// .expectNext(credentialItem1) -// .expectNext(credentialItem2) -// .verifyComplete(); -// -// verify(credentialManagementService, times(1)) -// .getCredentials("1234567890", 0, 10, "modifiedAt", Sort.Direction.DESC); -// } -// -// @Test -// void testUpdateCredentials() { -// WebTestClient webTestClient = WebTestClient.bindToController(controller).build(); -// String authorizationHeader = "Bearer test-token"; -// SignedCredentials signedCredentials = SignedCredentials.builder().credentials(Collections.singletonList(SignedCredentials.SignedCredential.builder().credential("test").build())).build(); // Assume this class exists -// String userId = "user-id"; -// -// when(accessTokenService.getUserIdFromHeader(authorizationHeader)).thenReturn(Mono.just(userId)); -// when(credentialManagementService.updateCredentials(signedCredentials, userId)).thenReturn(Mono.empty()); -// -// webTestClient.post() -// .uri("/api/v1/credentials") -// .header(HttpHeaders.AUTHORIZATION, authorizationHeader) -// .contentType(MediaType.APPLICATION_JSON) -// .bodyValue(signedCredentials) -// .exchange() -// .expectStatus().isNoContent(); -// } -//} \ No newline at end of file +package es.in2.issuer.infrastructure.controller; + +import es.in2.issuer.application.workflow.VerifiableCredentialIssuanceWorkflow; +import es.in2.issuer.domain.model.dto.AuthServerNonceRequest; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class DeferredCredentialMetadataControllerTest { + + @Mock + private VerifiableCredentialIssuanceWorkflow verifiableCredentialIssuanceWorkflow; + + @InjectMocks + private DeferredCredentialMetadataController deferredCredentialMetadataController; + + @Test + void bindAccessTokenByPreAuthorizedCode() { + // Arrange + AuthServerNonceRequest authServerNonceRequest = new AuthServerNonceRequest("pre-authorized-code", "access-token"); + when(verifiableCredentialIssuanceWorkflow.bindAccessTokenByPreAuthorizedCode(anyString(), eq(authServerNonceRequest))).thenReturn(Mono.empty()); + + // Act + Mono result = deferredCredentialMetadataController.bindAccessTokenByPreAuthorizedCode(authServerNonceRequest); + + // Assert + StepVerifier.create(result) + .verifyComplete(); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/infrastructure/controller/GlobalExceptionHandlerTest.java b/src/test/java/es/in2/issuer/infrastructure/controller/GlobalExceptionHandlerTest.java index 63f59a2ec..02339a869 100644 --- a/src/test/java/es/in2/issuer/infrastructure/controller/GlobalExceptionHandlerTest.java +++ b/src/test/java/es/in2/issuer/infrastructure/controller/GlobalExceptionHandlerTest.java @@ -1,8 +1,5 @@ package es.in2.issuer.infrastructure.controller; -import static org.mockito.Mockito.*; -import static org.junit.jupiter.api.Assertions.*; - import es.in2.issuer.domain.exception.*; import es.in2.issuer.domain.model.dto.CredentialErrorResponse; import es.in2.issuer.domain.model.dto.GlobalErrorMessage; @@ -19,6 +16,10 @@ import java.time.LocalDateTime; import java.util.NoSuchElementException; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + class GlobalExceptionHandlerTest { private GlobalExceptionHandler globalExceptionHandler; private WebRequest mockWebRequest; @@ -140,6 +141,23 @@ void handleUserDoesNotExist() { .verifyComplete(); } + @Test + void handleUserDoesNotExistException_withMessage() { + String errorMessage = "Error message for testing"; + UserDoesNotExistException userDoesNotExistException = new UserDoesNotExistException(errorMessage); + + Mono> responseEntityMono = globalExceptionHandler.handleUserDoesNotExistException(userDoesNotExistException); + + StepVerifier.create(responseEntityMono) + .assertNext(responseEntity -> { + assertEquals(HttpStatus.NOT_FOUND, responseEntity.getStatusCode()); + assertNotNull(responseEntity.getBody()); + assertEquals(CredentialResponseErrorCodes.USER_DOES_NOT_EXIST, responseEntity.getBody().error()); + assertEquals(errorMessage, responseEntity.getBody().description()); + }) + .verifyComplete(); + } + @Test void handleVcTemplateDoesNotExist() { VcTemplateDoesNotExistException exception = new VcTemplateDoesNotExistException(null); @@ -156,6 +174,23 @@ void handleVcTemplateDoesNotExist() { .verifyComplete(); } + @Test + void handleVcTemplateDoesNotExist_withMessage() { + String errorMessage = "Error message for testing"; + VcTemplateDoesNotExistException vcTemplateDoesNotExistException = new VcTemplateDoesNotExistException(errorMessage); + + Mono> responseEntityMono = globalExceptionHandler.vcTemplateDoesNotExist(vcTemplateDoesNotExistException); + + StepVerifier.create(responseEntityMono) + .assertNext(responseEntity -> { + assertEquals(HttpStatus.NOT_FOUND, responseEntity.getStatusCode()); + assertNotNull(responseEntity.getBody()); + assertEquals(CredentialResponseErrorCodes.VC_TEMPLATE_DOES_NOT_EXIST, responseEntity.getBody().error()); + assertEquals(errorMessage, responseEntity.getBody().description()); + }) + .verifyComplete(); + } + @Test void handleParseException() { ParseException exception = new ParseException("Error message", 213); diff --git a/src/test/java/es/in2/issuer/infrastructure/controller/NotificationControllerTest.java b/src/test/java/es/in2/issuer/infrastructure/controller/NotificationControllerTest.java new file mode 100644 index 000000000..1180d1c5c --- /dev/null +++ b/src/test/java/es/in2/issuer/infrastructure/controller/NotificationControllerTest.java @@ -0,0 +1,38 @@ +package es.in2.issuer.infrastructure.controller; + +import es.in2.issuer.domain.service.NotificationService; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class NotificationControllerTest { + + @Mock + private NotificationService notificationService; + + @InjectMocks + private NotificationController notificationController; + + @Test + void sendEmailNotification() { + // Arrange + String procedureId = "testProcedureId"; + when(notificationService.sendNotification(anyString(), eq(procedureId))).thenReturn(Mono.empty()); + + // Act + Mono result = notificationController.sendEmailNotification(procedureId); + + // Assert + StepVerifier.create(result) + .verifyComplete(); + } +} \ No newline at end of file diff --git a/src/test/java/es/in2/issuer/infrastructure/controller/VerifiableCredentialControllerTest.java b/src/test/java/es/in2/issuer/infrastructure/controller/VerifiableCredentialControllerTest.java deleted file mode 100644 index 2eb7a7e4a..000000000 --- a/src/test/java/es/in2/issuer/infrastructure/controller/VerifiableCredentialControllerTest.java +++ /dev/null @@ -1,98 +0,0 @@ -//package es.in2.issuer.infrastructure.controller; -// -//import es.in2.issuer.application.service.impl.VerifiableCredentialIssuanceServiceImpl; -//import es.in2.issuer.domain.model.*; -//import es.in2.issuer.domain.service.AccessTokenService; -//import org.junit.jupiter.api.Test; -//import org.junit.jupiter.api.extension.ExtendWith; -//import org.mockito.InjectMocks; -//import org.mockito.Mock; -//import org.mockito.junit.jupiter.MockitoExtension; -//import reactor.core.publisher.Mono; -// -//import java.util.List; -// -//import static org.junit.jupiter.api.Assertions.*; -//import static org.mockito.Mockito.*; -// -//@ExtendWith(MockitoExtension.class) -//class VerifiableCredentialControllerTest { -// -// @Mock -// private VerifiableCredentialIssuanceServiceImpl verifiableCredentialIssuanceService; -// -// @Mock -// private AccessTokenService accessTokenService; -// -// @InjectMocks -// private VerifiableCredentialController controller; -// -// @Test -// void testCreateVerifiableCredential_Success() { -// // Arrange -// CredentialRequest mockCredentialRequest = new CredentialRequest("format",new CredentialDefinition(List.of("")), new Proof("proofType", "jwt")); -// //Example Token with claim "sub" : "1234567890" -// String mockTokenString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwicHJlZmVycmVkX3VzZXJuYW1lIjoidXNlcm5hbWUiLCJpYXQiOjE1MTYyMzkwMjJ9.3Ye-IUQRtSkYGVVZSjGqlVtnQNCsAwz_qPgkmgxkleg"; -// VerifiableCredentialResponse mockResponse = new VerifiableCredentialResponse(null, "123-1234-1243", "nonce", 600); -// -// when(accessTokenService.getCleanBearerToken(any())).thenReturn(Mono.just(mockTokenString)); -// when(accessTokenService.getUserIdFromHeader(any())).thenReturn(Mono.just("1234567890")); -// when(verifiableCredentialIssuanceService.generateVerifiableCredentialResponse("1234567890", mockCredentialRequest, mockTokenString)) -// .thenReturn(Mono.just(mockResponse)); -// -// // Act -// Mono result = controller.createVerifiableCredential("Bearer "+mockTokenString, mockCredentialRequest); -// -// // Assert -// result.subscribe(response -> assertEquals(mockResponse, response)); -// -// verify(verifiableCredentialIssuanceService, times(1)) -// .generateVerifiableCredentialResponse("1234567890", mockCredentialRequest, mockTokenString); -// } -// -// @Test -// void testGetCredential_Success() { -// // Arrange -// DeferredCredentialRequest mockCredentialRequest = new DeferredCredentialRequest("123-1234-1243"); -// //Example Token with claim "sub" : "1234567890" -// String mockTokenString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwicHJlZmVycmVkX3VzZXJuYW1lIjoidXNlcm5hbWUiLCJpYXQiOjE1MTYyMzkwMjJ9.3Ye-IUQRtSkYGVVZSjGqlVtnQNCsAwz_qPgkmgxkleg"; -// VerifiableCredentialResponse mockResponse = new VerifiableCredentialResponse("credential", null, "nonce", 600); -// -// when(accessTokenService.getCleanBearerToken(any())).thenReturn(Mono.just(mockTokenString)); -// when(accessTokenService.getUserIdFromHeader(any())).thenReturn(Mono.just("1234567890")); -// when(verifiableCredentialIssuanceService.generateVerifiableCredentialDeferredResponse("1234567890", mockCredentialRequest, mockTokenString)) -// .thenReturn(Mono.just(mockResponse)); -// -// // Act -// Mono result = controller.getCredential("Bearer "+mockTokenString, mockCredentialRequest); -// -// // Assert -// result.subscribe(response -> assertEquals(mockResponse, response)); -// -// verify(verifiableCredentialIssuanceService, times(1)) -// .generateVerifiableCredentialDeferredResponse("1234567890", mockCredentialRequest, mockTokenString); -// } -// -// @Test -// void testCreateVerifiableCredentials_Success() { -// // Arrange -// BatchCredentialRequest mockCredentialRequest = new BatchCredentialRequest(List.of(new CredentialRequest("format",new CredentialDefinition(List.of("")), new Proof("proofType", "jwt")))); -// //Example Token with claim "sub" : "1234567890" -// String mockTokenString = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwicHJlZmVycmVkX3VzZXJuYW1lIjoidXNlcm5hbWUiLCJpYXQiOjE1MTYyMzkwMjJ9.3Ye-IUQRtSkYGVVZSjGqlVtnQNCsAwz_qPgkmgxkleg"; -// BatchCredentialResponse mockResponse = new BatchCredentialResponse(List.of(new BatchCredentialResponse.CredentialResponse("credential"))); -// -// when(accessTokenService.getCleanBearerToken(any())).thenReturn(Mono.just(mockTokenString)); -// when(accessTokenService.getUserIdFromHeader(any())).thenReturn(Mono.just("1234567890")); -// when(verifiableCredentialIssuanceService.generateVerifiableCredentialBatchResponse("1234567890", mockCredentialRequest, mockTokenString)) -// .thenReturn(Mono.just(mockResponse)); -// -// // Act -// Mono result = controller.createVerifiableCredentials("Bearer "+mockTokenString, mockCredentialRequest); -// -// // Assert -// result.subscribe(response -> assertEquals(mockResponse, response)); -// -// verify(verifiableCredentialIssuanceService, times(1)) -// .generateVerifiableCredentialBatchResponse("1234567890", mockCredentialRequest, mockTokenString); -// } -//}