Skip to content

Commit

Permalink
Merge pull request #64 from ooni/bootstrap-dw-tests
Browse files Browse the repository at this point in the history
Run V2: Bootstrap DW tests
  • Loading branch information
sdsantos authored Aug 13, 2024
2 parents 919e117 + e0dbaac commit 809a155
Show file tree
Hide file tree
Showing 30 changed files with 641 additions and 75 deletions.
68 changes: 42 additions & 26 deletions composeApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@ val appConfig =
appName = "News Media Scan",
srcRoot = "src/dwMain/kotlin",
resRoot = "src/dwMain/resources",
composeResRoot = "src/dwMain/composeResources",
),
"ooni" to
AppConfig(
appId = "org.ooni.probe",
appName = "OONI Probe",
srcRoot = "src/ooniMain/kotlin",
resRoot = "src/ooniMain/resources",
composeResRoot = "src/ooniMain/composeResources",
),
)

Expand Down Expand Up @@ -101,9 +103,12 @@ kotlin {
}
all {
languageSettings {
optIn("kotlin.ExperimentalStdlibApi")
// optIn("kotlinx.cinterop.ExperimentalForeignApi")
optIn("kotlinx.cinterop.BetaInteropApi")
optIn("kotlinx.coroutines.ExperimentalCoroutinesApi")
optIn("androidx.compose.material3.ExperimentalMaterial3Api")
optIn("androidx.compose.foundation.ExperimentalFoundationApi")
optIn("androidx.compose.material3.ExperimentalMaterial3Api")
optIn("androidx.compose.ui.test.ExperimentalTestApi")
}
}
Expand Down Expand Up @@ -161,14 +166,18 @@ android {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
sourceSets["main"].resources.setSrcDirs(
listOf(
"src/androidMain/resources",
"src/commonMain/resources",
),
)
dependencies {
debugImplementation(compose.uiTooling)
}
android {
lint {
warningsAsErrors = true
disable += listOf("AndroidGradlePluginVersion", "ObsoleteLintCustomCheck")
}
lint {
warningsAsErrors = true
disable += listOf("AndroidGradlePluginVersion", "ObsoleteLintCustomCheck")
}
}

Expand Down Expand Up @@ -209,37 +218,43 @@ tasks {
tasks.register("copyBrandingToCommonResources") {
doLast {
val projectDir = project.projectDir.absolutePath

val destinationFile = File(projectDir, "src/commonMain/composeResources")

val sourceFile = File(projectDir, config.resRoot)

copyRecursive(sourceFile, destinationFile)
copyRecursive(
from = File(projectDir, config.resRoot),
to = File(projectDir, "src/commonMain/resources"),
)
copyRecursive(
from = File(projectDir, config.composeResRoot),
to = File(projectDir, "src/commonMain/composeResources"),
)
}
}

tasks.register("cleanCopiedCommonResourcesToFlavor") {
doLast {
val projectDir = project.projectDir.absolutePath

val destinationFile = File(projectDir, "src/commonMain/composeResources")
destinationFile.listFiles()?.forEach { folder ->
folder.listFiles()?.forEach { file ->
if (file.name == ".gitignore") {
file
.readText()
.lines()
.forEach { line ->
if (line.isNotEmpty()) {
println("Removing $line")
File(folder, line).deleteRecursively()
fun deleteFilesFromGitIgnore(folderPath: String) {
val destinationFile = File(projectDir, folderPath)
destinationFile.listFiles()?.forEach { folder ->
folder.listFiles()?.forEach { file ->
if (file.name == ".gitignore") {
file
.readText()
.lines()
.forEach { line ->
if (line.isNotEmpty()) {
println("Removing $line")
File(folder, line).deleteRecursively()
}
}.also {
file.delete()
}
}.also {
file.delete()
}
}
}
}
}
deleteFilesFromGitIgnore("src/commonMain/composeResources")
deleteFilesFromGitIgnore("src/commonMain/resources")
}
}

Expand All @@ -266,6 +281,7 @@ data class AppConfig(
val appName: String,
val srcRoot: String,
val resRoot: String,
val composeResRoot: String,
)

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class AndroidApplication : Application() {
oonimkallBridge = AndroidOonimkallBridge(),
baseFileDir = filesDir.absolutePath,
cacheDir = cacheDir.absolutePath,
readAssetFile = ::readAssetFile,
databaseDriverFactory = ::buildDatabaseDriver,
networkTypeFinder =
AndroidNetworkTypeFinder(getSystemService(ConnectivityManager::class.java)),
Expand All @@ -38,4 +39,6 @@ class AndroidApplication : Application() {
}

private fun buildDatabaseDriver(): SqlDriver = AndroidSqliteDriver(Database.Schema, this, "v2")

private fun readAssetFile(path: String) = assets.open(path).bufferedReader().use { it.readText() }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.ooni.engine.models

import kotlinx.datetime.Instant
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import org.ooni.probe.data.models.NetTest

/**
* This class represents the response from a fetch request to the OONI API.
*
* @see [https://github.com/ooni/spec/blob/master/backends/bk-005-ooni-run-v2.md]
*/
@Serializable
data class OONIRunDescriptor(
@SerialName("oonirun_link_id") val oonirunLinkId: Long,
@SerialName("name") val name: String,
@SerialName("short_description") val shortDescription: String,
@SerialName("description") val description: String,
@SerialName("author") val author: String,
@SerialName("nettests") val netTests: List<NetTest>,
@SerialName("name_intl") val nameIntl: Map<String, String>,
@SerialName("short_description_intl") val shortDescriptionIntl: Map<String, String>,
@SerialName("description_intl") val descriptionIntl: Map<String, String>,
@SerialName("icon") val icon: String,
@SerialName("color") val color: String,
@SerialName("animation") val animation: String? = null,
@SerialName("expiration_date") val expirationDate: Instant,
@SerialName("date_created") val dateCreated: Instant,
@SerialName("date_updated") val dateUpdated: Instant,
@SerialName("revision") val revision: String,
@SerialName("is_expired") val isExpired: Boolean,
)
1 change: 1 addition & 0 deletions composeApp/src/commonMain/kotlin/org/ooni/probe/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ fun App(dependencies: Dependencies) {

LaunchedEffect(Unit) {
logAppStart(dependencies)
dependencies.bootstrapTestDescriptors()
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import kotlinx.serialization.Serializable

@Serializable
data class NetTest(
@SerialName("test_name")
val name: String,
val inputs: List<String>? = null,
@SerialName("test_name") val name: String,
@SerialName("inputs") val inputs: List<String>? = null,
)
Original file line number Diff line number Diff line change
Expand Up @@ -24,29 +24,33 @@ class TestDescriptorRepository(
.mapToList(backgroundDispatcher)
.map { list -> list.mapNotNull { it.toModel() } }

suspend fun create(model: InstalledTestDescriptorModel) {
suspend fun createOrIgnore(models: List<InstalledTestDescriptorModel>) {
withContext(backgroundDispatcher) {
database.testDescriptorQueries.insert(
runId = model.id.value,
name = model.name,
short_description = model.shortDescription,
description = model.description,
author = model.author,
nettests = json.encodeToString(model.netTests),
name_intl = json.encodeToString(model.nameIntl),
short_description_intl = json.encodeToString(model.shortDescriptionIntl),
description_intl = json.encodeToString(model.descriptionIntl),
icon = model.icon,
color = model.color,
animation = model.animation,
expiration_date = model.expirationDate?.toEpochMilliseconds(),
date_created = model.dateCreated?.toEpochMilliseconds(),
date_updated = model.dateUpdated?.toEpochMilliseconds(),
revision = model.revision,
previous_revision = null,
is_expired = if (model.isExpired) 1 else 0,
auto_update = if (model.autoUpdate) 1 else 0,
)
database.transaction {
models.forEach { model ->
database.testDescriptorQueries.insertOrIgnore(
runId = model.id.value,
name = model.name,
short_description = model.shortDescription,
description = model.description,
author = model.author,
nettests = json.encodeToString(model.netTests),
name_intl = json.encodeToString(model.nameIntl),
short_description_intl = json.encodeToString(model.shortDescriptionIntl),
description_intl = json.encodeToString(model.descriptionIntl),
icon = model.icon,
color = model.color,
animation = model.animation,
expiration_date = model.expirationDate?.toEpochMilliseconds(),
date_created = model.dateCreated?.toEpochMilliseconds(),
date_updated = model.dateUpdated?.toEpochMilliseconds(),
revision = model.revision,
previous_revision = null,
is_expired = if (model.isExpired) 1 else 0,
auto_update = if (model.autoUpdate) 1 else 0,
)
}
}
}
}

Expand Down
12 changes: 12 additions & 0 deletions composeApp/src/commonMain/kotlin/org/ooni/probe/di/Dependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import org.ooni.probe.Database
import org.ooni.probe.data.models.ResultModel
import org.ooni.probe.data.repositories.ResultRepository
import org.ooni.probe.data.repositories.TestDescriptorRepository
import org.ooni.probe.domain.BootstrapTestDescriptors
import org.ooni.probe.domain.GetBootstrapTestDescriptors
import org.ooni.probe.domain.GetDefaultTestDescriptors
import org.ooni.probe.domain.GetResult
import org.ooni.probe.domain.GetResults
Expand All @@ -27,6 +29,7 @@ class Dependencies(
private val oonimkallBridge: OonimkallBridge,
private val baseFileDir: String,
private val cacheDir: String,
private val readAssetFile: (String) -> String,
private val databaseDriverFactory: () -> SqlDriver,
private val networkTypeFinder: NetworkTypeFinder,
) {
Expand Down Expand Up @@ -62,6 +65,15 @@ class Dependencies(

// Domain

val bootstrapTestDescriptors by lazy {
BootstrapTestDescriptors(
getBootstrapTestDescriptors = getBootstrapTestDescriptors::invoke,
createOrIgnoreTestDescriptors = testDescriptorRepository::createOrIgnore,
)
}
private val getBootstrapTestDescriptors by lazy {
GetBootstrapTestDescriptors(readAssetFile, json, backgroundDispatcher)
}
private val getDefaultTestDescriptors by lazy { GetDefaultTestDescriptors() }
private val getResults by lazy { GetResults(resultRepository) }
private val getResult by lazy { GetResult(resultRepository) }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.ooni.probe.domain

import org.ooni.probe.data.models.InstalledTestDescriptorModel

class BootstrapTestDescriptors(
private val getBootstrapTestDescriptors: suspend () -> List<InstalledTestDescriptorModel>,
private val createOrIgnoreTestDescriptors: suspend (List<InstalledTestDescriptorModel>) -> Unit,
) {
suspend operator fun invoke() {
createOrIgnoreTestDescriptors(getBootstrapTestDescriptors())
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.ooni.probe.domain

import androidx.compose.ui.graphics.Color
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.asFlow
import kotlinx.coroutines.flow.flatMapLatest
Expand All @@ -10,6 +9,7 @@ import org.ooni.probe.data.models.DefaultTestDescriptor
import org.ooni.probe.data.models.Descriptor
import org.ooni.probe.data.models.InstalledTestDescriptorModel
import org.ooni.probe.data.models.getCurrent
import org.ooni.probe.shared.hexToColor

class GetTestDescriptors(
private val getDefaultTestDescriptors: () -> List<DefaultTestDescriptor>,
Expand Down Expand Up @@ -50,7 +50,7 @@ class GetTestDescriptors(
description = { descriptionIntl?.getCurrent() ?: description },
// TODO: fetch drawable resource from path
icon = null,
color = color?.filter { it != '#' }?.toIntOrNull()?.let { Color(it) },
color = color?.hexToColor(),
animation = animation,
dataUsage = { null },
netTests = netTests.orEmpty(),
Expand Down
14 changes: 14 additions & 0 deletions composeApp/src/commonMain/kotlin/org/ooni/probe/shared/ColorExt.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.ooni.probe.shared

import androidx.compose.ui.graphics.Color

fun String.hexToColor(): Color {
val baseNumber = filter { it != '#' }
val fullNumber =
if (baseNumber.length == 6) {
"FF$baseNumber"
} else {
baseNumber
}
return Color(fullNumber.hexToInt())
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ fun DashboardScreen(
}

LazyColumn {
val allSectionsHaveValues = state.tests.entries.all { it.value.any() }
state.tests.forEach { (type, tests) ->
if (state.tests.keys.size > 1 && tests.isNotEmpty()) {
if (allSectionsHaveValues && tests.isNotEmpty()) {
item(type) {
TestDescriptorItem(type)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import ooniprobe.composeapp.generated.resources.Res
import ooniprobe.composeapp.generated.resources.ic_chevron_right
import ooniprobe.composeapp.generated.resources.logo
import ooniprobe.composeapp.generated.resources.ic_settings
import org.jetbrains.compose.resources.painterResource
import org.ooni.probe.data.models.Descriptor

Expand All @@ -40,7 +40,8 @@ fun TestDescriptorItem(descriptor: Descriptor) {
modifier = Modifier.padding(bottom = 2.dp),
) {
Icon(
painter = painterResource(descriptor.icon ?: Res.drawable.logo),
// TODO: pick better fallback icon
painter = painterResource(descriptor.icon ?: Res.drawable.ic_settings),
contentDescription = null,
tint = descriptor.color ?: MaterialTheme.colorScheme.onSurface,
modifier =
Expand All @@ -50,7 +51,7 @@ fun TestDescriptorItem(descriptor: Descriptor) {
)
Text(
descriptor.title(),
style = MaterialTheme.typography.titleLarge,
style = MaterialTheme.typography.titleMedium,
)
}
descriptor.shortDescription()?.let { shortDescription ->
Expand Down
2 changes: 2 additions & 0 deletions composeApp/src/commonMain/resources/assets/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

descriptors.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ CREATE TABLE TestDescriptor (
PRIMARY KEY(`runId`)
);

insert:
INSERT INTO TestDescriptor (
insertOrIgnore:
INSERT OR IGNORE INTO TestDescriptor (
runId,
name,
short_description,
Expand Down
Loading

0 comments on commit 809a155

Please sign in to comment.