diff --git a/.gitignore b/.gitignore index bb3186038..f787dd454 100644 --- a/.gitignore +++ b/.gitignore @@ -354,6 +354,9 @@ scripts/dockerize/dockerfiles /jdk_21_maven/cs/rest/testing-system/target/ /jdk_21_maven/em/external/rest/testing-system/target/ /jdk_21_maven/em/embedded/rest/testing-system/target/ +/jdk_21_maven/cs/rest/flight-search-api/target/ +/jdk_21_maven/em/external/rest/flight-search-api/target/ +/jdk_21_maven/em/embedded/rest/flight-search-api/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 f612246d4..31e94118d 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 (52) +### REST: Java/Kotlin (53) * **AdoptMe** (not-known license), [jdk_21_maven/cs/rest/adoptme](jdk_21_maven/cs/rest/adoptme), from [https://github.com/daanimelian/Programacion3-TPO](https://github.com/daanimelian/Programacion3-TPO) @@ -109,6 +109,8 @@ Auth configuration files can found in the [auth](auth) folder. * **Features-Service** (Apache), [jdk_8_maven/cs/rest/original/features-service](jdk_8_maven/cs/rest/original/features-service), from [https://github.com/JavierMF/features-service](https://github.com/JavierMF/features-service) +* **Flight Search API** (MIT), [jdk_21_maven/cs/rest/flight-search-api](jdk_21_maven/cs/rest/flight-search-api), from [https://github.com/Rapter1990/flightsearchapi](https://github.com/Rapter1990/flightsearchapi) + * **GDPR-KV** (not-known license), [jdk_21_gradle/cs/rest/gdpr-kv](jdk_21_gradle/cs/rest/gdpr-kv), from [https://github.com/jessicant/GDPR-KV](https://github.com/jessicant/GDPR-KV) * **Genome Nexus** (MIT), [jdk_8_maven/cs/rest-gui/genome-nexus](jdk_8_maven/cs/rest-gui/genome-nexus), from [https://github.com/genome-nexus/genome-nexus](https://github.com/genome-nexus/genome-nexus) diff --git a/auth/flight-search-api-auth.yaml b/auth/flight-search-api-auth.yaml new file mode 100644 index 000000000..e45f2ef0d --- /dev/null +++ b/auth/flight-search-api-auth.yaml @@ -0,0 +1,25 @@ +auth: + - name: WfdAdmin1 + loginEndpointAuth: + payloadRaw: "{\"email\": \"wfd_admin1@wfd.invalid\", \"password\": \"Wfd-Admin-Pass1\"}" + - name: WfdAdmin2 + loginEndpointAuth: + payloadRaw: "{\"email\": \"wfd_admin2@wfd.invalid\", \"password\": \"Wfd-Admin-Pass2\"}" + - name: WfdUser1 + loginEndpointAuth: + payloadRaw: "{\"email\": \"wfd_user1@wfd.invalid\", \"password\": \"Wfd-User-Pass1\"}" + - name: WfdUser2 + loginEndpointAuth: + payloadRaw: "{\"email\": \"wfd_user2@wfd.invalid\", \"password\": \"Wfd-User-Pass2\"}" + +authTemplate: + loginEndpointAuth: + endpoint: /api/v1/authentication/user/login + verb: POST + contentType: application/json + token: + extractFrom: body + extractSelector: /response/accessToken + sendName: Authorization + sendIn: header + sendTemplate: "Bearer {token}" diff --git a/dockerfiles/additional_files/flight-search-api/flight-search-api-mongo-seed.js b/dockerfiles/additional_files/flight-search-api/flight-search-api-mongo-seed.js new file mode 100644 index 000000000..ade1d14c6 --- /dev/null +++ b/dockerfiles/additional_files/flight-search-api/flight-search-api-mongo-seed.js @@ -0,0 +1,19 @@ +// MODIFIED (WFD-added, not part of the original SUT): the same four accounts the drivers seed. +// Airports and flights are left for the search to create (the SUT's own loader is never scheduled). +db = db.getSiblingDB('flightdatabase'); + +const user = function (id, hash, type) { + return { + "_id": id, "EMAIL": id + "@wfd.invalid", "PASSWORD": hash, + "FIRST_NAME": id, "LAST_NAME": id, "PHONE_NUMBER": "05550000000", + "USER_TYPE": type, "USER_STATUS": "ACTIVE", + "_class": "com.example.demo.auth.model.entity.UserEntity" + }; +}; + +db.getCollection('user-collection').insertMany([ + user("wfd_admin1", "$2a$10$2xOaY0XmjU8VrHnQ6ORmme.4pAD21fsnoM9dcf8Y8NYwmXZztsDsC", "ADMIN"), // Wfd-Admin-Pass1 + user("wfd_admin2", "$2a$10$qKrL3SboXVhfaaevAMiU.eFAj1wD4.X2VVvI.XSmjVlTPf8.95Z9y", "ADMIN"), // Wfd-Admin-Pass2 + user("wfd_user1", "$2a$10$t.OcuL3NBcdCtRCUtX4SiuG6RPgGxs0yQpdvVl11J0Mv249/vu9Za", "USER"), // Wfd-User-Pass1 + user("wfd_user2", "$2a$10$1WlQAEEMP97IO1o8vLl3ROrLeF9hdKRjd0yxlOve.ZhF.HCW9rES.", "USER") // Wfd-User-Pass2 +]); diff --git a/dockerfiles/flight-search-api.dockerfile b/dockerfiles/flight-search-api.dockerfile new file mode 100644 index 000000000..3eec2caa8 --- /dev/null +++ b/dockerfiles/flight-search-api.dockerfile @@ -0,0 +1,13 @@ +FROM amazoncorretto:21-alpine-jdk + +COPY ./dist/flight-search-api-sut.jar . +COPY ./dist/jacocoagent.jar . + + + + +ENTRYPOINT \ + java \ + -javaagent:jacocoagent.jar=output=tcpserver,address=*,port=6300,append=false,dumponexit=false \ + -jar flight-search-api-sut.jar \ + --server.port=8080 --spring.data.mongodb.host=db --spring.data.mongodb.port=27017 --spring.data.mongodb.database=flightdatabase \ No newline at end of file diff --git a/dockerfiles/flight-search-api.yaml b/dockerfiles/flight-search-api.yaml new file mode 100644 index 000000000..1dde012cb --- /dev/null +++ b/dockerfiles/flight-search-api.yaml @@ -0,0 +1,42 @@ +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-flight-search-api: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-flight-search-api + sut-flight-search-api: + image: webfuzzing/wfd-flight-search-api:FINAL +# build: +# dockerfile: ./dockerfiles/flight-search-api.dockerfile +# context: .. + environment: + AUTH_PORT: ${AUTH_PORT:-8081} + ports: + - "${JACOCO_PORT:-6300}:6300" + depends_on: + db: + condition: service_healthy + db: + image: mongo:7 + volumes: + - ./additional_files/flight-search-api/flight-search-api-mongo-seed.js:/docker-entrypoint-initdb.d/flight-search-api-mongo-seed.js + healthcheck: + test: mongosh --quiet --eval "db.adminCommand('ping')" + interval: 30s + timeout: 30s + retries: 3 \ No newline at end of file diff --git a/experiments/bb-exp.py b/experiments/bb-exp.py index 172e96d7d..99a9f6ce3 100644 --- a/experiments/bb-exp.py +++ b/experiments/bb-exp.py @@ -86,6 +86,7 @@ def __init__(self, name, auth, sleep, schemaformat, classfiles): Sut("erc20-rest-service",False,SLEEP,JSON,["jdk_8_gradle/cs/rest/erc20-rest-service/build/classes"]), Sut("familie-ba-sak",True,SLEEP,JSON,["jdk_17_maven/cs/rest/familie-ba-sak/target/classes"]), Sut("features-service",False,SLEEP,JSON,["jdk_8_maven/cs/rest/original/features-service/target/classes"]), + Sut("flight-search-api",True,SLEEP,JSON,["jdk_21_maven/cs/rest/flight-search-api/target/classes"]), Sut("gdpr-kv",False,SLEEP,JSON,["jdk_21_gradle/cs/rest/gdpr-kv/build/classes"]), Sut("traccar",True,SLEEP,JSON,["jdk_21_gradle/cs/rest/traccar/build/classes"]), Sut("genome-nexus",False,SLEEP,JSON,["jdk_8_maven/cs/rest-gui/genome-nexus/component/target/classes", diff --git a/experiments/wb-exp.py b/experiments/wb-exp.py index e48a12926..a7d89d6a9 100644 --- a/experiments/wb-exp.py +++ b/experiments/wb-exp.py @@ -193,6 +193,7 @@ def __init__(self, name, platform): Sut("erc20-rest-service", JDK_8), Sut("familie-ba-sak",JDK_17), Sut("features-service", JDK_8), + Sut("flight-search-api", JDK_21), Sut("gdpr-kv", JDK_21), Sut("traccar", JDK_21), Sut("genome-nexus", JDK_8), diff --git a/jacoco.dockerfile b/jacoco.dockerfile index 1f0bc9a6c..1fe52af9b 100644 --- a/jacoco.dockerfile +++ b/jacoco.dockerfile @@ -22,6 +22,7 @@ COPY jdk_11_maven/cs/rest/cwa-verification-server/target/classes ${CLASS_FILES} COPY jdk_8_gradle/cs/rest/erc20-rest-service/build/classes ${CLASS_FILES}/jdk_8_gradle/cs/rest/erc20-rest-service/build/classes COPY jdk_17_maven/cs/rest/familie-ba-sak/target/classes ${CLASS_FILES}/jdk_17_maven/cs/rest/familie-ba-sak/target/classes COPY jdk_8_maven/cs/rest/original/features-service/target/classes ${CLASS_FILES}/jdk_8_maven/cs/rest/original/features-service/target/classes +COPY jdk_21_maven/cs/rest/flight-search-api/target/classes ${CLASS_FILES}/jdk_21_maven/cs/rest/flight-search-api/target/classes COPY jdk_21_gradle/cs/rest/gdpr-kv/build/classes ${CLASS_FILES}/jdk_21_gradle/cs/rest/gdpr-kv/build/classes COPY jdk_8_maven/cs/rest-gui/genome-nexus/component/target/classes ${CLASS_FILES}/jdk_8_maven/cs/rest-gui/genome-nexus/component/target/classes COPY jdk_8_maven/cs/rest-gui/genome-nexus/model/target/classes ${CLASS_FILES}/jdk_8_maven/cs/rest-gui/genome-nexus/model/target/classes diff --git a/jdk_21_maven/cs/rest/flight-search-api/pom.xml b/jdk_21_maven/cs/rest/flight-search-api/pom.xml index 2ba7efd47..9057e3104 100644 --- a/jdk_21_maven/cs/rest/flight-search-api/pom.xml +++ b/jdk_21_maven/cs/rest/flight-search-api/pom.xml @@ -32,8 +32,11 @@ 0.12.3 1.5.5.Final 0.2.0 - 2.1.0 - 2.1.0 + + + 2.7.0 + 2.7.0 + 0.8.12 3.5.2 3.5.2 @@ -189,6 +192,12 @@ org.springframework.boot spring-boot-maven-plugin + + + flight-search-api + sut + org.projectlombok diff --git a/jdk_21_maven/cs/rest/pom.xml b/jdk_21_maven/cs/rest/pom.xml index fada58e36..94365a121 100644 --- a/jdk_21_maven/cs/rest/pom.xml +++ b/jdk_21_maven/cs/rest/pom.xml @@ -21,6 +21,7 @@ lovemining movies-xml testing-system + flight-search-api diff --git a/jdk_21_maven/em/embedded/rest/flight-search-api/pom.xml b/jdk_21_maven/em/embedded/rest/flight-search-api/pom.xml new file mode 100644 index 000000000..cbafe8c03 --- /dev/null +++ b/jdk_21_maven/em/embedded/rest/flight-search-api/pom.xml @@ -0,0 +1,48 @@ + + + + 4.0.0 + + evomaster-benchmark-jdk21-em-embedded-rest-flight-search-api + jar + + + org.evomaster + evomaster-benchmark-jdk21-em-embedded-rest + 4.3.1-SNAPSHOT + + + + + + org.springframework.boot + spring-boot-dependencies + 3.4.1 + pom + import + + + + + + + + com.case + flightsearchapi + 0.0.1-SNAPSHOT + + + + org.testcontainers + testcontainers + compile + + + + org.mongodb + mongodb-driver-sync + + + + diff --git a/jdk_21_maven/em/embedded/rest/flight-search-api/src/main/java/em/embedded/com/example/demo/EmbeddedEvoMasterController.java b/jdk_21_maven/em/embedded/rest/flight-search-api/src/main/java/em/embedded/com/example/demo/EmbeddedEvoMasterController.java new file mode 100644 index 000000000..df3e544d7 --- /dev/null +++ b/jdk_21_maven/em/embedded/rest/flight-search-api/src/main/java/em/embedded/com/example/demo/EmbeddedEvoMasterController.java @@ -0,0 +1,189 @@ +package em.embedded.com.example.demo; + +import com.example.demo.FlightSearchApiApplication; +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoDatabase; +import org.bson.Document; +import org.evomaster.client.java.controller.AuthUtils; +import org.evomaster.client.java.controller.EmbeddedSutController; +import org.evomaster.client.java.controller.InstrumentedSutStarter; +import org.evomaster.client.java.controller.api.dto.SutInfoDto; +import org.evomaster.client.java.controller.api.dto.auth.AuthenticationDto; +import org.evomaster.client.java.controller.problem.ProblemInfo; +import org.evomaster.client.java.controller.problem.RestProblem; +import org.evomaster.client.java.sql.DbSpecification; +import org.springframework.boot.SpringApplication; +import org.springframework.context.ConfigurableApplicationContext; +import org.testcontainers.containers.GenericContainer; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * Class used to start/stop the SUT. + */ +public class EmbeddedEvoMasterController extends EmbeddedSutController { + + private static final String MONGODB_IMAGE = "mongo:7"; + + private static final int MONGODB_PORT = 27017; + + private static final String MONGODB_DATABASE = "flightdatabase"; + + // The DB starts empty (the flight loader is never scheduled); airports and flights can be created via the API + private static final List USERS = List.of( + user("wfd_admin1", "$2a$10$2xOaY0XmjU8VrHnQ6ORmme.4pAD21fsnoM9dcf8Y8NYwmXZztsDsC", "ADMIN"), + user("wfd_admin2", "$2a$10$qKrL3SboXVhfaaevAMiU.eFAj1wD4.X2VVvI.XSmjVlTPf8.95Z9y", "ADMIN"), + user("wfd_user1", "$2a$10$t.OcuL3NBcdCtRCUtX4SiuG6RPgGxs0yQpdvVl11J0Mv249/vu9Za", "USER"), + user("wfd_user2", "$2a$10$1WlQAEEMP97IO1o8vLl3ROrLeF9hdKRjd0yxlOve.ZhF.HCW9rES.", "USER") + ); + + private static Document user(String id, String passwordHash, String type) { + return new Document("_id", id) + .append("EMAIL", id + "@wfd.invalid") + .append("PASSWORD", passwordHash) + .append("FIRST_NAME", id) + .append("LAST_NAME", id) + .append("PHONE_NUMBER", "05550000000") + .append("USER_TYPE", type) + .append("USER_STATUS", "ACTIVE") + .append("_class", "com.example.demo.auth.model.entity.UserEntity"); + } + + private static final GenericContainer mongodb = new GenericContainer(MONGODB_IMAGE) + .withExposedPorts(MONGODB_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 MongoClient mongoClient; + + public EmbeddedEvoMasterController() { + this(0); + } + + public EmbeddedEvoMasterController(int port) { + setControllerPort(port); + } + + @Override + public String startSut() { + + mongodb.start(); + mongoClient = MongoClients.create("mongodb://" + mongodb.getHost() + ":" + mongodb.getMappedPort(MONGODB_PORT)); + seedUsers(); + + ctx = SpringApplication.run(FlightSearchApiApplication.class, new String[]{ + "--server.port=0", + "--spring.data.mongodb.host=" + mongodb.getHost(), + "--spring.data.mongodb.port=" + mongodb.getMappedPort(MONGODB_PORT), + "--spring.data.mongodb.database=" + MONGODB_DATABASE + }); + + return "http://localhost:" + getSutPort(); + } + + private void seedUsers() { + List users = new ArrayList<>(); + for (Document u : USERS) { + users.add(new Document(u)); + } + mongoClient.getDatabase(MONGODB_DATABASE).getCollection("user-collection").insertMany(users); + } + + 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 (mongoClient != null) { + mongoClient.close(); + mongoClient = null; + } + mongodb.stop(); + } + + @Override + public String getPackagePrefixesToCover() { + return "com.example.demo."; + } + + @Override + public void resetStateOfSUT() { + MongoDatabase db = mongoClient.getDatabase(MONGODB_DATABASE); + for (String name : db.listCollectionNames()) { + db.getCollection(name).deleteMany(new Document()); + } + seedUsers(); + } + + @Override + public Object getMongoConnection() { + return mongoClient; + } + + @Override + public List getDbSpecifications() { + return null; + } + + private static AuthenticationDto login(String name, String email, String password) { + return AuthUtils.getForJsonTokenBearer( + name, + "/api/v1/authentication/user/login", + "{\"email\": \"" + email + "\", \"password\": \"" + password + "\"}", + "/response/accessToken" + ); + } + + @Override + public List getInfoForAuthentication() { + return List.of( + login("WfdAdmin1", "wfd_admin1@wfd.invalid", "Wfd-Admin-Pass1"), + login("WfdAdmin2", "wfd_admin2@wfd.invalid", "Wfd-Admin-Pass2"), + login("WfdUser1", "wfd_user1@wfd.invalid", "Wfd-User-Pass1"), + login("WfdUser2", "wfd_user2@wfd.invalid", "Wfd-User-Pass2") + ); + } + + @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/embedded/rest/pom.xml b/jdk_21_maven/em/embedded/rest/pom.xml index f25c2703d..ba4c6e908 100644 --- a/jdk_21_maven/em/embedded/rest/pom.xml +++ b/jdk_21_maven/em/embedded/rest/pom.xml @@ -20,6 +20,7 @@ lovemining movies-xml testing-system + flight-search-api diff --git a/jdk_21_maven/em/external/rest/flight-search-api/pom.xml b/jdk_21_maven/em/external/rest/flight-search-api/pom.xml new file mode 100644 index 000000000..049fefec4 --- /dev/null +++ b/jdk_21_maven/em/external/rest/flight-search-api/pom.xml @@ -0,0 +1,87 @@ + + + + 4.0.0 + + evomaster-benchmark-jdk21-em-external-rest-flight-search-api + jar + + + org.evomaster + evomaster-benchmark-jdk21-em-external-rest + 4.3.1-SNAPSHOT + + + + + + org.springframework.boot + spring-boot-dependencies + 3.4.1 + pom + import + + + + + + + org.testcontainers + testcontainers + compile + + + + org.mongodb + mongodb-driver-sync + + + + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.6.2 + + + package + + shade + + + flight-search-api-evomaster-runner + + + + em.external.com.example.demo.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/flight-search-api/src/main/java/em/external/com/example/demo/ExternalEvoMasterController.java b/jdk_21_maven/em/external/rest/flight-search-api/src/main/java/em/external/com/example/demo/ExternalEvoMasterController.java new file mode 100644 index 000000000..fdff4fedf --- /dev/null +++ b/jdk_21_maven/em/external/rest/flight-search-api/src/main/java/em/external/com/example/demo/ExternalEvoMasterController.java @@ -0,0 +1,242 @@ +package em.external.com.example.demo; + +import com.mongodb.client.MongoClient; +import com.mongodb.client.MongoClients; +import com.mongodb.client.MongoDatabase; +import org.bson.Document; +import org.evomaster.client.java.controller.AuthUtils; +import org.evomaster.client.java.controller.ExternalSutController; +import org.evomaster.client.java.controller.InstrumentedSutStarter; +import org.evomaster.client.java.controller.api.dto.SutInfoDto; +import org.evomaster.client.java.controller.api.dto.auth.AuthenticationDto; +import org.evomaster.client.java.controller.problem.ProblemInfo; +import org.evomaster.client.java.controller.problem.RestProblem; +import org.evomaster.client.java.sql.DbSpecification; +import org.testcontainers.containers.GenericContainer; + +import java.util.ArrayList; +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 MONGODB_IMAGE = "mongo:7"; + + private static final int MONGODB_PORT = 27017; + + private static final String MONGODB_DATABASE = "flightdatabase"; + + // The DB starts empty (the flight loader is never scheduled); airports and flights can be created via the API + private static final List USERS = List.of( + user("wfd_admin1", "$2a$10$2xOaY0XmjU8VrHnQ6ORmme.4pAD21fsnoM9dcf8Y8NYwmXZztsDsC", "ADMIN"), + user("wfd_admin2", "$2a$10$qKrL3SboXVhfaaevAMiU.eFAj1wD4.X2VVvI.XSmjVlTPf8.95Z9y", "ADMIN"), + user("wfd_user1", "$2a$10$t.OcuL3NBcdCtRCUtX4SiuG6RPgGxs0yQpdvVl11J0Mv249/vu9Za", "USER"), + user("wfd_user2", "$2a$10$1WlQAEEMP97IO1o8vLl3ROrLeF9hdKRjd0yxlOve.ZhF.HCW9rES.", "USER") + ); + + private static Document user(String id, String passwordHash, String type) { + return new Document("_id", id) + .append("EMAIL", id + "@wfd.invalid") + .append("PASSWORD", passwordHash) + .append("FIRST_NAME", id) + .append("LAST_NAME", id) + .append("PHONE_NUMBER", "05550000000") + .append("USER_TYPE", type) + .append("USER_STATUS", "ACTIVE") + .append("_class", "com.example.demo.auth.model.entity.UserEntity"); + } + + private static final GenericContainer mongodb = new GenericContainer(MONGODB_IMAGE) + .withExposedPorts(MONGODB_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/flight-search-api/target"; + if (args.length > 2) { + jarLocation = args[2]; + } + if (!jarLocation.endsWith(".jar")) { + jarLocation += "/flight-search-api-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 MongoClient mongoClient; + + public ExternalEvoMasterController() { + this(DEFAULT_CONTROLLER_PORT, "../target/flight-search-api-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.mongodb.host=" + mongodb.getHost(), + "--spring.data.mongodb.port=" + mongodb.getMappedPort(MONGODB_PORT), + "--spring.data.mongodb.database=" + MONGODB_DATABASE + }; + } + + @Override + public String[] getJVMParameters() { + return new String[]{}; + } + + @Override + public String getBaseURL() { + return "http://localhost:" + sutPort; + } + + @Override + public String getPathToExecutableJar() { + return jarLocation; + } + + @Override + public String getLogMessageOfInitializedServer() { + return "Started FlightSearchApiApplication in "; + } + + @Override + public long getMaxAwaitForInitializationInSeconds() { + return timeoutSeconds; + } + + @Override + public void preStart() { + mongodb.start(); + mongoClient = MongoClients.create("mongodb://" + mongodb.getHost() + ":" + mongodb.getMappedPort(MONGODB_PORT)); + seedUsers(); + } + + private void seedUsers() { + List users = new ArrayList<>(); + for (Document u : USERS) { + users.add(new Document(u)); + } + mongoClient.getDatabase(MONGODB_DATABASE).getCollection("user-collection").insertMany(users); + } + + @Override + public void postStart() { + } + + @Override + public void preStop() { + } + + @Override + public void postStop() { + if (mongoClient != null) { + mongoClient.close(); + mongoClient = null; + } + mongodb.stop(); + } + + @Override + public String getPackagePrefixesToCover() { + return "com.example.demo."; + } + + @Override + public void resetStateOfSUT() { + MongoDatabase db = mongoClient.getDatabase(MONGODB_DATABASE); + for (String name : db.listCollectionNames()) { + db.getCollection(name).deleteMany(new Document()); + } + seedUsers(); + } + + @Override + public Object getMongoConnection() { + return mongoClient; + } + + @Override + public List getDbSpecifications() { + return null; + } + + private static AuthenticationDto login(String name, String email, String password) { + return AuthUtils.getForJsonTokenBearer( + name, + "/api/v1/authentication/user/login", + "{\"email\": \"" + email + "\", \"password\": \"" + password + "\"}", + "/response/accessToken" + ); + } + + @Override + public List getInfoForAuthentication() { + return List.of( + login("WfdAdmin1", "wfd_admin1@wfd.invalid", "Wfd-Admin-Pass1"), + login("WfdAdmin2", "wfd_admin2@wfd.invalid", "Wfd-Admin-Pass2"), + login("WfdUser1", "wfd_user1@wfd.invalid", "Wfd-User-Pass1"), + login("WfdUser2", "wfd_user2@wfd.invalid", "Wfd-User-Pass2") + ); + } + + @Override + public ProblemInfo getProblemInfo() { + return new RestProblem( + getBaseURL() + "/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 e23485358..4a6a8fc08 100644 --- a/jdk_21_maven/em/external/rest/pom.xml +++ b/jdk_21_maven/em/external/rest/pom.xml @@ -21,6 +21,7 @@ lovemining movies-xml testing-system + flight-search-api \ No newline at end of file diff --git a/openapi/flight-search-api.json b/openapi/flight-search-api.json new file mode 100644 index 000000000..5ba8aa0ce --- /dev/null +++ b/openapi/flight-search-api.json @@ -0,0 +1,2882 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "flightsearchapi", + "description": "Case Study - Flight Search Api (Java 21, Spring Boot, Mongodb, JUnit, Spring Security, JWT, Docker, Kubernetes, Prometheus, Grafana, Github Actions (CI/CD) ) ", + "contact": { + "name": "Sercan Noyan Germiyanoğlu", + "url": "https://github.com/Rapter1990/flightsearchapi" + }, + "version": "1.0.0" + }, + "servers": [ + { + "url": "http://localhost:8080", + "description": "Generated server url" + } + ], + "tags": [ + { + "name": "Search Flight", + "description": "Endpoints for searching flights based on given criteria." + }, + { + "name": "Actuator", + "description": "Monitor and interact", + "externalDocs": { + "description": "Spring Boot Actuator Web API Documentation", + "url": "https://docs.spring.io/spring-boot/docs/current/actuator-api/html/" + } + }, + { + "name": "Authentication", + "description": "Handles user authentication and authorization operations." + }, + { + "name": "Flight Management", + "description": "Endpoints for managing flights including creation, retrieval, updating, and deletion." + }, + { + "name": "Airport Management", + "description": "Endpoints for managing airports including creation, retrieval, updating, and deletion." + } + ], + "paths": { + "/api/v1/flights/{id}": { + "get": { + "tags": [ + "Flight Management" + ], + "summary": "Get flight by ID", + "description": "Retrieves a flight by its ID. Accessible by both ADMIN and USER roles.", + "operationId": "getFlightById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Flight successfully retrieved", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseFlightResponse" + } + } + } + }, + "400": { + "description": "Invalid flight details provided", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseFlightResponse" + } + } + } + }, + "401": { + "description": "Unauthorized, authentication is required", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseFlightResponse" + } + } + } + }, + "403": { + "description": "Access forbidden", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseFlightResponse" + } + } + } + }, + "404": { + "description": "Airport not found", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseFlightResponse" + } + } + } + } + } + }, + "put": { + "tags": [ + "Flight Management" + ], + "summary": "Update an flight", + "description": "Updates an existing flight by its ID. Accessible by ADMIN only.", + "operationId": "updateFlightById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateFlightRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Flight successfully updated", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseFlightResponse" + } + } + } + }, + "400": { + "description": "Invalid update details provided", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseFlightResponse" + } + } + } + }, + "401": { + "description": "Unauthorized, authentication is required", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseFlightResponse" + } + } + } + }, + "403": { + "description": "Access forbidden", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseFlightResponse" + } + } + } + }, + "404": { + "description": "Flight not found", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseFlightResponse" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Flight Management" + ], + "summary": "Delete an flight", + "description": "Deletes a flight by its ID. Accessible by ADMIN only.", + "operationId": "deleteAirportById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Flight successfully deleted", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseString" + } + } + } + }, + "400": { + "description": "Invalid update details provided", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseString" + } + } + } + }, + "401": { + "description": "Unauthorized, authentication is required", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseString" + } + } + } + }, + "403": { + "description": "Access forbidden", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseString" + } + } + } + }, + "404": { + "description": "Flight not found", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseString" + } + } + } + } + } + } + }, + "/api/v1/airports/{id}": { + "get": { + "tags": [ + "Airport Management" + ], + "summary": "Get airport by ID", + "description": "Retrieves an airport by its ID. Accessible by both ADMIN and USER roles.", + "operationId": "getAirportById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Airport successfully retrieved", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseAirportResponse" + } + } + } + }, + "400": { + "description": "Invalid airport details provided", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseAirportResponse" + } + } + } + }, + "401": { + "description": "Unauthorized, authentication is required", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseAirportResponse" + } + } + } + }, + "403": { + "description": "Access forbidden", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseAirportResponse" + } + } + } + }, + "404": { + "description": "Airport not found", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseAirportResponse" + } + } + } + } + } + }, + "put": { + "tags": [ + "Airport Management" + ], + "summary": "Update an airport", + "description": "Updates an existing airport by its ID. Accessible by ADMIN only.", + "operationId": "updateAirportById", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateAirportRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Airport successfully updated", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseAirportResponse" + } + } + } + }, + "400": { + "description": "Invalid update details provided", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseAirportResponse" + } + } + } + }, + "401": { + "description": "Unauthorized, authentication is required", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseAirportResponse" + } + } + } + }, + "403": { + "description": "Access forbidden", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseAirportResponse" + } + } + } + }, + "404": { + "description": "Airport not found", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseAirportResponse" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Airport Management" + ], + "summary": "Delete an airport", + "description": "Deletes an airport by its ID. Accessible by ADMIN only.", + "operationId": "deleteAirportById_1", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Airport successfully deleted", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseString" + } + } + } + }, + "400": { + "description": "Invalid update details provided", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseString" + } + } + } + }, + "401": { + "description": "Unauthorized, authentication is required", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseString" + } + } + } + }, + "403": { + "description": "Access forbidden", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseString" + } + } + } + }, + "404": { + "description": "Airport not found", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseString" + } + } + } + } + } + } + }, + "/api/v1/flights": { + "get": { + "tags": [ + "Flight Management" + ], + "summary": "Get all flights", + "description": "Retrieves a paginated list of flights. Accessible by both ADMIN and USER roles.", + "operationId": "getAllFlights", + "parameters": [ + { + "name": "request", + "in": "query", + "required": true, + "schema": { + "$ref": "#/components/schemas/AirportPagingRequest" + } + } + ], + "responses": { + "200": { + "description": "Flights successfully retrieved", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseCustomPagingResponseFlightResponse" + } + } + } + }, + "400": { + "description": "Invalid flights details provided", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseCustomPagingResponseFlightResponse" + } + } + } + }, + "401": { + "description": "Unauthorized, authentication is required", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseCustomPagingResponseFlightResponse" + } + } + } + }, + "403": { + "description": "Access forbidden", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseCustomPagingResponseFlightResponse" + } + } + } + }, + "404": { + "description": "Flight not found", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseCustomPagingResponseFlightResponse" + } + } + } + } + } + }, + "post": { + "tags": [ + "Flight Management" + ], + "summary": "Create a new flight", + "description": "Creates a new flight and saves it to the database. Accessible by ADMIN only.", + "operationId": "createFlight", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateFlightRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Flight successfully created", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseString" + } + } + } + }, + "400": { + "description": "Invalid flight details provided", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseString" + } + } + } + }, + "401": { + "description": "Unauthorized, authentication is required", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseString" + } + } + } + }, + "403": { + "description": "Access forbidden", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseString" + } + } + } + } + } + } + }, + "/api/v1/flights/search": { + "post": { + "tags": [ + "Search Flight" + ], + "summary": "Search for flights", + "description": "Searches for flights based on departure, arrival airports, departure date, and optionally return date. Accessible by ADMIN and USER roles.", + "operationId": "searchFlights", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SearchFlightRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Flights successfully retrieved", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseCustomPagingResponseFlightResponse" + } + } + } + }, + "400": { + "description": "Invalid search criteria provided", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseCustomPagingResponseFlightResponse" + } + } + } + }, + "401": { + "description": "Unauthorized, authentication is required", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseCustomPagingResponseFlightResponse" + } + } + } + }, + "403": { + "description": "Access forbidden", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseCustomPagingResponseFlightResponse" + } + } + } + } + } + } + }, + "/api/v1/authentication/user/register": { + "post": { + "tags": [ + "Authentication" + ], + "summary": "Register a new user", + "description": "Registers a new user in the system.", + "operationId": "registerAdmin", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RegisterRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "User successfully registered", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseVoid" + } + } + } + }, + "400": { + "description": "Invalid request data", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseVoid" + } + } + } + }, + "409": { + "description": "User already exists", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseVoid" + } + } + } + } + } + } + }, + "/api/v1/authentication/user/refresh-token": { + "post": { + "tags": [ + "Authentication" + ], + "summary": "Refresh access token", + "description": "Refreshes an expired access token using a valid refresh token.", + "operationId": "refreshToken", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TokenRefreshRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Token successfully refreshed", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseTokenResponse" + } + } + } + }, + "400": { + "description": "Invalid refresh token", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseTokenResponse" + } + } + } + }, + "401": { + "description": "Refresh token expired or invalid", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseTokenResponse" + } + } + } + } + } + } + }, + "/api/v1/authentication/user/logout": { + "post": { + "tags": [ + "Authentication" + ], + "summary": "Log out a user", + "description": "Invalidates the provided token, effectively logging out the user.", + "operationId": "logout", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TokenInvalidateRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Logout successful", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseVoid" + } + } + } + }, + "400": { + "description": "Invalid token provided", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseVoid" + } + } + } + } + } + } + }, + "/api/v1/authentication/user/login": { + "post": { + "tags": [ + "Authentication" + ], + "summary": "User login", + "description": "Authenticates a user and returns an access and refresh token.", + "operationId": "loginAdmin", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoginRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Login successful", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseTokenResponse" + } + } + } + }, + "401": { + "description": "Invalid login credentials", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseTokenResponse" + } + } + } + } + } + } + }, + "/api/v1/airports": { + "get": { + "tags": [ + "Airport Management" + ], + "summary": "Get all airports", + "description": "Retrieves a paginated list of airports. Accessible by both ADMIN and USER roles.", + "operationId": "getAllAirports", + "parameters": [ + { + "name": "request", + "in": "query", + "required": true, + "schema": { + "$ref": "#/components/schemas/AirportPagingRequest" + } + } + ], + "responses": { + "200": { + "description": "Airports successfully retrieved", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseCustomPagingResponseAirportResponse" + } + } + } + }, + "400": { + "description": "Invalid airports details provided", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseCustomPagingResponseAirportResponse" + } + } + } + }, + "401": { + "description": "Unauthorized, authentication is required", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseCustomPagingResponseAirportResponse" + } + } + } + }, + "403": { + "description": "Access forbidden", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseCustomPagingResponseAirportResponse" + } + } + } + }, + "404": { + "description": "Airport not found", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseCustomPagingResponseAirportResponse" + } + } + } + } + } + }, + "post": { + "tags": [ + "Airport Management" + ], + "summary": "Create a new airport", + "description": "Creates a new airport and saves it to the database. Accessible by ADMIN only.", + "operationId": "createAirport", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateAirportRequest" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Airport successfully created", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseString" + } + } + } + }, + "400": { + "description": "Invalid airport details provided", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseString" + } + } + } + }, + "401": { + "description": "Unauthorized, authentication is required", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseString" + } + } + } + }, + "403": { + "description": "Access forbidden", + "content": { + "*/*": { + "schema": { + "$ref": "#/components/schemas/CustomResponseString" + } + } + } + } + } + } + }, + "/actuator/loggers/{name}": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'loggers-name'", + "operationId": "loggerLevels", + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + }, + "404": { + "description": "Not Found" + } + } + }, + "post": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'loggers-name'", + "operationId": "configureLogLevel", + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "string", + "enum": [ + "TRACE", + "DEBUG", + "INFO", + "WARN", + "ERROR", + "FATAL", + "OFF" + ] + } + } + } + }, + "responses": { + "204": { + "description": "No Content" + }, + "400": { + "description": "Bad Request" + } + } + } + }, + "/actuator": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator root web endpoint", + "operationId": "links", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/Link" + } + } + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/Link" + } + } + } + }, + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/Link" + } + } + } + } + } + } + } + } + }, + "/actuator/threaddump": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'threaddump'", + "operationId": "threadDump", + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain;charset=UTF-8": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/actuator/scheduledtasks": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'scheduledtasks'", + "operationId": "scheduledTasks", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/actuator/sbom": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'sbom'", + "operationId": "sboms", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/actuator/sbom/{id}": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'sbom-id'", + "operationId": "sbom", + "parameters": [ + { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/octet-stream": { + "schema": { + "type": "object" + } + } + } + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/actuator/prometheus": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'prometheus'", + "operationId": "scrape", + "parameters": [ + { + "name": "format", + "in": "query", + "schema": { + "type": "string", + "enum": [ + "CONTENT_TYPE_004", + "CONTENT_TYPE_OPENMETRICS_100", + "CONTENT_TYPE_PROTOBUF" + ] + } + }, + { + "name": "includedNames", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "text/plain;version=0.0.4;charset=utf-8": { + "schema": { + "type": "object" + } + }, + "application/openmetrics-text;version=1.0.0;charset=utf-8": { + "schema": { + "type": "object" + } + }, + "application/vnd.google.protobuf;proto=io.prometheus.client.MetricFamily;encoding=delimited": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/actuator/metrics": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'metrics'", + "operationId": "listNames", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/actuator/metrics/{requiredMetricName}": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'metrics-requiredMetricName'", + "operationId": "metric", + "parameters": [ + { + "name": "requiredMetricName", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "tag", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/actuator/mappings": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'mappings'", + "operationId": "mappings", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/actuator/loggers": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'loggers'", + "operationId": "loggers", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/actuator/info": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'info'", + "operationId": "info", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/actuator/heapdump": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'heapdump'", + "operationId": "heapDump", + "parameters": [ + { + "name": "live", + "in": "query", + "schema": { + "type": "boolean" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/octet-stream": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/actuator/health": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'health'", + "operationId": "health", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/actuator/env": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'env'", + "operationId": "environment", + "parameters": [ + { + "name": "pattern", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/actuator/env/{toMatch}": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'env-toMatch'", + "operationId": "environmentEntry", + "parameters": [ + { + "name": "toMatch", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/actuator/configprops": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'configprops'", + "operationId": "configurationProperties", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/actuator/configprops/{prefix}": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'configprops-prefix'", + "operationId": "configurationPropertiesWithPrefix", + "parameters": [ + { + "name": "prefix", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/actuator/conditions": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'conditions'", + "operationId": "conditions", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + }, + "/actuator/caches": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'caches'", + "operationId": "caches", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'caches'", + "operationId": "clearCaches", + "responses": { + "204": { + "description": "No Content" + } + } + } + }, + "/actuator/caches/{cache}": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'caches-cache'", + "operationId": "cache", + "parameters": [ + { + "name": "cache", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "cacheManager", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + }, + "404": { + "description": "Not Found" + } + } + }, + "delete": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'caches-cache'", + "operationId": "clearCache", + "parameters": [ + { + "name": "cache", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "cacheManager", + "in": "query", + "schema": { + "type": "string" + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "404": { + "description": "Not Found" + } + } + } + }, + "/actuator/beans": { + "get": { + "tags": [ + "Actuator" + ], + "summary": "Actuator web endpoint 'beans'", + "operationId": "beans", + "responses": { + "200": { + "description": "OK", + "content": { + "application/vnd.spring-boot.actuator.v3+json": { + "schema": { + "type": "object" + } + }, + "application/vnd.spring-boot.actuator.v2+json": { + "schema": { + "type": "object" + } + }, + "application/json": { + "schema": { + "type": "object" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "UpdateFlightRequest": { + "required": [ + "arrivalTime", + "departureTime", + "fromAirportId", + "price", + "toAirportId" + ], + "type": "object", + "properties": { + "fromAirportId": { + "type": "string" + }, + "toAirportId": { + "type": "string" + }, + "departureTime": { + "type": "string", + "format": "date-time" + }, + "arrivalTime": { + "type": "string", + "format": "date-time" + }, + "price": { + "type": "number", + "format": "double" + } + } + }, + "AirportResponse": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "cityName": { + "type": "string" + } + } + }, + "CustomResponseFlightResponse": { + "type": "object", + "properties": { + "time": { + "type": "string", + "format": "date-time" + }, + "httpStatus": { + "type": "string", + "enum": [ + "100 CONTINUE", + "101 SWITCHING_PROTOCOLS", + "102 PROCESSING", + "103 EARLY_HINTS", + "103 CHECKPOINT", + "200 OK", + "201 CREATED", + "202 ACCEPTED", + "203 NON_AUTHORITATIVE_INFORMATION", + "204 NO_CONTENT", + "205 RESET_CONTENT", + "206 PARTIAL_CONTENT", + "207 MULTI_STATUS", + "208 ALREADY_REPORTED", + "226 IM_USED", + "300 MULTIPLE_CHOICES", + "301 MOVED_PERMANENTLY", + "302 FOUND", + "302 MOVED_TEMPORARILY", + "303 SEE_OTHER", + "304 NOT_MODIFIED", + "305 USE_PROXY", + "307 TEMPORARY_REDIRECT", + "308 PERMANENT_REDIRECT", + "400 BAD_REQUEST", + "401 UNAUTHORIZED", + "402 PAYMENT_REQUIRED", + "403 FORBIDDEN", + "404 NOT_FOUND", + "405 METHOD_NOT_ALLOWED", + "406 NOT_ACCEPTABLE", + "407 PROXY_AUTHENTICATION_REQUIRED", + "408 REQUEST_TIMEOUT", + "409 CONFLICT", + "410 GONE", + "411 LENGTH_REQUIRED", + "412 PRECONDITION_FAILED", + "413 PAYLOAD_TOO_LARGE", + "413 REQUEST_ENTITY_TOO_LARGE", + "414 URI_TOO_LONG", + "414 REQUEST_URI_TOO_LONG", + "415 UNSUPPORTED_MEDIA_TYPE", + "416 REQUESTED_RANGE_NOT_SATISFIABLE", + "417 EXPECTATION_FAILED", + "418 I_AM_A_TEAPOT", + "419 INSUFFICIENT_SPACE_ON_RESOURCE", + "420 METHOD_FAILURE", + "421 DESTINATION_LOCKED", + "422 UNPROCESSABLE_ENTITY", + "423 LOCKED", + "424 FAILED_DEPENDENCY", + "425 TOO_EARLY", + "426 UPGRADE_REQUIRED", + "428 PRECONDITION_REQUIRED", + "429 TOO_MANY_REQUESTS", + "431 REQUEST_HEADER_FIELDS_TOO_LARGE", + "451 UNAVAILABLE_FOR_LEGAL_REASONS", + "500 INTERNAL_SERVER_ERROR", + "501 NOT_IMPLEMENTED", + "502 BAD_GATEWAY", + "503 SERVICE_UNAVAILABLE", + "504 GATEWAY_TIMEOUT", + "505 HTTP_VERSION_NOT_SUPPORTED", + "506 VARIANT_ALSO_NEGOTIATES", + "507 INSUFFICIENT_STORAGE", + "508 LOOP_DETECTED", + "509 BANDWIDTH_LIMIT_EXCEEDED", + "510 NOT_EXTENDED", + "511 NETWORK_AUTHENTICATION_REQUIRED" + ] + }, + "isSuccess": { + "type": "boolean" + }, + "response": { + "$ref": "#/components/schemas/FlightResponse" + } + } + }, + "FlightResponse": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "fromAirport": { + "$ref": "#/components/schemas/AirportResponse" + }, + "toAirport": { + "$ref": "#/components/schemas/AirportResponse" + }, + "departureTime": { + "type": "string", + "format": "date-time" + }, + "arrivalTime": { + "type": "string", + "format": "date-time" + }, + "price": { + "type": "number", + "format": "double" + } + } + }, + "UpdateAirportRequest": { + "required": [ + "cityName", + "name" + ], + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "cityName": { + "type": "string" + } + } + }, + "CustomResponseAirportResponse": { + "type": "object", + "properties": { + "time": { + "type": "string", + "format": "date-time" + }, + "httpStatus": { + "type": "string", + "enum": [ + "100 CONTINUE", + "101 SWITCHING_PROTOCOLS", + "102 PROCESSING", + "103 EARLY_HINTS", + "103 CHECKPOINT", + "200 OK", + "201 CREATED", + "202 ACCEPTED", + "203 NON_AUTHORITATIVE_INFORMATION", + "204 NO_CONTENT", + "205 RESET_CONTENT", + "206 PARTIAL_CONTENT", + "207 MULTI_STATUS", + "208 ALREADY_REPORTED", + "226 IM_USED", + "300 MULTIPLE_CHOICES", + "301 MOVED_PERMANENTLY", + "302 FOUND", + "302 MOVED_TEMPORARILY", + "303 SEE_OTHER", + "304 NOT_MODIFIED", + "305 USE_PROXY", + "307 TEMPORARY_REDIRECT", + "308 PERMANENT_REDIRECT", + "400 BAD_REQUEST", + "401 UNAUTHORIZED", + "402 PAYMENT_REQUIRED", + "403 FORBIDDEN", + "404 NOT_FOUND", + "405 METHOD_NOT_ALLOWED", + "406 NOT_ACCEPTABLE", + "407 PROXY_AUTHENTICATION_REQUIRED", + "408 REQUEST_TIMEOUT", + "409 CONFLICT", + "410 GONE", + "411 LENGTH_REQUIRED", + "412 PRECONDITION_FAILED", + "413 PAYLOAD_TOO_LARGE", + "413 REQUEST_ENTITY_TOO_LARGE", + "414 URI_TOO_LONG", + "414 REQUEST_URI_TOO_LONG", + "415 UNSUPPORTED_MEDIA_TYPE", + "416 REQUESTED_RANGE_NOT_SATISFIABLE", + "417 EXPECTATION_FAILED", + "418 I_AM_A_TEAPOT", + "419 INSUFFICIENT_SPACE_ON_RESOURCE", + "420 METHOD_FAILURE", + "421 DESTINATION_LOCKED", + "422 UNPROCESSABLE_ENTITY", + "423 LOCKED", + "424 FAILED_DEPENDENCY", + "425 TOO_EARLY", + "426 UPGRADE_REQUIRED", + "428 PRECONDITION_REQUIRED", + "429 TOO_MANY_REQUESTS", + "431 REQUEST_HEADER_FIELDS_TOO_LARGE", + "451 UNAVAILABLE_FOR_LEGAL_REASONS", + "500 INTERNAL_SERVER_ERROR", + "501 NOT_IMPLEMENTED", + "502 BAD_GATEWAY", + "503 SERVICE_UNAVAILABLE", + "504 GATEWAY_TIMEOUT", + "505 HTTP_VERSION_NOT_SUPPORTED", + "506 VARIANT_ALSO_NEGOTIATES", + "507 INSUFFICIENT_STORAGE", + "508 LOOP_DETECTED", + "509 BANDWIDTH_LIMIT_EXCEEDED", + "510 NOT_EXTENDED", + "511 NETWORK_AUTHENTICATION_REQUIRED" + ] + }, + "isSuccess": { + "type": "boolean" + }, + "response": { + "$ref": "#/components/schemas/AirportResponse" + } + } + }, + "CreateFlightRequest": { + "required": [ + "arrivalTime", + "departureTime", + "fromAirportId", + "price", + "toAirportId" + ], + "type": "object", + "properties": { + "fromAirportId": { + "type": "string" + }, + "toAirportId": { + "type": "string" + }, + "departureTime": { + "type": "string", + "format": "date-time" + }, + "arrivalTime": { + "type": "string", + "format": "date-time" + }, + "price": { + "type": "number", + "format": "double" + } + } + }, + "CustomResponseString": { + "type": "object", + "properties": { + "time": { + "type": "string", + "format": "date-time" + }, + "httpStatus": { + "type": "string", + "enum": [ + "100 CONTINUE", + "101 SWITCHING_PROTOCOLS", + "102 PROCESSING", + "103 EARLY_HINTS", + "103 CHECKPOINT", + "200 OK", + "201 CREATED", + "202 ACCEPTED", + "203 NON_AUTHORITATIVE_INFORMATION", + "204 NO_CONTENT", + "205 RESET_CONTENT", + "206 PARTIAL_CONTENT", + "207 MULTI_STATUS", + "208 ALREADY_REPORTED", + "226 IM_USED", + "300 MULTIPLE_CHOICES", + "301 MOVED_PERMANENTLY", + "302 FOUND", + "302 MOVED_TEMPORARILY", + "303 SEE_OTHER", + "304 NOT_MODIFIED", + "305 USE_PROXY", + "307 TEMPORARY_REDIRECT", + "308 PERMANENT_REDIRECT", + "400 BAD_REQUEST", + "401 UNAUTHORIZED", + "402 PAYMENT_REQUIRED", + "403 FORBIDDEN", + "404 NOT_FOUND", + "405 METHOD_NOT_ALLOWED", + "406 NOT_ACCEPTABLE", + "407 PROXY_AUTHENTICATION_REQUIRED", + "408 REQUEST_TIMEOUT", + "409 CONFLICT", + "410 GONE", + "411 LENGTH_REQUIRED", + "412 PRECONDITION_FAILED", + "413 PAYLOAD_TOO_LARGE", + "413 REQUEST_ENTITY_TOO_LARGE", + "414 URI_TOO_LONG", + "414 REQUEST_URI_TOO_LONG", + "415 UNSUPPORTED_MEDIA_TYPE", + "416 REQUESTED_RANGE_NOT_SATISFIABLE", + "417 EXPECTATION_FAILED", + "418 I_AM_A_TEAPOT", + "419 INSUFFICIENT_SPACE_ON_RESOURCE", + "420 METHOD_FAILURE", + "421 DESTINATION_LOCKED", + "422 UNPROCESSABLE_ENTITY", + "423 LOCKED", + "424 FAILED_DEPENDENCY", + "425 TOO_EARLY", + "426 UPGRADE_REQUIRED", + "428 PRECONDITION_REQUIRED", + "429 TOO_MANY_REQUESTS", + "431 REQUEST_HEADER_FIELDS_TOO_LARGE", + "451 UNAVAILABLE_FOR_LEGAL_REASONS", + "500 INTERNAL_SERVER_ERROR", + "501 NOT_IMPLEMENTED", + "502 BAD_GATEWAY", + "503 SERVICE_UNAVAILABLE", + "504 GATEWAY_TIMEOUT", + "505 HTTP_VERSION_NOT_SUPPORTED", + "506 VARIANT_ALSO_NEGOTIATES", + "507 INSUFFICIENT_STORAGE", + "508 LOOP_DETECTED", + "509 BANDWIDTH_LIMIT_EXCEEDED", + "510 NOT_EXTENDED", + "511 NETWORK_AUTHENTICATION_REQUIRED" + ] + }, + "isSuccess": { + "type": "boolean" + }, + "response": { + "type": "string" + } + } + }, + "CustomPaging": { + "type": "object", + "properties": { + "pageNumber": { + "minimum": 1, + "type": "integer", + "format": "int32" + }, + "pageSize": { + "minimum": 1, + "type": "integer", + "format": "int32" + } + } + }, + "SearchFlightRequest": { + "required": [ + "departureTime", + "fromAirportId", + "toAirportId" + ], + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/CustomPaging" + }, + "fromAirportId": { + "type": "string" + }, + "toAirportId": { + "type": "string" + }, + "departureTime": { + "type": "string", + "format": "date-time" + }, + "arrivalTime": { + "type": "string", + "format": "date-time" + } + } + }, + "CustomPagingResponseFlightResponse": { + "type": "object", + "properties": { + "content": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FlightResponse" + } + }, + "pageNumber": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "totalElementCount": { + "type": "integer", + "format": "int64" + }, + "totalPageCount": { + "type": "integer", + "format": "int32" + } + } + }, + "CustomResponseCustomPagingResponseFlightResponse": { + "type": "object", + "properties": { + "time": { + "type": "string", + "format": "date-time" + }, + "httpStatus": { + "type": "string", + "enum": [ + "100 CONTINUE", + "101 SWITCHING_PROTOCOLS", + "102 PROCESSING", + "103 EARLY_HINTS", + "103 CHECKPOINT", + "200 OK", + "201 CREATED", + "202 ACCEPTED", + "203 NON_AUTHORITATIVE_INFORMATION", + "204 NO_CONTENT", + "205 RESET_CONTENT", + "206 PARTIAL_CONTENT", + "207 MULTI_STATUS", + "208 ALREADY_REPORTED", + "226 IM_USED", + "300 MULTIPLE_CHOICES", + "301 MOVED_PERMANENTLY", + "302 FOUND", + "302 MOVED_TEMPORARILY", + "303 SEE_OTHER", + "304 NOT_MODIFIED", + "305 USE_PROXY", + "307 TEMPORARY_REDIRECT", + "308 PERMANENT_REDIRECT", + "400 BAD_REQUEST", + "401 UNAUTHORIZED", + "402 PAYMENT_REQUIRED", + "403 FORBIDDEN", + "404 NOT_FOUND", + "405 METHOD_NOT_ALLOWED", + "406 NOT_ACCEPTABLE", + "407 PROXY_AUTHENTICATION_REQUIRED", + "408 REQUEST_TIMEOUT", + "409 CONFLICT", + "410 GONE", + "411 LENGTH_REQUIRED", + "412 PRECONDITION_FAILED", + "413 PAYLOAD_TOO_LARGE", + "413 REQUEST_ENTITY_TOO_LARGE", + "414 URI_TOO_LONG", + "414 REQUEST_URI_TOO_LONG", + "415 UNSUPPORTED_MEDIA_TYPE", + "416 REQUESTED_RANGE_NOT_SATISFIABLE", + "417 EXPECTATION_FAILED", + "418 I_AM_A_TEAPOT", + "419 INSUFFICIENT_SPACE_ON_RESOURCE", + "420 METHOD_FAILURE", + "421 DESTINATION_LOCKED", + "422 UNPROCESSABLE_ENTITY", + "423 LOCKED", + "424 FAILED_DEPENDENCY", + "425 TOO_EARLY", + "426 UPGRADE_REQUIRED", + "428 PRECONDITION_REQUIRED", + "429 TOO_MANY_REQUESTS", + "431 REQUEST_HEADER_FIELDS_TOO_LARGE", + "451 UNAVAILABLE_FOR_LEGAL_REASONS", + "500 INTERNAL_SERVER_ERROR", + "501 NOT_IMPLEMENTED", + "502 BAD_GATEWAY", + "503 SERVICE_UNAVAILABLE", + "504 GATEWAY_TIMEOUT", + "505 HTTP_VERSION_NOT_SUPPORTED", + "506 VARIANT_ALSO_NEGOTIATES", + "507 INSUFFICIENT_STORAGE", + "508 LOOP_DETECTED", + "509 BANDWIDTH_LIMIT_EXCEEDED", + "510 NOT_EXTENDED", + "511 NETWORK_AUTHENTICATION_REQUIRED" + ] + }, + "isSuccess": { + "type": "boolean" + }, + "response": { + "$ref": "#/components/schemas/CustomPagingResponseFlightResponse" + } + } + }, + "RegisterRequest": { + "required": [ + "firstName", + "lastName", + "phoneNumber" + ], + "type": "object", + "properties": { + "email": { + "maxLength": 2147483647, + "minLength": 7, + "type": "string" + }, + "password": { + "maxLength": 2147483647, + "minLength": 8, + "type": "string" + }, + "firstName": { + "type": "string" + }, + "lastName": { + "type": "string" + }, + "phoneNumber": { + "maxLength": 20, + "minLength": 11, + "type": "string" + }, + "userType": { + "type": "string", + "enum": [ + "USER", + "ADMIN" + ] + } + } + }, + "CustomResponseVoid": { + "type": "object", + "properties": { + "time": { + "type": "string", + "format": "date-time" + }, + "httpStatus": { + "type": "string", + "enum": [ + "100 CONTINUE", + "101 SWITCHING_PROTOCOLS", + "102 PROCESSING", + "103 EARLY_HINTS", + "103 CHECKPOINT", + "200 OK", + "201 CREATED", + "202 ACCEPTED", + "203 NON_AUTHORITATIVE_INFORMATION", + "204 NO_CONTENT", + "205 RESET_CONTENT", + "206 PARTIAL_CONTENT", + "207 MULTI_STATUS", + "208 ALREADY_REPORTED", + "226 IM_USED", + "300 MULTIPLE_CHOICES", + "301 MOVED_PERMANENTLY", + "302 FOUND", + "302 MOVED_TEMPORARILY", + "303 SEE_OTHER", + "304 NOT_MODIFIED", + "305 USE_PROXY", + "307 TEMPORARY_REDIRECT", + "308 PERMANENT_REDIRECT", + "400 BAD_REQUEST", + "401 UNAUTHORIZED", + "402 PAYMENT_REQUIRED", + "403 FORBIDDEN", + "404 NOT_FOUND", + "405 METHOD_NOT_ALLOWED", + "406 NOT_ACCEPTABLE", + "407 PROXY_AUTHENTICATION_REQUIRED", + "408 REQUEST_TIMEOUT", + "409 CONFLICT", + "410 GONE", + "411 LENGTH_REQUIRED", + "412 PRECONDITION_FAILED", + "413 PAYLOAD_TOO_LARGE", + "413 REQUEST_ENTITY_TOO_LARGE", + "414 URI_TOO_LONG", + "414 REQUEST_URI_TOO_LONG", + "415 UNSUPPORTED_MEDIA_TYPE", + "416 REQUESTED_RANGE_NOT_SATISFIABLE", + "417 EXPECTATION_FAILED", + "418 I_AM_A_TEAPOT", + "419 INSUFFICIENT_SPACE_ON_RESOURCE", + "420 METHOD_FAILURE", + "421 DESTINATION_LOCKED", + "422 UNPROCESSABLE_ENTITY", + "423 LOCKED", + "424 FAILED_DEPENDENCY", + "425 TOO_EARLY", + "426 UPGRADE_REQUIRED", + "428 PRECONDITION_REQUIRED", + "429 TOO_MANY_REQUESTS", + "431 REQUEST_HEADER_FIELDS_TOO_LARGE", + "451 UNAVAILABLE_FOR_LEGAL_REASONS", + "500 INTERNAL_SERVER_ERROR", + "501 NOT_IMPLEMENTED", + "502 BAD_GATEWAY", + "503 SERVICE_UNAVAILABLE", + "504 GATEWAY_TIMEOUT", + "505 HTTP_VERSION_NOT_SUPPORTED", + "506 VARIANT_ALSO_NEGOTIATES", + "507 INSUFFICIENT_STORAGE", + "508 LOOP_DETECTED", + "509 BANDWIDTH_LIMIT_EXCEEDED", + "510 NOT_EXTENDED", + "511 NETWORK_AUTHENTICATION_REQUIRED" + ] + }, + "isSuccess": { + "type": "boolean" + }, + "response": { + "type": "object" + } + } + }, + "TokenRefreshRequest": { + "required": [ + "refreshToken" + ], + "type": "object", + "properties": { + "refreshToken": { + "type": "string" + } + } + }, + "CustomResponseTokenResponse": { + "type": "object", + "properties": { + "time": { + "type": "string", + "format": "date-time" + }, + "httpStatus": { + "type": "string", + "enum": [ + "100 CONTINUE", + "101 SWITCHING_PROTOCOLS", + "102 PROCESSING", + "103 EARLY_HINTS", + "103 CHECKPOINT", + "200 OK", + "201 CREATED", + "202 ACCEPTED", + "203 NON_AUTHORITATIVE_INFORMATION", + "204 NO_CONTENT", + "205 RESET_CONTENT", + "206 PARTIAL_CONTENT", + "207 MULTI_STATUS", + "208 ALREADY_REPORTED", + "226 IM_USED", + "300 MULTIPLE_CHOICES", + "301 MOVED_PERMANENTLY", + "302 FOUND", + "302 MOVED_TEMPORARILY", + "303 SEE_OTHER", + "304 NOT_MODIFIED", + "305 USE_PROXY", + "307 TEMPORARY_REDIRECT", + "308 PERMANENT_REDIRECT", + "400 BAD_REQUEST", + "401 UNAUTHORIZED", + "402 PAYMENT_REQUIRED", + "403 FORBIDDEN", + "404 NOT_FOUND", + "405 METHOD_NOT_ALLOWED", + "406 NOT_ACCEPTABLE", + "407 PROXY_AUTHENTICATION_REQUIRED", + "408 REQUEST_TIMEOUT", + "409 CONFLICT", + "410 GONE", + "411 LENGTH_REQUIRED", + "412 PRECONDITION_FAILED", + "413 PAYLOAD_TOO_LARGE", + "413 REQUEST_ENTITY_TOO_LARGE", + "414 URI_TOO_LONG", + "414 REQUEST_URI_TOO_LONG", + "415 UNSUPPORTED_MEDIA_TYPE", + "416 REQUESTED_RANGE_NOT_SATISFIABLE", + "417 EXPECTATION_FAILED", + "418 I_AM_A_TEAPOT", + "419 INSUFFICIENT_SPACE_ON_RESOURCE", + "420 METHOD_FAILURE", + "421 DESTINATION_LOCKED", + "422 UNPROCESSABLE_ENTITY", + "423 LOCKED", + "424 FAILED_DEPENDENCY", + "425 TOO_EARLY", + "426 UPGRADE_REQUIRED", + "428 PRECONDITION_REQUIRED", + "429 TOO_MANY_REQUESTS", + "431 REQUEST_HEADER_FIELDS_TOO_LARGE", + "451 UNAVAILABLE_FOR_LEGAL_REASONS", + "500 INTERNAL_SERVER_ERROR", + "501 NOT_IMPLEMENTED", + "502 BAD_GATEWAY", + "503 SERVICE_UNAVAILABLE", + "504 GATEWAY_TIMEOUT", + "505 HTTP_VERSION_NOT_SUPPORTED", + "506 VARIANT_ALSO_NEGOTIATES", + "507 INSUFFICIENT_STORAGE", + "508 LOOP_DETECTED", + "509 BANDWIDTH_LIMIT_EXCEEDED", + "510 NOT_EXTENDED", + "511 NETWORK_AUTHENTICATION_REQUIRED" + ] + }, + "isSuccess": { + "type": "boolean" + }, + "response": { + "$ref": "#/components/schemas/TokenResponse" + } + } + }, + "TokenResponse": { + "type": "object", + "properties": { + "accessToken": { + "type": "string" + }, + "accessTokenExpiresAt": { + "type": "integer", + "format": "int64" + }, + "refreshToken": { + "type": "string" + } + } + }, + "TokenInvalidateRequest": { + "required": [ + "accessToken", + "refreshToken" + ], + "type": "object", + "properties": { + "accessToken": { + "type": "string" + }, + "refreshToken": { + "type": "string" + } + } + }, + "LoginRequest": { + "required": [ + "email", + "password" + ], + "type": "object", + "properties": { + "email": { + "type": "string" + }, + "password": { + "type": "string" + } + } + }, + "CreateAirportRequest": { + "required": [ + "cityName", + "name" + ], + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "cityName": { + "type": "string" + } + } + }, + "AirportPagingRequest": { + "type": "object", + "properties": { + "pagination": { + "$ref": "#/components/schemas/CustomPaging" + } + } + }, + "CustomPagingResponseAirportResponse": { + "type": "object", + "properties": { + "content": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AirportResponse" + } + }, + "pageNumber": { + "type": "integer", + "format": "int32" + }, + "pageSize": { + "type": "integer", + "format": "int32" + }, + "totalElementCount": { + "type": "integer", + "format": "int64" + }, + "totalPageCount": { + "type": "integer", + "format": "int32" + } + } + }, + "CustomResponseCustomPagingResponseAirportResponse": { + "type": "object", + "properties": { + "time": { + "type": "string", + "format": "date-time" + }, + "httpStatus": { + "type": "string", + "enum": [ + "100 CONTINUE", + "101 SWITCHING_PROTOCOLS", + "102 PROCESSING", + "103 EARLY_HINTS", + "103 CHECKPOINT", + "200 OK", + "201 CREATED", + "202 ACCEPTED", + "203 NON_AUTHORITATIVE_INFORMATION", + "204 NO_CONTENT", + "205 RESET_CONTENT", + "206 PARTIAL_CONTENT", + "207 MULTI_STATUS", + "208 ALREADY_REPORTED", + "226 IM_USED", + "300 MULTIPLE_CHOICES", + "301 MOVED_PERMANENTLY", + "302 FOUND", + "302 MOVED_TEMPORARILY", + "303 SEE_OTHER", + "304 NOT_MODIFIED", + "305 USE_PROXY", + "307 TEMPORARY_REDIRECT", + "308 PERMANENT_REDIRECT", + "400 BAD_REQUEST", + "401 UNAUTHORIZED", + "402 PAYMENT_REQUIRED", + "403 FORBIDDEN", + "404 NOT_FOUND", + "405 METHOD_NOT_ALLOWED", + "406 NOT_ACCEPTABLE", + "407 PROXY_AUTHENTICATION_REQUIRED", + "408 REQUEST_TIMEOUT", + "409 CONFLICT", + "410 GONE", + "411 LENGTH_REQUIRED", + "412 PRECONDITION_FAILED", + "413 PAYLOAD_TOO_LARGE", + "413 REQUEST_ENTITY_TOO_LARGE", + "414 URI_TOO_LONG", + "414 REQUEST_URI_TOO_LONG", + "415 UNSUPPORTED_MEDIA_TYPE", + "416 REQUESTED_RANGE_NOT_SATISFIABLE", + "417 EXPECTATION_FAILED", + "418 I_AM_A_TEAPOT", + "419 INSUFFICIENT_SPACE_ON_RESOURCE", + "420 METHOD_FAILURE", + "421 DESTINATION_LOCKED", + "422 UNPROCESSABLE_ENTITY", + "423 LOCKED", + "424 FAILED_DEPENDENCY", + "425 TOO_EARLY", + "426 UPGRADE_REQUIRED", + "428 PRECONDITION_REQUIRED", + "429 TOO_MANY_REQUESTS", + "431 REQUEST_HEADER_FIELDS_TOO_LARGE", + "451 UNAVAILABLE_FOR_LEGAL_REASONS", + "500 INTERNAL_SERVER_ERROR", + "501 NOT_IMPLEMENTED", + "502 BAD_GATEWAY", + "503 SERVICE_UNAVAILABLE", + "504 GATEWAY_TIMEOUT", + "505 HTTP_VERSION_NOT_SUPPORTED", + "506 VARIANT_ALSO_NEGOTIATES", + "507 INSUFFICIENT_STORAGE", + "508 LOOP_DETECTED", + "509 BANDWIDTH_LIMIT_EXCEEDED", + "510 NOT_EXTENDED", + "511 NETWORK_AUTHENTICATION_REQUIRED" + ] + }, + "isSuccess": { + "type": "boolean" + }, + "response": { + "$ref": "#/components/schemas/CustomPagingResponseAirportResponse" + } + } + }, + "Link": { + "type": "object", + "properties": { + "href": { + "type": "string" + }, + "templated": { + "type": "boolean" + } + } + } + }, + "securitySchemes": { + "bearerAuth": { + "type": "http", + "description": "JWT Token", + "in": "header", + "scheme": "bearer", + "bearerFormat": "JWT" + } + } + } +} diff --git a/scripts/build/docker-compose.build.yml b/scripts/build/docker-compose.build.yml index e31268086..9d1936296 100644 --- a/scripts/build/docker-compose.build.yml +++ b/scripts/build/docker-compose.build.yml @@ -272,6 +272,7 @@ services: cp cs/rest/lovemining/target/lovemining-sut.jar /dist/ cp cs/rest/movies-xml/target/movies-xml-sut.jar /dist/ cp cs/rest/testing-system/target/testing-system-sut.jar /dist/ + cp cs/rest/flight-search-api/target/flight-search-api-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 @@ -283,6 +284,7 @@ services: cp em/external/rest/lovemining/target/lovemining-evomaster-runner.jar /dist/ cp em/external/rest/movies-xml/target/movies-xml-evomaster-runner.jar /dist/ cp em/external/rest/testing-system/target/testing-system-evomaster-runner.jar /dist/ + cp em/external/rest/flight-search-api/target/flight-search-api-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-wb.py b/scripts/dist-wb.py index f99c38d09..9f882f45e 100644 --- a/scripts/dist-wb.py +++ b/scripts/dist-wb.py @@ -322,6 +322,8 @@ def build_jdk_21_maven(): copy(folder + "/em/external/rest/movies-xml/target/movies-xml-evomaster-runner.jar", DIST) copy(folder + "/cs/rest/testing-system/target/testing-system-sut.jar", DIST) copy(folder + "/em/external/rest/testing-system/target/testing-system-evomaster-runner.jar", DIST) + copy(folder + "/cs/rest/flight-search-api/target/flight-search-api-sut.jar", DIST) + copy(folder + "/em/external/rest/flight-search-api/target/flight-search-api-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 889068631..496c0f728 100644 --- a/scripts/dockerize/data/sut.csv +++ b/scripts/dockerize/data/sut.csv @@ -51,3 +51,4 @@ kafka-rest,TRUE,-Dorg.apache.logging.log4j.level=INFO,kafka-rest.properties,,htt management-cassandra,TRUE,-Dmgmtapi.cql.tcp=cassandra:9999,-K true -H tcp://0.0.0.0:8080 -S mgmtapi.sock,http://localhost:8080/openapi.json,http://localhost:8080,FALSE,cassandra,"[{""name"": ""cassandra"", ""image_name"": ""k8ssandra/cass-management-api:4.1.12-v0.1.126"", ""tmp_fs"": """", ""environment"": ""HEAP_NEWSIZE: 128M;MAX_HEAP_SIZE: 512M;JVM_EXTRA_OPTS: -Ddb.unix_socket_file=/tmp/mgmtapi.sock"", ""volume"": ""./additional_files/management-cassandra/mgmtapi-bridge.py:/mgmtapi-bridge.py"", ""health_check_command"": ""test -S /tmp/mgmtapi.sock && cqlsh -e \""SELECT now() FROM system.local\"""", ""command"": ""[\""bash\"", \""-c\"", 'python3 /mgmtapi-bridge.py /tmp/mgmtapi.sock 9999 & exec cassandra -f']""}]" petclinic-rest,TRUE,,--server.port=8080 --spring.jpa.show-sql=false,http://localhost:8080/petclinic/v3/api-docs,http://localhost:8080,FALSE,, traccar,TRUE,,traccar.xml,,http://localhost:8080,TRUE,, +flight-search-api,TRUE,,--server.port=8080 --spring.data.mongodb.host=db --spring.data.mongodb.port=27017 --spring.data.mongodb.database=flightdatabase,http://localhost:8080/v3/api-docs,http://localhost:8080,FALSE,db,"[{""image_name"": ""mongo:7"", ""tmp_fs"": """", ""environment"": """", ""volume"": ""./additional_files/flight-search-api/flight-search-api-mongo-seed.js:/docker-entrypoint-initdb.d/flight-search-api-mongo-seed.js"", ""health_check_command"": ""mongosh --quiet --eval \""db.adminCommand('ping')\""""}]" diff --git a/statistics/data.csv b/statistics/data.csv index aeae1ea57..c355ee423 100644 --- a/statistics/data.csv +++ b/statistics/data.csv @@ -63,4 +63,5 @@ TRUE,kafka-rest,REST,Java,JDK 17,Maven,475,81418,Kafka,Confluent,50,FALSE,https: TRUE,management-cassandra,REST,Java,JDK 11,Maven,225,35096,Cassandra,Apache,63,FALSE,https://github.com/k8ssandra/management-api-for-apache-cassandra TRUE,petclinic-rest,REST,Java,JDK 17,Maven,109,8675,H2,Apache,43,FALSE,https://github.com/spring-petclinic/spring-petclinic-rest TRUE,traccar,REST,Java,JDK 21,Gradle,1478,141962,H2,Apache,117,TRUE,https://github.com/traccar/traccar +TRUE,flight-search-api,REST,Java,JDK 21,Maven,194,14440,MongoDB,MIT,40,TRUE,https://github.com/Rapter1990/flightsearchapi diff --git a/statistics/http-verbs.csv b/statistics/http-verbs.csv index 449a732fd..de086bdf9 100644 --- a/statistics/http-verbs.csv +++ b/statistics/http-verbs.csv @@ -10,6 +10,7 @@ digitalbanking,28,7,6,4,3,3,4,0,0,0 erc20-rest-service,8,0,5,0,0,0,0,0,0,0 familie-ba-sak,66,23,82,10,0,0,2,0,0,0 features-service,6,1,6,5,0,0,0,0,0,0 +flight-search-api,26,2,8,4,0,0,0,0,0,0 gdpr-kv,3,2,0,2,0,0,0,0,0,0 genome-nexus,13,0,10,0,0,0,0,0,0,0 gestaohospital,10,3,5,2,0,0,0,0,0,0 diff --git a/statistics/http-verbs.md b/statistics/http-verbs.md index 1f0dede4e..e68c1e34c 100644 --- a/statistics/http-verbs.md +++ b/statistics/http-verbs.md @@ -11,6 +11,7 @@ | erc20-rest-service | 8 | 0 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 13 | | familie-ba-sak | 66 | 23 | 82 | 10 | 0 | 0 | 2 | 0 | 0 | 0 | 183 | | features-service | 6 | 1 | 6 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 18 | +| flight-search-api | 26 | 2 | 8 | 4 | 0 | 0 | 0 | 0 | 0 | 0 | 40 | | gdpr-kv | 3 | 2 | 0 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 7 | | genome-nexus | 13 | 0 | 10 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 23 | | gestaohospital | 10 | 3 | 5 | 2 | 0 | 0 | 0 | 0 | 0 | 0 | 20 | @@ -52,4 +53,4 @@ | user-management | 7 | 2 | 7 | 5 | 0 | 0 | 0 | 0 | 0 | 0 | 21 | | webgoat | 50 | 10 | 112 | 8 | 8 | 8 | 8 | 0 | 0 | 0 | 204 | | youtube-mock | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | -| Total | 1027 | 174 | 755 | 171 | 21 | 20 | 53 | 0 | 0 | 0 | 2221 | +| Total | 1053 | 176 | 763 | 175 | 21 | 20 | 53 | 0 | 0 | 0 | 2261 | diff --git a/statistics/table_wfd.md b/statistics/table_wfd.md index 1e4540669..3da16b539 100644 --- a/statistics/table_wfd.md +++ b/statistics/table_wfd.md @@ -19,6 +19,7 @@ |REST|__erc20-rest-service__|1378|7|13|Java|JDK 8|Gradle||| |REST|__familie-ba-sak__|143556|1089|183|Kotlin|JDK 17|Maven|PostgreSQL|✓| |REST|__features-service__|2275|39|18|Java|JDK 8|Maven|H2|| +|REST|__flight-search-api__|14440|194|40|Java|JDK 21|Maven|MongoDB|✓| |REST|__gdpr-kv__|6399|62|7|Java|JDK 21|Gradle|DynamoDB|| |REST|__genome-nexus__|30004|405|23|Java|JDK 8|Maven|MongoDB|| |REST|__gestaohospital__|3506|33|20|Java|JDK 8|Maven|MongoDB||