Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
684a8f5
wip
francastagna Nov 20, 2025
26aa643
wip: testing graph creation
francastagna Nov 25, 2025
18b4f1e
added algoritm logic
francastagna Dec 2, 2025
580b45a
Merge branch 'master' into feature/dynamosa-3
francastagna Dec 2, 2025
550f4ba
moved annotated methods
francastagna Dec 2, 2025
1a14ed9
updated docs/options.md
francastagna Dec 2, 2025
1e7634c
updated client-java/pom.xml
francastagna Dec 3, 2025
9477a69
fixes
francastagna Dec 3, 2025
0782b66
refactoring: remove unused class
francastagna Dec 3, 2025
d29d515
refactoring: cleaning stuff
francastagna Dec 3, 2025
755bd48
refactoring: cleaning stuff
francastagna Dec 3, 2025
83149d3
refactoring: cleaning stuff
francastagna Dec 3, 2025
300ba05
add tests
francastagna Dec 5, 2025
e74328f
Merge branch 'master' into feature/dynamosa-3
francastagna Dec 5, 2025
9f184af
enablegraphs and writecfg is false by default
francastagna Dec 5, 2025
7f63038
fixing stuff
francastagna Dec 5, 2025
38b68f8
update docs/options.md
francastagna Dec 5, 2025
a44bc04
Address Andrea's initial feedback on PR #1399
francastagna Dec 15, 2025
31f7fb8
Merge branch 'master' into feature/dynamosa-3
francastagna Dec 15, 2025
2484d00
updating comment
francastagna Dec 15, 2025
788af33
Merge branch 'master' into feature/dynamosa-3
francastagna Jan 16, 2026
d509a3d
change writeCfg config default value to false
francastagna Jan 16, 2026
f725bf9
improve error handling of IOException in EvoMasterGraph
francastagna Jan 16, 2026
b539721
remove old comment in BranchPool
francastagna Jan 16, 2026
6f8ebeb
replaced all System.out.println() calls with SimpleLogger calls in Co…
francastagna Jan 16, 2026
cbb9af3
Merge branch 'master' into feature/dynamosa-3
francastagna Jan 16, 2026
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.evomaster.client.java.controller.api.dto;

import java.io.Serializable;

