diff --git a/mailbox-android/src/main/java/org/briarproject/mailbox/android/AppModule.kt b/mailbox-android/src/main/java/org/briarproject/mailbox/android/AppModule.kt
index fce42c9512b07a41dac70fab0c703f8c3a69999e..ec7f6a9096e20be9679e6975a7208ff093996d27 100644
--- a/mailbox-android/src/main/java/org/briarproject/mailbox/android/AppModule.kt
+++ b/mailbox-android/src/main/java/org/briarproject/mailbox/android/AppModule.kt
@@ -45,17 +45,19 @@ import javax.inject.Singleton
 internal class AppModule {
     @Singleton
     @Provides
-    fun provideDatabaseConfig(app: Application) = object : DatabaseConfig {
+    fun provideDatabaseConfig(fileProvider: FileProvider) = object : DatabaseConfig {
         override fun getDatabaseDirectory(): File {
-            return app.applicationContext.getDir("db", MODE_PRIVATE)
+            // The database itself does mkdirs() and we use the existence to see if DB exists
+            return File(fileProvider.root, "db")
         }
     }
 
     @Singleton
     @Provides
     fun provideFileProvider(app: Application) = object : FileProvider {
-        private val tempFilesDir = File(app.applicationContext.cacheDir, "tmp").also { it.mkdirs() }
+        override val root: File get() = app.applicationContext.filesDir
         override val folderRoot = app.applicationContext.getDir("folders", MODE_PRIVATE)
+        private val tempFilesDir = File(app.applicationContext.cacheDir, "tmp").also { it.mkdirs() }
 
         override fun getTemporaryFile(fileId: String) = File(tempFilesDir, fileId)
         override fun getFolder(folderId: String) = File(folderRoot, folderId).also { it.mkdirs() }
diff --git a/mailbox-cli/src/main/java/org/briarproject/mailbox/cli/JavaCliModule.kt b/mailbox-cli/src/main/java/org/briarproject/mailbox/cli/JavaCliModule.kt
index 58774946a9b32cbb472412908c022c1fc6a0d32b..eb5d4421c4442bfef37d3dd880b495d8c599c1da 100644
--- a/mailbox-cli/src/main/java/org/briarproject/mailbox/cli/JavaCliModule.kt
+++ b/mailbox-cli/src/main/java/org/briarproject/mailbox/cli/JavaCliModule.kt
@@ -89,21 +89,17 @@ internal class JavaCliModule {
 
     @Singleton
     @Provides
-    fun provideDatabaseConfig() = object : DatabaseConfig {
+    fun provideDatabaseConfig(fileProvider: FileProvider) = object : DatabaseConfig {
         override fun getDatabaseDirectory(): File {
-            val dbDir = File(dataDir, "db")
-            if (!dbDir.exists() && !dbDir.mkdirs()) {
-                throw IOException("dbDir could not be created: ${dbDir.absolutePath}")
-            } else if (!dbDir.isDirectory) {
-                throw IOException("dbDir is not a directory: ${dbDir.absolutePath}")
-            }
-            return dbDir
+            // The database itself does mkdirs() and we use the existence to see if DB exists
+            return File(fileProvider.root, "db")
         }
     }
 
     @Singleton
     @Provides
     fun provideFileProvider() = object : FileProvider {
+        override val root: File get() = dataDir
         private val tempFilesDir = File(dataDir, "tmp").also { it.mkdirs() }
         override val folderRoot = File(dataDir, "folders").also { it.mkdirs() }
 
diff --git a/mailbox-cli/src/main/java/org/briarproject/mailbox/cli/Main.kt b/mailbox-cli/src/main/java/org/briarproject/mailbox/cli/Main.kt
index 44cf1c5ed05f073620b16a7a257481b6c2820198..216e13ee020f57e02c13129961ccb56530b6a52d 100644
--- a/mailbox-cli/src/main/java/org/briarproject/mailbox/cli/Main.kt
+++ b/mailbox-cli/src/main/java/org/briarproject/mailbox/cli/Main.kt
@@ -100,6 +100,7 @@ class Main : CliktCommand(
             }
         )
 
+        // This is a cli app, we'll always want this fully up when started, so start lifecycle
         lifecycleManager.startServices()
         lifecycleManager.waitForStartup()
 
@@ -110,16 +111,14 @@ class Main : CliktCommand(
             exitProcess(1)
         }
 
-        // TODO this is obviously not the final code, just a stub to get us started
-        val setupTokenExists = db.read { txn ->
-            setupManager.getSetupToken(txn) != null
-        }
         val ownerTokenExists = db.read { txn ->
             setupManager.getOwnerToken(txn) != null
         }
-        if (!setupTokenExists && !ownerTokenExists) setupManager.restartSetup()
-        qrCodeEncoder.getQrCodeBitMatrix()?.let {
-            println(QrCodeRenderer.getQrString(it))
+        if (!ownerTokenExists) {
+            // If not set up, show QR code for manual setup
+            qrCodeEncoder.getQrCodeBitMatrix()?.let {
+                println(QrCodeRenderer.getQrString(it))
+            }
         }
     }
 
diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/CoreModule.kt b/mailbox-core/src/main/java/org/briarproject/mailbox/core/CoreModule.kt
index 31dce9ca6947a43adfccaa3d6a91619ba62da8af..631bfebf1a2b6559c73761f963e50b26c10099e5 100644
--- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/CoreModule.kt
+++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/CoreModule.kt
@@ -28,6 +28,7 @@ import org.briarproject.mailbox.core.event.EventModule
 import org.briarproject.mailbox.core.lifecycle.LifecycleModule
 import org.briarproject.mailbox.core.server.WebServerModule
 import org.briarproject.mailbox.core.settings.SettingsModule
+import org.briarproject.mailbox.core.setup.SetupModule
 import org.briarproject.mailbox.core.system.Clock
 import org.briarproject.mailbox.core.tor.TorModule
 import javax.inject.Singleton
@@ -37,6 +38,7 @@ import javax.inject.Singleton
         EventModule::class,
         LifecycleModule::class,
         DatabaseModule::class,
+        SetupModule::class,
         WebServerModule::class,
         SettingsModule::class,
         TorModule::class,
diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/files/FileManager.kt b/mailbox-core/src/main/java/org/briarproject/mailbox/core/files/FileManager.kt
index dc113ea23a3d4c46047d6147f2b2bc426b377e5e..675dfdc06271c2bb2ebdc990987198fd49038771 100644
--- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/files/FileManager.kt
+++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/files/FileManager.kt
@@ -28,9 +28,12 @@ import io.ktor.response.respondFile
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.withContext
 import org.briarproject.mailbox.core.db.Database
+import org.briarproject.mailbox.core.db.DatabaseConfig
 import org.briarproject.mailbox.core.server.AuthException
 import org.briarproject.mailbox.core.server.AuthManager
 import org.briarproject.mailbox.core.server.MailboxPrincipal
+import org.briarproject.mailbox.core.setup.SetupManager
+import org.briarproject.mailbox.core.setup.WipeManager
 import org.briarproject.mailbox.core.system.InvalidIdException
 import org.briarproject.mailbox.core.system.RandomIdManager
 import org.slf4j.LoggerFactory.getLogger
@@ -40,10 +43,24 @@ private val LOG = getLogger(FileManager::class.java)
 
 class FileManager @Inject constructor(
     private val fileProvider: FileProvider,
+    private val dbConfig: DatabaseConfig,
 ) {
+
+    /**
+     * Used by [SetupManager] to test for the existence of the database.
+     */
+    fun hasDbFile(): Boolean {
+        val dbDir = dbConfig.getDatabaseDirectory()
+        println("${dbDir.absolutePath} exists: ${dbDir.exists()} isDirectory: ${dbDir.isDirectory}")
+        return dbDir.isDirectory
+    }
+
+    /**
+     * Used by [WipeManager] to wipe all files.
+     */
     fun deleteAllFiles(): Boolean {
         var allDeleted = true
-        fileProvider.folderRoot.listFiles()?.forEach { folder ->
+        fileProvider.root.listFiles()?.forEach { folder ->
             if (!folder.deleteRecursively()) {
                 allDeleted = false
                 LOG.warn("Not everything in $folder could get deleted.")
diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/files/FileProvider.kt b/mailbox-core/src/main/java/org/briarproject/mailbox/core/files/FileProvider.kt
index b8a10f5ca19268d10b931580cd80f9d12ca3ac32..f9017f28ae299a6ce47726366ebe106e41a3d0c4 100644
--- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/files/FileProvider.kt
+++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/files/FileProvider.kt
@@ -22,6 +22,11 @@ package org.briarproject.mailbox.core.files
 import java.io.File
 
 interface FileProvider {
+    /**
+     * The root files directory.
+     * Attention: This is not guaranteed to be the parent of other files on all platforms.
+     */
+    val root: File
     val folderRoot: File
     fun getTemporaryFile(fileId: String): File
     fun getFolder(folderId: String): File
diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/settings/SettingsManager.kt b/mailbox-core/src/main/java/org/briarproject/mailbox/core/settings/SettingsManager.kt
index d7ab1ea2c916015a349fbe2f4759e825d9794d11..2b631bfb16cec4ac91567e81501a574a8c69de0b 100644
--- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/settings/SettingsManager.kt
+++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/settings/SettingsManager.kt
@@ -41,4 +41,11 @@ interface SettingsManager {
      */
     @Throws(DbException::class)
     fun mergeSettings(s: Settings, namespace: String)
+
+    /**
+     * Merges the given settings with any existing settings in the given
+     * namespace.
+     */
+    @Throws(DbException::class)
+    fun mergeSettings(txn: Transaction, s: Settings, namespace: String)
 }
diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/settings/SettingsManagerImpl.kt b/mailbox-core/src/main/java/org/briarproject/mailbox/core/settings/SettingsManagerImpl.kt
index 49930785522aae6c61dbfc03482a462b0221bdea..a8e404ebeca97c86917ae59c77e59f26a6a1e598 100644
--- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/settings/SettingsManagerImpl.kt
+++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/settings/SettingsManagerImpl.kt
@@ -43,4 +43,8 @@ internal class SettingsManagerImpl(private val db: Database) : SettingsManager {
     override fun mergeSettings(s: Settings, namespace: String) {
         db.write { txn -> db.mergeSettings(txn, s, namespace) }
     }
+
+    override fun mergeSettings(txn: Transaction, s: Settings, namespace: String) {
+        db.mergeSettings(txn, s, namespace)
+    }
 }
diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/setup/SetupManager.kt b/mailbox-core/src/main/java/org/briarproject/mailbox/core/setup/SetupManager.kt
index c74d1fac3fba7e77b253d48935d122a1a58b4216..b1d5aaa18c045ce2cb5be89b8f47e1011e056790 100644
--- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/setup/SetupManager.kt
+++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/setup/SetupManager.kt
@@ -25,6 +25,8 @@ import io.ktor.http.HttpStatusCode
 import io.ktor.response.respond
 import org.briarproject.mailbox.core.db.DbException
 import org.briarproject.mailbox.core.db.Transaction
+import org.briarproject.mailbox.core.files.FileManager
+import org.briarproject.mailbox.core.lifecycle.LifecycleManager.OpenDatabaseHook
 import org.briarproject.mailbox.core.server.AuthException
 import org.briarproject.mailbox.core.server.AuthManager
 import org.briarproject.mailbox.core.settings.Settings
@@ -36,23 +38,50 @@ private const val SETTINGS_NAMESPACE_OWNER = "owner"
 private const val SETTINGS_SETUP_TOKEN = "setupToken"
 private const val SETTINGS_OWNER_TOKEN = "ownerToken"
 
-class SetupManager @Inject constructor(
+interface SetupManager : OpenDatabaseHook {
+    /**
+     * True if a database has been setup.
+     * This is usually the case, if the lifecycle has been started once.
+     * The Mailbox might still need pairing/linking.
+     * This is false after wiping.
+     */
+    val hasDb: Boolean
+
+    @Throws(DbException::class)
+    fun setToken(setupToken: String?, ownerToken: String?)
+
+    fun getSetupToken(txn: Transaction): String?
+
+    @Throws(DbException::class)
+    fun getOwnerToken(txn: Transaction): String?
+}
+
+class SetupManagerImpl @Inject constructor(
     private val randomIdManager: RandomIdManager,
     private val settingsManager: SettingsManager,
-) {
+    private val fileManager: FileManager,
+) : SetupManager {
 
-    /**
-     * Stores a new single-use setup token and wipes the owner auth token, if one existed.
-     */
-    fun restartSetup() {
-        val settings = Settings()
-        settings[SETTINGS_SETUP_TOKEN] = randomIdManager.getNewRandomId()
-        settings[SETTINGS_OWNER_TOKEN] = null
-        settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE_OWNER)
+    override val hasDb: Boolean get() = fileManager.hasDbFile()
+
+    override fun onDatabaseOpened(txn: Transaction) {
+        val settings = settingsManager.getSettings(txn, SETTINGS_NAMESPACE_OWNER)
+        val setupToken = settings[SETTINGS_SETUP_TOKEN]
+        val ownerToken = settings[SETTINGS_OWNER_TOKEN]
+        // ensure that setup token is initialized if both tokens are empty
+        if (setupToken == null && ownerToken == null) {
+            settings[SETTINGS_SETUP_TOKEN] = randomIdManager.getNewRandomId()
+            settingsManager.mergeSettings(txn, settings, SETTINGS_NAMESPACE_OWNER)
+        }
     }
 
+    /**
+     * Sets either the [setupToken] or the [ownerToken].
+     * Can not set both at once.
+     */
     @Throws(DbException::class)
-    fun setToken(setupToken: String?, ownerToken: String?) {
+    override fun setToken(setupToken: String?, ownerToken: String?) {
+        require(setupToken == null || ownerToken == null) { "Can not set both tokens" }
         val settings = Settings()
         if (setupToken != null) randomIdManager.assertIsRandomId(setupToken)
         settings[SETTINGS_SETUP_TOKEN] = setupToken
@@ -61,13 +90,13 @@ class SetupManager @Inject constructor(
         settingsManager.mergeSettings(settings, SETTINGS_NAMESPACE_OWNER)
     }
 
-    fun getSetupToken(txn: Transaction): String? {
+    override fun getSetupToken(txn: Transaction): String? {
         val settings = settingsManager.getSettings(txn, SETTINGS_NAMESPACE_OWNER)
         return settings[SETTINGS_SETUP_TOKEN]
     }
 
     @Throws(DbException::class)
-    fun getOwnerToken(txn: Transaction): String? {
+    override fun getOwnerToken(txn: Transaction): String? {
         val settings = settingsManager.getSettings(txn, SETTINGS_NAMESPACE_OWNER)
         return settings[SETTINGS_OWNER_TOKEN]
     }
diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/setup/SetupModule.kt b/mailbox-core/src/main/java/org/briarproject/mailbox/core/setup/SetupModule.kt
new file mode 100644
index 0000000000000000000000000000000000000000..55b9fe2fdedc497ed9e3530d2f3953ae369c7715
--- /dev/null
+++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/setup/SetupModule.kt
@@ -0,0 +1,39 @@
+/*
+ *     Briar Mailbox
+ *     Copyright (C) 2021-2022  The Briar Project
+ *
+ *     This program is free software: you can redistribute it and/or modify
+ *     it under the terms of the GNU Affero General Public License as
+ *     published by the Free Software Foundation, either version 3 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This program is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU Affero General Public License for more details.
+ *
+ *     You should have received a copy of the GNU Affero General Public License
+ *     along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ *
+ */
+
+package org.briarproject.mailbox.core.setup
+
+import dagger.Module
+import dagger.Provides
+import org.briarproject.mailbox.core.lifecycle.LifecycleManager
+import javax.inject.Singleton
+
+@Module
+class SetupModule {
+    @Provides
+    @Singleton
+    fun provideSetupManager(
+        lifecycleManager: LifecycleManager,
+        setupManagerImpl: SetupManagerImpl,
+    ): SetupManager {
+        return setupManagerImpl.also {
+            lifecycleManager.registerOpenDatabaseHook(it)
+        }
+    }
+}
diff --git a/mailbox-core/src/main/java/org/briarproject/mailbox/core/setup/WipeManager.kt b/mailbox-core/src/main/java/org/briarproject/mailbox/core/setup/WipeManager.kt
index 59629b3cd8459a2a03b562559ce2f84f13dba434..6fde359876a0212dcf002a46034ef2c22b466cc1 100644
--- a/mailbox-core/src/main/java/org/briarproject/mailbox/core/setup/WipeManager.kt
+++ b/mailbox-core/src/main/java/org/briarproject/mailbox/core/setup/WipeManager.kt
@@ -30,7 +30,6 @@ import org.briarproject.mailbox.core.lifecycle.LifecycleManager
 import org.briarproject.mailbox.core.server.AuthException
 import org.briarproject.mailbox.core.server.MailboxPrincipal
 import org.briarproject.mailbox.core.server.MailboxPrincipal.OwnerPrincipal
-import org.briarproject.mailbox.core.util.IoUtils
 import javax.inject.Inject
 
 class WipeManager @Inject constructor(
@@ -44,8 +43,6 @@ class WipeManager @Inject constructor(
      */
     fun wipeDatabaseAndFiles() {
         db.dropAllTablesAndClose()
-        val dir = databaseConfig.getDatabaseDirectory()
-        IoUtils.deleteFileOrDir(dir)
         fileManager.deleteAllFiles()
     }
 
diff --git a/mailbox-core/src/test/java/org/briarproject/mailbox/core/TestComponent.kt b/mailbox-core/src/test/java/org/briarproject/mailbox/core/TestComponent.kt
index e0ad498eb2764b4fd53066fb45a2cbf2f7feda97..960874cd8156d7c84da414d9c281237a3510881a 100644
--- a/mailbox-core/src/test/java/org/briarproject/mailbox/core/TestComponent.kt
+++ b/mailbox-core/src/test/java/org/briarproject/mailbox/core/TestComponent.kt
@@ -9,7 +9,7 @@ import org.briarproject.mailbox.core.lifecycle.LifecycleManager
 import org.briarproject.mailbox.core.settings.MetadataManager
 import org.briarproject.mailbox.core.settings.SettingsManager
 import org.briarproject.mailbox.core.setup.SetupManager
-import org.briarproject.mailbox.core.system.RandomIdManager
+import org.briarproject.mailbox.core.setup.WipeManager
 import javax.inject.Singleton
 
 @Singleton
@@ -26,7 +26,7 @@ interface TestComponent {
     fun getFileManager(): FileManager
     fun getDatabaseConfig(): DatabaseConfig
     fun getDatabase(): Database
-    fun getRandomIdManager(): RandomIdManager
     fun getFileProvider(): FileProvider
     fun getMetadataManager(): MetadataManager
+    fun getWipeManager(): WipeManager
 }
diff --git a/mailbox-core/src/test/java/org/briarproject/mailbox/core/TestModule.kt b/mailbox-core/src/test/java/org/briarproject/mailbox/core/TestModule.kt
index 2a1adc06bdf8bc09bb97f6dd91fae266dd1cdf42..1764c14999c730a122f02ccfee6cea3ca34376a8 100644
--- a/mailbox-core/src/test/java/org/briarproject/mailbox/core/TestModule.kt
+++ b/mailbox-core/src/test/java/org/briarproject/mailbox/core/TestModule.kt
@@ -10,6 +10,7 @@ import org.briarproject.mailbox.core.files.FileProvider
 import org.briarproject.mailbox.core.lifecycle.LifecycleModule
 import org.briarproject.mailbox.core.server.WebServerModule
 import org.briarproject.mailbox.core.settings.SettingsModule
+import org.briarproject.mailbox.core.setup.SetupModule
 import org.briarproject.mailbox.core.system.Clock
 import java.io.File
 import javax.inject.Singleton
@@ -18,6 +19,7 @@ import javax.inject.Singleton
     includes = [
         LifecycleModule::class,
         TestDatabaseModule::class,
+        SetupModule::class,
         WebServerModule::class,
         SettingsModule::class,
         // no Tor module
@@ -40,10 +42,14 @@ internal class TestModule(private val tempDir: File) {
     @Singleton
     @Provides
     fun provideFileProvider() = object : FileProvider {
-        private val tempFilesDir = File(tempDir, "tmp").also { it.mkdirs() }
+        override val root: File get() = tempDir
         override val folderRoot = File(tempDir, "folders")
+        private val tempFilesDir = File(tempDir, "tmp").also { it.mkdirs() }
 
-        override fun getTemporaryFile(fileId: String) = File(tempFilesDir, fileId)
+        override fun getTemporaryFile(fileId: String) = File(tempFilesDir, fileId).also { file ->
+            // we delete root at the end of each test, so tempFilesDir gets deleted as well
+            file.parentFile.mkdirs()
+        }
         override fun getFolder(folderId: String) = File(folderRoot, folderId).also { it.mkdirs() }
         override fun getFile(folderId: String, fileId: String) = File(getFolder(folderId), fileId)
     }
diff --git a/mailbox-core/src/test/java/org/briarproject/mailbox/core/files/FileManagerIntegrationTest.kt b/mailbox-core/src/test/java/org/briarproject/mailbox/core/files/FileManagerIntegrationTest.kt
index de2f1d0461bd0ded29e70e91c0a353160794caec..fd0d67b97374bf1a1ce6a4865ea2cbe3fa801430 100644
--- a/mailbox-core/src/test/java/org/briarproject/mailbox/core/files/FileManagerIntegrationTest.kt
+++ b/mailbox-core/src/test/java/org/briarproject/mailbox/core/files/FileManagerIntegrationTest.kt
@@ -12,7 +12,6 @@ import kotlinx.coroutines.runBlocking
 import org.briarproject.mailbox.core.TestUtils.assertTimestampRecent
 import org.briarproject.mailbox.core.TestUtils.getNewRandomId
 import org.briarproject.mailbox.core.server.IntegrationTest
-import org.junit.jupiter.api.AfterEach
 import org.junit.jupiter.api.Assertions.assertArrayEquals
 import org.junit.jupiter.api.BeforeEach
 import org.junit.jupiter.api.Test
@@ -31,12 +30,6 @@ class FileManagerIntegrationTest : IntegrationTest() {
         addContact(contact2)
     }
 
-    @AfterEach
-    override fun clearDb() {
-        super.clearDb()
-        testComponent.getFileManager().deleteAllFiles()
-    }
-
     @Test
     fun `post new file rejects wrong token`(): Unit = runBlocking {
         val response: HttpResponse = httpClient.post("$baseUrl/files/${getNewRandomId()}") {
diff --git a/mailbox-core/src/test/java/org/briarproject/mailbox/core/server/IntegrationTest.kt b/mailbox-core/src/test/java/org/briarproject/mailbox/core/server/IntegrationTest.kt
index 10afd983ebd1403e75c3a426035ff35d0a80efdb..bbb9f151b9da66d78110d5b3687f2be17be3807c 100644
--- a/mailbox-core/src/test/java/org/briarproject/mailbox/core/server/IntegrationTest.kt
+++ b/mailbox-core/src/test/java/org/briarproject/mailbox/core/server/IntegrationTest.kt
@@ -24,6 +24,8 @@ import org.junit.jupiter.api.TestInstance
 import org.junit.jupiter.api.TestInstance.Lifecycle
 import org.junit.jupiter.api.io.TempDir
 import java.io.File
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
 
 @TestInstance(Lifecycle.PER_CLASS)
 abstract class IntegrationTest(private val installJsonFeature: Boolean = true) {
@@ -31,7 +33,9 @@ abstract class IntegrationTest(private val installJsonFeature: Boolean = true) {
     protected lateinit var testComponent: TestComponent
     protected val db by lazy { testComponent.getDatabase() }
     private val lifecycleManager by lazy { testComponent.getLifecycleManager() }
+    protected val setupManager by lazy { testComponent.getSetupManager() }
     protected val metadataManager by lazy { testComponent.getMetadataManager() }
+    private val wipeManager by lazy { testComponent.getWipeManager() }
     protected val httpClient = HttpClient(CIO) {
         expectSuccess = false // prevents exceptions on non-success responses
         if (installJsonFeature) {
@@ -55,6 +59,7 @@ abstract class IntegrationTest(private val installJsonFeature: Boolean = true) {
     fun setUp(@TempDir tempDir: File) {
         testComponent = DaggerTestComponent.builder().testModule(TestModule(tempDir)).build()
         testComponent.injectCoreEagerSingletons()
+        assertFalse(setupManager.hasDb)
         lifecycleManager.startServices()
         lifecycleManager.waitForStartup()
     }
@@ -73,11 +78,13 @@ abstract class IntegrationTest(private val installJsonFeature: Boolean = true) {
             // clears [metadataManager.ownerConnectionTime]
             metadataManager.onDatabaseOpened(txn)
         }
+        assertTrue(setupManager.hasDb)
     }
 
     @AfterEach
-    open fun clearDb() {
-        db.dropAllTablesAndClose()
+    open fun wipe() {
+        wipeManager.wipeDatabaseAndFiles()
+        assertFalse(setupManager.hasDb)
     }
 
     protected fun addOwnerToken() {
diff --git a/mailbox-core/src/test/java/org/briarproject/mailbox/core/setup/SetupManagerTest.kt b/mailbox-core/src/test/java/org/briarproject/mailbox/core/setup/SetupManagerTest.kt
index 83e40b887e92326ca36b829f853641d6726cbe9a..86f28ca64de352f0761dcffd1f02c41a56a0c85f 100644
--- a/mailbox-core/src/test/java/org/briarproject/mailbox/core/setup/SetupManagerTest.kt
+++ b/mailbox-core/src/test/java/org/briarproject/mailbox/core/setup/SetupManagerTest.kt
@@ -7,38 +7,10 @@ import kotlinx.coroutines.runBlocking
 import org.briarproject.mailbox.core.server.IntegrationTest
 import org.junit.jupiter.api.Test
 import kotlin.test.assertEquals
-import kotlin.test.assertNotNull
 import kotlin.test.assertNull
 
 class SetupManagerTest : IntegrationTest() {
 
-    private val setupManager by lazy { testComponent.getSetupManager() }
-
-    @Test
-    fun `restarting setup wipes owner token and creates setup token`() {
-        // initially, there's no setup and no owner token
-        db.read { txn ->
-            assertNull(setupManager.getSetupToken(txn))
-            assertNull(setupManager.getOwnerToken(txn))
-        }
-
-        // setting an owner token stores it in DB
-        setupManager.setToken(null, ownerToken)
-        db.read { txn ->
-            assertNull(setupManager.getSetupToken(txn))
-            assertEquals(ownerToken, setupManager.getOwnerToken(txn))
-        }
-
-        // restarting setup wipes owner token, creates setup token
-        setupManager.restartSetup()
-        db.read { txn ->
-            val setupToken = setupManager.getSetupToken(txn)
-            assertNotNull(setupToken)
-            testComponent.getRandomIdManager().assertIsRandomId(setupToken)
-            assertNull(setupManager.getOwnerToken(txn))
-        }
-    }
-
     @Test
     fun `setup request gets rejected when using non-setup token`() = runBlocking {
         // initially, there's no setup and no owner token
@@ -78,6 +50,9 @@ class SetupManagerTest : IntegrationTest() {
         // set a setup-token
         setupManager.setToken(token, null)
 
+        // we are not yet set up
+        assertNull(db.read { txn -> setupManager.getOwnerToken(txn) })
+
         // use it for setup PUT request
         val response: SetupResponse = httpClient.put("$baseUrl/setup") {
             authenticateWithToken(token)
diff --git a/mailbox-core/src/test/java/org/briarproject/mailbox/core/setup/WipingWipeRouteManagerTest.kt b/mailbox-core/src/test/java/org/briarproject/mailbox/core/setup/WipingWipeRouteManagerTest.kt
index 984af156d0059376039d3ce0b0d83397210c3857..d29fd75bae37f94104c8088ee9ec1d754a872c9a 100644
--- a/mailbox-core/src/test/java/org/briarproject/mailbox/core/setup/WipingWipeRouteManagerTest.kt
+++ b/mailbox-core/src/test/java/org/briarproject/mailbox/core/setup/WipingWipeRouteManagerTest.kt
@@ -41,7 +41,11 @@ class WipingWipeRouteManagerTest : IntegrationTest() {
 
         // no more files are stored
         val folderRoot = testComponent.getFileProvider().folderRoot
-        assertTrue(folderRoot.listFiles()?.isEmpty() ?: false)
+        assertFalse(folderRoot.exists())
+
+        // file root has been cleared
+        val root = testComponent.getFileProvider().root
+        assertTrue(root.listFiles()?.isEmpty() ?: false)
 
         // no more contacts in DB - contacts table is gone
         // it actually fails because db is closed though