Skip to content

Commit

Permalink
Generate unit tests for new implementations automagically.
Browse files Browse the repository at this point in the history
fixes: #61
  • Loading branch information
big-andy-coates committed Nov 15, 2023
1 parent ede81c0 commit 576bd66
Show file tree
Hide file tree
Showing 12 changed files with 60 additions and 238 deletions.
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,11 @@ Adding a new validator implementation is relatively straight forward and very we
5. Add a new implementation of [Implementation](src/main/java/org/creekservice/kafka/test/perf/implementations/Implementation.java)
to the [main implementations](src/main/java/org/creekservice/kafka/test/perf/implementations) package for the new validator library.
See JavaDocs and other implementations for help.
6. Add a unit test class for your new implementation to the [test implementations](src/test/java/org/creekservice/kafka/test/perf/implementations) package.
This should subtype [ImplementationTest.java](src/test/java/org/creekservice/kafka/test/perf/implementations/ImplementationTest.java).
The unit test class needs to content. See other implementations for examples.
Ensure tests pass!
7. Register your new Implementation type in [Implementations.java](src/main/java/org/creekservice/kafka/test/perf/implementations/Implementations.java).
6. Register your new Implementation type in [Implementations.java](src/main/java/org/creekservice/kafka/test/perf/implementations/Implementations.java).
This will ensure the new implementation is included in the docs and included in the functional test
7. Run [ImplementationTest.java](src/test/java/org/creekservice/kafka/test/perf/implementations/ImplementationTest.java).
This unit test will test each implementation, including yours.
Ensure tests pass!
8. Manually add appropriate benchmark methods to [JsonSerdeBenchmark.java](src/main/java/org/creekservice/kafka/test/perf/performance/JsonSerdeBenchmark.java)
and [JsonValidateBenchmark.java](src/main/java/org/creekservice/kafka/test/perf/performance/JsonValidateBenchmark.java).
This is currently manual as JMH library does provide a way to generate these automatically.
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Stream;
import org.creekservice.api.test.util.TestPaths;
import org.creekservice.kafka.test.perf.model.ModelState;
import org.creekservice.kafka.test.perf.model.PolyTypeA;
Expand All @@ -39,9 +40,10 @@
import org.creekservice.kafka.test.perf.testsuite.SchemaSpec;
import org.creekservice.kafka.test.perf.util.TestSchemas;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;

