Skip to content

Commit 858dd0a

Browse files
Add YugabyteDB module (#4372)
Yugabyte provides two implementations `YSQL` and `YCQL`. This module will provide both `YugabyteDBYSQLContainer` and `YugabyteDBYCQLContainer`. Signed-off-by: Srinivasa Vasu <[email protected]> Co-authored-by: Eddú Meléndez <[email protected]>
1 parent e3ec7d4 commit 858dd0a

File tree

20 files changed

+935
-0
lines changed

20 files changed

+935
-0
lines changed

.github/ISSUE_TEMPLATE/bug_report.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ body:
5050
- ToxiProxy
5151
- Trino
5252
- Vault
53+
- YugabyteDB
5354
validations:
5455
required: true
5556
- type: input

.github/ISSUE_TEMPLATE/enhancement.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ body:
5050
- ToxiProxy
5151
- Trino
5252
- Vault
53+
- YugabyteDB
5354
validations:
5455
required: true
5556
- type: textarea

.github/ISSUE_TEMPLATE/feature.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ body:
5050
- ToxiProxy
5151
- Trino
5252
- Vault
53+
- YugabyteDB
5354
- New Module
5455
- type: textarea
5556
id: problem

.github/dependabot.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,11 @@ updates:
258258
schedule:
259259
interval: "monthly"
260260
open-pull-requests-limit: 10
261+
- package-ecosystem: "gradle"
262+
directory: "/modules/yugabytedb"
263+
schedule:
264+
interval: "monthly"
265+
open-pull-requests-limit: 10
261266

262267
# Examples
263268
- package-ecosystem: "gradle"

.github/labeler.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,5 +87,7 @@
8787
- modules/trino/**/*
8888
"modules/vault":
8989
- modules/vault/**/*
90+
"modules/yugabytedb":
91+
- modules/yugabytedb/**/*
9092
"type/docs":
9193
- docs/**/*.md
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# YugabyteDB Module
2+
3+
!!! note
4+
This module is INCUBATING. While it is ready for use and operational in the current version of Testcontainers, it is possible that it may receive breaking changes in the future. See [our contributing guidelines](/contributing/#incubating-modules) for more information on our incubating modules policy.
5+
6+
See [Database containers](./index.md) for documentation and usage that is common to all database container types.
7+
8+
YugabyteDB supports two APIs.
9+
- Yugabyte Structured Query Language [YSQL](https://docs.yugabyte.com/latest/api/ysql/) is a fully-relational API that is built by the PostgreSQL code
10+
- Yugabyte Cloud Query Language [YCQL](https://docs.yugabyte.com/latest/api/ycql/) is a semi-relational SQL API that has its roots in the Cassandra Query Language
11+
12+
## Usage example
13+
14+
### YSQL API
15+
16+
<!--codeinclude-->
17+
[Creating a YSQL container](../../../modules/yugabytedb/src/test/java/org/testcontainers/junit/yugabytedb/YugabyteDBYSQLTest.java) inside_block:creatingYSQLContainer
18+
<!--/codeinclude-->
19+
20+
21+
<!--codeinclude-->
22+
[Starting a YSQL container](../../../modules/yugabytedb/src/test/java/org/testcontainers/junit/yugabytedb/YugabyteDBYSQLTest.java) inside_block:startingYSQLContainer
23+
<!--/codeinclude-->
24+
25+
26+
### YCQL API
27+
28+
<!--codeinclude-->
29+
[Creating a YCQL container](../../../modules/yugabytedb/src/test/java/org/testcontainers/junit/yugabytedb/YugabyteDBYCQLTest.java) inside_block:creatingYCQLContainer
30+
<!--/codeinclude-->
31+
32+
33+
<!--codeinclude-->
34+
[Starting a YCQL container](../../../modules/yugabytedb/src/test/java/org/testcontainers/junit/yugabytedb/YugabyteDBYCQLTest.java) inside_block:startingYCQLContainer
35+
<!--/codeinclude-->
36+
37+
38+
## Adding this module to your project dependencies
39+
40+
Add the following dependency to your `pom.xml`/`build.gradle` file:
41+
42+
=== "Gradle"
43+
```groovy
44+
testImplementation "org.testcontainers:yugabytedb:{{latest_version}}"
45+
```
46+
=== "Maven"
47+
```xml
48+
<dependency>
49+
<groupId>org.testcontainers</groupId>
50+
<artifactId>yugabytedb</artifactId>
51+
<version>{{latest_version}}</version>
52+
<scope>test</scope>
53+
</dependency>
54+
```
55+
56+
!!! hint
57+
Adding this Testcontainers library JAR will not automatically add the Yugabytedb driver JAR to your project.
58+
You should ensure that your project has the Yugabytedb driver as a dependency, if you plan on using it.
59+
Refer to the driver page [YSQL](https://docs.yugabyte.com/latest/integrations/jdbc-driver/) and [YCQL](https://docs.yugabyte.com/latest/reference/drivers/ycql-client-drivers/) for instructions.

modules/yugabytedb/build.gradle

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
description = "Testcontainers :: JDBC :: YugabyteDB"
2+
3+
dependencies {
4+
api project(':jdbc')
5+
testImplementation project(':jdbc-test')
6+
// YCQL driver
7+
testImplementation 'com.yugabyte:java-driver-core:4.6.0-yb-11'
8+
// YSQL driver
9+
testImplementation 'com.yugabyte:jdbc-yugabytedb:42.3.4'
10+
}
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
package org.testcontainers.containers;
2+
3+
import com.github.dockerjava.api.command.InspectContainerResponse;
4+
import org.testcontainers.containers.delegate.YugabyteDBYCQLDelegate;
5+
import org.testcontainers.containers.strategy.YugabyteDBYCQLWaitStrategy;
6+
import org.testcontainers.ext.ScriptUtils;
7+
import org.testcontainers.utility.DockerImageName;
8+
9+
import java.net.InetSocketAddress;
10+
import java.time.Duration;
11+
import java.util.Collections;
12+
import java.util.Set;
13+
14+
/**
15+
* Testcontainers implementation for YugabyteDB YCQL API.
16+
*
17+
* @author srinivasa-vasu
18+
* @see <a href="https://docs.yugabyte.com/stable/api/ycql/">YCQL API</a>
19+
*/
20+
public class YugabyteDBYCQLContainer extends GenericContainer<YugabyteDBYCQLContainer> {
21+
22+
private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName.parse("yugabytedb/yugabyte");
23+
24+
private static final Integer YCQL_PORT = 9042;
25+
26+
private static final Integer MASTER_DASHBOARD_PORT = 7000;
27+
28+
private static final Integer TSERVER_DASHBOARD_PORT = 9000;
29+
30+
private static final String ENTRYPOINT = "bin/yugabyted start --background=false";
31+
32+
private static final String LOCAL_DC = "datacenter1";
33+
34+
private String keyspace;
35+
36+
private String username;
37+
38+
private String password;
39+
40+
private String initScript;
41+
42+
/**
43+
* @param imageName image name
44+
*/
45+
public YugabyteDBYCQLContainer(final String imageName) {
46+
this(DockerImageName.parse(imageName));
47+
}
48+
49+
/**
50+
* @param imageName image name
51+
*/
52+
public YugabyteDBYCQLContainer(final DockerImageName imageName) {
53+
super(imageName);
54+
imageName.assertCompatibleWith(DEFAULT_IMAGE_NAME);
55+
withExposedPorts(YCQL_PORT, MASTER_DASHBOARD_PORT, TSERVER_DASHBOARD_PORT);
56+
waitingFor(new YugabyteDBYCQLWaitStrategy(this).withStartupTimeout(Duration.ofSeconds(60)));
57+
withCommand(ENTRYPOINT);
58+
}
59+
60+
@Override
61+
public Set<Integer> getLivenessCheckPortNumbers() {
62+
return Collections.singleton(getMappedPort(YCQL_PORT));
63+
}
64+
65+
/**
66+
* Configures the environment variables. Setting up these variables would create the
67+
* custom objects. Setting {@link #withKeyspaceName(String)},
68+
* {@link #withUsername(String)}, {@link #withPassword(String)} these parameters will
69+
* initilaize the database with those custom values
70+
*/
71+
@Override
72+
protected void configure() {
73+
addEnv("YCQL_KEYSPACE", keyspace);
74+
addEnv("YCQL_USER", username);
75+
addEnv("YCQL_PASSWORD", password);
76+
}
77+
78+
/**
79+
* @param initScript path of the initialization script file
80+
* @return {@link YugabyteDBYCQLContainer} instance
81+
*/
82+
public YugabyteDBYCQLContainer withInitScript(String initScript) {
83+
this.initScript = initScript;
84+
return this;
85+
}
86+
87+
/**
88+
* Setting this would create the keyspace
89+
* @param keyspace keyspace
90+
* @return {@link YugabyteDBYCQLContainer} instance
91+
*/
92+
public YugabyteDBYCQLContainer withKeyspaceName(final String keyspace) {
93+
this.keyspace = keyspace;
94+
return this;
95+
}
96+
97+
/**
98+
* Setting this would create the custom user role
99+
* @param username user name
100+
* @return {@link YugabyteDBYCQLContainer} instance
101+
*/
102+
public YugabyteDBYCQLContainer withUsername(final String username) {
103+
this.username = username;
104+
return this;
105+
}
106+
107+
/**
108+
* Setting this along with {@link #withUsername(String)} would enable authentication
109+
* @param password password
110+
* @return {@link YugabyteDBYCQLContainer} instance
111+
*/
112+
public YugabyteDBYCQLContainer withPassword(final String password) {
113+
this.password = password;
114+
return this;
115+
}
116+
117+
/**
118+
* Executes the initilization script
119+
* @param containerInfo containerInfo
120+
*/
121+
@Override
122+
protected void containerIsStarted(InspectContainerResponse containerInfo) {
123+
if (this.initScript != null) {
124+
ScriptUtils.runInitScript(new YugabyteDBYCQLDelegate(this), initScript);
125+
}
126+
}
127+
128+
/**
129+
* Returns a {@link InetSocketAddress} representation of YCQL's contact point info
130+
* @return contactpoint
131+
*/
132+
public InetSocketAddress getContactPoint() {
133+
return new InetSocketAddress(getHost(), getMappedPort(YCQL_PORT));
134+
}
135+
136+
/**
137+
* Returns the local datacenter name
138+
* @return localdc name
139+
*/
140+
public String getLocalDc() {
141+
return LOCAL_DC;
142+
}
143+
144+
/**
145+
* Username getter method
146+
* @return username
147+
*/
148+
public String getUsername() {
149+
return this.username;
150+
}
151+
152+
/**
153+
* Password getter method
154+
* @return password
155+
*/
156+
public String getPassword() {
157+
return this.password;
158+
}
159+
160+
/**
161+
* Keyspace getter method
162+
* @return keyspace
163+
*/
164+
public String getKeyspace() {
165+
return this.keyspace;
166+
}
167+
}

0 commit comments

Comments
 (0)