Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Run tests screen #89

Merged
merged 5 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="#FF000000"
android:pathData="M480,616L240,376L296,320L480,504L664,320L720,376L480,616Z"/>
</vector>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="#FF000000"
android:pathData="M480,432L296,616L240,560L480,320L720,560L664,616L480,432Z"/>
</vector>
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
<string name="Dashboard_RunV2_Title">OONI Run Links</string>
<string name="Dashboard_RunV2_RunFinished">Run finished. Tap to view results.</string>

<string name="Dashboard_RunTests_Title">Run tests</string>
<string name="Dashboard_RunTests_Description">Select the tests to run</string>
<string name="Dashboard_RunTests_SelectAll">Select all tests</string>
<string name="Dashboard_RunTests_SelectNone">Deselect all tests</string>

<string name="OONIRun_Run">Run</string>
<string name="Notification_StopTest">Stop test</string>

Expand Down Expand Up @@ -193,4 +198,10 @@
<string name="notification_channel_name">Testing</string>
<string name="task_origin_manual">Manual Run</string>
<string name="task_origin_auto_run">Auto Run</string>
<string name="collapse">Collapse</string>
<string name="expand">Expand</string>
<plurals name="Dashboard_RunTests_RunButton_Label">
<item quantity="one">Run %1$d test</item>
<item quantity="other">Run %1$d tests</item>
</plurals>
</resources>
6 changes: 3 additions & 3 deletions composeApp/src/commonMain/kotlin/org/ooni/engine/Engine.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import org.ooni.engine.models.TaskEventResult
import org.ooni.engine.models.TaskOrigin
import org.ooni.engine.models.TaskSettings
import org.ooni.engine.models.resultOf
import org.ooni.probe.config.Config
import org.ooni.probe.config.OrganizationConfig
import org.ooni.probe.shared.Platform
import org.ooni.probe.shared.PlatformInfo

