Skip to content

Commit 808b1fc

Browse files
committed
Added tests for TableTxExecutor
1 parent b977127 commit 808b1fc

File tree

2 files changed

+161
-5
lines changed

2 files changed

+161
-5
lines changed

jdbc/src/main/java/tech/ydb/jdbc/context/TableTxExecutor.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,21 +89,22 @@ protected void commitImpl(YdbContext ctx, YdbValidator validator, QueryTransacti
8989
return;
9090
}
9191

92-
YdbTracer tracer = ctx.getTracer();
9392
String hash = Hashing.sha256().hashBytes(tx.getId().getBytes()).toString();
94-
tracer.trace("--> commit-and-store-tx " + hash);
95-
tracer.query(commitQuery);
96-
9793
Params params = Params.of(
9894
"$hash", PrimitiveValue.newText(hash),
9995
"$tx", PrimitiveValue.newText(tx.getId())
10096
);
10197

98+
YdbTracer tracer = ctx.getTracer();
10299
ExecuteQuerySettings settings = ctx.withRequestTimeout(ExecuteQuerySettings.newBuilder()).build();
103100
try {
104101
QueryStream query = tx.createQuery(commitQuery, true, params, settings);
105102
validator.clearWarnings();
106-
validator.call("CommitAndStore TxId: " + tx.getId(), tracer, query::execute);
103+
validator.call("CommitAndStore TxId: " + tx.getId(), tracer, () -> {
104+
tracer.trace("--> commit-and-store-tx " + hash);
105+
tracer.query(commitQuery);
106+
return query.execute();
107+
});
107108
} catch (YdbConditionallyRetryableException ex) {
108109

109110
try (Session session = createNewTableSession(validator)) {
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
package tech.ydb.jdbc;
2+
3+
import java.sql.Connection;
4+
import java.sql.DriverManager;
5+
import java.sql.ResultSet;
6+
import java.sql.SQLException;
7+
import java.sql.Statement;
8+
9+
import org.junit.Assert;
10+
import org.junit.jupiter.api.Assertions;
11+
import org.junit.jupiter.api.Test;
12+
import org.junit.jupiter.api.extension.RegisterExtension;
13+
14+
import tech.ydb.core.Status;
15+
import tech.ydb.core.StatusCode;
16+
import tech.ydb.core.UnexpectedResultException;
17+
import tech.ydb.jdbc.impl.YdbTracerImpl;
18+
import tech.ydb.jdbc.impl.helper.ExceptionAssert;
19+
import tech.ydb.jdbc.impl.helper.JdbcConnectionExtention;
20+
import tech.ydb.jdbc.impl.helper.JdbcUrlHelper;
21+
import tech.ydb.test.junit5.YdbHelperExtension;
22+
23+
/**
24+
*
25+
* @author Aleksandr Gorshenin
26+
*/
27+
public class YdbDriverTxValidateTest {
28+
29+
@RegisterExtension
30+
private static final YdbHelperExtension ydb = new YdbHelperExtension();
31+
32+
@RegisterExtension
33+
private static final JdbcConnectionExtention jdbc = new JdbcConnectionExtention(ydb)
34+
.withArg("usePrefixPath", "tx_validated");
35+
36+
private static final JdbcUrlHelper jdbcURL = new JdbcUrlHelper(ydb)
37+
.withArg("enableTxTracer", "true")
38+
.withArg("usePrefixPath", "tx_validated");
39+
40+
private void assertTxCount(String tableName, long count) throws SQLException {
41+
try (Statement st = jdbc.connection().createStatement()) {
42+
try (ResultSet rs = st.executeQuery("select count(*) from " + tableName)) {
43+
Assertions.assertTrue(rs.next());
44+
Assertions.assertEquals(count, rs.getLong(1));
45+
Assertions.assertFalse(rs.next());
46+
}
47+
}
48+
}
49+
50+
@Test
51+
public void basicUsageTest() throws SQLException {
52+
String url = jdbcURL.withArg("withTxValidationTable", "tx_store").build();
53+
try (Connection conn = DriverManager.getConnection(url)) {
54+
// table was created automatically
55+
assertTxCount("tx_store", 0);
56+
57+
// statements with auto commit won't be validated
58+
try (Statement st = conn.createStatement()) {
59+
Assertions.assertTrue(st.execute("SELECT * FROM tx_store"));
60+
Assertions.assertFalse(st.execute("DELETE FROM tx_store"));
61+
}
62+
63+
assertTxCount("tx_store", 0);
64+
65+
conn.setAutoCommit(false);
66+
67+
// scheme statements and read won't be validated
68+
Assertions.assertFalse(conn.createStatement()
69+
.execute("CREATE TABLE tmp (id Int32, vv UInt64, PRIMARY KEY(id))"));
70+
conn.commit();
71+
assertTxCount("tx_store", 0);
72+
73+
// read tx wont' be validated
74+
Assertions.assertTrue(conn.createStatement().execute("SELECT * FROM tmp;"));
75+
conn.commit();
76+
assertTxCount("tx_store", 0);
77+
78+
// rollbacked tx wont' be validated
79+
Assertions.assertFalse(conn.createStatement().execute("INSERT INTO tmp(id, vv) VALUES (1, 1);"));
80+
conn.rollback();
81+
assertTxCount("tx_store", 0);
82+
83+
Assertions.assertFalse(conn.createStatement().execute("INSERT INTO tmp(id, vv) VALUES (1, 1);"));
84+
conn.commit();
85+
assertTxCount("tx_store", 1);
86+
}
87+
88+
try (Connection conn = DriverManager.getConnection(url)) {
89+
conn.createStatement().execute("DROP TABLE tmp");
90+
// reuse current table
91+
assertTxCount("tx_store", 1);
92+
} finally {
93+
jdbc.connection().createStatement().execute("DROP TABLE tx_store");
94+
}
95+
}
96+
97+
@Test
98+
public void commitedTxTest() throws SQLException {
99+
String url = jdbcURL.withArg("withTxValidationTable", "tx1_store").build();
100+
try (Connection conn = DriverManager.getConnection(url)) {
101+
ErrorTxTracer tracer = YdbTracerImpl.use(new ErrorTxTracer());
102+
// table was created automatically
103+
assertTxCount("tx1_store", 0);
104+
105+
conn.setAutoCommit(false);
106+
107+
conn.createStatement().execute("DELETE FROM tx1_store");
108+
// throw condintionally retryable exception AFTER commit
109+
tracer.throwErrorOn("<-- Status", Status.of(StatusCode.UNDETERMINED));
110+
conn.commit(); // no error, tx is validated successfully
111+
112+
assertTxCount("tx1_store", 1);
113+
114+
conn.createStatement().execute("DELETE FROM tx1_store");
115+
// throw condintionally retryable exception BEFORE commit
116+
tracer.throwErrorOn("--> commit-and-store-tx", Status.of(StatusCode.UNDETERMINED));
117+
ExceptionAssert.sqlRecoverable("Transaction wasn't committed", conn::commit);
118+
119+
Assert.assertNull(tracer.error);
120+
} finally {
121+
jdbc.connection().createStatement().execute("DROP TABLE tx1_store");
122+
}
123+
}
124+
125+
@Test
126+
public void invalididTxTableTest() throws SQLException {
127+
String url = jdbcURL.withArg("withTxValidationTable", "tx store").build();
128+
ExceptionAssert.ydbException(
129+
"Cannot initialize TableTxExecutor with tx table " + ydb.database() + "/tx_validated/tx store",
130+
() -> DriverManager.getConnection(url)
131+
);
132+
}
133+
134+
private class ErrorTxTracer extends YdbTracerImpl {
135+
private String traceMsg = null;
136+
private Status error = null;
137+
138+
public void throwErrorOn(String traceMsg, Status error) {
139+
this.traceMsg = traceMsg;
140+
this.error = error;
141+
}
142+
143+
@Override
144+
public void trace(String message) {
145+
super.trace(message);
146+
System.out.println("TRACE " + message);
147+
if (traceMsg != null && error != null && message.startsWith(traceMsg)) {
148+
Status status = error;
149+
error = null;
150+
traceMsg = null;
151+
throw new UnexpectedResultException("Test error", status);
152+
}
153+
}
154+
}
155+
}

0 commit comments

Comments
 (0)