test(version-tests): add tests for client, domain, and service layers#570
test(version-tests): add tests for client, domain, and service layers#570margi212 wants to merge 2 commits into
Conversation
…ervice layers - Add RegistryClientFactoryTests: GHCR client resolution, unsupported/null/empty/whitespace/case-sensitive registry, instance reuse - Add GHCRClientLoggerTests: request/response logging toggle, token/header masking, null/empty/non-JSON body, redirect response - Add TagsTestRequestTests: builder construction, toBuilder(), field setters, null/empty edge cases, executor null validation - Add NamedThreadFactoryTests: named thread creation, counter increment, separate factory counters, runnable execution, concurrent creation - Add WorkParallelizerTests: parallel transform/run, empty/single/large lists, multi-type transformation, concurrent execution - Extend TagTestResultTests: TagsTestResults sorting, from() factory, toBuilder(), setResults()/clearResults(), failure detection Signed-off-by: Margi <39212098+margi212@users.noreply.github.com>
client, domain, and service layers of the docling-version-tests module.docling-version-tests module.
docling-version-tests module.
:java_duke: JaCoCo coverage report
|
|
||||||||||||||
|
HTML test reports are available as workflow artifacts (zipped HTML). • Download: Artifacts for this run |
edeandrea
left a comment
There was a problem hiding this comment.
Hi @margi212 Thanks for doing this! I've made some specific comments in certain places but I'll add some general comments here.
You may be new to AssertJ and thats totally fine, but if possible could you try to keep the assertions more fluent? Thats one of the main powers of AssertJ - rather than having lots of single assertThat statements, assertions can be combined in a fluent style.
The other thing I noticed was that there were lots of tests that were just variations on the same test. Many of them are unneeded, and others could be re-written using parameterized tests (same test assertion(s) just with different inputs).
| } | ||
|
|
||
| @Test | ||
| void shouldRunItemsInParallel() { |
There was a problem hiding this comment.
I'm not sure what the purpose of this test is or what its trying to prove?
|
|
||
| @Test | ||
| void shouldRunEmptyList() { | ||
| var executor = Executors.newSingleThreadExecutor(); |
There was a problem hiding this comment.
I'm not sure what the purpose of this test is or what its trying to prove?
| } | ||
|
|
||
| @Test | ||
| void shouldRunSingleItem() { |
There was a problem hiding this comment.
I'm not sure what the purpose of this test is or what its trying to prove?
|
|
||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| class WorkParallelizerTests { |
There was a problem hiding this comment.
I feel like there are many overlapping tests here that aren't needed and don't really prove anything. The first two which do something on a non-empty & empty list are probably enough. The rest of them are really different variations of the same test.
|
|
||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| class NamedThreadFactoryTests { |
There was a problem hiding this comment.
I feel like there are many overlapping tests here that aren't needed and don't really prove anything. The first one which creates a named thread and verifies the thread name is probably sufficient. The rest of them are really different variations of the same test.
| import io.vertx.core.http.HttpClientResponse; | ||
| import io.vertx.core.http.HttpMethod; | ||
|
|
||
| class GHCRClientLoggerTests { |
There was a problem hiding this comment.
There are a lot of repetitive tests here that are variations on the same test (response status, headers, etc).
|
|
||
| import ai.docling.client.tester.client.ghcr.GHCRClient; | ||
|
|
||
| class RegistryClientFactoryTests { |
There was a problem hiding this comment.
I'd say the tests are all valid, but many of them are the same test just with different inputs and the same expectations.
They could be cleaned up using JUnit's ParameterizedTest - that way you only have to write the test logic once and pass different inputs into the test.
| assertThat(request.image()).isEqualTo("docling-project/docling-serve"); | ||
| assertThat(request.executor()).isEqualTo(TEST_EXECUTOR); | ||
| assertThat(request.cleanupContainerImages()).isTrue(); | ||
| assertThat(request.tags()).containsExactly("v1.0.0", "v1.1.0"); |
There was a problem hiding this comment.
Rather than a handful of individual asserts like this you could do something like this instead:
var request = ... // Build the request using the builder as you have
var expected = new TagsTestRequest("ghcr.io", "docling-project/docling-serve", TEST_EXECUTOR, true, List.of("v.1.0.0", "v1.1.0"));
assertThat(request)
.isNotNull()
.usingRecursiveComparison()
.isEqualTo(expected);AssertJ provides a nice way to perform equality by doing field-by-field comparisons (see https://assertj.github.io/doc/#assertj-core-recursive-comparison).
| .tags(List.of("v2.0.0")) | ||
| .build(); | ||
|
|
||
| assertThat(originalRequest.registry()).isEqualTo("ghcr.io"); |
There was a problem hiding this comment.
Similar comment as above regarding the usage of recursive comparisons
| assertThat(copy.cleanupContainerImages()).isEqualTo(original.cleanupContainerImages()); | ||
| assertThat(copy.tags()).isEqualTo(original.tags()); | ||
| } | ||
|
|
There was a problem hiding this comment.
The rest of these tests are just variants of the same tests and aren't needed.
Summary
Adds comprehensive unit test coverage across the
client,domain, andservicelayers of thedocling-version-testsmodule.Changes
New Test Classes
RegistryClientFactoryTestsRegistryClientFactoryGHCRClientLoggerTestsGHCRClientLoggerTagsTestRequestTestsTagsTestRequestNamedThreadFactoryTestsNamedThreadFactoryWorkParallelizerTestsWorkParallelizerExtended Test Classes
TagTestResultTestsTagsTestResultssorting,from()factory,toBuilder(),setResults()/clearResults(), failure detection, and nested/long stack trace handlingCoverage Highlights
RegistryClientFactory— validates correct client dispatch forghcr.io, plus rejection of unsupported, null, empty, whitespace-padded, and case-mismatched registry strings; verifies client instance reuse.GHCRClientLogger— validates conditional request/response logging, masking oftokenfields in JSON bodies,AuthorizationandSet-Cookieheader redaction, and graceful handling of null, empty, non-JSON, and JSON-array bodies.TagsTestRequest— validates builder construction,toBuilder()round-trip fidelity, method chaining, override behavior, and mandatoryexecutorfield enforcement.NamedThreadFactory— validates thread naming with incrementing suffix, isolated counters per factory instance, and thread-safe concurrent creation.WorkParallelizer— validates paralleltransformandrunsemantics across empty, single, multi-item, and large (100-item) workloads with type-safe generic transformation.TagTestResult/TagsTestResults— extends existing tests with version-sorted result sets, factory construction from aTagsTestRequest, mutable builder operations, and failure presence detection.Test Design Notes
assertThat(AssertJ).CountDownLatch/AtomicIntegerto avoid race conditions in assertions.