test(wal): cover WriteAheadLogTest and tempFile
This commit is contained in:
1 parent
6db05fc798
commit
e475c44e83
1 file changed
+128
@@ -0,0 +1,128 @@
|
|||||||
|
package kestrel.store.wal
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
import java.io.RandomAccessFile
|
||||||
|
import java.nio.file.Files
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertFailsWith
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
class WriteAheadLogTest {
|
||||||
|
private fun tempFile(): File = Files.createTempFile("kestrel-wal", ".log").toFile().also { it.deleteOnExit() }
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun beginAssignsIncreasingTransactionIds() {
|
||||||
|
val wal = WriteAheadLog(tempFile())
|
||||||
|
val a = wal.beginTransaction()
|
||||||
|
val b = wal.beginTransaction()
|
||||||
|
assertTrue(b > a)
|
||||||
|
wal.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun logUpdateChainsPrevLsnToTheTransactionsPriorRecord() {
|
||||||
|
val wal = WriteAheadLog(tempFile())
|
||||||
|
val txn = wal.beginTransaction()
|
||||||
|
val beginLsn = wal.lastLsnOf(txn)
|
||||||
|
val firstUpdateLsn = wal.logUpdate(txn, 0L, ByteArray(1), ByteArray(1))
|
||||||
|
val secondUpdateLsn = wal.logUpdate(txn, 0L, ByteArray(1), ByteArray(1))
|
||||||
|
|
||||||
|
val firstRecord = wal.readAt(firstUpdateLsn) as LogRecord.Update
|
||||||
|
val secondRecord = wal.readAt(secondUpdateLsn) as LogRecord.Update
|
||||||
|
assertEquals(beginLsn, firstRecord.prevLsn)
|
||||||
|
assertEquals(firstUpdateLsn, secondRecord.prevLsn)
|
||||||
|
wal.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun commitClearsActiveTrackingForTheTransaction() {
|
||||||
|
val wal = WriteAheadLog(tempFile())
|
||||||
|
val txn = wal.beginTransaction()
|
||||||
|
wal.commit(txn)
|
||||||
|
assertEquals(WriteAheadLog.NO_LSN, wal.lastLsnOf(txn))
|
||||||
|
wal.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun loggingUpdateForUnknownTransactionFails() {
|
||||||
|
val wal = WriteAheadLog(tempFile())
|
||||||
|
assertFailsWith<WalException> { wal.logUpdate(999L, 0L, ByteArray(1), ByteArray(1)) }
|
||||||
|
wal.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun checkpointRejectsActiveTransactions() {
|
||||||
|
val wal = WriteAheadLog(tempFile())
|
||||||
|
wal.beginTransaction()
|
||||||
|
assertFailsWith<IllegalStateException> { wal.checkpoint() }
|
||||||
|
wal.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun checkpointIsRecordedAsLastCheckpointLsn() {
|
||||||
|
val wal = WriteAheadLog(tempFile())
|
||||||
|
val txn = wal.beginTransaction()
|
||||||
|
wal.commit(txn)
|
||||||
|
val checkpointLsn = wal.checkpoint()
|
||||||
|
assertEquals(checkpointLsn, wal.lastCheckpointLsn)
|
||||||
|
wal.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun readFromReturnsRecordsInLogOrder() {
|
||||||
|
val wal = WriteAheadLog(tempFile())
|
||||||
|
val txn = wal.beginTransaction()
|
||||||
|
wal.logUpdate(txn, 1L, ByteArray(1), ByteArray(1))
|
||||||
|
wal.commit(txn)
|
||||||
|
val records = wal.readFrom(0L).map { it.second }
|
||||||
|
assertTrue(records[0] is LogRecord.Begin)
|
||||||
|
assertTrue(records[1] is LogRecord.Update)
|
||||||
|
assertTrue(records[2] is LogRecord.Commit)
|
||||||
|
wal.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun reopeningResumesTransactionIdsPastThoseAlreadyLogged() {
|
||||||
|
val file = tempFile()
|
||||||
|
val first = WriteAheadLog(file)
|
||||||
|
val txn = first.beginTransaction()
|
||||||
|
first.commit(txn)
|
||||||
|
first.close()
|
||||||
|
|
||||||
|
val reopened = WriteAheadLog(file)
|
||||||
|
val nextTxn = reopened.beginTransaction()
|
||||||
|
assertTrue(nextTxn > txn)
|
||||||
|
reopened.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun reopeningRecoversLastCheckpointLsn() {
|
||||||
|
val file = tempFile()
|
||||||
|
val first = WriteAheadLog(file)
|
||||||
|
val txn = first.beginTransaction()
|
||||||
|
first.commit(txn)
|
||||||
|
val checkpointLsn = first.checkpoint()
|
||||||
|
first.close()
|
||||||
|
|
||||||
|
val reopened = WriteAheadLog(file)
|
||||||
|
assertEquals(checkpointLsn, reopened.lastCheckpointLsn)
|
||||||
|
reopened.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun corruptedFrameFailsChecksumValidation() {
|
||||||
|
val file = tempFile()
|
||||||
|
val wal = WriteAheadLog(file)
|
||||||
|
val txn = wal.beginTransaction()
|
||||||
|
wal.commit(txn)
|
||||||
|
wal.close()
|
||||||
|
|
||||||
|
RandomAccessFile(file, "rw").use { raf ->
|
||||||
|
raf.seek(10)
|
||||||
|
raf.write(0xFF)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertFailsWith<WalCorruptionException> { WriteAheadLog(file) }
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user