public abstract class ImplementationTest {
public class ImplementationTest {

private static final Path REMOTES_ROOT =
TestPaths.moduleRoot("json-schema-validation-comparison")
Expand All @@ -55,14 +57,10 @@ public abstract class ImplementationTest {
List.of("element"),
List.of(new PolyTypeA(UUID.randomUUID()), new PolyTypeB(0.0000000002d)));

private Implementation impl;
private TestData testData;
private AdditionalSchemas additionalSchemas;

@BeforeEach
void setUp() throws Exception {
this.impl = instantiateSerde();
this.testData = testData(impl);
void setUp() {
this.additionalSchemas =
new AdditionalSchemas(
Map.of(
Expand All @@ -75,25 +73,34 @@ void setUp() throws Exception {
REMOTES_ROOT);
}

@Test
void shouldReturnValueMetaData() {
@ParameterizedTest(name = "{0}")
@MethodSource("implementations")
void shouldReturnValueMetaData(final String shortName, final Implementation impl) {
assertThat(impl.metadata(), is(notNullValue()));
}

@Test
void shouldNotThrowPreparingValidSchema() {
@ParameterizedTest(name = "{0}")
@MethodSource("implementations")
void shouldNotThrowPreparingValidSchema(final String shortName, final Implementation impl) {
// Given:
final TestData testData = testData(impl);

// When:
impl.prepare(testData.schema, testData.spec, additionalSchemas);

// Then: did not throw.
}

@SuppressFBWarnings("RV_EXCEPTION_NOT_THROWN")
@Test
void shouldThrowValidatingInvalidJson() {
@ParameterizedTest(name = "{0}")
@MethodSource("implementations")
void shouldThrowValidatingInvalidJson(final String shortName, final Implementation impl) {
assumeFalse(
getClass().getName().contains("Jackson")
|| getClass().getName().contains("Confluent"),
shortName.equals("Jackson") || shortName.equals("Confluent"),
"Exclude impls that don't support this");

// Given:
final TestData testData = testData(impl);
final Implementation.JsonValidator validator =
impl.prepare(testData.schema, testData.spec, additionalSchemas);
final String badJson =
Expand All @@ -103,14 +110,15 @@ void shouldThrowValidatingInvalidJson() {
assertThrows(RuntimeException.class, () -> validator.validate(badJson));
}

@Test
void shouldNotThrowValidatingValidJson() {
@ParameterizedTest(name = "{0}")
@MethodSource("implementations")
void shouldNotThrowValidatingValidJson(final String shortName, final Implementation impl) {
assumeFalse(
getClass().getName().contains("Jackson")
|| getClass().getName().contains("Confluent"),
shortName.equals("Jackson") || shortName.equals("Confluent"),
"Exclude impls that don't support this");

// Given:
final TestData testData = testData(impl);
final Implementation.JsonValidator validator =
impl.prepare(testData.schema, testData.spec, additionalSchemas);
final String goodJson =
Expand All @@ -124,16 +132,18 @@ void shouldNotThrowValidatingValidJson() {
}

@SuppressFBWarnings("RV_EXCEPTION_NOT_THROWN")
@Test
void shouldHandleRemoteSchemas() {
@ParameterizedTest(name = "{0}")
@MethodSource("implementations")
void shouldHandleRemoteSchemas(final String shortName, final Implementation impl) {
assumeFalse(
getClass().getName().contains("Jackson")
|| getClass().getName().contains("Confluent")
|| getClass().getName().contains("Skema")
|| getClass().getName().contains("Vert"),
shortName.equals("Jackson")
|| shortName.equals("Confluent")
|| shortName.equals("Skema")
|| shortName.equals("Vertx"),
"Exclude impls that don't support this");

// Given:
final TestData testData = testData(impl);
final Implementation.JsonValidator validator =
impl.prepare(testData.remoteSchema, testData.spec, additionalSchemas);

Expand All @@ -142,9 +152,11 @@ void shouldHandleRemoteSchemas() {
assertThrows(RuntimeException.class, () -> validator.validate("abc"));
}

@Test
void shouldRoundTrip() {
@ParameterizedTest(name = "{0}")
@MethodSource("implementations")
void shouldRoundTrip(final String shortName, final Implementation impl) {
// Given:
final TestData testData = testData(impl);
final Implementation.JsonValidator validator =
impl.prepare(testData.schema, testData.spec, additionalSchemas);

Expand All @@ -157,21 +169,25 @@ void shouldRoundTrip() {
}

@SuppressFBWarnings("RV_EXCEPTION_NOT_THROWN")
@Test
void shouldValidateOnSerialize() {
assumeFalse(getClass().getName().contains("Jackson"), "Exclude the raw Jackson serde");
@ParameterizedTest(name = "{0}")
@MethodSource("implementations")
void shouldValidateOnSerialize(final String shortName, final Implementation impl) {
assumeFalse(shortName.equals("Jackson"), "Exclude the raw Jackson serde");

// Given:
final TestData testData = testData(impl);
final Implementation.JsonValidator validator =
impl.prepare(testData.schema, testData.spec, additionalSchemas);

// Then:
assertThrows(RuntimeException.class, () -> validator.serialize(BAD_DECIMAL, true));
}

@Test
void shouldNotValidateOnSerialize() {
@ParameterizedTest(name = "{0}")
@MethodSource("implementations")
void shouldNotValidateOnSerialize(final String shortName, final Implementation impl) {
// Given:
final TestData testData = testData(impl);
final Implementation.JsonValidator validator =
impl.prepare(testData.schema, testData.spec, additionalSchemas);

Expand All @@ -182,11 +198,13 @@ void shouldNotValidateOnSerialize() {
}

@SuppressFBWarnings("RV_EXCEPTION_NOT_THROWN")
@Test
void shouldValidateOnDeserialize() {
assumeFalse(getClass().getName().contains("Jackson"), "Exclude the raw Jackson serde");
@ParameterizedTest(name = "{0}")
@MethodSource("implementations")
void shouldValidateOnDeserialize(final String shortName, final Implementation impl) {
assumeFalse(shortName.equals("Jackson"), "Exclude the raw Jackson serde");

// Given:
final TestData testData = testData(impl);
final Implementation.JsonValidator validator =
impl.prepare(testData.schema, testData.spec, additionalSchemas);
final byte[] serialized = validator.serialize(BAD_DECIMAL, false);
Expand All @@ -195,14 +213,9 @@ void shouldValidateOnDeserialize() {
assertThrows(RuntimeException.class, () -> validator.deserialize(serialized));
}

private Implementation instantiateSerde() throws Exception {
final String testName = getClass().getName();
final String serdeName = testName.substring(0, testName.length() - "Test".length());
final Class<?> serdeType = getClass().getClassLoader().loadClass(serdeName);
if (!Implementation.class.isAssignableFrom(serdeType)) {
throw new AssertionError("Not a serde type: " + serdeType);
}
return (Implementation) serdeType.getDeclaredConstructor().newInstance();
private static Stream<Object[]> implementations() {
return Implementations.all().stream()
.map(impl -> new Object[] {impl.metadata().shortName(), impl});
}

private TestData testData(final Implementation impl) {
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Loading

0 comments on commit 576bd66

Please sign in to comment.