Skip to content

Commit b7b3964

Browse files
committed
Split files to smaller ones and tidy up the whole test package
1 parent b5039cf commit b7b3964

17 files changed

Lines changed: 580 additions & 531 deletions

memex/CONTRIBUTING.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,21 @@ For integration tests requiring a database, we use Testcontainers to spin up a M
3939
* **Requirement**: A Docker daemon must be running locally for this to work (e.g., by starting Docker Desktop).
4040
* **Using an External MongoDB**: If you do not have Docker available, or wish to use a specific external MongoDB instance for testing, you can specify its connection string by setting the `spring.data.mongodb.uri` property in `src/test/resources/application-test.properties`. In this case, Testcontainers will not attempt to start a local MongoDB container.
4141

42+
### Test Data `testid` Range
43+
44+
To ensure test data isolation and prevent unintended side effects, vehicle inspection `testid` values used during test setup and execution **must** fall within a dedicated range. This range is defined by the following properties in `src/test/resources/application-test.properties`:
45+
* `memex.test.data.vehicleinspection-testid-range.start`
46+
* `memex.test.data.vehicleinspection-testid-range.end`
47+
48+
**Important:**
49+
* When writing or modifying tests, ensure all `testid` values used for creating, querying, or deleting test data are within this configured range.
50+
* Tests **must not** attempt to read, modify, or delete data outside of this dedicated test ID range. This is crucial for preventing tests from interfering with each other or with any non-test data.
51+
* Using a `testid` outside of this range during test data manipulation will lead to test failures.
52+
53+
**Caution**: If you configure the tests to run against a real (non-Testcontainer) MongoDB instance, be aware that the tests **will modify data within this `testid` range on that MongoDB instance.** Ensure this range does not overlap with critical data if using a shared or persistent MongoDB server for testing. It is generally recommended to use Testcontainers or a dedicated, ephemeral test database to avoid accidental data modification.
54+
55+
These properties can be adjusted in `src/test/resources/application-test.properties` if necessary for specific testing needs, but ensure they define a sensible range and that all tests strictly adhere to operating only within the specified `testid` boundaries.
56+
4257
### Code Coverage
4358

4459
We use **JaCoCo** to measure code coverage by our tests.

memex/src/test/java/com/johnlpage/demo/DemoApplicationTests.java

Lines changed: 0 additions & 40 deletions
This file was deleted.

memex/src/test/java/com/johnlpage/memex/cucumber/CucumberTestsContainersConfig.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package com.johnlpage.memex.cucumber;
22

3-
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
3+
import org.jetbrains.annotations.NotNull;
44
import org.springframework.boot.test.context.TestConfiguration;
55
import org.springframework.context.annotation.Bean;
66
import org.springframework.context.annotation.Condition;
@@ -10,13 +10,6 @@
1010
import org.springframework.test.context.DynamicPropertyRegistrar;
1111
import org.testcontainers.mongodb.MongoDBAtlasLocalContainer;
1212

13-
class MongoUriMissingCondition implements Condition {
14-
@Override
15-
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
16-
String uri = context.getEnvironment().getProperty("spring.data.mongodb.uri");
17-
return uri == null || uri.trim().isEmpty();
18-
}
19-
}
2013

2114
@TestConfiguration
2215
public class CucumberTestsContainersConfig {
@@ -36,4 +29,12 @@ public DynamicPropertyRegistrar mongoDbProperties(MongoDBAtlasLocalContainer mon
3629
registry.add("spring.data.mongodb.database", () -> "memex");
3730
};
3831
}
32+
33+
static class MongoUriMissingCondition implements Condition {
34+
@Override
35+
public boolean matches(ConditionContext context, @NotNull AnnotatedTypeMetadata metadata) {
36+
String uri = context.getEnvironment().getProperty("spring.data.mongodb.uri");
37+
return uri == null || uri.trim().isEmpty();
38+
}
39+
}
3940
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.johnlpage.memex.cucumber.service;
2+
3+
import org.springframework.stereotype.Component;
4+
5+
import java.util.Map;
6+
7+
@Component
8+
public class MacrosRegister {
9+
10+
private final Map<String, String> macros = new java.util.HashMap<>();
11+
12+
public void registerMacro(String macroName, String macroValue) {
13+
macros.put(macroName, macroValue);
14+
}
15+
16+
public String replaceMacros(String originalString) {
17+
String processedString = originalString;
18+
for (Map.Entry<String, String> entry : macros.entrySet()) {
19+
processedString = processedString.replace(entry.getKey(), entry.getValue());
20+
}
21+
22+
return processedString;
23+
}
24+
}

