Skip to content

Commit 27c4001

Browse files
committed
test: Validate proper dynamic table factory wiring (#334)
1 parent 1f193d6 commit 27c4001

3 files changed

Lines changed: 105 additions & 0 deletions

File tree

flink-sql-runner/pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,13 @@
346346
<scope>test</scope>
347347
</dependency>
348348

349+
<dependency>
350+
<groupId>io.github.classgraph</groupId>
351+
<artifactId>classgraph</artifactId>
352+
<version>${classgraph.version}</version>
353+
<scope>test</scope>
354+
</dependency>
355+
349356
<dependency>
350357
<groupId>org.testcontainers</groupId>
351358
<artifactId>testcontainers-junit-jupiter</artifactId>
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright © 2026 DataSQRL (contact@datasqrl.com)
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.datasqrl.flinkrunner;
17+
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
20+
import com.google.auto.service.AutoService;
21+
import io.github.classgraph.AnnotationClassRef;
22+
import io.github.classgraph.ClassGraph;
23+
import io.github.classgraph.ClassInfo;
24+
import java.util.Set;
25+
import java.util.stream.Stream;
26+
import org.apache.flink.table.factories.DynamicTableSinkFactory;
27+
import org.apache.flink.table.factories.DynamicTableSourceFactory;
28+
import org.apache.flink.table.factories.Factory;
29+
import org.junit.jupiter.api.Test;
30+
31+
class FactoryAutoServiceTest {
32+
33+
private static final Set<String> FIRST_PARTY_ARTIFACTS =
34+
Set.of(
35+
"datagen-connectors",
36+
"flexible-csv-format",
37+
"flexible-json-format",
38+
"flink-sql-runner",
39+
"kafka-safe-connector",
40+
"postgresql-connector",
41+
"stdlib-iceberg");
42+
43+
@Test
44+
void dynamicTableFactoriesAreRegisteredWithAutoService() {
45+
try (var scanResult =
46+
new ClassGraph()
47+
.enableAnnotationInfo()
48+
.enableClassInfo()
49+
.acceptPackages("com.datasqrl", "org.apache.flink.streaming.connectors.kafka")
50+
.scan()) {
51+
52+
var factories =
53+
Stream.concat(
54+
scanResult.getClassesImplementing(DynamicTableSourceFactory.class).stream(),
55+
scanResult.getClassesImplementing(DynamicTableSinkFactory.class).stream())
56+
.filter(FactoryAutoServiceTest::isFirstPartyClass)
57+
.distinct()
58+
.toList();
59+
60+
assertThat(factories).isNotEmpty();
61+
62+
var factoriesMissingAutoService =
63+
factories.stream()
64+
.filter(factory -> !hasAutoServiceFactoryAnnotation(factory))
65+
.map(ClassInfo::getName)
66+
.toList();
67+
68+
assertThat(factoriesMissingAutoService)
69+
.as("Dynamic table factories missing @AutoService(Factory.class)")
70+
.isEmpty();
71+
}
72+
}
73+
74+
private static boolean isFirstPartyClass(ClassInfo classInfo) {
75+
var classpathElement = classInfo.getClasspathElementURI().toString();
76+
return FIRST_PARTY_ARTIFACTS.stream().anyMatch(classpathElement::contains);
77+
}
78+
79+
private static boolean hasAutoServiceFactoryAnnotation(ClassInfo classInfo) {
80+
var annotationInfo = classInfo.getAnnotationInfo(AutoService.class.getName());
81+
if (annotationInfo == null) {
82+
return false;
83+
}
84+
85+
var serviceTypes = annotationInfo.getParameterValues().getValue("value");
86+
if (serviceTypes instanceof Object[] array) {
87+
return Stream.of(array).anyMatch(FactoryAutoServiceTest::isFactoryClassRef);
88+
}
89+
90+
return isFactoryClassRef(serviceTypes);
91+
}
92+
93+
private static boolean isFactoryClassRef(Object serviceType) {
94+
return serviceType instanceof AnnotationClassRef classRef
95+
&& Factory.class.getName().equals(classRef.getName());
96+
}
97+
}

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
<auto.service.version>1.1.1</auto.service.version>
101101
<awaitility.version>4.3.0</awaitility.version>
102102
<aws-msk-iam-auth.version>2.3.6</aws-msk-iam-auth.version>
103+
<classgraph.version>4.8.184</classgraph.version>
103104
<commons-exec.version>1.6.0</commons-exec.version>
104105
<commons-math3.version>3.6.1</commons-math3.version>
105106
<feign.version>13.5</feign.version>

0 commit comments

Comments
 (0)