Add test on UnifiedPushProvider

This commit is contained in:
Benoit Marty
2024-05-22 10:31:08 +02:00
committed by Benoit Marty
parent 6dcc16fc6b
commit bfa238ba0d
10 changed files with 502 additions and 14 deletions

View File

@@ -30,6 +30,7 @@ import io.element.android.libraries.matrix.api.room.RoomNotificationSettings
const val A_USER_NAME = "alice"
const val A_PASSWORD = "password"
const val A_SECRET = "secret"
val A_USER_ID = UserId("@alice:server.org")
val A_USER_ID_2 = UserId("@bob:server.org")

View File

@@ -60,4 +60,5 @@ dependencies {
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.tests.testutils)
testImplementation(projects.services.toolbox.test)
testImplementation(projects.services.appnavstate.test)
}

View File

@@ -17,6 +17,8 @@
package io.element.android.libraries.pushproviders.unifiedpush
import android.content.Context
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.pushproviders.api.Distributor
import io.element.android.libraries.pushproviders.unifiedpush.registration.EndpointRegistrationHandler
@@ -30,12 +32,17 @@ import org.unifiedpush.android.connector.UnifiedPush
import javax.inject.Inject
import kotlin.time.Duration.Companion.seconds
class RegisterUnifiedPushUseCase @Inject constructor(
interface RegisterUnifiedPushUseCase {
suspend fun execute(distributor: Distributor, clientSecret: String): Result<Unit>
}
@ContributesBinding(AppScope::class)
class DefaultRegisterUnifiedPushUseCase @Inject constructor(
@ApplicationContext private val context: Context,
private val endpointRegistrationHandler: EndpointRegistrationHandler,
private val coroutineScope: CoroutineScope,
) {
suspend fun execute(distributor: Distributor, clientSecret: String): Result<Unit> {
) : RegisterUnifiedPushUseCase {
override suspend fun execute(distributor: Distributor, clientSecret: String): Result<Unit> {
UnifiedPush.saveDistributor(context, distributor.value)
val completable = CompletableDeferred<Result<Unit>>()
val job = coroutineScope.launch {

View File

@@ -19,22 +19,34 @@ package io.element.android.libraries.pushproviders.unifiedpush
import android.content.Context
import android.content.SharedPreferences
import androidx.core.content.edit
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.di.DefaultPreferences
import io.element.android.libraries.matrix.api.core.UserId
import javax.inject.Inject
class UnifiedPushStore @Inject constructor(
interface UnifiedPushStore {
fun getEndpoint(clientSecret: String): String?
fun storeUpEndpoint(endpoint: String?, clientSecret: String)
fun getPushGateway(clientSecret: String): String?
fun storePushGateway(gateway: String?, clientSecret: String)
fun getDistributorValue(userId: UserId): String?
fun setDistributorValue(userId: UserId, value: String)
}
@ContributesBinding(AppScope::class)
class DefaultUnifiedPushStore @Inject constructor(
@ApplicationContext val context: Context,
@DefaultPreferences private val defaultPrefs: SharedPreferences,
) {
) : UnifiedPushStore {
/**
* Retrieves the UnifiedPush Endpoint.
*
* @param clientSecret the client secret, to identify the session
* @return the UnifiedPush Endpoint or null if not received
*/
fun getEndpoint(clientSecret: String): String? {
override fun getEndpoint(clientSecret: String): String? {
return defaultPrefs.getString(PREFS_ENDPOINT_OR_TOKEN + clientSecret, null)
}
@@ -44,7 +56,7 @@ class UnifiedPushStore @Inject constructor(
* @param endpoint the endpoint to store
* @param clientSecret the client secret, to identify the session
*/
fun storeUpEndpoint(endpoint: String?, clientSecret: String) {
override fun storeUpEndpoint(endpoint: String?, clientSecret: String) {
defaultPrefs.edit {
putString(PREFS_ENDPOINT_OR_TOKEN + clientSecret, endpoint)
}
@@ -56,7 +68,7 @@ class UnifiedPushStore @Inject constructor(
* @param clientSecret the client secret, to identify the session
* @return the Push Gateway or null if not defined
*/
fun getPushGateway(clientSecret: String): String? {
override fun getPushGateway(clientSecret: String): String? {
return defaultPrefs.getString(PREFS_PUSH_GATEWAY + clientSecret, null)
}
@@ -66,17 +78,17 @@ class UnifiedPushStore @Inject constructor(
* @param gateway the push gateway to store
* @param clientSecret the client secret, to identify the session
*/
fun storePushGateway(gateway: String?, clientSecret: String) {
override fun storePushGateway(gateway: String?, clientSecret: String) {
defaultPrefs.edit {
putString(PREFS_PUSH_GATEWAY + clientSecret, gateway)
}
}
fun getDistributorValue(userId: UserId): String? {
override fun getDistributorValue(userId: UserId): String? {
return defaultPrefs.getString(PREFS_DISTRIBUTOR + userId, null)
}
fun setDistributorValue(userId: UserId, value: String) {
override fun setDistributorValue(userId: UserId, value: String) {
defaultPrefs.edit {
putString(PREFS_DISTRIBUTOR + userId, value)
}

View File

@@ -17,18 +17,25 @@
package io.element.android.libraries.pushproviders.unifiedpush
import android.content.Context
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.ApplicationContext
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.pushproviders.api.PusherSubscriber
import org.unifiedpush.android.connector.UnifiedPush
import javax.inject.Inject
class UnregisterUnifiedPushUseCase @Inject constructor(
interface UnregisterUnifiedPushUseCase {
suspend fun execute(matrixClient: MatrixClient, clientSecret: String): Result<Unit>
}
@ContributesBinding(AppScope::class)
class DefaultUnregisterUnifiedPushUseCase @Inject constructor(
@ApplicationContext private val context: Context,
private val unifiedPushStore: UnifiedPushStore,
private val pusherSubscriber: PusherSubscriber,
) {
suspend fun execute(matrixClient: MatrixClient, clientSecret: String): Result<Unit> {
) : UnregisterUnifiedPushUseCase {
override suspend fun execute(matrixClient: MatrixClient, clientSecret: String): Result<Unit> {
val endpoint = unifiedPushStore.getEndpoint(clientSecret)
val gateway = unifiedPushStore.getPushGateway(clientSecret)
if (endpoint == null || gateway == null) {

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.pushproviders.unifiedpush
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.pushstore.api.clientsecret.PushClientSecret
class FakePushClientSecret(
private val getSecretForUserResult: (SessionId) -> String = { TODO() },
private val getUserIdFromSecretResult: (String) -> SessionId? = { TODO() }
) : PushClientSecret {
override suspend fun getSecretForUser(userId: SessionId): String {
return getSecretForUserResult(userId)
}
override suspend fun getUserIdFromSecret(clientSecret: String): SessionId? {
return getUserIdFromSecretResult(clientSecret)
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.pushproviders.unifiedpush
import io.element.android.libraries.pushproviders.api.Distributor
class FakeRegisterUnifiedPushUseCase(
private val result: (Distributor, String) -> Result<Unit> = { _, _ -> TODO("Not yet implemented") }
) : RegisterUnifiedPushUseCase {
override suspend fun execute(distributor: Distributor, clientSecret: String): Result<Unit> {
return result(distributor, clientSecret)
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.pushproviders.unifiedpush
import io.element.android.libraries.matrix.api.core.UserId
class FakeUnifiedPushStore(
private val getEndpointResult: (String) -> String? = { TODO() },
private val storeUpEndpointResult: (String?, String) -> Unit = { _, _ -> TODO() },
private val getPushGatewayResult: (String) -> String? = { TODO() },
private val storePushGatewayResult: (String?, String) -> Unit = { _, _ -> TODO() },
private val getDistributorValueResult: (UserId) -> String? = { TODO() },
private val setDistributorValueResult: (UserId, String) -> Unit = { _, _ -> TODO() },
) : UnifiedPushStore {
override fun getEndpoint(clientSecret: String): String? {
return getEndpointResult(clientSecret)
}
override fun storeUpEndpoint(endpoint: String?, clientSecret: String) {
storeUpEndpointResult(endpoint, clientSecret)
}
override fun getPushGateway(clientSecret: String): String? {
return getPushGatewayResult(clientSecret)
}
override fun storePushGateway(gateway: String?, clientSecret: String) {
storePushGatewayResult(gateway, clientSecret)
}
override fun getDistributorValue(userId: UserId): String? {
return getDistributorValueResult(userId)
}
override fun setDistributorValue(userId: UserId, value: String) {
setDistributorValueResult(userId, value)
}
}

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.pushproviders.unifiedpush
import io.element.android.libraries.matrix.api.MatrixClient
class FakeUnregisterUnifiedPushUseCase(
private val result: (MatrixClient, String) -> Result<Unit> = { _, _ -> TODO("Not yet implemented") }
) : UnregisterUnifiedPushUseCase {
override suspend fun execute(matrixClient: MatrixClient, clientSecret: String): Result<Unit> {
return result(matrixClient, clientSecret)
}
}

View File

@@ -0,0 +1,321 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.libraries.pushproviders.unifiedpush
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.test.AN_EXCEPTION
import io.element.android.libraries.matrix.test.A_SECRET
import io.element.android.libraries.matrix.test.A_SESSION_ID
import io.element.android.libraries.matrix.test.FakeMatrixClient
import io.element.android.libraries.pushproviders.api.CurrentUserPushConfig
import io.element.android.libraries.pushproviders.api.Distributor
import io.element.android.libraries.pushproviders.unifiedpush.troubleshoot.FakeUnifiedPushDistributorProvider
import io.element.android.libraries.pushstore.api.clientsecret.PushClientSecret
import io.element.android.services.appnavstate.api.AppNavigationState
import io.element.android.services.appnavstate.api.AppNavigationStateService
import io.element.android.services.appnavstate.api.NavigationState
import io.element.android.services.appnavstate.test.FakeAppNavigationStateService
import io.element.android.tests.testutils.lambda.lambdaRecorder
import io.element.android.tests.testutils.lambda.value
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.test.runTest
import org.junit.Test
class UnifiedPushProviderTest {
@Test
fun `test index and name`() {
val unifiedPushProvider = createUnifiedPushProvider()
assertThat(unifiedPushProvider.name).isEqualTo(UnifiedPushConfig.NAME)
assertThat(unifiedPushProvider.index).isEqualTo(UnifiedPushConfig.INDEX)
}
@Test
fun `getDistributors return the available distributors`() {
val unifiedPushProvider = createUnifiedPushProvider(
unifiedPushDistributorProvider = FakeUnifiedPushDistributorProvider(
getDistributorsResult = listOf(
Distributor("value", "Name"),
)
)
)
val result = unifiedPushProvider.getDistributors()
assertThat(result).containsExactly(Distributor("value", "Name"))
assertThat(unifiedPushProvider.isAvailable()).isTrue()
}
@Test
fun `getDistributors return empty`() {
val unifiedPushProvider = createUnifiedPushProvider(
unifiedPushDistributorProvider = FakeUnifiedPushDistributorProvider(
getDistributorsResult = emptyList()
)
)
val result = unifiedPushProvider.getDistributors()
assertThat(result).isEmpty()
assertThat(unifiedPushProvider.isAvailable()).isFalse()
}
@Test
fun `register ok`() = runTest {
val getSecretForUserResultLambda = lambdaRecorder<SessionId, String> { A_SECRET }
val executeLambda = lambdaRecorder<Distributor, String, Result<Unit>> { _, _ -> Result.success(Unit) }
val setDistributorValueResultLambda = lambdaRecorder<UserId, String, Unit> { _, _ -> }
val unifiedPushProvider = createUnifiedPushProvider(
pushClientSecret = FakePushClientSecret(
getSecretForUserResult = getSecretForUserResultLambda,
),
registerUnifiedPushUseCase = FakeRegisterUnifiedPushUseCase(
result = executeLambda,
),
unifiedPushStore = FakeUnifiedPushStore(
setDistributorValueResult = setDistributorValueResultLambda,
),
)
val result = unifiedPushProvider.registerWith(FakeMatrixClient(), Distributor("value", "Name"))
assertThat(result).isEqualTo(Result.success(Unit))
getSecretForUserResultLambda.assertions()
.isCalledExactly(1)
.withSequence(listOf(value(A_SESSION_ID)))
executeLambda.assertions()
.isCalledExactly(1)
.withSequence(listOf(value(Distributor("value", "Name")), value(A_SECRET)))
setDistributorValueResultLambda.assertions()
.isCalledExactly(1)
.withSequence(listOf(value(A_SESSION_ID), value("value")))
}
@Test
fun `register ko`() = runTest {
val getSecretForUserResultLambda = lambdaRecorder<SessionId, String> { A_SECRET }
val executeLambda = lambdaRecorder<Distributor, String, Result<Unit>> { _, _ -> Result.failure(AN_EXCEPTION) }
val setDistributorValueResultLambda = lambdaRecorder<UserId, String, Unit>(ensureNeverCalled = true) { _, _ -> }
val unifiedPushProvider = createUnifiedPushProvider(
pushClientSecret = FakePushClientSecret(
getSecretForUserResult = getSecretForUserResultLambda,
),
registerUnifiedPushUseCase = FakeRegisterUnifiedPushUseCase(
result = executeLambda,
),
unifiedPushStore = FakeUnifiedPushStore(
setDistributorValueResult = setDistributorValueResultLambda,
),
)
val result = unifiedPushProvider.registerWith(FakeMatrixClient(), Distributor("value", "Name"))
assertThat(result).isEqualTo(Result.failure<Unit>(AN_EXCEPTION))
getSecretForUserResultLambda.assertions()
.isCalledExactly(1)
.withSequence(listOf(value(A_SESSION_ID)))
executeLambda.assertions()
.isCalledExactly(1)
.withSequence(listOf(value(Distributor("value", "Name")), value(A_SECRET)))
}
@Test
fun `unregister ok`() = runTest {
val matrixClient = FakeMatrixClient()
val getSecretForUserResultLambda = lambdaRecorder<SessionId, String> { A_SECRET }
val executeLambda = lambdaRecorder<MatrixClient, String, Result<Unit>> { _, _ -> Result.success(Unit) }
val unifiedPushProvider = createUnifiedPushProvider(
pushClientSecret = FakePushClientSecret(
getSecretForUserResult = getSecretForUserResultLambda,
),
unRegisterUnifiedPushUseCase = FakeUnregisterUnifiedPushUseCase(
result = executeLambda,
),
)
val result = unifiedPushProvider.unregister(matrixClient)
assertThat(result).isEqualTo(Result.success(Unit))
getSecretForUserResultLambda.assertions()
.isCalledExactly(1)
.withSequence(listOf(value(A_SESSION_ID)))
executeLambda.assertions()
.isCalledExactly(1)
.withSequence(listOf(value(matrixClient), value(A_SECRET)))
}
@Test
fun `unregister ko`() = runTest {
val matrixClient = FakeMatrixClient()
val getSecretForUserResultLambda = lambdaRecorder<SessionId, String> { A_SECRET }
val executeLambda = lambdaRecorder<MatrixClient, String, Result<Unit>> { _, _ -> Result.failure(AN_EXCEPTION) }
val unifiedPushProvider = createUnifiedPushProvider(
pushClientSecret = FakePushClientSecret(
getSecretForUserResult = getSecretForUserResultLambda,
),
unRegisterUnifiedPushUseCase = FakeUnregisterUnifiedPushUseCase(
result = executeLambda,
),
)
val result = unifiedPushProvider.unregister(matrixClient)
assertThat(result).isEqualTo(Result.failure<Unit>(AN_EXCEPTION))
getSecretForUserResultLambda.assertions()
.isCalledExactly(1)
.withSequence(listOf(value(A_SESSION_ID)))
executeLambda.assertions()
.isCalledExactly(1)
.withSequence(listOf(value(matrixClient), value(A_SECRET)))
}
@Test
fun `getCurrentDistributor ok`() = runTest {
val distributor = Distributor("value", "Name")
val matrixClient = FakeMatrixClient()
val unifiedPushProvider = createUnifiedPushProvider(
unifiedPushStore = FakeUnifiedPushStore(
getDistributorValueResult = { distributor.value }
),
unifiedPushDistributorProvider = FakeUnifiedPushDistributorProvider(
getDistributorsResult = listOf(
Distributor("value2", "Name2"),
distributor,
)
)
)
val result = unifiedPushProvider.getCurrentDistributor(matrixClient)
assertThat(result).isEqualTo(distributor)
}
@Test
fun `getCurrentDistributor not know`() = runTest {
val distributor = Distributor("value", "Name")
val matrixClient = FakeMatrixClient()
val unifiedPushProvider = createUnifiedPushProvider(
unifiedPushStore = FakeUnifiedPushStore(
getDistributorValueResult = { "unknown" }
),
unifiedPushDistributorProvider = FakeUnifiedPushDistributorProvider(
getDistributorsResult = listOf(
distributor,
)
)
)
val result = unifiedPushProvider.getCurrentDistributor(matrixClient)
assertThat(result).isNull()
}
@Test
fun `getCurrentDistributor not found`() = runTest {
val distributor = Distributor("value", "Name")
val matrixClient = FakeMatrixClient()
val unifiedPushProvider = createUnifiedPushProvider(
unifiedPushStore = FakeUnifiedPushStore(
getDistributorValueResult = { distributor.value }
),
unifiedPushDistributorProvider = FakeUnifiedPushDistributorProvider(
getDistributorsResult = emptyList()
)
)
val result = unifiedPushProvider.getCurrentDistributor(matrixClient)
assertThat(result).isNull()
}
@Test
fun `getCurrentUserPushConfig no session`() = runTest {
val unifiedPushProvider = createUnifiedPushProvider()
val result = unifiedPushProvider.getCurrentUserPushConfig()
assertThat(result).isNull()
}
@Test
fun `getCurrentUserPushConfig no push gateway`() = runTest {
val unifiedPushProvider = createUnifiedPushProvider(
appNavigationStateService = FakeAppNavigationStateService(
appNavigationState = MutableStateFlow(
AppNavigationState(
navigationState = NavigationState.Session(owner = "owner", sessionId = A_SESSION_ID),
isInForeground = true
)
)
),
pushClientSecret = FakePushClientSecret(
getSecretForUserResult = { A_SECRET }
),
unifiedPushStore = FakeUnifiedPushStore(
getPushGatewayResult = { null }
),
)
val result = unifiedPushProvider.getCurrentUserPushConfig()
assertThat(result).isNull()
}
@Test
fun `getCurrentUserPushConfig no push key`() = runTest {
val unifiedPushProvider = createUnifiedPushProvider(
appNavigationStateService = FakeAppNavigationStateService(
appNavigationState = MutableStateFlow(
AppNavigationState(
navigationState = NavigationState.Session(owner = "owner", sessionId = A_SESSION_ID),
isInForeground = true
)
)
),
pushClientSecret = FakePushClientSecret(
getSecretForUserResult = { A_SECRET }
),
unifiedPushStore = FakeUnifiedPushStore(
getPushGatewayResult = { "aPushGateway" },
getEndpointResult = { null }
),
)
val result = unifiedPushProvider.getCurrentUserPushConfig()
assertThat(result).isNull()
}
@Test
fun `getCurrentUserPushConfig ok`() = runTest {
val unifiedPushProvider = createUnifiedPushProvider(
appNavigationStateService = FakeAppNavigationStateService(
appNavigationState = MutableStateFlow(
AppNavigationState(
navigationState = NavigationState.Session(owner = "owner", sessionId = A_SESSION_ID),
isInForeground = true
)
)
),
pushClientSecret = FakePushClientSecret(
getSecretForUserResult = { A_SECRET }
),
unifiedPushStore = FakeUnifiedPushStore(
getPushGatewayResult = { "aPushGateway" },
getEndpointResult = { "aEndpoint" }
),
)
val result = unifiedPushProvider.getCurrentUserPushConfig()
assertThat(result).isEqualTo(CurrentUserPushConfig("aPushGateway", "aEndpoint"))
}
private fun createUnifiedPushProvider(
unifiedPushDistributorProvider: UnifiedPushDistributorProvider = FakeUnifiedPushDistributorProvider(),
registerUnifiedPushUseCase: RegisterUnifiedPushUseCase = FakeRegisterUnifiedPushUseCase(),
unRegisterUnifiedPushUseCase: UnregisterUnifiedPushUseCase = FakeUnregisterUnifiedPushUseCase(),
pushClientSecret: PushClientSecret = FakePushClientSecret(),
unifiedPushStore: UnifiedPushStore = FakeUnifiedPushStore(),
appNavigationStateService: AppNavigationStateService = FakeAppNavigationStateService(),
): UnifiedPushProvider {
return UnifiedPushProvider(
unifiedPushDistributorProvider = unifiedPushDistributorProvider,
registerUnifiedPushUseCase = registerUnifiedPushUseCase,
unRegisterUnifiedPushUseCase = unRegisterUnifiedPushUseCase,
pushClientSecret = pushClientSecret,
unifiedPushStore = unifiedPushStore,
appNavigationStateService = appNavigationStateService
)
}
}