Skip to content

starting addressing #1154 #1246

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 23, 2025
Merged
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
@@ -31,4 +31,6 @@ public class ControllerConstants {
public static final String MONGO_INSERTION = "/mongoInsertion";

public static final String POST_SEARCH_ACTION = "/postSearchAction";

public static final String DERIVE_PARAMS = "/deriveParams";
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.evomaster.client.java.controller.api.dto.problem;

import org.evomaster.client.java.controller.api.dto.problem.param.RestDerivedParamDto;

import java.util.List;

/**
@@ -25,4 +27,7 @@ public class RestProblemDto extends ProblemInfoDto{
* should not be set
*/
public String openApiSchema;


public List<RestDerivedParamDto> derivedParams;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package org.evomaster.client.java.controller.api.dto.problem.param;

public class DeriveParamResponseDto {

public String paramName;

public String paramValue;

public Integer actionIndex;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.evomaster.client.java.controller.api.dto.problem.param;

public class DerivedParamChangeReqDto {

public String paramName;

public String jsonData;

public String entryPoint;

public Integer actionIndex;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.evomaster.client.java.controller.api.dto.problem.param;

import java.util.Set;

public class RestDerivedParamDto {

/**
* The name of the parameter
*/
public String paramName;

/**
* The context in which this parameter is used, eg, whether it is a body payload or a query parameter.
* This information is needed, as EM will need to determine which other values to use to derive this param.
*/
public String context;

/**
* In case the parameter is used differently in different endpoints, specify for which endpoints this
* derivation applies. If left null, it will apply to all endpoints where this param is present.
*/
public Set<String> endpointPaths;

/**
* Optional positive integer specifying in which order the updates are done.
* Left empty is equivalent to set it to 0.
*
* If all updates are independent (or there is only 1), then there is no point in specifying this value.
* However, if the derivation of A depends on first deriving B, then A should get an higher order than B,
* eg 1 vs 0.
* In this case, first B is computed based on current state, and then, A is computed with current state
* updated with derived B.
*/
public Integer order;
}
Original file line number Diff line number Diff line change
@@ -8,6 +8,9 @@
import org.evomaster.client.java.controller.api.dto.database.operations.MongoDatabaseCommandDto;
import org.evomaster.client.java.controller.api.dto.database.operations.MongoInsertionResultsDto;
import org.evomaster.client.java.controller.api.dto.problem.*;
import org.evomaster.client.java.controller.api.dto.problem.param.DeriveParamResponseDto;
import org.evomaster.client.java.controller.api.dto.problem.param.DerivedParamChangeReqDto;
import org.evomaster.client.java.controller.api.dto.problem.param.RestDerivedParamDto;
import org.evomaster.client.java.controller.api.dto.problem.rpc.ScheduleTaskInvocationsDto;
import org.evomaster.client.java.controller.api.dto.problem.rpc.ScheduleTaskInvocationsResult;
import org.evomaster.client.java.controller.mongo.MongoScriptRunner;
@@ -206,6 +209,14 @@ public Response getSutInfo(@Context HttpServletRequest httpServletRequest) {
dto.restProblem.endpointsToSkip = rp.getEndpointsToSkip();
dto.restProblem.openApiSchema = rp.getOpenApiSchema();
dto.restProblem.servicesToNotMock = servicesToNotMock;
dto.restProblem.derivedParams = rp.getDerivedParams().stream()
.map(p -> new RestDerivedParamDto(){{
paramName = p.paramName;
context = p.context.toString();
endpointPaths = p.endpointPaths;
order = p.order;
}})
.collect(Collectors.toList());

} else if (info instanceof GraphQlProblem) {
GraphQlProblem p = (GraphQlProblem) info;
@@ -640,6 +651,42 @@ public Response scheduleTasksCommand(
return Response.status(200).entity(WrappedResponseDto.withData(responseDto)).build();
}


@Path(ControllerConstants.DERIVE_PARAMS)
@Consumes(MediaType.APPLICATION_JSON)
@POST
public Response deriveParams(List<DerivedParamChangeReqDto> dtos){

List<DeriveParamResponseDto> results = new ArrayList<>();
List<String> errors = new ArrayList<>();

for(DerivedParamChangeReqDto dto : dtos){
noKillSwitch(() -> {
try {
String value = sutController.deriveObjectParameterData(dto.paramName, dto.jsonData, dto.entryPoint);
DeriveParamResponseDto response = new DeriveParamResponseDto();
response.paramName = dto.paramName;
response.paramValue = value;
response.actionIndex = dto.actionIndex;
results.add(response);
} catch (Exception e) {
String msg = "ERROR: failed to derived object parameter for '"
+ dto.paramName +"': " + e.getMessage();
SimpleLogger.error(msg, e);
errors.add(msg);
}
});
}

if(!errors.isEmpty()){
String msg = "There were " + errors.size() + " errors.\n";
msg += String.join("\n", errors);
return Response.status(500).entity(WrappedResponseDto.withError(msg)).build();
}

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

@Path(ControllerConstants.NEW_ACTION)
@Consumes(MediaType.APPLICATION_JSON)
@PUT
Original file line number Diff line number Diff line change
@@ -241,6 +241,20 @@ public final void setControllerHost(String controllerHost) {
this.controllerHost = controllerHost;
}


/**
* Function used to derived params from the other values in the same object.
* @param paramName the name of the parameter we need to derive
* @param jsonObject JSON representation of full object evolved in EM. You might need just a subset to derive needed param
* @param endpointPath the path of endpoint for this object, in case need to distinguish between same params in different endpoints
* @return a string representation of derived value for paramName
* @throws Exception
*/
public String deriveObjectParameterData(String paramName, String jsonObject, String endpointPath) throws Exception{
throw new IllegalStateException("You must override deriveObjectParameterData method if you use derived param data");
}


@Override
public InsertionResultsDto execInsertionsIntoDatabase(List<InsertionDto> insertions, InsertionResultsDto... previous) {

Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.evomaster.client.java.controller.problem;

import org.evomaster.client.java.controller.problem.param.RestDerivedParam;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -15,10 +17,19 @@ public class RestProblem extends ProblemInfo{

private final String openApiSchema;

private final List<RestDerivedParam> derivedParams;

public RestProblem(String openApiUrl, List<String> endpointsToSkip) {
this(openApiUrl, endpointsToSkip, null);
}

public RestProblem(
String openApiUrl,
List<String> endpointsToSkip,
String openApiSchema
){
this(openApiUrl, endpointsToSkip, openApiSchema, null, null);
}

/**
*
@@ -31,13 +42,28 @@ public RestProblem(String openApiUrl, List<String> endpointsToSkip) {
* @param openApiSchema the actual schema, as a string. Note, if this specified, then
* openApiUrl must be null
*/
public RestProblem(String openApiUrl, List<String> endpointsToSkip, String openApiSchema) {
public RestProblem(
String openApiUrl,
List<String> endpointsToSkip,
String openApiSchema,
List<ExternalService> servicesToNotMock,
List<RestDerivedParam> derivedParams
) {
this.openApiUrl = openApiUrl;
this.endpointsToSkip = endpointsToSkip == null
? new ArrayList<>()
: new ArrayList<>(endpointsToSkip);
? Collections.emptyList()
: Collections.unmodifiableList(new ArrayList<>(endpointsToSkip));
this.openApiSchema = openApiSchema;

this.servicesToNotMock.clear();
if(servicesToNotMock != null && !servicesToNotMock.isEmpty()) {
this.servicesToNotMock.addAll(servicesToNotMock);
}

this.derivedParams = derivedParams == null
? Collections.emptyList()
: Collections.unmodifiableList(new ArrayList<>(derivedParams));

boolean url = openApiUrl != null && !openApiUrl.isEmpty();
boolean schema = openApiSchema != null && !openApiSchema.isEmpty();

@@ -49,22 +75,29 @@ public RestProblem(String openApiUrl, List<String> endpointsToSkip, String openA
}
}


@Override
public RestProblem withServicesToNotMock(List<ExternalService> servicesToNotMock){
return new RestProblem(openApiUrl, endpointsToSkip,openApiSchema,servicesToNotMock,derivedParams);
}

public RestProblem withDerivedParams(List<RestDerivedParam> derivedParams){
return new RestProblem(openApiUrl, endpointsToSkip,openApiSchema,servicesToNotMock,derivedParams);
}

public String getOpenApiUrl() {
return openApiUrl;
}

public List<String> getEndpointsToSkip() {
return Collections.unmodifiableList(endpointsToSkip);
return endpointsToSkip;
}

public String getOpenApiSchema() {
return openApiSchema;
}

@Override
public RestProblem withServicesToNotMock(List<ExternalService> servicesToNotMock){
RestProblem p = new RestProblem(this.openApiUrl, this.endpointsToSkip, this.openApiSchema);
p.servicesToNotMock.addAll(servicesToNotMock);
return p;
public List<RestDerivedParam> getDerivedParams() {
return derivedParams;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.evomaster.client.java.controller.problem.param;

public enum DerivedParamContext {

BODY_PAYLOAD
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.evomaster.client.java.controller.problem.param;

import java.util.Objects;
import java.util.Set;

public class RestDerivedParam {

/**
* The name of the parameter
*/
public final String paramName;

/**
* The context in which this parameter is used, eg, whether it is a body payload or a query parameter.
* This information is needed, as EM will need to determine which other values to use to derive this param.
*/
public final DerivedParamContext context;

/**
* In case the parameter is used differently in different endpoints, specify for which endpoints this
* derivation applies. If left null, it will apply to all endpoints where this param is present.
*/
public final Set<String> endpointPaths;

/**
* Positive integer specifying in which order the updates are done, starting from lowest value, incrementally.
* If all updates are independent (or there is only 1), this value can be left to 0.
* However, if the derivation of A depends on first deriving B, then A should get an higher order than B,
* eg 1 vs 0.
* In this case, first B is computed based on current state, and then, A is computed with current state
* updated with derived B.
*/
public final Integer order;

public RestDerivedParam(
String paramName,
DerivedParamContext context,
Set<String> endpointPaths,
Integer order
) {
this.paramName = Objects.requireNonNull(paramName);
this.context = Objects.requireNonNull(context);
this.endpointPaths = endpointPaths;
this.order = order;

if(this.order < 0){
throw new IllegalArgumentException("order must be positive: " + order);
}
}
}
Original file line number Diff line number Diff line change
@@ -8,6 +8,8 @@ import com.netflix.governator.guice.LifecycleInjector
import org.evomaster.client.java.controller.api.dto.*
import org.evomaster.client.java.controller.api.dto.database.operations.*
import org.evomaster.client.java.controller.api.dto.problem.RestProblemDto
import org.evomaster.client.java.controller.api.dto.problem.param.DeriveParamResponseDto
import org.evomaster.client.java.controller.api.dto.problem.param.DerivedParamChangeReqDto
import org.evomaster.client.java.controller.api.dto.problem.rpc.ScheduleTaskInvocationsDto
import org.evomaster.client.java.controller.api.dto.problem.rpc.ScheduleTaskInvocationsResult
import org.evomaster.core.BaseModule
@@ -454,6 +456,10 @@ class SamplerVerifierTest {
override fun close() {
}

override fun deriveParams(deriveParams: List<DerivedParamChangeReqDto>): List<DeriveParamResponseDto> {
return listOf()
}

override fun invokeScheduleTasksAndGetResults(dtos: ScheduleTaskInvocationsDto): ScheduleTaskInvocationsResult? {
return null
}
2 changes: 1 addition & 1 deletion core/src/main/kotlin/org/evomaster/core/EMConfig.kt
Original file line number Diff line number Diff line change
@@ -2004,7 +2004,7 @@ class EMConfig {
@Max(stringLengthHardLimit.toDouble())
@Cfg("The maximum length allowed for evolved strings. Without this limit, strings could in theory be" +
" billions of characters long")
var maxLengthForStrings = 200
var maxLengthForStrings = 1024


@Min(0.0)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.evomaster.core.problem.enterprise.param

class DerivedParamChangeReq(

val paramName: String,

val jsonData: String,

val entryPoint: String,

val actionIndex: Int
)

Loading