Skip to content

Commit 6b73a67

Browse files
authored
Merge pull request boskworks#136 from prdoyle/tweak
Speed up tests
2 parents c7fa990 + 53008c9 commit 6b73a67

File tree

9 files changed

+67
-58
lines changed

9 files changed

+67
-58
lines changed

bosk-core/src/main/java/works/bosk/Catalog.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@
1616
import static java.util.Collections.unmodifiableCollection;
1717
import static java.util.Collections.unmodifiableList;
1818
import static java.util.Collections.unmodifiableMap;
19+
import static java.util.LinkedHashMap.newLinkedHashMap;
1920
import static java.util.Objects.requireNonNull;
20-
import static java.util.stream.Collectors.toList;
2121
import static lombok.AccessLevel.PROTECTED;
2222

2323
/**
@@ -84,6 +84,7 @@ public Stream<E> stream() {
8484
return contents.values().stream();
8585
}
8686

87+
@Override
8788
public Spliterator<E> spliterator() {
8889
// Note that we could add DISTINCT, IMMUTABLE and NONNULL to the
8990
// characteristics if it turns out to be worth the trouble. Similar for idStream.
@@ -135,11 +136,11 @@ public static <TT extends Entity> Catalog<TT> of(TT... entities) {
135136
}
136137

137138
public static <TT extends Entity> Catalog<TT> of(Stream<TT> entities) {
138-
return of(entities.collect(toList()));
139+
return of(entities.toList());
139140
}
140141

141142
public static <TT extends Entity> Catalog<TT> of(Collection<TT> entities) {
142-
Map<Identifier, TT> newValues = new LinkedHashMap<>(entities.size());
143+
Map<Identifier, TT> newValues = newLinkedHashMap(entities.size());
143144
for (TT entity: entities) {
144145
TT old = newValues.put(requireNonNull(entity.id()), entity);
145146
if (old != null) {

bosk-mongo/src/main/java/works/bosk/drivers/mongo/AbstractFormatDriver.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import static works.bosk.drivers.mongo.Formatter.REVISION_ZERO;
1717

1818
@RequiredArgsConstructor
19-
non-sealed abstract class AbstractFormatDriver<R extends StateTreeNode> implements FormatDriver<R> {
19+
abstract non-sealed class AbstractFormatDriver<R extends StateTreeNode> implements FormatDriver<R> {
2020
final RootReference<R> rootRef;
2121
final BoskDiagnosticContext diagnosticContext;
2222
final Formatter formatter;

bosk-mongo/src/main/java/works/bosk/drivers/mongo/Formatter.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public final class Formatter extends BsonFormatter {
4646
* always set the correct context for each downstream operation.
4747
*/
4848
private volatile MapValue<String> lastEventDiagnosticAttributes = MapValue.empty();
49+
private final Codec<?> manifestCodec = codecFor(Manifest.class);
4950

