Skip to content

Commit 22b65fa

Browse files
committed
First commit for integration tests
1 parent 581236f commit 22b65fa

File tree

15 files changed

+200733
-13
lines changed

15 files changed

+200733
-13
lines changed

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ plugins {
99

1010
val sinkVersion by extra("0.0.1")
1111
val flinkVersion by extra("1.18.0")
12-
val clickhouseVersion by extra("0.4.6")
12+
val clickhouseVersion by extra("0.9.0-SNAPSHOT")
1313
val junitVersion by extra("5.8.2")
1414

1515
allprojects {

flink-connector-clickhouse-1.17/build.gradle.kts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,18 @@ plugins {
1414

1515
val scalaVersion = "2.13.12"
1616
val sinkVersion: String by rootProject.extra
17+
val clickhouseVersion: String by rootProject.extra // Temporary until we have a Java Client release
1718

1819
repositories {
1920
// Use Maven Central for resolving dependencies.
2021
// mavenLocal()
21-
maven("https://s01.oss.sonatype.org/content/groups/staging/") // Temporary until we have a Java Client release
22+
maven("https://central.sonatype.com/repository/maven-snapshots/") // Temporary until we have a Java Client release
2223
mavenCentral()
2324
}
2425

2526
val flinkVersion = System.getenv("FLINK_VERSION") ?: "1.17.2"
2627

2728
extra.apply {
28-
set("clickHouseDriverVersion", "0.9.0-SNAPSHOT") // Temporary until we have a Java Client release
2929
set("flinkVersion", flinkVersion)
3030
set("log4jVersion","2.17.2")
3131
set("testContainersVersion", "1.21.0")
@@ -53,7 +53,7 @@ dependencies {
5353

5454
testImplementation(project(":flink-connector-clickhouse-base"))
5555
// ClickHouse Client Libraries
56-
implementation("com.clickhouse:client-v2:${project.extra["clickHouseDriverVersion"]}:all")
56+
implementation("com.clickhouse:client-v2:${clickhouseVersion}:all")
5757
// Apache Flink Libraries
5858
implementation("org.apache.flink:flink-connector-base:${project.extra["flinkVersion"]}")
5959
implementation("org.apache.flink:flink-streaming-java:${project.extra["flinkVersion"]}")

flink-connector-clickhouse-2.0.0/build.gradle.kts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,16 +14,16 @@ plugins {
1414

1515
val scalaVersion = "2.13.12"
1616
val sinkVersion: String by rootProject.extra
17+
val clickhouseVersion: String by rootProject.extra // Temporary until we have a Java Client release
1718

1819
repositories {
1920
// Use Maven Central for resolving dependencies.
2021
// mavenLocal()
21-
maven("https://s01.oss.sonatype.org/content/groups/staging/") // Temporary until we have a Java Client release
22+
maven("https://central.sonatype.com/repository/maven-snapshots/") // Temporary until we have a Java Client release
2223
mavenCentral()
2324
}
2425

2526
extra.apply {
26-
set("clickHouseDriverVersion", "0.9.0-SNAPSHOT") // Temporary until we have a Java Client release
2727
set("flinkVersion", "2.0.0")
2828
set("log4jVersion","2.17.2")
2929
set("testContainersVersion", "1.21.0")
@@ -45,7 +45,7 @@ dependencies {
4545
implementation("org.apache.logging.log4j:log4j-core:${project.extra["log4jVersion"]}")
4646

4747
// ClickHouse Client Libraries
48-
implementation("com.clickhouse:client-v2:${project.extra["clickHouseDriverVersion"]}:all")
48+
implementation("com.clickhouse:client-v2:${clickhouseVersion}:all")
4949
// Apache Flink Libraries
5050
implementation("org.apache.flink:flink-connector-base:${project.extra["flinkVersion"]}")
5151
implementation("org.apache.flink:flink-streaming-java:${project.extra["flinkVersion"]}")

flink-connector-clickhouse-base/build.gradle.kts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,22 @@ plugins {
77
`maven-publish`
88
java
99
signing
10+
`java-test-fixtures`
1011
id("com.gradleup.nmcp") version "0.0.8"
1112
id("com.github.johnrengelman.shadow") version "8.1.1"
1213
}
1314

1415
val scalaVersion = "2.13.12"
1516
val sinkVersion: String by rootProject.extra
17+
val clickhouseVersion: String by rootProject.extra // Temporary until we have a Java Client release
1618

1719
repositories {
18-
maven("https://s01.oss.sonatype.org/content/groups/staging/") // Temporary until we have a Java Client release
20+
maven("https://central.sonatype.com/repository/maven-snapshots/") // Temporary until we have a Java Client release
1921
// Use Maven Central for resolving dependencies.
2022
mavenCentral()
2123
}
2224

2325
extra.apply {
24-
set("clickHouseDriverVersion", "0.9.0-SNAPSHOT") // Temporary until we have a Java Client release
2526
set("flinkVersion", "2.0.0")
2627
set("log4jVersion","2.17.2")
2728
set("testContainersVersion", "1.21.0")
@@ -30,8 +31,8 @@ extra.apply {
3031

3132
dependencies {
3233
// Use JUnit Jupiter for testing.
33-
testImplementation(libs.junit.jupiter)
34-
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
34+
testFixturesImplementation(libs.junit.jupiter)
35+
testFixturesImplementation("org.junit.platform:junit-platform-launcher")
3536

3637
// logger
3738
implementation("org.apache.logging.log4j:log4j-slf4j-impl:${project.extra["log4jVersion"]}")
@@ -40,7 +41,17 @@ dependencies {
4041
implementation("org.apache.logging.log4j:log4j-core:${project.extra["log4jVersion"]}")
4142

4243
// ClickHouse Client Libraries
43-
implementation("com.clickhouse:client-v2:${project.extra["clickHouseDriverVersion"]}:all")
44+
implementation("com.clickhouse:client-v2:${clickhouseVersion}:all")
45+
46+
// For testing
47+
testFixturesImplementation("com.clickhouse:client-v2:${clickhouseVersion}:all")
48+
testFixturesImplementation("org.testcontainers:testcontainers:${project.extra["testContainersVersion"]}")
49+
testFixturesImplementation("org.testcontainers:clickhouse:${project.extra["testContainersVersion"]}")
50+
testFixturesImplementation("com.squareup.okhttp3:okhttp:5.1.0")
51+
testFixturesImplementation("com.google.code.gson:gson:2.10.1")
52+
testFixturesImplementation("org.scalatest:scalatest_2.13:3.2.19")
53+
testFixturesImplementation("org.scalatestplus:junit-4-13_2.13:3.2.18.0")
54+
4455
}
4556

4657
sourceSets {
Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
package com.clickhouse.flink;
2+
3+
import com.google.gson.Gson;
4+
import com.google.gson.JsonArray;
5+
import com.google.gson.JsonElement;
6+
import com.google.gson.JsonObject;
7+
import okhttp3.*;
8+
import org.testcontainers.containers.GenericContainer;
9+
import org.testcontainers.containers.Network;
10+
import org.testcontainers.images.builder.Transferable;
11+
import org.testcontainers.utility.DockerImageName;
12+
import org.testcontainers.utility.MountableFile;
13+
14+
import java.io.File;
15+
import java.io.IOException;
16+
import java.util.ArrayList;
17+
import java.util.List;
18+
19+
public class Cluster {
20+
21+
private static final int INTERNAL_REST_PORT = 8081;
22+
private static final int INTERNAL_JOB_MANAGER_RCP_PORT = 6123;
23+
24+
private GenericContainer<?> containerJobManager;
25+
private List<GenericContainer<?>> containerTaskManagerList = new ArrayList<>();
26+
27+
public static class Builder {
28+
private String flinkVersion;
29+
private int taskManagers;
30+
private String sourcePath;
31+
private String dataFilename;
32+
private String targetPath;
33+
private Network network;
34+
35+
public Builder() {
36+
taskManagers = 1;
37+
flinkVersion = "latest";
38+
sourcePath = null;
39+
dataFilename = null;
40+
targetPath = null;
41+
network = null;
42+
}
43+
public Builder withTaskManagers(int taskManagers) {
44+
this.taskManagers = taskManagers;
45+
return this;
46+
}
47+
48+
public Builder withFlinkVersion(String flinkVersion) {
49+
this.flinkVersion = flinkVersion;
50+
return this;
51+
}
52+
53+
public Builder withDataFile(String sourcePath, String dataFilename, String targetPath) {
54+
this.sourcePath = sourcePath;
55+
this.dataFilename = dataFilename;
56+
this.targetPath = targetPath;
57+
return this;
58+
}
59+
60+
public Builder withNetwork(Network network) {
61+
this.network = network;
62+
return this;
63+
}
64+
65+
public Cluster build() {
66+
// when we are not specifying a network we should create one
67+
if (network == null) {
68+
network = Network.newNetwork();
69+
}
70+
Cluster cluster = new Cluster(flinkVersion, taskManagers, sourcePath, dataFilename, targetPath, network);
71+
return cluster;
72+
}
73+
74+
}
75+
76+
public Cluster(String flinkVersion, int taskManagers, String sourcePath, String dataFilename, String targetPath, Network network) {
77+
MountableFile mountableFile = MountableFile.forHostPath(sourcePath + dataFilename);
78+
String dataFileInContainer = String.format("%s/%s", targetPath, dataFilename);
79+
String flinkImageTag = String.format("flink:%s", flinkVersion);
80+
DockerImageName FLINK_IMAGE = DockerImageName.parse(flinkImageTag);
81+
containerJobManager = new GenericContainer<>(FLINK_IMAGE)
82+
.withCommand("jobmanager")
83+
.withNetwork(network)
84+
.withExposedPorts(INTERNAL_REST_PORT, INTERNAL_JOB_MANAGER_RCP_PORT)
85+
.withNetworkAliases("jobmanager")
86+
.withEnv("FLINK_PROPERTIES","jobmanager.rpc.address: jobmanager");
87+
88+
if (sourcePath != null) {
89+
containerJobManager.withCopyFileToContainer(mountableFile, dataFileInContainer);
90+
}
91+
for (int i = 0; i < taskManagers; i++) {
92+
GenericContainer<?> containerTaskManager = new GenericContainer<>(FLINK_IMAGE)
93+
.withCommand("taskmanager")
94+
.withNetwork(network)
95+
.dependsOn(containerJobManager)
96+
.withEnv("FLINK_PROPERTIES","jobmanager.rpc.address: jobmanager");
97+
if (sourcePath != null) {
98+
containerTaskManager.withCopyFileToContainer(mountableFile, dataFileInContainer);
99+
}
100+
containerTaskManagerList.add(containerTaskManager);
101+
}
102+
103+
containerJobManager.start();
104+
for (int i = 0; i < taskManagers; i++) {
105+
containerTaskManagerList.get(i).start();
106+
}
107+
// TODO: add strategy for wait
108+
}
109+
110+
public int getDashboardPort() {
111+
return containerJobManager.getMappedPort(INTERNAL_REST_PORT);
112+
}
113+
114+
public String getDashboardUrl() {
115+
return String.format("%s:%s",containerJobManager.getContainerIpAddress(), getDashboardPort());
116+
}
117+
118+
public GenericContainer<?> getContainerJobManager() {
119+
return containerJobManager;
120+
}
121+
122+
public List<GenericContainer<?>> getContainerTaskManagerList() {
123+
return containerTaskManagerList;
124+
}
125+
126+
public String uploadJar(String jarFilePath) throws IOException {
127+
File jarFile = new File(jarFilePath);
128+
String clusterURLJarUploadAPI = String.format("http://%s/jars/upload", getDashboardUrl());
129+
OkHttpClient client = new OkHttpClient();
130+
RequestBody fileBody = RequestBody.create(jarFile, MediaType.parse("application/java-archive"));
131+
MultipartBody requestBody = new MultipartBody.Builder()
132+
.setType(MultipartBody.FORM)
133+
.addFormDataPart("jarfile", jarFile.getName(), fileBody)
134+
.build();
135+
Request request = new Request.Builder()
136+
.url(clusterURLJarUploadAPI)
137+
.post(requestBody).build();
138+
Response response = client.newCall(request).execute();
139+
if (!response.isSuccessful()) {
140+
System.err.println("Unexpected code " + response);
141+
return null;
142+
} else {
143+
Gson gson = new Gson();
144+
System.out.println("Upload successful!");
145+
String responseBody = response.body().string();
146+
JsonObject jsonObject = gson.fromJson(responseBody, JsonObject.class);
147+
if (jsonObject.has("status") &
148+
jsonObject.get("status").getAsString().equalsIgnoreCase("success") &
149+
jsonObject.has("filename") ) {
150+
String filename = jsonObject.get("filename").getAsString();
151+
System.out.println("filename: " + filename);
152+
return filename;
153+
}
154+
return null;
155+
}
156+
157+
158+
}
159+
public List<String> listAllJars() throws IOException {
160+
String clusterURLListJars = String.format("http://%s/jars", getDashboardUrl());
161+
162+
OkHttpClient client = new OkHttpClient();
163+
Request request = new Request.Builder()
164+
.url(clusterURLListJars)
165+
.build();
166+
Response response = client.newCall(request).execute();
167+
if (!response.isSuccessful()) {
168+
System.err.println("Unexpected code " + response);
169+
return null;
170+
} else {
171+
Gson gson = new Gson();
172+
String responseBody = response.body().string();
173+
System.out.println(responseBody);
174+
JsonObject jsonObject = gson.fromJson(responseBody, JsonObject.class);
175+
List<String> jars = new ArrayList<>();
176+
if (jsonObject.has("files")) {
177+
JsonArray jsonArray = jsonObject.getAsJsonArray("files");
178+
for (JsonElement element : jsonArray) {
179+
if (element.getAsJsonObject().has("id")) {
180+
jars.add(element.getAsJsonObject().get("id").getAsString());
181+
System.out.println("id: " + element.getAsJsonObject().get("id").getAsString());
182+
}
183+
}
184+
185+
}
186+
return jars;
187+
}
188+
189+
190+
}
191+
192+
public String runJob(String jarId, String entryClass, int parallelism, String... args) throws IOException {
193+
String programArg = String.join(",", args);
194+
String clusterURLJarRunAPI = String.format("http://%s/jars/%s/run?programArg=%s", getDashboardUrl(), jarId, programArg);
195+
RequestBody body = RequestBody.create(
196+
"",
197+
MediaType.get("application/json; charset=utf-8")
198+
);
199+
200+
OkHttpClient client = new OkHttpClient();
201+
Request request = new Request.Builder()
202+
.url(clusterURLJarRunAPI)
203+
.post(body)
204+
.build();
205+
206+
Response response = client.newCall(request).execute();
207+
if (!response.isSuccessful()) {
208+
System.err.println("Unexpected code " + response);
209+
return null;
210+
} else {
211+
Gson gson = new Gson();
212+
System.out.println("Upload successful!");
213+
String responseBody = response.body().string();
214+
System.out.println(responseBody);
215+
JsonObject jsonObject = gson.fromJson(responseBody, JsonObject.class);
216+
if (jsonObject.has("jobid") ) {
217+
String jobid = jsonObject.get("jobid").getAsString();
218+
System.out.println("jobid: " + jobid);
219+
return jobid;
220+
}
221+
return null;
222+
}
223+
}
224+
225+
public String jobStatus(String jobId) throws IOException {
226+
String clusterURLJobStatusAPI = String.format("http://%s/jobs/%s", getDashboardUrl(), jobId);
227+
OkHttpClient client = new OkHttpClient();
228+
Request request = new Request.Builder()
229+
.url(clusterURLJobStatusAPI)
230+
.build();
231+
Response response = client.newCall(request).execute();
232+
if (!response.isSuccessful()) {
233+
System.err.println("Unexpected code " + response);
234+
return null;
235+
} else {
236+
Gson gson = new Gson();
237+
System.out.println("Upload successful!");
238+
String responseBody = response.body().string();
239+
System.out.println(responseBody);
240+
JsonObject jsonObject = gson.fromJson(responseBody, JsonObject.class);
241+
if (jsonObject.has("state")) {
242+
String state = jsonObject.get("state").getAsString();
243+
System.out.println("state: " + state);
244+
return state;
245+
}
246+
return null;
247+
}
248+
}
249+
250+
public void tearDown() {
251+
252+
}
253+
254+
}

0 commit comments

Comments
 (0)