WIP on execution / SQLite integration tests
This commit is contained in:
@@ -1,43 +1,103 @@
|
||||
package solutions.bitbadger.documents
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import solutions.bitbadger.documents.query.Definition
|
||||
import solutions.bitbadger.documents.query.Count
|
||||
import solutions.bitbadger.documents.query.Find
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertNull
|
||||
|
||||
|
||||
/**
|
||||
* SQLite integration tests for the `Custom` object / `custom*` connection extension functions
|
||||
*/
|
||||
@DisplayName("SQLite - Custom")
|
||||
class CustomSQLiteIT {
|
||||
|
||||
private val tbl = "test_table";
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
Configuration.connectionString = "jdbc:sqlite:memory"
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the dialect
|
||||
*/
|
||||
@AfterEach
|
||||
fun cleanUp() {
|
||||
Configuration.dialectValue = null
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("list succeeds with empty list")
|
||||
fun listEmpty() {
|
||||
Configuration.dbConn().use { conn ->
|
||||
conn.customNonQuery(Definition.ensureTable(tbl), listOf())
|
||||
conn.customNonQuery(Definition.ensureKey(tbl, Dialect.SQLITE), listOf())
|
||||
val result = conn.customList<TestDocument>(Find.all(tbl), listOf(), Results::fromData)
|
||||
fun listEmpty() =
|
||||
SQLiteDB().use { db ->
|
||||
JsonDocument.load(db.conn, SQLiteDB.tableName)
|
||||
db.conn.customNonQuery("DELETE FROM ${SQLiteDB.tableName}")
|
||||
val result = db.conn.customList<JsonDocument>(Find.all(SQLiteDB.tableName), mapFunc = Results::fromData)
|
||||
assertEquals(0, result.size, "There should have been no results")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class TestDocument(val id: String)
|
||||
@Test
|
||||
@DisplayName("list succeeds with a non-empty list")
|
||||
fun listAll() =
|
||||
SQLiteDB().use { db ->
|
||||
JsonDocument.load(db.conn, SQLiteDB.tableName)
|
||||
val result = db.conn.customList<JsonDocument>(Find.all(SQLiteDB.tableName), mapFunc = Results::fromData)
|
||||
assertEquals(5, result.size, "There should have been 5 results")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("single succeeds when document not found")
|
||||
fun singleNone() =
|
||||
SQLiteDB().use { db ->
|
||||
assertNull(
|
||||
db.conn.customSingle(Find.all(SQLiteDB.tableName), mapFunc = Results::fromData),
|
||||
"There should not have been a document returned"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("single succeeds when a document is found")
|
||||
fun singleOne() {
|
||||
SQLiteDB().use { db ->
|
||||
JsonDocument.load(db.conn, SQLiteDB.tableName)
|
||||
assertNotNull(
|
||||
db.conn.customSingle<JsonDocument>(Find.all(SQLiteDB.tableName), mapFunc = Results::fromData),
|
||||
"There should not have been a document returned"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("nonQuery makes changes")
|
||||
fun nonQueryChanges() =
|
||||
SQLiteDB().use { db ->
|
||||
JsonDocument.load(db.conn, SQLiteDB.tableName)
|
||||
assertEquals(
|
||||
5L, db.conn.customScalar(Count.all(SQLiteDB.tableName), mapFunc = Results::toCount),
|
||||
"There should have been 5 documents in the table"
|
||||
)
|
||||
db.conn.customNonQuery("DELETE FROM ${SQLiteDB.tableName}")
|
||||
assertEquals(
|
||||
0L, db.conn.customScalar(Count.all(SQLiteDB.tableName), mapFunc = Results::toCount),
|
||||
"There should have been no documents in the table"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("nonQuery makes no changes when where clause matches nothing")
|
||||
fun nonQueryNoChanges() =
|
||||
SQLiteDB().use { db ->
|
||||
JsonDocument.load(db.conn, SQLiteDB.tableName)
|
||||
assertEquals(
|
||||
5L, db.conn.customScalar(Count.all(SQLiteDB.tableName), mapFunc = Results::toCount),
|
||||
"There should have been 5 documents in the table"
|
||||
)
|
||||
db.conn.customNonQuery(
|
||||
"DELETE FROM ${SQLiteDB.tableName} WHERE data->>'id' = :id",
|
||||
listOf(Parameter(":id", ParameterType.STRING, "eighty-two"))
|
||||
)
|
||||
assertEquals(
|
||||
5L, db.conn.customScalar(Count.all(SQLiteDB.tableName), mapFunc = Results::toCount),
|
||||
"There should still have been 5 documents in the table"
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("scalar succeeds")
|
||||
fun scalar() =
|
||||
SQLiteDB().use { db ->
|
||||
assertEquals(
|
||||
3L,
|
||||
db.conn.customScalar("SELECT 3 AS it FROM ${SQLiteDB.catalog} LIMIT 1", mapFunc = Results::toCount),
|
||||
"The number 3 should have been returned"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
45
src/integration-test/kotlin/DefinitionSQLiteIT.kt
Normal file
45
src/integration-test/kotlin/DefinitionSQLiteIT.kt
Normal file
@@ -0,0 +1,45 @@
|
||||
package solutions.bitbadger.documents
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import java.sql.Connection
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
/**
|
||||
* SQLite integration tests for the `Definition` object / `ensure*` connection extension functions
|
||||
*/
|
||||
@DisplayName("SQLite - Definition")
|
||||
class DefinitionSQLiteIT {
|
||||
|
||||
/**
|
||||
* Determine if a database item exists
|
||||
*
|
||||
* @param item The items whose existence should be checked
|
||||
* @param conn The current database connection
|
||||
* @return True if the item exists in the given database, false if not
|
||||
*/
|
||||
private fun itExists(item: String, conn: Connection) =
|
||||
conn.customScalar("SELECT EXISTS (SELECT 1 FROM ${SQLiteDB.catalog} WHERE name = :name) AS it",
|
||||
listOf(Parameter(":name", ParameterType.STRING, item)), Results::toExists)
|
||||
|
||||
@Test
|
||||
@DisplayName("ensureTable creates table and index")
|
||||
fun ensureTable() =
|
||||
SQLiteDB().use { db ->
|
||||
assertFalse(itExists("ensured", db.conn), "The 'ensured' table should not exist")
|
||||
assertFalse(itExists("idx_ensured_key", db.conn), "The PK index for the 'ensured' table should not exist")
|
||||
db.conn.ensureTable("ensured")
|
||||
assertTrue(itExists("ensured", db.conn), "The 'ensured' table should exist")
|
||||
assertTrue(itExists("idx_ensured_key", db.conn), "The PK index for the 'ensured' table should now exist")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("ensureFieldIndex creates an index")
|
||||
fun ensureFieldIndex() =
|
||||
SQLiteDB().use { db ->
|
||||
assertFalse(itExists("idx_${SQLiteDB.tableName}_test", db.conn), "The test index should not exist")
|
||||
db.conn.ensureFieldIndex(SQLiteDB.tableName, "test", listOf("id", "category"))
|
||||
assertTrue(itExists("idx_${SQLiteDB.tableName}_test", db.conn), "The test index should now exist")
|
||||
}
|
||||
}
|
||||
66
src/integration-test/kotlin/DocumentSQLiteIT.kt
Normal file
66
src/integration-test/kotlin/DocumentSQLiteIT.kt
Normal file
@@ -0,0 +1,66 @@
|
||||
package solutions.bitbadger.documents
|
||||
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.fail
|
||||
|
||||
/**
|
||||
* SQLite integration tests for the `Document` object / `insert`, `save`, `update` connection extension functions
|
||||
*/
|
||||
@DisplayName("SQLite - Document")
|
||||
class DocumentSQLiteIT {
|
||||
|
||||
@Test
|
||||
@DisplayName("insert works with default values")
|
||||
fun insertDefault() =
|
||||
SQLiteDB().use { db ->
|
||||
assertEquals(0L, db.conn.countAll(SQLiteDB.tableName), "There should be no documents in the table")
|
||||
val doc = JsonDocument("turkey", "", 0, SubDocument("gobble", "gobble"))
|
||||
db.conn.insert(SQLiteDB.tableName, doc)
|
||||
val after = db.conn.findAll<JsonDocument>(SQLiteDB.tableName)
|
||||
assertEquals(1, after.size, "There should be one document in the table")
|
||||
assertEquals(doc, after[0], "The document should be what was inserted")
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("insert fails with duplicate key")
|
||||
fun insertDupe() =
|
||||
SQLiteDB().use { db ->
|
||||
db.conn.insert(SQLiteDB.tableName, JsonDocument("a", "", 0, null))
|
||||
try {
|
||||
db.conn.insert(SQLiteDB.tableName, JsonDocument("a", "b", 22, null))
|
||||
fail("Inserting a document with a duplicate key should have thrown an exception")
|
||||
} catch (_: Exception) {
|
||||
// yay
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("insert succeeds with numeric auto IDs")
|
||||
fun insertNumAutoId() =
|
||||
SQLiteDB().use { db ->
|
||||
try {
|
||||
Configuration.autoIdStrategy = AutoId.NUMBER
|
||||
Configuration.idField = "key"
|
||||
assertEquals(0L, db.conn.countAll(SQLiteDB.tableName), "There should be no documents in the table")
|
||||
|
||||
db.conn.insert(SQLiteDB.tableName, NumIdDocument(0, "one"))
|
||||
db.conn.insert(SQLiteDB.tableName, NumIdDocument(0, "two"))
|
||||
db.conn.insert(SQLiteDB.tableName, NumIdDocument(77, "three"))
|
||||
db.conn.insert(SQLiteDB.tableName, NumIdDocument(0, "four"))
|
||||
|
||||
val after = db.conn.findAll<NumIdDocument>(SQLiteDB.tableName, listOf(Field.named("key")))
|
||||
assertEquals(4, after.size, "There should have been 4 documents returned")
|
||||
assertEquals(
|
||||
"1|2|77|78", after.joinToString("|") { it.key.toString() },
|
||||
"The IDs were not generated correctly"
|
||||
)
|
||||
} finally {
|
||||
Configuration.autoIdStrategy = AutoId.DISABLED
|
||||
Configuration.idField = "id"
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: UUID, Random String
|
||||
}
|
||||
36
src/integration-test/kotlin/SQLiteDB.kt
Normal file
36
src/integration-test/kotlin/SQLiteDB.kt
Normal file
@@ -0,0 +1,36 @@
|
||||
package solutions.bitbadger.documents
|
||||
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* A wrapper for a throwaway SQLite database
|
||||
*/
|
||||
class SQLiteDB : AutoCloseable {
|
||||
|
||||
private var dbName = "";
|
||||
|
||||
init {
|
||||
dbName = "test-db-${AutoId.generateRandomString(8)}.db"
|
||||
Configuration.connectionString = "jdbc:sqlite:$dbName"
|
||||
}
|
||||
|
||||
val conn = Configuration.dbConn()
|
||||
|
||||
init {
|
||||
conn.ensureTable(tableName)
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
conn.close()
|
||||
File(dbName).delete()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
/** The catalog table for SQLite's schema */
|
||||
val catalog = "sqlite_master"
|
||||
|
||||
/** The table used for test documents */
|
||||
val tableName = "test_table"
|
||||
}
|
||||
}
|
||||
40
src/integration-test/kotlin/Types.kt
Normal file
40
src/integration-test/kotlin/Types.kt
Normal file
@@ -0,0 +1,40 @@
|
||||
package solutions.bitbadger.documents
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import java.sql.Connection
|
||||
|
||||
@Serializable
|
||||
data class NumIdDocument(val key: Int, val text: String)
|
||||
|
||||
@Serializable
|
||||
data class SubDocument(val foo: String, val bar: String)
|
||||
|
||||
@Serializable
|
||||
data class ArrayDocument(val id: String, val values: List<String>) {
|
||||
companion object {
|
||||
/** A set of documents used for integration tests */
|
||||
val testDocuments = listOf(
|
||||
ArrayDocument("first", listOf("a", "b", "c" )),
|
||||
ArrayDocument("second", listOf("c", "d", "e")),
|
||||
ArrayDocument("third", listOf("x", "y", "z")))
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class JsonDocument(val id: String, val value: String, val numValue: Int, val sub: SubDocument?) {
|
||||
companion object {
|
||||
/** An empty JsonDocument */
|
||||
val emptyDoc = JsonDocument("", "", 0, null)
|
||||
|
||||
/** Documents to use for testing */
|
||||
val testDocuments = listOf(
|
||||
JsonDocument("one", "FIRST!", 0, null),
|
||||
JsonDocument("two", "another", 10, SubDocument("green", "blue")),
|
||||
JsonDocument("three", "", 4, null),
|
||||
JsonDocument("four", "purple", 17, SubDocument("green", "red")),
|
||||
JsonDocument("five", "purple", 18, null))
|
||||
|
||||
fun load(conn: Connection, tableName: String = "test_table") =
|
||||
testDocuments.forEach { conn.insert(tableName, it) }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user