test(sql): cover DiskCatalogTest and tempFile
This commit is contained in:
1 parent
910c0761fa
commit
65424efff3
1 file changed
+159
@@ -0,0 +1,159 @@
|
||||
package kestrel.store.sql
|
||||
|
||||
import kestrel.catalog.Column
|
||||
import kestrel.catalog.SequenceDefinition
|
||||
import kestrel.catalog.UniqueConstraint
|
||||
import kestrel.storage.ColumnType
|
||||
import kestrel.storage.Row
|
||||
import kestrel.storage.Value
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertFailsWith
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class DiskCatalogTest {
|
||||
private fun tempFile(prefix: String): File = Files.createTempFile(prefix, ".db").toFile().also { it.deleteOnExit() }
|
||||
|
||||
private val usersColumns = listOf(
|
||||
Column("id", ColumnType.Integer, notNull = true, primaryKey = true),
|
||||
Column("name", ColumnType.Text, notNull = true, primaryKey = false)
|
||||
)
|
||||
|
||||
@Test
|
||||
fun creatingTheSameTableTwiceFails() {
|
||||
val catalog = DiskCatalog.open(tempFile("kestrel-cat-data"), tempFile("kestrel-cat-wal"))
|
||||
catalog.createTable("users", usersColumns)
|
||||
assertFailsWith<DiskCatalogException> { catalog.createTable("users", usersColumns) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun droppedTableIsNoLongerListedOrQueryable() {
|
||||
val catalog = DiskCatalog.open(tempFile("kestrel-cat-data"), tempFile("kestrel-cat-wal"))
|
||||
catalog.createTable("users", usersColumns)
|
||||
catalog.dropTable("users")
|
||||
|
||||
assertTrue(catalog.tableNames.isEmpty())
|
||||
assertFailsWith<DiskCatalogException> { catalog.table("users") }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun reopeningAFreshProcessSeesTablesAndRowsThroughNewObjectsEntirely() {
|
||||
val dataFile = tempFile("kestrel-cat-data")
|
||||
val walFile = tempFile("kestrel-cat-wal")
|
||||
|
||||
val catalog1 = DiskCatalog.open(dataFile, walFile)
|
||||
val table1 = catalog1.createTable("users", usersColumns)
|
||||
val txn1 = catalog1.beginTransaction()
|
||||
table1.insert(txn1, Row(listOf(Value.IntegerValue(1), Value.TextValue("alice"))))
|
||||
table1.insert(txn1, Row(listOf(Value.IntegerValue(2), Value.TextValue("bob"))))
|
||||
catalog1.commit(txn1)
|
||||
catalog1.close()
|
||||
|
||||
val catalog2 = DiskCatalog.open(dataFile, walFile)
|
||||
assertEquals(listOf("users"), catalog2.tableNames)
|
||||
val table2 = catalog2.table("users")
|
||||
val reader = catalog2.beginTransaction()
|
||||
assertEquals(setOf(1L, 2L), table2.scan(reader).map { (it.second.values[0] as Value.IntegerValue).value }.toSet())
|
||||
val (_, aliceRow) = table2.findByPrimaryKey(reader, Value.IntegerValue(1))!!
|
||||
assertEquals("alice", (aliceRow.values[1] as Value.TextValue).value)
|
||||
catalog2.commit(reader)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aCommittedWriteThatNeverFlushedTheBufferPoolSurvivesAReopen() {
|
||||
val dataFile = tempFile("kestrel-cat-data")
|
||||
val walFile = tempFile("kestrel-cat-wal")
|
||||
|
||||
val catalog1 = DiskCatalog.open(dataFile, walFile)
|
||||
val table1 = catalog1.createTable("users", usersColumns)
|
||||
val txn = catalog1.beginTransaction()
|
||||
table1.insert(txn, Row(listOf(Value.IntegerValue(1), Value.TextValue("alice"))))
|
||||
catalog1.commit(txn)
|
||||
// No catalog1.close(): the dirty pages may still only live in the buffer pool.
|
||||
|
||||
val catalog2 = DiskCatalog.open(dataFile, walFile)
|
||||
val table2 = catalog2.table("users")
|
||||
val reader = catalog2.beginTransaction()
|
||||
assertEquals("alice", table2.findByPrimaryKey(reader, Value.IntegerValue(1))!!.second.values[1].let { (it as Value.TextValue).value })
|
||||
catalog2.commit(reader)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aPrimaryKeyIndexThatSplitsSurvivesAReopenWithTheCorrectRoot() {
|
||||
val dataFile = tempFile("kestrel-cat-data")
|
||||
val walFile = tempFile("kestrel-cat-wal")
|
||||
|
||||
val catalog1 = DiskCatalog.open(dataFile, walFile)
|
||||
val table1 = catalog1.createTable("users", usersColumns)
|
||||
val txn = catalog1.beginTransaction()
|
||||
for (id in 1..300L) table1.insert(txn, Row(listOf(Value.IntegerValue(id), Value.TextValue("user$id"))))
|
||||
catalog1.commit(txn)
|
||||
catalog1.close()
|
||||
|
||||
val catalog2 = DiskCatalog.open(dataFile, walFile)
|
||||
val table2 = catalog2.table("users")
|
||||
val reader = catalog2.beginTransaction()
|
||||
assertEquals(300, table2.scan(reader).size)
|
||||
for (id in listOf(1L, 150L, 300L)) {
|
||||
assertEquals("user$id", table2.findByPrimaryKey(reader, Value.IntegerValue(id))!!.second.values[1].let { (it as Value.TextValue).value })
|
||||
}
|
||||
val range = table2.rangeByPrimaryKey(reader, Value.IntegerValue(100), true, Value.IntegerValue(105), true)
|
||||
assertEquals((100..105L).toList(), range.map { (it.second.values[0] as Value.IntegerValue).value })
|
||||
catalog2.commit(reader)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aSecondaryIndexCreatedBeforeCloseSurvivesAReopen() {
|
||||
val dataFile = tempFile("kestrel-cat-data")
|
||||
val walFile = tempFile("kestrel-cat-wal")
|
||||
val columns = usersColumns + Column("dept", ColumnType.Text, notNull = false, primaryKey = false)
|
||||
|
||||
val catalog1 = DiskCatalog.open(dataFile, walFile)
|
||||
val table1 = catalog1.createTable("users", columns)
|
||||
catalog1.createIndex("users", "idx_dept", "dept")
|
||||
val txn = catalog1.beginTransaction()
|
||||
table1.insert(txn, Row(listOf(Value.IntegerValue(1), Value.TextValue("alice"), Value.TextValue("eng"))))
|
||||
table1.insert(txn, Row(listOf(Value.IntegerValue(2), Value.TextValue("bob"), Value.TextValue("eng"))))
|
||||
catalog1.commit(txn)
|
||||
catalog1.close()
|
||||
|
||||
val catalog2 = DiskCatalog.open(dataFile, walFile)
|
||||
val table2 = catalog2.table("users")
|
||||
val reader = catalog2.beginTransaction()
|
||||
val engineers = table2.findBySecondary(reader, "idx_dept", Value.TextValue("eng"))
|
||||
assertEquals(setOf("alice", "bob"), engineers.map { (it.second.values[1] as Value.TextValue).value }.toSet())
|
||||
catalog2.commit(reader)
|
||||
}
|
||||
|
||||
private val orderLineColumns = listOf(
|
||||
Column("order_id", ColumnType.Integer, notNull = true, primaryKey = false),
|
||||
Column("line_no", ColumnType.Integer, notNull = true, primaryKey = false),
|
||||
Column("sku", ColumnType.Text, notNull = false, primaryKey = false)
|
||||
)
|
||||
|
||||
@Test
|
||||
fun aTableCannotDeclareBothAnInlinePrimaryKeyColumnAndACompositePrimaryKey() {
|
||||
val catalog = DiskCatalog.open(tempFile("kestrel-cat-data"), tempFile("kestrel-cat-wal"))
|
||||
assertFailsWith<DiskCatalogException> {
|
||||
catalog.createTable("users", usersColumns, compositePrimaryKey = listOf("name"))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aCompositePrimaryKeyReferencingAnUnknownColumnIsRejected() {
|
||||
val catalog = DiskCatalog.open(tempFile("kestrel-cat-data"), tempFile("kestrel-cat-wal"))
|
||||
assertFailsWith<DiskCatalogException> {
|
||||
catalog.createTable("order_lines", orderLineColumns, compositePrimaryKey = listOf("order_id", "missing"))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aCompositePrimaryKeyListingTheSameColumnTwiceIsRejected() {
|
||||
val catalog = DiskCatalog.open(tempFile("kestrel-cat-data"), tempFile("kestrel-cat-wal"))
|
||||
assertFailsWith<DiskCatalogException> {
|
||||
catalog.createTable("order_lines", orderLineColumns, compositePrimaryKey = listOf("order_id", "order_id"))
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user