diff --git a/build.gradle b/build.gradle index e70e5c513..a02339f0a 100644 --- a/build.gradle +++ b/build.gradle @@ -2,10 +2,10 @@ import java.time.OffsetDateTime import java.time.format.DateTimeFormatter plugins { - id 'java-library' + id 'io.seqera.wave.java-library-conventions' id 'io.seqera.wave.groovy-application-conventions' - id "com.github.johnrengelman.shadow" version "7.1.1" - id "io.micronaut.minimal.application" version "3.7.0" + id "com.github.johnrengelman.shadow" version "8.1.1" + id "io.micronaut.minimal.application" version "4.1.1" id "com.google.cloud.tools.jib" version "3.4.2" id 'org.asciidoctor.jvm.convert' version '3.3.2' id 'jacoco' @@ -29,12 +29,13 @@ repositories { } dependencies { + annotationProcessor("io.micronaut.validation:micronaut-validation-processor") annotationProcessor("io.micronaut:micronaut-http-validation") compileOnly("io.micronaut.data:micronaut-data-processor") compileOnly("io.micronaut:micronaut-inject-groovy") compileOnly("io.micronaut:micronaut-http-validation") implementation("jakarta.persistence:jakarta.persistence-api:3.0.0") - api 'io.seqera:lib-mail:1.0.0' + api 'io.seqera:lib-mail:1.1.0' api 'io.seqera:wave-api:0.13.3' api 'io.seqera:wave-utils:0.14.1' implementation("io.micronaut:micronaut-http-client") @@ -43,13 +44,14 @@ dependencies { implementation("io.micronaut.reactor:micronaut-reactor") implementation("io.micronaut.reactor:micronaut-reactor-http-client") implementation("jakarta.annotation:jakarta.annotation-api") - implementation("io.micronaut:micronaut-validation") + implementation("io.micronaut.validation:micronaut-validation") implementation 'io.micronaut.security:micronaut-security' - implementation "org.codehaus.groovy:groovy-json" - implementation "org.codehaus.groovy:groovy-nio" + implementation "org.apache.groovy:groovy-json" + implementation "org.apache.groovy:groovy-nio" implementation 'com.google.guava:guava:32.1.2-jre' implementation 'dev.failsafe:failsafe:3.1.0' - implementation('io.projectreactor:reactor-core') + implementation 'io.micronaut.reactor:micronaut-reactor' + implementation 'io.micronaut.reactor:micronaut-reactor-http-client' implementation("io.seqera:tower-crypto:22.4.0-watson") { transitive = false } // to be replaced with 22.4.0 once released implementation 'org.apache.commons:commons-compress:1.27.1' implementation 'org.apache.commons:commons-lang3:3.12.0' @@ -62,6 +64,7 @@ dependencies { implementation 'com.squareup.moshi:moshi-adapters:1.14.0' implementation 'redis.clients:jedis:5.1.3' implementation "io.github.resilience4j:resilience4j-ratelimiter:0.17.0" + implementation("io.micronaut:micronaut-retry") // caching deps implementation("io.micronaut.cache:micronaut-cache-core") implementation("io.micronaut.cache:micronaut-cache-caffeine") @@ -85,7 +88,7 @@ dependencies { testImplementation("org.testcontainers:mysql:1.17.3") // -- - implementation("ch.qos.logback:logback-classic:1.4.8") + implementation("ch.qos.logback:logback-classic:1.5.3") // rate limit implementation 'com.coveo:spillway:3.0.0' diff --git a/buildSrc/src/main/groovy/io.seqera.wave.groovy-application-conventions.gradle b/buildSrc/src/main/groovy/io.seqera.wave.groovy-application-conventions.gradle index 0cf39fc5e..c14579b32 100644 --- a/buildSrc/src/main/groovy/io.seqera.wave.groovy-application-conventions.gradle +++ b/buildSrc/src/main/groovy/io.seqera.wave.groovy-application-conventions.gradle @@ -12,7 +12,7 @@ plugins { group = 'io.seqera' -tasks.withType(Test) { +tasks.withType(Test).configureEach { // note: "--enable-preview" is required to use virtual thread on Java 19 and 20 - jvmArgs (["--enable-preview"]) + jvmArgs(["--enable-preview"]) } diff --git a/buildSrc/src/main/groovy/io.seqera.wave.groovy-common-conventions.gradle b/buildSrc/src/main/groovy/io.seqera.wave.groovy-common-conventions.gradle index da3059f91..915567a14 100644 --- a/buildSrc/src/main/groovy/io.seqera.wave.groovy-common-conventions.gradle +++ b/buildSrc/src/main/groovy/io.seqera.wave.groovy-common-conventions.gradle @@ -22,9 +22,9 @@ compileJava { options.release.set(11) } -tasks.withType(GroovyCompile) { - sourceCompatibility = '11' - targetCompatibility = '11' +tasks.withType(GroovyCompile).configureEach { + sourceCompatibility = '17' + targetCompatibility = '17' } group = 'io.seqera' diff --git a/buildSrc/src/main/groovy/io.seqera.wave.java-library-conventions.gradle b/buildSrc/src/main/groovy/io.seqera.wave.java-library-conventions.gradle index f6197b641..8a690aede 100644 --- a/buildSrc/src/main/groovy/io.seqera.wave.java-library-conventions.gradle +++ b/buildSrc/src/main/groovy/io.seqera.wave.java-library-conventions.gradle @@ -24,9 +24,9 @@ compileJava { options.release.set(11) } -tasks.withType(GroovyCompile) { - sourceCompatibility = '11' - targetCompatibility = '11' +tasks.withType(GroovyCompile).configureEach { + sourceCompatibility = '17' + targetCompatibility = '17' } test { @@ -40,21 +40,21 @@ java { } dependencies { - implementation 'org.slf4j:slf4j-api:1.7.36' + implementation 'org.slf4j:slf4j-api:2.0.13' - testImplementation 'ch.qos.logback:logback-core:1.2.11' - testImplementation 'ch.qos.logback:logback-classic:1.2.11' - testImplementation "org.codehaus.groovy:groovy:3.0.15" - testImplementation "org.codehaus.groovy:groovy-nio:3.0.15" - testImplementation ("org.codehaus.groovy:groovy-test:3.0.17") - testImplementation ("cglib:cglib-nodep:3.3.0") - testImplementation ("org.objenesis:objenesis:3.2") - testImplementation ("org.spockframework:spock-core:2.3-groovy-3.0") { exclude group: 'org.codehaus.groovy'; exclude group: 'net.bytebuddy' } - testImplementation ('org.spockframework:spock-junit4:2.3-groovy-3.0') { exclude group: 'org.codehaus.groovy'; exclude group: 'net.bytebuddy' } + testImplementation 'ch.qos.logback:logback-core:1.4.11' + testImplementation 'ch.qos.logback:logback-classic:1.4.11' + testImplementation 'org.apache.groovy:groovy:4.0.15' + testImplementation 'org.apache.groovy:groovy-nio:4.0.15' + testImplementation 'org.apache.groovy:groovy-test:4.0.15' + testImplementation 'org.objenesis:objenesis:3.4' + testImplementation 'net.bytebuddy:byte-buddy:1.14.17' + testImplementation 'org.spockframework:spock-core:2.3-groovy-4.0' + testImplementation 'org.spockframework:spock-junit4:2.3-groovy-4.0' } -tasks.withType(Test) { - jvmArgs ([ +tasks.withType(Test).configureEach { + jvmArgs([ '--enable-preview', '--add-opens=java.base/java.lang=ALL-UNNAMED', '--add-opens=java.base/java.io=ALL-UNNAMED', diff --git a/gradle.properties b/gradle.properties index 645585ab7..54b62b375 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,5 +16,5 @@ # along with this program. If not, see . # -micronautVersion=3.10.3 +micronautVersion=4.6.3 micronautEnvs=dev,h2,mail,aws-ses diff --git a/src/main/groovy/io/seqera/wave/auth/BasicAuthenticationProvider.groovy b/src/main/groovy/io/seqera/wave/auth/BasicAuthenticationProvider.groovy index b76abda4e..d76ff89ee 100644 --- a/src/main/groovy/io/seqera/wave/auth/BasicAuthenticationProvider.groovy +++ b/src/main/groovy/io/seqera/wave/auth/BasicAuthenticationProvider.groovy @@ -19,18 +19,17 @@ package io.seqera.wave.auth import groovy.util.logging.Slf4j +import io.micronaut.core.annotation.NonNull import io.micronaut.core.annotation.Nullable import io.micronaut.http.HttpRequest -import io.micronaut.security.authentication.AuthenticationProvider +import io.micronaut.security.authentication.AuthenticationFailureReason import io.micronaut.security.authentication.AuthenticationRequest import io.micronaut.security.authentication.AuthenticationResponse +import io.micronaut.security.authentication.provider.HttpRequestAuthenticationProvider import io.seqera.wave.service.account.AccountService import io.seqera.wave.util.StringUtils import jakarta.inject.Inject import jakarta.inject.Singleton -import org.reactivestreams.Publisher -import reactor.core.publisher.Flux -import reactor.core.publisher.FluxSink /** * Basic Authentication provider * @@ -38,25 +37,22 @@ import reactor.core.publisher.FluxSink */ @Slf4j @Singleton -class BasicAuthenticationProvider implements AuthenticationProvider { +class BasicAuthenticationProvider implements HttpRequestAuthenticationProvider { @Inject private AccountService accountService @Override - Publisher authenticate(@Nullable HttpRequest httpRequest, AuthenticationRequest authRequest) { - Flux.create(emitter -> { - final user = authRequest.identity?.toString() - final pass = authRequest.secret?.toString() - if (accountService.isAuthorised(user, pass)) { - log.trace "Auth request OK - user '$user'; password: '${StringUtils.redact(pass)}'" - emitter.next(AuthenticationResponse.success((String) authRequest.identity)) - emitter.complete() - } - else { - log.trace "Auth request FAILED - user '$user'; password: '${StringUtils.redact(pass)}'" - emitter.error(AuthenticationResponse.exception()) - } - }, FluxSink.OverflowStrategy.ERROR) + AuthenticationResponse authenticate(@Nullable HttpRequest httpRequest, @NonNull AuthenticationRequest authRequest) { + final user = authRequest.identity?.toString() + final pass = authRequest.secret?.toString() + if (accountService.isAuthorised(user, pass)) { + log.trace "Auth request OK - user '$user'; password: '${StringUtils.redact(pass)}'" + return AuthenticationResponse.success(authRequest.identity) + } + else { + log.trace "Auth request FAILED - user '$user'; password: '${StringUtils.redact(pass)}'" + return AuthenticationResponse.failure(AuthenticationFailureReason.CREDENTIALS_DO_NOT_MATCH) + } } } diff --git a/src/main/groovy/io/seqera/wave/auth/RegistryConfig.groovy b/src/main/groovy/io/seqera/wave/auth/RegistryConfig.groovy index eb43f3dad..560a784a5 100644 --- a/src/main/groovy/io/seqera/wave/auth/RegistryConfig.groovy +++ b/src/main/groovy/io/seqera/wave/auth/RegistryConfig.groovy @@ -47,7 +47,7 @@ class RegistryConfig { * io: [ ... ] * ] */ - private Map registries + Map registries RegistryKeys getRegistryKeys(String registryName) { final String defaultRegistry = registries.get('default')?.toString() ?: 'docker.io' diff --git a/src/main/groovy/io/seqera/wave/configuration/ScanConfig.groovy b/src/main/groovy/io/seqera/wave/configuration/ScanConfig.groovy index baef40d75..5a5ac6006 100644 --- a/src/main/groovy/io/seqera/wave/configuration/ScanConfig.groovy +++ b/src/main/groovy/io/seqera/wave/configuration/ScanConfig.groovy @@ -95,7 +95,11 @@ class ScanConfig { @Memoized Path getCacheDirectory() { final result = Path.of(buildDirectory).toAbsolutePath().resolve('.trivy-cache') - Files.createDirectories(result) + try { + Files.createDirectories(result) + } catch (IOException e) { + log.error "Unable to create scan cache directory=${result} - cause: ${e.message}" + } return result } diff --git a/src/main/groovy/io/seqera/wave/controller/ContainerController.groovy b/src/main/groovy/io/seqera/wave/controller/ContainerController.groovy index fabef4017..10f71ddb4 100644 --- a/src/main/groovy/io/seqera/wave/controller/ContainerController.groovy +++ b/src/main/groovy/io/seqera/wave/controller/ContainerController.groovy @@ -29,6 +29,7 @@ import io.micronaut.context.annotation.Value import io.micronaut.core.annotation.Nullable import io.micronaut.http.HttpRequest import io.micronaut.http.HttpResponse +import io.micronaut.http.annotation.Body import io.micronaut.http.annotation.Controller import io.micronaut.http.annotation.Delete import io.micronaut.http.annotation.Error @@ -181,13 +182,13 @@ class ContainerController { @Deprecated @Post('/container-token') @ExecuteOn(TaskExecutors.IO) - CompletableFuture> getToken(HttpRequest httpRequest, SubmitContainerTokenRequest req) { + CompletableFuture> getToken(HttpRequest httpRequest, @Body SubmitContainerTokenRequest req) { return getContainerImpl(httpRequest, req, false) } @Post('/v1alpha2/container') @ExecuteOn(TaskExecutors.IO) - CompletableFuture> getTokenV2(HttpRequest httpRequest, SubmitContainerTokenRequest req) { + CompletableFuture> getTokenV2(HttpRequest httpRequest, @Body SubmitContainerTokenRequest req) { return getContainerImpl(httpRequest, req, true) } diff --git a/src/main/groovy/io/seqera/wave/controller/InspectController.groovy b/src/main/groovy/io/seqera/wave/controller/InspectController.groovy index 88d66f9b8..35e50bc58 100644 --- a/src/main/groovy/io/seqera/wave/controller/InspectController.groovy +++ b/src/main/groovy/io/seqera/wave/controller/InspectController.groovy @@ -25,6 +25,7 @@ import groovy.util.logging.Slf4j import io.micronaut.context.annotation.Value import io.micronaut.core.annotation.Nullable import io.micronaut.http.HttpResponse +import io.micronaut.http.annotation.Body import io.micronaut.http.annotation.Controller import io.micronaut.http.annotation.Post import io.micronaut.http.annotation.QueryValue @@ -70,7 +71,7 @@ class InspectController { private String serverUrl @Post("/v1alpha1/inspect") - CompletableFuture> inspect(ContainerInspectRequest req, @Nullable @QueryValue String platform) { + CompletableFuture> inspect(@Body ContainerInspectRequest req, @Nullable @QueryValue String platform) { if( !req.containerImage ) throw new BadRequestException("Missing 'containerImage' attribute") diff --git a/src/main/groovy/io/seqera/wave/controller/ValidateController.groovy b/src/main/groovy/io/seqera/wave/controller/ValidateController.groovy index 631d0bcc8..f12e794dd 100644 --- a/src/main/groovy/io/seqera/wave/controller/ValidateController.groovy +++ b/src/main/groovy/io/seqera/wave/controller/ValidateController.groovy @@ -18,14 +18,14 @@ package io.seqera.wave.controller -import javax.validation.Valid - +import io.micronaut.http.annotation.Body import io.micronaut.http.annotation.Controller import io.micronaut.http.annotation.Post import io.micronaut.scheduling.TaskExecutors import io.micronaut.scheduling.annotation.ExecuteOn import io.seqera.wave.auth.RegistryAuthService import jakarta.inject.Inject +import jakarta.validation.Valid import reactor.core.publisher.Mono @ExecuteOn(TaskExecutors.IO) @@ -35,7 +35,7 @@ class ValidateController { @Inject RegistryAuthService loginService @Post - Mono validateCreds(@Valid ValidateRegistryCredsRequest request){ + Mono validateCreds(@Valid @Body ValidateRegistryCredsRequest request){ Mono.just( loginService.validateUser(request.registry, request.userName, request.password) ) diff --git a/src/main/groovy/io/seqera/wave/controller/ValidateRegistryCredsRequest.groovy b/src/main/groovy/io/seqera/wave/controller/ValidateRegistryCredsRequest.groovy index db465ef0a..3fbe92d07 100644 --- a/src/main/groovy/io/seqera/wave/controller/ValidateRegistryCredsRequest.groovy +++ b/src/main/groovy/io/seqera/wave/controller/ValidateRegistryCredsRequest.groovy @@ -18,10 +18,8 @@ package io.seqera.wave.controller -import io.micronaut.core.annotation.Nullable -import javax.validation.constraints.NotBlank - import io.micronaut.core.annotation.Introspected +import jakarta.validation.constraints.NotBlank @Introspected class ValidateRegistryCredsRequest { diff --git a/src/main/groovy/io/seqera/wave/exchange/PairingRequest.groovy b/src/main/groovy/io/seqera/wave/exchange/PairingRequest.groovy index b54ac876d..fb17c68ec 100644 --- a/src/main/groovy/io/seqera/wave/exchange/PairingRequest.groovy +++ b/src/main/groovy/io/seqera/wave/exchange/PairingRequest.groovy @@ -18,11 +18,10 @@ package io.seqera.wave.exchange -import javax.validation.constraints.NotBlank -import javax.validation.constraints.NotNull - import groovy.transform.CompileStatic import io.micronaut.core.annotation.Introspected +import jakarta.validation.constraints.NotBlank +import jakarta.validation.constraints.NotNull /** * Model the request for a remote service instance to register diff --git a/src/main/groovy/io/seqera/wave/proxy/ErrResponse.groovy b/src/main/groovy/io/seqera/wave/proxy/ErrResponse.groovy index 7283fb205..5905f539e 100644 --- a/src/main/groovy/io/seqera/wave/proxy/ErrResponse.groovy +++ b/src/main/groovy/io/seqera/wave/proxy/ErrResponse.groovy @@ -90,17 +90,17 @@ class ErrResponse implements HttpResponse { } static ErrResponse forString(String msg, HttpRequest request) { - final head = HttpHeaders.of('Content-Type': ['text/plain'], {true}) + final head = HttpHeaders.of('Content-Type': ['text/plain'], (a, b) -> true) new ErrResponse(statusCode: 400, body: msg, request: request, uri: request.uri(), headers: head) } static ErrResponse forStream(String msg, HttpRequest request) { - final head = HttpHeaders.of('Content-Type': ['text/plain'], {true}) + final head = HttpHeaders.of('Content-Type': ['text/plain'], (a, b) -> true) new ErrResponse(statusCode: 400, body: new ByteArrayInputStream(msg.bytes), request: request, uri: request.uri(), headers: head) } static ErrResponse forByteArray(String msg, HttpRequest request) { - final head = HttpHeaders.of('Content-Type': ['text/plain'], {true}) + final head = HttpHeaders.of('Content-Type': ['text/plain'], (a, b) -> true) new ErrResponse(statusCode: 400, body: msg.bytes, request: request, uri: request.uri(), headers: head) } } diff --git a/src/main/groovy/io/seqera/wave/ratelimit/impl/SpillWayStorageFactory.groovy b/src/main/groovy/io/seqera/wave/ratelimit/impl/SpillWayStorageFactory.groovy index c7431642f..cc6f9d036 100644 --- a/src/main/groovy/io/seqera/wave/ratelimit/impl/SpillWayStorageFactory.groovy +++ b/src/main/groovy/io/seqera/wave/ratelimit/impl/SpillWayStorageFactory.groovy @@ -18,8 +18,6 @@ package io.seqera.wave.ratelimit.impl -import javax.validation.constraints.NotNull - import com.coveo.spillway.storage.InMemoryStorage import com.coveo.spillway.storage.LimitUsageStorage import com.coveo.spillway.storage.RedisStorage @@ -27,9 +25,9 @@ import groovy.transform.CompileStatic import groovy.util.logging.Slf4j import io.micronaut.context.annotation.Factory import io.micronaut.context.annotation.Requires -import io.seqera.wave.configuration.RateLimiterConfig import io.seqera.wave.configuration.RedisConfig import jakarta.inject.Singleton +import jakarta.validation.constraints.NotNull import redis.clients.jedis.JedisPool /** diff --git a/src/main/groovy/io/seqera/wave/ratelimit/impl/SpillwayRateLimiter.groovy b/src/main/groovy/io/seqera/wave/ratelimit/impl/SpillwayRateLimiter.groovy index 358e951dd..e2c9eab60 100644 --- a/src/main/groovy/io/seqera/wave/ratelimit/impl/SpillwayRateLimiter.groovy +++ b/src/main/groovy/io/seqera/wave/ratelimit/impl/SpillwayRateLimiter.groovy @@ -18,8 +18,6 @@ package io.seqera.wave.ratelimit.impl -import javax.validation.constraints.NotNull - import com.coveo.spillway.Spillway import com.coveo.spillway.SpillwayFactory import com.coveo.spillway.limit.Limit @@ -34,6 +32,7 @@ import io.seqera.wave.exception.SlowDownException import io.seqera.wave.ratelimit.AcquireRequest import io.seqera.wave.ratelimit.RateLimiterService import jakarta.inject.Singleton +import jakarta.validation.constraints.NotNull /** * This class manage how many requests can be requested from an user during a configurable period * @@ -60,7 +59,7 @@ class SpillwayRateLimiter implements RateLimiterService { init(storage, config) } - protected void init(@NotNull LimitUsageStorage storage, @NotNull RateLimiterConfig config){ + protected void init(LimitUsageStorage storage, RateLimiterConfig config){ SpillwayFactory spillwayFactory = new SpillwayFactory(storage) initBuilds(spillwayFactory, config) initPulls(spillwayFactory, config) diff --git a/src/main/groovy/io/seqera/wave/service/account/AccountServiceImpl.groovy b/src/main/groovy/io/seqera/wave/service/account/AccountServiceImpl.groovy index 3cccda9ab..f8d6bb4f1 100644 --- a/src/main/groovy/io/seqera/wave/service/account/AccountServiceImpl.groovy +++ b/src/main/groovy/io/seqera/wave/service/account/AccountServiceImpl.groovy @@ -36,7 +36,7 @@ import jakarta.annotation.PostConstruct @ConfigurationProperties('wave') class AccountServiceImpl implements AccountService { - private Map accounts = Map.of() + Map accounts = Map.of() @PostConstruct private dumpAccounts() { diff --git a/src/main/groovy/io/seqera/wave/service/pairing/socket/PairingWebSocket.groovy b/src/main/groovy/io/seqera/wave/service/pairing/socket/PairingWebSocket.groovy index 1605e3b96..a4f7b0785 100644 --- a/src/main/groovy/io/seqera/wave/service/pairing/socket/PairingWebSocket.groovy +++ b/src/main/groovy/io/seqera/wave/service/pairing/socket/PairingWebSocket.groovy @@ -25,6 +25,8 @@ import groovy.util.logging.Slf4j import io.micronaut.context.annotation.Value import io.micronaut.core.annotation.Nullable import io.micronaut.http.client.exceptions.HttpClientResponseException +import io.micronaut.scheduling.TaskExecutors +import io.micronaut.scheduling.annotation.ExecuteOn import io.micronaut.websocket.CloseReason import io.micronaut.websocket.WebSocketSession import io.micronaut.websocket.annotation.OnClose @@ -47,6 +49,7 @@ import static io.seqera.wave.util.LongRndKey.rndHex @Slf4j @CompileStatic @Singleton +@ExecuteOn(TaskExecutors.IO) @ServerWebSocket("/pairing/{service}/token/{token}{?endpoint}") class PairingWebSocket { diff --git a/src/main/groovy/io/seqera/wave/tower/User.groovy b/src/main/groovy/io/seqera/wave/tower/User.groovy index c8dbb71d8..bce993103 100644 --- a/src/main/groovy/io/seqera/wave/tower/User.groovy +++ b/src/main/groovy/io/seqera/wave/tower/User.groovy @@ -18,12 +18,12 @@ package io.seqera.wave.tower -import javax.validation.constraints.NotNull -import javax.validation.constraints.Size - import groovy.transform.CompileStatic import groovy.transform.EqualsAndHashCode import groovy.transform.ToString +import jakarta.validation.constraints.NotNull +import jakarta.validation.constraints.Size + /** * Model a tower user * diff --git a/src/test/groovy/io/seqera/wave/controller/ContainerControllerTest.groovy b/src/test/groovy/io/seqera/wave/controller/ContainerControllerTest.groovy index 1a4658f62..d582316b8 100644 --- a/src/test/groovy/io/seqera/wave/controller/ContainerControllerTest.groovy +++ b/src/test/groovy/io/seqera/wave/controller/ContainerControllerTest.groovy @@ -72,7 +72,6 @@ import jakarta.inject.Inject * @author Paolo Di Tommaso */ @MicronautTest -@Property(name='wave.build.workspace', value='/some/wsp') @Property(name='wave.build.repo', value='wave/build') @Property(name='wave.build.cache', value='wave/build/cache') class ContainerControllerTest extends Specification { diff --git a/src/test/groovy/io/seqera/wave/controller/RegistryControllerLocalTest.groovy b/src/test/groovy/io/seqera/wave/controller/RegistryControllerLocalTest.groovy index ef37f10ba..9057ac53e 100644 --- a/src/test/groovy/io/seqera/wave/controller/RegistryControllerLocalTest.groovy +++ b/src/test/groovy/io/seqera/wave/controller/RegistryControllerLocalTest.groovy @@ -142,16 +142,19 @@ class RegistryControllerLocalTest extends Specification implements DockerRegistr h.add('Accept', it) } }) - HttpResponse response = client.toBlocking().exchange(request, Map) + HttpResponse response = client.toBlocking().exchange(request, String) then: response.status() == HttpStatus.OK when: - def list = response.body().manifests.collect{ - String type = it.mediaType.indexOf("manifest") ? "manifests" : "blobs" - "/v2/$IMAGE/$type/$it.digest" + def parsedBody = new JsonSlurper().parseText(response.body.get()) as Map + and: + def list = parsedBody.manifests.collect { + String type = it.mediaType.contains("manifest") ? "manifests" : "blobs" + return "/v2/$IMAGE/$type/$it.digest" as String } + and: boolean fails = list.find{ url -> HttpRequest requestGet = HttpRequest.GET(url).headers({ h -> accept.each { diff --git a/src/test/groovy/io/seqera/wave/service/CredentialsServiceTest.groovy b/src/test/groovy/io/seqera/wave/service/CredentialsServiceTest.groovy index a2babb87d..66b2012b2 100644 --- a/src/test/groovy/io/seqera/wave/service/CredentialsServiceTest.groovy +++ b/src/test/groovy/io/seqera/wave/service/CredentialsServiceTest.groovy @@ -51,11 +51,9 @@ class CredentialsServiceTest extends Specification { @Inject CredentialsService credentialsService - @MockBean(TowerClient) TowerClient towerClient = Mock(TowerClient) - @MockBean(PairingService) PairingService securityService = Mock(PairingService) @@ -121,7 +119,6 @@ class CredentialsServiceTest extends Specification { noExceptionThrown() } - def 'should fail if keys where not registered for the tower endpoint'() { given: def identity = new PlatformId(new User(id:10), 10,"token",'endpoint') @@ -169,7 +166,7 @@ class CredentialsServiceTest extends Specification { registry: 'docker.io' ) and: - def identity = new PlatformId(new User(id:10), 10,"token",'tower.io', '101') + def identity = new PlatformId(new User(id:10), 100, 'token', 'tower.io', '101') def auth = JwtAuth.of(identity) when: @@ -185,7 +182,7 @@ class CredentialsServiceTest extends Specification { ) and: 'non matching credentials are listed' - 1 * towerClient.listCredentials('tower.io',auth,10) >> CompletableFuture.completedFuture(new ListCredentialsResponse( + 1 * towerClient.listCredentials('tower.io',auth,100) >> CompletableFuture.completedFuture(new ListCredentialsResponse( credentials: [nonContainerRegistryCredentials,otherRegistryCredentials] )) @@ -223,7 +220,7 @@ class CredentialsServiceTest extends Specification { def 'should get registry creds from compute creds when not found in tower credentials'() { given: 'a tower user in a workspace on a specific instance with a valid token' def userId = 10 - def workspaceId = 10 + def workspaceId = 100 def token = "valid-token" def towerEndpoint = "http://tower.io:9090" def workflowId = "id123" diff --git a/src/test/groovy/io/seqera/wave/service/builder/KubeBuildStrategyTest.groovy b/src/test/groovy/io/seqera/wave/service/builder/KubeBuildStrategyTest.groovy index 74ffaae38..2c9e221e2 100644 --- a/src/test/groovy/io/seqera/wave/service/builder/KubeBuildStrategyTest.groovy +++ b/src/test/groovy/io/seqera/wave/service/builder/KubeBuildStrategyTest.groovy @@ -38,11 +38,9 @@ import jakarta.inject.Inject * @author Paolo Di Tommaso */ @MicronautTest -@Property(name="wave.build.workspace",value="/build/work") @Property(name="wave.build.k8s.namespace",value="foo") @Property(name="wave.build.k8s.configPath",value="/home/kube.config") @Property(name="wave.build.k8s.storage.claimName",value="bar") -@Property(name="wave.build.k8s.storage.mountPath",value="/build") @Property(name='wave.build.k8s.node-selector[linux/amd64]',value="service=wave-build") @Property(name='wave.build.k8s.node-selector[linux/arm64]',value="service=wave-build-arm64") class KubeBuildStrategyTest extends Specification { diff --git a/src/test/groovy/io/seqera/wave/service/k8s/K8sServiceImplTest.groovy b/src/test/groovy/io/seqera/wave/service/k8s/K8sServiceImplTest.groovy index ddf92e6d9..d4cb2e061 100644 --- a/src/test/groovy/io/seqera/wave/service/k8s/K8sServiceImplTest.groovy +++ b/src/test/groovy/io/seqera/wave/service/k8s/K8sServiceImplTest.groovy @@ -37,8 +37,6 @@ import io.kubernetes.client.openapi.models.V1ObjectMeta import io.kubernetes.client.openapi.models.V1Pod import io.kubernetes.client.openapi.models.V1PodList import io.micronaut.context.ApplicationContext -import io.micronaut.context.annotation.Replaces -import io.micronaut.test.extensions.spock.annotation.MicronautTest import io.seqera.wave.configuration.BlobCacheConfig import io.seqera.wave.configuration.MirrorConfig import io.seqera.wave.configuration.ScanConfig @@ -46,17 +44,8 @@ import io.seqera.wave.configuration.ScanConfig * * @author Paolo Di Tommaso */ -@MicronautTest class K8sServiceImplTest extends Specification { - @Replaces(ScanConfig.class) - static class MockScanConfig extends ScanConfig { - @Override - Path getCacheDirectory() { - return Path.of('/build/scan/cache') - } - } - def 'should validate context OK ' () { when: def PROPS = [ diff --git a/src/test/groovy/io/seqera/wave/service/scan/DockerScanStrategyTest.groovy b/src/test/groovy/io/seqera/wave/service/scan/DockerScanStrategyTest.groovy index 5e9c898e5..1a759cc58 100644 --- a/src/test/groovy/io/seqera/wave/service/scan/DockerScanStrategyTest.groovy +++ b/src/test/groovy/io/seqera/wave/service/scan/DockerScanStrategyTest.groovy @@ -20,24 +20,30 @@ package io.seqera.wave.service.scan import spock.lang.Specification -import java.nio.file.Files import java.nio.file.Path -import io.micronaut.context.ApplicationContext +import io.micronaut.test.annotation.MockBean +import io.micronaut.test.extensions.spock.annotation.MicronautTest +import io.seqera.wave.configuration.ScanConfig +import jakarta.inject.Inject /** * * @author Munish Chouhan */ +@MicronautTest class DockerScanStrategyTest extends Specification { + @Inject + DockerScanStrategy dockerContainerStrategy + + @MockBean(ScanConfig) + ScanConfig mockConfig() { + Mock(ScanConfig) { + getCacheDirectory() >> Path.of('/some/scan/cache') + } + } + def 'should get docker command' () { - given: - def workspace = Files.createTempDirectory('test') - def props = ['wave.build.workspace': workspace.toString()] - and: - def ctx = ApplicationContext.run(props) - and: - def dockerContainerStrategy = ctx.getBean(DockerScanStrategy) when: def scanDir = Path.of('/some/scan/dir') @@ -56,7 +62,7 @@ class DockerScanStrategyTest extends Specification { '-v', '/some/scan/dir:/some/scan/dir:rw', '-v', - "/build/scan/cache:/root/.cache/:rw", + '/some/scan/cache:/root/.cache/:rw', '-v', '/user/test/build-workspace/config.json:/root/.docker/config.json:ro', '-e', @@ -65,8 +71,5 @@ class DockerScanStrategyTest extends Specification { 'BAR=2' ] - cleanup: - ctx.close() - workspace?.deleteDir() } }