Skip to content

Commit 9b638d0

Browse files
authored
fix oblogproxy-ce build script and add java test case (#19)
* add java test case for oblogproxy-ce * add boot success message * fix java test case * modify test action trigger rule
1 parent 2770210 commit 9b638d0

File tree

6 files changed

+346
-13
lines changed

6 files changed

+346
-13
lines changed
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
name: test oblogproxy-ce
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- '!**/*.md'
7+
- '.github/workflows/**-oblogproxy-ce.yml'
8+
- '.github/workflows/**-oceanbase-ce.yml'
9+
- 'oblogproxy-ce/**'
10+
- 'oceanbase-ce/**'
11+
- 'test/**'
12+
13+
concurrency:
14+
group: test-oblogproxy-ce-${{ github.event.pull_request.number || github.ref }}
15+
cancel-in-progress: true
16+
17+
jobs:
18+
build-oceanbase-ce:
19+
uses: ./.github/workflows/build-oceanbase-ce.yml
20+
with:
21+
cache_key: test-oblogproxy-ce_oceanbase-ce
22+
image_file: oceanbase-ce.tar
23+
version: 4.2.1.6-106000012024042515
24+
25+
build-oblogproxy-ce:
26+
runs-on: ubuntu-latest
27+
steps:
28+
- name: Print environment variables
29+
run: printenv
30+
31+
- name: Check out repository code
32+
uses: actions/checkout@v4
33+
34+
- name: Set up QEMU
35+
uses: docker/setup-qemu-action@v3
36+
37+
- name: Set up Docker Buildx
38+
uses: docker/setup-buildx-action@v3
39+
40+
- name: Build oblogproxy-ce image
41+
uses: docker/build-push-action@v6
42+
with:
43+
context: ./oblogproxy-ce
44+
platforms: linux/amd64
45+
file: ./oblogproxy-ce/Dockerfile
46+
push: false
47+
load: true
48+
tags: oblogproxy-ce
49+
build-args: |
50+
VERSION=2.0.2-100000012024060321
51+
52+
- name: Export Docker image
53+
run: docker save -o oblogproxy-ce.tar oblogproxy-ce
54+
55+
- name: Upload artifact
56+
uses: actions/upload-artifact@v4
57+
with:
58+
name: test-oblogproxy-ce_oblogproxy-ce
59+
path: oblogproxy-ce.tar
60+
61+
test-oblogproxy-ce:
62+
runs-on: ubuntu-latest
63+
needs: [ build-oceanbase-ce, build-oblogproxy-ce ]
64+
steps:
65+
- name: Download artifact
66+
uses: actions/download-artifact@v4
67+
with:
68+
pattern: test-oblogproxy-ce_**
69+
path: /tmp
70+
71+
- name: Load Docker image
72+
run: |
73+
docker load -i /tmp/test-oblogproxy-ce_oceanbase-ce/oceanbase-ce.tar
74+
docker load -i /tmp/test-oblogproxy-ce_oblogproxy-ce/oblogproxy-ce.tar
75+
sudo rm -rf /tmp/*
76+
77+
- name: Start oceanbase-ce container
78+
uses: oceanbase/setup-oceanbase-ce@v1
79+
with:
80+
image_name: oceanbase-ce
81+
container_name: oceanbase-ce
82+
sql_port: 12881
83+
rpc_port: 12882
84+
mode: mini
85+
sys_root_password: 123456
86+
tenant_root_password: 654321
87+
88+
- name: Start oblogproxy-ce container
89+
run: docker run --name oblogproxy-ce -e OB_SYS_USERNAME=root -e OB_SYS_PASSWORD=123456 -p 12983:2983 -d oblogproxy-ce
90+
91+
- name: Set container IP
92+
id: set_container_ip
93+
run: |
94+
observer_ip=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' oceanbase-ce)
95+
oblogproxy_ip=$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' oblogproxy-ce)
96+
echo "Container 'oceanbase-ce' IP is $observer_ip."
97+
echo "Container 'oblogproxy-ce' IP is $oblogproxy_ip."
98+
99+
echo "observer_ip=$observer_ip" >> $GITHUB_OUTPUT
100+
echo "oblogproxy_ip=$oblogproxy_ip" >> $GITHUB_OUTPUT
101+
102+
- name: Checkout repository
103+
uses: actions/checkout@v4
104+
105+
- name: Set up Java
106+
uses: actions/setup-java@v4
107+
with:
108+
java-version: '8'
109+
distribution: 'zulu'
110+
111+
- name: Build test project
112+
run: |
113+
cd test
114+
mvn install -DskipTests=true
115+
116+
- name: Run test methods
117+
env:
118+
observer_ip: ${{ steps.set_container_ip.outputs.observer_ip }}
119+
oblogproxy_ip: ${{ steps.set_container_ip.outputs.oblogproxy_ip }}
120+
oblogproxy_port: 12983
121+
username: root@test
122+
password: 654321
123+
run: |
124+
cd test
125+
mvn verify -Dtest=LogProxyCETest -DfailIfNoTests=false

.github/workflows/test-oceanbase-ce.yml

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
name: test oceanbase-ce
22

33
on:
4-
push:
5-
branches: [ main ]
64
pull_request:
75
paths:
6+
- '!**/*.md'
87
- '.github/workflows/**-oceanbase-ce.yml'
98
- 'oceanbase-ce/**'
109
- 'test/**'
@@ -17,15 +16,15 @@ jobs:
1716
build:
1817
uses: ./.github/workflows/build-oceanbase-ce.yml
1918
with:
20-
cache_key: oceanbase-ce
19+
cache_key: test-oceanbase-ce
2120
image_file: oceanbase-ce.tar
2221
version: 4.2.3.1-101000032024061316
2322

2423
test-slim:
2524
needs: build
2625
uses: ./.github/workflows/java-test-oceanbase-ce.yml
2726
with:
28-
cache_key: oceanbase-ce
27+
cache_key: test-oceanbase-ce
2928
image_file: oceanbase-ce.tar
3029
mode: slim
3130
port: 1234
@@ -38,7 +37,7 @@ jobs:
3837
needs: build
3938
uses: ./.github/workflows/java-test-oceanbase-ce.yml
4039
with:
41-
cache_key: oceanbase-ce
40+
cache_key: test-oceanbase-ce
4241
image_file: oceanbase-ce.tar
4342
cluster_name: github-action
4443
mode: mini

oblogproxy-ce/start.sh

100644100755
Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
#!/bin/bash
22

33
if [[ -n ${OB_SYS_USERNAME} && -n ${OB_SYS_PASSWORD} ]]; then
4-
echo "y" | /usr/local/oblogproxy/run.sh config_sys ${OB_SYS_USERNAME} ${OB_ROOT_PASSWORD}
4+
echo "y" | /usr/local/oblogproxy/run.sh config_sys ${OB_SYS_USERNAME} ${OB_SYS_PASSWORD}
55
fi
66

7-
rm -rf /usr/local/oblogproxy/run/*
87
/usr/local/oblogproxy/run.sh start
9-
exec /sbin/init
8+
echo "boot success!" && exec /sbin/init

test/pom.xml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,17 @@
3535
</exclusion>
3636
</exclusions>
3737
</dependency>
38+
<dependency>
39+
<groupId>com.oceanbase</groupId>
40+
<artifactId>oblogclient-logproxy</artifactId>
41+
<version>1.1.2</version>
42+
<exclusions>
43+
<exclusion>
44+
<groupId>org.slf4j</groupId>
45+
<artifactId>slf4j-api</artifactId>
46+
</exclusion>
47+
</exclusions>
48+
</dependency>
3849
<dependency>
3950
<groupId>org.junit.jupiter</groupId>
4051
<artifactId>junit-jupiter</artifactId>
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
/*
2+
* Copyright 2024 OceanBase.
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+
17+
package com.oceanbase.test;
18+
19+
import com.oceanbase.clogproxy.client.LogProxyClient;
20+
import com.oceanbase.clogproxy.client.config.ClientConf;
21+
import com.oceanbase.clogproxy.client.config.ObReaderConfig;
22+
import com.oceanbase.clogproxy.client.exception.LogProxyClientException;
23+
import com.oceanbase.clogproxy.client.listener.RecordListener;
24+
import com.oceanbase.oms.logmessage.DataMessage;
25+
import com.oceanbase.oms.logmessage.LogMessage;
26+
import java.sql.Connection;
27+
import java.sql.Driver;
28+
import java.sql.SQLException;
29+
import java.sql.Statement;
30+
import java.time.Duration;
31+
import java.util.Map;
32+
import java.util.Properties;
33+
import java.util.concurrent.BlockingQueue;
34+
import java.util.concurrent.CountDownLatch;
35+
import java.util.concurrent.LinkedBlockingQueue;
36+
import java.util.concurrent.TimeUnit;
37+
import java.util.concurrent.atomic.AtomicBoolean;
38+
import java.util.stream.Collectors;
39+
import java.util.stream.Stream;
40+
import org.junit.jupiter.api.Assertions;
41+
import org.junit.jupiter.params.ParameterizedTest;
42+
import org.junit.jupiter.params.provider.Arguments;
43+
import org.junit.jupiter.params.provider.MethodSource;
44+
45+
public class LogProxyCETest {
46+
47+
private static final org.slf4j.Logger LOG =
48+
org.slf4j.LoggerFactory.getLogger(LogProxyCETest.class);
49+
50+
static Stream<Arguments> testLogProxyCEArgs() {
51+
// non-null env vars
52+
String observerIP = Utils.getNonEmptyEnv("observer_ip");
53+
String logProxyIP = Utils.getNonEmptyEnv("oblogproxy_ip");
54+
String logProxyPort = Utils.getNonEmptyEnv("oblogproxy_port");
55+
String username = Utils.getNonEmptyEnv("username");
56+
String password = Utils.getNonEmptyEnv("password");
57+
58+
return Stream.of(
59+
Arguments.of(observerIP, logProxyIP, "2983", username, password),
60+
Arguments.of(observerIP, "127.0.0.1", logProxyPort, username, password));
61+
}
62+
63+
@ParameterizedTest
64+
@MethodSource("testLogProxyCEArgs")
65+
public void testLogProxyCE(
66+
String observerIP,
67+
String logProxyIP,
68+
String logProxyPort,
69+
String username,
70+
String password)
71+
throws InterruptedException {
72+
73+
LOG.info(
74+
"Testing with args: [observerIP: {}, logProxyIP: {}, logProxyPort: {}, username: {}, password: {}]",
75+
observerIP,
76+
logProxyIP,
77+
logProxyPort,
78+
username,
79+
password);
80+
81+
ObReaderConfig obReaderConfig = new ObReaderConfig();
82+
83+
Properties props = new Properties();
84+
props.setProperty("user", username);
85+
props.setProperty("password", password);
86+
87+
Driver driver = Utils.getDriver(false);
88+
try (Connection conn = driver.connect("jdbc:mysql://" + observerIP + ":2881/test", props)) {
89+
obReaderConfig.setRsList(Utils.getRSList(conn));
90+
obReaderConfig.setTableWhiteList(Utils.getTenantName(conn) + ".*.*");
91+
} catch (SQLException e) {
92+
Assertions.fail(e);
93+
}
94+
95+
obReaderConfig.setUsername(username);
96+
obReaderConfig.setPassword(password);
97+
obReaderConfig.setStartTimestamp(0L);
98+
obReaderConfig.setWorkingMode("memory");
99+
100+
ClientConf clientConf =
101+
ClientConf.builder()
102+
.transferQueueSize(1000)
103+
.connectTimeoutMs((int) Duration.ofSeconds(30).toMillis())
104+
.maxReconnectTimes(0)
105+
.ignoreUnknownRecordType(true)
106+
.build();
107+
108+
LogProxyClient client =
109+
new LogProxyClient(
110+
logProxyIP, Integer.parseInt(logProxyPort), obReaderConfig, clientConf);
111+
112+
BlockingQueue<LogMessage> messageQueue = new LinkedBlockingQueue<>(2);
113+
AtomicBoolean started = new AtomicBoolean(false);
114+
CountDownLatch latch = new CountDownLatch(1);
115+
116+
client.addListener(
117+
new RecordListener() {
118+
@Override
119+
public void notify(LogMessage message) {
120+
switch (message.getOpt()) {
121+
case HEARTBEAT:
122+
LOG.info(
123+
"Received heartbeat with checkpoint {}",
124+
message.getCheckpoint());
125+
if (started.compareAndSet(false, true)) {
126+
latch.countDown();
127+
}
128+
break;
129+
case BEGIN:
130+
LOG.info("Received transaction begin: {}", message);
131+
break;
132+
case COMMIT:
133+
LOG.info("Received transaction commit: {}", message);
134+
break;
135+
case INSERT:
136+
case UPDATE:
137+
case DELETE:
138+
case DDL:
139+
try {
140+
messageQueue.put(message);
141+
} catch (InterruptedException e) {
142+
throw new RuntimeException("Failed to add message to queue", e);
143+
}
144+
break;
145+
default:
146+
throw new IllegalArgumentException(
147+
"Unsupported log message type: " + message.getOpt());
148+
}
149+
}
150+
151+
@Override
152+
public void onException(LogProxyClientException e) {
153+
LOG.error(e.toString());
154+
}
155+
});
156+
157+
client.start();
158+
159+
if (!latch.await(30, TimeUnit.SECONDS)) {
160+
Assertions.fail("Timeout to receive heartbeat message");
161+
}
162+
163+
String ddl = "CREATE TABLE t_product (id INT(10) PRIMARY KEY, name VARCHAR(20))";
164+
try (Connection conn = driver.connect("jdbc:mysql://" + observerIP + ":2881/test", props);
165+
Statement statement = conn.createStatement()) {
166+
statement.execute(ddl);
167+
statement.execute("INSERT INTO t_product VALUES (1, 'meat')");
168+
} catch (SQLException e) {
169+
Assertions.fail(e);
170+
}
171+
172+
while (messageQueue.size() < 2) {
173+
Thread.sleep(1000);
174+
}
175+
176+
LogMessage first = messageQueue.take();
177+
Assertions.assertEquals(DataMessage.Record.Type.DDL, first.getOpt());
178+
Assertions.assertEquals(ddl, first.getFieldList().get(0).getValue().toString());
179+
180+
LogMessage second = messageQueue.take();
181+
Assertions.assertEquals(DataMessage.Record.Type.INSERT, second.getOpt());
182+
Assertions.assertEquals("t_product", second.getTableName());
183+
184+
Map<String, String> fieldMap =
185+
second.getFieldList().stream()
186+
.filter(f -> !f.isPrev())
187+
.collect(
188+
Collectors.toMap(
189+
DataMessage.Record.Field::getFieldname,
190+
f -> f.getValue().toString()));
191+
Assertions.assertEquals(2, fieldMap.size());
192+
Assertions.assertEquals("1", fieldMap.get("id"));
193+
Assertions.assertEquals("meat", fieldMap.get("name"));
194+
195+
try (Connection conn = driver.connect("jdbc:mysql://" + observerIP + ":2881/test", props);
196+
Statement statement = conn.createStatement()) {
197+
statement.execute("DROP TABLE t_product");
198+
} catch (SQLException e) {
199+
Assertions.fail(e);
200+
}
201+
202+
client.stop();
203+
}
204+
}

0 commit comments

Comments
 (0)