Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ public enum ReplacementCategory {
*/
MONGO,

/**
* Replacements to handle CASSANDRA command intereception
*/
CASSANDRA,

/**
* Replacements to handle OPENSEARCH command interceptions
*/
Expand Down
23 changes: 23 additions & 0 deletions client-java/instrumentation/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,11 @@
<artifactId>mongodb-driver-sync</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.cassandra</groupId>
<artifactId>java-driver-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.neo4j.driver</groupId>
<artifactId>neo4j-java-driver</artifactId>
Expand All @@ -213,6 +218,24 @@
</dependency>
</dependencies>

<!--
The Cassandra Java driver (java-driver-core) depends on a newer version of Netty than what
other test dependencies (e.g. Spring Boot 2.5.x) pull in. When Maven resolves them separately,
different Netty modules end up in different versions, causing NoSuchMethodError at runtime.
Pinning all Netty modules here forces a consistent version across the test classpath.
-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-bom</artifactId>
<version>4.1.94.Final</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<plugins>
<plugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ public StatementDescription(String line, String method) {

private final Set<MongoFindCommand> mongoFindCommandData = new CopyOnWriteArraySet<>();

private final Set<ExecutedCqlCommand> executedCqlCommandData = new CopyOnWriteArraySet<>();

private final Set<Neo4JRunCommand> neo4JRunCommandData = new CopyOnWriteArraySet<>();

private final Set<OpenSearchCommand> openSearchCommandData = new CopyOnWriteArraySet<>();
Expand All @@ -122,6 +124,10 @@ public Set<MongoFindCommand> getMongoInfoData(){
return Collections.unmodifiableSet(mongoFindCommandData);
}

public Set<ExecutedCqlCommand> getCqlInfoData(){
return Collections.unmodifiableSet(executedCqlCommandData);
}

public Set<Neo4JRunCommand> getNeo4JInfoData(){
return Collections.unmodifiableSet(neo4JRunCommandData);
}
Expand All @@ -146,6 +152,10 @@ public void addMongoInfo(MongoFindCommand info){
mongoFindCommandData.add(info);
}

public void addCqlInfo(ExecutedCqlCommand info){
executedCqlCommandData.add(info);
}

public void addNeo4JInfo(Neo4JRunCommand info){
neo4JRunCommandData.add(info);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package org.evomaster.client.java.instrumentation;

import java.io.Serializable;
import java.util.Objects;

/**
* Info related to CQL command execution
*/
public class ExecutedCqlCommand implements Serializable {

/**
* A constant to represent that execution time could not be obtained.
*/
public static final long FAILURE_EXECUTION_TIME = -1L;

/**
* The actual CQL string with the command that was executed
*/
private final String cqlCommand;

/**
* Whether the CQL command failed, for any reason
*/
private final boolean threwCqlException;

/**
* Execution time
*/
private final long executionTime;

public ExecutedCqlCommand(String cqlCommand, boolean threwCqlException, long executionTime) {
this.cqlCommand = cqlCommand;
this.threwCqlException = threwCqlException;
this.executionTime = executionTime;
}

public String getCqlCommand() {
return cqlCommand;
}

public boolean hasThrownCqlException() {
return threwCqlException;
}

public long getExecutionTime() {
return executionTime;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ExecutedCqlCommand executedCqlCommand = (ExecutedCqlCommand) o;
return threwCqlException == executedCqlCommand.threwCqlException && Objects.equals(cqlCommand, executedCqlCommand.cqlCommand);
}

@Override
public int hashCode() {
return Objects.hash(cqlCommand, threwCqlException);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ public static void setExecutingInitMongo(boolean executingInitMongo){
ExecutionTracer.setExecutingInitMongo(executingInitMongo);
}

public static void setExecutingInitCassandra(boolean executingInitCassandra){
ExecutionTracer.setExecutingInitCassandra(executingInitCassandra);
}

public static void setExecutingAction(boolean executingAction){
ExecutionTracer.setExecutingAction(executingAction);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ public static List<MethodReplacementClass> getList() {
new ByteClassReplacement(),
new CharacterClassReplacement(),
new CollectionClassReplacement(),
new CqlSessionClassReplacement(),
new CursorPreparerClassReplacement(),
new DateClassReplacement(),
new DateFormatClassReplacement(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.evomaster.client.java.instrumentation.coverage.methodreplacement.thirdpartyclasses;

import org.evomaster.client.java.instrumentation.ExecutedCqlCommand;
import org.evomaster.client.java.instrumentation.coverage.methodreplacement.Replacement;
import org.evomaster.client.java.instrumentation.coverage.methodreplacement.ThirdPartyMethodReplacementClass;
import org.evomaster.client.java.instrumentation.coverage.methodreplacement.UsageFilter;
import org.evomaster.client.java.instrumentation.shared.ReplacementCategory;
import org.evomaster.client.java.instrumentation.shared.ReplacementType;
import org.evomaster.client.java.instrumentation.staticstate.ExecutionTracer;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class CqlSessionClassReplacement extends ThirdPartyMethodReplacementClass {
private static final CqlSessionClassReplacement singleton = new CqlSessionClassReplacement();

@Override
protected String getNameOfThirdPartyTargetClass() {
return "com.datastax.oss.driver.api.core.CqlSession";
}

@Replacement(replacingStatic = false, type = ReplacementType.TRACKER, id = "findSyncString", usageFilter = UsageFilter.ANY, category = ReplacementCategory.CASSANDRA, castTo = "com.datastax.oss.driver.api.core.cql.ResultSet")
public static Object execute(Object cqlSession, String query) {
return handleCqlExecute("findSyncString", cqlSession, query);
}

private static Object handleCqlExecute(String id, Object cqlSession, String query) {
long start = System.currentTimeMillis();
try {
Method executeMethod = retrieveExecuteMethod(id, cqlSession);
Object result = executeMethod.invoke(cqlSession, query);
long end = System.currentTimeMillis();
long executionTime = end - start;
ExecutedCqlCommand info = new ExecutedCqlCommand(query, false, executionTime);
ExecutionTracer.addCqlInfo(info);
return result;
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw (RuntimeException) e.getCause();
}
}

private static Method retrieveExecuteMethod(String id, Object cqlSession){
return getOriginal(singleton, id, cqlSession);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

/**
* Code running in the Java Agent to receive and respond to the
* requests from the the SUT controller.
* requests from the SUT controller.
*/
public class AgentController {

Expand Down Expand Up @@ -94,6 +94,10 @@ public static void start(int port){
handleExecutingInitMongo();
sendCommand(Command.ACK);
break;
case EXECUTING_INIT_CASSANDRA:
handleExecutingInitCassandra();
sendCommand(Command.ACK);
break;
case EXECUTING_ACTION:
handleExecutingAction();
sendCommand(Command.ACK);
Expand Down Expand Up @@ -180,6 +184,16 @@ private static void handleExecutingInitMongo() {
}
}

private static void handleExecutingInitCassandra() {
try {
Object msg = in.readObject();
Boolean executingInitCassandra = (Boolean) msg;
InstrumentationController.setExecutingInitCassandra(executingInitCassandra);
} catch (Exception e){
SimpleLogger.error("Failure in handling executing-init-cassandra: "+e.getMessage());
}
}

private static void handleExecutingAction() {
try {
Object msg = in.readObject();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public enum Command implements Serializable {
KILL_SWITCH,
EXECUTING_INIT_SQL,
EXECUTING_INIT_MONGO,
EXECUTING_INIT_CASSANDRA,
EXECUTING_ACTION,
BOOT_TIME_INFO,
EXTRACT_JVM_DTO,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public class ExecutionTracer {

private static boolean executingInitMongo = false;

private static boolean executingInitCassandra = false;

private static boolean executingInitRedis = false;

private static boolean executingInitNeo4J = false;
Expand Down Expand Up @@ -199,6 +201,10 @@ public static void setExecutingInitMongo(boolean executingInitMongo) {
ExecutionTracer.executingInitMongo = executingInitMongo;
}

public static void setExecutingInitCassandra(boolean executingInitCassandra) {
ExecutionTracer.executingInitCassandra = executingInitCassandra;
}

public static void setExecutingInitRedis(boolean executingInitRedis) {
ExecutionTracer.executingInitRedis = executingInitRedis;
}
Expand Down Expand Up @@ -435,6 +441,11 @@ public static void addMongoInfo(MongoFindCommand info){
getCurrentAdditionalInfo().addMongoInfo(info);
}

public static void addCqlInfo(ExecutedCqlCommand info){
if (!executingInitCassandra)
getCurrentAdditionalInfo().addCqlInfo(info);
}

public static void addNeo4JInfo(Neo4JRunCommand info){
if (!executingInitNeo4J)
getCurrentAdditionalInfo().addNeo4JInfo(info);
Expand Down
Loading