Skip to content

Commit e528852

Browse files
aparajonsvc-squareup-copybara
authored andcommitted
Update VitessTestDb to support loading the schema directory
from a filesystem path GitOrigin-RevId: 1e6870f5c8ac859624ebe3fc9166926458c1364c
1 parent a17def6 commit e528852

File tree

5 files changed

+53
-32
lines changed

5 files changed

+53
-32
lines changed

misk-vitess/README.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,12 @@ This will start a minified Vitess cluster in a Docker container that will be rea
2525

2626
### Configuration
2727

28-
`VitessTestDb` depends on the existence of a schema directory ( i.e., `schemaDir`),
29-
which contains `.sql` schema change and `vschema.json` files. The expected input format is shown below:
28+
`VitessTestDb` depends on the existence of a schema directory ( i.e., `schemaDir`), which contains `.sql` schema change and `vschema.json` files. The location can be a classpath or filesystem path, which is designated by the prefix `classpath:` or `filesystem:`. When using `classpath:`, `VitessTestDb` looks within `resources`.
29+
30+
The expected input format is shown below:
3031

3132
```
32-
/vitess/schema
33+
/resources/vitess/schema
3334
├── keyspace1
3435
│ ├── v0001__add_table.sql
3536
│ ├── vschema.json
@@ -38,10 +39,16 @@ which contains `.sql` schema change and `vschema.json` files. The expected inpu
3839
│ ├── vschema.json
3940
```
4041

41-
The `schemaDir` option defaults to `vitess/schema`, but can take in any custom resource path to the constructor, e.g.,
42+
`VitessTestDb` will throw exceptions if an invalid directory structure is provided. The default value is `classpath:/vitess/schema`, it but can take in any custom resource path to the constructor, e.g.,
43+
44+
```
45+
testDb = VitessTestDb(schemaDir = "classpath:/prefix/my_schema")
46+
```
47+
48+
To use a filesystem path, the prefix `filesystem:` should be used, e.g.,
4249

4350
```
44-
testDb = VitessTestDb(schemaDir = "prefix/my_schema")
51+
testDb = VitessTestDb(schemaDir = "filesystem:/some_path/some_path2/my_schema")
4552
```
4653

4754
Other configurable parameters include:

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

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
package misk.vitess.testing
22

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
83
import misk.vitess.testing.internal.VitessClusterConfig
94
import misk.vitess.testing.internal.VitessQueryExecutor
105
import misk.vitess.testing.internal.VitessQueryExecutorException
@@ -43,7 +38,6 @@ class CustomArgsTest {
4338
private const val DB2_PORT = 34003
4439

4540
private val executorService = Executors.newFixedThreadPool(2)
46-
private val dockerClient = setupDockerClient()
4741

4842
@JvmStatic
4943
@BeforeAll
@@ -56,6 +50,7 @@ class CustomArgsTest {
5650
port = DB1_PORT,
5751
keepAlive = true,
5852
mysqlVersion = DB1_MYSQL_VERSION,
53+
schemaDir = "filesystem:${Paths.get(System.getProperty("user.dir"), "src/test/resources/vitess/schema")}",
5954
sqlMode = DB1_SQL_MODE,
6055
transactionIsolationLevel = DB1_TXN_ISO_LEVEL,
6156
transactionTimeoutSeconds = Duration.ofSeconds(5),
@@ -77,16 +72,6 @@ class CustomArgsTest {
7772
testDb1QueryExecutor = VitessQueryExecutor(VitessClusterConfig(DB1_PORT))
7873
testDb2QueryExecutor = VitessQueryExecutor(VitessClusterConfig(DB2_PORT))
7974
}
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-
}
9075
}
9176

9277
@Test
@@ -192,6 +177,15 @@ class CustomArgsTest {
192177
assertTablesApplied()
193178
}
194179

180+
@Test
181+
fun `test unsupported schema directory prefix `() {
182+
val exception = assertThrows<VitessTestDbStartupException> { createUnsupportedSchemaDirectoryDb().applySchema() }
183+
assertEquals(
184+
"Schema directory `some/path/without/filesystem/or/classpath` must start with one of the supported prefixes: [classpath:, filesystem:]",
185+
exception.message,
186+
)
187+
}
188+
195189
private fun assertTraditionalSchemaUpdatesApplied(applySchemaResult: ApplySchemaResult) {
196190
// The vschema is always applied for each keyspace.
197191
assertEquals(2, applySchemaResult.vschemaUpdates.size)
@@ -226,4 +220,10 @@ class CustomArgsTest {
226220
port = DB1_PORT,
227221
vitessImage = "vitess/vttestserver:v19.0.9-mysql80")
228222
}
223+
224+
private fun createUnsupportedSchemaDirectoryDb(): VitessTestDb {
225+
return VitessTestDb(
226+
containerName = "unsupported_schema_dir_vitess_db",
227+
schemaDir = "some/path/without/filesystem/or/classpath")
228+
}
229229
}