/**
* Descriptor and numeric id for a branch objective (true or false outcome).
*/
public class BranchObjectiveDto implements Serializable {

public int id;
public String descriptiveId;
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.evomaster.client.java.controller.api.dto;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

/**
* Serializable representation of the control-dependence information of a method.
* Contains only the data needed by EvoMaster core: branch objective identifiers,
* the subset that are roots, and the parent-child relationships between them.
*/
public class ControlDependenceGraphDto implements Serializable {

public String className;
public String methodName;
public List<BranchObjectiveDto> objectives = new ArrayList<>();
public List<Integer> rootObjectiveIds = new ArrayList<>();
public List<DependencyEdgeDto> edges = new ArrayList<>();
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.evomaster.client.java.controller.api.dto;

import java.io.Serializable;

/**
* Directed edge describing that parentObjectiveId must be covered before childObjectiveId.
*/
public class DependencyEdgeDto implements Serializable {

public int parentObjectiveId;
public int childObjectiveId;
}

Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,19 @@ public class SutRunDto {
*/
public String methodReplacementCategories;

/**
* Whether to enable Control Dependence Graph generation in the Java agent
*/
public Boolean enableControlDependenceGraphs;

/**
* Whether to write generated graphs (DOT/PNGs) to disk on the agent side.
* <p>
* <b>Debugging only</b>: when enabled, graph files are written to a fixed location,
* so running multiple experiments in parallel will cause file overwrites.
*/
public Boolean writeCfg;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this only for debugging purposes? if so, clarify it in the comment. also, i guess this would not work when running expeirments in parallel, as all will overwrite same file?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, only for debugging porpuses.
Probably won't work when running experiments in parallel you are right.



public SutRunDto() {
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,9 @@ public class TestResultsDto {
public List<AdditionalInfoDto> additionalInfoList = new ArrayList<>();

public List<ExtraHeuristicsDto> extraHeuristics = new ArrayList<>();

/**
* Incremental control-dependence graphs discovered since the last handshake.
*/
public List<ControlDependenceGraphDto> controlDependenceGraphs = new ArrayList<>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import org.evomaster.client.java.controller.api.dto.problem.rpc.ScheduleTaskInvocationDto;
import org.evomaster.client.java.controller.internal.SutController;
import org.evomaster.client.java.instrumentation.*;
import org.evomaster.client.java.instrumentation.external.ControlDependenceSnapshot;
import org.evomaster.client.java.controller.api.dto.ControlDependenceGraphDto;
import org.evomaster.client.java.instrumentation.object.ClassToSchema;
import org.evomaster.client.java.instrumentation.staticstate.ExecutionTracer;
import org.evomaster.client.java.instrumentation.staticstate.ObjectiveRecorder;
Expand All @@ -31,6 +33,8 @@
*/
public abstract class EmbeddedSutController extends SutController {

private int controlDependenceGraphIndex = 0;

@Override
public final void setupForGeneratedTest(){
//In the past, we configured P6Spy here
Expand Down Expand Up @@ -138,4 +142,21 @@ public final void getJvmDtoSchema(List<String> dtoNames) {
public final void bootingSut(boolean bootingSut) {
ObjectiveRecorder.setBooting(bootingSut);
}

@Override
public List<ControlDependenceGraphDto> getControlDependenceGraphs() {
ControlDependenceSnapshot snapshot = InstrumentationController.getControlDependenceSnapshot(controlDependenceGraphIndex);
controlDependenceGraphIndex = snapshot.getNextIndex();
return snapshot.getGraphs();
}

@Override
public void setControlDependenceGraphsEnabled(boolean enableGraphs) {
InstrumentationController.setControlDependenceGraphsEnabled(enableGraphs);
}

@Override
public void setWriteCfgEnabled(boolean writeCfg) {
InstrumentationController.setWriteCfgEnabled(writeCfg);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import org.evomaster.client.java.controller.internal.SutController;
import org.evomaster.client.java.instrumentation.external.JarAgentLocator;
import org.evomaster.client.java.instrumentation.external.ServerController;
import org.evomaster.client.java.instrumentation.external.ControlDependenceGraphConfigDto;
import org.evomaster.client.java.controller.api.dto.ControlDependenceGraphDto;

import java.io.BufferedReader;
import java.io.IOException;
Expand Down Expand Up @@ -447,6 +449,15 @@ public BootTimeInfoDto getBootTimeInfoDto() {
return getBootTimeInfoDto(serverController.handleBootTimeObjectiveInfo());
}

@Override
public List<ControlDependenceGraphDto> getControlDependenceGraphs() {
if (!isInstrumentationActivated()){
return Collections.emptyList();
}
List<ControlDependenceGraphDto> graphs = serverController.getControlDependenceGraphs();
return graphs != null ? graphs : Collections.emptyList();
}

@Override
public final void newActionSpecificHandler(ActionDto dto) {
if (isInstrumentationActivated()) {
Expand Down Expand Up @@ -522,6 +533,28 @@ public final void setExecutingInitMongo(boolean executingInitMongo) {
ExecutionTracer.setExecutingInitMongo(executingInitMongo);
}

/**
* Send CDG configuration to the Java Agent.
*/
public final void setControlDependenceGraphsEnabled(boolean enableGraphs) {
checkInstrumentation();
ControlDependenceGraphConfigDto dto = new ControlDependenceGraphConfigDto();
dto.enableGraphs = enableGraphs;
dto.writeCfg = null;
serverController.setControlDependenceGraphConfig(dto);
}

/**
* Control whether the agent writes DOT/PNG graphs to disk.
*/
public final void setWriteCfgEnabled(boolean writeCfg) {
checkInstrumentation();
ControlDependenceGraphConfigDto dto = new ControlDependenceGraphConfigDto();
dto.enableGraphs = null;
dto.writeCfg = writeCfg;
serverController.setControlDependenceGraphConfig(dto);
}

@Override
public final void setExecutingAction(boolean executingAction){
checkInstrumentation();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.evomaster.client.java.sql.SqlScriptRunner;
import org.evomaster.client.java.controller.problem.rpc.schema.LocalAuthSetupSchema;
import org.evomaster.client.java.instrumentation.*;
import org.evomaster.client.java.controller.api.dto.ControlDependenceGraphDto;
import org.evomaster.client.java.instrumentation.shared.StringSpecializationInfo;
import org.evomaster.client.java.instrumentation.staticstate.ExecutionTracer;
import org.evomaster.client.java.utils.SimpleLogger;
Expand Down Expand Up @@ -254,7 +255,6 @@ public Response getSutInfo(@Context HttpServletRequest httpServletRequest) {
return Response.status(500).entity(WrappedResponseDto.withError(msg)).build();
}


return Response.status(200).entity(WrappedResponseDto.withData(dto)).build();
}

Expand Down Expand Up @@ -377,6 +377,11 @@ public Response runSut(SutRunDto dto, @Context HttpServletRequest httpServletReq
if (!noKillSwitch(() -> sutController.isSutRunning())) {
noKillSwitch(() -> sutController.bootingSut(true));
baseUrlOfSUT = noKillSwitch(() -> sutController.startSut());
// Configure CDG generation on the agent, if requested by core
Boolean enableGraphs = dto.enableControlDependenceGraphs;
if (enableGraphs != null) noKillSwitch(() -> sutController.setControlDependenceGraphsEnabled(enableGraphs));
Boolean writeCfg = dto.writeCfg;
if (writeCfg != null) noKillSwitch(() -> sutController.setWriteCfgEnabled(writeCfg));
noKillSwitch(() -> sutController.bootingSut(false));
if (baseUrlOfSUT == null) {
//there has been an internal failure in starting the SUT
Expand Down Expand Up @@ -588,6 +593,12 @@ public Response getTestResults(
SimpleLogger.error(msg);
return Response.status(500).entity(WrappedResponseDto.withError(msg)).build();
}

List<ControlDependenceGraphDto> cdgs =
noKillSwitch(() -> sutController.getControlDependenceGraphs());
if (cdgs != null && !cdgs.isEmpty()) {
dto.controlDependenceGraphs.addAll(cdgs);
}
// }
// else {
// // there is still some data that we need during minimization
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import org.evomaster.client.java.instrumentation.AdditionalInfo;
import org.evomaster.client.java.instrumentation.BootTimeObjectiveInfo;
import org.evomaster.client.java.instrumentation.TargetInfo;
import org.evomaster.client.java.controller.api.dto.ControlDependenceGraphDto;
import org.evomaster.client.java.instrumentation.staticstate.UnitsInfoRecorder;
import org.evomaster.client.java.utils.SimpleLogger;
import org.glassfish.jersey.jackson.JacksonFeature;
Expand Down Expand Up @@ -1564,6 +1565,15 @@ public abstract List<TargetInfo> getTargetInfos(Collection<Integer> ids,

public abstract void setExecutingAction(boolean executingAction);

/**
* Enable/disable Control Dependence Graph generation in the Java agent.
*/
public abstract void setControlDependenceGraphsEnabled(boolean enableGraphs);

/**
* Enable/disable writing graphs to disk in the Java agent.
*/
public abstract void setWriteCfgEnabled(boolean writeCfg);

/**
* specify whether the SUT is booting (ie starting up), or not.
Expand All @@ -1576,6 +1586,8 @@ public abstract List<TargetInfo> getTargetInfos(Collection<Integer> ids,

public abstract BootTimeInfoDto getBootTimeInfoDto();

public abstract List<ControlDependenceGraphDto> getControlDependenceGraphs();

protected BootTimeInfoDto getBootTimeInfoDto(BootTimeObjectiveInfo info){
if (info == null)
return null;
Expand Down
5 changes: 4 additions & 1 deletion client-java/instrumentation/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@
<groupId>org.evomaster</groupId>
<artifactId>evomaster-client-java-instrumentation-shared</artifactId>
</dependency>
<dependency>
<groupId>org.evomaster</groupId>
<artifactId>evomaster-client-java-controller-api</artifactId>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this new dependency necessary? why?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! The instrumentation module uses DTOs from controller-api to exchange control dependence graph information with the controller.

Specifically:
GraphPool.java (lines 17-19) imports ControlDependenceGraphDto, BranchObjectiveDto, and DependencyEdgeDto

These DTOs are used in GraphPool.buildControlDependenceDto() (lines 344-418) to build the graph representation that gets exported to the controller

</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
Expand Down Expand Up @@ -181,7 +185,6 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package org.evomaster.client.java.instrumentation;

import org.evomaster.client.java.instrumentation.object.ClassToSchema;
import org.evomaster.client.java.instrumentation.graphs.GraphPool;
import org.evomaster.client.java.instrumentation.staticstate.ExecutionTracer;
import org.evomaster.client.java.instrumentation.staticstate.ObjectiveRecorder;
import org.evomaster.client.java.instrumentation.staticstate.UnitsInfoRecorder;
import org.evomaster.client.java.instrumentation.graphs.ControlDependenceGraphConfig;
import org.evomaster.client.java.instrumentation.external.ControlDependenceSnapshot;

import java.util.ArrayList;
import java.util.Collection;
Expand All @@ -16,6 +18,7 @@ public class InstrumentationController {
public static void resetForNewSearch(){
ExecutionTracer.reset();
ObjectiveRecorder.reset(false);
GraphPool.refreshAllCdgs();
}

/*
Expand Down Expand Up @@ -146,4 +149,16 @@ public static void extractSpecifiedDto(List<String> dtoNames){
UnitsInfoRecorder.registerSpecifiedDtoSchema(ExtractJvmClass.extractAsSchema(dtoNames));
}

public static ControlDependenceSnapshot getControlDependenceSnapshot(int fromIndex){
return GraphPool.exportSnapshotFromIndex(fromIndex);
}

public static void setControlDependenceGraphsEnabled(boolean enableGraphs) {
ControlDependenceGraphConfig.setEnableGraphs(enableGraphs);
}

public static void setWriteCfgEnabled(boolean writeCfg) {
ControlDependenceGraphConfig.setWriteCfgEnabled(writeCfg);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import org.evomaster.client.java.instrumentation.shared.ClassName;
import org.evomaster.client.java.instrumentation.staticstate.UnitsInfoRecorder;
import org.evomaster.client.java.utils.SimpleLogger;
import org.evomaster.client.java.instrumentation.graphs.ControlDependenceGraphConfig;
import org.evomaster.client.java.instrumentation.graphs.visitor.CFGClassVisitor;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
Expand Down Expand Up @@ -65,11 +67,15 @@ public byte[] transformBytes(ClassLoader classLoader, ClassName className, Class
ClassNode cn = new ClassNode();
reader.accept(cn, readFlags);

if(canInstrumentForCoverage(className)){
boolean canCollectCoverage = canInstrumentForCoverage(className);
if(canCollectCoverage){
if (ControlDependenceGraphConfig.isGraphsEnabled()){
cv = new CFGClassVisitor(classLoader, cv);
}
cv = new CoverageClassVisitor(cv, className);
} else {
cv = new ThirdPartyClassVisitor(cv, className);
}
}

try {
cn.accept(cv);
Expand Down
Loading