Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,9 @@ scripts/dockerize/dockerfiles
/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_21_maven/cs/rest/adoptme/target/
/jdk_21_maven/em/external/rest/adoptme/target/
/jdk_21_maven/em/embedded/rest/adoptme/target/
/jdk_21_maven/cs/rest/arimaa/target/
/jdk_21_maven/em/external/rest/arimaa/target/
/jdk_21_maven/em/embedded/rest/arimaa/target/
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ 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 (42)
### REST: Java/Kotlin (43)

* **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)

* **Arimaa** (not-known license), [jdk_21_maven/cs/rest/arimaa](jdk_21_maven/cs/rest/arimaa), from [https://github.com/KEAArimaaProject/arimaa-backend](https://github.com/KEAArimaaProject/arimaa-backend)

Expand Down
13 changes: 13 additions & 0 deletions dockerfiles/adoptme.dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
FROM amazoncorretto:21-alpine-jdk

COPY ./dist/adoptme-sut.jar .
COPY ./dist/jacocoagent.jar .




ENTRYPOINT \
java \
-javaagent:jacocoagent.jar=output=tcpserver,address=*,port=6300,append=false,dumponexit=false \
-Xmx1G -jar adoptme-sut.jar \
--server.port=8080 --spring.neo4j.uri=bolt://db:7687 --spring.neo4j.authentication.username=neo4j --spring.neo4j.authentication.password=neo4j123
46 changes: 46 additions & 0 deletions dockerfiles/adoptme.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
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-adoptme: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-adoptme
sut-adoptme:
image: webfuzzing/wfd-adoptme:FINAL
# build:
# dockerfile: ./dockerfiles/adoptme.dockerfile
# context: ..
environment:
AUTH_PORT: ${AUTH_PORT:-8081}
ports:
- "${JACOCO_PORT:-6300}:6300"
depends_on:
db:
condition: service_healthy
db:
image: neo4j:5.26
tmpfs:
- '/data'
environment:
NEO4J_AUTH: neo4j/neo4j123
NEO4J_server_memory_heap_max__size: 512M
NEO4J_server_memory_pagecache_size: 256M
healthcheck:
test: ['CMD', 'cypher-shell', '-u', 'neo4j', '-p', 'neo4j123', 'RETURN 1']
interval: 30s
timeout: 30s
retries: 3
1 change: 1 addition & 0 deletions experiments/bb-exp.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ def __init__(self, name, auth, sleep, schemaformat, classfiles):

# To ge the SUTs, you need in EMB to run the script "scripts/dist.py"
SUTS = [
Sut("adoptme",False,SLEEP,JSON,["jdk_21_maven/cs/rest/adoptme/target/classes"]),
Sut("arimaa",True,SLEEP,JSON,["jdk_21_maven/cs/rest/arimaa/target/classes"]),
Sut("bibliothek",False,SLEEP,JSON,["jdk_17_gradle/cs/rest/bibliothek/build/classes"]),
Sut("blogapi",True, SLEEP,JSON,["jdk_8_maven/cs/rest/original/blogapi/target/classes"]),
Expand Down
1 change: 1 addition & 0 deletions experiments/wb-exp.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ def __init__(self, name, platform):

SUTS = [
# REST
Sut("adoptme", JDK_21),
Sut("arimaa", JDK_21),
Sut("bibliothek", JDK_17),
Sut("blogapi",JDK_8),
Expand Down
1 change: 1 addition & 0 deletions jacoco.dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ ENV CLASS_FILES=/classfiles

### IMPORTANT!!!: must be kept in sync with what declared in run-tools.py, which will need to be updated
### any time in this file we add a new entry to WFD
COPY jdk_21_maven/cs/rest/adoptme/target/classes ${CLASS_FILES}/jdk_21_maven/cs/rest/adoptme/target/classes
COPY jdk_21_maven/cs/rest/arimaa/target/classes ${CLASS_FILES}/jdk_21_maven/cs/rest/arimaa/target/classes
COPY jdk_17_gradle/cs/rest/bibliothek/build/classes ${CLASS_FILES}/jdk_17_gradle/cs/rest/bibliothek/build/classes
COPY jdk_8_maven/cs/rest/original/blogapi/target/classes ${CLASS_FILES}/jdk_8_maven/cs/rest/original/blogapi/target/classes
Expand Down
13 changes: 13 additions & 0 deletions jdk_21_maven/cs/rest/adoptme/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- MODIFIED-->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.8.9</version>
</dependency>
<!-- MODIFIED-->
</dependencies>

<build>
Expand All @@ -73,6 +80,12 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<!-- MODIFIED-->
<!-- WFD expects a single self-contained "adoptme-sut.jar". The classifier keeps
the plain jar as the main artifact, which the embedded driver depends on. -->
<finalName>adoptme</finalName>
<classifier>sut</classifier>
<!-- MODIFIED-->
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
Expand Down
1 change: 1 addition & 0 deletions jdk_21_maven/cs/rest/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@


<modules>
<module>adoptme</module>
<module>joinus</module>
<module>person-controller</module>
<module>redis-sample</module>
Expand Down
46 changes: 46 additions & 0 deletions jdk_21_maven/em/embedded/rest/adoptme/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<artifactId>evomaster-benchmark-jdk21-em-embedded-rest-adoptme</artifactId>
<packaging>jar</packaging>

<parent>
<groupId>org.evomaster</groupId>
<artifactId>evomaster-benchmark-jdk21-em-embedded-rest</artifactId>
<version>4.3.1-SNAPSHOT</version>
</parent>

<!-- Embedded mode puts the SUT and the driver on one classpath, and the SUT's parent pom does
not apply here. Without this import, transitive dependencies win instead (eg testcontainers'
slf4j-api 1.7 replaces the 2.x Spring Boot needs). -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>3.5.6</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<!-- The SUT as a library -->
<dependency>
<groupId>com.programacion3</groupId>
<artifactId>adoptme</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers</artifactId>
<scope>compile</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
package em.embedded.adoptme;

import com.programacion3.adoptme.AdoptMApplication;
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 org.testcontainers.containers.wait.strategy.Wait;

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
* Class used to start/stop the SUT.
*/
public class EmbeddedEvoMasterController extends EmbeddedSutController {

private static final String NEO4J_VERSION = "5.26";

private static final int NEO4J_BOLT_PORT = 7687;

private static final int NEO4J_HTTP_PORT = 7474;

private static final String NEO4J_USER = "neo4j";

private static final String NEO4J_PASSWORD = "neo4j123";

private static final String AUTH_HEADER = "Basic " + Base64.getEncoder().encodeToString(
(NEO4J_USER + ":" + NEO4J_PASSWORD).getBytes(StandardCharsets.UTF_8));

private static final HttpClient HTTP = HttpClient.newHttpClient();

/*
The SUT seeds the graph itself at startup, so the seed is copied out of the database
instead of being duplicated here: one shadow node per adopter, with the same properties.
*/
private static final String BACKUP_SEEDED_ADOPTERS =
"MATCH (a:Adopter) CREATE (b:SeedBackup) SET b = properties(a)";

private static final String DELETE_ADDED_ADOPTERS =
"MATCH (a:Adopter) WHERE NOT EXISTS { MATCH (:SeedBackup {id: a.id}) } DETACH DELETE a";

private static final String RESTORE_SEEDED_ADOPTERS =
"MATCH (b:SeedBackup) MERGE (a:Adopter {id: b.id}) SET a = properties(b)";

private static final GenericContainer neo4j = new GenericContainer("neo4j:" + NEO4J_VERSION)
.withEnv("NEO4J_AUTH", NEO4J_USER + "/" + NEO4J_PASSWORD)
.withEnv("NEO4J_server_memory_heap_max__size", "512M")
.withEnv("NEO4J_server_memory_pagecache_size", "256M")
.withExposedPorts(NEO4J_BOLT_PORT, NEO4J_HTTP_PORT)
.waitingFor(Wait.forLogMessage(".*Started\\..*", 1))
.withStartupTimeout(Duration.ofMinutes(3));


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;

public EmbeddedEvoMasterController() {
this(0);
}

public EmbeddedEvoMasterController(int port) {
setControllerPort(port);
}


@Override
public String startSut() {

neo4j.start();

ctx = SpringApplication.run(AdoptMApplication.class, new String[]{
"--server.port=0",
"--spring.neo4j.uri=bolt://" + neo4j.getHost() + ":" + neo4j.getMappedPort(NEO4J_BOLT_PORT),
"--spring.neo4j.authentication.username=" + NEO4J_USER,
"--spring.neo4j.authentication.password=" + NEO4J_PASSWORD
});

runCypher(BACKUP_SEEDED_ADOPTERS);

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;
}

neo4j.stop();
}

@Override
public String getPackagePrefixesToCover() {
return "com.programacion3.adoptme.";
}

/*
POST /adopters is the only endpoint that writes: it can add adopters, and it overwrites a
seeded one when it reuses its id. The shelters, dogs and relationships are read-only.
*/
@Override
public void resetStateOfSUT() {
if (neo4j.isRunning()) {
runCypher(DELETE_ADDED_ADOPTERS, RESTORE_SEEDED_ADOPTERS);
}
}


@Override
public List<DbSpecification> getDbSpecifications() {
return null;
}


@Override
public List<AuthenticationDto> getInfoForAuthentication() {
return null;
}


/*
/routes/tsp/bnb is factorial in its "nodes" (default = all 15 shelters) and never returns;
Black-box runs need excludes endpoints.
*/
@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;
}

/** Sends the given Cypher statements to Neo4j as a single transaction, over its HTTP API. */
private void runCypher(String... statements) {
String body = Arrays.stream(statements)
.map(s -> "{\"statement\":\"" + s + "\"}")
.collect(Collectors.joining(",", "{\"statements\":[", "]}"));
String url = "http://" + neo4j.getHost() + ":" + neo4j.getMappedPort(NEO4J_HTTP_PORT)
+ "/db/neo4j/tx/commit";

HttpResponse<String> response;
try {
response = HTTP.send(HttpRequest.newBuilder(URI.create(url))
.timeout(Duration.ofSeconds(30))
.header("Content-Type", "application/json")
.header("Authorization", AUTH_HEADER)
.POST(HttpRequest.BodyPublishers.ofString(body))
.build(), HttpResponse.BodyHandlers.ofString());
} catch (IOException | InterruptedException e) {
throw new IllegalStateException("Could not run " + body, e);
}
// a rejected statement comes back as 200 with the error in the body, so check both
if (response.statusCode() != 200 || !response.body().contains("\"errors\":[]")) {
throw new IllegalStateException("Neo4j rejected " + body + ": " + response.body());
}
}

}
Loading
Loading