misk-vitess/src/testFixtures/kotlin/misk/vitess/testing/VitessTestDb.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,12 @@ import kotlin.time.measureTime
1919
* @property keepAlive Whether to keep the database running after the test suite completes. Default is `true`.
2020
* @property mysqlVersion The MySQL version to use. Default is `8.0.36`.
2121
* @property port The port to connect to the database, which represents the vtgate. Default is `27003`.
22-
* @property schemaDir Location of vschema and SQL migration files in resources. The expected input format looks like:
22+
* @property schemaDir The location of vschema and SQL schema change files, which can be a classpath or filesystem path, which
23+
* is designated by the prefix `classpath:` or `filesystem:`. When using `classpath:`, `VitessTestDb` looks within `resources`.
24+
*
25+
* The expected input format of a schema directory looks like:
2326
* ```
24-
* /resources
27+
* /resources/vitess
2528
* ├── schema
2629
* │ ├── keyspace1
2730
* │ │ ├── v0001__add_table.sql
@@ -31,7 +34,7 @@ import kotlin.time.measureTime
3134
* │ │ ├── vschema.json
3235
* ```
3336
*
34-
* In this example, schema would be the expected arg. The default is `vitess/schema`.
37+
* `VitessTestDb` will throw exceptions if an invalid directory structure is provided. The default value is `classpath:/vitess/schema`.
3538
*
3639
* @property sqlMode The server SQL mode. Defaults to the MySQL8 defaults:
3740
* `ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION`.

misk-vitess/src/testFixtures/kotlin/misk/vitess/testing/VitessTestDbSettings.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ object DefaultSettings {
1212
const val LINT_SCHEMA = false
1313
const val MYSQL_VERSION = "8.0.36"
1414
const val PORT = 27003
15-
const val SCHEMA_DIR = "vitess/schema"
15+
const val SCHEMA_DIR = "classpath:/vitess/schema"
1616
const val SQL_MODE: String =
1717
"ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"
1818
@JvmField var TRANSACTION_ISOLATION_LEVEL: TransactionIsolationLevel = TransactionIsolationLevel.REPEATABLE_READ

misk-vitess/src/testFixtures/kotlin/misk/vitess/testing/internal/VitessSchemaManager.kt

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import misk.vitess.testing.DefaultSettings.VTCTLD_CLIENT_IMAGE
2424
import misk.vitess.testing.VSchemaUpdate
2525
import misk.vitess.testing.VitessTestDbStartupException
2626
import wisp.resources.ClasspathResourceLoaderBackend
27+
import wisp.resources.FilesystemLoaderBackend
2728
import wisp.resources.ResourceLoader
2829

2930
/**
@@ -44,8 +45,14 @@ internal class VitessSchemaManager(
4445
val keyspaces: List<VitessKeyspace>
4546

4647
init {
47-
// We may be able to remove the temp schema directory logic if we can parse the schema files directly from
48-
// resources.
48+
val supportedSchemaPrefixes = listOf(ClasspathResourceLoaderBackend.SCHEME, FilesystemLoaderBackend.SCHEME)
49+
val usesSupportedPrefix = supportedSchemaPrefixes.any { schemaDir.startsWith(it) }
50+
if (!usesSupportedPrefix) {
51+
throw VitessTestDbStartupException(
52+
"Schema directory `$schemaDir` must start with one of the supported prefixes: $supportedSchemaPrefixes"
53+
)
54+
}
55+
4956
val tempSchemaDir = createTempSchemaDirectory()
5057

5158
currentSchemaDirPath = tempSchemaDir
@@ -326,16 +333,20 @@ internal class VitessSchemaManager(
326333
private fun createTempSchemaDirectory(): Path {
327334
val tempDir = Files.createTempDirectory("schema-")
328335

329-
val resourceLoader = ResourceLoader(mapOf(ClasspathResourceLoaderBackend.SCHEME to ClasspathResourceLoaderBackend))
336+
val resourceLoader = ResourceLoader(
337+
mapOf(
338+
ClasspathResourceLoaderBackend.SCHEME to ClasspathResourceLoaderBackend,
339+
FilesystemLoaderBackend.SCHEME to FilesystemLoaderBackend
340+
)
341+
)
330342

331343
tempDir.createDirectories()
332344

333-
val resourcePath = "classpath:/$schemaDir"
334-
if (!resourceLoader.exists(resourcePath)) {
335-
throw VitessTestDbStartupException("Schema directory `$schemaDir` does not exist in resources")
345+
if (!resourceLoader.exists(schemaDir)) {
346+
throw VitessTestDbStartupException("Schema directory `$schemaDir` does not exist")
336347
}
337348

338-
resourceLoader.copyTo(resourcePath, tempDir)
349+
resourceLoader.copyTo(schemaDir, tempDir)
339350

340351
return tempDir
341352
}

0 commit comments

Comments
 (0)