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 @@ -12,20 +12,26 @@ public class RedisFailedCommand {
public String command;

/**
* Command type. Corresponds to a RedisCommandType dataType.
* Key involved. Could be null if the command does not have a key in the arguments. For example: KEYS (pattern).
*/
public String type;
public String key;

/**
* Key involved. Could be null if the command does not have a key in the arguments. For example: KEYS (pattern).
* Pattern involved. It'd only apply to commands with pattern like KEYS.
*/
public String key;
public String pattern;

/**
* Field involved. It'd only apply to hash commands with a field like HGET.
*/
public String field;

public RedisFailedCommand() {}

public RedisFailedCommand(String command, String key, String type) {
public RedisFailedCommand(String command, String key, String pattern, String field) {
this.command = command;
this.key = key;
this.type = type;
this.pattern = pattern;
this.field = field;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@
*/
public class RedisInsertionDto {

/** The Redis command.*/
public String command;

/** The Redis key.*/
public String key;

/** The field associated to the value. */
public String field;

/** The serialized value to set for that key. */
public String value;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,14 @@
import org.evomaster.client.java.controller.api.dto.database.execution.RedisExecutionsDto;
import org.evomaster.client.java.controller.api.dto.database.execution.RedisFailedCommand;
import org.evomaster.client.java.controller.internal.TaintHandlerExecutionTracer;
import org.evomaster.client.java.controller.redis.RedisKeyValueStore;
import org.evomaster.client.java.controller.redis.ReflectionBasedRedisClient;
import org.evomaster.client.java.controller.redis.RedisHeuristicsCalculator;
import org.evomaster.client.java.controller.redis.RedisValueData;
import org.evomaster.client.java.controller.redis.*;
import org.evomaster.client.java.instrumentation.RedisCommand;
import org.evomaster.client.java.utils.SimpleLogger;

import java.util.*;

import static org.evomaster.client.java.controller.redis.RedisHeuristicsCalculator.MAX_REDIS_DISTANCE;
import static org.evomaster.client.java.instrumentation.RedisCommand.RedisCommandType.*;

/**
* Class used to act upon Redis commands executed by the SUT
Expand Down Expand Up @@ -106,18 +104,55 @@ public List<RedisCommandEvaluation> getEvaluatedRedisCommands() {
}

private void registerFailedCommand(RedisCommand redisCommand, double distance) {
RedisCommand.RedisCommandType type = redisCommand.getType();
if (distance > 0 &&
redisCommand.getType().equals(RedisCommand.RedisCommandType.GET)) {
type.equals(GET) || type.equals(KEYS) || type.equals(HGET) || type.equals(HGETALL)) {
//For this first iteration we'll only work on GET commands.
failedCommands.add(createFailedCommand(redisCommand));
}
}

private RedisFailedCommand createFailedCommand(RedisCommand redisCommand) {
Comment thread
jgaleotti marked this conversation as resolved.
return new RedisFailedCommand(
redisCommand.getType().getLabel().toUpperCase(),
redisCommand.extractArgs().get(0),
redisCommand.getType().getDataType());
RedisCommand.RedisCommandType type = redisCommand.getType();
List<String> args = redisCommand.extractArgs();
switch (type) {
case GET:
case HGETALL: {
if (args.isEmpty()) {
throw new IllegalArgumentException("Command " + type.getLabel() + " has invalid arguments.");
}
return new RedisFailedCommand(
type.getLabel().toUpperCase(),
args.get(0),
null,
null);
}

case KEYS: {
if (args.isEmpty()) {
throw new IllegalArgumentException("Command KEYS has invalid arguments.");
}
return new RedisFailedCommand(
type.getLabel().toUpperCase(),
null,
RedisUtils.redisPatternToRegex(args.get(0)),
null);
}

case HGET: {
if (args.size() < 2) {
throw new IllegalArgumentException("Command HGET has invalid arguments.");
}
return new RedisFailedCommand(
type.getLabel().toUpperCase(),
args.get(0),
null,
args.get(1));
}
default:
throw new RuntimeException(
"Invalid command registering failed redis commands. Type encountered: " + type);
}
}

private RedisDistanceWithMetrics computeDistance(RedisCommand redisCommand, ReflectionBasedRedisClient redisClient) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,17 @@ public static RedisInsertionResultsDto executeInsert(
for (int i = 0; i < insertions.size(); i++) {
RedisInsertionDto dto = insertions.get(i);
try {
client.setValue(dto.key, dto.value);
switch (dto.command.toUpperCase()) {
case "SET":
client.setValue(dto.key, dto.value);
break;
case "HSET":
client.hashSet(dto.key, dto.field, dto.value);
break;
default:
throw new IllegalArgumentException(
"Unsupported Redis command: " + dto.command);
}
results.set(i, true);
} catch (Exception e) {
throw new RuntimeException(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public class ReflectionBasedRedisClient {
private static final String CREATE_METHOD = "create";
private static final String FLUSHALL_METHOD = "flushall";
private static final String GET_METHOD = "get";
private static final String HGET_METHOD = "hget";
private static final String HGETALL_METHOD = "hgetall";
private static final String HSET_METHOD = "hset";
private static final String KEYS_METHOD = "keys";
Expand Down Expand Up @@ -92,6 +93,11 @@ public String getValue(String key) {
return (String) invoke(GET_METHOD, key);
}

/** Equivalent to HGET key field */
public String getHashValue(String key, String field) {
return (String) invoke(HGET_METHOD, key, field);
}

/** Equivalent to KEYS * */
public Set<String> getAllKeys() {
Object result = invoke(KEYS_METHOD, "*");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,31 @@ public RedisStatementDsl set(String key, String value) {
throw new IllegalArgumentException("Unspecified key");
}
RedisInsertionDto dto = new RedisInsertionDto();
dto.command = "SET";
dto.key = key;
dto.value = value;
list.add(dto);
return this;
}

@Override
public RedisStatementDsl hset(String key, String field, String value) {
checkDsl();
if (key == null || key.isEmpty()) {
throw new IllegalArgumentException("Unspecified key");
}
if (field == null || field.isEmpty()) {
throw new IllegalArgumentException("Unspecified field");
}
RedisInsertionDto dto = new RedisInsertionDto();
dto.command = "HSET";
dto.key = key;
dto.field = field;
dto.value = value;
list.add(dto);
return this;
}

@Override
public RedisSequenceDsl and() {
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,14 @@ public interface RedisSequenceDsl {
* @return a statement object on which the sequence can be continued or closed
*/
RedisStatementDsl set(String key, String value);

/**
* An HSET operation on the Redis database.
*
* @param key the hash key
* @param field the field within the hash
* @param value the string value to store at that field
* @return a statement object on which the sequence can be continued or closed
*/
RedisStatementDsl hset(String key, String field, String value);
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ public void cleanUp() {
@Test
public void testInsertSingleKey() {
RedisInsertionDto dto = new RedisInsertionDto();
dto.command = "SET";
dto.key = "user:1";
dto.value = "Alice";

Expand All @@ -48,10 +49,12 @@ public void testInsertSingleKey() {
@Test
public void testInsertMultipleKeys() {
RedisInsertionDto dto1 = new RedisInsertionDto();
dto1.command = "SET";
dto1.key = "product:1";
dto1.value = "chair";

RedisInsertionDto dto2 = new RedisInsertionDto();
dto2.command = "SET";
dto2.key = "product:2";
dto2.value = "table";

Expand Down Expand Up @@ -79,15 +82,74 @@ public void testInsertEmptyListThrows() {
@Test
public void testOverwritesExistingKey() {
RedisInsertionDto first = new RedisInsertionDto();
first.command = "SET";
first.key = "overwrite:key";
first.value = "old";
RedisCommandExecutor.executeInsert(client, Collections.singletonList(first));

RedisInsertionDto second = new RedisInsertionDto();
second.command = "SET";
second.key = "overwrite:key";
second.value = "new";
RedisCommandExecutor.executeInsert(client, Collections.singletonList(second));

assertEquals("new", client.getValue("overwrite:key"));
}

@Test
public void testInsertHset() {
RedisInsertionDto dto = new RedisInsertionDto();
dto.command = "HSET";
dto.key = "user:1";
dto.field = "name";
dto.value = "Alice";

RedisInsertionResultsDto results =
RedisCommandExecutor.executeInsert(client, Collections.singletonList(dto));

assertTrue(results.executionResults.get(0));
assertEquals("Alice", client.getHashValue("user:1", "name"));
}

@Test
public void testInsertMultipleHset() {
RedisInsertionDto dto1 = new RedisInsertionDto();
dto1.command = "HSET";
dto1.key = "product:1";
dto1.field = "name";
dto1.value = "chair";

RedisInsertionDto dto2 = new RedisInsertionDto();
dto2.command = "HSET";
dto2.key = "product:1";
dto2.field = "color";
dto2.value = "red";

RedisInsertionResultsDto results =
RedisCommandExecutor.executeInsert(client, Arrays.asList(dto1, dto2));

assertTrue(results.executionResults.get(0));
assertTrue(results.executionResults.get(1));
assertEquals("chair", client.getHashValue("product:1", "name"));
assertEquals("red", client.getHashValue("product:1", "color"));
}

@Test
public void testOverwritesExistingHsetField() {
RedisInsertionDto first = new RedisInsertionDto();
first.command = "HSET";
first.key = "overwrite:key";
first.field = "field";
first.value = "old";
RedisCommandExecutor.executeInsert(client, Collections.singletonList(first));

RedisInsertionDto second = new RedisInsertionDto();
second.command = "HSET";
second.key = "overwrite:key";
second.field = "field";
second.value = "new";
RedisCommandExecutor.executeInsert(client, Collections.singletonList(second));

assertEquals("new", client.getHashValue("overwrite:key", "field"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.redis.lettuce.findhashnosave;

import com.redis.SwaggerConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@EnableSwagger2
@SpringBootApplication(exclude = SecurityAutoConfiguration.class)
public class RedisLettuceFindHashNoSaveApp extends SwaggerConfiguration {
public RedisLettuceFindHashNoSaveApp() {
super("redislettucefindhashnosave");
}

public static void main(String[] args) {
SpringApplication.run(RedisLettuceFindHashNoSaveApp.class, args);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.redis.lettuce.findhashnosave;

import com.redis.lettuce.AbstractRedisLettuceRest;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping(path = "/redislettucefindhashnosave")
public class RedisLettuceFindHashNoSaveRest extends AbstractRedisLettuceRest {

@GetMapping("/findHash")
public ResponseEntity<Void> findHashNoSave() {
String result = sync.hget("key-for-findhash", "field");
if (result != null) {
return ResponseEntity.status(200).build();
} else {
return ResponseEntity.status(404).build();
}
}

@GetMapping("/findHashAllFields")
public ResponseEntity<Void> findHashesNoSave() {
var result = sync.hgetall("another-key-for-findhashes");
if (result != null && !result.isEmpty()) {
return ResponseEntity.status(200).build();
} else {
return ResponseEntity.status(404).build();
}
}

}


Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public class RedisLettuceFindKeyNoSaveRest extends AbstractRedisLettuceRest {

@GetMapping("/findKey")
public ResponseEntity<Void> findKey() {
String result = sync.get("here-goes-the-key");
String result = sync.get("key-for-findkey");
if (result != null) {
return ResponseEntity.status(200).build();
} else {
Expand Down
Loading
Loading