Skip to content

Commit 34181ba

Browse files
committed
#6: Run YDB Repository Integration Tests on every commit
1 parent 8148d24 commit 34181ba

19 files changed

+306
-193
lines changed

.github/workflows/build.yaml

+21-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Build YOJ (unit tests only)
1+
name: Build YOJ
22

33
on:
44
push:
@@ -9,7 +9,7 @@ on:
99

1010
jobs:
1111
build:
12-
name: Build YOJ (unit tests only)
12+
name: Build YOJ - Unit Tests
1313
runs-on: ubuntu-latest
1414

1515
env:
@@ -27,3 +27,22 @@ jobs:
2727

2828
- name: Build with Maven
2929
run: mvn $MAVEN_ARGS verify
30+
integration-test:
31+
name: Build YOJ - YDB Repository Integration Tests
32+
runs-on: ubuntu-latest
33+
34+
env:
35+
MAVEN_ARGS: --batch-mode --update-snapshots -Dstyle.color=always
36+
37+
steps:
38+
- uses: actions/checkout@v4
39+
40+
- name: Set up JDK
41+
uses: actions/setup-java@v4
42+
with:
43+
java-version: 17
44+
distribution: 'temurin'
45+
cache: 'maven'
46+
47+
- name: Build with Maven
48+
run: mvn $MAVEN_ARGS -Plombok,integration-test -am -pl :yoj-repository-ydb-v2 verify

pom.xml

+6
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@
151151
<bytebuddy.version>1.14.11</bytebuddy.version>
152152
<snakeyaml.version>1.33</snakeyaml.version>
153153
<aspectjweaver.version>1.9.21</aspectjweaver.version>
154+
<system-stubs.version>2.1.7</system-stubs.version>
154155
</properties>
155156

156157
<profiles>
@@ -508,6 +509,11 @@
508509
<artifactId>assertj-core</artifactId>
509510
<version>${assertj-core.version}</version>
510511
</dependency>
512+
<dependency>
513+
<groupId>uk.org.webcompere</groupId>
514+
<artifactId>system-stubs-junit4</artifactId>
515+
<version>${system-stubs.version}</version>
516+
</dependency>
511517
<dependency>
512518
<artifactId>slf4j-api</artifactId>
513519
<groupId>org.slf4j</groupId>

repository-test/src/main/java/tech/ydb/yoj/repository/test/RepositoryTestSupport.java