5051
public Formatter(BoskInfo<?> boskInfo, BsonSerializer bsonSerializer) {
5152
super(boskInfo, bsonSerializer);
@@ -129,7 +130,7 @@ Manifest decodeManifest(BsonDocument manifestDoc) throws UnrecognizedFormatExcep
129130
BsonDocument manifest = manifestDoc.clone();
130131
manifest.remove("_id");
131132
validateManifest(manifest);
132-
return (Manifest) codecFor(Manifest.class)
133+
return (Manifest) this.manifestCodec
133134
.decode(
134135
new BsonDocumentReader(manifest),
135136
DecoderContext.builder().build());

bosk-mongo/src/main/java/works/bosk/drivers/mongo/bson/BsonFormatter.java

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -80,9 +80,7 @@ private static <T> void buildDottedFieldNameOf(Reference<T> ref, int startLength
8080
}
8181

8282
static {
83-
DECODER = s->{
84-
return URLDecoder.decode(s, StandardCharsets.UTF_8);
85-
};
83+
DECODER = s-> URLDecoder.decode(s, StandardCharsets.UTF_8);
8684

8785
ENCODER = s->{
8886
// Selective percent-encoding of characters MongoDB doesn't like.
@@ -95,7 +93,7 @@ private static <T> void buildDottedFieldNameOf(Reference<T> ref, int startLength
9593
int cp = s.codePointAt(i);
9694
switch (cp) {
9795
case '%': // For percent-encoding
98-
case '+': case ' ': // These two are affected by URLDecoder
96+
case '+', ' ': // These two are affected by URLDecoder
9997
case '$': // MongoDB treats these specially
10098
case '.': // MongoDB separator for dotted field names
10199
case 0: // Can MongoDB handle nulls? Probably. Do we want to find out? Not really.
@@ -252,11 +250,11 @@ public <T> BsonValue object2bsonValue(T object, Type type) {
252250
try (BsonDocumentWriter writer = new BsonDocumentWriter(document)) {
253251
// To support arbitrary values, not just whole documents, we put the result INSIDE a document.
254252
writer.writeStartDocument();
255-
writer.writeName("value");
253+
writer.writeName(VALUE_FIELD_NAME);
256254
objectCodec.encode(writer, object, EncoderContext.builder().build());
257255
writer.writeEndDocument();
258256
}
259-
return document.get("value");
257+
return document.get(VALUE_FIELD_NAME);
260258
}
261259

262260
/**
@@ -269,13 +267,13 @@ public <T> BsonValue object2bsonValue(T object, Type type) {
269267
public <T> T bsonValue2object(BsonValue bson, Reference<T> target) {
270268
Codec<T> objectCodec = (Codec<T>) codecFor(target.targetType());
271269
BsonDocument document = new BsonDocument();
272-
document.append("value", bson);
270+
document.append(VALUE_FIELD_NAME, bson);
273271
try (
274272
@SuppressWarnings("unused") StateTreeSerializer.DeserializationScope scope = deserializationScopeFunction.apply(target);
275273
BsonReader reader = document.asBsonReader()
276274
) {
277275
reader.readStartDocument();
278-
reader.readName("value");
276+
reader.readName(VALUE_FIELD_NAME);
279277
return objectCodec.decode(reader, DecoderContext.builder().build());
280278
}
281279
}
@@ -337,4 +335,5 @@ static <T> List<String> containerSegments(Reference<T> elementRef, int elementRe
337335
return elementSegments.subList(0, elementSegments.size()-1); // Trim off the element itself
338336
}
339337

338+
private static final String VALUE_FIELD_NAME = "value";
340339
}

bosk-mongo/src/main/java/works/bosk/drivers/mongo/bson/BsonSerializer.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -256,13 +256,14 @@ private static <E extends Entity> Codec<Listing<E>> listingCodec(Class<Listing<E
256256
@SuppressWarnings("rawtypes")
257257
Codec<Reference> referenceCodec = registry.get(Reference.class);
258258
return new Codec<>() {
259+
259260
@Override public Class<Listing<E>> getEncoderClass() { return targetClass; }
260261

261262
@Override
262263
public void encode(BsonWriter writer, Listing<E> value, EncoderContext encoderContext) {
263264
writer.writeStartDocument();
264265

265-
writer.writeName("domain");
266+
writer.writeName(DOMAIN_FIELD_NAME);
266267
referenceCodec.encode(writer, value.domain(), encoderContext);
267268

268269
writer.writeName("ids");
@@ -282,7 +283,7 @@ public Listing<E> decode(BsonReader reader, DecoderContext decoderContext) {
282283
if (reader.getCurrentBsonType() == BsonType.DOCUMENT) {
283284
reader.readStartDocument(); // can't read start document if currentBsonType == "ARRAY"
284285
}
285-
reader.readName("domain");
286+
reader.readName(DOMAIN_FIELD_NAME);
286287
Reference<Catalog<E>> domain = referenceCodec.decode(reader, decoderContext);
287288

288289
reader.readName("ids");
@@ -479,7 +480,7 @@ public void encode(BsonWriter writer, TaggedUnion<V> taggedUnion, EncoderContext
479480
try {
480481
writer.writeName(tag);
481482
caseCodec.encode(writer, caseDynamicClass.cast(variant), encoderContext);
482-
} catch (Throwable e) {
483+
} catch (Exception e) {
483484
throw new IllegalStateException("Error encoding " + caseStaticClass.getSimpleName() + ": " + e.getMessage(), e);
484485
}
485486
writer.writeEndDocument();
@@ -592,7 +593,7 @@ public void encode(BsonWriter writer, SideTable<K, V> value, EncoderContext enco
592593
public SideTable<K, V> decode(BsonReader reader, DecoderContext decoderContext) {
593594
reader.readStartDocument();
594595

595-
reader.readName("domain");
596+
reader.readName(DOMAIN_FIELD_NAME);
596597
@SuppressWarnings("unchecked")
597598
Reference<Catalog<K>> domain = referenceCodec.decode(reader, decoderContext);
598599

@@ -817,4 +818,5 @@ private static void writeNothing(Object node, BsonWriter writer, EncoderContext
817818
}
818819
}
819820

821+
private static final String DOMAIN_FIELD_NAME = "domain";
820822
}

bosk-mongo/src/main/java/works/bosk/drivers/mongo/status/BsonComparator.java

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,31 +15,7 @@ public Difference difference(BsonValue expected, BsonValue actual) {
1515
// Now we know they have the same bson type
1616

1717
if (expected instanceof BsonDocument expectedDoc && actual instanceof BsonDocument actualDoc) {
18-
var differences = new ArrayList<Difference>();
19-
for (String expectedKey: expectedDoc.keySet()) {
20-
var expectedValue = expectedDoc.get(expectedKey);
21-
var actualValue = actualDoc.get(expectedKey);
22-
if (actualValue == null) {
23-
differences.add(new NodeMissing(expectedKey));
24-
} else {
25-
Difference fieldDifference = difference(expectedValue, actualValue);
26-
if (!(fieldDifference instanceof NoDifference)) {
27-
differences.add(fieldDifference.withPrefix(expectedKey));
28-
}
29-
}
30-
if (differences.size() >= MAX_DIFFERENCES) {
31-
break;
32-
}
33-
}
34-
for (Map.Entry<String, BsonValue> entry : actualDoc.entrySet()) {
35-
var expectedValue = expectedDoc.get(entry.getKey());
36-
if (expectedValue == null) {
37-
differences.add(new UnexpectedNode(entry.getKey()));
38-
}
39-
if (differences.size() >= MAX_DIFFERENCES) {
40-
break;
41-
}
42-
}
18+
var differences = findSomeDifferences(expectedDoc, actualDoc);
4319
return switch (differences.size()) {
4420
case 0 -> new NoDifference();
4521
case 1 -> differences.get(0);
@@ -67,6 +43,36 @@ public Difference difference(BsonValue expected, BsonValue actual) {
6743
}
6844
}
6945

46+
private ArrayList<Difference> findSomeDifferences(BsonDocument expectedDoc, BsonDocument actualDoc) {
47+
var differences = new ArrayList<Difference>();
48+
for (var entry: expectedDoc.entrySet()) {
49+
var expectedKey = entry.getKey();
50+
var expectedValue = entry.getValue();
51+
var actualValue = actualDoc.get(expectedKey);
52+
if (actualValue == null) {
53+
differences.add(new NodeMissing(expectedKey));
54+
} else {
55+
Difference fieldDifference = difference(expectedValue, actualValue);
56+
if (!(fieldDifference instanceof NoDifference)) {
57+
differences.add(fieldDifference.withPrefix(expectedKey));
58+
}
59+
}
60+
if (differences.size() >= MAX_DIFFERENCES) {
61+
break;
62+
}
63+
}
64+
for (Map.Entry<String, BsonValue> entry : actualDoc.entrySet()) {
65+
var expectedValue = expectedDoc.get(entry.getKey());
66+
if (expectedValue == null) {
67+
differences.add(new UnexpectedNode(entry.getKey()));
68+
}
69+
if (differences.size() >= MAX_DIFFERENCES) {
70+
break;
71+
}
72+
}
73+
return differences;
74+
}
75+
7076
public static final int MAX_DIFFERENCES = 4;
7177

7278
}

bosk-mongo/src/test/java/works/bosk/drivers/mongo/MongoDriverConformanceTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ static Stream<ParameterSet> parameters() {
3838
return TestParameters.driverSettings(
3939
Stream.of(
4040
PandoFormat.oneBigDocument(),
41-
PandoFormat.withGraftPoints("/catalog", "/sideTable"), // Basic
42-
PandoFormat.withGraftPoints("/nestedSideTable"), // Documents are themselves side tables
41+
// PandoFormat.withGraftPoints("/catalog", "/sideTable"), // Basic
42+
// PandoFormat.withGraftPoints("/nestedSideTable"), // Documents are themselves side tables
4343
PandoFormat.withGraftPoints("/nestedSideTable/-x-"), // Graft points are side table entries
44-
PandoFormat.withGraftPoints("/catalog/-x-/sideTable", "/sideTable/-x-/catalog", "/sideTable/-x-/sideTable/-y-/catalog"), // Nesting, parameters
45-
PandoFormat.withGraftPoints("/sideTable/-x-/sideTable/-y-/catalog"), // Multiple parameters in the not-separated part
44+
// PandoFormat.withGraftPoints("/catalog/-x-/sideTable", "/sideTable/-x-/catalog", "/sideTable/-x-/sideTable/-y-/catalog"), // Nesting, parameters
45+
// PandoFormat.withGraftPoints("/sideTable/-x-/sideTable/-y-/catalog"), // Multiple parameters in the not-separated part
4646
SEQUOIA
4747
),
4848
Stream.of(EventTiming.NORMAL) // EARLY is slow; LATE is really slow

bosk-testing/src/main/java/works/bosk/drivers/DriverConformanceTest.java

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -359,8 +359,9 @@ void deleteFields_fails(Path enclosingCatalogPath) throws InvalidTypeException {
359359
Reference<Object> target = ref.then(Object.class, childID.toString(), field);
360360
assertThrows(IllegalArgumentException.class, () ->
361361
driver.submitDeletion(target), "Must not allow deletion of field " + target);
362-
assertCorrectBoskContents();
362+
// assertCorrectBoskContents(); // This slows down the test a lot, and don't realistically catch a lot more errors
363363
}
364+
assertCorrectBoskContents();
364365
}
365366
}
366367

@@ -622,7 +623,6 @@ static Stream<Path> enclosingCatalogPath() {
622623
return Stream.of(
623624
Path.just(TestEntity.Fields.catalog),
624625
Path.of(TestEntity.Fields.catalog, AWKWARD_ID, TestEntity.Fields.catalog),
625-
Path.of(TestEntity.Fields.sideTable, AWKWARD_ID, TestEntity.Fields.catalog),
626626
Path.of(TestEntity.Fields.nestedSideTable, "outer", "inner", TestEntity.Fields.catalog),
627627
Path.of(TestEntity.Fields.sideTable, AWKWARD_ID, TestEntity.Fields.catalog, "parent", TestEntity.Fields.catalog),
628628
Path.of(TestEntity.Fields.sideTable, AWKWARD_ID, TestEntity.Fields.sideTable, "parent", TestEntity.Fields.catalog)
@@ -633,21 +633,21 @@ static Stream<Path> enclosingCatalogPath() {
633633
static Stream<Identifier> childID() {
634634
return Stream.of(
635635
"child1",
636-
"child2",
637-
"nonexistent",
638-
"id.with.dots",
639-
"id/with/slashes",
640-
"$id$with$dollars$",
641-
"id:with:colons:",
642-
AWKWARD_ID,
643-
"idWithEmojis\uD83C\uDF33\uD83E\uDDCA"
636+
// "child2",
637+
// "nonexistent",
638+
// "id.with.dots",
639+
// "id/with/slashes",
640+
// "$id$with$dollars$",
641+
// "id:with:colons:",
642+
// "idWithEmojis\uD83C\uDF33\uD83E\uDDCA"
643+
AWKWARD_ID
644644
).map(Identifier::from);
645645
}
646646

647647
/**
648648
* Contains all kinds of special characters
649649
*/
650-
public static final String AWKWARD_ID = "$id.with%everything:/ +\uD83D\uDE09";
650+
public static final String AWKWARD_ID = "awkward$id.with%everything:/ +\uD83D\uDE09";
651651

652652
@SuppressWarnings("unused")
653653
static Stream<String> testEntityField() {

lib-testing/src/main/java/works/bosk/AbstractBoskTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ public interface Variant extends VariantCase {
137137
public record VariantCase1(String stringField) implements Variant { }
138138

139139
protected static Bosk<TestRoot> setUpBosk(DriverFactory<TestRoot> driverFactory) {
140-
return new Bosk<TestRoot>(boskName(1), TestRoot.class, AbstractRoundTripTest::initialRoot, driverFactory, Bosk.simpleRegistrar());
140+
return new Bosk<>(boskName(1), TestRoot.class, AbstractRoundTripTest::initialRoot, driverFactory, Bosk.simpleRegistrar());
141141
}
142142

143143
protected static TestRoot initialRoot(Bosk<TestRoot> bosk) {

0 commit comments

Comments
 (0)