This repository has been archived by the owner on Nov 5, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 742
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* WIP: Backups androidTest + extract the build logic for integration testing * Make the test work * Finish the e2e integration test * WIP: Simplify the BackupDataUseCase * Refactor `IvyFileReader` * Improve the `BackupDataUseCaseAndroidTest` * Fix Detekt errors
- Loading branch information
1 parent
d41c3f5
commit afe9ce2
Showing
12 changed files
with
268 additions
and
71 deletions.
There are no files selected for viewing
19 changes: 19 additions & 0 deletions
19
buildSrc/src/main/kotlin/ivy.integration.testing.gradle.kts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
plugins { | ||
id("ivy.feature") | ||
} | ||
|
||
android { | ||
defaultConfig { | ||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" | ||
} | ||
|
||
packaging { | ||
resources.pickFirsts.add("win32-x86-64/attach_hotspot_windows.dll") | ||
resources.pickFirsts.add("win32-x86/attach_hotspot_windows.dll") | ||
resources.pickFirsts.add("META-INF/**") | ||
} | ||
} | ||
|
||
dependencies { | ||
androidTestImplementation(libs.bundles.integration.testing) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Binary file not shown.
139 changes: 139 additions & 0 deletions
139
ivy-data/src/androidTest/java/com/ivy/data/backup/BackupDataUseCaseAndroidTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
package com.ivy.data.backup | ||
|
||
import android.content.Context | ||
import android.net.Uri | ||
import androidx.core.net.toUri | ||
import androidx.room.Room | ||
import androidx.test.core.app.ApplicationProvider | ||
import androidx.test.ext.junit.runners.AndroidJUnit4 | ||
import androidx.test.platform.app.InstrumentationRegistry | ||
import com.ivy.base.di.KotlinxSerializationModule | ||
import com.ivy.base.legacy.SharedPrefs | ||
import com.ivy.data.db.IvyRoomDatabase | ||
import com.ivy.data.file.IvyFileReader | ||
import com.ivy.testing.TestDispatchersProvider | ||
import io.kotest.matchers.collections.shouldBeEmpty | ||
import io.kotest.matchers.ints.shouldBeGreaterThan | ||
import kotlinx.coroutines.runBlocking | ||
import org.junit.After | ||
import org.junit.Before | ||
import org.junit.Test | ||
import org.junit.runner.RunWith | ||
import java.io.File | ||
|
||
@RunWith(AndroidJUnit4::class) | ||
class BackupDataUseCaseAndroidTest { | ||
|
||
private lateinit var db: IvyRoomDatabase | ||
private lateinit var useCase: BackupDataUseCase | ||
|
||
@Before | ||
fun createDb() { | ||
val context = ApplicationProvider.getApplicationContext<Context>() | ||
db = Room.inMemoryDatabaseBuilder(context, IvyRoomDatabase::class.java).build() | ||
val appContext = InstrumentationRegistry.getInstrumentation().context | ||
useCase = BackupDataUseCase( | ||
accountDao = db.accountDao, | ||
budgetDao = db.budgetDao, | ||
categoryDao = db.categoryDao, | ||
loanRecordDao = db.loanRecordDao, | ||
loanDao = db.loanDao, | ||
plannedPaymentRuleDao = db.plannedPaymentRuleDao, | ||
settingsDao = db.settingsDao, | ||
transactionDao = db.transactionDao, | ||
sharedPrefs = SharedPrefs(appContext), | ||
accountWriter = db.writeAccountDao, | ||
categoryWriter = db.writeCategoryDao, | ||
transactionWriter = db.writeTransactionDao, | ||
settingsWriter = db.writeSettingsDao, | ||
budgetWriter = db.writeBudgetDao, | ||
loanWriter = db.writeLoanDao, | ||
loanRecordWriter = db.writeLoanRecordDao, | ||
plannedPaymentRuleWriter = db.writePlannedPaymentRuleDao, | ||
context = appContext, | ||
json = KotlinxSerializationModule.provideJson(), | ||
dispatchersProvider = TestDispatchersProvider, | ||
fileReader = IvyFileReader(appContext) | ||
) | ||
} | ||
|
||
@After | ||
fun closeDb() { | ||
db.close() | ||
} | ||
|
||
@Test | ||
fun backup450_150() = runBlocking { | ||
backupTestCase("450-150") | ||
} | ||
|
||
private suspend fun backupTestCase(version: String) { | ||
importBackupZipTestCase(version) | ||
importBackupJsonTestCase(version) | ||
|
||
// close and re-open the db to ensure fresh data | ||
closeDb() | ||
createDb() | ||
exportsAndImportsTestCase(version) | ||
} | ||
|
||
private suspend fun importBackupZipTestCase(version: String) { | ||
// given | ||
val backupUri = copyTestResourceToInternalStorage("backups/$version.zip") | ||
|
||
// when | ||
val res = useCase.importBackupFile(backupUri, onProgress = {}) | ||
|
||
// then | ||
res.shouldBeSuccessful() | ||
} | ||
|
||
private suspend fun importBackupJsonTestCase(version: String) { | ||
// given | ||
val backupUri = copyTestResourceToInternalStorage("backups/$version.json") | ||
|
||
// when | ||
val res = useCase.importBackupFile(backupUri, onProgress = {}) | ||
|
||
// then | ||
res.shouldBeSuccessful() | ||
} | ||
|
||
private suspend fun exportsAndImportsTestCase(version: String) { | ||
// given | ||
val backupUri = copyTestResourceToInternalStorage("backups/$version.zip") | ||
// preload data | ||
useCase.importBackupFile(backupUri, onProgress = {}).shouldBeSuccessful() | ||
val exportedFileUri = tempAndroidFile("exported", ".zip").toUri() | ||
|
||
// then | ||
useCase.exportToFile(exportedFileUri) | ||
val reImportRes = useCase.importBackupFile(backupUri, onProgress = {}) | ||
|
||
// then | ||
reImportRes.shouldBeSuccessful() | ||
} | ||
|
||
private fun copyTestResourceToInternalStorage(resPath: String): Uri { | ||
val context = InstrumentationRegistry.getInstrumentation().targetContext | ||
val assetManager = context.assets | ||
val inputStream = assetManager.open(resPath) | ||
val outputFile = tempAndroidFile("temp-backup", resPath.split(".").last()) | ||
outputFile.outputStream().use { fileOut -> | ||
fileOut.write(inputStream.readBytes()) | ||
} | ||
return Uri.fromFile(outputFile) | ||
} | ||
|
||
private fun tempAndroidFile(prefix: String, suffix: String): File { | ||
val context = InstrumentationRegistry.getInstrumentation().targetContext | ||
return File.createTempFile(prefix, suffix, context.filesDir) | ||
} | ||
|
||
private fun ImportResult.shouldBeSuccessful() { | ||
failedRows.shouldBeEmpty() | ||
categoriesImported shouldBeGreaterThan 0 | ||
accountsImported shouldBeGreaterThan 0 | ||
transactionsImported shouldBeGreaterThan 0 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package com.ivy.data.file | ||
|
||
import android.content.Context | ||
import android.net.Uri | ||
import arrow.core.Either | ||
import dagger.hilt.android.qualifiers.ApplicationContext | ||
import java.io.BufferedReader | ||
import java.io.FileInputStream | ||
import java.io.FileNotFoundException | ||
import java.io.IOException | ||
import java.io.InputStreamReader | ||
import java.nio.charset.Charset | ||
import javax.inject.Inject | ||
|
||
class IvyFileReader @Inject constructor( | ||
@ApplicationContext | ||
private val appContext: Context | ||
) { | ||
fun read( | ||
uri: Uri, | ||
charset: Charset = Charsets.UTF_8 | ||
): Either<Failure, String> { | ||
return try { | ||
val contentResolver = appContext.contentResolver | ||
var fileContent: String? = null | ||
|
||
contentResolver.openFileDescriptor(uri, "r")?.use { | ||
FileInputStream(it.fileDescriptor).use { fileInputStream -> | ||
fileContent = readFileContent( | ||
fileInputStream = fileInputStream, | ||
charset = charset | ||
) | ||
} | ||
} | ||
|
||
Either.Right(fileContent!!) | ||
} catch (e: FileNotFoundException) { | ||
Either.Left(Failure.FileNotFound(e)) | ||
} catch (e: Exception) { | ||
Either.Left(Failure.IO(e)) | ||
} | ||
} | ||
|
||
@Throws(IOException::class) | ||
private fun readFileContent( | ||
fileInputStream: FileInputStream, | ||
charset: Charset | ||
): String { | ||
BufferedReader(InputStreamReader(fileInputStream, charset)).use { br -> | ||
val sb = StringBuilder() | ||
var line: String? | ||
while (br.readLine().also { line = it } != null) { | ||
sb.append(line) | ||
sb.append('\n') | ||
} | ||
return sb.toString() | ||
} | ||
} | ||
|
||
sealed interface Failure { | ||
val e: Throwable | ||
|
||
data class FileNotFound(override val e: Throwable) : Failure | ||
data class IO(override val e: Throwable) : Failure | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 0 additions & 10 deletions
10
ivy-testing/src/main/java/com/ivy/testing/TestResourceUtil.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.