Expand Down Expand Up @@ -146,7 +146,7 @@ class Engine(
softwareName = buildSoftwareName(taskOrigin),
softwareVersion = platformInfo.version,
proxy = preferences.proxy,
probeServicesURL = Config.OONI_API_BASE_URL,
probeServicesURL = OrganizationConfig.ooniApiBaseUrl,
stateDir = "$baseFilePath/state",
tunnelDir = "$baseFilePath/tunnel",
tempDir = cacheDir,
Expand All @@ -156,7 +156,7 @@ class Engine(
)

private fun buildSoftwareName(taskOrigin: TaskOrigin) =
Config.BASE_SOFTWARE_NAME +
OrganizationConfig.baseSoftwareName +
"-" +
platformInfo.platform.value +
"-" +
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package org.ooni.probe.config

interface OrganizationConfigInterface {
val baseSoftwareName: String

val ooniApiBaseUrl: String
val ooniRunDashboardUrl: String

val testDisplayMode: TestDisplayMode
}

enum class TestDisplayMode {
Regular,
WebsitesOnly,
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ data class Descriptor(

val isExpired get() = expirationDate != null && expirationDate < LocalDateTime.now()

companion object {
}
val key: String
get() = when (source) {
is Source.Default -> name
is Source.Installed -> source.value.id.value.toString()
}

val allTests get() = netTests + longRunningTests
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.ooni.probe.data.models

enum class DescriptorType {
Default,
Installed,
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,26 @@ sealed interface TestRunState {

data class Running(
val descriptor: Descriptor? = null,
val descriptorIndex: Int = 0,
val testType: TestType? = null,
val estimatedRuntime: List<Duration>? = null,
val estimatedRuntimeOfDescriptors: List<Duration>? = null,
val testProgress: Double = 0.0,
val testIndex: Int = 0,
val testTotal: Int = 1,
val log: String? = "",
) : TestRunState {
val estimatedTimeLeft: Duration?
get() {
if (estimatedRuntime == null) return null
val remainingTests =
estimatedRuntime.drop(testIndex + 1)
if (estimatedRuntimeOfDescriptors == null) return null
val remainingDescriptorsEstimatedTime =
estimatedRuntimeOfDescriptors.drop(descriptorIndex + 1)
.sumOf { it.inWholeSeconds }.seconds
val remainingFromCurrentTest =
(estimatedRuntime[testIndex] * (1 - testProgress)).coerceAtLeast(0.seconds)
return remainingTests + remainingFromCurrentTest
val currentDescriptorEstimatedTime = estimatedRuntimeOfDescriptors[descriptorIndex]
val descriptorProgress = (testIndex + testProgress) / testTotal
val currentDescriptorRemainingBasedOnTest =
(currentDescriptorEstimatedTime * (1 - descriptorProgress))
.coerceAtLeast(0.seconds)
return remainingDescriptorsEstimatedTime + currentDescriptorRemainingBasedOnTest
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ sealed class PreferenceKey<T>(val preferenceKey: Preferences.Key<T>) {

class StringKey(preferenceKey: Preferences.Key<String>) : PreferenceKey<String>(preferenceKey)

class BooleanKey(preferenceKey: Preferences.Key<Boolean>) : PreferenceKey<Boolean>(preferenceKey)
class BooleanKey(preferenceKey: Preferences.Key<Boolean>) :
PreferenceKey<Boolean>(preferenceKey)

class FloatKey(preferenceKey: Preferences.Key<Float>) : PreferenceKey<Float>(preferenceKey)

Expand Down Expand Up @@ -133,18 +134,45 @@ class PreferenceRepository(
descriptor: Descriptor,
netTest: NetTest,
isAutoRun: Boolean,
): Flow<Boolean> {
val key = getPreferenceKey(
name = netTest.test.name,
prefix = (descriptor.source as? Descriptor.Source.Installed)
?.value?.id?.value?.toString(),
autoRun = isAutoRun,
)
return dataStore.data.map {
it[booleanPreferencesKey(key)] == true
): Flow<Boolean> =
dataStore.data.map {
it[booleanPreferencesKey(getNetTestKey(descriptor, netTest, isAutoRun))] == true
}

fun areNetTestsEnabled(
list: List<Pair<Descriptor, NetTest>>,
isAutoRun: Boolean,
): Flow<Map<Pair<Descriptor, NetTest>, Boolean>> =
dataStore.data.map {
list.associate { (descriptor, netTest) ->
Pair(descriptor, netTest) to
(it[booleanPreferencesKey(getNetTestKey(descriptor, netTest, isAutoRun))] == true)
}
}

suspend fun setAreNetTestsEnabled(
list: List<Pair<Descriptor, NetTest>>,
isAutoRun: Boolean,
isEnabled: Boolean,
) {
dataStore.edit {
list.forEach { (descriptor, netTest) ->
it[booleanPreferencesKey(getNetTestKey(descriptor, netTest, isAutoRun))] = isEnabled
}
}
}

private fun getNetTestKey(
descriptor: Descriptor,
netTest: NetTest,
isAutoRun: Boolean,
) = getPreferenceKey(
name = netTest.test.name,
prefix = (descriptor.source as? Descriptor.Source.Installed)
?.value?.id?.value?.toString(),
autoRun = isAutoRun,
)

suspend fun clear() {
dataStore.edit { it.clear() }
}
Expand Down
28 changes: 19 additions & 9 deletions composeApp/src/commonMain/kotlin/org/ooni/probe/di/Dependencies.kt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import org.ooni.probe.shared.PlatformInfo
import org.ooni.probe.ui.dashboard.DashboardViewModel
import org.ooni.probe.ui.result.ResultViewModel
import org.ooni.probe.ui.results.ResultsViewModel
import org.ooni.probe.ui.run.RunViewModel
import org.ooni.probe.ui.running.RunningViewModel
import org.ooni.probe.ui.settings.SettingsViewModel
import org.ooni.probe.ui.settings.about.AboutViewModel
Expand Down Expand Up @@ -234,17 +235,27 @@ class Dependencies(
fun dashboardViewModel(
goToResults: () -> Unit,
goToRunningTest: () -> Unit,
goToRunTests: () -> Unit,
) = DashboardViewModel(
goToResults = goToResults,
goToRunningTest = goToRunningTest,
goToRunTests = goToRunTests,
getTestDescriptors = getTestDescriptors::invoke,
startBackgroundRun = startBackgroundRun,
observeTestRunState = testStateManager.observeState(),
observeTestRunErrors = testStateManager.observeError(),
)

fun proxyViewModel(onBack: () -> Unit) = ProxyViewModel(onBack, preferenceRepository)

fun resultsViewModel(
goToResult: (ResultModel.Id) -> Unit,
goToUpload: () -> Unit,
) = ResultsViewModel(
goToResult = goToResult,
goToUpload = goToUpload,
getResults = getResults::invoke,
)

fun runningViewModel(
onBack: () -> Unit,
goToResults: () -> Unit,
Expand All @@ -256,14 +267,13 @@ class Dependencies(
cancelTestRun = testStateManager::cancelTestRun,
)

fun resultsViewModel(
goToResult: (ResultModel.Id) -> Unit,
goToUpload: () -> Unit,
) = ResultsViewModel(
goToResult = goToResult,
goToUpload = goToUpload,
getResults = getResults::invoke,
)
fun runViewModel(onBack: () -> Unit) =
RunViewModel(
onBack = onBack,
startBackgroundRun = startBackgroundRun,
getTestDescriptors = getTestDescriptors::invoke,
preferenceRepository = preferenceRepository,
)

fun resultViewModel(
resultId: ResultModel.Id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class RunDescriptors(
return
}
setCurrentTestState {
TestRunState.Running(estimatedRuntime = estimatedRuntime)
TestRunState.Running(estimatedRuntimeOfDescriptors = estimatedRuntime)
}

try {
Expand All @@ -63,8 +63,8 @@ class RunDescriptors(
coroutineScope {
val runJob = async {
// Actually running the descriptors
descriptors.forEach { descriptor ->
runDescriptor(descriptor, spec.taskOrigin, spec.isRerun)
descriptors.forEachIndexed { index, descriptor ->
runDescriptor(descriptor, index, spec.taskOrigin, spec.isRerun)
}
}
// Observe if a cancel request has been made
Expand Down Expand Up @@ -124,6 +124,7 @@ class RunDescriptors(

private suspend fun runDescriptor(
descriptor: Descriptor,
index: Int,
taskOrigin: TaskOrigin,
isRerun: Boolean,
) {
Expand All @@ -134,15 +135,17 @@ class RunDescriptors(
)
val resultWithId = newResult.copy(id = storeResult(newResult))

(descriptor.netTests + descriptor.longRunningTests).forEachIndexed { index, netTest ->
descriptor.allTests.forEachIndexed { testIndex, netTest ->
runNetTest(
RunNetTest.Specification(
descriptor = descriptor,
descriptorIndex = index,
netTest = netTest,
taskOrigin = taskOrigin,
isRerun = isRerun,
initialResult = resultWithId,
testIndex = index,
testIndex = testIndex,
testTotal = descriptor.allTests.size,
),
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,13 @@ class RunNetTest(
) {
data class Specification(
val descriptor: Descriptor,
val descriptorIndex: Int,
val netTest: NetTest,
val taskOrigin: TaskOrigin,
val isRerun: Boolean,
val initialResult: ResultModel,
val testIndex: Int,
val testTotal: Int,
)

private var result = spec.initialResult
Expand All @@ -52,9 +54,11 @@ class RunNetTest(
if (it !is TestRunState.Running) return@setCurrentTestState it
it.copy(
descriptor = spec.descriptor,
descriptorIndex = spec.descriptorIndex,
testType = spec.netTest.test,
testProgress = spec.testIndex * progressStep,
testIndex = spec.testIndex,
testTotal = spec.testTotal,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ fun DashboardScreen(
TestDescriptorSection(type)
}
}
items(tests) { test ->
items(tests, key = { it.key }) { test ->
TestDescriptorItem(test)
}
}
Expand Down
Loading