@@ -2,109 +2,59 @@ package com.powersync
22
33import app.cash.turbine.turbineScope
44import co.touchlab.kermit.ExperimentalKermitApi
5- import co.touchlab.kermit.Logger
6- import co.touchlab.kermit.Severity
7- import co.touchlab.kermit.TestConfig
8- import co.touchlab.kermit.TestLogWriter
95import com.powersync.db.ActiveDatabaseGroup
10- import com.powersync.db.getString
116import com.powersync.db.schema.Schema
127import com.powersync.testutils.UserRow
13- import com.powersync.testutils.generatePrintLogWriter
8+ import com.powersync.testutils.databaseTest
149import com.powersync.testutils.getTempDir
1510import com.powersync.testutils.waitFor
11+ import io.kotest.assertions.throwables.shouldThrow
12+ import io.kotest.matchers.collections.shouldHaveSize
13+ import io.kotest.matchers.shouldBe
14+ import io.kotest.matchers.string.shouldContain
1615import kotlinx.coroutines.CompletableDeferred
1716import kotlinx.coroutines.Dispatchers
1817import kotlinx.coroutines.async
1918import kotlinx.coroutines.delay
2019import kotlinx.coroutines.runBlocking
21- import kotlinx.coroutines.test.runTest
2220import kotlinx.coroutines.withContext
23- import kotlin.test.AfterTest
24- import kotlin.test.BeforeTest
2521import kotlin.test.Test
2622import kotlin.test.assertEquals
27- import kotlin.test.assertFailsWith
2823import kotlin.test.assertNotNull
29- import kotlin.test.assertTrue
3024
3125@OptIn(ExperimentalKermitApi ::class )
3226class DatabaseTest {
33- private val logWriter =
34- TestLogWriter (
35- loggable = Severity .Debug ,
36- )
37-
38- private val logger =
39- Logger (
40- TestConfig (
41- minSeverity = Severity .Debug ,
42- logWriterList = listOf (logWriter, generatePrintLogWriter()),
43- ),
44- )
45-
46- private lateinit var database: PowerSyncDatabase
47-
48- private fun openDB () =
49- PowerSyncDatabase (
50- factory = com.powersync.testutils.factory,
51- schema = Schema (UserRow .table),
52- dbFilename = " testdb" ,
53- logger = logger,
54- )
55-
56- @BeforeTest
57- fun setupDatabase () {
58- logWriter.reset()
59-
60- database = openDB()
61-
62- runBlocking {
63- database.disconnectAndClear(true )
64- }
65- }
66-
67- @AfterTest
68- fun tearDown () {
69- runBlocking {
70- if (! database.closed) {
71- database.disconnectAndClear(true )
72- }
73- }
74- com.powersync.testutils.cleanup(" testdb" )
75- }
76-
7727 @Test
7828 fun testLinksPowerSync () =
79- runTest {
29+ databaseTest {
8030 database.get(" SELECT powersync_rs_version();" ) { it.getString(0 )!! }
8131 }
8232
8333 @Test
8434 fun testWAL () =
85- runTest {
35+ databaseTest {
8636 val mode =
8737 database.get(
8838 " PRAGMA journal_mode" ,
8939 mapper = { it.getString(0 )!! },
9040 )
91- assertEquals( mode, " wal" )
41+ mode shouldBe " wal"
9242 }
9343
9444 @Test
9545 fun testFTS () =
96- runTest {
46+ databaseTest {
9747 val mode =
9848 database.get(
9949 " SELECT sqlite_compileoption_used('ENABLE_FTS5');" ,
10050 mapper = { it.getLong(0 )!! },
10151 )
102- assertEquals( mode, 1 )
52+ mode shouldBe 1
10353 }
10454
10555 @Test
10656 fun testConcurrentReads () =
107- runTest {
57+ databaseTest {
10858 database.execute(
10959 " INSERT INTO users (id, name, email) VALUES (uuid(), ?, ?)" ,
11060 listOf (
@@ -117,7 +67,7 @@ class DatabaseTest {
11767 val transactionItemCreated = CompletableDeferred <Unit >()
11868 // Start a long running writeTransaction
11969 val transactionJob =
120- async {
70+ scope. async {
12171 database.writeTransaction { tx ->
12272 // Create another user
12373 // External readers should not see this user while the transaction is open
@@ -155,7 +105,7 @@ class DatabaseTest {
155105
156106 @Test
157107 fun testTransactionReads () =
158- runTest {
108+ databaseTest {
159109 database.execute(
160110 " INSERT INTO users (id, name, email) VALUES (uuid(), ?, ?)" ,
161111 listOf (
@@ -186,18 +136,18 @@ class DatabaseTest {
186136
187137 @Test
188138 fun testTableUpdates () =
189- runTest {
139+ databaseTest {
190140 turbineScope {
191141 val query = database.watch(" SELECT * FROM users" ) { UserRow .from(it) }.testIn(this )
192142
193143 // Wait for initial query
194- assertEquals( 0 , query.awaitItem().size)
144+ query.awaitItem() shouldHaveSize 0
195145
196146 database.execute(
197147 " INSERT INTO users (id, name, email) VALUES (uuid(), ?, ?)" ,
198148 listOf (" Test" , " test@example.org" ),
199149 )
200- assertEquals( 1 , query.awaitItem().size)
150+ query.awaitItem() shouldHaveSize 1
201151
202152 database.writeTransaction {
203153 it.execute(
@@ -210,7 +160,7 @@ class DatabaseTest {
210160 )
211161 }
212162
213- assertEquals( 3 , query.awaitItem().size)
163+ query.awaitItem() shouldHaveSize 3
214164
215165 try {
216166 database.writeTransaction {
@@ -225,7 +175,7 @@ class DatabaseTest {
225175 " INSERT INTO users (id, name, email) VALUES (uuid(), ?, ?)" ,
226176 listOf (" Test4" , " test4@example.org" ),
227177 )
228- assertEquals( 4 , query.awaitItem().size)
178+ query.awaitItem() shouldHaveSize 4
229179
230180 query.expectNoEvents()
231181 query.cancel()
@@ -234,12 +184,12 @@ class DatabaseTest {
234184
235185 @Test
236186 fun testClosingReadPool () =
237- runTest {
187+ databaseTest {
238188 val pausedLock = CompletableDeferred <Unit >()
239189 val inLock = CompletableDeferred <Unit >()
240190 // Request a lock
241191 val lockJob =
242- async {
192+ scope. async {
243193 database.readLock {
244194 inLock.complete(Unit )
245195 runBlocking {
@@ -254,60 +204,48 @@ class DatabaseTest {
254204 // Close the database. This should close the read pool
255205 // The pool should wait for jobs to complete before closing
256206 val closeJob =
257- async {
207+ scope. async {
258208 database.close()
259209 }
260210
261211 // Wait a little for testing
262- // Spawns in a different context for the delay to actually take affect
263- async { withContext(Dispatchers .Default ) { delay(500 ) } }.await()
212+ // Spawns in a different context for the delay to actually take effect
213+ scope. async { withContext(Dispatchers .Default ) { delay(500 ) } }.await()
264214
265215 // The database should not close yet
266216 assertEquals(actual = database.closed, expected = false )
267217
268218 // Any new readLocks should throw
269- val exception = assertFailsWith<PowerSyncException > { database.readLock {} }
270- assertEquals(
271- expected = " Cannot process connection pool request" ,
272- actual = exception.message,
273- )
219+ val exception = shouldThrow<PowerSyncException > { database.readLock {} }
220+ exception.message shouldBe " Cannot process connection pool request"
221+
274222 // Release the lock
275223 pausedLock.complete(Unit )
276224 lockJob.await()
277225 closeJob.await()
278226
279- assertEquals(actual = database.closed, expected = true )
227+ database.closed shouldBe true
280228 }
281229
282230 @Test
283231 fun openDBWithDirectory () =
284- runTest {
232+ databaseTest {
285233 val tempDir =
286234 getTempDir()
287235 ? : // SQLiteR, which is used on iOS, does not support opening dbs from directories
288- return @runTest
289-
290- val dbFilename = " testdb"
236+ return @databaseTest
291237
292- val db =
293- PowerSyncDatabase (
294- factory = com.powersync.testutils.factory,
295- schema = Schema (UserRow .table),
296- dbFilename = dbFilename,
297- dbDirectory = getTempDir(),
298- logger = logger,
299- )
300-
301- val path = db.get(" SELECT file FROM pragma_database_list;" ) { it.getString(0 )!! }
302- assertTrue { path.contains(tempDir) }
303- db.close()
238+ // On platforms that support it, openDatabase() from our test utils should use a temporary
239+ // location.
240+ val path = database.get(" SELECT file FROM pragma_database_list;" ) { it.getString(0 )!! }
241+ path shouldContain tempDir
304242 }
305243
306244 @Test
307245 fun warnsMultipleInstances () =
308- runTest {
246+ databaseTest {
309247 // Opens a second DB with the same database filename
310- val db2 = openDB ()
248+ val db2 = openDatabase ()
311249 waitFor {
312250 assertNotNull(
313251 logWriter.logs.find {
@@ -320,9 +258,9 @@ class DatabaseTest {
320258
321259 @Test
322260 fun readConnectionsReadOnly () =
323- runTest {
261+ databaseTest {
324262 val exception =
325- assertFailsWith <PowerSyncException > {
263+ shouldThrow <PowerSyncException > {
326264 database.getOptional(
327265 """
328266 INSERT INTO
@@ -334,23 +272,24 @@ class DatabaseTest {
334272 parameters = listOf (" steven" , " steven@journeyapps.com" ),
335273 ) {}
336274 }
275+
337276 // The exception messages differ slightly between drivers
338- assertTrue { exception.message!! .contains( " write a readonly database" ) }
277+ exception.message shouldContain " write a readonly database"
339278 }
340279
341280 @Test
342281 fun basicReadTransaction () =
343- runTest {
282+ databaseTest {
344283 val count =
345284 database.readTransaction { it ->
346285 it.get(" SELECT COUNT(*) from users" ) { it.getLong(0 )!! }
347286 }
348- assertEquals(expected = 0 , actual = count)
287+ count shouldBe 0
349288 }
350289
351290 @Test
352291 fun localOnlyCRUD () =
353- runTest {
292+ databaseTest {
354293 database.updateSchema(
355294 schema =
356295 Schema (
@@ -374,16 +313,16 @@ class DatabaseTest {
374313 )
375314
376315 val count = database.get(" SELECT COUNT(*) FROM local_users" ) { it.getLong(0 )!! }
377- assertEquals(actual = count, expected = 1 )
316+ count shouldBe 1
378317
379318 // No CRUD entries should be present for local only tables
380319 val crudItems = database.getAll(" SELECT id from ps_crud" ) { it.getLong(0 )!! }
381- assertEquals(actual = crudItems.size, expected = 0 )
320+ crudItems shouldHaveSize 0
382321 }
383322
384323 @Test
385324 fun insertOnlyCRUD () =
386- runTest {
325+ databaseTest {
387326 database.updateSchema(schema = Schema (UserRow .table.copy(insertOnly = true )))
388327
389328 database.execute(
@@ -396,15 +335,15 @@ class DatabaseTest {
396335 )
397336
398337 val crudItems = database.getAll(" SELECT id from ps_crud" ) { it.getLong(0 )!! }
399- assertEquals(actual = crudItems.size, expected = 1 )
338+ crudItems shouldHaveSize 1
400339
401340 val count = database.get(" SELECT COUNT(*) from users" ) { it.getLong(0 )!! }
402- assertEquals(actual = count, expected = 0 )
341+ count shouldBe 0
403342 }
404343
405344 @Test
406345 fun viewOverride () =
407- runTest {
346+ databaseTest {
408347 database.updateSchema(schema = Schema (UserRow .table.copy(viewNameOverride = " people" )))
409348
410349 database.execute(
@@ -417,9 +356,9 @@ class DatabaseTest {
417356 )
418357
419358 val crudItems = database.getAll(" SELECT id from ps_crud" ) { it.getLong(0 )!! }
420- assertEquals(actual = crudItems.size, expected = 1 )
359+ crudItems shouldHaveSize 1
421360
422361 val count = database.get(" SELECT COUNT(*) from people" ) { it.getLong(0 )!! }
423- assertEquals(actual = count, expected = 1 )
362+ count shouldBe 1
424363 }
425364}
0 commit comments