memex/src/test/java/com/johnlpage/memex/cucumber/steps/VehicleInspectionIdRangeValidator.java renamed to memex/src/test/java/com/johnlpage/memex/cucumber/service/VehicleInspectionIdRangeValidator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.johnlpage.memex.cucumber.steps;
1+
package com.johnlpage.memex.cucumber.service;
22

33
import lombok.Getter;
44
import org.springframework.beans.factory.annotation.Value;
@@ -11,7 +11,7 @@ public class VehicleInspectionIdRangeValidator {
1111
@Value("${memex.test.data.vehicleinspection-testid-range.start:10000}")
1212
private long rangeStart;
1313

14-
@Value("${memex.test.data.vehicleinspection-testid-range.end:20000}")
14+
@Value("${memex.test.data.vehicleinspection-testid-range.end:11000}")
1515
private long rangeEnd;
1616

1717
public void validate(long id) {

memex/src/test/java/com/johnlpage/memex/cucumber/steps/VehicleInspectionKafkaConsumerSteps.java renamed to memex/src/test/java/com/johnlpage/memex/cucumber/steps/KafkaConsumerSteps.java

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,23 @@
33
import com.fasterxml.jackson.core.JsonProcessingException;
44
import com.fasterxml.jackson.databind.JsonNode;
55
import com.fasterxml.jackson.databind.ObjectMapper;
6-
import com.fasterxml.jackson.databind.node.ObjectNode;
6+
import com.johnlpage.memex.cucumber.service.VehicleInspectionIdRangeValidator;
77
import com.johnlpage.memex.model.VehicleInspection;
8-
import io.cucumber.datatable.DataTable;
98
import io.cucumber.java.en.Then;
109
import io.cucumber.java.en.When;
1110
import org.assertj.core.api.Assertions;
12-
import org.bson.Document;
13-
import org.springframework.beans.BeanWrapperImpl;
1411
import org.springframework.beans.factory.annotation.Autowired;
1512
import org.springframework.data.mongodb.core.MongoTemplate;
1613
import org.springframework.data.mongodb.core.query.Criteria;
1714
import org.springframework.data.mongodb.core.query.Query;
1815
import org.springframework.kafka.core.KafkaTemplate;
1916

20-
import java.util.HashMap;
2117
import java.util.Iterator;
2218
import java.util.List;
2319
import java.util.Map;
2420

2521

26-
public class VehicleInspectionKafkaConsumerSteps {
22+
public class KafkaConsumerSteps {
2723

2824
@Autowired
2925
private KafkaTemplate<String, String> kafkaTemplate;
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package com.johnlpage.memex.cucumber.steps;
2+
3+
import com.fasterxml.jackson.core.JsonProcessingException;
4+
import com.fasterxml.jackson.databind.ObjectMapper;
5+
import com.johnlpage.memex.cucumber.service.VehicleInspectionIdRangeValidator;
6+
import com.johnlpage.memex.model.VehicleInspection;
7+
import com.mongodb.client.result.DeleteResult;
8+
import io.cucumber.datatable.DataTable;
9+
import io.cucumber.java.en.Given;
10+
import lombok.extern.slf4j.Slf4j;
11+
import org.bson.Document;
12+
import org.springframework.beans.factory.annotation.Autowired;
13+
import org.springframework.data.mongodb.core.FindAndModifyOptions;
14+
import org.springframework.data.mongodb.core.MongoTemplate;
15+
import org.springframework.data.mongodb.core.query.Criteria;
16+
import org.springframework.data.mongodb.core.query.Query;
17+
import org.springframework.data.mongodb.core.query.Update;
18+
19+
import java.util.List;
20+
import java.util.Map;
21+
22+
import static org.junit.jupiter.api.Assertions.assertNotNull;
23+
24+
@Slf4j
25+
public class MongoPreConditionSteps {
26+
27+
@Autowired
28+
private MongoTemplate mongoTemplate;
29+
30+
@Autowired
31+
private ObjectMapper objectMapper;
32+
33+
@Autowired
34+
private VehicleInspectionIdRangeValidator idRangeValidator;
35+
36+
@Given("the following vehicle inspections exist:")
37+
public void givenVehicleInspectionsExist(DataTable dataTable) throws JsonProcessingException {
38+
List<Map<String, String>> rows = dataTable.asMaps(String.class, String.class);
39+
40+
for (Map<String, String> row : rows) {
41+
String json = row.get("vehicleInspection");
42+
VehicleInspection inspection = objectMapper.readValue(json, VehicleInspection.class);
43+
Long testId = inspection.getTestid();
44+
assertNotNull(testId, "testid is expected to be part of the data input");
45+
46+
idRangeValidator.validate(testId);
47+
Query query = Query.query(Criteria.where("_id").is(testId));
48+
49+
Document updateDoc = new Document(objectMapper.convertValue(inspection, Map.class));
50+
Update update = Update.fromDocument(updateDoc);
51+
52+
VehicleInspection existingInspection = mongoTemplate.findAndModify(query, update,
53+
FindAndModifyOptions.options().upsert(true).returnNew(true), VehicleInspection.class);
54+
55+
log.info("Upserted VehicleInspection with id {}: {}", testId, existingInspection);
56+
}
57+
}
58+
59+
@Given("the vehicle inspections in range {long}-{long} do not exist")
60+
public void theFollowingVehicleInspectionsInRangeDoesNotExist(long startId, long endId) {
61+
idRangeValidator.validateRange(startId, endId);
62+
Query query = new Query();
63+
query.addCriteria(Criteria.where("_id").gte(startId).lte(endId));
64+
DeleteResult result = mongoTemplate.remove(query, VehicleInspection.class);
65+
66+
if(result.getDeletedCount() > 0) {
67+
log.info("Removed VehicleInspection within a range {}-{}: {}", startId, endId, result.getDeletedCount());
68+
}
69+
}
70+
71+
@Given("the vehicle inspection with id {long} does not exist")
72+
public void theFollowingVehicleInspectionDoesNotExist(long testId) {
73+
idRangeValidator.validate(testId);
74+
Query query = new Query();
75+
query.addCriteria(Criteria.where("_id").is(testId));
76+
DeleteResult result = mongoTemplate.remove(query, VehicleInspection.class);
77+
78+
if(result.getDeletedCount() > 0) {
79+
log.info("Removed VehicleInspection with id {}: {}", testId, result.getDeletedCount());
80+
}
81+
}
82+
83+
@Given("the following vehicle inspections do not exist:")
84+
public void givenTheFollowingVehicleInspectionsDoNotExist(DataTable dataTable) {
85+
for (Map<String, String> row : dataTable.asMaps()) {
86+
if (row.size() != 1) {
87+
throw new IllegalArgumentException("Only one column per row is supported in this step.");
88+
}
89+
90+
String key = row.keySet().iterator().next();
91+
String value = row.get(key);
92+
93+
long rangeStart = idRangeValidator.getRangeStart();
94+
long rangeEnd = idRangeValidator.getRangeEnd();
95+
96+
Query query = Query.query(Criteria.where("_id").gte(rangeStart).lte(rangeEnd));
97+
98+
if (key.equalsIgnoreCase("testid")) {
99+
long testid = Long.parseLong(value);
100+
idRangeValidator.validate(testid);
101+
query = Query.query(Criteria.where("_id").is(testid));
102+
} else {
103+
query.addCriteria(Criteria.where(key).is(value));
104+
}
105+
DeleteResult result = mongoTemplate.remove(query, VehicleInspection.class);
106+
107+
if (result.getDeletedCount() > 0) {
108+
log.info("Removed VehicleInspection with {}: {} - Count: {}", key, value, result.getDeletedCount());
109+
}
110+
}
111+
}
112+
}

0 commit comments

Comments
 (0)