diff --git a/.gitignore b/.gitignore
index efe2cd61d..6243070d1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -329,6 +329,9 @@ scripts/dockerize/dockerfiles
/jdk_25_maven/cs/rest/jasper/target/
/jdk_25_maven/em/external/rest/jasper/target/
/jdk_25_maven/em/embedded/rest/jasper/target/
+/jdk_21_maven/cs/rest/redis-sample/target/
+/jdk_21_maven/em/external/rest/redis-sample/target/
+/jdk_21_maven/em/embedded/rest/redis-sample/target/
/jdk_11_maven/em/embedded/rest/tracking-system/target/
/jdk_11_maven/em/external/rest/tracking-system/target/
/jdk_17_maven/em/embedded/rest/tiltaksgjennomforing/target/
diff --git a/README.md b/README.md
index 8238051c0..60e1dc27b 100644
--- a/README.md
+++ b/README.md
@@ -85,7 +85,7 @@ How to setup authentication information, based on the current content of the ini
Auth configuration files can found in the [auth](auth) folder.
-### REST: Java/Kotlin (38)
+### REST: Java/Kotlin (39)
* **Bibliothek** (MIT), [jdk_17_gradle/cs/rest/bibliothek](jdk_17_gradle/cs/rest/bibliothek), from [https://github.com/PaperMC/bibliothek](https://github.com/PaperMC/bibliothek)
@@ -135,6 +135,8 @@ Auth configuration files can found in the [auth](auth) folder.
* **Quartz Manager** (Apache), [jdk_11_maven/cs/rest-gui/quartz-manager](jdk_11_maven/cs/rest-gui/quartz-manager), from [https://github.com/fabioformosa/quartz-manager](https://github.com/fabioformosa/quartz-manager)
+* **Redis Sample** (not-known license), [jdk_21_maven/cs/rest/redis-sample](jdk_21_maven/cs/rest/redis-sample), from [https://github.com/hendisantika/spring-boot-redis-sample](https://github.com/hendisantika/spring-boot-redis-sample)
+
* **Reservations API** (not-known license), [jdk_11_gradle/cs/rest/reservations-api](jdk_11_gradle/cs/rest/reservations-api), from [https://github.com/cyrilgavala/reservations-api](https://github.com/cyrilgavala/reservations-api)
* **Restcountries** (MPL), [jdk_8_maven/cs/rest/original/restcountries](jdk_8_maven/cs/rest/original/restcountries), from [https://github.com/apilayer/restcountries](https://github.com/apilayer/restcountries)
diff --git a/dockerfiles/redis-sample.dockerfile b/dockerfiles/redis-sample.dockerfile
new file mode 100644
index 000000000..e6429223a
--- /dev/null
+++ b/dockerfiles/redis-sample.dockerfile
@@ -0,0 +1,17 @@
+FROM amazoncorretto:21-alpine-jdk
+
+COPY ./dist/redis-sample-sut.jar .
+COPY ./dist/jacocoagent.jar .
+
+
+
+#ENV TOOL="undefined"
+#ENV RUN="0"
+
+ENTRYPOINT \
+ java \
+# unfortunately dumponexit is completely unreliable in Docker :(
+# -javaagent:jacocoagent.jar=destfile=./jacoco/redis-sample__${TOOL}__${RUN}__jacoco.exec,append=false,dumponexit=true \
+ -javaagent:jacocoagent.jar=output=tcpserver,address=*,port=6300,append=false,dumponexit=false \
+ -jar redis-sample-sut.jar \
+ --server.port=8080 --spring.data.redis.host=db --spring.data.redis.port=6379 --spring.data.redis.password=53cret --spring.autoconfigure.exclude=org.springframework.boot.security.autoconfigure.web.servlet.ServletWebSecurityAutoConfiguration --app.numberOfRatings=5000 --app.ratingStars=5
\ No newline at end of file
diff --git a/dockerfiles/redis-sample.yaml b/dockerfiles/redis-sample.yaml
new file mode 100644
index 000000000..9defd496a
--- /dev/null
+++ b/dockerfiles/redis-sample.yaml
@@ -0,0 +1,32 @@
+services:
+ mitmproxy:
+ image: mitmproxy/mitmproxy:10.2.4
+ user: "0:0"
+ environment:
+ MITM_LOG_DIR: /custom-logs
+ MITM_LOG_FILE: ${MITM_LOG_FILE:-minlog.csv}
+ command: >
+ mitmdump
+ --mode reverse:http://sut-redis-sample:8080
+ --listen-host 0.0.0.0
+ --listen-port 8080
+ --set keep_host_header=true
+ -s /addons/minlog.py
+ volumes:
+ - ${HOST_LOG_DIR:-./mitm-logs}:/custom-logs
+ - ./addons:/addons:ro
+ ports:
+ - "${HOST_PORT:-8080}:8080"
+ depends_on:
+ - sut-redis-sample
+ sut-redis-sample:
+ build:
+ dockerfile: ./dockerfiles/redis-sample.dockerfile
+ context: ..
+ environment:
+ AUTH_PORT: ${AUTH_PORT:-8081}
+ ports:
+ - "${JACOCO_PORT:-6300}:6300"
+ db:
+ image: redis:7.4-alpine
+ command: redis-server --requirepass 53cret
\ No newline at end of file
diff --git a/experiments/wb-exp.py b/experiments/wb-exp.py
index 572a119c2..f4afaa39a 100644
--- a/experiments/wb-exp.py
+++ b/experiments/wb-exp.py
@@ -201,6 +201,7 @@ def __init__(self, name, platform):
Sut("ohsome-api", JDK_17),
Sut("pay-publicapi",JDK_11),
Sut("person-controller",JDK_21),
+ Sut("redis-sample", JDK_21),
Sut("proxyprint", JDK_8),
Sut("quartz-manager", JDK_11),
Sut("reservations-api", JDK_11),
diff --git a/jdk_21_maven/cs/rest/pom.xml b/jdk_21_maven/cs/rest/pom.xml
index 3cb72b60b..ada40d03e 100644
--- a/jdk_21_maven/cs/rest/pom.xml
+++ b/jdk_21_maven/cs/rest/pom.xml
@@ -14,6 +14,7 @@
person-controller
+ redis-sample
diff --git a/jdk_21_maven/cs/rest/redis-sample/pom.xml b/jdk_21_maven/cs/rest/redis-sample/pom.xml
index c4330e501..62e35db3b 100644
--- a/jdk_21_maven/cs/rest/redis-sample/pom.xml
+++ b/jdk_21_maven/cs/rest/redis-sample/pom.xml
@@ -83,6 +83,13 @@
2.2.4
test
+
+
+ org.springdoc
+ springdoc-openapi-starter-webmvc-ui
+ 3.1.0
+
+
@@ -107,6 +114,12 @@
org.springframework.boot
spring-boot-maven-plugin
+
+
+ redis-sample
+ sut
+
org.projectlombok
diff --git a/jdk_21_maven/cs/rest/redis-sample/src/main/java/id/my/hendisantika/springbootredissample/boot/CreateBooks.java b/jdk_21_maven/cs/rest/redis-sample/src/main/java/id/my/hendisantika/springbootredissample/boot/CreateBooks.java
index 0d9808476..4430629c1 100644
--- a/jdk_21_maven/cs/rest/redis-sample/src/main/java/id/my/hendisantika/springbootredissample/boot/CreateBooks.java
+++ b/jdk_21_maven/cs/rest/redis-sample/src/main/java/id/my/hendisantika/springbootredissample/boot/CreateBooks.java
@@ -12,6 +12,7 @@
import org.springframework.core.annotation.Order;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.stereotype.Component;
import java.io.File;
@@ -51,9 +52,13 @@ public void run(String... args) throws Exception {
TypeReference> typeReference = new TypeReference<>() {
};
- Resource resource = resourceLoader.getResource("classpath:/data/books/");
- File directory = resource.getFile();
- File[] files = directory.listFiles((dir, name) -> name.endsWith(".json"));
+ // MODIFIED
+ // In the packaged jar getFile() throws FileNotFoundException: class path resource
+ // [data/books/] cannot be resolved to absolute file path -> startup dies.
+ File[] files = Arrays.stream(new PathMatchingResourcePatternResolver()
+ .getResources("classpath*:/data/books/*.json"))
+ .map(r -> new File(r.getFilename())).toArray(File[]::new);
+ // MODIFIED
if (files == null || files.length == 0) {
log.warn("No JSON files found in /data/books/ directory.");
diff --git a/jdk_21_maven/em/embedded/rest/pom.xml b/jdk_21_maven/em/embedded/rest/pom.xml
index 143794554..ee9b2fbe5 100644
--- a/jdk_21_maven/em/embedded/rest/pom.xml
+++ b/jdk_21_maven/em/embedded/rest/pom.xml
@@ -13,6 +13,7 @@
person-controller
+ redis-sample
diff --git a/jdk_21_maven/em/embedded/rest/redis-sample/pom.xml b/jdk_21_maven/em/embedded/rest/redis-sample/pom.xml
new file mode 100644
index 000000000..06d3f0432
--- /dev/null
+++ b/jdk_21_maven/em/embedded/rest/redis-sample/pom.xml
@@ -0,0 +1,51 @@
+
+
+
+ 4.0.0
+
+ evomaster-benchmark-jdk21-em-embedded-rest-redis-sample
+ jar
+
+
+ org.evomaster
+ evomaster-benchmark-jdk21-em-embedded-rest
+ 4.3.1-SNAPSHOT
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-dependencies
+ 4.1.0
+ pom
+ import
+
+
+
+
+
+
+
+ id.my.hendisantika
+ spring-boot-redis-sample
+ 0.0.1-SNAPSHOT
+
+
+
+ org.testcontainers
+ testcontainers
+ compile
+
+
+
+ io.lettuce
+ lettuce-core
+
+
+
+
diff --git a/jdk_21_maven/em/embedded/rest/redis-sample/src/main/java/em/embedded/redis/sample/EmbeddedEvoMasterController.java b/jdk_21_maven/em/embedded/rest/redis-sample/src/main/java/em/embedded/redis/sample/EmbeddedEvoMasterController.java
new file mode 100644
index 000000000..fe63293d3
--- /dev/null
+++ b/jdk_21_maven/em/embedded/rest/redis-sample/src/main/java/em/embedded/redis/sample/EmbeddedEvoMasterController.java
@@ -0,0 +1,171 @@
+package em.embedded.redis.sample;
+
+import id.my.hendisantika.springbootredissample.SpringBootRedisSampleApplication;
+import org.evomaster.client.java.controller.EmbeddedSutController;
+import org.evomaster.client.java.controller.InstrumentedSutStarter;
+import org.evomaster.client.java.controller.api.dto.auth.AuthenticationDto;
+import org.evomaster.client.java.controller.api.dto.SutInfoDto;
+import org.evomaster.client.java.sql.DbSpecification;
+import org.evomaster.client.java.controller.problem.ProblemInfo;
+import org.evomaster.client.java.controller.problem.RestProblem;
+import org.springframework.boot.SpringApplication;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.testcontainers.containers.GenericContainer;
+import io.lettuce.core.RedisClient;
+import io.lettuce.core.api.StatefulRedisConnection;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Class used to start/stop the SUT. This will be controller by the EvoMaster process
+ */
+public class EmbeddedEvoMasterController extends EmbeddedSutController {
+
+ private static final String REDIS_VERSION = "7.4-alpine";
+
+ private static final int REDIS_PORT = 6379;
+
+ private static final String REDIS_PASSWORD = "53cret";
+
+ private static final String SECURITY_EXCLUDE =
+ "org.springframework.boot.security.autoconfigure.web.servlet.ServletWebSecurityAutoConfiguration";
+
+ private static final int NUMBER_OF_RATINGS = 5000;
+
+ private static final int RATING_STARS = 5;
+
+ private static final String CACHE_KEY_PATTERN = "id.my.hendisantika.springbootredissample.*Cache::*";
+
+ private static final GenericContainer redis = new GenericContainer("redis:" + REDIS_VERSION)
+ .withCommand("redis-server", "--requirepass", REDIS_PASSWORD)
+ .withExposedPorts(REDIS_PORT);
+
+
+ public static void main(String[] args) {
+
+ int port = 40100;
+ if (args.length > 0) {
+ port = Integer.parseInt(args[0]);
+ }
+
+ EmbeddedEvoMasterController controller = new EmbeddedEvoMasterController(port);
+ InstrumentedSutStarter starter = new InstrumentedSutStarter(controller);
+
+ starter.start();
+ }
+
+
+ private ConfigurableApplicationContext ctx;
+
+ private RedisClient redisClient;
+
+ private StatefulRedisConnection redisConnection;
+
+ public EmbeddedEvoMasterController() {
+ this(0);
+ }
+
+ public EmbeddedEvoMasterController(int port) {
+ setControllerPort(port);
+ }
+
+
+ @Override
+ public String startSut() {
+
+ redis.start();
+ redisClient = RedisClient.create("redis://:" + REDIS_PASSWORD + "@"
+ + redis.getHost() + ":" + redis.getMappedPort(REDIS_PORT));
+ redisConnection = redisClient.connect();
+
+ ctx = SpringApplication.run(SpringBootRedisSampleApplication.class, new String[]{
+ "--server.port=0",
+ "--spring.data.redis.host=" + redis.getHost(),
+ "--spring.data.redis.port=" + redis.getMappedPort(REDIS_PORT),
+ "--spring.data.redis.password=" + REDIS_PASSWORD,
+ "--spring.autoconfigure.exclude=" + SECURITY_EXCLUDE,
+ "--app.numberOfRatings=" + NUMBER_OF_RATINGS,
+ "--app.ratingStars=" + RATING_STARS
+ });
+
+ return "http://localhost:" + getSutPort();
+ }
+
+ protected int getSutPort() {
+ return (Integer) ((Map) ctx.getEnvironment()
+ .getPropertySources().get("server.ports").getSource())
+ .get("local.server.port");
+ }
+
+
+ @Override
+ public boolean isSutRunning() {
+ return ctx != null && ctx.isRunning();
+ }
+
+ @Override
+ public void stopSut() {
+
+ if (ctx != null) {
+ ctx.stop();
+ ctx.close();
+ ctx = null;
+ }
+
+ if (redisConnection != null) {
+ redisConnection.close();
+ redisClient.shutdown();
+ redisConnection = null;
+ redisClient = null;
+ }
+
+ redis.stop();
+ }
+
+ @Override
+ public String getPackagePrefixesToCover() {
+ return "id.my.hendisantika.springbootredissample.";
+ }
+
+ /*
+ Only the Spring Cache entries accumulate: the API is read-only, and the seeded data is
+ written once at startup by runners guarded on an empty repository, so it must survive.
+ */
+ @Override
+ public void resetStateOfSUT() {
+ if (redisConnection == null) {
+ return;
+ }
+ List keys = redisConnection.sync().keys(CACHE_KEY_PATTERN);
+ if (!keys.isEmpty()) {
+ redisConnection.sync().del(keys.toArray(new String[0]));
+ }
+ }
+
+
+ @Override
+ public List getDbSpecifications() {
+ return null;
+ }
+
+
+ @Override
+ public List getInfoForAuthentication() {
+ return null;
+ }
+
+
+ @Override
+ public ProblemInfo getProblemInfo() {
+ return new RestProblem(
+ "http://localhost:" + getSutPort() + "/v3/api-docs",
+ null
+ );
+ }
+
+ @Override
+ public SutInfoDto.OutputFormat getPreferredOutputFormat() {
+ return SutInfoDto.OutputFormat.JAVA_JUNIT_5;
+ }
+}
diff --git a/jdk_21_maven/em/external/rest/pom.xml b/jdk_21_maven/em/external/rest/pom.xml
index 4a511f300..3e059511d 100644
--- a/jdk_21_maven/em/external/rest/pom.xml
+++ b/jdk_21_maven/em/external/rest/pom.xml
@@ -14,6 +14,7 @@
person-controller
+ redis-sample
\ No newline at end of file
diff --git a/jdk_21_maven/em/external/rest/redis-sample/pom.xml b/jdk_21_maven/em/external/rest/redis-sample/pom.xml
new file mode 100644
index 000000000..91fb2b0cb
--- /dev/null
+++ b/jdk_21_maven/em/external/rest/redis-sample/pom.xml
@@ -0,0 +1,84 @@
+
+
+
+ 4.0.0
+
+ evomaster-benchmark-jdk21-em-external-rest-redis-sample
+ jar
+
+
+ org.evomaster
+ evomaster-benchmark-jdk21-em-external-rest
+ 4.3.1-SNAPSHOT
+
+
+
+
+
+
+ org.testcontainers
+ testcontainers
+ compile
+
+
+
+ io.lettuce
+ lettuce-core
+ 7.5.2.RELEASE
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+
+ 3.6.2
+
+
+ package
+
+ shade
+
+
+ redis-sample-evomaster-runner
+
+
+
+ em.external.redis.sample.ExternalEvoMasterController
+
+ org.evomaster.client.java.instrumentation.InstrumentingAgent
+
+ org.evomaster.client.java.instrumentation.InstrumentingAgent
+
+ true
+ true
+
+
+
+
+
+
+ org.slf4j
+ shaded.emb.org.slf4j
+
+
+ com.fasterxml.jackson.annotation
+ shaded.emb.com.fasterxml.jackson.annotation
+
+
+
+
+
+
+
+
+
diff --git a/jdk_21_maven/em/external/rest/redis-sample/src/main/java/em/external/redis/sample/ExternalEvoMasterController.java b/jdk_21_maven/em/external/rest/redis-sample/src/main/java/em/external/redis/sample/ExternalEvoMasterController.java
new file mode 100644
index 000000000..69afea8ec
--- /dev/null
+++ b/jdk_21_maven/em/external/rest/redis-sample/src/main/java/em/external/redis/sample/ExternalEvoMasterController.java
@@ -0,0 +1,225 @@
+package em.external.redis.sample;
+
+
+import org.evomaster.client.java.controller.ExternalSutController;
+import org.evomaster.client.java.controller.InstrumentedSutStarter;
+import org.evomaster.client.java.controller.api.dto.auth.AuthenticationDto;
+import org.evomaster.client.java.controller.api.dto.SutInfoDto;
+import org.evomaster.client.java.sql.DbSpecification;
+import org.evomaster.client.java.controller.problem.ProblemInfo;
+import org.evomaster.client.java.controller.problem.RestProblem;
+import org.testcontainers.containers.GenericContainer;
+import io.lettuce.core.RedisClient;
+import io.lettuce.core.api.StatefulRedisConnection;
+
+import java.util.List;
+
+public class ExternalEvoMasterController extends ExternalSutController {
+
+ private static final int DEFAULT_CONTROLLER_PORT = 40100;
+
+ private static final int DEFAULT_SUT_PORT = 12345;
+
+ private static final String REDIS_VERSION = "7.4-alpine";
+
+ private static final int REDIS_PORT = 6379;
+
+ private static final String REDIS_PASSWORD = "53cret";
+
+ private static final String SECURITY_EXCLUDE =
+ "org.springframework.boot.security.autoconfigure.web.servlet.ServletWebSecurityAutoConfiguration";
+
+ private static final int NUMBER_OF_RATINGS = 5000;
+
+ private static final int RATING_STARS = 5;
+
+ private static final String CACHE_KEY_PATTERN = "id.my.hendisantika.springbootredissample.*Cache::*";
+
+ private static final GenericContainer redis = new GenericContainer("redis:" + REDIS_VERSION)
+ .withCommand("redis-server", "--requirepass", REDIS_PASSWORD)
+ .withExposedPorts(REDIS_PORT);
+
+
+ public static void main(String[] args) {
+
+ int controllerPort = DEFAULT_CONTROLLER_PORT;
+ if (args.length > 0) {
+ controllerPort = Integer.parseInt(args[0]);
+ }
+ int sutPort = DEFAULT_SUT_PORT;
+ if (args.length > 1) {
+ sutPort = Integer.parseInt(args[1]);
+ }
+ String jarLocation = "cs/rest/redis-sample/target";
+ if (args.length > 2) {
+ jarLocation = args[2];
+ }
+ if (!jarLocation.endsWith(".jar")) {
+ jarLocation += "/redis-sample-sut.jar";
+ }
+
+ int timeoutSeconds = 120;
+ if (args.length > 3) {
+ timeoutSeconds = Integer.parseInt(args[3]);
+ }
+
+ String command = "java";
+ if (args.length > 4) {
+ command = args[4];
+ }
+
+ ExternalEvoMasterController controller =
+ new ExternalEvoMasterController(controllerPort, jarLocation, sutPort, timeoutSeconds, command);
+
+ controller.setNeedsJdk17Options(true);
+
+ InstrumentedSutStarter starter = new InstrumentedSutStarter(controller);
+
+ starter.start();
+ }
+
+
+ private final int timeoutSeconds;
+
+ private final int sutPort;
+
+ private String jarLocation;
+
+ private RedisClient redisClient;
+
+ private StatefulRedisConnection redisConnection;
+
+ public ExternalEvoMasterController() {
+ this(DEFAULT_CONTROLLER_PORT, "../target/redis-sample-sut.jar", DEFAULT_SUT_PORT, 120, "java");
+ }
+
+ public ExternalEvoMasterController(String jarLocation) {
+ this();
+ this.jarLocation = jarLocation;
+ }
+
+ public ExternalEvoMasterController(int controllerPort, String jarLocation, int sutPort, int timeoutSeconds, String command) {
+ this.sutPort = sutPort;
+ this.jarLocation = jarLocation;
+ this.timeoutSeconds = timeoutSeconds;
+
+ setControllerPort(controllerPort);
+ setJavaCommand(command);
+ }
+
+ @Override
+ public String[] getInputParameters() {
+ return new String[]{
+ "--server.port=" + sutPort,
+ "--spring.data.redis.host=" + redis.getHost(),
+ "--spring.data.redis.port=" + redis.getMappedPort(REDIS_PORT),
+ "--spring.data.redis.password=" + REDIS_PASSWORD,
+ "--spring.autoconfigure.exclude=" + SECURITY_EXCLUDE,
+ "--app.numberOfRatings=" + NUMBER_OF_RATINGS,
+ "--app.ratingStars=" + RATING_STARS
+ };
+ }
+
+ @Override
+ public String[] getJVMParameters() {
+ return new String[]{};
+ }
+
+
+ @Override
+ public String getBaseURL() {
+ return "http://localhost:" + sutPort;
+ }
+
+ @Override
+ public String getPathToExecutableJar() {
+ return jarLocation;
+ }
+
+ /*
+ Spring logs "Started ... in" before the CommandLineRunners, and seeding the ratings takes
+ another ~12s. Fuzzing that early makes EvoMaster's kill switch abort the still-running
+ runner, which brings the whole SUT down. This is the last line the last runner writes.
+ */
+ @Override
+ public String getLogMessageOfInitializedServer() {
+ return ">>>> BookRating created...";
+ }
+
+ @Override
+ public long getMaxAwaitForInitializationInSeconds() {
+ return timeoutSeconds;
+ }
+
+ @Override
+ public void preStart() {
+ redis.start();
+ redisClient = RedisClient.create("redis://:" + REDIS_PASSWORD + "@"
+ + redis.getHost() + ":" + redis.getMappedPort(REDIS_PORT));
+ redisConnection = redisClient.connect();
+ }
+
+ @Override
+ public void postStart() {
+ }
+
+ @Override
+ public void preStop() {
+ }
+
+ @Override
+ public void postStop() {
+ if (redisConnection != null) {
+ redisConnection.close();
+ redisClient.shutdown();
+ redisConnection = null;
+ redisClient = null;
+ }
+
+ redis.stop();
+ }
+
+ @Override
+ public String getPackagePrefixesToCover() {
+ return "id.my.hendisantika.springbootredissample.";
+ }
+
+ @Override
+ public ProblemInfo getProblemInfo() {
+ return new RestProblem(
+ getBaseURL() + "/v3/api-docs",
+ null
+ );
+ }
+
+ @Override
+ public SutInfoDto.OutputFormat getPreferredOutputFormat() {
+ return SutInfoDto.OutputFormat.JAVA_JUNIT_5;
+ }
+
+ @Override
+ public List getInfoForAuthentication() {
+ return null;
+ }
+
+ /*
+ Only the Spring Cache entries accumulate: the API is read-only, and the seeded data is
+ written once at startup by runners guarded on an empty repository, so it must survive.
+ */
+ @Override
+ public void resetStateOfSUT() {
+ if (redisConnection == null) {
+ return;
+ }
+ List keys = redisConnection.sync().keys(CACHE_KEY_PATTERN);
+ if (!keys.isEmpty()) {
+ redisConnection.sync().del(keys.toArray(new String[0]));
+ }
+ }
+
+ @Override
+ public List getDbSpecifications() {
+ return null;
+ }
+
+}
diff --git a/openapi-swagger/redis-sample.json b/openapi-swagger/redis-sample.json
new file mode 100644
index 000000000..0a1ac93eb
--- /dev/null
+++ b/openapi-swagger/redis-sample.json
@@ -0,0 +1,205 @@
+{
+ "openapi": "3.1.0",
+ "info": {
+ "title": "OpenAPI definition",
+ "version": "v0"
+ },
+ "servers": [
+ {
+ "url": "http://localhost:13456",
+ "description": "Generated server url"
+ }
+ ],
+ "paths": {
+ "/api/users": {
+ "get": {
+ "tags": [
+ "user-controller"
+ ],
+ "operationId": "getUsers",
+ "parameters": [
+ {
+ "name": "email",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "string",
+ "default": "yuji@yopmail.com"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "*/*": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/books": {
+ "get": {
+ "tags": [
+ "book-controller"
+ ],
+ "operationId": "getBooks",
+ "parameters": [
+ {
+ "name": "page",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "format": "int32",
+ "default": 0
+ }
+ },
+ {
+ "name": "size",
+ "in": "query",
+ "required": false,
+ "schema": {
+ "type": "integer",
+ "format": "int32",
+ "default": 10
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "*/*": {
+ "schema": {
+ "type": "object",
+ "additionalProperties": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/books/{isbn}": {
+ "get": {
+ "tags": [
+ "book-controller"
+ ],
+ "operationId": "getIsbn",
+ "parameters": [
+ {
+ "name": "isbn",
+ "in": "path",
+ "required": true,
+ "schema": {
+ "type": "string"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "*/*": {
+ "schema": {
+ "$ref": "#/components/schemas/Book"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "/api/books/categories": {
+ "get": {
+ "tags": [
+ "book-controller"
+ ],
+ "operationId": "getCategories",
+ "responses": {
+ "200": {
+ "description": "OK",
+ "content": {
+ "*/*": {
+ "schema": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "components": {
+ "schemas": {
+ "Book": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "title": {
+ "type": "string"
+ },
+ "subtitle": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "language": {
+ "type": "string"
+ },
+ "pageCount": {
+ "type": "integer",
+ "format": "int64"
+ },
+ "thumbnail": {
+ "type": "string"
+ },
+ "price": {
+ "type": "number",
+ "format": "double"
+ },
+ "currency": {
+ "type": "string"
+ },
+ "infoLink": {
+ "type": "string"
+ },
+ "authors": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ },
+ "uniqueItems": true
+ },
+ "categories": {
+ "type": "array",
+ "items": {
+ "$ref": "#/components/schemas/Category"
+ },
+ "uniqueItems": true
+ }
+ }
+ },
+ "Category": {
+ "type": "object",
+ "properties": {
+ "id": {
+ "type": "string"
+ },
+ "name": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/scripts/build/docker-compose.build.yml b/scripts/build/docker-compose.build.yml
index 45b2871d7..645dfd930 100644
--- a/scripts/build/docker-compose.build.yml
+++ b/scripts/build/docker-compose.build.yml
@@ -255,10 +255,12 @@ services:
(cd cs && mvn clean install -DskipTests)
fi
cp cs/rest/person-controller/target/person-controller-sut.jar /dist/
+ cp cs/rest/redis-sample/target/redis-sample-sut.jar /dist/
cp cs/rest-gui/webgoat/target/webgoat-sut.jar /dist/
cp cs/rest-gui/microcks/webapp/target/microcks-sut.jar /dist/
if [ "$${BUILD_EVOMASTER:-false}" = "true" ]; then
cp em/external/rest/person-controller/target/person-controller-evomaster-runner.jar /dist/
+ cp em/external/rest/redis-sample/target/redis-sample-evomaster-runner.jar /dist/
cp em/external/rest-gui/webgoat/target/webgoat-evomaster-runner.jar /dist/
cp em/external/rest-gui/microcks/target/microcks-evomaster-runner.jar /dist/
fi
diff --git a/scripts/dist.py b/scripts/dist.py
index f28332b73..55a7aaa8b 100755
--- a/scripts/dist.py
+++ b/scripts/dist.py
@@ -294,6 +294,9 @@ def build_jdk_21_maven():
copy(folder + "/cs/rest/person-controller/target/person-controller-sut.jar", DIST)
copy(folder + "/em/external/rest/person-controller/target/person-controller-evomaster-runner.jar", DIST)
+ copy(folder + "/cs/rest/redis-sample/target/redis-sample-sut.jar", DIST)
+ copy(folder + "/em/external/rest/redis-sample/target/redis-sample-evomaster-runner.jar", DIST)
+
copy(folder + "/cs/rest-gui/webgoat/target/webgoat-sut.jar", DIST)
copy(folder + "/em/external/rest-gui/webgoat/target/webgoat-evomaster-runner.jar", DIST)
diff --git a/scripts/dockerize/data/sut.csv b/scripts/dockerize/data/sut.csv
index 7ae52af33..43c907bce 100644
--- a/scripts/dockerize/data/sut.csv
+++ b/scripts/dockerize/data/sut.csv
@@ -37,3 +37,4 @@ quartz-manager,TRUE,,--server.port=8080 --quartz-manager.security.accounts.in-me
microcks,TRUE,-DPOSTMAN_RUNNER_URL=http://postman:3000 -DSERVICES_UPDATE_INTERVAL='0 0 0/2 * * *' -DKEYCLOAK_URL=http://keycloak:8080 -DKEYCLOAK_PUBLIC_URL=http://localhost:${AUTH_PORT:-8081} -DENABLE_CORS_POLICY=false -DCORS_REST_ALLOW_CREDENTIALS=true -DTEST_CALLBACK_URL=http://localhost:${HOST_PORT:-8080},--server.port=8080 --spring.profiles.active=prod --grpc.server.port=0 --spring.data.mongodb.uri=mongodb://mongodb:27017/test --spring.security.oauth2.resourceserver.jwt.issuer-uri=http://localhost:${AUTH_PORT:-8081}/realms/microcks --spring.security.oauth2.resourceserver.jwt.jwk-set-uri=http://keycloak:8080/realms/microcks/protocol/openid-connect/certs,http://localhost:8080/v3/api-docs,http://localhost:8080,FALSE,"","[{""name"": ""mongodb"", ""image_name"": ""mongo:7.0"", ""tmp_fs"": ""/data/db"", ""environment"": ""MONGODB_REPLICA_SET_MODE: primary;ALLOW_EMPTY_PASSWORD: yes"", ""volume"": """", ""health_check_command"": """"},{""name"": ""keycloak"",""image_name"": ""quay.io/keycloak/keycloak:26.0.0"", ""command"":[""start-dev"", ""--hostname=http://localhost:${AUTH_PORT:-8081}"", ""--import-realm"", ""--health-enabled=true""], ""port"": ""${AUTH_PORT:-8081}:8080"", ""tmp_fs"": """", ""environment"": ""KEYCLOAK_ADMIN: 'admin';KEYCLOAK_ADMIN_PASSWORD: 'admin';KC_HEALTH_ENABLED: 'true';KC_METRICS_ENABLED: 'true'"", ""volume"": ""../scripts/dockerize/data/additional_files/microcks/microcks-realm-sample.json:/opt/keycloak/data/import/microcks-realm.json"", ""health_check_command"": [""CMD"", ""sh"", ""-c"", ""echo -e 'GET /health/live HTTP/1.1\r\nHost: localhost\r\n\r\n' > /dev/tcp/localhost/9000""]},{""name"": ""postman"", ""image_name"": ""quay.io/microcks/microcks-postman-runtime:0.6.0"", ""tmp_fs"": """", ""environment"": """", ""volume"": """", ""health_check_command"": [""CMD"", ""curl"", ""-f"", ""http://localhost:3000/health""]}]"
commafeed,TRUE,"-Dquarkus.http.port=8080 -Dquarkus.datasource.db-kind=h2 -Dquarkus.datasource.jdbc.url=""jdbc:h2:mem:commafeed;DB_CLOSE_DELAY=-1"" -Dquarkus.datasource.username=sa -Dquarkus.datasource.password=sa","",http://localhost:8080/openapi?format=json,http://localhost:8080,FALSE,"",""
jasper,TRUE,,--server.port=8080 --spring.profiles.active=api-docs --spring.datasource.url=jdbc:postgresql://db:5432/jasper --spring.datasource.username=postgres --spring.datasource.password=password --spring.datasource.hikari.auto-commit=false --spring.jpa.database-platform=jasper.config.PostgreSQLDialect --springdoc.api-docs.path=/api/v3/api-docs --jasper.allow-user-tag-header=true --jasper.allow-user-role-header=true --jasper.allow-auth-headers=true,http://localhost:8080/api/v3/api-docs/jasper,http://localhost:8080,FALSE,,"[{""image_name"": ""postgres:18"", ""tmp_fs"": ""/var/lib/postgresql"", ""environment"": ""POSTGRES_PASSWORD: password;POSTGRES_HOST_AUTH_METHOD: trust;POSTGRES_DB: jasper"", ""volume"": """", ""health_check_command"": """"}]"
+redis-sample,TRUE,"",--server.port=8080 --spring.data.redis.host=db --spring.data.redis.port=6379 --spring.data.redis.password=53cret --spring.autoconfigure.exclude=org.springframework.boot.security.autoconfigure.web.servlet.ServletWebSecurityAutoConfiguration --app.numberOfRatings=5000 --app.ratingStars=5,http://localhost:8080/v3/api-docs,http://localhost:8080,FALSE,"","[{""image_name"": ""redis:7.4-alpine"", ""tmp_fs"": """", ""environment"": """", ""volume"": """", ""health_check_command"": """", ""command"": ""redis-server --requirepass 53cret""}]"
diff --git a/statistics/data.csv b/statistics/data.csv
index 71ea4f7c2..80b1fbd4a 100644
--- a/statistics/data.csv
+++ b/statistics/data.csv
@@ -47,6 +47,7 @@ TRUE,signal-registration,gRPC,Java,JDK 17,Maven,177,13652,,UNDEFINED,5,FALSE,htt
TRUE,webgoat,REST,Java,JDK 21,Maven,355,27638,H2,GPL,204,TRUE,https://github.com/WebGoat/WebGoat
TRUE,commafeed,REST,Java,JDK 25,Maven,201,21287,H2,Apache,44,TRUE,https://github.com/Athou/commafeed
TRUE,jasper,REST,Java,JDK 25,Maven,337,46791,PostgreSQL,MIT,61,TRUE,https://github.com/cjmalloy/jasper
+TRUE,redis-sample,REST,Java,JDK 21,Maven,18,1006,Redis,UNDEFINED,4,FALSE,https://github.com/hendisantika/spring-boot-redis-sample
FALSE,ind0,REST,Java,JDK 8,Gradle,103,17039,PostgreSQL,Proprietary,20,FALSE,UNDEFINED
FALSE,ind1,REST,Java;Kotlin,JDK 11,Gradle,163,15240,PostgreSQL,Proprietary,53,FALSE,UNDEFINED
diff --git a/statistics/table_emb.md b/statistics/table_emb.md
index 4eb795fd6..de751d2e8 100644
--- a/statistics/table_emb.md
+++ b/statistics/table_emb.md
@@ -29,6 +29,7 @@
|REST|__person-controller__|1112|16|12|Java|JDK 21|Maven|MongoDB||
|REST|__proxyprint__|8338|73|74|Java|JDK 8|Maven|H2|✓|
|REST|__quartz-manager__|5068|129|11|Java|JDK 11|Maven||✓|
+|REST|__redis-sample__|1006|18|4|Java|JDK 21|Maven|Redis||
|REST|__reservations-api__|1853|39|7|Java|JDK 11|Gradle|MongoDB|✓|
|REST|__rest-ncs__|605|9|6|Java|JDK 8|Maven|||
|REST|__rest-news__|857|11|7|Kotlin|JDK 8|Maven|H2||