Localize Troubleshoot notification feature.

This commit is contained in:
Benoit Marty 2024-03-27 18:16:47 +01:00 committed by Benoit Marty
parent 37712298c5
commit a3253bbe5c
26 changed files with 221 additions and 64 deletions

View file

@ -166,10 +166,10 @@ private fun NotificationSettingsContentView(
onCheckedChange = onInviteForMeNotificationsChanged onCheckedChange = onInviteForMeNotificationsChanged
) )
} }
PreferenceCategory(title = "Troubleshoot") { PreferenceCategory(title = stringResource(id = R.string.troubleshoot_notifications_entry_point_section)) {
PreferenceText( PreferenceText(
modifier = Modifier, modifier = Modifier,
title = "Troubleshoot notifications", title = stringResource(id = R.string.troubleshoot_notifications_entry_point_title),
onClick = onTroubleshootNotificationsClicked onClick = onTroubleshootNotificationsClicked
) )
} }

View file

@ -21,11 +21,13 @@ import androidx.compose.foundation.layout.size
import androidx.compose.foundation.progressSemantics import androidx.compose.foundation.progressSemantics
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.preferences.impl.R
import io.element.android.libraries.architecture.AsyncAction import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState
import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState.Status import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState.Status
@ -63,7 +65,7 @@ fun TroubleshootNotificationsView(
PreferencePage( PreferencePage(
modifier = modifier, modifier = modifier,
onBackPressed = onBackPressed, onBackPressed = onBackPressed,
title = "Troubleshoot notifications", title = stringResource(id = R.string.troubleshoot_notifications_screen_title),
) { ) {
TroubleshootNotificationsContent(state) TroubleshootNotificationsContent(state)
} }
@ -120,7 +122,7 @@ private fun TroubleshootTestView(
}, },
trailingContent = ListItemContent.Custom { trailingContent = ListItemContent.Custom {
Button( Button(
text = "Attempt to fix", text = stringResource(id = R.string.troubleshoot_notifications_screen_quick_fix_action),
onClick = onQuickFixClicked onClick = onQuickFixClicked
) )
} }
@ -148,8 +150,7 @@ private fun TroubleshootNotificationsContent(state: TroubleshootNotificationsSta
AsyncAction.Uninitialized -> { AsyncAction.Uninitialized -> {
ListItem(headlineContent = { ListItem(headlineContent = {
Text( Text(
text = "Run the tests to detect any issue in your configuration " + text = stringResource(id = R.string.troubleshoot_notifications_screen_notice)
"that may make notifications not behave as expected."
) )
}) })
RunTestButton(state = state) RunTestButton(state = state)
@ -157,21 +158,21 @@ private fun TroubleshootNotificationsContent(state: TroubleshootNotificationsSta
AsyncAction.Loading -> Unit AsyncAction.Loading -> Unit
is AsyncAction.Failure -> { is AsyncAction.Failure -> {
ListItem(headlineContent = { ListItem(headlineContent = {
Text(text = "Some tests failed, please check the details.") Text(text = stringResource(id = R.string.troubleshoot_notifications_screen_failure))
}) })
RunTestButton(state = state) RunTestButton(state = state)
} }
AsyncAction.Confirming -> { AsyncAction.Confirming -> {
ListItem(headlineContent = { ListItem(headlineContent = {
Text( Text(
text = "Some tests require your attention. Please check the details." text = stringResource(id = R.string.troubleshoot_notifications_screen_waiting)
) )
}) })
} }
is AsyncAction.Success -> { is AsyncAction.Success -> {
ListItem(headlineContent = { ListItem(headlineContent = {
Text( Text(
text = "All tests passed successfully." text = stringResource(id = R.string.troubleshoot_notifications_screen_success)
) )
}) })
} }
@ -183,7 +184,12 @@ private fun RunTestButton(state: TroubleshootNotificationsState) {
ListItem( ListItem(
headlineContent = { headlineContent = {
Button( Button(
text = if (state.testSuiteState.mainState is AsyncAction.Failure) "Run tests again" else "Run tests", text = stringResource(
id = if (state.testSuiteState.mainState is AsyncAction.Failure)
R.string.troubleshoot_notifications_screen_action_again
else
R.string.troubleshoot_notifications_screen_action
),
onClick = { onClick = {
state.eventSink(TroubleshootNotificationsEvents.StartTests) state.eventSink(TroubleshootNotificationsEvents.StartTests)
}, },

View file

@ -49,4 +49,14 @@ If you proceed, some of your settings may change."</string>
<string name="screen_notification_settings_system_notifications_action_required_content_link">"system settings"</string> <string name="screen_notification_settings_system_notifications_action_required_content_link">"system settings"</string>
<string name="screen_notification_settings_system_notifications_turned_off">"System notifications turned off"</string> <string name="screen_notification_settings_system_notifications_turned_off">"System notifications turned off"</string>
<string name="screen_notification_settings_title">"Notifications"</string> <string name="screen_notification_settings_title">"Notifications"</string>
<string name="troubleshoot_notifications_entry_point_section">"Troubleshoot"</string>
<string name="troubleshoot_notifications_entry_point_title">"Troubleshoot notifications"</string>
<string name="troubleshoot_notifications_screen_action">"Run tests"</string>
<string name="troubleshoot_notifications_screen_action_again">"Run tests again"</string>
<string name="troubleshoot_notifications_screen_failure">"Some tests failed. Please check the details."</string>
<string name="troubleshoot_notifications_screen_notice">"Run the tests to detect any issue in your configuration that may make notifications not behave as expected."</string>
<string name="troubleshoot_notifications_screen_quick_fix_action">"Attempt to fix"</string>
<string name="troubleshoot_notifications_screen_success">"All tests passed successfully."</string>
<string name="troubleshoot_notifications_screen_title">"Troubleshoot notifications"</string>
<string name="troubleshoot_notifications_screen_waiting">"Some tests require your attention. Please check the details."</string>
</resources> </resources>

View file

@ -24,8 +24,10 @@ import io.element.android.libraries.core.notifications.NotificationTroubleshootT
import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState
import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.AppScope
import io.element.android.libraries.permissions.api.PermissionStateProvider import io.element.android.libraries.permissions.api.PermissionStateProvider
import io.element.android.libraries.permissions.impl.R
import io.element.android.libraries.permissions.impl.action.PermissionActions import io.element.android.libraries.permissions.impl.action.PermissionActions
import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider import io.element.android.services.toolbox.api.sdk.BuildVersionSdkIntProvider
import io.element.android.services.toolbox.api.strings.StringProvider
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject import javax.inject.Inject
@ -35,12 +37,13 @@ class NotificationTroubleshootCheckPermissionTest @Inject constructor(
private val permissionStateProvider: PermissionStateProvider, private val permissionStateProvider: PermissionStateProvider,
private val sdkVersionProvider: BuildVersionSdkIntProvider, private val sdkVersionProvider: BuildVersionSdkIntProvider,
private val permissionActions: PermissionActions, private val permissionActions: PermissionActions,
private val stringProvider: StringProvider,
) : NotificationTroubleshootTest { ) : NotificationTroubleshootTest {
override val order: Int = 0 override val order: Int = 0
private val delegate = NotificationTroubleshootTestDelegate( private val delegate = NotificationTroubleshootTestDelegate(
defaultName = "Check permissions", defaultName = stringProvider.getString(R.string.troubleshoot_notifications_test_check_permission_title),
defaultDescription = "Ensure that the application can show notifications.", defaultDescription = stringProvider.getString(R.string.troubleshoot_notifications_test_check_permission_description),
hasQuickFix = true, hasQuickFix = true,
fakeDelay = NotificationTroubleshootTestDelegate.SHORT_DELAY, fakeDelay = NotificationTroubleshootTestDelegate.SHORT_DELAY,
) )

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="troubleshoot_notifications_test_check_permission_description">"Ensure that the application can show notifications."</string>
<string name="troubleshoot_notifications_test_check_permission_title">"Check permissions"</string>
</resources>

View file

@ -23,6 +23,7 @@ import io.element.android.libraries.core.notifications.NotificationTroubleshootT
import io.element.android.libraries.permissions.impl.FakePermissionStateProvider import io.element.android.libraries.permissions.impl.FakePermissionStateProvider
import io.element.android.libraries.permissions.impl.action.FakePermissionActions import io.element.android.libraries.permissions.impl.action.FakePermissionActions
import io.element.android.services.toolbox.test.sdk.FakeBuildVersionSdkIntProvider import io.element.android.services.toolbox.test.sdk.FakeBuildVersionSdkIntProvider
import io.element.android.services.toolbox.test.strings.FakeStringProvider
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
@ -33,7 +34,8 @@ class NotificationTroubleshootCheckPermissionTestTest {
val sut = NotificationTroubleshootCheckPermissionTest( val sut = NotificationTroubleshootCheckPermissionTest(
permissionStateProvider = FakePermissionStateProvider(), permissionStateProvider = FakePermissionStateProvider(),
sdkVersionProvider = FakeBuildVersionSdkIntProvider(sdkInt = Build.VERSION_CODES.TIRAMISU - 1), sdkVersionProvider = FakeBuildVersionSdkIntProvider(sdkInt = Build.VERSION_CODES.TIRAMISU - 1),
permissionActions = FakePermissionActions() permissionActions = FakePermissionActions(),
stringProvider = FakeStringProvider(),
) )
launch { launch {
sut.run(this) sut.run(this)
@ -51,7 +53,8 @@ class NotificationTroubleshootCheckPermissionTestTest {
val sut = NotificationTroubleshootCheckPermissionTest( val sut = NotificationTroubleshootCheckPermissionTest(
permissionStateProvider = FakePermissionStateProvider(), permissionStateProvider = FakePermissionStateProvider(),
sdkVersionProvider = FakeBuildVersionSdkIntProvider(sdkInt = Build.VERSION_CODES.TIRAMISU), sdkVersionProvider = FakeBuildVersionSdkIntProvider(sdkInt = Build.VERSION_CODES.TIRAMISU),
permissionActions = FakePermissionActions() permissionActions = FakePermissionActions(),
stringProvider = FakeStringProvider(),
) )
launch { launch {
sut.run(this) sut.run(this)
@ -77,7 +80,8 @@ class NotificationTroubleshootCheckPermissionTestTest {
val sut = NotificationTroubleshootCheckPermissionTest( val sut = NotificationTroubleshootCheckPermissionTest(
permissionStateProvider = permissionStateProvider, permissionStateProvider = permissionStateProvider,
sdkVersionProvider = FakeBuildVersionSdkIntProvider(sdkInt = Build.VERSION_CODES.TIRAMISU), sdkVersionProvider = FakeBuildVersionSdkIntProvider(sdkInt = Build.VERSION_CODES.TIRAMISU),
permissionActions = actions permissionActions = actions,
stringProvider = FakeStringProvider(),
) )
launch { launch {
sut.run(this) sut.run(this)

View file

@ -22,6 +22,8 @@ import io.element.android.libraries.core.notifications.NotificationTroubleshootT
import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState
import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.AppScope
import io.element.android.libraries.push.api.GetCurrentPushProvider import io.element.android.libraries.push.api.GetCurrentPushProvider
import io.element.android.libraries.push.impl.R
import io.element.android.services.toolbox.api.strings.StringProvider
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject import javax.inject.Inject
@ -29,11 +31,12 @@ import javax.inject.Inject
@ContributesMultibinding(AppScope::class) @ContributesMultibinding(AppScope::class)
class CurrentPushProviderTest @Inject constructor( class CurrentPushProviderTest @Inject constructor(
private val getCurrentPushProvider: GetCurrentPushProvider, private val getCurrentPushProvider: GetCurrentPushProvider,
private val stringProvider: StringProvider,
) : NotificationTroubleshootTest { ) : NotificationTroubleshootTest {
override val order = 110 override val order = 110
private val delegate = NotificationTroubleshootTestDelegate( private val delegate = NotificationTroubleshootTestDelegate(
defaultName = "Current push provider", defaultName = stringProvider.getString(R.string.troubleshoot_notifications_test_current_push_provider_title),
defaultDescription = "Get the name of the current provider.", defaultDescription = stringProvider.getString(R.string.troubleshoot_notifications_test_current_push_provider_description),
fakeDelay = NotificationTroubleshootTestDelegate.SHORT_DELAY, fakeDelay = NotificationTroubleshootTestDelegate.SHORT_DELAY,
) )
override val state: StateFlow<NotificationTroubleshootTestState> = delegate.state override val state: StateFlow<NotificationTroubleshootTestState> = delegate.state
@ -43,12 +46,12 @@ class CurrentPushProviderTest @Inject constructor(
val provider = getCurrentPushProvider.getCurrentPushProvider() val provider = getCurrentPushProvider.getCurrentPushProvider()
if (provider != null) { if (provider != null) {
delegate.updateState( delegate.updateState(
description = "Current push provider: $provider", description = stringProvider.getString(R.string.troubleshoot_notifications_test_current_push_provider_success, provider),
status = NotificationTroubleshootTestState.Status.Success status = NotificationTroubleshootTestState.Status.Success
) )
} else { } else {
delegate.updateState( delegate.updateState(
description = "No push providers selected", description = stringProvider.getString(R.string.troubleshoot_notifications_test_current_push_provider_failure),
status = NotificationTroubleshootTestState.Status.Failure(false) status = NotificationTroubleshootTestState.Status.Failure(false)
) )
} }

View file

@ -21,8 +21,10 @@ import io.element.android.libraries.core.notifications.NotificationTroubleshootT
import io.element.android.libraries.core.notifications.NotificationTroubleshootTestDelegate import io.element.android.libraries.core.notifications.NotificationTroubleshootTestDelegate
import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState
import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.AppScope
import io.element.android.libraries.push.impl.R
import io.element.android.libraries.push.impl.notifications.NotificationDisplayer import io.element.android.libraries.push.impl.notifications.NotificationDisplayer
import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator import io.element.android.libraries.push.impl.notifications.factories.NotificationCreator
import io.element.android.services.toolbox.api.strings.StringProvider
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
@ -36,12 +38,13 @@ import kotlin.time.Duration.Companion.seconds
class NotificationTest @Inject constructor( class NotificationTest @Inject constructor(
private val notificationCreator: NotificationCreator, private val notificationCreator: NotificationCreator,
private val notificationDisplayer: NotificationDisplayer, private val notificationDisplayer: NotificationDisplayer,
private val notificationClickHandler: NotificationClickHandler private val notificationClickHandler: NotificationClickHandler,
private val stringProvider: StringProvider,
) : NotificationTroubleshootTest { ) : NotificationTroubleshootTest {
override val order = 50 override val order = 50
private val delegate = NotificationTroubleshootTestDelegate( private val delegate = NotificationTroubleshootTestDelegate(
defaultName = "Display notification", defaultName = stringProvider.getString(R.string.troubleshoot_notifications_test_display_notification_title),
defaultDescription = "Check that the application can display notification", defaultDescription = stringProvider.getString(R.string.troubleshoot_notifications_test_display_notification_description),
fakeDelay = NotificationTroubleshootTestDelegate.SHORT_DELAY, fakeDelay = NotificationTroubleshootTestDelegate.SHORT_DELAY,
) )
override val state: StateFlow<NotificationTroubleshootTestState> = delegate.state override val state: StateFlow<NotificationTroubleshootTestState> = delegate.state
@ -53,12 +56,12 @@ class NotificationTest @Inject constructor(
if (result) { if (result) {
coroutineScope.listenToNotificationClick() coroutineScope.listenToNotificationClick()
delegate.updateState( delegate.updateState(
description = "Please click on the notification to continue the test.", description = stringProvider.getString(R.string.troubleshoot_notifications_test_display_notification_waiting),
status = NotificationTroubleshootTestState.Status.WaitingForUser status = NotificationTroubleshootTestState.Status.WaitingForUser
) )
} else { } else {
delegate.updateState( delegate.updateState(
description = "Cannot display the notification.", description = stringProvider.getString(R.string.troubleshoot_notifications_test_display_notification_permission_failure),
status = NotificationTroubleshootTestState.Status.Failure(false) status = NotificationTroubleshootTestState.Status.Failure(false)
) )
} }
@ -76,12 +79,12 @@ class NotificationTest @Inject constructor(
if (s == null) { if (s == null) {
notificationDisplayer.dismissDiagnosticNotification() notificationDisplayer.dismissDiagnosticNotification()
delegate.updateState( delegate.updateState(
description = "The notification has not been clicked.", description = stringProvider.getString(R.string.troubleshoot_notifications_test_display_notification_failure),
status = NotificationTroubleshootTestState.Status.Failure(false) status = NotificationTroubleshootTestState.Status.Failure(false)
) )
} else { } else {
delegate.updateState( delegate.updateState(
description = "The notification has been clicked!", description = stringProvider.getString(R.string.troubleshoot_notifications_test_display_notification_success),
status = NotificationTroubleshootTestState.Status.Success status = NotificationTroubleshootTestState.Status.Success
) )
} }

View file

@ -23,6 +23,8 @@ import io.element.android.libraries.core.notifications.NotificationTroubleshootT
import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.AppScope
import io.element.android.libraries.push.api.PushService import io.element.android.libraries.push.api.PushService
import io.element.android.libraries.push.api.gateway.PushGatewayFailure import io.element.android.libraries.push.api.gateway.PushGatewayFailure
import io.element.android.libraries.push.impl.R
import io.element.android.services.toolbox.api.strings.StringProvider
import io.element.android.services.toolbox.api.systemclock.SystemClock import io.element.android.services.toolbox.api.systemclock.SystemClock
import kotlinx.coroutines.CompletableDeferred import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
@ -39,11 +41,12 @@ class PushLoopbackTest @Inject constructor(
private val pushService: PushService, private val pushService: PushService,
private val diagnosticPushHandler: DiagnosticPushHandler, private val diagnosticPushHandler: DiagnosticPushHandler,
private val clock: SystemClock, private val clock: SystemClock,
private val stringProvider: StringProvider,
) : NotificationTroubleshootTest { ) : NotificationTroubleshootTest {
override val order = 500 override val order = 500
private val delegate = NotificationTroubleshootTestDelegate( private val delegate = NotificationTroubleshootTestDelegate(
defaultName = "Test Push loopback", defaultName = stringProvider.getString(R.string.troubleshoot_notifications_test_push_loop_back_title),
defaultDescription = "Ensure that the application is receiving push.", defaultDescription = stringProvider.getString(R.string.troubleshoot_notifications_test_push_loop_back_description),
) )
override val state: StateFlow<NotificationTroubleshootTestState> = delegate.state override val state: StateFlow<NotificationTroubleshootTestState> = delegate.state
@ -59,7 +62,7 @@ class PushLoopbackTest @Inject constructor(
pushService.testPush() pushService.testPush()
} catch (pusherRejected: PushGatewayFailure.PusherRejected) { } catch (pusherRejected: PushGatewayFailure.PusherRejected) {
delegate.updateState( delegate.updateState(
description = "Error: pusher has rejected the request.", description = stringProvider.getString(R.string.troubleshoot_notifications_test_push_loop_back_failure_1),
status = NotificationTroubleshootTestState.Status.Failure(false) status = NotificationTroubleshootTestState.Status.Failure(false)
) )
job.cancel() job.cancel()
@ -67,7 +70,7 @@ class PushLoopbackTest @Inject constructor(
} catch (e: Exception) { } catch (e: Exception) {
Timber.e(e, "Failed to test push") Timber.e(e, "Failed to test push")
delegate.updateState( delegate.updateState(
description = "Error: ${e.message}.", description = stringProvider.getString(R.string.troubleshoot_notifications_test_push_loop_back_failure_2, e.message),
status = NotificationTroubleshootTestState.Status.Failure(false) status = NotificationTroubleshootTestState.Status.Failure(false)
) )
job.cancel() job.cancel()
@ -75,7 +78,7 @@ class PushLoopbackTest @Inject constructor(
} }
if (!testPushResult) { if (!testPushResult) {
delegate.updateState( delegate.updateState(
description = "Error, cannot test push.", description = stringProvider.getString(R.string.troubleshoot_notifications_test_push_loop_back_failure_3),
status = NotificationTroubleshootTestState.Status.Failure(false) status = NotificationTroubleshootTestState.Status.Failure(false)
) )
job.cancel() job.cancel()
@ -87,12 +90,12 @@ class PushLoopbackTest @Inject constructor(
job.cancel() job.cancel()
if (result == null) { if (result == null) {
delegate.updateState( delegate.updateState(
description = "Error, timeout waiting for push.", description = stringProvider.getString(R.string.troubleshoot_notifications_test_push_loop_back_failure_4),
status = NotificationTroubleshootTestState.Status.Failure(false) status = NotificationTroubleshootTestState.Status.Failure(false)
) )
} else { } else {
delegate.updateState( delegate.updateState(
description = "Push loopback took $result ms", description = stringProvider.getString(R.string.troubleshoot_notifications_test_push_loop_back_success, result),
status = NotificationTroubleshootTestState.Status.Success status = NotificationTroubleshootTestState.Status.Success
) )
} }

View file

@ -21,7 +21,9 @@ import io.element.android.libraries.core.notifications.NotificationTroubleshootT
import io.element.android.libraries.core.notifications.NotificationTroubleshootTestDelegate import io.element.android.libraries.core.notifications.NotificationTroubleshootTestDelegate
import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState
import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.AppScope
import io.element.android.libraries.push.impl.R
import io.element.android.libraries.pushproviders.api.PushProvider import io.element.android.libraries.pushproviders.api.PushProvider
import io.element.android.services.toolbox.api.strings.StringProvider
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject import javax.inject.Inject
@ -29,12 +31,13 @@ import javax.inject.Inject
@ContributesMultibinding(AppScope::class) @ContributesMultibinding(AppScope::class)
class PushProvidersTest @Inject constructor( class PushProvidersTest @Inject constructor(
pushProviders: Set<@JvmSuppressWildcards PushProvider>, pushProviders: Set<@JvmSuppressWildcards PushProvider>,
private val stringProvider: StringProvider,
) : NotificationTroubleshootTest { ) : NotificationTroubleshootTest {
private val sortedPushProvider = pushProviders.sortedBy { it.index } private val sortedPushProvider = pushProviders.sortedBy { it.index }
override val order = 100 override val order = 100
private val delegate = NotificationTroubleshootTestDelegate( private val delegate = NotificationTroubleshootTestDelegate(
defaultName = "Detect push providers", defaultName = stringProvider.getString(R.string.troubleshoot_notifications_test_detect_push_provider_title),
defaultDescription = "Ensure that the application has at least one push provider.", defaultDescription = stringProvider.getString(R.string.troubleshoot_notifications_test_detect_push_provider_description),
fakeDelay = NotificationTroubleshootTestDelegate.SHORT_DELAY, fakeDelay = NotificationTroubleshootTestDelegate.SHORT_DELAY,
) )
override val state: StateFlow<NotificationTroubleshootTestState> = delegate.state override val state: StateFlow<NotificationTroubleshootTestState> = delegate.state
@ -44,12 +47,17 @@ class PushProvidersTest @Inject constructor(
val result = sortedPushProvider.isNotEmpty() val result = sortedPushProvider.isNotEmpty()
if (result) { if (result) {
delegate.updateState( delegate.updateState(
description = "Found ${sortedPushProvider.size} push providers: ${sortedPushProvider.joinToString { it.name }}", description = stringProvider.getQuantityString(
resId = R.plurals.troubleshoot_notifications_test_detect_push_provider_success,
quantity = sortedPushProvider.size,
sortedPushProvider.size,
sortedPushProvider.joinToString { it.name }
),
status = NotificationTroubleshootTestState.Status.Success status = NotificationTroubleshootTestState.Status.Success
) )
} else { } else {
delegate.updateState( delegate.updateState(
description = "No push providers found", description = stringProvider.getString(R.string.troubleshoot_notifications_test_detect_push_provider_failure),
status = NotificationTroubleshootTestState.Status.Failure(false) status = NotificationTroubleshootTestState.Status.Failure(false)
) )
} }

View file

@ -50,4 +50,28 @@
<string name="push_distributor_background_sync_android">"Background synchronization"</string> <string name="push_distributor_background_sync_android">"Background synchronization"</string>
<string name="push_distributor_firebase_android">"Google Services"</string> <string name="push_distributor_firebase_android">"Google Services"</string>
<string name="push_no_valid_google_play_services_apk_android">"No valid Google Play Services found. Notifications may not work properly."</string> <string name="push_no_valid_google_play_services_apk_android">"No valid Google Play Services found. Notifications may not work properly."</string>
<string name="troubleshoot_notifications_test_current_push_provider_description">"Get the name of the current provider."</string>
<string name="troubleshoot_notifications_test_current_push_provider_failure">"No push providers selected."</string>
<string name="troubleshoot_notifications_test_current_push_provider_success">"Current push provider: %1$s."</string>
<string name="troubleshoot_notifications_test_current_push_provider_title">"Current push provider"</string>
<string name="troubleshoot_notifications_test_detect_push_provider_description">"Ensure that the application has at least one push provider."</string>
<string name="troubleshoot_notifications_test_detect_push_provider_failure">"No push providers found."</string>
<plurals name="troubleshoot_notifications_test_detect_push_provider_success">
<item quantity="one">"Found %1$d push provider: %2$s"</item>
<item quantity="other">"Found %1$d push providers: %2$s"</item>
</plurals>
<string name="troubleshoot_notifications_test_detect_push_provider_title">"Detect push providers"</string>
<string name="troubleshoot_notifications_test_display_notification_description">"Check that the application can display notification."</string>
<string name="troubleshoot_notifications_test_display_notification_failure">"The notification has not been clicked."</string>
<string name="troubleshoot_notifications_test_display_notification_permission_failure">"Cannot display the notification."</string>
<string name="troubleshoot_notifications_test_display_notification_success">"The notification has been clicked!"</string>
<string name="troubleshoot_notifications_test_display_notification_title">"Display notification"</string>
<string name="troubleshoot_notifications_test_display_notification_waiting">"Please click on the notification to continue the test."</string>
<string name="troubleshoot_notifications_test_push_loop_back_description">"Ensure that the application is receiving push."</string>
<string name="troubleshoot_notifications_test_push_loop_back_failure_1">"Error: pusher has rejected the request."</string>
<string name="troubleshoot_notifications_test_push_loop_back_failure_2">"Error: %1$s."</string>
<string name="troubleshoot_notifications_test_push_loop_back_failure_3">"Error, cannot test push."</string>
<string name="troubleshoot_notifications_test_push_loop_back_failure_4">"Error, timeout waiting for push."</string>
<string name="troubleshoot_notifications_test_push_loop_back_success">"Push loop back took %1$d ms."</string>
<string name="troubleshoot_notifications_test_push_loop_back_title">"Test Push loop back"</string>
</resources> </resources>

View file

@ -20,6 +20,7 @@ import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState
import io.element.android.libraries.push.test.FakeGetCurrentPushProvider import io.element.android.libraries.push.test.FakeGetCurrentPushProvider
import io.element.android.services.toolbox.test.strings.FakeStringProvider
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
@ -28,7 +29,8 @@ class CurrentPushProviderTestTest {
@Test @Test
fun `test CurrentPushProviderTest with a push provider`() = runTest { fun `test CurrentPushProviderTest with a push provider`() = runTest {
val sut = CurrentPushProviderTest( val sut = CurrentPushProviderTest(
getCurrentPushProvider = FakeGetCurrentPushProvider("foo") getCurrentPushProvider = FakeGetCurrentPushProvider("foo"),
stringProvider = FakeStringProvider(),
) )
launch { launch {
sut.run(this) sut.run(this)
@ -45,7 +47,8 @@ class CurrentPushProviderTestTest {
@Test @Test
fun `test CurrentPushProviderTest without push provider`() = runTest { fun `test CurrentPushProviderTest without push provider`() = runTest {
val sut = CurrentPushProviderTest( val sut = CurrentPushProviderTest(
getCurrentPushProvider = FakeGetCurrentPushProvider(null) getCurrentPushProvider = FakeGetCurrentPushProvider(null),
stringProvider = FakeStringProvider(),
) )
launch { launch {
sut.run(this) sut.run(this)

View file

@ -21,6 +21,7 @@ import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState
import io.element.android.libraries.push.impl.notifications.fake.MockkNotificationCreator import io.element.android.libraries.push.impl.notifications.fake.MockkNotificationCreator
import io.element.android.libraries.push.impl.notifications.fake.MockkNotificationDisplayer import io.element.android.libraries.push.impl.notifications.fake.MockkNotificationDisplayer
import io.element.android.services.toolbox.test.strings.FakeStringProvider
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
@ -82,7 +83,8 @@ class NotificationTestTest {
return NotificationTest( return NotificationTest(
notificationCreator = mockkNotificationCreator.instance, notificationCreator = mockkNotificationCreator.instance,
notificationDisplayer = mockkNotificationDisplayer.instance, notificationDisplayer = mockkNotificationDisplayer.instance,
notificationClickHandler = notificationClickHandler notificationClickHandler = notificationClickHandler,
stringProvider = FakeStringProvider(),
) )
} }
} }

View file

@ -23,6 +23,7 @@ import io.element.android.libraries.matrix.test.AN_EXCEPTION
import io.element.android.libraries.matrix.test.A_FAILURE_REASON import io.element.android.libraries.matrix.test.A_FAILURE_REASON
import io.element.android.libraries.push.api.gateway.PushGatewayFailure import io.element.android.libraries.push.api.gateway.PushGatewayFailure
import io.element.android.libraries.push.test.FakePushService import io.element.android.libraries.push.test.FakePushService
import io.element.android.services.toolbox.test.strings.FakeStringProvider
import io.element.android.services.toolbox.test.systemclock.FakeSystemClock import io.element.android.services.toolbox.test.systemclock.FakeSystemClock
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
@ -35,7 +36,8 @@ class PushLoopbackTestTest {
val sut = PushLoopbackTest( val sut = PushLoopbackTest(
pushService = FakePushService(), pushService = FakePushService(),
diagnosticPushHandler = diagnosticPushHandler, diagnosticPushHandler = diagnosticPushHandler,
clock = FakeSystemClock() clock = FakeSystemClock(),
stringProvider = FakeStringProvider(),
) )
launch { launch {
sut.run(this) sut.run(this)
@ -45,7 +47,6 @@ class PushLoopbackTestTest {
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
val lastItem = awaitItem() val lastItem = awaitItem()
assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false)) assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false))
assertThat(lastItem.description).contains("timeout")
} }
} }
@ -59,7 +60,8 @@ class PushLoopbackTestTest {
} }
), ),
diagnosticPushHandler = diagnosticPushHandler, diagnosticPushHandler = diagnosticPushHandler,
clock = FakeSystemClock() clock = FakeSystemClock(),
stringProvider = FakeStringProvider(),
) )
launch { launch {
sut.run(this) sut.run(this)
@ -69,7 +71,6 @@ class PushLoopbackTestTest {
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
val lastItem = awaitItem() val lastItem = awaitItem()
assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false)) assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false))
assertThat(lastItem.description).contains("rejected")
} }
} }
@ -81,7 +82,8 @@ class PushLoopbackTestTest {
testPushBlock = { false } testPushBlock = { false }
), ),
diagnosticPushHandler = diagnosticPushHandler, diagnosticPushHandler = diagnosticPushHandler,
clock = FakeSystemClock() clock = FakeSystemClock(),
stringProvider = FakeStringProvider(),
) )
launch { launch {
sut.run(this) sut.run(this)
@ -91,7 +93,6 @@ class PushLoopbackTestTest {
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
val lastItem = awaitItem() val lastItem = awaitItem()
assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false)) assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Failure(false))
assertThat(lastItem.description).contains("cannot test push")
} }
} }
@ -105,7 +106,8 @@ class PushLoopbackTestTest {
} }
), ),
diagnosticPushHandler = diagnosticPushHandler, diagnosticPushHandler = diagnosticPushHandler,
clock = FakeSystemClock() clock = FakeSystemClock(),
stringProvider = FakeStringProvider(),
) )
launch { launch {
sut.run(this) sut.run(this)
@ -128,7 +130,8 @@ class PushLoopbackTestTest {
true true
}), }),
diagnosticPushHandler = diagnosticPushHandler, diagnosticPushHandler = diagnosticPushHandler,
clock = FakeSystemClock() clock = FakeSystemClock(),
stringProvider = FakeStringProvider(),
) )
launch { launch {
sut.run(this) sut.run(this)

View file

@ -20,6 +20,7 @@ import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState
import io.element.android.libraries.pushproviders.test.FakePushProvider import io.element.android.libraries.pushproviders.test.FakePushProvider
import io.element.android.services.toolbox.test.strings.FakeStringProvider
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
@ -29,6 +30,7 @@ class PushProvidersTestTest {
fun `test PushProvidersTest with empty list`() = runTest { fun `test PushProvidersTest with empty list`() = runTest {
val sut = PushProvidersTest( val sut = PushProvidersTest(
pushProviders = emptySet(), pushProviders = emptySet(),
stringProvider = FakeStringProvider(),
) )
launch { launch {
sut.run(this) sut.run(this)
@ -48,6 +50,7 @@ class PushProvidersTestTest {
FakePushProvider(name = "foo"), FakePushProvider(name = "foo"),
FakePushProvider(name = "bar"), FakePushProvider(name = "bar"),
), ),
stringProvider = FakeStringProvider(),
) )
launch { launch {
sut.run(this) sut.run(this)
@ -57,6 +60,7 @@ class PushProvidersTestTest {
assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress) assertThat(awaitItem().status).isEqualTo(NotificationTroubleshootTestState.Status.InProgress)
val lastItem = awaitItem() val lastItem = awaitItem()
assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Success) assertThat(lastItem.status).isEqualTo(NotificationTroubleshootTestState.Status.Success)
assertThat(lastItem.description).contains("2")
assertThat(lastItem.description).contains("foo") assertThat(lastItem.description).contains("foo")
assertThat(lastItem.description).contains("bar") assertThat(lastItem.description).contains("bar")
} }

View file

@ -40,6 +40,8 @@ dependencies {
implementation(projects.libraries.core) implementation(projects.libraries.core)
implementation(projects.libraries.di) implementation(projects.libraries.di)
implementation(projects.libraries.matrix.api) implementation(projects.libraries.matrix.api)
implementation(projects.libraries.uiStrings)
implementation(projects.services.toolbox.api)
implementation(projects.libraries.pushstore.api) implementation(projects.libraries.pushstore.api)
implementation(projects.libraries.pushproviders.api) implementation(projects.libraries.pushproviders.api)
@ -57,4 +59,5 @@ dependencies {
testImplementation(libs.test.turbine) testImplementation(libs.test.turbine)
testImplementation(projects.libraries.matrix.test) testImplementation(projects.libraries.matrix.test)
testImplementation(projects.tests.testutils) testImplementation(projects.tests.testutils)
testImplementation(projects.services.toolbox.test)
} }

View file

@ -24,6 +24,8 @@ import io.element.android.libraries.core.notifications.TestFilterData
import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.AppScope
import io.element.android.libraries.pushproviders.firebase.FirebaseConfig import io.element.android.libraries.pushproviders.firebase.FirebaseConfig
import io.element.android.libraries.pushproviders.firebase.IsPlayServiceAvailable import io.element.android.libraries.pushproviders.firebase.IsPlayServiceAvailable
import io.element.android.libraries.pushproviders.firebase.R
import io.element.android.services.toolbox.api.strings.StringProvider
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject import javax.inject.Inject
@ -31,11 +33,12 @@ import javax.inject.Inject
@ContributesMultibinding(AppScope::class) @ContributesMultibinding(AppScope::class)
class FirebaseAvailabilityTest @Inject constructor( class FirebaseAvailabilityTest @Inject constructor(
private val isPlayServiceAvailable: IsPlayServiceAvailable, private val isPlayServiceAvailable: IsPlayServiceAvailable,
private val stringProvider: StringProvider,
) : NotificationTroubleshootTest { ) : NotificationTroubleshootTest {
override val order = 300 override val order = 300
private val delegate = NotificationTroubleshootTestDelegate( private val delegate = NotificationTroubleshootTestDelegate(
defaultName = "Check Firebase", defaultName = stringProvider.getString(R.string.troubleshoot_notifications_test_firebase_availability_title),
defaultDescription = "Ensure that Firebase is available.", defaultDescription = stringProvider.getString(R.string.troubleshoot_notifications_test_firebase_availability_description),
visibleWhenIdle = false, visibleWhenIdle = false,
fakeDelay = NotificationTroubleshootTestDelegate.LONG_DELAY, fakeDelay = NotificationTroubleshootTestDelegate.LONG_DELAY,
) )
@ -50,12 +53,12 @@ class FirebaseAvailabilityTest @Inject constructor(
val result = isPlayServiceAvailable.isAvailable() val result = isPlayServiceAvailable.isAvailable()
if (result) { if (result) {
delegate.updateState( delegate.updateState(
description = "Firebase is available", description = stringProvider.getString(R.string.troubleshoot_notifications_test_firebase_availability_success),
status = NotificationTroubleshootTestState.Status.Success status = NotificationTroubleshootTestState.Status.Success
) )
} else { } else {
delegate.updateState( delegate.updateState(
description = "Firebase is not available", description = stringProvider.getString(R.string.troubleshoot_notifications_test_firebase_availability_failure),
status = NotificationTroubleshootTestState.Status.Failure(false) status = NotificationTroubleshootTestState.Status.Failure(false)
) )
} }

View file

@ -25,6 +25,8 @@ import io.element.android.libraries.di.AppScope
import io.element.android.libraries.pushproviders.firebase.FirebaseConfig import io.element.android.libraries.pushproviders.firebase.FirebaseConfig
import io.element.android.libraries.pushproviders.firebase.FirebaseStore import io.element.android.libraries.pushproviders.firebase.FirebaseStore
import io.element.android.libraries.pushproviders.firebase.FirebaseTroubleshooter import io.element.android.libraries.pushproviders.firebase.FirebaseTroubleshooter
import io.element.android.libraries.pushproviders.firebase.R
import io.element.android.services.toolbox.api.strings.StringProvider
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject import javax.inject.Inject
@ -33,11 +35,12 @@ import javax.inject.Inject
class FirebaseTokenTest @Inject constructor( class FirebaseTokenTest @Inject constructor(
private val firebaseStore: FirebaseStore, private val firebaseStore: FirebaseStore,
private val firebaseTroubleshooter: FirebaseTroubleshooter, private val firebaseTroubleshooter: FirebaseTroubleshooter,
private val stringProvider: StringProvider,
) : NotificationTroubleshootTest { ) : NotificationTroubleshootTest {
override val order = 310 override val order = 310
private val delegate = NotificationTroubleshootTestDelegate( private val delegate = NotificationTroubleshootTestDelegate(
defaultName = "Check Firebase token", defaultName = stringProvider.getString(R.string.troubleshoot_notifications_test_firebase_token_title),
defaultDescription = "Ensure that Firebase token is available.", defaultDescription = stringProvider.getString(R.string.troubleshoot_notifications_test_firebase_token_description),
visibleWhenIdle = false, visibleWhenIdle = false,
fakeDelay = NotificationTroubleshootTestDelegate.LONG_DELAY, fakeDelay = NotificationTroubleshootTestDelegate.LONG_DELAY,
) )
@ -52,12 +55,15 @@ class FirebaseTokenTest @Inject constructor(
val token = firebaseStore.getFcmToken() val token = firebaseStore.getFcmToken()
if (token != null) { if (token != null) {
delegate.updateState( delegate.updateState(
description = "Firebase token: ${token.take(8)}*****", description = stringProvider.getString(
R.string.troubleshoot_notifications_test_firebase_token_success,
"${token.take(8)}*****"
),
status = NotificationTroubleshootTestState.Status.Success status = NotificationTroubleshootTestState.Status.Success
) )
} else { } else {
delegate.updateState( delegate.updateState(
description = "Firebase token is not known", description = stringProvider.getString(R.string.troubleshoot_notifications_test_firebase_token_failure),
status = NotificationTroubleshootTestState.Status.Failure(true) status = NotificationTroubleshootTestState.Status.Failure(true)
) )
} }

View file

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="troubleshoot_notifications_test_firebase_availability_description">"Ensure that Firebase is available."</string>
<string name="troubleshoot_notifications_test_firebase_availability_failure">"Firebase is not available."</string>
<string name="troubleshoot_notifications_test_firebase_availability_success">"Firebase is available."</string>
<string name="troubleshoot_notifications_test_firebase_availability_title">"Check Firebase"</string>
<string name="troubleshoot_notifications_test_firebase_token_description">"Ensure that Firebase token is available."</string>
<string name="troubleshoot_notifications_test_firebase_token_failure">"Firebase token is not known."</string>
<string name="troubleshoot_notifications_test_firebase_token_success">"Firebase token: %1$s."</string>
<string name="troubleshoot_notifications_test_firebase_token_title">"Check Firebase token"</string>
</resources>

View file

@ -20,6 +20,7 @@ import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState
import io.element.android.libraries.pushproviders.firebase.IsPlayServiceAvailable import io.element.android.libraries.pushproviders.firebase.IsPlayServiceAvailable
import io.element.android.services.toolbox.test.strings.FakeStringProvider
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
@ -32,7 +33,8 @@ class FirebaseAvailabilityTestTest {
override fun isAvailable(): Boolean { override fun isAvailable(): Boolean {
return true return true
} }
} },
stringProvider = FakeStringProvider(),
) )
launch { launch {
sut.run(this) sut.run(this)
@ -52,7 +54,8 @@ class FirebaseAvailabilityTestTest {
override fun isAvailable(): Boolean { override fun isAvailable(): Boolean {
return false return false
} }
} },
stringProvider = FakeStringProvider(),
) )
launch { launch {
sut.run(this) sut.run(this)

View file

@ -21,6 +21,7 @@ import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState
import io.element.android.libraries.pushproviders.firebase.FakeFirebaseTroubleshooter import io.element.android.libraries.pushproviders.firebase.FakeFirebaseTroubleshooter
import io.element.android.libraries.pushproviders.firebase.InMemoryFirebaseStore import io.element.android.libraries.pushproviders.firebase.InMemoryFirebaseStore
import io.element.android.services.toolbox.test.strings.FakeStringProvider
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
@ -31,6 +32,7 @@ class FirebaseTokenTestTest {
val sut = FirebaseTokenTest( val sut = FirebaseTokenTest(
firebaseStore = InMemoryFirebaseStore(FAKE_TOKEN), firebaseStore = InMemoryFirebaseStore(FAKE_TOKEN),
firebaseTroubleshooter = FakeFirebaseTroubleshooter(), firebaseTroubleshooter = FakeFirebaseTroubleshooter(),
stringProvider = FakeStringProvider(),
) )
launch { launch {
sut.run(this) sut.run(this)
@ -56,6 +58,7 @@ class FirebaseTokenTestTest {
Result.success(Unit) Result.success(Unit)
} }
), ),
stringProvider = FakeStringProvider(),
) )
launch { launch {
sut.run(this) sut.run(this)

View file

@ -32,6 +32,7 @@ dependencies {
implementation(projects.libraries.androidutils) implementation(projects.libraries.androidutils)
implementation(projects.libraries.core) implementation(projects.libraries.core)
implementation(projects.libraries.matrix.api) implementation(projects.libraries.matrix.api)
implementation(projects.libraries.uiStrings)
implementation(projects.libraries.pushstore.api) implementation(projects.libraries.pushstore.api)
implementation(projects.libraries.pushproviders.api) implementation(projects.libraries.pushproviders.api)
@ -57,4 +58,5 @@ dependencies {
testImplementation(libs.test.turbine) testImplementation(libs.test.turbine)
testImplementation(projects.libraries.matrix.test) testImplementation(projects.libraries.matrix.test)
testImplementation(projects.tests.testutils) testImplementation(projects.tests.testutils)
testImplementation(projects.services.toolbox.test)
} }

View file

@ -22,8 +22,10 @@ import io.element.android.libraries.core.notifications.NotificationTroubleshootT
import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState
import io.element.android.libraries.core.notifications.TestFilterData import io.element.android.libraries.core.notifications.TestFilterData
import io.element.android.libraries.di.AppScope import io.element.android.libraries.di.AppScope
import io.element.android.libraries.pushproviders.unifiedpush.R
import io.element.android.libraries.pushproviders.unifiedpush.UnifiedPushConfig import io.element.android.libraries.pushproviders.unifiedpush.UnifiedPushConfig
import io.element.android.libraries.pushproviders.unifiedpush.UnifiedPushDistributorProvider import io.element.android.libraries.pushproviders.unifiedpush.UnifiedPushDistributorProvider
import io.element.android.services.toolbox.api.strings.StringProvider
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import javax.inject.Inject import javax.inject.Inject
@ -32,11 +34,12 @@ import javax.inject.Inject
class UnifiedPushTest @Inject constructor( class UnifiedPushTest @Inject constructor(
private val unifiedPushDistributorProvider: UnifiedPushDistributorProvider, private val unifiedPushDistributorProvider: UnifiedPushDistributorProvider,
private val openDistributorWebPageAction: OpenDistributorWebPageAction, private val openDistributorWebPageAction: OpenDistributorWebPageAction,
private val stringProvider: StringProvider,
) : NotificationTroubleshootTest { ) : NotificationTroubleshootTest {
override val order = 400 override val order = 400
private val delegate = NotificationTroubleshootTestDelegate( private val delegate = NotificationTroubleshootTestDelegate(
defaultName = "Check UnifiedPush", defaultName = stringProvider.getString(R.string.troubleshoot_notifications_test_unified_push_title),
defaultDescription = "Ensure that UnifiedPush distributors are available.", defaultDescription = stringProvider.getString(R.string.troubleshoot_notifications_test_unified_push_description),
visibleWhenIdle = false, visibleWhenIdle = false,
fakeDelay = NotificationTroubleshootTestDelegate.SHORT_DELAY, fakeDelay = NotificationTroubleshootTestDelegate.SHORT_DELAY,
) )
@ -51,12 +54,17 @@ class UnifiedPushTest @Inject constructor(
val distributors = unifiedPushDistributorProvider.getDistributors() val distributors = unifiedPushDistributorProvider.getDistributors()
if (distributors.isNotEmpty()) { if (distributors.isNotEmpty()) {
delegate.updateState( delegate.updateState(
description = "Distributors found: ${distributors.joinToString { it.name }}", description = stringProvider.getQuantityString(
resId = R.plurals.troubleshoot_notifications_test_unified_push_success,
quantity = distributors.size,
distributors.size,
distributors.joinToString { it.name }
),
status = NotificationTroubleshootTestState.Status.Success status = NotificationTroubleshootTestState.Status.Success
) )
} else { } else {
delegate.updateState( delegate.updateState(
description = "No push distributors found", description = stringProvider.getString(R.string.troubleshoot_notifications_test_unified_push_failure),
status = NotificationTroubleshootTestState.Status.Failure(true) status = NotificationTroubleshootTestState.Status.Failure(true)
) )
} }

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="troubleshoot_notifications_test_unified_push_description">"Ensure that UnifiedPush distributors are available."</string>
<string name="troubleshoot_notifications_test_unified_push_failure">"No push distributors found."</string>
<plurals name="troubleshoot_notifications_test_unified_push_success">
<item quantity="one">"%1$d distributor found: %2$s."</item>
<item quantity="other">"%1$d distributors found: %2$s."</item>
</plurals>
<string name="troubleshoot_notifications_test_unified_push_title">"Check UnifiedPush"</string>
</resources>

View file

@ -20,6 +20,7 @@ import app.cash.turbine.test
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState import io.element.android.libraries.core.notifications.NotificationTroubleshootTestState
import io.element.android.libraries.pushproviders.api.Distributor import io.element.android.libraries.pushproviders.api.Distributor
import io.element.android.services.toolbox.test.strings.FakeStringProvider
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.runTest
import org.junit.Test import org.junit.Test
@ -34,6 +35,7 @@ class UnifiedPushTestTest {
) )
), ),
openDistributorWebPageAction = FakeOpenDistributorWebPageAction(), openDistributorWebPageAction = FakeOpenDistributorWebPageAction(),
stringProvider = FakeStringProvider(),
) )
launch { launch {
sut.run(this) sut.run(this)
@ -60,6 +62,7 @@ class UnifiedPushTestTest {
) )
} }
), ),
stringProvider = FakeStringProvider(),
) )
launch { launch {
sut.run(this) sut.run(this)

View file

@ -80,7 +80,29 @@
"name" : ":libraries:push:impl", "name" : ":libraries:push:impl",
"includeRegex" : [ "includeRegex" : [
"push_.*", "push_.*",
"notification_.*" "notification_.*",
"troubleshoot_notifications_test_current_push_provider.*",
"troubleshoot_notifications_test_detect_push_provider.*",
"troubleshoot_notifications_test_display_notification_.*",
"troubleshoot_notifications_test_push_loop_back_.*"
]
},
{
"name" : ":libraries:permissions:impl",
"includeRegex" : [
"troubleshoot_notifications_test_check_permission_.*"
]
},
{
"name" : ":libraries:pushproviders:firebase",
"includeRegex" : [
"troubleshoot_notifications_test_firebase_.*"
]
},
{
"name" : ":libraries:pushproviders:unifiedpush",
"includeRegex" : [
"troubleshoot_notifications_test_unified_push_.*"
] ]
}, },
{ {
@ -182,7 +204,9 @@
"screen\\.advanced_settings\\..*", "screen\\.advanced_settings\\..*",
"screen_edit_profile_.*", "screen_edit_profile_.*",
"screen_notification_settings_.*", "screen_notification_settings_.*",
"screen_blocked_users_.*" "screen_blocked_users_.*",
"troubleshoot_notifications_entry_point_.*",
"troubleshoot_notifications_screen_.*"
] ]
}, },
{ {