-7
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,6 @@ public abstract class RepositoryTestSupport {
1616

1717
protected Repository repository;
1818

19-
static {
20-
Runtime.getRuntime().addShutdownHook(new Thread(() -> repositoryMap.values().forEach(repo -> {
21-
repo.dropDb();
22-
repo.shutdown();
23-
})));
24-
}
25-
2619
protected abstract Repository createRepository();
2720

2821
@Before

repository-ydb-v2/pom.xml

+5
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,11 @@
152152
<artifactId>jackson-dataformat-yaml</artifactId>
153153
<scope>test</scope>
154154
</dependency>
155+
<dependency>
156+
<groupId>uk.org.webcompere</groupId>
157+
<artifactId>system-stubs-junit4</artifactId>
158+
<scope>test</scope>
159+
</dependency>
155160
</dependencies>
156161

157162
<build>

repository-ydb-v2/src/main/java/tech/ydb/yoj/repository/ydb/client/YdbPaths.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public static String canonicalDatabase(String database) {
2121
return database.endsWith("/") ? database.substring(0, database.length() - 1) : database;
2222
}
2323

24-
static String join(String parent, String child) {
24+
public static String join(String parent, String child) {
2525
return parent.isEmpty() ? child : (parent.endsWith("/") ? parent : parent + "/") + child;
2626
}
2727

Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
package tech.ydb.yoj.repository.ydb;
22

33
import com.google.common.base.Strings;
4+
import com.google.common.net.HostAndPort;
45
import lombok.SneakyThrows;
6+
import tech.ydb.test.integration.YdbHelper;
7+
import tech.ydb.test.junit4.GrpcTransportRule;
8+
import tech.ydb.yoj.repository.ydb.client.YdbPaths;
59

610
import java.nio.file.Files;
711
import java.nio.file.Paths;
@@ -12,32 +16,43 @@
1216
* YDB configuration for integration tests.
1317
*/
1418
public class TestYdbConfig {
19+
@Deprecated(forRemoval = true)
1520
private static final YdbConfig config = create(String.valueOf(Instant.now().toEpochMilli()));
1621

17-
private static String getStr(String name, String defaultValue) {
18-
String value = System.getenv(name);
19-
return !Strings.isNullOrEmpty(value) ? value : defaultValue;
22+
public static YdbConfig create(YdbHelper helper, Instant started) {
23+
return create(helper, String.valueOf(started.toEpochMilli()));
2024
}
2125

22-
private static int getInt(String name, int defaultValue) {
23-
String value = System.getProperty(name);
24-
try {
25-
return Integer.parseInt(value);
26-
} catch (NumberFormatException e) {
27-
return defaultValue;
28-
}
29-
}
30-
31-
@SneakyThrows
32-
private static byte[] getFile(String name, byte[] defaultValue) {
33-
String fileName = getStr(name, null);
34-
return Strings.isNullOrEmpty(fileName) ? defaultValue : Files.readAllBytes(Paths.get(fileName));
26+
private static YdbConfig create(YdbHelper helper, String repId) {
27+
String endpoint = helper.endpoint();
28+
HostAndPort hostAndPort = HostAndPort.fromString(endpoint);
29+
return YdbConfig
30+
.createForTesting(
31+
hostAndPort.getHost(),
32+
hostAndPort.getPort(),
33+
YdbPaths.join(helper.database(), "it-" + repId + "/"),
34+
helper.database()
35+
)
36+
.withSessionKeepAliveTime(Duration.ofSeconds(10))
37+
.withSessionMaxIdleTime(Duration.ofSeconds(10))
38+
.withUseTLS(helper.useTls())
39+
.withRootCA(helper.pemCert())
40+
.withUseTrustStore(helper.pemCert() == null)
41+
;
3542
}
3643

44+
/**
45+
* @deprecated This methods returns an environment variable-based {@code YdbConfig} for integration tests with YDB that's
46+
* already running locally (either in a Docker container, or as a standalone service).
47+
* <br>
48+
* We've transitioned to TestContainers, please use {@link GrpcTransportRule} and {@link #create(YdbHelper, Instant)} instead.
49+
*/
50+
@Deprecated(forRemoval = true)
3751
public static YdbConfig get() {
3852
return config;
3953
}
4054

55+
@Deprecated(forRemoval = true)
4156
private static YdbConfig create(String repId) {
4257
return YdbConfig
4358
.createForTesting(
@@ -52,4 +67,24 @@ private static YdbConfig create(String repId) {
5267
.withRootCA(getFile("YDB_ROOT_CA", null))
5368
;
5469
}
70+
71+
private static String getStr(String name, String defaultValue) {
72+
String value = System.getenv(name);
73+
return !Strings.isNullOrEmpty(value) ? value : defaultValue;
74+
}
75+
76+
private static int getInt(String name, int defaultValue) {
77+
String value = System.getProperty(name);
78+
try {
79+
return Integer.parseInt(value);
80+
} catch (NumberFormatException e) {
81+
return defaultValue;
82+
}
83+
}
84+
85+
@SneakyThrows
86+
private static byte[] getFile(String name, byte[] defaultValue) {
87+
String fileName = getStr(name, null);
88+
return Strings.isNullOrEmpty(fileName) ? defaultValue : Files.readAllBytes(Paths.get(fileName));
89+
}
5590
}

repository-ydb-v2/src/test/java/tech/ydb/yoj/repository/ydb/TestYdbRepository.java

+5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import io.grpc.ClientInterceptor;
44
import tech.ydb.auth.AuthProvider;
5+
import tech.ydb.core.grpc.GrpcTransport;
56
import tech.ydb.yoj.repository.db.IsolationLevel;
67
import tech.ydb.yoj.repository.db.RepositoryTransaction;
78
import tech.ydb.yoj.repository.db.Table;
@@ -53,6 +54,10 @@ public TestYdbRepository(YdbConfig config) {
5354
super(config);
5455
}
5556

57+
public TestYdbRepository(YdbConfig config, GrpcTransport transport) {
58+
super(config, transport);
59+
}
60+
5661
public TestYdbRepository(YdbConfig config, AuthProvider authProvider, List<ClientInterceptor> interceptors) {
5762
super(config, authProvider, interceptors);
5863
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
package tech.ydb.yoj.repository.ydb;
2+
3+
import org.junit.Assume;
4+
import org.junit.rules.TestRule;
5+
import org.junit.runner.Description;
6+
import org.junit.runners.model.MultipleFailureException;
7+
import org.junit.runners.model.Statement;
8+
import org.slf4j.Logger;
9+
import org.slf4j.LoggerFactory;
10+
import tech.ydb.core.grpc.GrpcTransport;
11+
import tech.ydb.test.integration.YdbHelper;
12+
import tech.ydb.test.integration.YdbHelperFactory;
13+
import tech.ydb.test.integration.utils.ProxyGrpcTransport;
14+
import uk.org.webcompere.systemstubs.environment.EnvironmentVariableMocker;
15+
16+
import java.time.Instant;
17+
import java.util.ArrayList;
18+
import java.util.HashMap;
19+
import java.util.List;
20+
import java.util.Map;
21+
import java.util.Set;
22+
import java.util.concurrent.atomic.AtomicReference;
23+
24+
public final class YdbEnvAndTransportRule implements TestRule {
25+
private final Instant started = Instant.now();
26+
private final GrpcTransportRule transportRule = new GrpcTransportRule();
27+
28+
@Override
29+
public Statement apply(Statement base, Description description) {
30+
return new Statement() {
31+
@Override
32+
public void evaluate() throws Throwable {
33+
List<Throwable> errors = new ArrayList<>();
34+
try {
35+
Map<String, String> evm = new HashMap<>();
36+
evm.put("YDB_DOCKER_IMAGE", "docker.io/ydbplatform/local-ydb@sha256:79b36e76ecc8bc64e208e8949c1710c50d84cf718b575feba0522dba27b377cd");
37+
38+
Statement ydbEnrichedStatement;
39+
40+
EnvironmentVariableMocker.connect(evm, Set.of());
41+
try {
42+
ydbEnrichedStatement = transportRule.apply(base, description);
43+
} finally {
44+
EnvironmentVariableMocker.remove(evm);
45+
}
46+
47+
ydbEnrichedStatement.evaluate();
48+
} catch (Throwable t) {
49+
errors.add(t);
50+
} finally {
51+
try {
52+
transportRule.close();
53+
} catch (Throwable t) {
54+
errors.add(t);
55+
}
56+
}
57+
MultipleFailureException.assertEmpty(errors);
58+
}
59+
};
60+
}
61+
62+
public GrpcTransport getGrpcTransport() {
63+
return transportRule;
64+
}
65+
66+
public YdbConfig getYdbConfig() {
67+
return TestYdbConfig.create(transportRule.helper(), started);
68+
}
69+
70+
private static final class GrpcTransportRule extends ProxyGrpcTransport implements TestRule {
71+
private static final Logger logger = LoggerFactory.getLogger(GrpcTransportRule.class);
72+
73+
private final AtomicReference<YdbHelper> helper = new AtomicReference<>();
74+
private final AtomicReference<GrpcTransport> transport = new AtomicReference<>();
75+
76+
@Override
77+
public Statement apply(Statement base, Description description) {
78+
YdbHelperFactory factory = YdbHelperFactory.getInstance();
79+
80+
return new Statement() {
81+
@Override
82+
public void evaluate() throws Throwable {
83+
if (!factory.isEnabled()) {
84+
logger.info("Test {} skipped because ydb helper is not available", description.getDisplayName());
85+
Assume.assumeFalse("YDB Helper is not available", true);
86+
return;
87+
}
88+
89+
String path = description.getClassName();
90+
if (description.getMethodName() != null) {
91+
path += "/" + description.getMethodName();
92+
}
93+
94+
logger.debug("create ydb helper for test {}", path);
95+
try (YdbHelper helper = factory.createHelper()) {
96+
GrpcTransportRule.this.helper.set(helper);
97+
try (GrpcTransport transport = helper.createTransport()) {
98+
GrpcTransportRule.this.transport.set(transport);
99+
base.evaluate();
100+
} finally {
101+
GrpcTransportRule.this.transport.set(null);
102+
}
103+
} finally {
104+
GrpcTransportRule.this.helper.set(null);
105+
}
106+
}
107+
};
108+
}
109+
110+
@Override
111+
protected GrpcTransport origin() {
112+
return GrpcTransportRule.this.transport.get();
113+
}
114+
115+
protected YdbHelper helper() {
116+
return GrpcTransportRule.this.helper.get();
117+
}
118+
}
119+
}

0 commit comments

Comments
 (0)