diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1c7e96a73..43edd1150 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,35 @@
All notable changes to this project will be documented in this file.
+## [[8.0.0]](https://github.com/iExecBlockchainComputing/iexec-core/releases/tag/v8.0.0) 2023-03-08
+
+### New Features
+* Support Gramine framework for TEE tasks.
+* Retrieve location of SMS services through an _iExec Platform Registry_.
+* Improve authentication on scheduler.
+ * burn challenge after login.
+ * handle JWT expiration through the expiration claim.
+ * cache JWT until expiration.
+ * better claims usage.
+* Show application version on banner.
+### Bug Fixes
+* Always return a `TaskNotificationType` on replicate status update when it has been authorized.
+* Handle task added twice.
+### Quality
+* Improve code quality and tests.
+* Removed unused variables in configuration.
+* Use existing `toString()` method to serialize and hash scheduler public configuration.
+* Use recommended annotation in `MetricController`.
+* Remove `spring-cloud-starter-openfeign` dependency.
+### Dependency Upgrades
+* Replace the deprecated `openjdk` Docker base image with `eclipse-temurin` and upgrade to Java 11.0.18 patch.
+* Upgrade to Spring Boot 2.6.14.
+* Upgrade to Gradle 7.6.
+* Upgrade OkHttp to 4.9.0.
+* Upgrade `jjwt` to `jjwt-api` 0.11.5.
+* Upgrade to `iexec-common` 7.0.0.
+* Upgrade to `jenkins-library` 2.4.0.
+
## [[7.3.1]](https://github.com/iExecBlockchainComputing/iexec-core/releases/tag/v7.3.1) 2023-02-17
* Subscribe only to deal events targeting a specific workerpool.
diff --git a/Dockerfile b/Dockerfile
index a3e5ec1e1..057bd7430 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM openjdk:11.0.15-jre-slim
+FROM eclipse-temurin:11.0.18_10-jre
ARG jar
diff --git a/Jenkinsfile b/Jenkinsfile
index 89896be81..b0b918a1c 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -1,4 +1,4 @@
-@Library('global-jenkins-library@2.2.3') _
+@Library('global-jenkins-library@2.4.0') _
buildJavaProject(
buildInfo: getBuildInfo(),
integrationTestsEnvVars: [],
diff --git a/README.md b/README.md
index 89a77d901..efc103098 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,8 @@ To run properly, the _iExec Core Scheduler_ requires:
* A _MongoDB_ instance to persist its data.
* An _iExec Blockchain Adapter_ for several blockchain network interactions.
* An _iExec Result Proxy_ to check if tasks results have been published.
-* An _iExec Secret Management Service_ (_iExec SMS_) for secret and enclave sessions management of TEE tasks.
+* An _iExec Platform Registry_ to retrieve locations of _iExec SMS_ services.
+* One or many _iExec Secret Management Service_ instances (referenced by the _iExec Platform Registry_) to handle secrets and enclave sessions of TEE tasks.
You can configure the _iExec Core Scheduler_ with the following properties:
@@ -23,17 +24,16 @@ You can configure the _iExec Core Scheduler_ with the following properties:
| `IEXEC_CORE_PORT` | Server port of the _iExec Core Scheduler_. | Positive integer | `13000` |
| `MONGO_HOST` | _MongoDB_ server host. Cannot be set with URI. | String | `localhost` |
| `MONGO_PORT` | _MongoDB_ server port. Cannot be set with URI. | Positive integer | `13002` |
+| `IEXEC_PLATFORM_REGISTRY` | _iExec Platform Registry_ server URL. | URL | |
+| `IEXEC_PLATFORM_REGISTRY_STACK` | [optional] Use a specific stack configuration exposed by the _iExec Platform Registry_. | String | |
+| `IEXEC_PLATFORM_REGISTRY_LABEL` | [optional] Use a labeled version of configuration files exposed by the _iExec Platform Registry_. It might be a Git label such as `main`, `v10` or `07998be`. | String | |
| `REVEAL_TIMEOUT_PERIOD` | Detector period to track reveal timeouts for tasks. | Positive integer | `120000` |
| `IEXEC_ASK_REPLICATE_PERIOD` | Worker configuration, interval in milliseconds between 2 replicate requests. | Positive integer | `5000` |
| `IEXEC_CORE_REQUIRED_WORKER_VERSION` | Empty value will allow any worker version. | String | |
| `IEXEC_WORKERS_WHITELIST` | List of worker addresses allowed to connect to the _iExec Core Scheduler_. | String | |
| `IEXEC_CORE_WALLET_PATH` | Path to the wallet of the server. | String | `./src/main/resources/wallet/encrypted-wallet_scheduler.json` |
| `IEXEC_CORE_WALLET_PASSWORD` | Password to unlock the wallet of the server. | String | `whatever` |
-| `IEXEC_CHAIN_ID` | Chain ID of the blockchain network to connect. | Positive integer | `17` |
-| `IEXEC_IS_SIDECHAIN` | Define if iExec on-chain protocol is built on top of token (`false`) or native currency (`true`). | Boolean | `false` |
| `IEXEC_PRIVATE_CHAIN_ADDRESS` | Private URL to connect to the blockchain node. | URL | `http://localhost:8545` |
-| `IEXEC_PUBLIC_CHAIN_ADDRESS` | [unused] Public URL to connect to the blockchain node. | URL | `http://localhost:8545` |
-| `IEXEC_HUB_ADDRESS` | Proxy contract address to interact with the iExec on-chain protocol. | String | `0xBF6B2B07e47326B7c8bfCb4A5460bef9f0Fd2002` |
| `POOL_ADDRESS` | On-chain address of the workerpool managed by the current _iExec Core Scheduler_. | String | `0x365E7BABAa85eC61Dffe5b520763062e6C29dA27` |
| `IEXEC_START_BLOCK_NUMBER` | Subscribe to new deal events from a specific block number. | Positive integer | `0` |
| `IEXEC_GAS_PRICE_MULTIPLIER` | Transactions will be sent with `networkGasPrice * gasPriceMultiplier`. | Float | `1.0` |
@@ -46,11 +46,6 @@ You can configure the _iExec Core Scheduler_ with the following properties:
| `IEXEC_RESULT_REPOSITORY_PROTOCOL` | _iExec Result Proxy_ server communication protocol. | String | `http` |
| `IEXEC_RESULT_REPOSITORY_HOST` | _iExec Result Proxy_ server host. | String | `localhost` |
| `IEXEC_RESULT_REPOSITORY_PORT` | _iExec Result Proxy_ server port. | Positive integer | `13200` |
-| `IEXEC_IPFS_HOST` | [unused] _IPFS_ node host. | String | `127.0.0.1` |
-| `IEXEC_IPFS_PORT` | [unused] _IPFS_ node port. | Positive integer | `5001` |
-| `IEXEC_SMS_PROTOCOL` | _iExec SMS_ server communication protocol. | String | `http` |
-| `IEXEC_SMS_HOST` | _iExec SMS_ server host. | String | `localhost` |
-| `IEXEC_SMS_PORT` | _iExec SMS_ server port. | Positive integer | `13300` |
| `IEXEC_CORE_MANAGEMENT_ACTUATORS` | Endpoint IDs that should be included or `*` for all. | String | `health, info` |
| `IEXEC_CORE_GRAYLOG_HOST` | _Graylog_ server host. | String | `localhost` |
| `IEXEC_CORE_GRAYLOG_PORT` | _Graylog_ server port. | Positive integer | `12201` |
diff --git a/build.gradle b/build.gradle
index 1b345c91e..eba2c6fbc 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,19 +1,18 @@
plugins {
id 'java'
- id 'eclipse'
+ id 'io.freefair.lombok' version '6.6.1'
+ id 'org.springframework.boot' version '2.6.14'
+ id 'io.spring.dependency-management' version '1.1.0'
id 'jacoco'
id 'org.sonarqube' version '3.3'
id 'maven-publish'
- id "org.springframework.boot" version "2.6.2"
- id "io.spring.dependency-management" version "1.0.11.RELEASE"
}
group = 'com.iexec.core'
-sourceCompatibility = 11
-targetCompatibility = 11
ext {
- springCloudVersion = '2021.0.0'
+ springCloudVersion = '2021.0.5'
+ jjwtVersion = '0.11.5'
mongockVersion = '4.2.7.BETA'
}
@@ -38,7 +37,6 @@ repositories {
maven {
url "https://nexus.intra.iex.ec/repository/maven-public/"
}
-
maven { url "https://jitpack.io" }
}
@@ -64,23 +62,27 @@ dependencies {
implementation "org.springframework.boot:spring-boot-starter-data-mongodb"
implementation "org.springframework.boot:spring-boot-starter-hateoas"
implementation "org.springframework.boot:spring-boot-starter-security"
+ implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation "org.springframework.boot:spring-boot-starter-web"
implementation "org.springframework.boot:spring-boot-starter-websocket"
- implementation "org.springframework.cloud:spring-cloud-starter-openfeign"
+ implementation 'org.springframework.cloud:spring-cloud-starter-config'
implementation "org.springframework.retry:spring-retry"
+ // apache commons.lang3
+ implementation 'org.apache.commons:commons-lang3'
+
// NoSuchMethodError: 'okhttp3.RequestBody okhttp3.RequestBody.create(java.lang.String, okhttp3.MediaType)'
// Spring Boot dependencies BOM enforces okhttp3 3.14.9 in 2.6.X
// It is required to define the dependency version required by web3j until migration to at least Spring Boot 2.7.X
implementation 'com.squareup.okhttp3:okhttp:4.9.0' // Web3j issue: https://github.com/web3j/web3j/issues/1180
- testImplementation "org.springframework.boot:spring-boot-starter-test"
-
// Spring Doc
implementation 'org.springdoc:springdoc-openapi-ui:1.6.3'
// jason web token
- implementation "io.jsonwebtoken:jjwt:0.7.0"
+ implementation "io.jsonwebtoken:jjwt-api:$jjwtVersion"
+ runtimeOnly "io.jsonwebtoken:jjwt-impl:$jjwtVersion"
+ runtimeOnly "io.jsonwebtoken:jjwt-jackson:$jjwtVersion"
// expiring map
implementation "net.jodah:expiringmap:0.5.10"
@@ -93,18 +95,14 @@ dependencies {
implementation 'io.micrometer:micrometer-registry-prometheus:1.8.1'
- // lombok
- compileOnly "org.projectlombok:lombok:1.18.2"
- annotationProcessor "org.projectlombok:lombok:1.18.2"
- testCompileOnly "org.projectlombok:lombok:1.18.2"
- testAnnotationProcessor "org.projectlombok:lombok:1.18.2"
-
// mongock
implementation "com.github.cloudyrock.mongock:mongock-spring-v5:${mongockVersion}"
implementation "com.github.cloudyrock.mongock:mongodb-springdata-v2-driver:${mongockVersion}"
+ testImplementation 'org.springframework.boot:spring-boot-starter-test'
+
// awaitility
- testImplementation 'org.awaitility:awaitility:4.0.1'
+ testImplementation 'org.awaitility:awaitility'
// mongo
testImplementation 'org.testcontainers:testcontainers:1.16.2'
@@ -112,6 +110,12 @@ dependencies {
testImplementation 'org.testcontainers:mongodb:1.16.2'
}
+java {
+ toolchain {
+ languageVersion.set(JavaLanguageVersion.of(11))
+ }
+}
+
jar {
enabled = true
archiveClassifier.set('library')
@@ -121,6 +125,13 @@ springBoot {
buildInfo()
}
+tasks.named("bootJar") {
+ manifest {
+ attributes("Implementation-Title": "iExec Core Scheduler",
+ "Implementation-Version": project.version)
+ }
+}
+
test {
useJUnitPlatform()
}
@@ -136,7 +147,7 @@ jacoco {
// sonarqube code coverage requires jacoco XML report
jacocoTestReport {
reports {
- xml.enabled true
+ xml.required = true
}
}
tasks.test.finalizedBy tasks.jacocoTestReport
@@ -145,7 +156,7 @@ tasks.sonarqube.dependsOn tasks.jacocoTestReport
publishing {
publications {
maven(MavenPublication) {
- artifact bootJar
+ artifact tasks.named("bootJar")
from components.java
}
}
diff --git a/gradle.properties b/gradle.properties
index e62901e8c..87b240e36 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,8 +1,8 @@
-version=7.3.1
-iexecCommonVersion=6.2.0
-iexecBlockchainAdapterVersion=7.3.0
-iexecResultVersion=7.3.0
-iexecSmsVersion=7.3.0
+version=8.0.0
+iexecCommonVersion=7.0.0
+iexecBlockchainAdapterVersion=8.0.0
+iexecResultVersion=8.0.0
+iexecSmsVersion=8.0.0
nexusUser
nexusPassword
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index e708b1c02..943f0cbfa 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 442d9132e..f398c33c4 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.3-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip
+networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/gradlew b/gradlew
index 4f906e0c8..65dcd68d6 100755
--- a/gradlew
+++ b/gradlew
@@ -1,7 +1,7 @@
-#!/usr/bin/env sh
+#!/bin/sh
#
-# Copyright 2015 the original author or authors.
+# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,67 +17,101 @@
#
##############################################################################
-##
-## Gradle start up script for UN*X
-##
+#
+# Gradle start up script for POSIX generated by Gradle.
+#
+# Important for running:
+#
+# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
+# noncompliant, but you have some other compliant shell such as ksh or
+# bash, then to run this script, type that shell name before the whole
+# command line, like:
+#
+# ksh Gradle
+#
+# Busybox and similar reduced shells will NOT work, because this script
+# requires all of these POSIX shell features:
+# * functions;
+# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
+# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
+# * compound commands having a testable exit status, especially «case»;
+# * various built-in commands including «command», «set», and «ulimit».
+#
+# Important for patching:
+#
+# (2) This script targets any POSIX shell, so it avoids extensions provided
+# by Bash, Ksh, etc; in particular arrays are avoided.
+#
+# The "traditional" practice of packing multiple parameters into a
+# space-separated string is a well documented source of bugs and security
+# problems, so this is (mostly) avoided, by progressively accumulating
+# options in "$@", and eventually passing that to Java.
+#
+# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
+# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
+# see the in-line comments for details.
+#
+# There are tweaks for specific operating systems such as AIX, CygWin,
+# Darwin, MinGW, and NonStop.
+#
+# (3) This script is generated from the Groovy template
+# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
+# within the Gradle project.
+#
+# You can find Gradle at https://github.com/gradle/gradle/.
+#
##############################################################################
# Attempt to set APP_HOME
+
# Resolve links: $0 may be a link
-PRG="$0"
-# Need this for relative symlinks.
-while [ -h "$PRG" ] ; do
- ls=`ls -ld "$PRG"`
- link=`expr "$ls" : '.*-> \(.*\)$'`
- if expr "$link" : '/.*' > /dev/null; then
- PRG="$link"
- else
- PRG=`dirname "$PRG"`"/$link"
- fi
+app_path=$0
+
+# Need this for daisy-chained symlinks.
+while
+ APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
+ [ -h "$app_path" ]
+do
+ ls=$( ls -ld "$app_path" )
+ link=${ls#*' -> '}
+ case $link in #(
+ /*) app_path=$link ;; #(
+ *) app_path=$APP_HOME$link ;;
+ esac
done
-SAVED="`pwd`"
-cd "`dirname \"$PRG\"`/" >/dev/null
-APP_HOME="`pwd -P`"
-cd "$SAVED" >/dev/null
-APP_NAME="Gradle"
-APP_BASE_NAME=`basename "$0"`
+# This is normally unused
+# shellcheck disable=SC2034
+APP_BASE_NAME=${0##*/}
+APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
-MAX_FD="maximum"
+MAX_FD=maximum
warn () {
echo "$*"
-}
+} >&2
die () {
echo
echo "$*"
echo
exit 1
-}
+} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
-case "`uname`" in
- CYGWIN* )
- cygwin=true
- ;;
- Darwin* )
- darwin=true
- ;;
- MINGW* )
- msys=true
- ;;
- NONSTOP* )
- nonstop=true
- ;;
+case "$( uname )" in #(
+ CYGWIN* ) cygwin=true ;; #(
+ Darwin* ) darwin=true ;; #(
+ MSYS* | MINGW* ) msys=true ;; #(
+ NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
@@ -87,9 +121,9 @@ CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
- JAVACMD="$JAVA_HOME/jre/sh/java"
+ JAVACMD=$JAVA_HOME/jre/sh/java
else
- JAVACMD="$JAVA_HOME/bin/java"
+ JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -98,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
- JAVACMD="java"
+ JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@@ -106,80 +140,105 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
-if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
- MAX_FD_LIMIT=`ulimit -H -n`
- if [ $? -eq 0 ] ; then
- if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
- MAX_FD="$MAX_FD_LIMIT"
- fi
- ulimit -n $MAX_FD
- if [ $? -ne 0 ] ; then
- warn "Could not set maximum file descriptor limit: $MAX_FD"
- fi
- else
- warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
- fi
+if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
+ case $MAX_FD in #(
+ max*)
+ # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
+ MAX_FD=$( ulimit -H -n ) ||
+ warn "Could not query maximum file descriptor limit"
+ esac
+ case $MAX_FD in #(
+ '' | soft) :;; #(
+ *)
+ # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
+ # shellcheck disable=SC3045
+ ulimit -n "$MAX_FD" ||
+ warn "Could not set maximum file descriptor limit to $MAX_FD"
+ esac
fi
-# For Darwin, add options to specify how the application appears in the dock
-if $darwin; then
- GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
-fi
+# Collect all arguments for the java command, stacking in reverse order:
+# * args from the command line
+# * the main class name
+# * -classpath
+# * -D...appname settings
+# * --module-path (only if needed)
+# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# For Cygwin or MSYS, switch paths to Windows format before running java
-if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
- APP_HOME=`cygpath --path --mixed "$APP_HOME"`
- CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
-
- JAVACMD=`cygpath --unix "$JAVACMD"`
-
- # We build the pattern for arguments to be converted via cygpath
- ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
- SEP=""
- for dir in $ROOTDIRSRAW ; do
- ROOTDIRS="$ROOTDIRS$SEP$dir"
- SEP="|"
- done
- OURCYGPATTERN="(^($ROOTDIRS))"
- # Add a user-defined pattern to the cygpath arguments
- if [ "$GRADLE_CYGPATTERN" != "" ] ; then
- OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
- fi
+if "$cygwin" || "$msys" ; then
+ APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
+ CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
+
+ JAVACMD=$( cygpath --unix "$JAVACMD" )
+
# Now convert the arguments - kludge to limit ourselves to /bin/sh
- i=0
- for arg in "$@" ; do
- CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
- CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
-
- if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
- eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
- else
- eval `echo args$i`="\"$arg\""
+ for arg do
+ if
+ case $arg in #(
+ -*) false ;; # don't mess with options #(
+ /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
+ [ -e "$t" ] ;; #(
+ *) false ;;
+ esac
+ then
+ arg=$( cygpath --path --ignore --mixed "$arg" )
fi
- i=`expr $i + 1`
+ # Roll the args list around exactly as many times as the number of
+ # args, so each arg winds up back in the position where it started, but
+ # possibly modified.
+ #
+ # NB: a `for` loop captures its iteration list before it begins, so
+ # changing the positional parameters here affects neither the number of
+ # iterations, nor the values presented in `arg`.
+ shift # remove old arg
+ set -- "$@" "$arg" # push replacement arg
done
- case $i in
- 0) set -- ;;
- 1) set -- "$args0" ;;
- 2) set -- "$args0" "$args1" ;;
- 3) set -- "$args0" "$args1" "$args2" ;;
- 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
- 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
- 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
- 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
- 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
- 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
- esac
fi
-# Escape application args
-save () {
- for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
- echo " "
-}
-APP_ARGS=`save "$@"`
+# Collect all arguments for the java command;
+# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
+# shell script including quotes and variable substitutions, so put them in
+# double quotes to make sure that they get re-expanded; and
+# * put everything else in single quotes, so that it's not re-expanded.
+
+set -- \
+ "-Dorg.gradle.appname=$APP_BASE_NAME" \
+ -classpath "$CLASSPATH" \
+ org.gradle.wrapper.GradleWrapperMain \
+ "$@"
+
+# Stop when "xargs" is not available.
+if ! command -v xargs >/dev/null 2>&1
+then
+ die "xargs is not available"
+fi
+
+# Use "xargs" to parse quoted args.
+#
+# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
+#
+# In Bash we could simply go:
+#
+# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
+# set -- "${ARGS[@]}" "$@"
+#
+# but POSIX shell has neither arrays nor command substitution, so instead we
+# post-process each arg (as a line of input to sed) to backslash-escape any
+# character that might be a shell metacharacter, then use eval to reverse
+# that process (while maintaining the separation between arguments), and wrap
+# the whole thing up as a single "set" statement.
+#
+# This will of course break if any of these variables contains a newline or
+# an unmatched quote.
+#
-# Collect all arguments for the java command, following the shell quoting and substitution rules
-eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+eval "set -- $(
+ printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
+ xargs -n1 |
+ sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
+ tr '\n' ' '
+ )" '"$@"'
exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
index ac1b06f93..6689b85be 100644
--- a/gradlew.bat
+++ b/gradlew.bat
@@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
-@if "%DEBUG%" == "" @echo off
+@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@@ -25,7 +25,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
-if "%DIRNAME%" == "" set DIRNAME=.
+if "%DIRNAME%"=="" set DIRNAME=.
+@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
-if "%ERRORLEVEL%" == "0" goto execute
+if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
-if "%ERRORLEVEL%"=="0" goto mainEnd
+if %ERRORLEVEL% equ 0 goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
-if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
-exit /b 1
+set EXIT_CODE=%ERRORLEVEL%
+if %EXIT_CODE% equ 0 set EXIT_CODE=1
+if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
+exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
diff --git a/lombok.config b/lombok.config
new file mode 100644
index 000000000..189c0bef9
--- /dev/null
+++ b/lombok.config
@@ -0,0 +1,3 @@
+# This file is generated by the 'io.freefair.lombok' Gradle plugin
+config.stopBubbling = true
+lombok.addLombokGeneratedAnnotation = true
diff --git a/src/main/java/com/iexec/core/AppConfig.java b/src/main/java/com/iexec/core/AppConfig.java
index 0fe288a44..5c5a32cea 100644
--- a/src/main/java/com/iexec/core/AppConfig.java
+++ b/src/main/java/com/iexec/core/AppConfig.java
@@ -17,8 +17,6 @@
package com.iexec.core;
import com.iexec.core.config.*;
-
-import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@@ -31,7 +29,5 @@
WebMvcConfig.class,
WebSocketConfig.class,
})
-@EnableFeignClients
public class AppConfig {
-
-}
\ No newline at end of file
+}
diff --git a/src/main/java/com/iexec/core/chain/ChainConfig.java b/src/main/java/com/iexec/core/chain/ChainConfig.java
index 1706d35e6..918f24760 100644
--- a/src/main/java/com/iexec/core/chain/ChainConfig.java
+++ b/src/main/java/com/iexec/core/chain/ChainConfig.java
@@ -34,12 +34,12 @@ public class ChainConfig {
@Value("#{blockchainAdapterService.publicChainConfig.isSidechain()}")
private boolean isSidechain;
- @Value("${chain.privateAddress}")
- private String privateChainAddress;
-
@Value("#{blockchainAdapterService.publicChainConfig.iexecHubContractAddress}")
private String hubAddress;
+ @Value("${chain.privateAddress}")
+ private String privateChainAddress;
+
@Value("${chain.poolAddress}")
private String poolAddress;
diff --git a/src/main/java/com/iexec/core/chain/adapter/BlockchainAdapterClientConfig.java b/src/main/java/com/iexec/core/chain/adapter/BlockchainAdapterClientConfig.java
index 083402b35..3d33e6b17 100644
--- a/src/main/java/com/iexec/core/chain/adapter/BlockchainAdapterClientConfig.java
+++ b/src/main/java/com/iexec/core/chain/adapter/BlockchainAdapterClientConfig.java
@@ -19,12 +19,10 @@
import com.iexec.blockchain.api.BlockchainAdapterApiClient;
import com.iexec.blockchain.api.BlockchainAdapterApiClientBuilder;
import feign.Logger;
-import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
-@Slf4j
@Configuration
public class BlockchainAdapterClientConfig {
diff --git a/src/main/java/com/iexec/core/configuration/PublicConfigurationService.java b/src/main/java/com/iexec/core/configuration/PublicConfigurationService.java
index 4ce837b1a..5fd2238e6 100644
--- a/src/main/java/com/iexec/core/configuration/PublicConfigurationService.java
+++ b/src/main/java/com/iexec/core/configuration/PublicConfigurationService.java
@@ -20,6 +20,7 @@
import com.iexec.core.chain.ChainConfig;
import com.iexec.core.chain.CredentialsService;
import com.iexec.core.chain.adapter.BlockchainAdapterClientConfig;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.web3j.crypto.Hash;
@@ -29,13 +30,13 @@
* This simple service will generate a random session id when the scheduler is started, it will be send to workers when
* they ping the scheduler. If they see that the session id has changed, it means that the scheduler has restarted.
*/
+@Slf4j
@Service
public class PublicConfigurationService {
private final ChainConfig chainConfig;
private final CredentialsService credentialsService;
private final WorkerConfiguration workerConfiguration;
private final ResultRepositoryConfiguration resultRepoConfig;
- private final SmsConfiguration smsConfiguration;
private final BlockchainAdapterClientConfig blockchainAdapterClientConfig;
private PublicConfiguration publicConfiguration = null;
@@ -50,13 +51,11 @@ public PublicConfigurationService(ChainConfig chainConfig,
CredentialsService credentialsService,
WorkerConfiguration workerConfiguration,
ResultRepositoryConfiguration resultRepoConfig,
- SmsConfiguration smsConfiguration,
BlockchainAdapterClientConfig blockchainAdapterClientConfig) {
this.chainConfig = chainConfig;
this.credentialsService = credentialsService;
this.workerConfiguration = workerConfiguration;
this.resultRepoConfig = resultRepoConfig;
- this.smsConfiguration = smsConfiguration;
this.blockchainAdapterClientConfig = blockchainAdapterClientConfig;
}
@@ -67,24 +66,12 @@ void buildPublicConfiguration() {
.blockchainAdapterUrl(blockchainAdapterClientConfig.getUrl())
.schedulerPublicAddress(credentialsService.getCredentials().getAddress())
.resultRepositoryURL(resultRepoConfig.getResultRepositoryURL())
- .smsURL(smsConfiguration.getSmsURL())
.askForReplicatePeriod(workerConfiguration.getAskForReplicatePeriod())
.requiredWorkerVersion(workerConfiguration.getRequiredWorkerVersion())
.build();
-
- // TODO: would be great to put this in Common
- // (a simple `@ToString` would be sufficient)
- final String publicConfigurationAsString = String.join("\n",
- publicConfiguration.getWorkerPoolAddress(),
- publicConfiguration.getBlockchainAdapterUrl(),
- publicConfiguration.getSchedulerPublicAddress(),
- publicConfiguration.getResultRepositoryURL(),
- publicConfiguration.getSmsURL(),
- publicConfiguration.getAskForReplicatePeriod() + "",
- publicConfiguration.getRequiredWorkerVersion()
- );
-
- this.publicConfigurationHash = Hash.sha3String(publicConfigurationAsString);
+ this.publicConfigurationHash = Hash.sha3String(publicConfiguration.toString());
+ log.info(publicConfiguration.toString());
+ log.info("Public configuration hash {}", publicConfigurationHash);
}
public String getPublicConfigurationHash() {
diff --git a/src/main/java/com/iexec/core/configuration/PurgeConfiguration.java b/src/main/java/com/iexec/core/configuration/PurgeConfiguration.java
new file mode 100644
index 000000000..cdd322601
--- /dev/null
+++ b/src/main/java/com/iexec/core/configuration/PurgeConfiguration.java
@@ -0,0 +1,25 @@
+package com.iexec.core.configuration;
+
+import com.iexec.common.lifecycle.purge.PurgeService;
+import com.iexec.common.lifecycle.purge.Purgeable;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.List;
+
+@Configuration
+public class PurgeConfiguration {
+ /**
+ * Creates a {@link PurgeService} bean, with a list of all {@link Purgeable} beans as a parameter.
+ *
+ * If no {@link Purgeable} bean is known, then an empty list is passed as a parameter.
+ * This is a special case of Spring IoC, please see
+ * Spring documentation.
+ * @param purgeableServices List of services that can be purged on a task completion
+ * @return An instance of {@link PurgeService} containing a list of all {@link Purgeable} beans.
+ */
+ @Bean
+ PurgeService purgeService(List purgeableServices) {
+ return new PurgeService(purgeableServices);
+ }
+}
diff --git a/src/main/java/com/iexec/core/configuration/SmsConfiguration.java b/src/main/java/com/iexec/core/configuration/SmsConfiguration.java
deleted file mode 100644
index b0cb2bd89..000000000
--- a/src/main/java/com/iexec/core/configuration/SmsConfiguration.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2020 IEXEC BLOCKCHAIN TECH
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.iexec.core.configuration;
-
-import com.iexec.sms.api.SmsClient;
-import com.iexec.sms.api.SmsClientBuilder;
-import feign.Logger;
-import lombok.AllArgsConstructor;
-import lombok.Getter;
-import lombok.NoArgsConstructor;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
-import org.springframework.stereotype.Component;
-
-@Component
-@Getter
-@AllArgsConstructor
-@NoArgsConstructor
-public class SmsConfiguration {
-
- @Value("${sms.protocol}")
- private String protocol;
-
- @Value("${sms.host}")
- private String host;
-
- @Value("${sms.port}")
- private String port;
-
- public String getSmsURL() {
- return protocol + "://" + host + ":" + port;
- }
-
- @Bean
- public SmsClient smsClient() {
- return SmsClientBuilder.getInstance(Logger.Level.NONE, getSmsURL());
- }
-}
diff --git a/src/main/java/com/iexec/core/contribution/ContributionHelper.java b/src/main/java/com/iexec/core/contribution/ContributionHelper.java
index 8b25b6338..90ec12e50 100644
--- a/src/main/java/com/iexec/core/contribution/ContributionHelper.java
+++ b/src/main/java/com/iexec/core/contribution/ContributionHelper.java
@@ -21,7 +21,6 @@
import java.util.HashSet;
import java.util.List;
-import java.util.Optional;
import java.util.Set;
public class ContributionHelper {
@@ -38,12 +37,9 @@ static int getContributedWeight(List replicates, String contribution)
int groupWeight = 0;
for (Replicate replicate : replicates) {
- Optional lastRelevantStatus = replicate.getLastRelevantStatus();
- if (lastRelevantStatus.isEmpty()) {
- continue;
- }
+ ReplicateStatus lastRelevantStatus = replicate.getLastRelevantStatus();
- boolean isContributed = lastRelevantStatus.get().equals(ReplicateStatus.CONTRIBUTED);
+ boolean isContributed = lastRelevantStatus == ReplicateStatus.CONTRIBUTED;
boolean haveSameContribution = contribution.equals(replicate.getContributionHash());
boolean hasWeight = replicate.getWorkerWeight() > 0;
@@ -64,14 +60,11 @@ static int getPendingWeight(List replicates, long maxExecutionTime) {
for (Replicate replicate : replicates) {
- Optional lastRelevantStatus = replicate.getLastRelevantStatus();
- if (lastRelevantStatus.isEmpty()) {
- continue;
- }
+ ReplicateStatus lastRelevantStatus = replicate.getLastRelevantStatus();
boolean isCreatedLessThanOnePeriodAgo = !replicate.isCreatedMoreThanNPeriodsAgo(1, maxExecutionTime);
- boolean isNotContributed = !lastRelevantStatus.get().equals(ReplicateStatus.CONTRIBUTED);
- boolean isNotFailed = !lastRelevantStatus.get().equals(ReplicateStatus.FAILED);
+ boolean isNotContributed = lastRelevantStatus != ReplicateStatus.CONTRIBUTED;
+ boolean isNotFailed = lastRelevantStatus != ReplicateStatus.FAILED;
boolean hasWeight = replicate.getWorkerWeight() > 0;
if (isCreatedLessThanOnePeriodAgo && isNotContributed && isNotFailed && hasWeight) {
@@ -92,12 +85,8 @@ static Set getDistinctContributions(List replicates) {
for (Replicate replicate : replicates) {
- Optional lastRelevantStatus = replicate.getLastRelevantStatus();
- if (lastRelevantStatus.isEmpty()) {
- continue;
- }
-
- if (lastRelevantStatus.get().equals(ReplicateStatus.CONTRIBUTED)) {
+ ReplicateStatus lastRelevantStatus = replicate.getLastRelevantStatus();
+ if (lastRelevantStatus == ReplicateStatus.CONTRIBUTED) {
distinctContributions.add(replicate.getContributionHash());
}
}
diff --git a/src/main/java/com/iexec/core/detector/replicate/UnnotifiedAbstractDetector.java b/src/main/java/com/iexec/core/detector/replicate/UnnotifiedAbstractDetector.java
index 3559e2ac9..47a588c1a 100644
--- a/src/main/java/com/iexec/core/detector/replicate/UnnotifiedAbstractDetector.java
+++ b/src/main/java/com/iexec/core/detector/replicate/UnnotifiedAbstractDetector.java
@@ -30,7 +30,6 @@
import lombok.extern.slf4j.Slf4j;
import java.util.List;
-import java.util.Optional;
import static com.iexec.common.replicate.ReplicateStatus.WORKER_LOST;
import static com.iexec.common.replicate.ReplicateStatus.getMissingStatuses;
@@ -60,8 +59,8 @@ void dectectOnchainCompletedWhenOffchainCompleting(List detectWhenOf
ChainContributionStatus onchainCompleted) {
for (Task task : taskService.findByCurrentStatus(detectWhenOffChainTaskStatuses)) {
for (Replicate replicate : replicatesService.getReplicates(task.getChainTaskId())) {
- Optional lastRelevantStatus = replicate.getLastRelevantStatus();
- if (lastRelevantStatus.isEmpty() || !lastRelevantStatus.get().equals(offchainCompleting)) {
+ ReplicateStatus lastRelevantStatus = replicate.getLastRelevantStatus();
+ if (lastRelevantStatus != offchainCompleting) {
continue;
}
@@ -69,7 +68,7 @@ void dectectOnchainCompletedWhenOffchainCompleting(List detectWhenOf
if (statusTrueOnChain) {
log.info("Detected confirmed missing update (replicate) [is:{}, should:{}, taskId:{}]",
- lastRelevantStatus.get(), onchainCompleted, task.getChainTaskId());
+ lastRelevantStatus, onchainCompleted, task.getChainTaskId());
updateReplicateStatuses(task, replicate, offchainCompleted);
}
}
@@ -82,9 +81,9 @@ void dectectOnchainCompleted(List detectWhenOffChainTaskStatuses,
ChainContributionStatus onchainCompleted) {
for (Task task : taskService.findByCurrentStatus(detectWhenOffChainTaskStatuses)) {
for (Replicate replicate : replicatesService.getReplicates(task.getChainTaskId())) {
- Optional lastRelevantStatus = replicate.getLastRelevantStatus();
+ ReplicateStatus lastRelevantStatus = replicate.getLastRelevantStatus();
- if (lastRelevantStatus.isEmpty() || lastRelevantStatus.get().equals(offchainCompleted)) {
+ if (lastRelevantStatus == offchainCompleted) {
continue;
}
@@ -92,7 +91,7 @@ void dectectOnchainCompleted(List detectWhenOffChainTaskStatuses,
if (statusTrueOnChain) {
log.info("Detected confirmed missing update (replicate) [is:{}, should:{}, taskId:{}]",
- lastRelevantStatus.get(), onchainCompleted, task.getChainTaskId());
+ lastRelevantStatus, onchainCompleted, task.getChainTaskId());
updateReplicateStatuses(task, replicate, offchainCompleted);
}
}
diff --git a/src/main/java/com/iexec/core/registry/PlatformRegistryConfiguration.java b/src/main/java/com/iexec/core/registry/PlatformRegistryConfiguration.java
new file mode 100644
index 000000000..da0982882
--- /dev/null
+++ b/src/main/java/com/iexec/core/registry/PlatformRegistryConfiguration.java
@@ -0,0 +1,20 @@
+package com.iexec.core.registry;
+
+import lombok.Getter;
+import org.hibernate.validator.constraints.URL;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+
+@Getter
+@Configuration
+public class PlatformRegistryConfiguration {
+
+ @URL
+ @Value("${sms.scone}")
+ private String sconeSms;
+
+ @URL
+ @Value("${sms.gramine}")
+ private String gramineSms;
+
+}
diff --git a/src/main/java/com/iexec/core/replicate/NoReplicateStatusException.java b/src/main/java/com/iexec/core/replicate/NoReplicateStatusException.java
new file mode 100644
index 000000000..4f35eb208
--- /dev/null
+++ b/src/main/java/com/iexec/core/replicate/NoReplicateStatusException.java
@@ -0,0 +1,14 @@
+package com.iexec.core.replicate;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * Exception that can be thrown
+ * when searching for a {@link com.iexec.common.replicate.ReplicateStatus} fails.
+ */
+@AllArgsConstructor
+@Getter
+public class NoReplicateStatusException extends RuntimeException {
+ private final String chainTaskId;
+}
diff --git a/src/main/java/com/iexec/core/replicate/Replicate.java b/src/main/java/com/iexec/core/replicate/Replicate.java
index f2282b976..f87ec6c1a 100644
--- a/src/main/java/com/iexec/core/replicate/Replicate.java
+++ b/src/main/java/com/iexec/core/replicate/Replicate.java
@@ -19,20 +19,19 @@
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.iexec.common.chain.ChainReceipt;
-import com.iexec.common.replicate.ReplicateStatus;
-import com.iexec.common.replicate.ReplicateStatusCause;
-import com.iexec.common.replicate.ReplicateStatusDetails;
-import com.iexec.common.replicate.ReplicateStatusModifier;
-import com.iexec.common.replicate.ReplicateStatusUpdate;
-
+import com.iexec.common.replicate.*;
import lombok.Data;
import lombok.NoArgsConstructor;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
import java.util.stream.Collectors;
-import static com.iexec.common.replicate.ReplicateStatus.*;
-import static com.iexec.common.replicate.ReplicateStatusUpdate.*;
+import static com.iexec.common.replicate.ReplicateStatus.CREATED;
+import static com.iexec.common.replicate.ReplicateStatus.WORKER_LOST;
+import static com.iexec.common.replicate.ReplicateStatusUpdate.poolManagerRequest;
@Data
@@ -40,7 +39,11 @@
@JsonIgnoreProperties(ignoreUnknown = true)
public class Replicate {
- private List statusUpdateList;
+ // FIXME: should be final
+ private List statusUpdateList = new ArrayList<>(
+ // a new replicate should only be created by the scheduler
+ List.of(poolManagerRequest(CREATED))
+ );
private String walletAddress;
private String resultLink;
private String chainCallbackData;
@@ -52,9 +55,6 @@ public class Replicate {
public Replicate(String walletAddress, String chainTaskId) {
this.chainTaskId = chainTaskId;
this.walletAddress = walletAddress;
- this.statusUpdateList = new ArrayList<>();
- // a new replicate should only be create by the scheduler
- this.statusUpdateList.add(poolManagerRequest(CREATED));
this.contributionHash = "";
}
@@ -64,10 +64,10 @@ public ReplicateStatus getCurrentStatus() {
}
@JsonIgnore
- public Optional getLastRelevantStatus() { // FIXME: remove Optional and add a no-args constructor
+ public ReplicateStatus getLastRelevantStatus() {
// ignore cases like: WORKER_LOST and RECOVERING
- List statusList = getStatusUpdateList().stream()
+ List statusList = statusUpdateList.stream()
.map(ReplicateStatusUpdate::getStatus)
.collect(Collectors.toList());
@@ -77,21 +77,21 @@ public Optional getLastRelevantStatus() { // FIXME: remove Opt
for (int i = statusList.size() - 1; i >= 0; i--) {
if (!ignoredStatuses.contains(statusList.get(i))) {
- return Optional.of(statusList.get(i));
+ return statusList.get(i);
}
}
- return Optional.empty();
+ throw new NoReplicateStatusException(chainTaskId);
}
@JsonIgnore
public ReplicateStatus getLastButOneStatus() {
- return this.getStatusUpdateList().get(this.getStatusUpdateList().size() - 2).getStatus();
+ return statusUpdateList.get(statusUpdateList.size() - 2).getStatus();
}
@JsonIgnore
private ReplicateStatusUpdate getLatestStatusUpdate() {
- return this.getStatusUpdateList().get(this.getStatusUpdateList().size() - 1);
+ return statusUpdateList.get(statusUpdateList.size() - 1);
}
public boolean updateStatus(ReplicateStatus newStatus, ReplicateStatusModifier modifier) {
@@ -115,7 +115,7 @@ public boolean updateStatus(ReplicateStatusUpdate statusUpdate) {
}
public boolean containsStatus(ReplicateStatus replicateStatus) {
- for (ReplicateStatusUpdate replicateStatusUpdate : this.getStatusUpdateList()) {
+ for (ReplicateStatusUpdate replicateStatusUpdate : statusUpdateList) {
if (replicateStatusUpdate.getStatus().equals(replicateStatus)) {
return true;
}
@@ -132,7 +132,7 @@ public boolean containsRevealedStatus() {
}
public boolean isCreatedMoreThanNPeriodsAgo(int numberPeriod, long maxExecutionTime) {
- Date creationDate = this.getStatusUpdateList().get(0).getDate();
+ Date creationDate = statusUpdateList.get(0).getDate();
Date numberPeriodsAfterCreationDate = new Date(creationDate.getTime() + numberPeriod * maxExecutionTime);
Date now = new Date();
@@ -149,21 +149,19 @@ public boolean isBusyComputing() {
}
public boolean isRecoverable() {
- Optional currentStatus = getLastRelevantStatus();
- if (currentStatus.isEmpty()) return false;
- return ReplicateStatus.isRecoverable(currentStatus.get());
+ ReplicateStatus currentStatus = getLastRelevantStatus();
+ return ReplicateStatus.isRecoverable(currentStatus);
}
public boolean isBeforeStatus(ReplicateStatus status) {
- Optional currentStatus = getLastRelevantStatus();
- if (currentStatus.isEmpty()) return false;
- return currentStatus.get().ordinal() < status.ordinal();
+ ReplicateStatus currentStatus = getLastRelevantStatus();
+ return currentStatus.ordinal() < status.ordinal();
}
boolean isStatusBeforeWorkerLostEqualsTo(ReplicateStatus status) {
- int size = getStatusUpdateList().size();
+ int size = statusUpdateList.size();
return size >= 2
- && getStatusUpdateList().get(size - 1).getStatus().equals(WORKER_LOST)
- && getStatusUpdateList().get(size - 2).getStatus().equals(status);
+ && statusUpdateList.get(size - 1).getStatus().equals(WORKER_LOST)
+ && statusUpdateList.get(size - 2).getStatus().equals(status);
}
}
diff --git a/src/main/java/com/iexec/core/replicate/ReplicateSupplyService.java b/src/main/java/com/iexec/core/replicate/ReplicateSupplyService.java
index 60ada9cbf..5d632ec6b 100644
--- a/src/main/java/com/iexec/core/replicate/ReplicateSupplyService.java
+++ b/src/main/java/com/iexec/core/replicate/ReplicateSupplyService.java
@@ -17,12 +17,16 @@
package com.iexec.core.replicate;
import com.iexec.common.chain.WorkerpoolAuthorization;
+import com.iexec.common.lifecycle.purge.ExpiringTaskMapFactory;
+import com.iexec.common.lifecycle.purge.Purgeable;
import com.iexec.common.notification.TaskNotification;
import com.iexec.common.notification.TaskNotificationExtra;
import com.iexec.common.notification.TaskNotificationType;
import com.iexec.common.replicate.ReplicateStatus;
import com.iexec.common.replicate.ReplicateStatusDetails;
import com.iexec.common.replicate.ReplicateStatusUpdate;
+import com.iexec.common.replicate.ReplicateTaskSummary;
+import com.iexec.common.replicate.ReplicateTaskSummary.ReplicateTaskSummaryBuilder;
import com.iexec.common.task.TaskAbortCause;
import com.iexec.core.chain.SignatureService;
import com.iexec.core.chain.Web3jService;
@@ -33,22 +37,19 @@
import com.iexec.core.task.update.TaskUpdateRequestManager;
import com.iexec.core.worker.Worker;
import com.iexec.core.worker.WorkerService;
-import net.jodah.expiringmap.ExpiringMap;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
import java.util.*;
-import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import static com.iexec.common.replicate.ReplicateStatus.*;
-import static com.iexec.core.task.Task.LONGEST_TASK_TIMEOUT;
@Service
-public class ReplicateSupplyService {
+public class ReplicateSupplyService implements Purgeable {
private final ReplicatesService replicatesService;
private final SignatureService signatureService;
@@ -56,10 +57,7 @@ public class ReplicateSupplyService {
private final TaskUpdateRequestManager taskUpdateRequestManager;
private final WorkerService workerService;
private final Web3jService web3jService;
- final Map taskAccessForNewReplicateLocks =
- ExpiringMap.builder()
- .expiration(LONGEST_TASK_TIMEOUT.getSeconds(), TimeUnit.SECONDS)
- .build();
+ final Map taskAccessForNewReplicateLocks = ExpiringTaskMapFactory.getExpiringTaskMap();
public ReplicateSupplyService(ReplicatesService replicatesService,
SignatureService signatureService,
@@ -87,7 +85,7 @@ public ReplicateSupplyService(ReplicatesService replicatesService,
*
*/
@Retryable(value = {OptimisticLockingFailureException.class}, maxAttempts = 5)
- Optional getAuthOfAvailableReplicate(long workerLastBlock, String walletAddress) {
+ Optional getAvailableReplicateTaskSummary(long workerLastBlock, String walletAddress) {
// return empty if max computing task is reached or if the worker is not found
if (!workerService.canAcceptMoreWorks(walletAddress)) {
return Optional.empty();
@@ -112,7 +110,7 @@ Optional getAuthOfAvailableReplicate(long workerLastBlo
}
Worker worker = optional.get();
- return getAuthorizationForAnyAvailableTask(
+ return getReplicateTaskSummaryForAnyAvailableTask(
walletAddress,
worker.isTeeEnabled()
);
@@ -124,17 +122,17 @@ Optional getAuthOfAvailableReplicate(long workerLastBlo
*
* @param walletAddress Wallet address of the worker asking for work.
* @param isTeeEnabled Whether this worker supports TEE.
- * @return An {@link Optional} containing a {@link WorkerpoolAuthorization}
+ * @return An {@link Optional} containing a {@link ReplicateTaskSummary}
* if any {@link Task} is available and can be handled by this worker,
* {@link Optional#empty()} otherwise.
*/
- private Optional getAuthorizationForAnyAvailableTask(
+ private Optional getReplicateTaskSummaryForAnyAvailableTask(
String walletAddress,
boolean isTeeEnabled) {
final List alreadyScannedTasks = new ArrayList<>();
- Optional authorization = Optional.empty();
- while (authorization.isEmpty()) {
+ Optional replicateTaskSummary = Optional.empty();
+ while (replicateTaskSummary.isEmpty()) {
final Optional oTask = taskService.getPrioritizedInitializedOrRunningTask(
!isTeeEnabled,
alreadyScannedTasks
@@ -146,12 +144,12 @@ private Optional getAuthorizationForAnyAvailableTask(
final Task task = oTask.get();
alreadyScannedTasks.add(task.getChainTaskId());
- authorization = getAuthorizationForTask(task, walletAddress);
+ replicateTaskSummary = getReplicateTaskSummary(task, walletAddress);
}
- return authorization;
+ return replicateTaskSummary;
}
- private Optional getAuthorizationForTask(Task task, String walletAddress) {
+ private Optional getReplicateTaskSummary(Task task, String walletAddress) {
String chainTaskId = task.getChainTaskId();
if (!acceptOrRejectTask(task, walletAddress)) {
return Optional.empty();
@@ -162,7 +160,12 @@ private Optional getAuthorizationForTask(Task task, Str
walletAddress,
chainTaskId,
task.getEnclaveChallenge());
- return Optional.of(authorization);
+ ReplicateTaskSummaryBuilder replicateTaskSummary = ReplicateTaskSummary.builder()
+ .workerpoolAuthorization(authorization);
+ if(task.isTeeTask()){
+ replicateTaskSummary.smsUrl(task.getSmsUrl());
+ }
+ return Optional.of(replicateTaskSummary.build());
}
/**
@@ -342,12 +345,8 @@ private Optional recoverReplicateInContributionPhase(Task
String chainTaskId = task.getChainTaskId();
String walletAddress = replicate.getWalletAddress();
- if (replicate.getLastRelevantStatus().isEmpty()) {
- return Optional.empty();
- }
-
boolean beforeContributing = replicate.isBeforeStatus(ReplicateStatus.CONTRIBUTING);
- boolean didReplicateStartContributing = replicate.getLastRelevantStatus().get().equals(ReplicateStatus.CONTRIBUTING);
+ boolean didReplicateStartContributing = replicate.getLastRelevantStatus() == ReplicateStatus.CONTRIBUTING;
boolean didReplicateContributeOnChain = replicatesService.didReplicateContributeOnchain(chainTaskId, walletAddress);
if (beforeContributing) {
@@ -370,12 +369,8 @@ private Optional recoverReplicateInContributionPhase(Task
}
Replicate replicateWithLatestChanges = oReplicateWithLatestChanges.get();
- if (replicateWithLatestChanges.getLastRelevantStatus().isEmpty()) {
- return Optional.empty();
- }
-
- boolean didReplicateContribute = replicateWithLatestChanges.getLastRelevantStatus().get()
- .equals(ReplicateStatus.CONTRIBUTED);
+ boolean didReplicateContribute = replicateWithLatestChanges.getLastRelevantStatus()
+ == ReplicateStatus.CONTRIBUTED;
if (didReplicateContribute) {
final Optional oReplicatesList = replicatesService.getReplicatesList(chainTaskId);
@@ -405,12 +400,8 @@ private Optional recoverReplicateInRevealPhase(Task task,
String chainTaskId = task.getChainTaskId();
String walletAddress = replicate.getWalletAddress();
- if (replicate.getLastRelevantStatus().isEmpty()) {
- return Optional.empty();
- }
-
- boolean isInStatusContributed = replicate.getLastRelevantStatus().get().equals(ReplicateStatus.CONTRIBUTED);
- boolean didReplicateStartRevealing = replicate.getLastRelevantStatus().get().equals(ReplicateStatus.REVEALING);
+ boolean isInStatusContributed = replicate.getLastRelevantStatus() == ReplicateStatus.CONTRIBUTED;
+ boolean didReplicateStartRevealing = replicate.getLastRelevantStatus() == ReplicateStatus.REVEALING;
boolean didReplicateRevealOnChain = replicatesService.didReplicateRevealOnchain(chainTaskId, walletAddress);
if (isInStatusContributed) {
@@ -434,15 +425,12 @@ private Optional recoverReplicateInRevealPhase(Task task,
return Optional.empty();
}
replicate = oReplicateWithLatestChanges.get();
- if (replicate.getLastRelevantStatus().isEmpty()) {
- return Optional.empty();
- }
- boolean didReplicateReveal = replicate.getLastRelevantStatus().get()
- .equals(ReplicateStatus.REVEALED);
+ boolean didReplicateReveal = replicate.getLastRelevantStatus()
+ == ReplicateStatus.REVEALED;
- boolean wasReplicateRequestedToUpload = replicate.getLastRelevantStatus().get()
- .equals(ReplicateStatus.RESULT_UPLOAD_REQUESTED);
+ boolean wasReplicateRequestedToUpload = replicate.getLastRelevantStatus()
+ == ReplicateStatus.RESULT_UPLOAD_REQUESTED;
if (didReplicateReveal) {
return Optional.of(TaskNotificationType.PLEASE_WAIT);
@@ -467,14 +455,10 @@ private Optional recoverReplicateInResultUploadPhase(Task
String chainTaskId = task.getChainTaskId();
String walletAddress = replicate.getWalletAddress();
- if (replicate.getLastRelevantStatus().isEmpty()) {
- return Optional.empty();
- }
-
- boolean wasReplicateRequestedToUpload = replicate.getLastRelevantStatus().get().equals(ReplicateStatus.RESULT_UPLOAD_REQUESTED);
- boolean didReplicateStartUploading = replicate.getLastRelevantStatus().get().equals(ReplicateStatus.RESULT_UPLOADING);
+ boolean wasReplicateRequestedToUpload = replicate.getLastRelevantStatus() == ReplicateStatus.RESULT_UPLOAD_REQUESTED;
+ boolean didReplicateStartUploading = replicate.getLastRelevantStatus() == ReplicateStatus.RESULT_UPLOADING;
boolean didReplicateUploadWithoutNotifying = replicatesService.isResultUploaded(task.getChainTaskId());
- boolean hasReplicateAlreadyUploaded = replicate.getLastRelevantStatus().get().equals(ReplicateStatus.RESULT_UPLOADED);
+ boolean hasReplicateAlreadyUploaded = replicate.getLastRelevantStatus() == ReplicateStatus.RESULT_UPLOADED;
if (wasReplicateRequestedToUpload) {
return Optional.of(TaskNotificationType.PLEASE_UPLOAD);
@@ -532,4 +516,17 @@ private TaskAbortCause getTaskAbortCause(Task task) {
return TaskAbortCause.UNKNOWN;
}
}
+
+ // region purge locks
+ @Override
+ public boolean purgeTask(String chainTaskId) {
+ taskAccessForNewReplicateLocks.remove(chainTaskId);
+ return !taskAccessForNewReplicateLocks.containsKey(chainTaskId);
+ }
+
+ @Override
+ public void purgeAllTasksData() {
+ taskAccessForNewReplicateLocks.clear();
+ }
+ // endregion
}
diff --git a/src/main/java/com/iexec/core/replicate/ReplicatesController.java b/src/main/java/com/iexec/core/replicate/ReplicatesController.java
index 0c1a2f8e1..0b302b653 100644
--- a/src/main/java/com/iexec/core/replicate/ReplicatesController.java
+++ b/src/main/java/com/iexec/core/replicate/ReplicatesController.java
@@ -16,7 +16,6 @@
package com.iexec.core.replicate;
-import com.iexec.common.chain.WorkerpoolAuthorization;
import com.iexec.common.notification.TaskNotification;
import com.iexec.common.notification.TaskNotificationType;
import com.iexec.common.replicate.*;
@@ -50,21 +49,21 @@ public ReplicatesController(ReplicatesService replicatesService,
}
@GetMapping("/replicates/available")
- public ResponseEntity getAvailableReplicate(
+ public ResponseEntity getAvailableReplicateTaskSummary(
@RequestParam(name = "blockNumber") long blockNumber,
@RequestHeader("Authorization") String bearerToken) {
String workerWalletAddress = jwtTokenProvider.getWalletAddressFromBearerToken(bearerToken);
if (workerWalletAddress.isEmpty()) {
- return ResponseEntity.status(HttpStatus.UNAUTHORIZED.value()).build();
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
- if (!workerService.isWorkerAllowedToAskReplicate(workerWalletAddress)){
- return ResponseEntity.status(HttpStatus.NO_CONTENT.value()).build();
+ if (!workerService.isWorkerAllowedToAskReplicate(workerWalletAddress)) {
+ return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
}
workerService.updateLastReplicateDemandDate(workerWalletAddress);
return replicateSupplyService
- .getAuthOfAvailableReplicate(blockNumber, workerWalletAddress)
+ .getAvailableReplicateTaskSummary(blockNumber, workerWalletAddress)
.map(ResponseEntity::ok)
.orElseGet(() -> status(HttpStatus.NO_CONTENT).build());
}
@@ -76,7 +75,7 @@ public ResponseEntity> getMissedTaskNotifications(
String workerWalletAddress = jwtTokenProvider.getWalletAddressFromBearerToken(bearerToken);
if (workerWalletAddress.isEmpty()) {
- return ResponseEntity.status(HttpStatus.UNAUTHORIZED.value()).build();
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
List missedTaskNotifications =
@@ -85,6 +84,17 @@ public ResponseEntity> getMissedTaskNotifications(
return ResponseEntity.ok(missedTaskNotifications);
}
+ /**
+ * Handles workers requests to update a replicate status.
+ *
+ * The scheduler response can only be null on authentication failures.
+ * In all other situations, a notification must be sent and the body cannot be null.
+ *
+ * @param bearerToken Authentication token of a worker.
+ * @param chainTaskId ID of the task on which the worker has an update.
+ * @param statusUpdate Status update sent by the worker.
+ * @return A notification to the worker. A notification is implemented in {@code TaskNotificationType}.
+ */
@PostMapping("/replicates/{chainTaskId}/updateStatus")
public ResponseEntity updateReplicateStatus(
@RequestHeader("Authorization") String bearerToken,
@@ -94,7 +104,7 @@ public ResponseEntity updateReplicateStatus(
String walletAddress = jwtTokenProvider.getWalletAddressFromBearerToken(bearerToken);
if (walletAddress.isEmpty()) {
- return ResponseEntity.status(HttpStatus.UNAUTHORIZED.value()).build();
+ return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
statusUpdate.setModifier(ReplicateStatusModifier.WORKER);
@@ -125,16 +135,17 @@ public ResponseEntity updateReplicateStatus(
return replicatesService
.updateReplicateStatus(chainTaskId, walletAddress, statusUpdate, updateReplicateStatusArgs)
.map(ResponseEntity::ok)
- .orElse(ResponseEntity.status(HttpStatus.FORBIDDEN.value())
- .build());
+ .orElse(ResponseEntity.status(HttpStatus.FORBIDDEN)
+ .body(TaskNotificationType.PLEASE_ABORT));
case ALREADY_REPORTED:
- return status(HttpStatus.ALREADY_REPORTED.value())
+ return ResponseEntity.status(HttpStatus.ALREADY_REPORTED)
.body(TaskNotificationType.PLEASE_WAIT);
case UNKNOWN_REPLICATE:
case BAD_WORKFLOW_TRANSITION:
case GENERIC_CANT_UPDATE:
default:
- return ResponseEntity.status(HttpStatus.FORBIDDEN.value()).build();
+ return ResponseEntity.status(HttpStatus.FORBIDDEN)
+ .body(TaskNotificationType.PLEASE_ABORT);
}
}
}
diff --git a/src/main/java/com/iexec/core/replicate/ReplicatesList.java b/src/main/java/com/iexec/core/replicate/ReplicatesList.java
index 5449b16a5..96651a248 100644
--- a/src/main/java/com/iexec/core/replicate/ReplicatesList.java
+++ b/src/main/java/com/iexec/core/replicate/ReplicatesList.java
@@ -69,8 +69,8 @@ public ReplicatesList(String chainTaskId, List replicates) {
public int getNbValidContributedWinners(String contributionHash) {
int nbValidWinners = 0;
for (Replicate replicate : replicates) {
- Optional oStatus = replicate.getLastRelevantStatus();
- if (oStatus.isPresent() && oStatus.get().equals(CONTRIBUTED)
+ ReplicateStatus status = replicate.getLastRelevantStatus();
+ if (status == CONTRIBUTED
&& contributionHash.equals(replicate.getContributionHash())) {
nbValidWinners++;
}
@@ -94,7 +94,7 @@ public int getNbReplicatesWithLastRelevantStatus(ReplicateStatus... listStatus)
int nbReplicates = 0;
for (Replicate replicate : replicates) {
for (ReplicateStatus status : listStatus) {
- if (Objects.equals(replicate.getLastRelevantStatus().orElse(null), status)) {
+ if (replicate.getLastRelevantStatus() == status) {
nbReplicates++;
}
}
diff --git a/src/main/java/com/iexec/core/replicate/ReplicatesService.java b/src/main/java/com/iexec/core/replicate/ReplicatesService.java
index 5c5da8949..06b965530 100644
--- a/src/main/java/com/iexec/core/replicate/ReplicatesService.java
+++ b/src/main/java/com/iexec/core/replicate/ReplicatesService.java
@@ -608,12 +608,8 @@ public boolean didReplicateRevealOnchain(String chainTaskId, String walletAddres
}
public void setRevealTimeoutStatusIfNeeded(String chainTaskId, Replicate replicate) {
- Optional oStatus = replicate.getLastRelevantStatus();
- if (oStatus.isEmpty()) {
- return;
- }
- ReplicateStatus status = oStatus.get();
- if (status.equals(REVEALING) || status.equals(CONTRIBUTED)) {
+ ReplicateStatus status = replicate.getLastRelevantStatus();
+ if (status == REVEALING || status == CONTRIBUTED) {
ReplicateStatusUpdate statusUpdate = ReplicateStatusUpdate.poolManagerRequest(FAILED, REVEAL_TIMEOUT);
updateReplicateStatus(chainTaskId, replicate.getWalletAddress(), statusUpdate);
}
diff --git a/src/main/java/com/iexec/core/security/ChallengeService.java b/src/main/java/com/iexec/core/security/ChallengeService.java
index dc05de1c4..c7be212e2 100644
--- a/src/main/java/com/iexec/core/security/ChallengeService.java
+++ b/src/main/java/com/iexec/core/security/ChallengeService.java
@@ -18,28 +18,33 @@
import net.jodah.expiringmap.ExpirationPolicy;
import net.jodah.expiringmap.ExpiringMap;
-import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.stereotype.Service;
+import java.security.SecureRandom;
+import java.util.Base64;
import java.util.concurrent.TimeUnit;
@Service
public class ChallengeService {
- // Map
- // this map will automatically delete entries older than one hour, ExpiringMap is thread-safe
- private final ExpiringMap challengeMap;
+ private final ExpiringMap challengesMap = ExpiringMap.builder()
+ .expiration(5, TimeUnit.MINUTES)
+ .expirationPolicy(ExpirationPolicy.CREATED)
+ .build();
- ChallengeService() {
- this.challengeMap = ExpiringMap.builder()
- .expiration(60, TimeUnit.MINUTES)
- .expirationPolicy(ExpirationPolicy.CREATED)
- .build();
+ public String computeChallenge() {
+ SecureRandom secureRandom = new SecureRandom();
+ byte[] seed = new byte[32];
+ secureRandom.nextBytes(seed);
+ return Base64.getEncoder().encodeToString(seed);
}
public String getChallenge(String workerWallet) {
- String challenge = RandomStringUtils.randomAlphabetic(10);
- challengeMap.putIfAbsent(workerWallet, challenge);
- return challengeMap.get(workerWallet);
+ return challengesMap.computeIfAbsent(workerWallet, wallet -> computeChallenge());
}
+
+ public void removeChallenge(String workerWallet, String challenge) {
+ challengesMap.remove(workerWallet, challenge);
+ }
+
}
diff --git a/src/main/java/com/iexec/core/security/EIP712ChallengeService.java b/src/main/java/com/iexec/core/security/EIP712ChallengeService.java
index 91740ef6a..c7e2106c5 100644
--- a/src/main/java/com/iexec/core/security/EIP712ChallengeService.java
+++ b/src/main/java/com/iexec/core/security/EIP712ChallengeService.java
@@ -16,10 +16,9 @@
package com.iexec.core.security;
+import com.iexec.common.chain.eip712.EIP712Domain;
import com.iexec.common.chain.eip712.entity.Challenge;
import com.iexec.common.chain.eip712.entity.EIP712Challenge;
-import com.iexec.common.chain.eip712.EIP712Domain;
-import lombok.extern.slf4j.Slf4j;
import net.jodah.expiringmap.ExpirationPolicy;
import net.jodah.expiringmap.ExpiringMap;
import org.springframework.stereotype.Service;
@@ -29,7 +28,6 @@
import java.util.Base64;
import java.util.concurrent.TimeUnit;
-@Slf4j
@Service
public class EIP712ChallengeService {
diff --git a/src/main/java/com/iexec/core/security/JwtTokenProvider.java b/src/main/java/com/iexec/core/security/JwtTokenProvider.java
index 5c46088f9..2b2ed3e55 100644
--- a/src/main/java/com/iexec/core/security/JwtTokenProvider.java
+++ b/src/main/java/com/iexec/core/security/JwtTokenProvider.java
@@ -16,39 +16,55 @@
package com.iexec.core.security;
-import io.jsonwebtoken.Claims;
-import io.jsonwebtoken.JwtException;
-import io.jsonwebtoken.Jwts;
-import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.*;
+import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.info.BuildProperties;
import org.springframework.stereotype.Component;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.Date;
+import java.util.concurrent.ConcurrentHashMap;
@Slf4j
@Component
public class JwtTokenProvider {
- private final ChallengeService challengeService;
- private final String secretKey;
+ static final int KEY_SIZE = 128;
+ private static final long TOKEN_VALIDITY_DURATION = 1000L * 60 * 60;
+ private final ConcurrentHashMap jwTokensMap = new ConcurrentHashMap<>();
+ private final String applicationId;
+ private final byte[] secretKey = new byte[KEY_SIZE];
- public JwtTokenProvider(ChallengeService challengeService) {
- this.challengeService = challengeService;
+ public JwtTokenProvider(BuildProperties buildProperties) {
+ this.applicationId = "iExec Scheduler v" + buildProperties.getVersion();
SecureRandom secureRandom = new SecureRandom();
- byte[] seed = new byte[32];
- secureRandom.nextBytes(seed);
- this.secretKey = Base64.getEncoder().encodeToString(seed);
+ secureRandom.nextBytes(secretKey);
}
- public String createToken(String walletAddress) {
- return Jwts.builder()
- .setAudience(walletAddress)
- .setIssuedAt(new Date())
- .setSubject(challengeService.getChallenge(walletAddress))
- .signWith(SignatureAlgorithm.HS256, secretKey)
- .compact();
+ /**
+ * Creates a signed JWT with expiration date for a given ethereum address.
+ *
+ * The token is cached. It might be pruned in best effort mode by other processes founding that token is expired.
+ * @param walletAddress worker address for which the token is created
+ * @return A signed JWT for a given ethereum address
+ */
+ public String getOrCreateToken(String walletAddress) {
+ // Do not try to check if JWT is valid here, it introduces too many questions on challenge validity,
+ // concurrency of operations and potential race conditions.
+ // When a token is presented, scheduler answers UNAUTHORIZED if the JWT is invalid and purges caches
+ // on expiration of a known JWT.
+ return jwTokensMap.computeIfAbsent(walletAddress, address -> {
+ Date now = new Date();
+ return Jwts.builder()
+ .setAudience(applicationId)
+ .setIssuedAt(now)
+ .setExpiration(new Date(now.getTime() + TOKEN_VALIDITY_DURATION))
+ .setSubject(address)
+ .signWith(Keys.hmacShaKeyFor(secretKey), SignatureAlgorithm.HS256)
+ .compact();
+ });
}
public String resolveToken(String token) {
@@ -58,46 +74,52 @@ public String resolveToken(String token) {
return null;
}
- /*
- * IMPORTANT /!\
- * Having the same validity duration for both challenge
- * and jwtoken can cause a problem. The latter should be
- * slightly longer (in minutes). In this case the challenge
- * is valid for 60 minutes while jwtoken stays valid
- * for 65 minutes.
- *
- * Problem description:
- * 1) jwtString expires
- * 2) worker gets old challenge
- * 3) old challenge expires
- * 4) worker tries logging with old challenge
+ /**
+ * Checks if a JWT is valid.
+ *
+ * A valid JWT must:
+ *
+ * - be signed with the scheduler private key
+ *
- not be expired
+ *
- contain the scheduler application ID in the audience claim
+ *
+ * An invalid JWT will return an UNAUTHORIZED status and require to perform a full authentication loop
+ * with a new signed challenge (get new challenge -> sign challenge -> check signed challenge -> get or create JWT).
+ *
+ * If the JWT has expired, the cache will be purged and a new JWT will be generated.
+ * For other invalid JWTs, the cached JWT will be returned on next login.
+ *
+ * @param token The token whose validity must be established
+ * @return true if the token is valid, false otherwise
*/
public boolean isValidToken(String token) {
try {
- Claims claims = Jwts.parser()
+ if (!jwTokensMap.containsValue(token)) {
+ throw new JwtException("Unknown JWT");
+ }
+ Claims claims = Jwts.parserBuilder()
.setSigningKey(secretKey)
- .parseClaimsJws(token).getBody();
-
- // check the expiration date
- Date now = new Date();
- long validityInMilliseconds = 1000L * 60 * 65; // 65 minutes
- Date tokenExpiryDate = new Date(claims.getIssuedAt().getTime() + validityInMilliseconds);
-
- // check the content of the challenge
- String walletAddress = claims.getAudience();
- boolean isChallengeCorrect = challengeService.getChallenge(walletAddress).equals(claims.getSubject());
-
- return tokenExpiryDate.after(now) && isChallengeCorrect;
+ .build()
+ .parseClaimsJws(token)
+ .getBody();
+ return applicationId.equals(claims.getAudience());
+ } catch (ExpiredJwtException e) {
+ log.warn("JWT has expired");
+ String walletAddress = e.getClaims().getSubject();
+ jwTokensMap.remove(walletAddress, token);
} catch (JwtException | IllegalArgumentException e) {
- log.warn("Expired or invalid JWT token [exception:{}]", e.getMessage());
+ log.warn("JWT is invalid [{}: {}]", e.getClass().getSimpleName(), e.getMessage());
}
return false;
}
public String getWalletAddress(String token) {
- return Jwts.parser()
+ return Jwts.parserBuilder()
.setSigningKey(secretKey)
- .parseClaimsJws(token).getBody().getAudience();
+ .build()
+ .parseClaimsJws(token)
+ .getBody()
+ .getSubject();
}
public String getWalletAddressFromBearerToken(String bearerToken) {
diff --git a/src/main/java/com/iexec/core/sms/SmsClientProviderConfiguration.java b/src/main/java/com/iexec/core/sms/SmsClientProviderConfiguration.java
new file mode 100644
index 000000000..da6b53e63
--- /dev/null
+++ b/src/main/java/com/iexec/core/sms/SmsClientProviderConfiguration.java
@@ -0,0 +1,14 @@
+package com.iexec.core.sms;
+
+import com.iexec.sms.api.SmsClientProvider;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class SmsClientProviderConfiguration {
+
+ @Bean
+ SmsClientProvider smsClientProvider() {
+ return new SmsClientProvider();
+ }
+}
diff --git a/src/main/java/com/iexec/core/sms/SmsService.java b/src/main/java/com/iexec/core/sms/SmsService.java
index 7df4bb4d0..ecef27718 100644
--- a/src/main/java/com/iexec/core/sms/SmsService.java
+++ b/src/main/java/com/iexec/core/sms/SmsService.java
@@ -16,10 +16,15 @@
package com.iexec.core.sms;
+import com.iexec.common.tee.TeeFramework;
+import com.iexec.common.tee.TeeUtils;
import com.iexec.common.utils.BytesUtils;
+import com.iexec.core.registry.PlatformRegistryConfiguration;
import com.iexec.sms.api.SmsClient;
+import com.iexec.sms.api.SmsClientProvider;
import feign.FeignException;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
import org.springframework.retry.annotation.Recover;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
@@ -30,25 +35,102 @@
@Slf4j
@Service
public class SmsService {
- private final SmsClient smsClient;
+ private final PlatformRegistryConfiguration registryConfiguration;
+ private final SmsClientProvider smsClientProvider;
- public SmsService(SmsClient smsClient) {
- this.smsClient = smsClient;
+ public SmsService(PlatformRegistryConfiguration registryConfiguration,
+ SmsClientProvider smsClientProvider) {
+ this.registryConfiguration = registryConfiguration;
+ this.smsClientProvider = smsClientProvider;
}
- public Optional getEnclaveChallenge(String chainTaskId, boolean isTeeEnabled) {
- return isTeeEnabled
- ? generateEnclaveChallenge(chainTaskId)
- : Optional.of(BytesUtils.EMPTY_ADDRESS);
+ /**
+ * Checks the following conditions:
+ *
+ * - Given deal exists on-chain;
+ * - The {@link SmsClient} can be created, based on the on-chain deal definition;
+ * - The targeted SMS is configured to run with the task's TEE framework.
+ *
+ *
+ * If any of these conditions is wrong, then the {@link SmsClient} is considered to be not-ready.
+ *
+ * @param chainTaskId ID of the on-chain task.
+ * @param tag Tag of the deal.
+ * @return SMS url if TEE types of tag & SMS match.
+ */
+ public Optional getVerifiedSmsUrl(String chainTaskId, String tag) {
+ final TeeFramework teeFrameworkForDeal = TeeUtils.getTeeFramework(tag);
+ if(teeFrameworkForDeal == null){
+ log.error("Can't get verified SMS url with invalid TEE framework " +
+ "from tag [chainTaskId:{}]", chainTaskId);
+ return Optional.empty();
+ }
+ Optional smsUrl = retrieveSmsUrl(teeFrameworkForDeal);
+ if(smsUrl.isEmpty()){
+ log.error("Can't get verified SMS url since type of tag is not " +
+ "supported [chainTaskId:{},teeFrameworkForDeal:{}]",
+ chainTaskId, teeFrameworkForDeal);
+ return Optional.empty();
+ }
+ final SmsClient smsClient = smsClientProvider.getSmsClient(smsUrl.get());
+ if(!checkSmsTeeFramework(smsClient, teeFrameworkForDeal, chainTaskId)){
+ log.error("Can't get verified SMS url since tag TEE type " +
+ "does not match SMS TEE type [chainTaskId:{},teeFrameworkForDeal:{}]",
+ chainTaskId, teeFrameworkForDeal);
+ return Optional.empty();
+ }
+ return smsUrl;
+ }
+
+ private Optional retrieveSmsUrl(TeeFramework teeFramework) {
+ Optional smsUrl = Optional.empty();
+ if(teeFramework == TeeFramework.SCONE){
+ smsUrl = Optional.of(registryConfiguration.getSconeSms());
+ } else if(teeFramework == TeeFramework.GRAMINE){
+ smsUrl = Optional.of(registryConfiguration.getGramineSms());
+ }
+ return smsUrl;
+ }
+
+ private boolean checkSmsTeeFramework(SmsClient smsClient,
+ TeeFramework teeFrameworkForDeal,
+ String chainTaskId) {
+ final TeeFramework smsTeeFramework;
+ try {
+ smsTeeFramework = smsClient.getTeeFramework();
+ } catch (FeignException e) {
+ log.error("Can't retrieve SMS TEE framework [chainTaskId:{}]",
+ chainTaskId, e);
+ return false;
+ }
+
+ if (smsTeeFramework != teeFrameworkForDeal) {
+ log.error("SMS is configured for another TEE framework " +
+ "[chainTaskId:{}, teeFrameworkForDeal:{}, smsTeeFramework:{}]",
+ chainTaskId, teeFrameworkForDeal, smsTeeFramework);
+ return false;
+ }
+ return true;
+ }
+
+ public Optional getEnclaveChallenge(String chainTaskId, String smsUrl) {
+ return StringUtils.isEmpty(smsUrl)
+ ? Optional.of(BytesUtils.EMPTY_ADDRESS)
+ : generateEnclaveChallenge(chainTaskId, smsUrl);
}
@Retryable(value = FeignException.class)
- Optional generateEnclaveChallenge(String chainTaskId) {
+ Optional generateEnclaveChallenge(String chainTaskId, String smsUrl) {
+ // SMS client should already have been created once before.
+ // If it couldn't be created, then the task would have been aborted.
+ // So the following won't throw an exception.
+ final SmsClient smsClient = smsClientProvider.getSmsClient(smsUrl);
- String teeChallengePublicKey = smsClient.generateTeeChallenge(chainTaskId);
+ final String teeChallengePublicKey = smsClient.generateTeeChallenge(chainTaskId);
- if (teeChallengePublicKey == null || teeChallengePublicKey.isEmpty()) {
- log.error("An error occurred while getting teeChallengePublicKey [chainTaskId:{}]", chainTaskId);
+ if (StringUtils.isEmpty(teeChallengePublicKey)) {
+ log.error("An error occurred while getting teeChallengePublicKey "
+ + "[chainTaskId:{}, smsUrl:{}]", chainTaskId, smsUrl);
return Optional.empty();
}
@@ -56,7 +138,7 @@ Optional generateEnclaveChallenge(String chainTaskId) {
}
@Recover
- Optional generateEnclaveChallenge(FeignException e, String chainTaskId) {
+ Optional generateEnclaveChallenge(FeignException e, String chainTaskId, String smsUrl) {
log.error("Failed to get enclaveChallenge from SMS even after retrying [chainTaskId:{}, attempts:3]", chainTaskId, e);
return Optional.empty();
}
diff --git a/src/main/java/com/iexec/core/task/Task.java b/src/main/java/com/iexec/core/task/Task.java
index cee3b77f2..5f95fdaab 100644
--- a/src/main/java/com/iexec/core/task/Task.java
+++ b/src/main/java/com/iexec/core/task/Task.java
@@ -21,7 +21,6 @@
import com.iexec.common.chain.ChainUtils;
import com.iexec.common.dapp.DappType;
import com.iexec.common.tee.TeeUtils;
-
import lombok.*;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Version;
@@ -30,7 +29,6 @@
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
-import java.time.Duration;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@@ -58,10 +56,6 @@ public class Task {
public static final String CURRENT_STATUS_FIELD_NAME = "currentStatus";
public static final String CONTRIBUTION_DEADLINE_FIELD_NAME = "contributionDeadline";
- /**
- * An XL task timeout happens after 100 hours.
- */
- public static final Duration LONGEST_TASK_TIMEOUT = Duration.ofHours(100);
@Id
private String id;
@@ -96,6 +90,7 @@ public class Task {
private String chainCallbackData;
private List dateStatusList;
private String enclaveChallenge;
+ private String smsUrl;
public Task(String dappName, String commandLine, int trust) {
this.dappType = DappType.DOCKER;
diff --git a/src/main/java/com/iexec/core/task/TaskController.java b/src/main/java/com/iexec/core/task/TaskController.java
index 378fa85e0..848a19b19 100644
--- a/src/main/java/com/iexec/core/task/TaskController.java
+++ b/src/main/java/com/iexec/core/task/TaskController.java
@@ -29,7 +29,6 @@
import com.iexec.core.replicate.ReplicateModel;
import com.iexec.core.replicate.ReplicatesService;
import com.iexec.core.security.EIP712ChallengeService;
-import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@@ -42,7 +41,6 @@
import static org.springframework.http.ResponseEntity.notFound;
import static org.springframework.http.ResponseEntity.ok;
-@Slf4j
@RestController
public class TaskController {
diff --git a/src/main/java/com/iexec/core/task/TaskRepository.java b/src/main/java/com/iexec/core/task/TaskRepository.java
index 5f799cd01..766014baf 100644
--- a/src/main/java/com/iexec/core/task/TaskRepository.java
+++ b/src/main/java/com/iexec/core/task/TaskRepository.java
@@ -56,13 +56,13 @@ interface TaskRepository extends MongoRepository {
*
*
* @param statuses The task status should be one of this list.
- * @param excludedTag The task tag should not be this tag
+ * @param excludedTags The task tag should not be one this tag list
* - use {@literal null} if no tag should be excluded.
* @param excludedChainTaskIds The chain task ID should not be one of this list.
* @param sort How to prioritize tasks.
* @return The first task matching with the criteria, according to the {@code sort} parameter.
*/
- Optional findFirstByCurrentStatusInAndTagNotAndChainTaskIdNotIn(List statuses, String excludedTag, List excludedChainTaskIds, Sort sort);
+ Optional findFirstByCurrentStatusInAndTagNotInAndChainTaskIdNotIn(List statuses, List excludedTags, List excludedChainTaskIds, Sort sort);
@Query("{ 'currentStatus': {$nin: ?0} }")
List findByCurrentStatusNotIn(List statuses);
diff --git a/src/main/java/com/iexec/core/task/TaskService.java b/src/main/java/com/iexec/core/task/TaskService.java
index 55a04c29e..cb8f6cb76 100644
--- a/src/main/java/com/iexec/core/task/TaskService.java
+++ b/src/main/java/com/iexec/core/task/TaskService.java
@@ -21,8 +21,8 @@
import com.iexec.common.tee.TeeUtils;
import com.iexec.core.chain.IexecHubService;
import com.iexec.core.replicate.ReplicatesList;
-import com.iexec.core.replicate.ReplicatesService;
import lombok.extern.slf4j.Slf4j;
+import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
@@ -39,14 +39,11 @@
public class TaskService {
private final TaskRepository taskRepository;
private final IexecHubService iexecHubService;
- private final ReplicatesService replicatesService;
public TaskService(TaskRepository taskRepository,
- IexecHubService iexecHubService,
- ReplicatesService replicatesService) {
+ IexecHubService iexecHubService) {
this.taskRepository = taskRepository;
this.iexecHubService = iexecHubService;
- this.replicatesService = replicatesService;
}
/**
@@ -78,26 +75,23 @@ public Optional addTask(
Date contributionDeadline,
Date finalDeadline
) {
- return taskRepository
- .findByChainDealIdAndTaskIndex(chainDealId, taskIndex)
- .>map(task -> {
- log.info("Task already added [chainDealId:{}, taskIndex:{}, " +
- "imageName:{}, commandLine:{}, trust:{}]", chainDealId,
- taskIndex, imageName, commandLine, trust);
- return Optional.empty();
- })
- .orElseGet(() -> {
- Task newTask = new Task(chainDealId, taskIndex, imageName,
- commandLine, trust, maxExecutionTime, tag);
- newTask.setDealBlockNumber(dealBlockNumber);
- newTask.setFinalDeadline(finalDeadline);
- newTask.setContributionDeadline(contributionDeadline);
- newTask = taskRepository.save(newTask);
- log.info("Added new task [chainDealId:{}, taskIndex:{}, imageName:{}, " +
- "commandLine:{}, trust:{}, chainTaskId:{}]", chainDealId,
- taskIndex, imageName, commandLine, trust, newTask.getChainTaskId());
- return Optional.of(newTask);
- });
+ Task newTask = new Task(chainDealId, taskIndex, imageName,
+ commandLine, trust, maxExecutionTime, tag);
+ newTask.setDealBlockNumber(dealBlockNumber);
+ newTask.setFinalDeadline(finalDeadline);
+ newTask.setContributionDeadline(contributionDeadline);
+ try {
+ newTask = taskRepository.save(newTask);
+ log.info("Added new task [chainDealId:{}, taskIndex:{}, imageName:{}, " +
+ "commandLine:{}, trust:{}, chainTaskId:{}]", chainDealId,
+ taskIndex, imageName, commandLine, trust, newTask.getChainTaskId());
+ return Optional.of(newTask);
+ } catch (DuplicateKeyException e) {
+ log.info("Task already added [chainDealId:{}, taskIndex:{}, " +
+ "imageName:{}, commandLine:{}, trust:{}]", chainDealId,
+ taskIndex, imageName, commandLine, trust);
+ return Optional.empty();
+ }
}
/**
@@ -149,19 +143,19 @@ public List findByCurrentStatus(List statusList) {
public Optional getPrioritizedInitializedOrRunningTask(
boolean shouldExcludeTeeTasks,
List excludedChainTaskIds) {
- final String excludedTag = shouldExcludeTeeTasks
- ? TeeUtils.TEE_TAG
+ final List excludedTags = shouldExcludeTeeTasks
+ ? List.of(TeeUtils.TEE_SCONE_ONLY_TAG, TeeUtils.TEE_GRAMINE_ONLY_TAG)
: null;
return findPrioritizedTask(
Arrays.asList(INITIALIZED, RUNNING),
- excludedTag,
+ excludedTags,
excludedChainTaskIds,
Sort.by(Sort.Order.desc(Task.CURRENT_STATUS_FIELD_NAME),
Sort.Order.asc(Task.CONTRIBUTION_DEADLINE_FIELD_NAME)));
}
/**
- * Shortcut for {@link TaskRepository#findFirstByCurrentStatusInAndTagNotAndChainTaskIdNotIn}.
+ * Shortcut for {@link TaskRepository#findFirstByCurrentStatusInAndTagNotInAndChainTaskIdNotIn}.
* Retrieves the prioritized task matching with given criteria:
*
* - Task is in one of given {@code statuses};
@@ -180,12 +174,12 @@ public Optional getPrioritizedInitializedOrRunningTask(
* @return The first task matching with the criteria, according to the {@code sort} parameter.
*/
private Optional findPrioritizedTask(List statuses,
- String excludedTag,
+ List excludedTags,
List excludedChainTaskIds,
Sort sort) {
- return taskRepository.findFirstByCurrentStatusInAndTagNotAndChainTaskIdNotIn(
+ return taskRepository.findFirstByCurrentStatusInAndTagNotInAndChainTaskIdNotIn(
statuses,
- excludedTag,
+ excludedTags,
excludedChainTaskIds,
sort
);
diff --git a/src/main/java/com/iexec/core/task/listener/TaskListeners.java b/src/main/java/com/iexec/core/task/listener/TaskListeners.java
index 7948527d6..a2ee4d0db 100644
--- a/src/main/java/com/iexec/core/task/listener/TaskListeners.java
+++ b/src/main/java/com/iexec/core/task/listener/TaskListeners.java
@@ -16,6 +16,7 @@
package com.iexec.core.task.listener;
+import com.iexec.common.lifecycle.purge.PurgeService;
import com.iexec.common.notification.TaskNotification;
import com.iexec.common.notification.TaskNotificationExtra;
import com.iexec.common.notification.TaskNotificationType;
@@ -43,15 +44,18 @@ public class TaskListeners {
private final NotificationService notificationService;
private final ReplicatesService replicatesService;
private final WorkerService workerService;
+ private final PurgeService purgeService;
public TaskListeners(TaskUpdateRequestManager taskUpdateRequestManager,
NotificationService notificationService,
ReplicatesService replicatesService,
- WorkerService workerService) {
+ WorkerService workerService,
+ PurgeService purgeService) {
this.taskUpdateRequestManager = taskUpdateRequestManager;
this.notificationService = notificationService;
this.replicatesService = replicatesService;
this.workerService = workerService;
+ this.purgeService = purgeService;
}
@@ -163,7 +167,7 @@ public void onTaskCompletedEvent(TaskCompletedEvent event) {
.workersAddress(Collections.emptyList())
.build());
- removeChainTaskIdFromWorkers(chainTaskId);
+ purgeTask(chainTaskId);
}
@EventListener
@@ -177,7 +181,7 @@ public void onTaskFailedEvent(TaskFailedEvent event) {
.workersAddress(Collections.emptyList())
.build());
- removeChainTaskIdFromWorkers(chainTaskId);
+ purgeTask(chainTaskId);
}
@EventListener
@@ -191,13 +195,17 @@ public void onTaskRunningFailedEvent(TaskRunningFailedEvent event) {
.workersAddress(Collections.emptyList())
.build());
- removeChainTaskIdFromWorkers(chainTaskId);
+ purgeTask(chainTaskId);
}
- private void removeChainTaskIdFromWorkers(String chainTaskId) {
+ private void purgeTask(String chainTaskId) {
+ // Remove task from workers
for (Replicate replicate : replicatesService.getReplicates(chainTaskId)) {
workerService.removeChainTaskIdFromWorker(chainTaskId, replicate.getWalletAddress());
}
+
+ // Remove other services in-mem task info
+ purgeService.purgeAllServices(chainTaskId);
}
}
diff --git a/src/main/java/com/iexec/core/task/update/TaskUpdateManager.java b/src/main/java/com/iexec/core/task/update/TaskUpdateManager.java
index 384ca7f00..7d65e2d26 100644
--- a/src/main/java/com/iexec/core/task/update/TaskUpdateManager.java
+++ b/src/main/java/com/iexec/core/task/update/TaskUpdateManager.java
@@ -202,13 +202,25 @@ void received2Initializing(Task task) {
return;
}
+ if (task.isTeeTask()) {
+ Optional smsUrl = smsService.getVerifiedSmsUrl(task.getChainTaskId(), task.getTag());
+ if(smsUrl.isEmpty()){
+ log.error("Couldn't get verified SMS url [chainTaskId: {}]", task.getChainTaskId());
+ updateTaskStatusAndSave(task, INITIALIZE_FAILED);
+ updateTaskStatusAndSave(task, FAILED);
+ return;
+ }
+ task.setSmsUrl(smsUrl.get()); //SMS URL source of truth for the task
+ taskService.updateTask(task);
+ }
+
blockchainAdapterService
.requestInitialize(task.getChainDealId(), task.getTaskIndex())
.filter(chainTaskId -> chainTaskId.equalsIgnoreCase(task.getChainTaskId()))
.ifPresentOrElse(chainTaskId -> {
log.info("Requested initialize on blockchain [chainTaskId:{}]",
task.getChainTaskId());
- final Optional enclaveChallenge = smsService.getEnclaveChallenge(chainTaskId, task.isTeeTask());
+ final Optional enclaveChallenge = smsService.getEnclaveChallenge(chainTaskId, task.getSmsUrl());
if (enclaveChallenge.isEmpty()) {
log.error("Can't initialize task, enclave challenge is empty" +
" [chainTaskId:{}]", chainTaskId);
@@ -365,7 +377,6 @@ void running2RunningFailed(Task task) {
boolean notAllReplicatesFailed = replicatesOfAliveWorkers
.stream()
.map(Replicate::getLastRelevantStatus)
- .map(Optional::get)
.anyMatch(Predicate.not(ReplicateStatus::isFailedBeforeComputed));
if (notAllReplicatesFailed) {
@@ -486,8 +497,7 @@ void resultUploading2Uploaded(Task task) {
boolean isReplicateUploading = replicate.getCurrentStatus() == ReplicateStatus.RESULT_UPLOADING;
boolean isReplicateRecoveringToUpload = replicate.getCurrentStatus() == ReplicateStatus.RECOVERING &&
- replicate.getLastRelevantStatus().isPresent() &&
- replicate.getLastRelevantStatus().get() == ReplicateStatus.RESULT_UPLOADING;
+ replicate.getLastRelevantStatus() == ReplicateStatus.RESULT_UPLOADING;
if (!isReplicateUploading && !isReplicateRecoveringToUpload) {
requestUpload(task);
diff --git a/src/main/java/com/iexec/core/task/update/TaskUpdateRequestManager.java b/src/main/java/com/iexec/core/task/update/TaskUpdateRequestManager.java
index 1d68612ea..3cda6d4a2 100644
--- a/src/main/java/com/iexec/core/task/update/TaskUpdateRequestManager.java
+++ b/src/main/java/com/iexec/core/task/update/TaskUpdateRequestManager.java
@@ -26,7 +26,7 @@
import java.util.concurrent.*;
import java.util.function.Supplier;
-import static com.iexec.core.task.Task.LONGEST_TASK_TIMEOUT;
+import static com.iexec.common.chain.CategoriesUtils.LONGEST_TASK_TIMEOUT;
/**
* This class is used to perform updates on a task one by one.
diff --git a/src/main/java/com/iexec/core/worker/WorkerController.java b/src/main/java/com/iexec/core/worker/WorkerController.java
index 0ba14b1a5..31cf37567 100644
--- a/src/main/java/com/iexec/core/worker/WorkerController.java
+++ b/src/main/java/com/iexec/core/worker/WorkerController.java
@@ -88,7 +88,8 @@ public ResponseEntity getToken(@RequestParam(name = "walletAddress") Str
if (SignatureUtils.doesSignatureMatchesAddress(signature.getR(), signature.getS(),
BytesUtils.bytesToString(hashToCheck), walletAddress)) {
- String token = jwtTokenProvider.createToken(walletAddress);
+ challengeService.removeChallenge(walletAddress, challenge);
+ String token = jwtTokenProvider.getOrCreateToken(walletAddress);
return ok(token);
}
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 85c4d9c1c..8aa0c0724 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -8,6 +8,10 @@ spring:
host: ${MONGO_HOST:localhost}
port: ${MONGO_PORT:13002}
auto-index-creation: true # Auto-index creation is disabled by default starting with Spring Data MongoDB 3.x.
+ config.import: "configserver:${IEXEC_PLATFORM_REGISTRY}" # configserver:http://platform-registry:8888
+ cloud.config:
+ profile: ${IEXEC_PLATFORM_REGISTRY_STACK:} # mainnet, bellecour3, 1234, ..
+ label: ${IEXEC_PLATFORM_REGISTRY_LABEL:} # main, develop, v10, 07998be
mongock:
runner-type: InitializingBean
change-logs-scan-package:
@@ -44,11 +48,7 @@ wallet:
password: ${IEXEC_CORE_WALLET_PASSWORD:whatever}
chain:
- id: ${IEXEC_CHAIN_ID:17}
- sidechain: ${IEXEC_IS_SIDECHAIN:false}
privateAddress: ${IEXEC_PRIVATE_CHAIN_ADDRESS:http://localhost:8545}
- publicAddress: ${IEXEC_PUBLIC_CHAIN_ADDRESS:http://localhost:8545}
- hubAddress: ${IEXEC_HUB_ADDRESS:0xBF6B2B07e47326B7c8bfCb4A5460bef9f0Fd2002}
poolAddress: ${POOL_ADDRESS:0x365E7BABAa85eC61Dffe5b520763062e6C29dA27}
startBlockNumber: ${IEXEC_START_BLOCK_NUMBER:0}
gasPriceMultiplier: ${IEXEC_GAS_PRICE_MULTIPLIER:1.0} # txs will be sent with networkGasPrice*gasPriceMultiplier, 4.0 means super fast
@@ -67,15 +67,6 @@ resultRepository:
host: ${IEXEC_RESULT_REPOSITORY_HOST:localhost}
port: ${IEXEC_RESULT_REPOSITORY_PORT:13200}
-ipfs:
- host: ${IEXEC_IPFS_HOST:127.0.0.1}
- port: ${IEXEC_IPFS_PORT:5001}
-
-sms:
- protocol: ${IEXEC_SMS_PROTOCOL:http}
- host: ${IEXEC_SMS_HOST:localhost}
- port: ${IEXEC_SMS_PORT:13300}
-
management:
endpoints:
web:
diff --git a/src/main/resources/banner.txt b/src/main/resources/banner.txt
index 9dd0c73d4..2bb249c33 100644
--- a/src/main/resources/banner.txt
+++ b/src/main/resources/banner.txt
@@ -4,4 +4,4 @@ ${Ansi.YELLOW} \ / | | _| \ \/ / _ \/ __| \ \ \ \
${Ansi.YELLOW} /_ _\ | | |___ > < __/ (__ / / / /
${Ansi.YELLOW} \/ |_|_____/_/\_\___|\___| /_/_/_/
${Ansi.YELLOW} =========
-${Ansi.YELLOW} :: Spring Boot${spring-boot.formatted-version} :: ${Ansi.DEFAULT}
\ No newline at end of file
+${Ansi.YELLOW} :: ${application.title}${application.formatted-version} built with Spring Boot${spring-boot.formatted-version} :: ${Ansi.DEFAULT}
\ No newline at end of file
diff --git a/src/test/java/com/iexec/core/chain/SignatureServiceTests.java b/src/test/java/com/iexec/core/chain/SignatureServiceTests.java
index 509a543b3..08b91b57a 100644
--- a/src/test/java/com/iexec/core/chain/SignatureServiceTests.java
+++ b/src/test/java/com/iexec/core/chain/SignatureServiceTests.java
@@ -20,8 +20,6 @@
import com.iexec.common.security.Signature;
import com.iexec.common.utils.BytesUtils;
import com.iexec.common.utils.HashUtils;
-import com.iexec.core.configuration.SmsConfiguration;
-
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -36,7 +34,6 @@
class SignatureServiceTests {
@Mock private CredentialsService credentialsService;
- @Mock private SmsConfiguration smsConfiguration;
@InjectMocks
private SignatureService signatureService;
diff --git a/src/test/java/com/iexec/core/chain/adapter/BlockchainAdapterServiceTests.java b/src/test/java/com/iexec/core/chain/adapter/BlockchainAdapterServiceTests.java
index b8589f096..9ef110344 100644
--- a/src/test/java/com/iexec/core/chain/adapter/BlockchainAdapterServiceTests.java
+++ b/src/test/java/com/iexec/core/chain/adapter/BlockchainAdapterServiceTests.java
@@ -139,7 +139,7 @@ void isCommandCompletedWithSuccess() {
Optional commandCompleted = blockchainAdapterService
.isCommandCompleted(blockchainAdapterClient::getStatusForInitializeTaskRequest,
CHAIN_TASK_ID, PERIOD, MAX_ATTEMPTS);
- Assertions.assertThat(commandCompleted.isPresent()).isTrue();
+ Assertions.assertThat(commandCompleted).isPresent();
Assertions.assertThat(commandCompleted.get()).isTrue();
}
@@ -153,7 +153,7 @@ void isCommandCompletedWithFailure() {
Optional commandCompleted = blockchainAdapterService
.isCommandCompleted(blockchainAdapterClient::getStatusForInitializeTaskRequest,
CHAIN_TASK_ID, PERIOD, MAX_ATTEMPTS);
- Assertions.assertThat(commandCompleted.isPresent()).isTrue();
+ Assertions.assertThat(commandCompleted).isPresent();
Assertions.assertThat(commandCompleted.get()).isFalse();
}
@@ -170,7 +170,7 @@ void isCommandCompletedWithMaxAttempts() {
// region getPublicChainConfig
@Test
void shouldGetPublicChainConfigOnlyOnce() {
- final PublicChainConfig expectedChainConfig = new PublicChainConfig();
+ final PublicChainConfig expectedChainConfig = PublicChainConfig.builder().build();
when(blockchainAdapterClient.getPublicChainConfig())
.thenReturn(expectedChainConfig);
diff --git a/src/test/java/com/iexec/core/configuration/ConfigurationRepositoryMigrationTest.java b/src/test/java/com/iexec/core/configuration/ConfigurationRepositoryMigrationTest.java
index f31dad808..d8ac5ee0f 100644
--- a/src/test/java/com/iexec/core/configuration/ConfigurationRepositoryMigrationTest.java
+++ b/src/test/java/com/iexec/core/configuration/ConfigurationRepositoryMigrationTest.java
@@ -21,18 +21,26 @@
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.Assertions;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
class ConfigurationRepositoryMigrationTest {
+ @Mock
+ private MongoCollection collection;
+
+ @Mock
+ private MongoDatabase db;
+
+ @Mock
+ private FindIterable findIterable;
+
@Mock
private MongockTemplate mongockTemplate;
@@ -58,11 +66,8 @@ void shouldMoveFromReplayField() {
}
private void mockFindFirstConfiguration(Document document) {
- MongoDatabase db = mock(MongoDatabase.class);
when(mongockTemplate.getDb()).thenReturn(db);
- MongoCollection collection = mock(MongoCollection.class);
when(db.getCollection(anyString())).thenReturn(collection);
- FindIterable findIterable = mock(FindIterable.class);
when(collection.find()).thenReturn(findIterable);
when(findIterable.first()).thenReturn(document);
}
diff --git a/src/test/java/com/iexec/core/configuration/PublicConfigurationServiceTests.java b/src/test/java/com/iexec/core/configuration/PublicConfigurationServiceTests.java
index 06985be83..349da0706 100644
--- a/src/test/java/com/iexec/core/configuration/PublicConfigurationServiceTests.java
+++ b/src/test/java/com/iexec/core/configuration/PublicConfigurationServiceTests.java
@@ -26,8 +26,6 @@
import org.mockito.MockitoAnnotations;
import org.web3j.crypto.Credentials;
-import java.security.NoSuchAlgorithmException;
-
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
@@ -43,8 +41,6 @@ class PublicConfigurationServiceTests {
@Mock
private ResultRepositoryConfiguration resultRepoConfig;
@Mock
- private SmsConfiguration smsConfiguration;
- @Mock
private BlockchainAdapterClientConfig blockchainAdapterClientConfig;
@InjectMocks
@@ -58,7 +54,7 @@ void init() {
// region getPublicConfiguration
@Test
- void shouldGetPublicConfiguration() throws NoSuchAlgorithmException {
+ void shouldGetPublicConfiguration() {
// This would be done by Spring in production
publicConfigurationService.buildPublicConfiguration();
@@ -73,7 +69,7 @@ void shouldNotGetPublicConfigurationWhenNotInitialized() {
// region getPublicConfiguration
@Test
- void shouldGetPublicConfigurationHash() throws NoSuchAlgorithmException {
+ void shouldGetPublicConfigurationHash() {
// This would be done by Spring in production
publicConfigurationService.buildPublicConfiguration();
diff --git a/src/test/java/com/iexec/core/configuration/PurgeConfigurationTests.java b/src/test/java/com/iexec/core/configuration/PurgeConfigurationTests.java
new file mode 100644
index 000000000..48efede64
--- /dev/null
+++ b/src/test/java/com/iexec/core/configuration/PurgeConfigurationTests.java
@@ -0,0 +1,25 @@
+package com.iexec.core.configuration;
+
+import com.iexec.common.lifecycle.purge.PurgeService;
+import com.iexec.common.lifecycle.purge.Purgeable;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.*;
+import static org.mockito.Mockito.mock;
+
+class PurgeConfigurationTests {
+ final PurgeConfiguration purgeConfiguration = new PurgeConfiguration();
+
+ @Test
+ void createPurgeService() {
+ final List purgeables = List.of(
+ mock(Purgeable.class),
+ mock(Purgeable.class),
+ mock(Purgeable.class)
+ );
+ final PurgeService purgeService = purgeConfiguration.purgeService(purgeables);
+ assertNotNull(purgeService);
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/iexec/core/contribution/ContributionHelperTests.java b/src/test/java/com/iexec/core/contribution/ContributionHelperTests.java
index 96919d0a9..d052da821 100644
--- a/src/test/java/com/iexec/core/contribution/ContributionHelperTests.java
+++ b/src/test/java/com/iexec/core/contribution/ContributionHelperTests.java
@@ -38,17 +38,17 @@ class ContributionHelperTests {
@Test
void shouldGetContributedWeight() {
Replicate replicate1 = mock(Replicate.class);
- when(replicate1.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CONTRIBUTED));
+ when(replicate1.getLastRelevantStatus()).thenReturn(ReplicateStatus.CONTRIBUTED);
when(replicate1.getContributionHash()).thenReturn(A);
when(replicate1.getWorkerWeight()).thenReturn(3);
Replicate replicate2 = mock(Replicate.class);
- when(replicate2.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CONTRIBUTED));
+ when(replicate2.getLastRelevantStatus()).thenReturn(ReplicateStatus.CONTRIBUTED);
when(replicate2.getContributionHash()).thenReturn(A);
when(replicate2.getWorkerWeight()).thenReturn(5);
Replicate replicate3 = mock(Replicate.class);
- when(replicate3.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CONTRIBUTED));
+ when(replicate3.getLastRelevantStatus()).thenReturn(ReplicateStatus.CONTRIBUTED);
when(replicate3.getContributionHash()).thenReturn(B);
when(replicate3.getWorkerWeight()).thenReturn(10);
@@ -61,7 +61,7 @@ void shouldGetContributedWeight() {
@Test
void shouldNotGetContributedWeightSinceNoContribution() {
Replicate replicate1 = mock(Replicate.class);
- when(replicate1.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CONTRIBUTED));
+ when(replicate1.getLastRelevantStatus()).thenReturn(ReplicateStatus.CONTRIBUTED);
when(replicate1.getContributionHash()).thenReturn("");
when(replicate1.getWorkerWeight()).thenReturn(3);
@@ -73,7 +73,7 @@ void shouldNotGetContributedWeightSinceNoContribution() {
@Test
void shouldNotGetContributedWeightSinceNoWeight() {
Replicate replicate1 = mock(Replicate.class);
- when(replicate1.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CONTRIBUTED));
+ when(replicate1.getLastRelevantStatus()).thenReturn(ReplicateStatus.CONTRIBUTED);
when(replicate1.getContributionHash()).thenReturn(A);
when(replicate1.getWorkerWeight()).thenReturn(0);
@@ -85,7 +85,7 @@ void shouldNotGetContributedWeightSinceNoWeight() {
@Test
void shouldNotGetContributedWeightSinceNoTContributed() {
Replicate replicate1 = mock(Replicate.class);
- when(replicate1.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CONTRIBUTING));
+ when(replicate1.getLastRelevantStatus()).thenReturn(ReplicateStatus.CONTRIBUTING);
when(replicate1.getContributionHash()).thenReturn(A);
when(replicate1.getWorkerWeight()).thenReturn(3);
@@ -98,12 +98,12 @@ void shouldNotGetContributedWeightSinceNoTContributed() {
void shouldGetPendingWeight() {
Replicate replicate1 = mock(Replicate.class);
when(replicate1.isCreatedMoreThanNPeriodsAgo(anyInt(), anyLong())).thenReturn(false);
- when(replicate1.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CREATED));
+ when(replicate1.getLastRelevantStatus()).thenReturn(ReplicateStatus.CREATED);
when(replicate1.getWorkerWeight()).thenReturn(3);
Replicate replicate2 = mock(Replicate.class);
when(replicate2.isCreatedMoreThanNPeriodsAgo(anyInt(), anyLong())).thenReturn(false);
- when(replicate2.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CREATED));
+ when(replicate2.getLastRelevantStatus()).thenReturn(ReplicateStatus.CREATED);
when(replicate2.getWorkerWeight()).thenReturn(5);
List replicates = Arrays.asList(replicate1, replicate2);
@@ -115,7 +115,7 @@ void shouldGetPendingWeight() {
void shouldCount0PendingWeightSinceContributed() {
Replicate replicate1 = mock(Replicate.class);
when(replicate1.isCreatedMoreThanNPeriodsAgo(anyInt(), anyLong())).thenReturn(false);
- when(replicate1.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CONTRIBUTED));
+ when(replicate1.getLastRelevantStatus()).thenReturn(ReplicateStatus.CONTRIBUTED);
when(replicate1.getWorkerWeight()).thenReturn(3);
List replicates = Collections.singletonList(replicate1);
@@ -127,12 +127,12 @@ void shouldCount0PendingWeightSinceContributed() {
void shouldCountOnlyPendingWeightForOneSinceOtherFailed() {
Replicate replicate1 = mock(Replicate.class);
when(replicate1.isCreatedMoreThanNPeriodsAgo(anyInt(), anyLong())).thenReturn(false);
- when(replicate1.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CREATED));
+ when(replicate1.getLastRelevantStatus()).thenReturn(ReplicateStatus.CREATED);
when(replicate1.getWorkerWeight()).thenReturn(3);
Replicate replicate2 = mock(Replicate.class);
when(replicate2.isCreatedMoreThanNPeriodsAgo(anyInt(), anyLong())).thenReturn(false);
- when(replicate2.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.FAILED));
+ when(replicate2.getLastRelevantStatus()).thenReturn(ReplicateStatus.FAILED);
when(replicate2.getWorkerWeight()).thenReturn(5);
List replicates = Arrays.asList(replicate1, replicate2);
@@ -144,12 +144,12 @@ void shouldCountOnlyPendingWeightForOneSinceOtherFailed() {
void shouldCountOnlyPendingWeightForOneSinceOtherContributed() {
Replicate replicate1 = mock(Replicate.class);
when(replicate1.isCreatedMoreThanNPeriodsAgo(anyInt(), anyLong())).thenReturn(false);
- when(replicate1.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CREATED));
+ when(replicate1.getLastRelevantStatus()).thenReturn(ReplicateStatus.CREATED);
when(replicate1.getWorkerWeight()).thenReturn(3);
Replicate replicate2 = mock(Replicate.class);
when(replicate2.isCreatedMoreThanNPeriodsAgo(anyInt(), anyLong())).thenReturn(false);
- when(replicate2.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CONTRIBUTED));
+ when(replicate2.getLastRelevantStatus()).thenReturn(ReplicateStatus.CONTRIBUTED);
when(replicate2.getWorkerWeight()).thenReturn(5);
List replicates = Arrays.asList(replicate1, replicate2);
@@ -161,12 +161,12 @@ void shouldCountOnlyPendingWeightForOneSinceOtherContributed() {
void shouldCountOnlyPendingWeightForOneSinceOtherVeryOld() {
Replicate replicate1 = mock(Replicate.class);
when(replicate1.isCreatedMoreThanNPeriodsAgo(anyInt(), anyLong())).thenReturn(false);
- when(replicate1.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CREATED));
+ when(replicate1.getLastRelevantStatus()).thenReturn(ReplicateStatus.CREATED);
when(replicate1.getWorkerWeight()).thenReturn(3);
Replicate replicate2 = mock(Replicate.class);
when(replicate2.isCreatedMoreThanNPeriodsAgo(anyInt(), anyLong())).thenReturn(true);
- when(replicate2.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CREATED));
+ when(replicate2.getLastRelevantStatus()).thenReturn(ReplicateStatus.CREATED);
when(replicate2.getWorkerWeight()).thenReturn(5);
List replicates = Arrays.asList(replicate1, replicate2);
@@ -178,12 +178,12 @@ void shouldCountOnlyPendingWeightForOneSinceOtherVeryOld() {
void shouldCountOnlyPendingWeightForOneSinceOtherNoWeight() {
Replicate replicate1 = mock(Replicate.class);
when(replicate1.isCreatedMoreThanNPeriodsAgo(anyInt(), anyLong())).thenReturn(false);
- when(replicate1.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CREATED));
+ when(replicate1.getLastRelevantStatus()).thenReturn(ReplicateStatus.CREATED);
when(replicate1.getWorkerWeight()).thenReturn(3);
Replicate replicate2 = mock(Replicate.class);
when(replicate2.isCreatedMoreThanNPeriodsAgo(anyInt(), anyLong())).thenReturn(false);
- when(replicate2.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CREATED));
+ when(replicate2.getLastRelevantStatus()).thenReturn(ReplicateStatus.CREATED);
when(replicate2.getWorkerWeight()).thenReturn(0);
List replicates = Arrays.asList(replicate1, replicate2);
@@ -194,17 +194,17 @@ void shouldCountOnlyPendingWeightForOneSinceOtherNoWeight() {
@Test
void shouldGetDistinctContributions() {
Replicate replicate1 = mock(Replicate.class);
- when(replicate1.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CONTRIBUTED));
+ when(replicate1.getLastRelevantStatus()).thenReturn(ReplicateStatus.CONTRIBUTED);
when(replicate1.getContributionHash()).thenReturn(A);
when(replicate1.getWorkerWeight()).thenReturn(3);
Replicate replicate2 = mock(Replicate.class);
- when(replicate2.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CONTRIBUTED));
+ when(replicate2.getLastRelevantStatus()).thenReturn(ReplicateStatus.CONTRIBUTED);
when(replicate2.getContributionHash()).thenReturn(A);
when(replicate2.getWorkerWeight()).thenReturn(5);
Replicate replicate3 = mock(Replicate.class);
- when(replicate3.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CONTRIBUTED));
+ when(replicate3.getLastRelevantStatus()).thenReturn(ReplicateStatus.CONTRIBUTED);
when(replicate3.getContributionHash()).thenReturn(B);
when(replicate3.getWorkerWeight()).thenReturn(10);
@@ -217,7 +217,7 @@ void shouldGetDistinctContributions() {
@Test
void shouldNotGetDistinctContributionsSinceNotContributed() {
Replicate replicate1 = mock(Replicate.class);
- when(replicate1.getLastRelevantStatus()).thenReturn(Optional.of(ReplicateStatus.CREATED));
+ when(replicate1.getLastRelevantStatus()).thenReturn(ReplicateStatus.CREATED);
List replicates = Collections.singletonList(replicate1);
diff --git a/src/test/java/com/iexec/core/detector/task/FinalDeadlineTaskDetectorTests.java b/src/test/java/com/iexec/core/detector/task/FinalDeadlineTaskDetectorTests.java
index e45f5ffce..ee19afa7f 100644
--- a/src/test/java/com/iexec/core/detector/task/FinalDeadlineTaskDetectorTests.java
+++ b/src/test/java/com/iexec/core/detector/task/FinalDeadlineTaskDetectorTests.java
@@ -38,8 +38,6 @@
class FinalDeadlineTaskDetectorTests {
- private final static String CHAIN_TASK_ID = "chainTaskId";
-
@Mock
private TaskService taskService;
diff --git a/src/test/java/com/iexec/core/registry/PlatformRegistryConfigurationTests.java b/src/test/java/com/iexec/core/registry/PlatformRegistryConfigurationTests.java
new file mode 100644
index 000000000..4945aaa6c
--- /dev/null
+++ b/src/test/java/com/iexec/core/registry/PlatformRegistryConfigurationTests.java
@@ -0,0 +1,30 @@
+package com.iexec.core.registry;
+
+import org.assertj.core.api.Assertions;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+@ExtendWith(SpringExtension.class)
+@ContextConfiguration(classes = PlatformRegistryConfiguration.class)
+@TestPropertySource(properties = {
+ "sms.scone=http://scone-sms",
+ "sms.gramine=http://gramine-sms"
+ })
+class PlatformRegistryConfigurationTests {
+
+ @Autowired
+ PlatformRegistryConfiguration platformRegistryConfiguration;
+
+ @Test
+ void shouldGetValues() {
+ Assertions.assertThat(platformRegistryConfiguration.getSconeSms())
+ .isEqualTo("http://scone-sms");
+ Assertions.assertThat(platformRegistryConfiguration.getGramineSms())
+ .isEqualTo("http://gramine-sms");
+ }
+
+}
diff --git a/src/test/java/com/iexec/core/replicate/ReplicateControllerTests.java b/src/test/java/com/iexec/core/replicate/ReplicateControllerTests.java
index 34f3a0fe7..1644b51a0 100644
--- a/src/test/java/com/iexec/core/replicate/ReplicateControllerTests.java
+++ b/src/test/java/com/iexec/core/replicate/ReplicateControllerTests.java
@@ -24,12 +24,17 @@ class ReplicateControllerTests {
private static final String CHAIN_TASK_ID = "chainTaskId";
private static final String WALLET_ADDRESS = "walletAddress";
+ private static final String SMS_URL = "smsUrl";
private static final String TOKEN = "token";
private static final int BLOCK_NUMBER = 1;
private static final WorkerpoolAuthorization AUTH = WorkerpoolAuthorization.builder()
.chainTaskId(CHAIN_TASK_ID)
.workerWallet(WALLET_ADDRESS)
.build();
+ private static final ReplicateTaskSummary REPLICATE_TASK_SUMMARY = ReplicateTaskSummary.builder()
+ .workerpoolAuthorization(AUTH)
+ .smsUrl(SMS_URL)
+ .build();
private static final ReplicateStatusUpdate UPDATE = ReplicateStatusUpdate.builder()
.status(ReplicateStatus.STARTED)
.build();
@@ -63,15 +68,15 @@ void shouldGetAvailableReplicate() {
when(workerService.isWorkerAllowedToAskReplicate(WALLET_ADDRESS))
.thenReturn(true);
when(replicateSupplyService
- .getAuthOfAvailableReplicate(BLOCK_NUMBER, WALLET_ADDRESS))
- .thenReturn(Optional.of(AUTH));
+ .getAvailableReplicateTaskSummary(BLOCK_NUMBER, WALLET_ADDRESS))
+ .thenReturn(Optional.of(REPLICATE_TASK_SUMMARY));
- ResponseEntity response =
- replicatesController.getAvailableReplicate(BLOCK_NUMBER, TOKEN);
+ ResponseEntity replicateTaskSummaryResponse =
+ replicatesController.getAvailableReplicateTaskSummary(BLOCK_NUMBER, TOKEN);
- assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
- WorkerpoolAuthorization auth = response.getBody();
- assertThat(auth.getChainTaskId()).isEqualTo(CHAIN_TASK_ID);
+ assertThat(replicateTaskSummaryResponse.getStatusCode()).isEqualTo(HttpStatus.OK);
+ ReplicateTaskSummary replicateTaskSummary = replicateTaskSummaryResponse.getBody();
+ assertThat(replicateTaskSummary.getWorkerpoolAuthorization().getChainTaskId()).isEqualTo(CHAIN_TASK_ID);
}
@Test
@@ -79,10 +84,10 @@ void shouldNotGetAvailableReplicateSinceNotAuthorizedToken() {
when(jwtTokenProvider.getWalletAddressFromBearerToken(TOKEN))
.thenReturn("");
- ResponseEntity response =
- replicatesController.getAvailableReplicate(BLOCK_NUMBER, TOKEN);
+ ResponseEntity replicateTaskSummaryResponse =
+ replicatesController.getAvailableReplicateTaskSummary(BLOCK_NUMBER, TOKEN);
- assertThat(response.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
+ assertThat(replicateTaskSummaryResponse.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
}
@Test
@@ -92,10 +97,10 @@ void shouldNotGetAvailableReplicateSinceNotAllowed() {
when(workerService.isWorkerAllowedToAskReplicate(WALLET_ADDRESS))
.thenReturn(false);
- ResponseEntity response =
- replicatesController.getAvailableReplicate(BLOCK_NUMBER, TOKEN);
+ ResponseEntity replicateTaskSummaryResponse =
+ replicatesController.getAvailableReplicateTaskSummary(BLOCK_NUMBER, TOKEN);
- assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT);
+ assertThat(replicateTaskSummaryResponse.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT);
}
@Test
@@ -105,13 +110,13 @@ void shouldNotGetAvailableReplicateSinceNoReplicateAvailable() {
when(workerService.isWorkerAllowedToAskReplicate(WALLET_ADDRESS))
.thenReturn(true);
when(replicateSupplyService
- .getAuthOfAvailableReplicate(BLOCK_NUMBER, WALLET_ADDRESS))
+ .getAvailableReplicateTaskSummary(BLOCK_NUMBER, WALLET_ADDRESS))
.thenReturn(Optional.empty());
- ResponseEntity response =
- replicatesController.getAvailableReplicate(BLOCK_NUMBER, TOKEN);
+ ResponseEntity replicateTaskSummaryResponse =
+ replicatesController.getAvailableReplicateTaskSummary(BLOCK_NUMBER, TOKEN);
- assertThat(response.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT);
+ assertThat(replicateTaskSummaryResponse.getStatusCode()).isEqualTo(HttpStatus.NO_CONTENT);
}
//endregion
@@ -164,7 +169,6 @@ void shouldGetEmptyMissedNotifications() {
//endregion
//region update replicate
-
@Test
void shouldUpdateReplicate() {
when(jwtTokenProvider.getWalletAddressFromBearerToken(TOKEN))
@@ -220,6 +224,7 @@ void shouldNotUpdateReplicateSinceUnauthorized() {
replicatesController.updateReplicateStatus(TOKEN, CHAIN_TASK_ID, UPDATE);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
+ assertThat(response.getBody()).isNull();
}
@Test
@@ -235,6 +240,7 @@ void shouldNotUpdateReplicateSinceForbidden() {
replicatesController.updateReplicateStatus(TOKEN, CHAIN_TASK_ID, UPDATE);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.FORBIDDEN);
+ assertThat(response.getBody()).isEqualTo(TaskNotificationType.PLEASE_ABORT);
}
@Test
diff --git a/src/test/java/com/iexec/core/replicate/ReplicateServiceTests.java b/src/test/java/com/iexec/core/replicate/ReplicateServiceTests.java
index e13bcc3ac..58115905a 100644
--- a/src/test/java/com/iexec/core/replicate/ReplicateServiceTests.java
+++ b/src/test/java/com/iexec/core/replicate/ReplicateServiceTests.java
@@ -140,7 +140,7 @@ void shouldGetReplicates() {
when(replicatesRepository.findByChainTaskId(CHAIN_TASK_ID)).thenReturn(Optional.of(replicatesList));
assertThat(replicatesService.getReplicates(CHAIN_TASK_ID)).isNotNull();
- assertThat(replicatesService.getReplicates(CHAIN_TASK_ID).size()).isEqualTo(1);
+ assertThat(replicatesService.getReplicates(CHAIN_TASK_ID)).hasSize(1);
}
@Test
@@ -167,7 +167,7 @@ void shouldGetReplicate() {
@Test
void shouldNotGetReplicate1() {
when(replicatesRepository.findByChainTaskId(CHAIN_TASK_ID)).thenReturn(Optional.empty());
- assertThat(replicatesService.getReplicate(CHAIN_TASK_ID, WALLET_WORKER_1)).isEqualTo(Optional.empty());
+ assertThat(replicatesService.getReplicate(CHAIN_TASK_ID, WALLET_WORKER_1)).isEmpty();
}
@Test
@@ -181,7 +181,7 @@ void shouldNotGetReplicate2() {
ReplicatesList replicatesList = new ReplicatesList(CHAIN_TASK_ID, Arrays.asList(replicate1, replicate2));
when(replicatesRepository.findByChainTaskId(CHAIN_TASK_ID)).thenReturn(Optional.of(replicatesList));
- assertThat(replicatesService.getReplicate(CHAIN_TASK_ID, WALLET_WORKER_3)).isEqualTo(Optional.empty());
+ assertThat(replicatesService.getReplicate(CHAIN_TASK_ID, WALLET_WORKER_3)).isEmpty();
}
@Test
@@ -200,7 +200,7 @@ void shouldGetCorrectNbReplicatesWithOneStatus() {
assertThat(replicatesService.getNbReplicatesWithCurrentStatus(CHAIN_TASK_ID, STARTING)).isEqualTo(2);
assertThat(replicatesService.getNbReplicatesWithCurrentStatus(CHAIN_TASK_ID, COMPUTED)).isEqualTo(1);
- assertThat(replicatesService.getNbReplicatesWithCurrentStatus(CHAIN_TASK_ID, CONTRIBUTED)).isEqualTo(0);
+ assertThat(replicatesService.getNbReplicatesWithCurrentStatus(CHAIN_TASK_ID, CONTRIBUTED)).isZero();
}
@Test
@@ -252,7 +252,7 @@ void shouldGetCorrectNbReplicatesWithOneLastRelevantStatus() {
assertThat(replicatesService.getNbReplicatesWithLastRelevantStatus(CHAIN_TASK_ID, STARTING)).isEqualTo(3);
assertThat(replicatesService.getNbReplicatesWithLastRelevantStatus(CHAIN_TASK_ID, COMPUTED)).isEqualTo(1);
- assertThat(replicatesService.getNbReplicatesWithLastRelevantStatus(CHAIN_TASK_ID, CONTRIBUTED)).isEqualTo(0);
+ assertThat(replicatesService.getNbReplicatesWithLastRelevantStatus(CHAIN_TASK_ID, CONTRIBUTED)).isZero();
}
@Test
@@ -304,7 +304,7 @@ void shouldGetCorrectNbReplicatesContainingOneStatus() {
assertThat(replicatesService.getNbReplicatesContainingStatus(CHAIN_TASK_ID, STARTING)).isEqualTo(3);
assertThat(replicatesService.getNbReplicatesContainingStatus(CHAIN_TASK_ID, COMPUTED)).isEqualTo(1);
- assertThat(replicatesService.getNbReplicatesContainingStatus(CHAIN_TASK_ID, CONTRIBUTED)).isEqualTo(0);
+ assertThat(replicatesService.getNbReplicatesContainingStatus(CHAIN_TASK_ID, CONTRIBUTED)).isZero();
}
@Test
@@ -333,7 +333,7 @@ void shouldGetCorrectNbReplicatesContainingMultipleStatus() {
int shouldBe0 = replicatesService.getNbReplicatesContainingStatus(CHAIN_TASK_ID, COMPLETED, FAILED,
RESULT_UPLOADING);
- assertThat(shouldBe0).isEqualTo(0);
+ assertThat(shouldBe0).isZero();
}
@Test
@@ -354,8 +354,7 @@ void shouldGetReplicateWithRevealStatus() {
when(replicatesRepository.findByChainTaskId(CHAIN_TASK_ID)).thenReturn(Optional.of(replicatesList));
Optional optional = replicatesService.getRandomReplicateWithRevealStatus(CHAIN_TASK_ID);
- assertThat(optional.isPresent()).isTrue();
- assertThat(optional).isEqualTo(Optional.of(replicate));
+ assertThat(optional).contains(replicate);
}
@Test
@@ -363,7 +362,7 @@ void shouldNotGetReplicateWithRevealStatusSinceEmptyReplicatesList() {
when(replicatesRepository.findByChainTaskId(CHAIN_TASK_ID)).thenReturn(Optional.empty());
Optional optional = replicatesService.getRandomReplicateWithRevealStatus(CHAIN_TASK_ID);
- assertThat(optional.isPresent()).isFalse();
+ assertThat(optional).isEmpty();
}
@Test
@@ -383,7 +382,7 @@ void shouldNotGetReplicateWithRevealStatusWithNonEmptyList() {
when(replicatesRepository.findByChainTaskId(CHAIN_TASK_ID)).thenReturn(Optional.of(replicatesList));
Optional optional = replicatesService.getRandomReplicateWithRevealStatus(CHAIN_TASK_ID);
- assertThat(optional.isPresent()).isFalse();
+ assertThat(optional).isEmpty();
}
@Test
@@ -629,8 +628,7 @@ void shouldNotUpdateReplicateStatusSinceAlreadyReported() {
.build();
final Optional result = replicatesService.updateReplicateStatus(CHAIN_TASK_ID, WALLET_WORKER_1, statusUpdate);
- assertThat(result)
- .isEqualTo(Optional.empty());
+ assertThat(result).isEmpty();
}
@Test
diff --git a/src/test/java/com/iexec/core/replicate/ReplicateSupplyServiceTests.java b/src/test/java/com/iexec/core/replicate/ReplicateSupplyServiceTests.java
index 17655ddd7..208ab1358 100644
--- a/src/test/java/com/iexec/core/replicate/ReplicateSupplyServiceTests.java
+++ b/src/test/java/com/iexec/core/replicate/ReplicateSupplyServiceTests.java
@@ -20,11 +20,9 @@
import com.iexec.common.notification.TaskNotification;
import com.iexec.common.notification.TaskNotificationExtra;
import com.iexec.common.notification.TaskNotificationType;
-import com.iexec.common.replicate.ReplicateStatus;
-import com.iexec.common.replicate.ReplicateStatusDetails;
-import com.iexec.common.replicate.ReplicateStatusModifier;
-import com.iexec.common.replicate.ReplicateStatusUpdate;
+import com.iexec.common.replicate.*;
import com.iexec.common.task.TaskAbortCause;
+import com.iexec.common.tee.TeeUtils;
import com.iexec.common.utils.BytesUtils;
import com.iexec.common.utils.DateTimeUtils;
import com.iexec.core.chain.SignatureService;
@@ -35,10 +33,10 @@
import com.iexec.core.task.update.TaskUpdateRequestManager;
import com.iexec.core.worker.Worker;
import com.iexec.core.worker.WorkerService;
-import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.*;
+import org.springframework.test.util.ReflectionTestUtils;
import java.util.*;
import java.util.concurrent.CompletableFuture;
@@ -49,12 +47,12 @@
import static com.iexec.common.replicate.ReplicateStatus.*;
import static com.iexec.core.task.TaskStatus.RUNNING;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
-@Slf4j
class ReplicateSupplyServiceTests {
private final static String WALLET_WORKER_1 = "0x1a69b2eb604db8eba185df03ea4f5288dcbbd248";
@@ -66,7 +64,7 @@ class ReplicateSupplyServiceTests {
private final static String DAPP_NAME = "dappName";
private final static String COMMAND_LINE = "commandLine";
private final static String NO_TEE_TAG = BytesUtils.EMPTY_HEX_STRING_32;
- private final static String TEE_TAG = "0x0000000000000000000000000000000000000000000000000000000000000001";
+ private final static String TEE_TAG = TeeUtils.TEE_SCONE_ONLY_TAG; //any supported TEE tag
private final static String ENCLAVE_CHALLENGE = "dummyEnclave";
private final static long maxExecutionTime = 60000;
long workerLastBlock = 12;
@@ -100,18 +98,18 @@ void workerCanWorkAndHasGas(String workerAddress) {
@Test
void shouldNotGetAnyReplicateSinceWorkerDoesNotExist() {
when(workerService.getWorker(Mockito.anyString())).thenReturn(Optional.empty());
- Optional oAuthorization =
- replicateSupplyService.getAuthOfAvailableReplicate(workerLastBlock, WALLET_WORKER_1);
- assertThat(oAuthorization).isEmpty();
+ Optional replicateTaskSummary =
+ replicateSupplyService.getAvailableReplicateTaskSummary(workerLastBlock, WALLET_WORKER_1);
+ assertThat(replicateTaskSummary).isEmpty();
Mockito.verifyNoInteractions(web3jService, taskService, taskUpdateRequestManager, replicatesService, signatureService);
}
@Test
void shouldNotGetReplicateSinceWorkerLastBlockNotAvailable() {
workerCanWorkAndHasGas(WALLET_WORKER_1);
- Optional oAuthorization =
- replicateSupplyService.getAuthOfAvailableReplicate(0, WALLET_WORKER_1);
- assertThat(oAuthorization).isEmpty();
+ Optional replicateTaskSummary =
+ replicateSupplyService.getAvailableReplicateTaskSummary(0, WALLET_WORKER_1);
+ assertThat(replicateTaskSummary).isEmpty();
Mockito.verifyNoInteractions(web3jService, taskService, taskUpdateRequestManager, replicatesService, signatureService);
}
@@ -119,9 +117,9 @@ void shouldNotGetReplicateSinceWorkerLastBlockNotAvailable() {
void shouldNotGetReplicateSinceNoRunningTask() {
workerCanWorkAndHasGas(WALLET_WORKER_1);
when(taskService.getPrioritizedInitializedOrRunningTask(false, Collections.emptyList())).thenReturn(Optional.empty());
- Optional oAuthorization =
- replicateSupplyService.getAuthOfAvailableReplicate(workerLastBlock, WALLET_WORKER_1);
- assertThat(oAuthorization).isEmpty();
+ Optional replicateTaskSummary =
+ replicateSupplyService.getAvailableReplicateTaskSummary(workerLastBlock, WALLET_WORKER_1);
+ assertThat(replicateTaskSummary).isEmpty();
Mockito.verify(taskService, Mockito.never()).getTaskByChainTaskId(CHAIN_TASK_ID);
Mockito.verifyNoInteractions(taskUpdateRequestManager, replicatesService, signatureService);
}
@@ -149,9 +147,9 @@ void shouldNotGetReplicateSinceNoReplicatesList() {
when(workerService.getWorker(WALLET_WORKER_2)).thenReturn(Optional.of(worker));
when(replicatesService.getReplicatesList(CHAIN_TASK_ID)).thenReturn(Optional.empty());
- Optional oAuthorization =
- replicateSupplyService.getAuthOfAvailableReplicate(workerLastBlock, WALLET_WORKER_2);
- assertThat(oAuthorization).isEmpty();
+ Optional replicateTaskSummary =
+ replicateSupplyService.getAvailableReplicateTaskSummary(workerLastBlock, WALLET_WORKER_2);
+ assertThat(replicateTaskSummary).isEmpty();
Mockito.verify(taskService, Mockito.never()).isConsensusReached(any());
Mockito.verifyNoInteractions(signatureService);
assertTaskAccessForNewReplicateLockNeverUsed(CHAIN_TASK_ID);
@@ -188,10 +186,10 @@ void shouldNotGetReplicateSinceConsensusReachedOnChain() {
when(taskService.isConsensusReached(replicatesList)).thenReturn(true);
when(replicatesList.hasWorkerAlreadyParticipated(WALLET_WORKER_2)).thenReturn(false);
- Optional oAuthorization =
- replicateSupplyService.getAuthOfAvailableReplicate(workerLastBlock, WALLET_WORKER_2);
+ Optional replicateTaskSummary =
+ replicateSupplyService.getAvailableReplicateTaskSummary(workerLastBlock, WALLET_WORKER_2);
- assertThat(oAuthorization).isEmpty();
+ assertThat(replicateTaskSummary).isEmpty();
Mockito.verify(taskService).isConsensusReached(replicatesList);
Mockito.verifyNoInteractions(signatureService);
@@ -201,9 +199,9 @@ void shouldNotGetReplicateSinceConsensusReachedOnChain() {
@Test
void shouldNotGetAnyReplicateSinceWorkerIsFull() {
when(workerService.canAcceptMoreWorks(WALLET_WORKER_1)).thenReturn(false);
- Optional oAuthorization =
- replicateSupplyService.getAuthOfAvailableReplicate(workerLastBlock, WALLET_WORKER_1);
- assertThat(oAuthorization).isEmpty();
+ Optional replicateTaskSummary =
+ replicateSupplyService.getAvailableReplicateTaskSummary(workerLastBlock, WALLET_WORKER_1);
+ assertThat(replicateTaskSummary).isEmpty();
Mockito.verifyNoInteractions(taskService, taskUpdateRequestManager, replicatesService, signatureService);
}
@@ -211,9 +209,9 @@ void shouldNotGetAnyReplicateSinceWorkerIsFull() {
void shouldNotGetAnyReplicateSinceWorkerDoesNotHaveEnoughGas() {
when(workerService.canAcceptMoreWorks(WALLET_WORKER_1)).thenReturn(true);
when(web3jService.hasEnoughGas(WALLET_WORKER_1)).thenReturn(false);
- Optional oAuthorization =
- replicateSupplyService.getAuthOfAvailableReplicate(workerLastBlock, WALLET_WORKER_1);
- assertThat(oAuthorization).isEmpty();
+ Optional replicateTaskSummary =
+ replicateSupplyService.getAvailableReplicateTaskSummary(workerLastBlock, WALLET_WORKER_1);
+ assertThat(replicateTaskSummary).isEmpty();
Mockito.verify(web3jService).hasEnoughGas(WALLET_WORKER_1);
Mockito.verifyNoInteractions(taskService, taskUpdateRequestManager, replicatesService, signatureService);
}
@@ -246,10 +244,10 @@ void shouldNotGetAnyReplicateSinceWorkerAlreadyParticipated() {
when(replicatesService.getReplicatesList(CHAIN_TASK_ID)).thenReturn(Optional.of(replicatesList));
when(replicatesList.hasWorkerAlreadyParticipated(WALLET_WORKER_1)).thenReturn(true);
- Optional oAuthorization =
- replicateSupplyService.getAuthOfAvailableReplicate(workerLastBlock, WALLET_WORKER_1);
+ Optional replicateTaskSummary =
+ replicateSupplyService.getAvailableReplicateTaskSummary(workerLastBlock, WALLET_WORKER_1);
- assertThat(oAuthorization).isEmpty();
+ assertThat(replicateTaskSummary).isEmpty();
Mockito.verifyNoInteractions(signatureService);
assertTaskAccessForNewReplicateLockNeverUsed(CHAIN_TASK_ID);
@@ -289,9 +287,9 @@ void shouldNotGetReplicateSinceDoesNotNeedMoreContributionsForConsensus() {
when(workerService.getWorker(WALLET_WORKER_2)).thenReturn(Optional.of(existingWorker));
when(replicatesService.getReplicatesList(CHAIN_TASK_ID)).thenReturn(Optional.of(replicatesList));
when(replicatesList.hasWorkerAlreadyParticipated(WALLET_WORKER_1)).thenReturn(false);
- Optional oAuthorization =
- replicateSupplyService.getAuthOfAvailableReplicate(workerLastBlock, WALLET_WORKER_2);
- assertThat(oAuthorization).isEmpty();
+ Optional replicateTaskSummary =
+ replicateSupplyService.getAvailableReplicateTaskSummary(workerLastBlock, WALLET_WORKER_2);
+ assertThat(replicateTaskSummary).isEmpty();
Mockito.verifyNoInteractions(signatureService);
assertTaskAccessForNewReplicateNotDeadLocking(CHAIN_TASK_ID);
@@ -325,10 +323,10 @@ void shouldNotGetReplicateSinceEnclaveChallengeNeededButNotGenerated() {
when(replicatesService.getReplicatesList(CHAIN_TASK_ID)).thenReturn(Optional.of(replicatesList));
when(replicatesList.hasWorkerAlreadyParticipated(WALLET_WORKER_1)).thenReturn(false);
- Optional oAuthorization =
- replicateSupplyService.getAuthOfAvailableReplicate(workerLastBlock, WALLET_WORKER_1);
+ Optional replicateTaskSummary =
+ replicateSupplyService.getAvailableReplicateTaskSummary(workerLastBlock, WALLET_WORKER_1);
- assertThat(oAuthorization).isEmpty();
+ assertThat(replicateTaskSummary).isEmpty();
Mockito.verify(replicatesService, Mockito.never()).addNewReplicate(CHAIN_TASK_ID, WALLET_WORKER_1);
Mockito.verify(workerService, Mockito.never()).addChainTaskIdToWorker(CHAIN_TASK_ID, WALLET_WORKER_1);
@@ -373,10 +371,10 @@ void shouldGetOnlyOneReplicateSinceOtherOneReachedConsensusDeadline() {
when(signatureService.createAuthorization(WALLET_WORKER_1, CHAIN_TASK_ID, BytesUtils.EMPTY_ADDRESS))
.thenReturn(WorkerpoolAuthorization.builder().chainTaskId(CHAIN_TASK_ID).build());
- final Optional oAuthorization = replicateSupplyService.getAuthOfAvailableReplicate(workerLastBlock, WALLET_WORKER_1);
+ final Optional replicateTaskSummary = replicateSupplyService.getAvailableReplicateTaskSummary(workerLastBlock, WALLET_WORKER_1);
- assertThat(oAuthorization).isPresent();
- assertThat(oAuthorization.get().getChainTaskId()).isEqualTo(CHAIN_TASK_ID);
+ assertThat(replicateTaskSummary).isPresent();
+ assertThat(replicateTaskSummary.get().getWorkerpoolAuthorization().getChainTaskId()).isEqualTo(CHAIN_TASK_ID);
Mockito.verify(replicatesService).addNewReplicate(CHAIN_TASK_ID, WALLET_WORKER_1);
Mockito.verify(workerService).addChainTaskIdToWorker(CHAIN_TASK_ID, WALLET_WORKER_1);
@@ -409,10 +407,10 @@ void shouldNotGetReplicateWhenTaskAlreadyAccessed() {
final Lock lock = replicateSupplyService.taskAccessForNewReplicateLocks.computeIfAbsent(CHAIN_TASK_ID, k -> new ReentrantLock());
CompletableFuture.runAsync(lock::lock).join();
- Optional oAuthorization =
- replicateSupplyService.getAuthOfAvailableReplicate(workerLastBlock, WALLET_WORKER_1);
+ Optional replicateTaskSummary =
+ replicateSupplyService.getAvailableReplicateTaskSummary(workerLastBlock, WALLET_WORKER_1);
- assertThat(oAuthorization).isEmpty();
+ assertThat(replicateTaskSummary).isEmpty();
Mockito.verifyNoInteractions(signatureService);
}
@@ -446,9 +444,9 @@ void shouldGetReplicateWithNoTee() {
.thenReturn(new WorkerpoolAuthorization());
when(replicatesList.hasWorkerAlreadyParticipated(WALLET_WORKER_1)).thenReturn(false);
- Optional oAuthorization =
- replicateSupplyService.getAuthOfAvailableReplicate(workerLastBlock, WALLET_WORKER_1);
- assertThat(oAuthorization).isPresent();
+ Optional replicateTaskSummary =
+ replicateSupplyService.getAvailableReplicateTaskSummary(workerLastBlock, WALLET_WORKER_1);
+ assertThat(replicateTaskSummary).isPresent();
Mockito.verify(replicatesService).addNewReplicate(CHAIN_TASK_ID, WALLET_WORKER_1);
Mockito.verify(workerService).addChainTaskIdToWorker(CHAIN_TASK_ID, WALLET_WORKER_1);
@@ -486,10 +484,10 @@ void shouldGetReplicateWithTee() {
.thenReturn(new WorkerpoolAuthorization());
when(replicatesList.hasWorkerAlreadyParticipated(WALLET_WORKER_1)).thenReturn(false);
- Optional oAuthorization =
- replicateSupplyService.getAuthOfAvailableReplicate(workerLastBlock, WALLET_WORKER_1);
+ Optional replicateTaskSummary =
+ replicateSupplyService.getAvailableReplicateTaskSummary(workerLastBlock, WALLET_WORKER_1);
- assertThat(oAuthorization).isPresent();
+ assertThat(replicateTaskSummary).isPresent();
Mockito.verify(replicatesService).addNewReplicate(CHAIN_TASK_ID, WALLET_WORKER_1);
Mockito.verify(workerService).addChainTaskIdToWorker(CHAIN_TASK_ID, WALLET_WORKER_1);
@@ -517,10 +515,10 @@ void shouldTeeNeededTaskNotBeGivenToTeeDisabledWorker() {
.thenReturn(Optional.empty());
when(workerService.getWorker(WALLET_WORKER_1)).thenReturn(Optional.of(existingWorker));
- Optional oAuthorization =
- replicateSupplyService.getAuthOfAvailableReplicate(workerLastBlock, WALLET_WORKER_1);
+ Optional replicateTaskSummary =
+ replicateSupplyService.getAvailableReplicateTaskSummary(workerLastBlock, WALLET_WORKER_1);
- assertThat(oAuthorization).isEmpty();
+ assertThat(replicateTaskSummary).isEmpty();
Mockito.verifyNoInteractions(signatureService);
assertTaskAccessForNewReplicateLockNeverUsed(CHAIN_TASK_ID);
}
@@ -555,10 +553,10 @@ void shouldTeeNeededTaskBeGivenToTeeEnabledWorker() {
.thenReturn(new WorkerpoolAuthorization());
when(replicatesList.hasWorkerAlreadyParticipated(WALLET_WORKER_1)).thenReturn(false);
- Optional oAuthorization =
- replicateSupplyService.getAuthOfAvailableReplicate(workerLastBlock, WALLET_WORKER_1);
+ Optional replicateTaskSummary =
+ replicateSupplyService.getAvailableReplicateTaskSummary(workerLastBlock, WALLET_WORKER_1);
- assertThat(oAuthorization).isPresent();
+ assertThat(replicateTaskSummary).isPresent();
Mockito.verify(replicatesService).addNewReplicate(CHAIN_TASK_ID, WALLET_WORKER_1);
Mockito.verify(workerService).addChainTaskIdToWorker(CHAIN_TASK_ID, WALLET_WORKER_1);
@@ -1156,6 +1154,59 @@ void shouldNotTellReplicateToWaitForCompletionSinceItDidNotReveal() {
.updateReplicateStatus(CHAIN_TASK_ID, WALLET_WORKER_1, RECOVERING);
}
+ // region purgeTask
+ @Test
+ void shouldPurgeTaskWhenKnownTask() {
+ final Map taskAccessForNewReplicateLocks = new HashMap<>();
+ taskAccessForNewReplicateLocks.put(CHAIN_TASK_ID, new ReentrantLock());
+ ReflectionTestUtils.setField(replicateSupplyService, "taskAccessForNewReplicateLocks", taskAccessForNewReplicateLocks);
+
+ assertTrue(replicateSupplyService.purgeTask(CHAIN_TASK_ID));
+ assertThat(taskAccessForNewReplicateLocks).isEmpty();
+ }
+
+ @Test
+ void shouldPurgeTaskWhenUnknownTask() {
+ final Map taskAccessForNewReplicateLocks = new HashMap<>();
+ taskAccessForNewReplicateLocks.put(CHAIN_TASK_ID_2, new ReentrantLock());
+ ReflectionTestUtils.setField(replicateSupplyService, "taskAccessForNewReplicateLocks", taskAccessForNewReplicateLocks);
+
+ assertTrue(replicateSupplyService.purgeTask(CHAIN_TASK_ID));
+ assertThat(taskAccessForNewReplicateLocks).containsOnlyKeys(CHAIN_TASK_ID_2);
+ }
+
+ @Test
+ void shouldPurgeTaskWhenEmpty() {
+ final Map taskAccessForNewReplicateLocks = new HashMap<>();
+ ReflectionTestUtils.setField(replicateSupplyService, "taskAccessForNewReplicateLocks", taskAccessForNewReplicateLocks);
+
+ assertTrue(replicateSupplyService.purgeTask(CHAIN_TASK_ID));
+ assertThat(taskAccessForNewReplicateLocks).isEmpty();
+ }
+ // endregion
+
+ // region purgeAllTasksData
+ @Test
+ void shouldPurgeAllTasksDataWhenEmpty() {
+ final Map taskAccessForNewReplicateLocks = new HashMap<>();
+ ReflectionTestUtils.setField(replicateSupplyService, "taskAccessForNewReplicateLocks", taskAccessForNewReplicateLocks);
+
+ replicateSupplyService.purgeAllTasksData();
+ assertThat(taskAccessForNewReplicateLocks).isEmpty();
+ }
+
+ @Test
+ void shouldPurgeAllTasksDataWhenFull() {
+ final Map taskAccessForNewReplicateLocks = new HashMap<>();
+ taskAccessForNewReplicateLocks.put(CHAIN_TASK_ID, new ReentrantLock());
+ taskAccessForNewReplicateLocks.put(CHAIN_TASK_ID_2, new ReentrantLock());
+ ReflectionTestUtils.setField(replicateSupplyService, "taskAccessForNewReplicateLocks", taskAccessForNewReplicateLocks);
+
+ replicateSupplyService.purgeAllTasksData();
+ assertThat(taskAccessForNewReplicateLocks).isEmpty();
+ }
+ // endregion
+
List getStubTaskList(TaskStatus status) {
Task task = Task.builder()
.chainTaskId(CHAIN_TASK_ID)
@@ -1166,9 +1217,7 @@ List getStubTaskList(TaskStatus status) {
}
Optional getStubReplicate(ReplicateStatus status) {
- Replicate replicate = new Replicate();
- replicate.setWalletAddress(WALLET_WORKER_1);
- replicate.setChainTaskId(CHAIN_TASK_ID);
+ Replicate replicate = new Replicate(WALLET_WORKER_1, CHAIN_TASK_ID);
replicate.setStatusUpdateList(new ArrayList<>());
replicate.updateStatus(status, ReplicateStatusModifier.WORKER);
return Optional.of(replicate);
diff --git a/src/test/java/com/iexec/core/replicate/ReplicateTests.java b/src/test/java/com/iexec/core/replicate/ReplicateTests.java
index ff999ee65..a2fc7efd1 100644
--- a/src/test/java/com/iexec/core/replicate/ReplicateTests.java
+++ b/src/test/java/com/iexec/core/replicate/ReplicateTests.java
@@ -22,15 +22,23 @@
import com.iexec.common.replicate.ReplicateStatusModifier;
import com.iexec.common.replicate.ReplicateStatusUpdate;
import org.junit.jupiter.api.Test;
+import org.springframework.test.util.ReflectionTestUtils;
import java.util.Collections;
import java.util.Date;
+import java.util.List;
import java.util.concurrent.TimeUnit;
+import static com.iexec.common.replicate.ReplicateStatus.*;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
class ReplicateTests {
+ private static final String WALLET_WORKER = "worker";
+ private static final String CHAIN_TASK_ID = "chainTaskId";
+
+
private final ObjectMapper mapper = new ObjectMapper();
@Test
@@ -59,8 +67,8 @@ void shouldSerializeAndDeserializeReplicate() throws JsonProcessingException {
@Test
void shouldInitializeStatusProperly(){
- Replicate replicate = new Replicate("worker", "taskId");
- assertThat(replicate.getStatusUpdateList().size()).isEqualTo(1);
+ Replicate replicate = new Replicate(WALLET_WORKER, CHAIN_TASK_ID);
+ assertThat(replicate.getStatusUpdateList()).hasSize(1);
ReplicateStatusUpdate statusChange = replicate.getStatusUpdateList().get(0);
assertThat(statusChange.getStatus()).isEqualTo(ReplicateStatus.CREATED);
@@ -73,18 +81,18 @@ void shouldInitializeStatusProperly(){
@Test
void shouldUpdateReplicateStatus(){
- Replicate replicate = new Replicate("worker", "taskId");
- assertThat(replicate.getStatusUpdateList().size()).isEqualTo(1);
+ Replicate replicate = new Replicate(WALLET_WORKER, CHAIN_TASK_ID);
+ assertThat(replicate.getStatusUpdateList()).hasSize(1);
// only pool manager sets date of the update
- replicate.updateStatus(ReplicateStatus.STARTING, ReplicateStatusModifier.POOL_MANAGER);
- assertThat(replicate.getStatusUpdateList().size()).isEqualTo(2);
+ replicate.updateStatus(STARTING, ReplicateStatusModifier.POOL_MANAGER);
+ assertThat(replicate.getStatusUpdateList()).hasSize(2);
ReplicateStatusUpdate initialStatus = replicate.getStatusUpdateList().get(0);
assertThat(initialStatus.getStatus()).isEqualTo(ReplicateStatus.CREATED);
ReplicateStatusUpdate updatedStatus = replicate.getStatusUpdateList().get(1);
- assertThat(updatedStatus.getStatus()).isEqualTo(ReplicateStatus.STARTING);
+ assertThat(updatedStatus.getStatus()).isEqualTo(STARTING);
Date now = new Date();
long duration = now.getTime() - updatedStatus.getDate().getTime();
@@ -94,20 +102,20 @@ void shouldUpdateReplicateStatus(){
@Test
void shouldGetProperLatestStatus(){
- Replicate replicate = new Replicate("worker", "taskId");
- assertThat(replicate.getStatusUpdateList().size()).isEqualTo(1);
+ Replicate replicate = new Replicate(WALLET_WORKER, CHAIN_TASK_ID);
+ assertThat(replicate.getStatusUpdateList()).hasSize(1);
assertThat(replicate.getCurrentStatus()).isEqualTo(ReplicateStatus.CREATED);
- replicate.updateStatus(ReplicateStatus.STARTING, ReplicateStatusModifier.WORKER);
- assertThat(replicate.getStatusUpdateList().size()).isEqualTo(2);
- assertThat(replicate.getCurrentStatus()).isEqualTo(ReplicateStatus.STARTING);
+ replicate.updateStatus(STARTING, ReplicateStatusModifier.WORKER);
+ assertThat(replicate.getStatusUpdateList()).hasSize(2);
+ assertThat(replicate.getCurrentStatus()).isEqualTo(STARTING);
}
@Test
void shouldReturnTrueWhenContributed(){
- Replicate replicate = new Replicate("0x1", "taskId");
- replicate.updateStatus(ReplicateStatus.STARTING, ReplicateStatusModifier.WORKER);
+ Replicate replicate = new Replicate("0x1", CHAIN_TASK_ID);
+ replicate.updateStatus(STARTING, ReplicateStatusModifier.WORKER);
replicate.updateStatus(ReplicateStatus.CONTRIBUTING, ReplicateStatusModifier.WORKER);
replicate.updateStatus(ReplicateStatus.CONTRIBUTED, ReplicateStatusModifier.WORKER);
replicate.updateStatus(ReplicateStatus.REVEALING, ReplicateStatusModifier.WORKER);
@@ -118,8 +126,8 @@ void shouldReturnTrueWhenContributed(){
@Test
void shouldReturnFalseWhenContributedMissing(){
- Replicate replicate = new Replicate("0x1", "taskId");
- replicate.updateStatus(ReplicateStatus.STARTING, ReplicateStatusModifier.WORKER);
+ Replicate replicate = new Replicate("0x1", CHAIN_TASK_ID);
+ replicate.updateStatus(STARTING, ReplicateStatusModifier.WORKER);
replicate.updateStatus(ReplicateStatus.CONTRIBUTING, ReplicateStatusModifier.WORKER);
replicate.updateStatus(ReplicateStatus.REVEALING, ReplicateStatusModifier.WORKER);
replicate.updateStatus(ReplicateStatus.REVEALED, ReplicateStatusModifier.WORKER);
@@ -131,7 +139,7 @@ void shouldReturnFalseWhenContributedMissing(){
void shouldBeCreatedLongAgo(){
final long maxExecutionTime = 60000;
Date now = new Date();
- Replicate replicate = new Replicate("0x1", "taskId");
+ Replicate replicate = new Replicate("0x1", CHAIN_TASK_ID);
ReplicateStatusUpdate oldCreationDate = replicate.getStatusUpdateList().get(0);
oldCreationDate.setDate(new Date(now.getTime() - 3 * maxExecutionTime));
replicate.setStatusUpdateList(Collections.singletonList(oldCreationDate));
@@ -143,7 +151,7 @@ void shouldBeCreatedLongAgo(){
void shouldNotBeCreatedLongAgo(){
final long maxExecutionTime = 60000;
Date now = new Date();
- Replicate replicate = new Replicate("0x1", "taskId");
+ Replicate replicate = new Replicate("0x1", CHAIN_TASK_ID);
ReplicateStatusUpdate oldCreationDate = replicate.getStatusUpdateList().get(0);
oldCreationDate.setDate(new Date(now.getTime() - maxExecutionTime));
replicate.setStatusUpdateList(Collections.singletonList(oldCreationDate));
@@ -153,9 +161,9 @@ void shouldNotBeCreatedLongAgo(){
@Test
void shouldBeBusyComputing() {
- Replicate replicate = new Replicate("worker", "taskId");
+ Replicate replicate = new Replicate(WALLET_WORKER, CHAIN_TASK_ID);
assertThat(replicate.isBusyComputing()).isTrue();
- replicate.updateStatus(ReplicateStatus.STARTING, ReplicateStatusModifier.WORKER);
+ replicate.updateStatus(STARTING, ReplicateStatusModifier.WORKER);
assertThat(replicate.isBusyComputing()).isTrue();
replicate.updateStatus(ReplicateStatus.APP_DOWNLOADING, ReplicateStatusModifier.WORKER);
assertThat(replicate.isBusyComputing()).isTrue();
@@ -177,4 +185,72 @@ void shouldBeBusyComputing() {
replicate.updateStatus(ReplicateStatus.COMPLETED, ReplicateStatusModifier.WORKER);
assertThat(replicate.isBusyComputing()).isFalse();
}
+
+ // region getLastRelevantStatus
+ @Test
+ void shouldGetLastRelevantStatusWhenOnlyRelevantStatus() {
+ final Replicate replicate = new Replicate(WALLET_WORKER, CHAIN_TASK_ID);
+ replicate.updateStatus(STARTING, ReplicateStatusModifier.WORKER);
+ replicate.updateStatus(STARTED, ReplicateStatusModifier.WORKER);
+
+ assertThat(replicate.getLastRelevantStatus()).isEqualTo(STARTED);
+ }
+
+ @Test
+ void shouldGetLastRelevantStatusWhenRelevantAndIrrelevantStatus() {
+ final Replicate replicate = new Replicate(WALLET_WORKER, CHAIN_TASK_ID);
+ replicate.updateStatus(STARTING, ReplicateStatusModifier.WORKER);
+ replicate.updateStatus(STARTED, ReplicateStatusModifier.WORKER);
+ replicate.updateStatus(WORKER_LOST, ReplicateStatusModifier.WORKER);
+
+ assertThat(replicate.getLastRelevantStatus()).isEqualTo(STARTED);
+ }
+
+ @Test
+ void shouldNotGetLastRelevantStatusWhenNoStatusAtAll() {
+ final Replicate replicate = new Replicate(WALLET_WORKER, CHAIN_TASK_ID);
+ ReflectionTestUtils.setField(replicate, "statusUpdateList", List.of());
+
+ assertThatExceptionOfType(NoReplicateStatusException.class)
+ .isThrownBy(replicate::getLastRelevantStatus)
+ .extracting(NoReplicateStatusException::getChainTaskId)
+ .isEqualTo(CHAIN_TASK_ID);
+ }
+
+ @Test
+ void shouldNotGetLastRelevantStatusWhenOnlyWorkerLost() {
+ final Replicate replicate = new Replicate(WALLET_WORKER, CHAIN_TASK_ID);
+ ReflectionTestUtils.setField(replicate, "statusUpdateList", List.of(ReplicateStatusUpdate.poolManagerRequest(WORKER_LOST)));
+
+ assertThatExceptionOfType(NoReplicateStatusException.class)
+ .isThrownBy(replicate::getLastRelevantStatus)
+ .extracting(NoReplicateStatusException::getChainTaskId)
+ .isEqualTo(CHAIN_TASK_ID);
+ }
+
+ @Test
+ void shouldNotGetLastRelevantStatusWhenOnlyRecovering() {
+ final Replicate replicate = new Replicate(WALLET_WORKER, CHAIN_TASK_ID);
+ ReflectionTestUtils.setField(replicate, "statusUpdateList", List.of(ReplicateStatusUpdate.poolManagerRequest(RECOVERING)));
+
+ assertThatExceptionOfType(NoReplicateStatusException.class)
+ .isThrownBy(replicate::getLastRelevantStatus)
+ .extracting(NoReplicateStatusException::getChainTaskId)
+ .isEqualTo(CHAIN_TASK_ID);
+ }
+
+ @Test
+ void shouldNotGetLastRelevantStatusWhenWorkerLostAndyRecovering() {
+ final Replicate replicate = new Replicate(WALLET_WORKER, CHAIN_TASK_ID);
+ ReflectionTestUtils.setField(replicate, "statusUpdateList", List.of(
+ ReplicateStatusUpdate.poolManagerRequest(WORKER_LOST),
+ ReplicateStatusUpdate.poolManagerRequest(RECOVERING)
+ ));
+
+ assertThatExceptionOfType(NoReplicateStatusException.class)
+ .isThrownBy(replicate::getLastRelevantStatus)
+ .extracting(NoReplicateStatusException::getChainTaskId)
+ .isEqualTo(CHAIN_TASK_ID);
+ }
+ // endregion
}
diff --git a/src/test/java/com/iexec/core/security/ChallengeServiceTests.java b/src/test/java/com/iexec/core/security/ChallengeServiceTests.java
index 1ebc34448..e8c4ac306 100644
--- a/src/test/java/com/iexec/core/security/ChallengeServiceTests.java
+++ b/src/test/java/com/iexec/core/security/ChallengeServiceTests.java
@@ -27,6 +27,13 @@ class ChallengeServiceTests {
private final ChallengeService challengeService = new ChallengeService();
+ @Test
+ void shouldCreateNewChallengeAfterRemoval() {
+ String challenge1 = challengeService.getChallenge(WALLET_WORKER_1);
+ challengeService.removeChallenge(WALLET_WORKER_1, challenge1);
+ String challenge2 = challengeService.getChallenge(WALLET_WORKER_1);
+ assertThat(challenge1).isNotEqualTo(challenge2);
+ }
@Test
void shouldGetSameChallengeForSameWallet() {
String challenge1 = challengeService.getChallenge(WALLET_WORKER_1);
diff --git a/src/test/java/com/iexec/core/security/EIP712ChallengeServiceTests.java b/src/test/java/com/iexec/core/security/EIP712ChallengeServiceTests.java
index 2cc652c43..fbf1e4895 100644
--- a/src/test/java/com/iexec/core/security/EIP712ChallengeServiceTests.java
+++ b/src/test/java/com/iexec/core/security/EIP712ChallengeServiceTests.java
@@ -23,7 +23,7 @@
import static org.assertj.core.api.Assertions.assertThat;
-public class EIP712ChallengeServiceTests {
+class EIP712ChallengeServiceTests {
private static final String WALLET_ADDRESS_1 = "1a69b2eb604db8eba185df03ea4f5288dcbbd248";
private static final String WALLET_ADDRESS_2 = "2a69b2eb604db8eba185df03ea4f5288dcbbd248";
diff --git a/src/test/java/com/iexec/core/security/JwtTokenProviderTests.java b/src/test/java/com/iexec/core/security/JwtTokenProviderTests.java
index 68fca9dcd..1282b8a79 100644
--- a/src/test/java/com/iexec/core/security/JwtTokenProviderTests.java
+++ b/src/test/java/com/iexec/core/security/JwtTokenProviderTests.java
@@ -16,32 +16,53 @@
package com.iexec.core.security;
+import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
+import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.security.Keys;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import org.springframework.boot.info.BuildProperties;
+import org.springframework.test.util.ReflectionTestUtils;
+import java.security.SecureRandom;
+import java.util.Base64;
+import java.util.Date;
+import java.util.concurrent.ConcurrentHashMap;
+
+import static com.iexec.core.security.JwtTokenProvider.KEY_SIZE;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
class JwtTokenProviderTests {
+ private static final String JWT_AUDIENCE = "iExec Scheduler vX.Y.Z";
private static final String WALLET_ADDRESS = "0x1a69b2eb604db8eba185df03ea4f5288dcbbd248";
-
- @Mock
- private ChallengeService challengeService;
-
- @InjectMocks
+ private static final SecureRandom secureRandom = new SecureRandom();
private JwtTokenProvider jwtTokenProvider;
+ private final byte[] secretKey = new byte[KEY_SIZE];
@BeforeEach
void init() {
MockitoAnnotations.openMocks(this);
+ secureRandom.nextBytes(secretKey);
+ BuildProperties buildProperties = mock(BuildProperties.class);
+ when(buildProperties.getVersion()).thenReturn("X.Y.Z");
+ jwtTokenProvider = spy(new JwtTokenProvider(buildProperties));
+ ReflectionTestUtils.setField(jwtTokenProvider, "secretKey", secretKey);
}
+ //region createToken
+ @Test
+ void shouldReturnExistingTokenIfValid() {
+ String token1 = jwtTokenProvider.getOrCreateToken(WALLET_ADDRESS);
+ String token2 = jwtTokenProvider.getOrCreateToken(WALLET_ADDRESS);
+ assertThat(token1).isEqualTo(token2);
+ }
+ //endregion
+
//region resolveToken
@Test
void shouldResolveToken() {
@@ -52,7 +73,7 @@ void shouldResolveToken() {
@Test
void shouldNotResolveTokenSinceNotValidOne() {
- String notBearerToken = "Not Bearer eb604db8eba185df03ea4f5";
+ String notBearerToken = "Not " + jwtTokenProvider.getOrCreateToken(WALLET_ADDRESS);
String resolvedToken = jwtTokenProvider.resolveToken(notBearerToken);
assertThat(resolvedToken).isNull();
}
@@ -67,24 +88,75 @@ void shouldNotResolveTokenSinceNullOne() {
//region isValidToken
@Test
void isValidTokenTrue() {
- when(challengeService.getChallenge(WALLET_ADDRESS)).thenReturn("challenge");
- String token = jwtTokenProvider.createToken(WALLET_ADDRESS);
+ String token = jwtTokenProvider.getOrCreateToken(WALLET_ADDRESS);
boolean isValidToken = jwtTokenProvider.isValidToken(token);
assertThat(isValidToken).isTrue();
}
@Test
- void isValidTokenFalseSinceNotSameChallenge() {
- when(challengeService.getChallenge(WALLET_ADDRESS)).thenReturn("challenge1", "challenge2");
- String token = jwtTokenProvider.createToken(WALLET_ADDRESS);
+ void isValidTokenFalseSinceBadAudience() {
+ Date now = new Date();
+ String token = Jwts.builder()
+ .setAudience("iExec Scheduler")
+ .setSubject(WALLET_ADDRESS)
+ .setIssuedAt(now)
+ .setExpiration(new Date(now.getTime() + 10000L))
+ .signWith(Keys.hmacShaKeyFor(secretKey), SignatureAlgorithm.HS256)
+ .compact();
+ ConcurrentHashMap tokensMap = new ConcurrentHashMap<>();
+ tokensMap.put(WALLET_ADDRESS, token);
+ ReflectionTestUtils.setField(jwtTokenProvider, "jwTokensMap", tokensMap);
+ boolean isValidToken = jwtTokenProvider.isValidToken(token);
+ assertThat(isValidToken).isFalse();
+ }
+
+ @Test
+ void isValidTokenFalseSinceExpired() {
+ Date now = new Date();
+ String token = Jwts.builder()
+ .setAudience(JWT_AUDIENCE)
+ .setSubject(WALLET_ADDRESS)
+ .setIssuedAt(now)
+ .setExpiration(now)
+ .signWith(Keys.hmacShaKeyFor(secretKey), SignatureAlgorithm.HS256)
+ .compact();
+ ConcurrentHashMap tokensMap = new ConcurrentHashMap<>();
+ tokensMap.put(WALLET_ADDRESS, token);
+ ReflectionTestUtils.setField(jwtTokenProvider, "jwTokensMap", tokensMap);
boolean isValidToken = jwtTokenProvider.isValidToken(token);
assertThat(isValidToken).isFalse();
}
+ @Test
+ void isValidTokenFalseSinceNotSigned() {
+ String token = Jwts.builder()
+ .setAudience(JWT_AUDIENCE)
+ .setIssuedAt(new Date())
+ .setSubject(WALLET_ADDRESS)
+ .compact();
+ boolean isTokenValid = jwtTokenProvider.isValidToken(token);
+ assertThat(isTokenValid).isFalse();
+ }
+
+ @Test
+ void isValidTokenFalseSinceWronglySigned() {
+ final byte[] newKey = new byte[KEY_SIZE];
+ secureRandom.nextBytes(newKey);
+ Date now = new Date();
+ String token = Jwts.builder()
+ .setAudience(JWT_AUDIENCE)
+ .setIssuedAt(now)
+ .setExpiration(new Date(now.getTime() + 10000L))
+ .setSubject(WALLET_ADDRESS)
+ .signWith(Keys.hmacShaKeyFor(newKey), SignatureAlgorithm.HS256)
+ .compact();
+ boolean isTokenValid = jwtTokenProvider.isValidToken(token);
+ assertThat(isTokenValid).isFalse();
+ }
+
@Test
void isValidTokenFalseSinceNotValidOne() {
- when(challengeService.getChallenge(WALLET_ADDRESS)).thenReturn("challenge");
- jwtTokenProvider.createToken(WALLET_ADDRESS);
+ jwtTokenProvider.getOrCreateToken(WALLET_ADDRESS);
boolean isValidToken = jwtTokenProvider.isValidToken("non.valid.token");
assertThat(isValidToken).isFalse();
}
@@ -93,8 +165,7 @@ void isValidTokenFalseSinceNotValidOne() {
//region getWalletAddress
@Test
void shouldGetCorrectWalletAddress() {
- when(challengeService.getChallenge(WALLET_ADDRESS)).thenReturn("challenge");
- String token = jwtTokenProvider.createToken(WALLET_ADDRESS);
+ String token = jwtTokenProvider.getOrCreateToken(WALLET_ADDRESS);
String walletAddress = jwtTokenProvider.getWalletAddress(token);
assertThat(walletAddress).isEqualTo(WALLET_ADDRESS);
}
@@ -108,8 +179,7 @@ void shouldThrowJwtExceptionSinceNotValidToken() {
//region getWalletAddressFromBearerToken
@Test
void shouldGetCorrectWalletAddressFromBearerToken() {
- when(challengeService.getChallenge(WALLET_ADDRESS)).thenReturn("challenge");
- String token = jwtTokenProvider.createToken(WALLET_ADDRESS);
+ String token = jwtTokenProvider.getOrCreateToken(WALLET_ADDRESS);
String bearerToken = "Bearer " + token;
String walletAddress = jwtTokenProvider.getWalletAddressFromBearerToken(bearerToken);
assertThat(walletAddress).isEqualTo(WALLET_ADDRESS);
@@ -117,8 +187,7 @@ void shouldGetCorrectWalletAddressFromBearerToken() {
@Test
void shouldNotGetWalletAddressSinceNotValidBearerToken() {
- when(challengeService.getChallenge(WALLET_ADDRESS)).thenReturn("challenge");
- String token = jwtTokenProvider.createToken(WALLET_ADDRESS);
+ String token = jwtTokenProvider.getOrCreateToken(WALLET_ADDRESS);
String notBearerToken = "Not Bearer " + token;
String walletAddress = jwtTokenProvider.getWalletAddressFromBearerToken(notBearerToken);
assertThat(walletAddress).isEmpty();
diff --git a/src/test/java/com/iexec/core/sms/SmsServiceTests.java b/src/test/java/com/iexec/core/sms/SmsServiceTests.java
index d1b9a8c63..cb3c0e9a9 100644
--- a/src/test/java/com/iexec/core/sms/SmsServiceTests.java
+++ b/src/test/java/com/iexec/core/sms/SmsServiceTests.java
@@ -1,39 +1,114 @@
package com.iexec.core.sms;
+import com.iexec.common.tee.TeeFramework;
+import com.iexec.common.tee.TeeUtils;
import com.iexec.common.utils.BytesUtils;
+import com.iexec.core.registry.PlatformRegistryConfiguration;
import com.iexec.sms.api.SmsClient;
+import com.iexec.sms.api.SmsClientProvider;
import feign.FeignException;
import feign.Request;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.Collections;
+import java.util.List;
import java.util.Optional;
+import java.util.stream.Stream;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.*;
class SmsServiceTests {
+ private static final String GRAMINE_SMS_URL = "http://gramine-sms";
+ private static final String SCONE_SMS_URL = "http://scone-sms";
private static final String CHAIN_TASK_ID = "chainTaskId";
+ private static final String url = "url";
@Mock
private SmsClient smsClient;
+ @Mock
+ private SmsClientProvider smsClientProvider;
+ @Mock
+ private PlatformRegistryConfiguration registryConfiguration;
+
@InjectMocks
private SmsService smsService;
@BeforeEach
void init() {
MockitoAnnotations.openMocks(this);
+ when(registryConfiguration.getSconeSms()).thenReturn(SCONE_SMS_URL);
+ when(registryConfiguration.getGramineSms()).thenReturn(GRAMINE_SMS_URL);
+ }
+
+ // region isSmsClientReady
+ static Stream validData() {
+ List supportedTeeTags =
+ List.of(
+ TeeUtils.TEE_SCONE_ONLY_TAG,
+ TeeUtils.TEE_GRAMINE_ONLY_TAG);
+ //Ensure all TeeEnclaveProvider are handled
+ // (adding a new one would break assertion)
+ Assertions.assertThat(supportedTeeTags)
+ .hasSize(TeeFramework.values().length);
+ return Stream.of(
+ Arguments.of(supportedTeeTags.get(0), SCONE_SMS_URL),
+ Arguments.of(supportedTeeTags.get(1), GRAMINE_SMS_URL)
+ );
+ }
+
+ @ParameterizedTest
+ @MethodSource("validData")
+ void shouldGetVerifiedSmsUrl(String inputTag, String expectedSmsUrl) {
+ when(smsClientProvider.getSmsClient(expectedSmsUrl)).thenReturn(smsClient);
+ when(smsClient.getTeeFramework()).thenReturn(TeeUtils.getTeeFramework(inputTag));
+
+ Assertions.assertThat(smsService.getVerifiedSmsUrl(CHAIN_TASK_ID, inputTag))
+ .isEqualTo(Optional.of(expectedSmsUrl));
+
+ verify(smsClientProvider).getSmsClient(expectedSmsUrl);
+ verify(smsClient).getTeeFramework();
+ }
+
+ @Test
+ void shouldNotGetVerifiedSmsUrlSinceCannotGetEnclaveProviderFromTag() {
+ Assertions.assertThat(smsService.getVerifiedSmsUrl(CHAIN_TASK_ID, "0xabc"))
+ .isEmpty();
+
+ verify(smsClientProvider, times(0)).getSmsClient(anyString());
+ verify(smsClient, times(0)).getTeeFramework();
}
+ @Test
+ void shouldNotGetVerifiedSmsUrlSinceSinceWrongTeeEnclaveProviderOnRemoteSms() {
+ when(smsClientProvider.getSmsClient(GRAMINE_SMS_URL)).thenReturn(smsClient);
+ when(smsClient.getTeeFramework()).thenReturn(TeeFramework.SCONE);
+
+ Assertions.assertThat(smsService.getVerifiedSmsUrl(CHAIN_TASK_ID, TeeUtils.TEE_GRAMINE_ONLY_TAG))
+ .isEmpty();
+
+ verify(smsClientProvider).getSmsClient(GRAMINE_SMS_URL);
+ verify(smsClient).getTeeFramework();
+ }
+ // endregion
+
+ // region getEnclaveChallenge
@Test
void shouldGetEmptyAddressForStandardTask() {
- Assertions.assertThat(smsService.getEnclaveChallenge(CHAIN_TASK_ID, false))
+ when(smsClientProvider.getSmsClient(url)).thenReturn(smsClient);
+ when(smsClient.generateTeeChallenge(CHAIN_TASK_ID)).thenReturn("");
+
+ Assertions.assertThat(smsService.getEnclaveChallenge(CHAIN_TASK_ID, ""))
.get()
.isEqualTo(BytesUtils.EMPTY_ADDRESS);
verify(smsClient, never()).generateTeeChallenge(anyString());
@@ -42,9 +117,10 @@ void shouldGetEmptyAddressForStandardTask() {
@Test
void shouldGetEnclaveChallengeForTeeTask() {
String expected = "challenge";
+ when(smsClientProvider.getSmsClient(url)).thenReturn(smsClient);
when(smsClient.generateTeeChallenge(CHAIN_TASK_ID)).thenReturn(expected);
- Optional received = smsService.getEnclaveChallenge(CHAIN_TASK_ID, true);
+ Optional received = smsService.getEnclaveChallenge(CHAIN_TASK_ID, url);
verify(smsClient).generateTeeChallenge(CHAIN_TASK_ID);
Assertions.assertThat(received)
.get()
@@ -53,30 +129,26 @@ void shouldGetEnclaveChallengeForTeeTask() {
@Test
void shouldNotGetEnclaveChallengeForTeeTaskWhenEmptySmsResponse() {
+ when(smsClientProvider.getSmsClient(url)).thenReturn(smsClient);
when(smsClient.generateTeeChallenge(CHAIN_TASK_ID)).thenReturn("");
- Optional received = smsService.getEnclaveChallenge(CHAIN_TASK_ID, true);
- verify(smsClient).generateTeeChallenge(CHAIN_TASK_ID);
- Assertions.assertThat(received).isEmpty();
- }
-
- @Test
- void shouldNotGetEnclaveChallengeForTeeTaskWhenNullSmsResponse() {
- when(smsClient.generateTeeChallenge(CHAIN_TASK_ID)).thenReturn(null);
-
- Optional received = smsService.getEnclaveChallenge(CHAIN_TASK_ID, true);
+ Optional received = smsService.getEnclaveChallenge(CHAIN_TASK_ID, url);
verify(smsClient).generateTeeChallenge(CHAIN_TASK_ID);
Assertions.assertThat(received).isEmpty();
}
+ // endregion
+ // region generateEnclaveChallenge
@Test
void shouldNotGetEnclaveChallengeOnFeignException() {
- Request request = Request.create(Request.HttpMethod.HEAD, "http://localhost",
+ when(smsClientProvider.getSmsClient(url)).thenReturn(smsClient);
+ Request request = Request.create(Request.HttpMethod.HEAD, url,
Collections.emptyMap(), Request.Body.empty(), null);
Assertions.assertThat(smsService.generateEnclaveChallenge(
new FeignException.Unauthorized("", request, new byte[0], null),
- CHAIN_TASK_ID
- )
+ CHAIN_TASK_ID,
+ url)
).isEmpty();
verifyNoInteractions(smsClient);
}
+ // endregion
}
\ No newline at end of file
diff --git a/src/test/java/com/iexec/core/task/TaskControllerTests.java b/src/test/java/com/iexec/core/task/TaskControllerTests.java
index 426c812d7..5702f0755 100644
--- a/src/test/java/com/iexec/core/task/TaskControllerTests.java
+++ b/src/test/java/com/iexec/core/task/TaskControllerTests.java
@@ -21,7 +21,6 @@
import com.iexec.common.chain.eip712.entity.EIP712Challenge;
import com.iexec.common.replicate.ComputeLogs;
import com.iexec.common.task.TaskDescription;
-import com.iexec.common.utils.CredentialsUtils;
import com.iexec.core.chain.IexecHubService;
import com.iexec.core.logs.TaskLogs;
import com.iexec.core.logs.TaskLogsService;
@@ -29,8 +28,7 @@
import com.iexec.core.replicate.ReplicateModel;
import com.iexec.core.replicate.ReplicatesService;
import com.iexec.core.security.EIP712ChallengeService;
-import lombok.Getter;
-import lombok.extern.slf4j.Slf4j;
+import lombok.SneakyThrows;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
@@ -38,21 +36,16 @@
import org.mockito.MockitoAnnotations;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
+import org.web3j.crypto.Credentials;
import org.web3j.crypto.ECKeyPair;
import org.web3j.crypto.Keys;
-import java.math.BigInteger;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.Key;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
import java.util.List;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
-@Slf4j
class TaskControllerTests {
private static final String TASK_ID = "0xtask";
@@ -72,21 +65,22 @@ class TaskControllerTests {
@InjectMocks private TaskController taskController;
@BeforeEach
- void setUp() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException {
+ @SneakyThrows
+ void setUp() {
MockitoAnnotations.openMocks(this);
EIP712Domain domain = new EIP712Domain();
challenge = new EIP712Challenge(domain, Challenge.builder().challenge("challenge").build());
badChallenge = new EIP712Challenge(domain, Challenge.builder().challenge("bad-challenge").build());
ecKeyPair = Keys.createEcKeyPair();
- requesterAddress = CredentialsUtils.getAddress(String.format("0x%032x", ecKeyPair.getPrivateKey()));
+ requesterAddress = Credentials.create(ecKeyPair).getAddress();
signature = challenge.signMessage(ecKeyPair);
}
//region utilities
- String generateWalletAddress() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException {
+ @SneakyThrows
+ String generateWalletAddress() {
ECKeyPair ecKeyPair = Keys.createEcKeyPair();
- BigInteger pk = ecKeyPair.getPrivateKey();
- return CredentialsUtils.getAddress(String.format("0x%032x", pk));
+ return Credentials.create(ecKeyPair).getAddress();
}
//endregion
@@ -208,7 +202,7 @@ void shouldGetTaskLogsWhenAuthenticated() {
when(challengeService.getChallenge(requesterAddress)).thenReturn(challenge);
when(taskLogsService.getTaskLogs(TASK_ID)).thenReturn(Optional.of(taskStdout));
ResponseEntity response = taskController.getTaskLogs(TASK_ID, authorization);
- assertTrue(response.getStatusCode().is2xxSuccessful());
+ assertEquals(HttpStatus.OK, response.getStatusCode());
verify(iexecHubService).getTaskDescription(TASK_ID);
}
@@ -248,11 +242,10 @@ void shouldFailToGetTaskLogsWhenInvalidAuthorization() {
}
@Test
- void shouldFailToGetTaskLogsWhenNotTaskRequester()
- throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException {
+ void shouldFailToGetTaskLogsWhenNotTaskRequester() {
String notRequesterAddress = generateWalletAddress();
TaskDescription description = TaskDescription.builder()
- .requester(CredentialsUtils.getAddress(notRequesterAddress))
+ .requester(notRequesterAddress)
.build();
String authorization = String.join("_", challenge.getHash(), signature, requesterAddress);
when(iexecHubService.getTaskDescription(TASK_ID)).thenReturn(description);
@@ -275,7 +268,7 @@ void shouldGetComputeLogsWhenAuthenticated() {
when(challengeService.getChallenge(requesterAddress)).thenReturn(challenge);
when(taskLogsService.getComputeLogs(TASK_ID, WORKER_ADDRESS)).thenReturn(Optional.of(computeLogs));
ResponseEntity response = taskController.getComputeLogs(TASK_ID, WORKER_ADDRESS, authorization);
- assertTrue(response.getStatusCode().is2xxSuccessful());
+ assertEquals(HttpStatus.OK, response.getStatusCode());
verify(iexecHubService).getTaskDescription(TASK_ID);
}
@@ -315,11 +308,10 @@ void shouldFailToGetComputeLogsWhenInvalidAuthorization() {
}
@Test
- void shouldFailToGetComputeLogsWhenNotTaskRequester()
- throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException {
+ void shouldFailToGetComputeLogsWhenNotTaskRequester() {
String notRequesterAddress = generateWalletAddress();
TaskDescription description = TaskDescription.builder()
- .requester(CredentialsUtils.getAddress(notRequesterAddress))
+ .requester(notRequesterAddress)
.build();
String authorization = String.join("_", challenge.getHash(), signature, requesterAddress);
when(iexecHubService.getTaskDescription(TASK_ID)).thenReturn(description);
diff --git a/src/test/java/com/iexec/core/task/TaskModelTests.java b/src/test/java/com/iexec/core/task/TaskModelTests.java
index c4634da4d..74d63704a 100644
--- a/src/test/java/com/iexec/core/task/TaskModelTests.java
+++ b/src/test/java/com/iexec/core/task/TaskModelTests.java
@@ -17,7 +17,6 @@
package com.iexec.core.task;
import com.iexec.common.dapp.DappType;
-import com.iexec.common.tee.TeeUtils;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
@@ -29,7 +28,7 @@ class TaskModelTests {
public static final String CHAIN_TASK_ID = "task";
public static final long MAX_EXECUTION_TIME = 1;
- public static final String TAG = TeeUtils.TEE_TAG;
+ public static final String TAG = "0xa";
public static final DappType DAPP_TYPE = DappType.DOCKER;
public static final String DAPP_NAME = "name";
public static final String COMMAND_LINE = "line";
diff --git a/src/test/java/com/iexec/core/task/TaskServiceRealRepositoryTest.java b/src/test/java/com/iexec/core/task/TaskServiceRealRepositoryTest.java
new file mode 100644
index 000000000..ed8b08a04
--- /dev/null
+++ b/src/test/java/com/iexec/core/task/TaskServiceRealRepositoryTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2023 IEXEC BLOCKCHAIN TECH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.iexec.core.task;
+
+import com.iexec.common.chain.ChainUtils;
+import com.iexec.core.chain.IexecHubService;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
+import org.springframework.dao.DuplicateKeyException;
+import org.springframework.test.context.DynamicPropertyRegistry;
+import org.springframework.test.context.DynamicPropertySource;
+import org.testcontainers.containers.MongoDBContainer;
+import org.testcontainers.junit.jupiter.Container;
+import org.testcontainers.junit.jupiter.Testcontainers;
+import org.testcontainers.utility.DockerImageName;
+
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.stream.Collectors;
+
+import static com.iexec.core.task.TaskTestsUtils.*;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.fail;
+
+@DataMongoTest
+@Testcontainers
+class TaskServiceRealRepositoryTest {
+ private final long maxExecutionTime = 60000;
+ private final Date contributionDeadline = new Date();
+ private final Date finalDeadline = new Date();
+
+ @Container
+ private static final MongoDBContainer mongoDBContainer = new MongoDBContainer(DockerImageName.parse("mongo:4.2"));
+
+ @DynamicPropertySource
+ static void registerProperties(DynamicPropertyRegistry registry) {
+ registry.add("spring.data.mongodb.host", mongoDBContainer::getContainerIpAddress);
+ registry.add("spring.data.mongodb.port", () -> mongoDBContainer.getMappedPort(27017));
+ }
+
+ @Autowired
+ private TaskRepository taskRepository;
+
+ @Mock
+ private IexecHubService iexecHubService;
+
+ private TaskService taskService;
+
+ @BeforeEach
+ void init() {
+ MockitoAnnotations.openMocks(this);
+ taskService = new TaskService(taskRepository, iexecHubService);
+ }
+
+ @Test
+ void shouldAddTaskASingleTime() {
+ final int concurrentRequests = 5;
+ final String expectedChainTaskId = ChainUtils.generateChainTaskId(CHAIN_DEAL_ID, 0);
+
+ // Let's start n `taskService.addTask` at the same time.
+ // Without any sync mechanism, this should fail
+ // as it'll try to add more than once the same task - with the same key - to the DB.
+ final ExecutorService executorService = Executors.newFixedThreadPool(concurrentRequests);
+ final List>> executions = new ArrayList<>(concurrentRequests);
+ for (int i = 0; i < concurrentRequests; i++) {
+ executions.add(executorService.submit(() -> taskService.addTask(CHAIN_DEAL_ID, 0, 0, DAPP_NAME, COMMAND_LINE,
+ 2, maxExecutionTime, "0x0", contributionDeadline, finalDeadline)));
+ }
+
+ // Let's wait for the `taskService.addTask` to complete and retrieve the results.
+ List> results = executions.stream().map(execution -> {
+ try {
+ return execution.get(1, TimeUnit.MINUTES);
+ } catch (ExecutionException e) {
+ if (e.getCause() instanceof DuplicateKeyException) {
+ fail("Task has been added twice. Should not happen!");
+ }
+ throw new RuntimeException("Something went wrong.", e);
+ } catch (InterruptedException | TimeoutException e) {
+ throw new RuntimeException(e);
+ }
+ }).collect(Collectors.toList());
+
+ // Check one execution has added the task,
+ // while the others have failed.
+ assertThat(results).hasSize(concurrentRequests);
+ final List nonEmptyResults = results
+ .stream()
+ .filter(Optional::isPresent)
+ .map(Optional::get)
+ .collect(Collectors.toList());
+ assertThat(nonEmptyResults).hasSize(1);
+ assertThat(nonEmptyResults.get(0).getChainTaskId()).isEqualTo(expectedChainTaskId);
+
+ // Finally, let's simply check the task has effectively been added.
+ assertThat(taskRepository.findByChainTaskId(CHAIN_TASK_ID)).isPresent();
+ }
+}
diff --git a/src/test/java/com/iexec/core/task/TaskServiceTests.java b/src/test/java/com/iexec/core/task/TaskServiceTests.java
index 41dcef919..7d9d0ddf3 100644
--- a/src/test/java/com/iexec/core/task/TaskServiceTests.java
+++ b/src/test/java/com/iexec/core/task/TaskServiceTests.java
@@ -25,6 +25,7 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.*;
+import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.domain.Sort;
import java.time.Instant;
@@ -66,7 +67,7 @@ void init() {
void shouldNotGetTaskWithTrust() {
when(taskRepository.findByChainTaskId("dummyId")).thenReturn(Optional.empty());
Optional task = taskService.getTaskByChainTaskId("dummyId");
- assertThat(task.isPresent()).isFalse();
+ assertThat(task).isEmpty();
}
@Test
@@ -75,8 +76,7 @@ void shouldGetOneTask() {
when(taskRepository.findByChainTaskId(CHAIN_TASK_ID)).thenReturn(Optional.of(task));
Optional optional = taskService.getTaskByChainTaskId(CHAIN_TASK_ID);
- assertThat(optional.isPresent()).isTrue();
- assertThat(optional).isEqualTo(Optional.of(task));
+ assertThat(optional).contains(task);
}
@Test
@@ -87,18 +87,18 @@ void shouldAddTask() {
when(taskRepository.save(any())).thenReturn(task);
Optional saved = taskService.addTask(CHAIN_DEAL_ID, 0, 0, DAPP_NAME, COMMAND_LINE,
2, maxExecutionTime, "0x0", contributionDeadline, finalDeadline);
- assertThat(saved).isPresent();
- assertThat(saved).isEqualTo(Optional.of(task));
+ assertThat(saved).contains(task);
}
@Test
void shouldNotAddTask() {
Task task = getStubTask(maxExecutionTime);
task.changeStatus(TaskStatus.INITIALIZED);
- when(taskRepository.findByChainDealIdAndTaskIndex(CHAIN_DEAL_ID, 0)).thenReturn(Optional.of(task));
+ when(taskRepository.save(any())).thenThrow(DuplicateKeyException.class);
+
Optional saved = taskService.addTask(CHAIN_DEAL_ID, 0, 0, DAPP_NAME, COMMAND_LINE,
2, maxExecutionTime, "0x0", contributionDeadline, finalDeadline);
- assertThat(saved).isEqualTo(Optional.empty());
+ assertThat(saved).isEmpty();
}
@Test
@@ -161,7 +161,7 @@ void shouldNotFindByCurrentStatusList() {
@Test
void shouldGetInitializedOrRunningTasks() {
Task task = mock(Task.class);
- when(taskRepository.findFirstByCurrentStatusInAndTagNotAndChainTaskIdNotIn(
+ when(taskRepository.findFirstByCurrentStatusInAndTagNotInAndChainTaskIdNotIn(
eq(Arrays.asList(INITIALIZED, RUNNING)),
any(),
eq(Collections.emptyList()),
diff --git a/src/test/java/com/iexec/core/task/TaskTests.java b/src/test/java/com/iexec/core/task/TaskTests.java
index 361aaac11..7c9fb97f2 100644
--- a/src/test/java/com/iexec/core/task/TaskTests.java
+++ b/src/test/java/com/iexec/core/task/TaskTests.java
@@ -37,24 +37,24 @@ class TaskTests {
void shouldInitializeProperly(){
Task task = new Task(DAPP_NAME, COMMAND_LINE, 2);
- assertThat(task.getDateStatusList().size()).isEqualTo(1);
+ assertThat(task.getDateStatusList()).hasSize(1);
assertThat(task.getDateStatusList().get(0).getStatus()).isEqualTo(TaskStatus.RECEIVED);
}
@Test
void shouldSetCurrentStatus() {
Task task = new Task(DAPP_NAME, COMMAND_LINE, 2);
- assertThat(task.getDateStatusList().size()).isEqualTo(1);
+ assertThat(task.getDateStatusList()).hasSize(1);
assertThat(task.getCurrentStatus()).isEqualTo(TaskStatus.RECEIVED);
task.changeStatus(TaskStatus.INITIALIZED);
- assertThat(task.getDateStatusList().size()).isEqualTo(2);
+ assertThat(task.getDateStatusList()).hasSize(2);
assertThat(task.getDateStatusList().get(0).getStatus()).isEqualTo(TaskStatus.RECEIVED);
assertThat(task.getDateStatusList().get(1).getStatus()).isEqualTo(TaskStatus.INITIALIZED);
assertThat(task.getCurrentStatus()).isEqualTo(TaskStatus.INITIALIZED);
task.changeStatus(TaskStatus.RUNNING);
- assertThat(task.getDateStatusList().size()).isEqualTo(3);
+ assertThat(task.getDateStatusList()).hasSize(3);
assertThat(task.getDateStatusList().get(2).getStatus()).isEqualTo(TaskStatus.RUNNING);
assertThat(task.getCurrentStatus()).isEqualTo(TaskStatus.RUNNING);
}
diff --git a/src/test/java/com/iexec/core/task/TaskTestsUtils.java b/src/test/java/com/iexec/core/task/TaskTestsUtils.java
index c2458591c..769a71a31 100644
--- a/src/test/java/com/iexec/core/task/TaskTestsUtils.java
+++ b/src/test/java/com/iexec/core/task/TaskTestsUtils.java
@@ -16,6 +16,7 @@
package com.iexec.core.task;
+import com.iexec.common.tee.TeeUtils;
import com.iexec.common.utils.BytesUtils;
import java.time.Instant;
@@ -32,7 +33,7 @@ public class TaskTestsUtils {
public final static String DAPP_NAME = "dappName";
public final static String COMMAND_LINE = "commandLine";
public final static String NO_TEE_TAG = BytesUtils.EMPTY_HEX_STRING_32;
- public final static String TEE_TAG = "0x0000000000000000000000000000000000000000000000000000000000000001";
+ public final static String TEE_TAG = TeeUtils.TEE_SCONE_ONLY_TAG; //any supported TEE tag
public final static String RESULT_LINK = "/ipfs/the_result_string";
public static Task getStubTask(long maxExecutionTime) {
diff --git a/src/test/java/com/iexec/core/task/listener/TaskListenerTest.java b/src/test/java/com/iexec/core/task/listener/TaskListenerTest.java
index 0dc3c4060..16a096af9 100644
--- a/src/test/java/com/iexec/core/task/listener/TaskListenerTest.java
+++ b/src/test/java/com/iexec/core/task/listener/TaskListenerTest.java
@@ -16,6 +16,7 @@
package com.iexec.core.task.listener;
+import com.iexec.common.lifecycle.purge.PurgeService;
import com.iexec.common.notification.TaskNotification;
import com.iexec.common.notification.TaskNotificationType;
import com.iexec.common.task.TaskAbortCause;
@@ -56,6 +57,8 @@ class TaskListenerTest {
private ReplicatesService replicatesService;
@Mock
private WorkerService workerService;
+ @Mock
+ private PurgeService purgeService;
@InjectMocks
private TaskListeners taskListeners;
@@ -157,6 +160,7 @@ void onTaskCompletedEvent() {
taskListeners.onTaskCompletedEvent(event);
verify(notificationService).sendTaskNotification(any());
verify(workerService).removeChainTaskIdFromWorker(CHAIN_TASK_ID, WALLET1);
+ verify(purgeService).purgeAllServices(CHAIN_TASK_ID);
// TODO capture args
}
@@ -174,6 +178,7 @@ void onTaskFailedEvent() {
.build()
);
verify(workerService).removeChainTaskIdFromWorker(CHAIN_TASK_ID, WALLET1);
+ verify(purgeService).purgeAllServices(CHAIN_TASK_ID);
}
@Test
@@ -190,5 +195,6 @@ void onTaskRunningFailedEvent() {
.build()
);
verify(workerService).removeChainTaskIdFromWorker(CHAIN_TASK_ID, WALLET1);
+ verify(purgeService).purgeAllServices(CHAIN_TASK_ID);
}
}
diff --git a/src/test/java/com/iexec/core/task/update/TaskUpdateManagerTest.java b/src/test/java/com/iexec/core/task/update/TaskUpdateManagerTest.java
index 4853433eb..5bd4ca9f7 100644
--- a/src/test/java/com/iexec/core/task/update/TaskUpdateManagerTest.java
+++ b/src/test/java/com/iexec/core/task/update/TaskUpdateManagerTest.java
@@ -22,6 +22,7 @@
import com.iexec.common.replicate.ReplicateStatus;
import com.iexec.common.replicate.ReplicateStatusModifier;
import com.iexec.common.replicate.ReplicateStatusUpdate;
+import com.iexec.common.tee.TeeUtils;
import com.iexec.common.utils.BytesUtils;
import com.iexec.common.utils.DateTimeUtils;
import com.iexec.core.chain.IexecHubService;
@@ -32,16 +33,19 @@
import com.iexec.core.replicate.Replicate;
import com.iexec.core.replicate.ReplicatesList;
import com.iexec.core.replicate.ReplicatesService;
+import com.iexec.core.sms.SmsService;
import com.iexec.core.task.Task;
import com.iexec.core.task.TaskService;
import com.iexec.core.task.TaskStatus;
-import com.iexec.core.sms.SmsService;
import com.iexec.core.task.event.PleaseUploadEvent;
import com.iexec.core.worker.Worker;
import com.iexec.core.worker.WorkerService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
-import org.mockito.*;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
import org.springframework.context.ApplicationEventPublisher;
import java.time.Instant;
@@ -55,10 +59,12 @@
import static com.iexec.core.task.TaskStatus.*;
import static com.iexec.core.task.TaskTestsUtils.*;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
class TaskUpdateManagerTest {
private final long maxExecutionTime = 60000;
+ private static final String smsUrl = "smsUrl";
@Mock
private WorkerService workerService;
@@ -307,6 +313,26 @@ void shouldNotUpdateReceived2InitializingSinceAfterContributionDeadline() {
assertThat(task.getCurrentStatus()).isEqualTo(RECEIVED);
}
+ @Test
+ void shouldNotUpdateReceived2InitializingSinceNoSmsClient() {
+ Task task = getStubTask(maxExecutionTime);
+ task.changeStatus(RECEIVED);
+ task.setChainTaskId(CHAIN_TASK_ID);
+
+ when(taskService.getTaskByChainTaskId(CHAIN_TASK_ID)).thenReturn(Optional.of(task));
+ when(iexecHubService.hasEnoughGas()).thenReturn(true);
+ when(iexecHubService.isTaskInUnsetStatusOnChain(CHAIN_DEAL_ID, 0)).thenReturn(true);
+ when(iexecHubService.isBeforeContributionDeadline(task.getChainDealId()))
+ .thenReturn(true);
+ when(taskService.updateTask(task)).thenReturn(Optional.of(task));
+ when(blockchainAdapterService.requestInitialize(CHAIN_DEAL_ID, 0)).thenReturn(Optional.of(CHAIN_TASK_ID));
+ when(smsService.getVerifiedSmsUrl(CHAIN_TASK_ID, task.getTag()))
+ .thenReturn(Optional.of(smsUrl));
+
+ taskUpdateManager.updateTask(CHAIN_TASK_ID);
+ assertThat(task.getCurrentStatus()).isEqualTo(FAILED);
+ }
+
@Test
void shouldUpdateInitializing2InitailizeFailedSinceChainTaskIdIsEmpty() {
Task task = getStubTask(maxExecutionTime);
@@ -343,7 +369,7 @@ void shouldUpdateInitializing2InitializeFailedSinceEnclaveChallengeIsEmpty() {
when(iexecHubService.getChainTask(CHAIN_TASK_ID)).thenReturn(Optional.of(ChainTask.builder()
.contributionDeadline(DateTimeUtils.addMinutesToDate(new Date(), 60).getTime())
.build()));
- when(smsService.getEnclaveChallenge(CHAIN_TASK_ID, false)).thenReturn(Optional.empty());
+ when(smsService.getEnclaveChallenge(CHAIN_TASK_ID, smsUrl)).thenReturn(Optional.empty());
taskUpdateManager.updateTask(task.getChainTaskId());
@@ -352,10 +378,12 @@ void shouldUpdateInitializing2InitializeFailedSinceEnclaveChallengeIsEmpty() {
}
@Test
- void shouldUpdateReceived2Initializing2Initialized() {
+ void shouldUpdateReceived2Initializing2InitializedOnStandard() {
Task task = getStubTask(maxExecutionTime);
+ String tag = NO_TEE_TAG;
task.changeStatus(RECEIVED);
task.setChainTaskId(CHAIN_TASK_ID);
+ task.setTag(tag);
when(taskService.getTaskByChainTaskId(CHAIN_TASK_ID)).thenReturn(Optional.of(task));
when(iexecHubService.hasEnoughGas()).thenReturn(true);
@@ -369,7 +397,7 @@ void shouldUpdateReceived2Initializing2Initialized() {
when(iexecHubService.getChainTask(CHAIN_TASK_ID)).thenReturn(Optional.of(ChainTask.builder()
.contributionDeadline(DateTimeUtils.addMinutesToDate(new Date(), 60).getTime())
.build()));
- when(smsService.getEnclaveChallenge(CHAIN_TASK_ID, false)).thenReturn(Optional.of(BytesUtils.EMPTY_ADDRESS));
+ when(smsService.getEnclaveChallenge(CHAIN_TASK_ID, null)).thenReturn(Optional.of(BytesUtils.EMPTY_ADDRESS));
taskUpdateManager.updateTask(CHAIN_TASK_ID);
assertThat(task.getChainDealId()).isEqualTo(CHAIN_DEAL_ID);
@@ -378,6 +406,82 @@ void shouldUpdateReceived2Initializing2Initialized() {
assertThat(task.getDateStatusList().get(task.getDateStatusList().size() - 3).getStatus()).isEqualTo(RECEIVED);
assertThat(task.getCurrentStatus()).isEqualTo(INITIALIZED);
assertThat(task.getEnclaveChallenge()).isEqualTo(BytesUtils.EMPTY_ADDRESS);
+ assertThat(task.getSmsUrl()).isNull();
+ verify(smsService, times(0)).getVerifiedSmsUrl(anyString(), anyString());
+ verify(taskService, times(2)).updateTask(task); //initializing & initialized
+ }
+
+
+ @Test
+ void shouldUpdateReceived2Initializing2InitializedOnTee() {
+ Task task = getStubTask(maxExecutionTime);
+ String tag = TeeUtils.TEE_GRAMINE_ONLY_TAG;
+ task.changeStatus(RECEIVED);
+ task.setChainTaskId(CHAIN_TASK_ID);
+ task.setTag(tag);// Any TEE would be fine
+
+ when(taskService.getTaskByChainTaskId(CHAIN_TASK_ID)).thenReturn(Optional.of(task));
+ when(iexecHubService.hasEnoughGas()).thenReturn(true);
+ when(iexecHubService.isTaskInUnsetStatusOnChain(CHAIN_DEAL_ID, 0)).thenReturn(true);
+ when(iexecHubService.isBeforeContributionDeadline(task.getChainDealId()))
+ .thenReturn(true);
+
+ when(taskService.updateTask(task)).thenReturn(Optional.of(task));
+ when(blockchainAdapterService.requestInitialize(CHAIN_DEAL_ID, 0)).thenReturn(Optional.of(CHAIN_TASK_ID));
+ when(blockchainAdapterService.isInitialized(CHAIN_TASK_ID)).thenReturn(Optional.of(true));
+ when(iexecHubService.getChainTask(CHAIN_TASK_ID)).thenReturn(Optional.of(ChainTask.builder()
+ .contributionDeadline(DateTimeUtils.addMinutesToDate(new Date(), 60).getTime())
+ .build()));
+ when(smsService.getVerifiedSmsUrl(CHAIN_TASK_ID, tag))
+ .thenReturn(Optional.of(smsUrl));
+ when(smsService.getEnclaveChallenge(CHAIN_TASK_ID, smsUrl)).thenReturn(Optional.of(BytesUtils.EMPTY_ADDRESS));
+
+ taskUpdateManager.updateTask(CHAIN_TASK_ID);
+ assertThat(task.getChainDealId()).isEqualTo(CHAIN_DEAL_ID);
+ assertThat(task.getDateStatusList().get(task.getDateStatusList().size() - 1).getStatus()).isEqualTo(INITIALIZED);
+ assertThat(task.getDateStatusList().get(task.getDateStatusList().size() - 2).getStatus()).isEqualTo(INITIALIZING);
+ assertThat(task.getDateStatusList().get(task.getDateStatusList().size() - 3).getStatus()).isEqualTo(RECEIVED);
+ assertThat(task.getCurrentStatus()).isEqualTo(INITIALIZED);
+ assertThat(task.getEnclaveChallenge()).isEqualTo(BytesUtils.EMPTY_ADDRESS);
+ assertThat(task.getSmsUrl()).isEqualTo(smsUrl);
+ verify(smsService, times(1)).getVerifiedSmsUrl(CHAIN_TASK_ID, tag);
+ verify(taskService, times(3)).updateTask(task); //save smsurl, INITIALIZING & INITIALIZED
+ }
+
+ @Test
+ void shouldNotUpdateReceived2Initializing2InitializedOnTeeSinceCannotRetrieveSmsUrl() {
+ Task task = getStubTask(maxExecutionTime);
+ String tag = TeeUtils.TEE_GRAMINE_ONLY_TAG;
+ task.changeStatus(RECEIVED);
+ task.setChainTaskId(CHAIN_TASK_ID);
+ task.setTag(tag);// Any TEE would be fine
+
+ when(taskService.getTaskByChainTaskId(CHAIN_TASK_ID)).thenReturn(Optional.of(task));
+ when(iexecHubService.hasEnoughGas()).thenReturn(true);
+ when(iexecHubService.isTaskInUnsetStatusOnChain(CHAIN_DEAL_ID, 0)).thenReturn(true);
+ when(iexecHubService.isBeforeContributionDeadline(task.getChainDealId()))
+ .thenReturn(true);
+
+ when(taskService.updateTask(task)).thenReturn(Optional.of(task));
+ when(blockchainAdapterService.requestInitialize(CHAIN_DEAL_ID, 0)).thenReturn(Optional.of(CHAIN_TASK_ID));
+ when(blockchainAdapterService.isInitialized(CHAIN_TASK_ID)).thenReturn(Optional.of(true));
+ when(iexecHubService.getChainTask(CHAIN_TASK_ID)).thenReturn(Optional.of(ChainTask.builder()
+ .contributionDeadline(DateTimeUtils.addMinutesToDate(new Date(), 60).getTime())
+ .build()));
+ when(smsService.getVerifiedSmsUrl(CHAIN_TASK_ID, tag)).thenReturn(Optional.empty());
+ when(smsService.getEnclaveChallenge(CHAIN_TASK_ID, null)).thenReturn(Optional.of(BytesUtils.EMPTY_ADDRESS));
+
+ taskUpdateManager.updateTask(CHAIN_TASK_ID);
+ assertThat(task.getChainDealId()).isEqualTo(CHAIN_DEAL_ID);
+ assertThat(task.getDateStatusList().get(task.getDateStatusList().size() - 1).getStatus()).isEqualTo(FAILED);
+ assertThat(task.getDateStatusList().get(task.getDateStatusList().size() - 2).getStatus()).isEqualTo(INITIALIZE_FAILED);
+ assertThat(task.getDateStatusList().get(task.getDateStatusList().size() - 3).getStatus()).isEqualTo(RECEIVED);
+ assertThat(task.getCurrentStatus()).isEqualTo(FAILED);
+ assertThat(task.getEnclaveChallenge()).isNull();
+ assertThat(task.getSmsUrl()).isNull();
+ verify(smsService, times(1)).getVerifiedSmsUrl(CHAIN_TASK_ID, tag);
+ verify(smsService, times(0)).getEnclaveChallenge(anyString(), anyString());
+ verify(taskService, times(2)).updateTask(task); // INITIALIZE_FAILED & FAILED
}
// Tests on initializing2Initialized transition
@@ -670,9 +774,7 @@ void shouldUpdateRunning2RunningFailedOn1Worker() {
// 1 replicate has tried to run the task:
// - R1 is in `COMPUTE_FAILED` status;
- Replicate replicate1 = new Replicate();
- replicate1.setWalletAddress(WALLET_WORKER_1);
- replicate1.setChainTaskId(CHAIN_TASK_ID);
+ Replicate replicate1 = new Replicate(WALLET_WORKER_1, CHAIN_TASK_ID);
replicate1.setStatusUpdateList(new ArrayList<>());
replicate1.updateStatus(ReplicateStatus.COMPUTE_FAILED, ReplicateStatusModifier.WORKER);
@@ -704,15 +806,11 @@ void shouldUpdateRunning2RunningFailedOn2Workers() {
// 2 replicates have tried to run the task:
// - R1 is in `COMPUTE_FAILED` status;
// - R2 is in `APP_DOWNLOAD_FAILED` status.
- Replicate replicate1 = new Replicate();
- replicate1.setWalletAddress(WALLET_WORKER_1);
- replicate1.setChainTaskId(CHAIN_TASK_ID);
+ Replicate replicate1 = new Replicate(WALLET_WORKER_1, CHAIN_TASK_ID);
replicate1.setStatusUpdateList(new ArrayList<>());
replicate1.updateStatus(ReplicateStatus.COMPUTE_FAILED, ReplicateStatusModifier.WORKER);
- Replicate replicate2 = new Replicate();
- replicate2.setWalletAddress(WALLET_WORKER_2);
- replicate2.setChainTaskId(CHAIN_TASK_ID);
+ Replicate replicate2 = new Replicate(WALLET_WORKER_2, CHAIN_TASK_ID);
replicate2.setStatusUpdateList(new ArrayList<>());
replicate2.updateStatus(ReplicateStatus.APP_DOWNLOAD_FAILED, ReplicateStatusModifier.WORKER);
@@ -743,9 +841,7 @@ void shouldNotUpdateRunning2RunningFailedOn1WorkerAsNonTeeTask() {
// 1 replicate has tried to run the task:
// - R1 is in `COMPUTE_FAILED` status;
- Replicate replicate1 = new Replicate();
- replicate1.setWalletAddress(WALLET_WORKER_1);
- replicate1.setChainTaskId(CHAIN_TASK_ID);
+ Replicate replicate1 = new Replicate(WALLET_WORKER_1, CHAIN_TASK_ID);
replicate1.setStatusUpdateList(new ArrayList<>());
replicate1.updateStatus(ReplicateStatus.COMPUTE_FAILED, ReplicateStatusModifier.WORKER);
@@ -776,15 +872,11 @@ void shouldNotUpdateRunning2RunningFailedOn2WorkersAsNonTeeTask() {
// 2 replicates have tried to run the task:
// - R1 is in `COMPUTE_FAILED` status;
// - R2 is in `APP_DOWNLOAD_FAILED` status.
- Replicate replicate1 = new Replicate();
- replicate1.setWalletAddress(WALLET_WORKER_1);
- replicate1.setChainTaskId(CHAIN_TASK_ID);
+ Replicate replicate1 = new Replicate(WALLET_WORKER_1, CHAIN_TASK_ID);
replicate1.setStatusUpdateList(new ArrayList<>());
replicate1.updateStatus(ReplicateStatus.COMPUTE_FAILED, ReplicateStatusModifier.WORKER);
- Replicate replicate2 = new Replicate();
- replicate2.setWalletAddress(WALLET_WORKER_2);
- replicate2.setChainTaskId(CHAIN_TASK_ID);
+ Replicate replicate2 = new Replicate(WALLET_WORKER_2, CHAIN_TASK_ID);
replicate2.setStatusUpdateList(new ArrayList<>());
replicate2.updateStatus(ReplicateStatus.APP_DOWNLOAD_FAILED, ReplicateStatusModifier.WORKER);
@@ -815,15 +907,11 @@ void shouldNotUpdateRunning2AllWorkersFailedSinceOneStillComputing() {
// 2 replicates have tried to run the task:
// - R1 is in `COMPUTE_FAILED` status;
// - R2 is in `COMPUTING` status.
- Replicate replicate1 = new Replicate();
- replicate1.setWalletAddress(WALLET_WORKER_1);
- replicate1.setChainTaskId(CHAIN_TASK_ID);
+ Replicate replicate1 = new Replicate(WALLET_WORKER_1, CHAIN_TASK_ID);
replicate1.setStatusUpdateList(new ArrayList<>());
replicate1.updateStatus(ReplicateStatus.COMPUTE_FAILED, ReplicateStatusModifier.WORKER);
- Replicate replicate2 = new Replicate();
- replicate2.setWalletAddress(WALLET_WORKER_2);
- replicate2.setChainTaskId(CHAIN_TASK_ID);
+ Replicate replicate2 = new Replicate(WALLET_WORKER_2, CHAIN_TASK_ID);
replicate2.setStatusUpdateList(new ArrayList<>());
replicate2.updateStatus(ReplicateStatus.COMPUTING, ReplicateStatusModifier.WORKER);
@@ -855,15 +943,11 @@ void shouldNotUpdateRunning2AllWorkersFailedSinceOneHasReachedComputed() {
// - R1 is in `COMPUTE_FAILED` status;
// - R2 is in `CONTRIBUTE_FAILED` status.
// Worker of R2 has been lost.
- Replicate replicate1 = new Replicate();
- replicate1.setWalletAddress(WALLET_WORKER_1);
- replicate1.setChainTaskId(CHAIN_TASK_ID);
+ Replicate replicate1 = new Replicate(WALLET_WORKER_1, CHAIN_TASK_ID);
replicate1.setStatusUpdateList(new ArrayList<>());
replicate1.updateStatus(ReplicateStatus.COMPUTE_FAILED, ReplicateStatusModifier.WORKER);
- Replicate replicate2 = new Replicate();
- replicate2.setWalletAddress(WALLET_WORKER_2);
- replicate2.setChainTaskId(CHAIN_TASK_ID);
+ Replicate replicate2 = new Replicate(WALLET_WORKER_2, CHAIN_TASK_ID);
replicate2.setStatusUpdateList(new ArrayList<>());
replicate2.updateStatus(ReplicateStatus.CONTRIBUTE_FAILED, ReplicateStatusModifier.WORKER);
@@ -892,9 +976,7 @@ void shouldNotUpdateRunning2AllWorkersFailedSinceOneStillHasToBeLaunched() {
// 1 replicates have tried to run the task and 1 is still to be run:
// - R1 is in `COMPUTE_FAILED` status;
// - R2 has not started yet.
- Replicate replicate1 = new Replicate();
- replicate1.setWalletAddress(WALLET_WORKER_1);
- replicate1.setChainTaskId(CHAIN_TASK_ID);
+ Replicate replicate1 = new Replicate(WALLET_WORKER_1, CHAIN_TASK_ID);
replicate1.setStatusUpdateList(new ArrayList<>());
replicate1.updateStatus(ReplicateStatus.COMPUTE_FAILED, ReplicateStatusModifier.WORKER);
diff --git a/src/test/java/com/iexec/core/task/update/TaskUpdateRequestManagerTests.java b/src/test/java/com/iexec/core/task/update/TaskUpdateRequestManagerTests.java
index 6394de573..d8543b48e 100644
--- a/src/test/java/com/iexec/core/task/update/TaskUpdateRequestManagerTests.java
+++ b/src/test/java/com/iexec/core/task/update/TaskUpdateRequestManagerTests.java
@@ -119,7 +119,7 @@ void shouldNotUpdateAtTheSameTime() {
.timeout(30, TimeUnit.SECONDS)
.until(() -> callsOrder.size() == callsPerUpdate * updates.size());
- Assertions.assertThat(callsOrder.size()).isEqualTo(callsPerUpdate * updates.size());
+ Assertions.assertThat(callsOrder).hasSize(callsPerUpdate * updates.size());
// We loop through calls order and see if all calls for a given update have finished
// before another update starts for this task.
diff --git a/src/test/java/com/iexec/core/utils/version/VersionServiceTest.java b/src/test/java/com/iexec/core/utils/version/VersionServiceTests.java
similarity index 97%
rename from src/test/java/com/iexec/core/utils/version/VersionServiceTest.java
rename to src/test/java/com/iexec/core/utils/version/VersionServiceTests.java
index 6b1589fed..ac7d1f8cb 100644
--- a/src/test/java/com/iexec/core/utils/version/VersionServiceTest.java
+++ b/src/test/java/com/iexec/core/utils/version/VersionServiceTests.java
@@ -11,7 +11,7 @@
import org.mockito.MockitoAnnotations;
import org.springframework.boot.info.BuildProperties;
-public class VersionServiceTest {
+class VersionServiceTests {
@Mock
private BuildProperties buildProperties;
diff --git a/src/test/java/com/iexec/core/worker/WorkerControllerTests.java b/src/test/java/com/iexec/core/worker/WorkerControllerTests.java
index 7ec95570d..5ba24c968 100644
--- a/src/test/java/com/iexec/core/worker/WorkerControllerTests.java
+++ b/src/test/java/com/iexec/core/worker/WorkerControllerTests.java
@@ -14,9 +14,6 @@
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
import java.util.List;
import java.util.Optional;
@@ -162,10 +159,10 @@ void shouldNotGetChallengeSinceNotAllowedToJoin() {
//region getToken
@Test
- void shouldGetToken() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException {
+ void shouldGetToken() {
when(workerService.isAllowedToJoin(WALLET)).thenReturn(true);
when(challengeService.getChallenge(WALLET)).thenReturn(CHALLENGE);
- when(jwtTokenProvider.createToken(WALLET)).thenReturn(TOKEN);
+ when(jwtTokenProvider.getOrCreateToken(WALLET)).thenReturn(TOKEN);
ResponseEntity response = workerController.getToken(WALLET, SIGN);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}
diff --git a/src/test/java/com/iexec/core/worker/WorkerServiceTests.java b/src/test/java/com/iexec/core/worker/WorkerServiceTests.java
index 68147f609..90067e8bb 100644
--- a/src/test/java/com/iexec/core/worker/WorkerServiceTests.java
+++ b/src/test/java/com/iexec/core/worker/WorkerServiceTests.java
@@ -65,8 +65,7 @@ void shouldGetWorker() {
when(workerRepository.findByWalletAddress(walletAddress)).thenReturn(Optional.of(existingWorker));
Optional foundWorker = workerService.getWorker(walletAddress);
- assertThat(foundWorker.isPresent()).isTrue();
- assertThat(foundWorker.get()).isEqualTo(existingWorker);
+ assertThat(foundWorker).contains(existingWorker);
}
// addWorker
@@ -175,15 +174,15 @@ void shouldUpdateLastAlive() throws ParseException {
Date now = new Date();
long duration = now.getTime() - argument.getValue().getLastAliveDate().getTime();
long diffInSeconds = TimeUnit.MILLISECONDS.toSeconds(duration);
- assertThat(diffInSeconds).isEqualTo(0);
+ assertThat(diffInSeconds).isZero();
// check object returned by the method
- assertThat(updatedWorker.isPresent()).isTrue();
+ assertThat(updatedWorker).isPresent();
assertThat(updatedWorker.get().getId()).isEqualTo(worker.getId());
assertThat(updatedWorker.get().getName()).isEqualTo(worker.getName());
duration = now.getTime() - updatedWorker.get().getLastAliveDate().getTime();
diffInSeconds = TimeUnit.MILLISECONDS.toSeconds(duration);
- assertThat(diffInSeconds).isEqualTo(0);
+ assertThat(diffInSeconds).isZero();
}
@Test
@@ -192,7 +191,7 @@ void shouldNotFindWorkerForUpdateLastAlive() {
when(workerRepository.findByWalletAddress(walletAddress)).thenReturn(Optional.empty());
Optional optional = workerService.updateLastAlive(walletAddress);
- assertThat(optional.isPresent()).isFalse();
+ assertThat(optional).isEmpty();
}
// isWorkerAllowedToAskReplicate
@@ -270,11 +269,11 @@ void shouldAddTaskIdToWorker(){
when(workerRepository.save(existingWorker)).thenReturn(existingWorker);
Optional addedWorker = workerService.addChainTaskIdToWorker("task3", walletAddress);
- assertThat(addedWorker.isPresent()).isTrue();
+ assertThat(addedWorker).isPresent();
Worker worker = addedWorker.get();
- assertThat(worker.getParticipatingChainTaskIds().size()).isEqualTo(3);
+ assertThat(worker.getParticipatingChainTaskIds()).hasSize(3);
assertThat(worker.getParticipatingChainTaskIds().get(2)).isEqualTo("task3");
- assertThat(worker.getComputingChainTaskIds().size()).isEqualTo(3);
+ assertThat(worker.getComputingChainTaskIds()).hasSize(3);
assertThat(worker.getComputingChainTaskIds().get(2)).isEqualTo("task3");
}
@@ -282,7 +281,7 @@ void shouldAddTaskIdToWorker(){
void shouldNotAddTaskIdToWorker(){
when(workerRepository.findByWalletAddress(Mockito.anyString())).thenReturn(Optional.empty());
Optional addedWorker = workerService.addChainTaskIdToWorker("task1", "0x1a69b2eb604db8eba185df03ea4f5288dcbbd248");
- assertThat(addedWorker.isPresent()).isFalse();
+ assertThat(addedWorker).isEmpty();
}
// getChainTaskIds
@@ -350,11 +349,11 @@ void shouldRemoveTaskIdFromWorker(){
when(workerRepository.save(existingWorker)).thenReturn(existingWorker);
Optional removedWorker = workerService.removeChainTaskIdFromWorker("task2", walletAddress);
- assertThat(removedWorker.isPresent()).isTrue();
+ assertThat(removedWorker).isPresent();
Worker worker = removedWorker.get();
- assertThat(worker.getParticipatingChainTaskIds().size()).isEqualTo(1);
+ assertThat(worker.getParticipatingChainTaskIds()).hasSize(1);
assertThat(worker.getParticipatingChainTaskIds().get(0)).isEqualTo("task1");
- assertThat(worker.getComputingChainTaskIds().size()).isEqualTo(1);
+ assertThat(worker.getComputingChainTaskIds()).hasSize(1);
assertThat(worker.getComputingChainTaskIds().get(0)).isEqualTo("task1");
}
@@ -362,7 +361,7 @@ void shouldRemoveTaskIdFromWorker(){
void shouldNotRemoveTaskIdWorkerNotFound(){
when(workerRepository.findByWalletAddress(Mockito.anyString())).thenReturn(Optional.empty());
Optional addedWorker = workerService.removeChainTaskIdFromWorker("task1", "0x1a69b2eb604db8eba185df03ea4f5288dcbbd248");
- assertThat(addedWorker.isPresent()).isFalse();
+ assertThat(addedWorker).isEmpty();
}
@Test
@@ -387,12 +386,12 @@ void shouldNotRemoveAnythingSinceTaskIdNotFound(){
when(workerRepository.save(existingWorker)).thenReturn(existingWorker);
Optional removedWorker = workerService.removeChainTaskIdFromWorker("dummyTaskId", walletAddress);
- assertThat(removedWorker.isPresent()).isTrue();
+ assertThat(removedWorker).isPresent();
Worker worker = removedWorker.get();
- assertThat(worker.getParticipatingChainTaskIds().size()).isEqualTo(2);
+ assertThat(worker.getParticipatingChainTaskIds()).hasSize(2);
assertThat(worker.getParticipatingChainTaskIds()).isEqualTo(participatingIds);
- assertThat(worker.getComputingChainTaskIds().size()).isEqualTo(2);
+ assertThat(worker.getComputingChainTaskIds()).hasSize(2);
assertThat(worker.getComputingChainTaskIds()).isEqualTo(computingIds);
}
@@ -418,12 +417,12 @@ void shouldRemoveComputedChainTaskIdFromWorker(){
when(workerRepository.save(existingWorker)).thenReturn(existingWorker);
Optional removedWorker = workerService.removeComputedChainTaskIdFromWorker("task1", walletAddress);
- assertThat(removedWorker.isPresent()).isTrue();
+ assertThat(removedWorker).isPresent();
Worker worker = removedWorker.get();
- assertThat(worker.getParticipatingChainTaskIds().size()).isEqualTo(2);
+ assertThat(worker.getParticipatingChainTaskIds()).hasSize(2);
assertThat(worker.getParticipatingChainTaskIds()).isEqualTo(participatingIds);
- assertThat(worker.getComputingChainTaskIds().size()).isEqualTo(1);
+ assertThat(worker.getComputingChainTaskIds()).hasSize(1);
assertThat(worker.getComputingChainTaskIds().get(0)).isEqualTo("task2");
}
@@ -449,7 +448,7 @@ void shouldNotRemoveComputedChainTaskIdFromWorkerSinceWorkerNotFound(){
when(workerRepository.save(existingWorker)).thenReturn(existingWorker);
Optional removedWorker = workerService.removeComputedChainTaskIdFromWorker("task1", walletAddress);
- assertThat(removedWorker.isPresent()).isFalse();
+ assertThat(removedWorker).isEmpty();
}
@Test
@@ -474,12 +473,12 @@ void shouldNotRemoveComputedChainTaskIdFromWorkerSinceChainTaskIdNotFound(){
when(workerRepository.save(existingWorker)).thenReturn(existingWorker);
Optional removedWorker = workerService.removeComputedChainTaskIdFromWorker("dummyTaskId", walletAddress);
- assertThat(removedWorker.isPresent()).isTrue();
+ assertThat(removedWorker).isPresent();
Worker worker = removedWorker.get();
- assertThat(worker.getParticipatingChainTaskIds().size()).isEqualTo(2);
+ assertThat(worker.getParticipatingChainTaskIds()).hasSize(2);
assertThat(worker.getParticipatingChainTaskIds()).isEqualTo(participatingIds);
- assertThat(worker.getComputingChainTaskIds().size()).isEqualTo(2);
+ assertThat(worker.getComputingChainTaskIds()).hasSize(2);
assertThat(worker.getComputingChainTaskIds()).isEqualTo(computingIds);
}
@@ -500,8 +499,9 @@ void shouldGetLostWorkers() {
assertThat(diffInMinutes).isEqualTo(1);
// check the claimedLostWorkers are actually the lostWorkers
- assertThat(claimedLostWorkers.size()).isEqualTo(2);
- assertThat(claimedLostWorkers).isEqualTo(lostWorkers);
+ assertThat(claimedLostWorkers)
+ .hasSize(2)
+ .isEqualTo(lostWorkers);
}
@Test
@@ -529,8 +529,9 @@ void shouldGetAliveWorkers() {
assertThat(diffInMinutes).isEqualTo(1);
// check the claimedAliveWorkers are actually the aliveWorkers
- assertThat(claimedAliveWorkers.size()).isEqualTo(1);
- assertThat(claimedAliveWorkers).isEqualTo(aliveWorkers);
+ assertThat(claimedAliveWorkers)
+ .hasSize(1)
+ .isEqualTo(aliveWorkers);
}
@Test
@@ -631,13 +632,13 @@ void shouldGetZeroAvailableCpuIfWorkerAlreadyFull() {
Arrays.asList("task1", "task2", "task3", "task4"));
when(workerRepository.findByLastAliveDateAfter(any())).thenReturn(Arrays.asList(worker1, worker2));
- assertThat(workerService.getAliveAvailableCpu()).isEqualTo(0);
+ assertThat(workerService.getAliveAvailableCpu()).isZero();
}
@Test
void shouldGetZeroAvailableCpuIfNoWorkerAlive() {
when(workerRepository.findByLastAliveDateAfter(any())).thenReturn(Collections.emptyList());
- assertThat(workerService.getAliveAvailableCpu()).isEqualTo(0);
+ assertThat(workerService.getAliveAvailableCpu()).isZero();
}
// getAliveTotalCpu