Skip to content

Commit 4da16a5

Browse files
aparajonsvc-squareup-copybara
authored andcommitted
Speed up VitessTestDb tests and simplify the test architecture
GitOrigin-RevId: f2509cda9ed1ee4c3251803bdea9c93aa484f2eb
1 parent dbaa26b commit 4da16a5

12 files changed

+333
-665
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
package misk.vitess.testing
2+
3+
import com.github.dockerjava.api.DockerClient
4+
import com.github.dockerjava.core.DefaultDockerClientConfig
5+
import com.github.dockerjava.core.DockerClientBuilder
6+
import com.github.dockerjava.httpclient5.ApacheDockerHttpClient
7+
import misk.docker.withMiskDefaults
8+
import misk.vitess.testing.internal.VitessClusterConfig
9+
import misk.vitess.testing.internal.VitessQueryExecutor
10+
import misk.vitess.testing.internal.VitessQueryExecutorException
11+
import org.junit.jupiter.api.Assertions.assertArrayEquals
12+
import org.junit.jupiter.api.Assertions.assertEquals
13+
import org.junit.jupiter.api.Assertions.assertFalse
14+
import org.junit.jupiter.api.Assertions.assertTrue
15+
import org.junit.jupiter.api.BeforeAll
16+
import org.junit.jupiter.api.Test
17+
import org.junit.jupiter.api.assertThrows
18+
import java.nio.file.Files
19+
import java.nio.file.Paths
20+
import java.time.Duration
21+
import java.util.concurrent.Executors
22+
import java.util.concurrent.Future
23+
import kotlin.io.path.pathString
24+
25+
class CustomArgsTest {
26+
companion object {
27+
private lateinit var testDb1: VitessTestDb
28+
private lateinit var testDb2: VitessTestDb
29+
private lateinit var testDb1RunResult: VitessTestDbStartupResult
30+
private lateinit var testDb2RunResult: VitessTestDbStartupResult
31+
private lateinit var testDb1QueryExecutor: VitessQueryExecutor
32+
private lateinit var testDb2QueryExecutor: VitessQueryExecutor
33+
34+
// testDb1 args
35+
private const val DB1_CONTAINER_NAME = "custom_args_test_vitess_db"
36+
private const val DB1_PORT = 33003
37+
private const val DB1_MYSQL_VERSION = "8.0.42"
38+
private const val DB1_SQL_MODE = "ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"
39+
private val DB1_TXN_ISO_LEVEL = TransactionIsolationLevel.READ_COMMITTED
40+
41+
// testDb2 args
42+
private const val DB2_CONTAINER_NAME = "custom_args2_test_vitess_db"
43+
private const val DB2_PORT = 34003
44+
45+
private val executorService = Executors.newFixedThreadPool(2)
46+
private val dockerClient = setupDockerClient()
47+
48+
@JvmStatic
49+
@BeforeAll
50+
fun setup() {
51+
testDb1 = VitessTestDb(
52+
autoApplySchemaChanges = true,
53+
containerName = DB1_CONTAINER_NAME,
54+
enableScatters = false,
55+
enableDeclarativeSchemaChanges = true,
56+
port = DB1_PORT,
57+
keepAlive = true,
58+
mysqlVersion = DB1_MYSQL_VERSION,
59+
sqlMode = DB1_SQL_MODE,
60+
transactionIsolationLevel = DB1_TXN_ISO_LEVEL,
61+
transactionTimeoutSeconds = Duration.ofSeconds(5),
62+
vitessImage = "vitess/vttestserver:v20.0.6-mysql80",
63+
vitessVersion = 20)
64+
65+
testDb2 = VitessTestDb(
66+
autoApplySchemaChanges = false,
67+
containerName = DB2_CONTAINER_NAME,
68+
port = DB2_PORT,
69+
keepAlive = false)
70+
71+
// Containers should be able to be run in parallel
72+
val future1: Future<VitessTestDbStartupResult> = executorService.submit<VitessTestDbStartupResult> { testDb1.run() }
73+
val future2: Future<VitessTestDbStartupResult> = executorService.submit<VitessTestDbStartupResult> { testDb2.run() }
74+
testDb1RunResult = future1.get()
75+
testDb2RunResult = future2.get()
76+
77+
testDb1QueryExecutor = VitessQueryExecutor(VitessClusterConfig(DB1_PORT))
78+
testDb2QueryExecutor = VitessQueryExecutor(VitessClusterConfig(DB2_PORT))
79+
}
80+
81+
private fun setupDockerClient(): DockerClient {
82+
val dockerClientConfig =
83+
DefaultDockerClientConfig.createDefaultConfigBuilder().withMiskDefaults().build()
84+
return DockerClientBuilder.getInstance(dockerClientConfig)
85+
.withDockerHttpClient(
86+
ApacheDockerHttpClient.Builder().dockerHost(dockerClientConfig.dockerHost).build()
87+
)
88+
.build()
89+
}
90+
}
91+
92+
@Test
93+
fun `test user defined MySql version`() {
94+
val results = testDb1QueryExecutor.executeQuery("SELECT @@global.version;")
95+
val actualMysqlVersion = results[0]["@@global.version"]
96+
assertEquals("$DB1_MYSQL_VERSION-Vitess", actualMysqlVersion)
97+
}
98+
99+
@Test
100+
fun `test user defined SQL mode`() {
101+
val results = testDb1QueryExecutor.executeQuery("SELECT @@global.sql_mode;")
102+
val actualSqlMode = results[0]["@@global.sql_mode"]
103+
assertEquals(DB1_SQL_MODE, actualSqlMode)
104+
}
105+
106+
@Test
107+
fun `test user defined transaction isolation level`() {
108+
val results = testDb1QueryExecutor.executeQuery("SELECT @@global.transaction_ISOLATION;")
109+
val actualTransactionIsolationLevel = results[0]["@@global.transaction_ISOLATION"]
110+
assertEquals(DB1_TXN_ISO_LEVEL.value, actualTransactionIsolationLevel)
111+
}
112+
113+
@Test
114+
fun `test scatter queries fail`() {
115+
val scatterQuery = "SELECT * FROM customers;"
116+
val exception = assertThrows<VitessQueryExecutorException> { testDb1QueryExecutor.executeQuery(scatterQuery) }
117+
118+
assertTrue(exception.cause?.message!!.contains("plan includes scatter, which is disallowed"))
119+
}
120+
121+
@Test
122+
fun `test transaction timeout`() {
123+
val exception = assertThrows<VitessQueryExecutorException> { testDb1QueryExecutor.executeTransaction("SELECT SLEEP(6);") }
124+
val actualMessage = exception.cause?.message!!
125+
val expectedMessageSubstring = "maximum statement execution time exceeded"
126+
assertTrue(
127+
actualMessage.contains(expectedMessageSubstring),
128+
"Expected message to contain \"$expectedMessageSubstring\" but was \"$actualMessage\"",
129+
)
130+
}
131+
132+
@Test
133+
fun `test disabling scatters fails on an unsupported version`() {
134+
val exception = assertThrows<RuntimeException> { createUnsupportedNoScatterDb().run() }
135+
assertEquals(
136+
"Vitess image version must be >= 20 when scatters are disabled, found 19.",
137+
exception.message,
138+
)
139+
}
140+
141+
@Test
142+
fun `test declarative schema changes are auto applied`() {
143+
val vitessQueryExecutor = VitessQueryExecutor(VitessClusterConfig(DB1_PORT))
144+
val keyspaces = vitessQueryExecutor.getKeyspaces()
145+
assertArrayEquals(arrayOf("gameworld", "gameworld_sharded"), keyspaces.toTypedArray())
146+
147+
val unshardedTables = vitessQueryExecutor.getTables("gameworld").map { it.tableName }
148+
assertArrayEquals(arrayOf("customers_seq", "games_seq"), unshardedTables.toTypedArray())
149+
150+
val shardedTables = vitessQueryExecutor.getTables("gameworld_sharded").map { it.tableName }
151+
assertArrayEquals(arrayOf("customers", "games"), shardedTables.toTypedArray())
152+
}
153+
154+
@Test
155+
fun `test applySchema after run with keepAlive = false`() {
156+
val vitessQueryExecutor = VitessQueryExecutor(VitessClusterConfig(DB2_PORT))
157+
// Keyspaces are still applied even if autoApplySchemaChanges is false.
158+
var keyspaces = vitessQueryExecutor.getKeyspaces()
159+
assertArrayEquals(arrayOf("gameworld", "gameworld_sharded"), keyspaces.toTypedArray())
160+
161+
// However tables should not yet be applied.
162+
assertTablesNotApplied()
163+
164+
// Truncating should work without needing to create a temporary schema.
165+
testDb2.truncate()
166+
167+
var schemaDirPath = Paths.get("/tmp/vitess-test-db/${testDb2RunResult.containerId}/schema")
168+
assertFalse(Files.exists(schemaDirPath), "Schema directory ${schemaDirPath.pathString} should not exist")
169+
170+
var applySchemaResult = testDb2.applySchema()
171+
// Now /tmp/{container_id}/schema should exist.
172+
assertTrue(Files.exists(schemaDirPath), "Schema directory ${schemaDirPath.pathString} should exist")
173+
174+
assertTraditionalSchemaUpdatesApplied(applySchemaResult)
175+
assertTablesApplied()
176+
177+
// Now reinitialize testDb2, with enableDeclarativeSchemaChanges set.
178+
testDb2 = VitessTestDb(
179+
autoApplySchemaChanges = false,
180+
containerName = DB2_CONTAINER_NAME,
181+
enableDeclarativeSchemaChanges = true,
182+
port = DB2_PORT,
183+
keepAlive = false)
184+
185+
// This will start a new container since keepAlive is set to false.
186+
testDb2.run()
187+
188+
// Now validate declarative schema changes are applied.
189+
assertTablesNotApplied()
190+
applySchemaResult = testDb2.applySchema()
191+
assertDeclarativeSchemaUpdatesApplied(applySchemaResult)
192+
assertTablesApplied()
193+
}
194+
195+
private fun assertTraditionalSchemaUpdatesApplied(applySchemaResult: ApplySchemaResult) {
196+
// The vschema is always applied for each keyspace.
197+
assertEquals(2, applySchemaResult.vschemaUpdates.size)
198+
// In traditional schema changes, the DDL's are processed as is per .sql file.
199+
assertEquals(4, applySchemaResult.ddlUpdates.size)
200+
}
201+
202+
private fun assertDeclarativeSchemaUpdatesApplied(applySchemaResult: ApplySchemaResult) {
203+
// The vschema is always applied for each keyspace.
204+
assertEquals(2, applySchemaResult.vschemaUpdates.size)
205+
// In declarative schema changes, the DDL's get consolidated as one diff per keyspace.
206+
assertEquals(2, applySchemaResult.ddlUpdates.size)
207+
}
208+
209+
private fun assertTablesNotApplied() {
210+
assertEquals(testDb2QueryExecutor.getTables("gameworld").size, 0)
211+
assertEquals(testDb2QueryExecutor.getTables("gameworld_sharded").size, 0)
212+
}
213+
214+
private fun assertTablesApplied() {
215+
val unshardedTables = testDb2QueryExecutor.getTables("gameworld").map { it.tableName }
216+
assertArrayEquals(arrayOf("customers_seq", "games_seq"), unshardedTables.toTypedArray())
217+
218+
val shardedTables = testDb2QueryExecutor.getTables("gameworld_sharded").map { it.tableName }
219+
assertArrayEquals(arrayOf("customers", "games"), shardedTables.toTypedArray())
220+
}
221+
222+
private fun createUnsupportedNoScatterDb(): VitessTestDb {
223+
return VitessTestDb(
224+
containerName = "unsupported_scatter_vitess_db",
225+
enableScatters = false,
226+
port = DB1_PORT,
227+
vitessImage = "vitess/vttestserver:v19.0.9-mysql80")
228+
}
229+
}

misk-vitess/src/test/kotlin/misk/vitess/testing/VitessTestDbKeepAliveTest.kt

-50
This file was deleted.

misk-vitess/src/test/kotlin/misk/vitess/testing/VitessTestDbMultipleContainerTest.kt

-61
This file was deleted.

0 commit comments

Comments
 (0)