From 0c56df0075dde3f043687e94635d448e0588d8bf Mon Sep 17 00:00:00 2001 From: Tangem Date: Wed, 9 Jul 2025 11:08:16 +0300 Subject: [PATCH] Updated on 2026-08-14 --- .../kotlin/com/tangem/common/BaseTestCase.kt | 32 +++++--- .../com/tangem/common/annotations/ApiEnv.kt | 14 ++++ .../tangem/common/rules/ApiEnvironmentRule.kt | 78 +++++++++++++++++++ .../tangem/tap/data/DefaultCardSdkProvider.kt | 1 + .../api/common/config/ApiEnvironment.kt | 3 + .../datasource/api/common/config/Express.kt | 40 ++++++---- .../datasource/api/common/config/TangemPay.kt | 37 +++++++-- .../api/common/config/TangemTech.kt | 23 +++++- .../config/managers/DevApiConfigsManager.kt | 45 ++++++++--- .../config/managers/MockApiConfigsManager.kt | 61 +++++++++++++++ .../managers/MutableApiConfigsManager.kt | 3 + .../com/tangem/datasource/di/NetworkModule.kt | 14 ++-- .../tangem/datasource/utils/HttpClientExt.kt | 3 +- .../visa/DefaultVisaActivationRepository.kt | 1 + .../utils/ApiEnvironmentComparator.kt | 3 +- .../EnvironmentsTogglesViewModel.kt | 6 +- 16 files changed, 306 insertions(+), 58 deletions(-) create mode 100644 app/src/androidTest/kotlin/com/tangem/common/annotations/ApiEnv.kt create mode 100644 app/src/androidTest/kotlin/com/tangem/common/rules/ApiEnvironmentRule.kt create mode 100644 core/datasource/src/main/java/com/tangem/datasource/api/common/config/managers/MockApiConfigsManager.kt diff --git a/app/src/androidTest/kotlin/com/tangem/common/BaseTestCase.kt b/app/src/androidTest/kotlin/com/tangem/common/BaseTestCase.kt index 48696ff92e..46e41677b6 100644 --- a/app/src/androidTest/kotlin/com/tangem/common/BaseTestCase.kt +++ b/app/src/androidTest/kotlin/com/tangem/common/BaseTestCase.kt @@ -1,7 +1,8 @@ package com.tangem.common import android.Manifest -import androidx.compose.ui.test.junit4.createAndroidComposeRule +import androidx.compose.ui.test.junit4.createEmptyComposeRule +import androidx.test.core.app.ActivityScenario import androidx.test.espresso.intent.Intents import androidx.test.rule.GrantPermissionRule import com.kaspersky.components.alluresupport.interceptors.step.ScreenshotStepInterceptor @@ -10,8 +11,8 @@ import com.kaspersky.components.composesupport.config.addComposeSupport import com.kaspersky.kaspresso.kaspresso.Kaspresso import com.kaspersky.kaspresso.testcases.api.testcase.TestCase import com.tangem.common.allure.FailedStepScreenshotInterceptor -import com.tangem.datasource.local.preferences.AppPreferencesStore -import com.tangem.sdk.api.TangemSdkManager +import com.tangem.common.rules.ApiEnvironmentRule +import com.tangem.datasource.api.common.config.managers.ApiConfigsManager import com.tangem.tap.MainActivity import dagger.hilt.android.testing.HiltAndroidRule import org.junit.Rule @@ -35,17 +36,20 @@ abstract class BaseTestCase : TestCase( ) { @Inject - lateinit var tangemSdkManager: TangemSdkManager - - @Inject - lateinit var appPreferencesStore: AppPreferencesStore + lateinit var apiConfigsManager: ApiConfigsManager private val hiltRule = HiltAndroidRule(this) - private val permissionRule = GrantPermissionRule.grant( + private val apiEnvironmentRule = ApiEnvironmentRule() + private val permissionRule = GrantPermissionRule.grant( Manifest.permission.POST_NOTIFICATIONS, Manifest.permission.CAMERA, ) - val composeTestRule = createAndroidComposeRule() + + /** + * It is important to use `ComposeRule` without specifying an activity to ensure that the initialization order of + * all test rules is fully controlled. + */ + val composeTestRule = createEmptyComposeRule() @Rule @JvmField @@ -53,18 +57,26 @@ abstract class BaseTestCase : TestCase( .outerRule(hiltRule) .around(ApplicationInjectionExecutionRule()) .around(permissionRule) + .around(apiEnvironmentRule) .around(composeTestRule) + /** + * Initialization order is important: + * – DI dependencies must be injected first, + * – then the API environment should be set up, + * – and only after that the activity should be launched. + */ protected fun setupHooks( additionalBeforeSection: () -> Unit = {}, additionalAfterSection: () -> Unit = {}, ) = before { hiltRule.inject() + apiEnvironmentRule.setup(apiConfigsManager) + ActivityScenario.launch(MainActivity::class.java) Intents.init() additionalBeforeSection() }.after { additionalAfterSection() Intents.release() } - } \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/common/annotations/ApiEnv.kt b/app/src/androidTest/kotlin/com/tangem/common/annotations/ApiEnv.kt new file mode 100644 index 0000000000..637411492b --- /dev/null +++ b/app/src/androidTest/kotlin/com/tangem/common/annotations/ApiEnv.kt @@ -0,0 +1,14 @@ +package com.tangem.common.annotations + +import com.tangem.datasource.api.common.config.ApiEnvironment + +/** + * Annotation to specify the API environment for a class or function. + * + * @property environment the API environment to be used (defaults to [ApiEnvironment.MOCK]) + */ +@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS) +@Retention(AnnotationRetention.RUNTIME) +annotation class ApiEnv( + val environment: ApiEnvironment = ApiEnvironment.MOCK, +) \ No newline at end of file diff --git a/app/src/androidTest/kotlin/com/tangem/common/rules/ApiEnvironmentRule.kt b/app/src/androidTest/kotlin/com/tangem/common/rules/ApiEnvironmentRule.kt new file mode 100644 index 0000000000..156e7054c9 --- /dev/null +++ b/app/src/androidTest/kotlin/com/tangem/common/rules/ApiEnvironmentRule.kt @@ -0,0 +1,78 @@ +package com.tangem.common.rules + +import androidx.test.platform.app.InstrumentationRegistry +import com.tangem.common.annotations.ApiEnv +import com.tangem.datasource.api.common.config.ApiEnvironment +import com.tangem.datasource.api.common.config.managers.ApiConfigsManager +import com.tangem.datasource.api.common.config.managers.MutableApiConfigsManager +import com.tangem.wallet.test.BuildConfig +import kotlinx.coroutines.runBlocking +import org.junit.rules.TestRule +import org.junit.runner.Description +import org.junit.runners.model.Statement +import timber.log.Timber + +/** + * A JUnit rule that sets up the API environment for tests based on annotations or instrumentation arguments. + * + * This rule allows tests to specify which API environment to use either through an annotation on the test method/class + * or via an instrumentation argument. + * + * This rule only finds and stores the required API environment. The actual environment setup is performed + * by calling the [setup] method with an appropriate [ApiConfigsManager] instance. + */ +class ApiEnvironmentRule : TestRule { + + private var targetEnvironment: ApiEnvironment? = null + + /** + * Sets up the API environment based on the provided [ApiConfigsManager]. + * This method is typically called in the test setup phase to ensure the correct API environment is configured. + * + * @param apiConfigsManager the manager responsible for API configurations + */ + fun setup(apiConfigsManager: ApiConfigsManager) { + val mutableManager = requireNotNull(apiConfigsManager as? MutableApiConfigsManager) { + "MutableApiConfigsManager isn't available in build type ${BuildConfig.BUILD_TYPE}." + } + + mutableManager.setupEnvironment() + } + + override fun apply(base: Statement, description: Description): Statement { + return object : Statement() { + override fun evaluate() { + targetEnvironment = determineEnvironment(description) + + base.evaluate() + } + } + } + + private fun determineEnvironment(description: Description): ApiEnvironment { + val instrumentationArgs = InstrumentationRegistry.getArguments() + val envArg = instrumentationArgs.getString(ENV_ARGUMENT) + + if (!envArg.isNullOrEmpty()) return ApiEnvironment.valueOf(envArg.uppercase()) + + val methodAnnotation = description.getAnnotation(ApiEnv::class.java) + if (methodAnnotation != null) return methodAnnotation.environment + + val classAnnotation = description.testClass.getAnnotation(ApiEnv::class.java) + if (classAnnotation != null) return classAnnotation.environment + + return ApiEnvironment.MOCK + } + + private fun MutableApiConfigsManager.setupEnvironment() { + val environment = requireNotNull(targetEnvironment) { "Target environment is null" } + + runBlocking { changeEnvironment(environment) } + + Timber.i("API environment set to: ${environment.name}") + } + + private companion object { + const val ENV_ARGUMENT = "testEnvironment" + } +} \ No newline at end of file diff --git a/app/src/main/java/com/tangem/tap/data/DefaultCardSdkProvider.kt b/app/src/main/java/com/tangem/tap/data/DefaultCardSdkProvider.kt index 59cfb837ad..4661ff7c91 100644 --- a/app/src/main/java/com/tangem/tap/data/DefaultCardSdkProvider.kt +++ b/app/src/main/java/com/tangem/tap/data/DefaultCardSdkProvider.kt @@ -76,6 +76,7 @@ internal class DefaultCardSdkProvider @Inject constructor( when (it[ApiConfig.ID.TangemTech.name]) { ApiEnvironment.DEV, ApiEnvironment.STAGE, + ApiEnvironment.MOCK, -> false ApiEnvironment.PROD, null, diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/ApiEnvironment.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/ApiEnvironment.kt index 15c20cc12b..19fc906239 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/ApiEnvironment.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/ApiEnvironment.kt @@ -16,6 +16,9 @@ enum class ApiEnvironment { @Json(name = "STAGE") STAGE, + @Json(name = "MOCK") + MOCK, + @Json(name = "PROD") PROD, } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/Express.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/Express.kt index a42f4d1353..af3ce61013 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/Express.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/Express.kt @@ -14,6 +14,7 @@ import com.tangem.utils.version.AppVersionProvider * @property environmentConfigStorage environment config storage * @property expressAuthProvider express auth provider * @property appVersionProvider app version provider + * @property appInfoProvider app info provider */ internal class Express( private val environmentConfigStorage: EnvironmentConfigStorage, @@ -27,9 +28,25 @@ internal class Express( override val environmentConfigs: List = listOf( createDevEnvironment(), createStageEnvironment(), + createMockedEnvironment(), createProdEnvironment(), ) + private fun getInitialEnvironment(): ApiEnvironment { + return when (BuildConfig.BUILD_TYPE) { + DEBUG_BUILD_TYPE, + -> ApiEnvironment.DEV + INTERNAL_BUILD_TYPE, + -> ApiEnvironment.STAGE + MOCKED_BUILD_TYPE, + -> ApiEnvironment.MOCK + EXTERNAL_BUILD_TYPE, + RELEASE_BUILD_TYPE, + -> ApiEnvironment.PROD + else -> error("Unknown build type [${BuildConfig.BUILD_TYPE}]") + } + } + private fun createDevEnvironment(): ApiEnvironmentConfig = ApiEnvironmentConfig( environment = ApiEnvironment.DEV, baseUrl = "[REDACTED_ENV_URL]", @@ -42,6 +59,12 @@ internal class Express( headers = createHeaders(isProd = false), ) + private fun createMockedEnvironment(): ApiEnvironmentConfig = ApiEnvironmentConfig( + environment = ApiEnvironment.MOCK, + baseUrl = "[REDACTED_ENV_URL]", + headers = createHeaders(isProd = false), + ) + private fun createProdEnvironment(): ApiEnvironmentConfig = ApiEnvironmentConfig( environment = ApiEnvironment.PROD, baseUrl = "https://express.tangem.com/v1/", @@ -63,21 +86,4 @@ internal class Express( ?.apiKey ?: error("No express config provided") } - - private companion object { - - fun getInitialEnvironment(): ApiEnvironment { - return when (BuildConfig.BUILD_TYPE) { - DEBUG_BUILD_TYPE, - -> ApiEnvironment.DEV - INTERNAL_BUILD_TYPE, - MOCKED_BUILD_TYPE, - -> ApiEnvironment.STAGE - EXTERNAL_BUILD_TYPE, - RELEASE_BUILD_TYPE, - -> ApiEnvironment.PROD - else -> error("Unknown build type [${BuildConfig.BUILD_TYPE}]") - } - } - } } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/TangemPay.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/TangemPay.kt index b45492d87b..6ac5527c5b 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/TangemPay.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/TangemPay.kt @@ -1,5 +1,6 @@ package com.tangem.datasource.api.common.config +import com.tangem.datasource.BuildConfig import com.tangem.utils.ProviderSuspend import com.tangem.utils.version.AppVersionProvider @@ -7,11 +8,37 @@ internal class TangemPay( private val appVersionProvider: AppVersionProvider, ) : ApiConfig() { - override val defaultEnvironment: ApiEnvironment = ApiEnvironment.DEV + override val defaultEnvironment: ApiEnvironment = getInitialEnvironment() override val environmentConfigs = listOf( - createProdEnvironment(), createDevEnvironment(), + createMockedEnvironment(), + createProdEnvironment(), + ) + + private fun getInitialEnvironment(): ApiEnvironment { + return when (BuildConfig.BUILD_TYPE) { + MOCKED_BUILD_TYPE -> ApiEnvironment.MOCK + DEBUG_BUILD_TYPE, + INTERNAL_BUILD_TYPE, + -> ApiEnvironment.DEV + EXTERNAL_BUILD_TYPE, + RELEASE_BUILD_TYPE, + -> ApiEnvironment.PROD + else -> error("Unknown build type [${BuildConfig.BUILD_TYPE}]") + } + } + + private fun createDevEnvironment(): ApiEnvironmentConfig = ApiEnvironmentConfig( + environment = ApiEnvironment.DEV, + baseUrl = "[REDACTED_ENV_URL]", + headers = createHeaders(), + ) + + private fun createMockedEnvironment(): ApiEnvironmentConfig = ApiEnvironmentConfig( + environment = ApiEnvironment.MOCK, + baseUrl = "[REDACTED_ENV_URL]", + headers = createHeaders(), ) private fun createProdEnvironment(): ApiEnvironmentConfig = ApiEnvironmentConfig( @@ -20,12 +47,6 @@ internal class TangemPay( headers = createHeaders(), ) - private fun createDevEnvironment(): ApiEnvironmentConfig = ApiEnvironmentConfig( - environment = ApiEnvironment.DEV, - baseUrl = "[REDACTED_ENV_URL]", - headers = createHeaders(), - ) - private fun createHeaders() = mapOf( "version" to ProviderSuspend { appVersionProvider.versionName }, "platform" to ProviderSuspend { "Android" }, diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/TangemTech.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/TangemTech.kt index af033309a1..be68593d10 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/TangemTech.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/TangemTech.kt @@ -1,5 +1,6 @@ package com.tangem.datasource.api.common.config +import com.tangem.datasource.BuildConfig import com.tangem.datasource.api.common.AuthProvider import com.tangem.datasource.utils.RequestHeader import com.tangem.utils.info.AppInfoProvider @@ -12,14 +13,28 @@ internal class TangemTech( private val appInfoProvider: AppInfoProvider, ) : ApiConfig() { - override val defaultEnvironment: ApiEnvironment = ApiEnvironment.PROD + override val defaultEnvironment: ApiEnvironment = getInitialEnvironment() override val environmentConfigs = listOf( createDevEnvironment(), createStageEnvironment(), + createMockedEnvironment(), createProdEnvironment(), ) + private fun getInitialEnvironment(): ApiEnvironment { + return when (BuildConfig.BUILD_TYPE) { + MOCKED_BUILD_TYPE, + -> ApiEnvironment.MOCK + DEBUG_BUILD_TYPE, + INTERNAL_BUILD_TYPE, + EXTERNAL_BUILD_TYPE, + RELEASE_BUILD_TYPE, + -> ApiEnvironment.PROD + else -> error("Unknown build type [${BuildConfig.BUILD_TYPE}]") + } + } + private fun createDevEnvironment(): ApiEnvironmentConfig = ApiEnvironmentConfig( environment = ApiEnvironment.DEV, baseUrl = "[REDACTED_ENV_URL]", @@ -32,6 +47,12 @@ internal class TangemTech( headers = createHeaders(), ) + private fun createMockedEnvironment(): ApiEnvironmentConfig = ApiEnvironmentConfig( + environment = ApiEnvironment.MOCK, + baseUrl = "[REDACTED_ENV_URL]", + headers = createHeaders(), + ) + private fun createProdEnvironment(): ApiEnvironmentConfig = ApiEnvironmentConfig( environment = ApiEnvironment.PROD, baseUrl = "https://api.tangem.org/v1/", diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/managers/DevApiConfigsManager.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/managers/DevApiConfigsManager.kt index 4327ec28df..60d34dab96 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/managers/DevApiConfigsManager.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/managers/DevApiConfigsManager.kt @@ -20,28 +20,26 @@ import kotlinx.coroutines.flow.* * @property dispatchers coroutine dispatcher provider */ internal class DevApiConfigsManager( - apiConfigs: ApiConfigs, + private val apiConfigs: ApiConfigs, private val appPreferencesStore: AppPreferencesStore, private val dispatchers: CoroutineDispatcherProvider, ) : MutableApiConfigsManager { - override val configs: Flow> get() = _apiConfigs + override val configs: StateFlow> + field = MutableStateFlow(value = getInitialConfigs()) - private val _apiConfigs = MutableStateFlow(value = apiConfigs.associateWith { it.defaultEnvironment }) - - override val isInitialized: StateFlow get() = _isInitialized.asStateFlow() - - private val _isInitialized = MutableStateFlow(value = false) + override val isInitialized: StateFlow + field = MutableStateFlow(value = false) override fun initialize() { - _isInitialized.value = false + isInitialized.value = false // We can't use appPreferencesStore.getObjectMap as base flow, // because we should keep possibility to work with configs synchronous. // See [getBaseUrl] appPreferencesStore.getObjectMap(PreferencesKeys.apiConfigsEnvironmentKey) .onEach { savedEnvironments -> - _apiConfigs.update { apiConfigs -> + configs.update { apiConfigs -> apiConfigs.mapValues { val (config, currentEnvironment) = it @@ -49,15 +47,15 @@ internal class DevApiConfigsManager( } } - if (!_isInitialized.value) { - _isInitialized.value = true + if (!isInitialized.value) { + isInitialized.value = true } } .launchIn(CoroutineScope(SupervisorJob() + dispatchers.default)) } override fun getEnvironmentConfig(id: ApiConfig.ID): ApiEnvironmentConfig { - val apiConfigs = _apiConfigs.value + val apiConfigs = configs.value val config = apiConfigs.map { it }.firstOrNull { it.key.id == id }?.key ?: error("Api config with id [$id] not found") @@ -78,4 +76,27 @@ internal class DevApiConfigsManager( mutablePreferences.setObjectMap(PreferencesKeys.apiConfigsEnvironmentKey, updatedMap) } } + + override suspend fun changeEnvironment(environment: ApiEnvironment) { + val supportedConfigs = apiConfigs + .filter { config -> + config.environmentConfigs.any { it.environment == environment } + } + .map { it.id.name } + + appPreferencesStore.editData { mutablePreferences -> + val updatedMap = mutablePreferences.getObjectMap(PreferencesKeys.apiConfigsEnvironmentKey) + .mapValues { (configName, currentEnvironment) -> + val isEnvSupported = supportedConfigs.contains(configName) + + if (isEnvSupported) environment else currentEnvironment + } + + mutablePreferences.setObjectMap(key = PreferencesKeys.apiConfigsEnvironmentKey, value = updatedMap) + } + } + + private fun getInitialConfigs(): Map { + return apiConfigs.associateWith(ApiConfig::defaultEnvironment) + } } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/managers/MockApiConfigsManager.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/managers/MockApiConfigsManager.kt new file mode 100644 index 0000000000..cf388f26ec --- /dev/null +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/managers/MockApiConfigsManager.kt @@ -0,0 +1,61 @@ +package com.tangem.datasource.api.common.config.managers + +import com.tangem.datasource.api.common.config.ApiConfig +import com.tangem.datasource.api.common.config.ApiConfigs +import com.tangem.datasource.api.common.config.ApiEnvironment +import com.tangem.datasource.api.common.config.ApiEnvironmentConfig +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow +import kotlinx.coroutines.flow.update + +/** + * Implementation of [ApiConfigsManager] in MOCK environment + * + * @property apiConfigs api configs + * +[REDACTED_AUTHOR] + */ +internal class MockApiConfigsManager( + private val apiConfigs: ApiConfigs, +) : MutableApiConfigsManager { + + override val configs: StateFlow> + field = MutableStateFlow(value = getInitialConfigs()) + + override val isInitialized: StateFlow = MutableStateFlow(value = true) + + override fun initialize() = Unit + + override fun getEnvironmentConfig(id: ApiConfig.ID): ApiEnvironmentConfig { + val apiConfigs = configs.value + + val (config, currentEnvironment) = apiConfigs.entries.firstOrNull { it.key.id == id } + ?: error("Api config with id [$id] not found") + + return config.environmentConfigs.firstOrNull { it.environment == currentEnvironment } + ?: error("Api config with id [$id] doesn't contain environment [$currentEnvironment]") + } + + override suspend fun changeEnvironment(id: String, environment: ApiEnvironment) { + configs.update { apiConfigs -> + val apiConfig = apiConfigs.keys.firstOrNull { it.id.name == id } + ?: error("Api config with id [$id] not found. Check that ApiConfig with id [$id] was provided into DI") + + apiConfigs + (apiConfig to environment) + } + } + + override suspend fun changeEnvironment(environment: ApiEnvironment) { + configs.update { apiConfigs -> + apiConfigs.mapValues { (config, currentEnvironment) -> + val isEnvSupported = config.environmentConfigs.any { it.environment == environment } + + if (isEnvSupported) environment else currentEnvironment + } + } + } + + private fun getInitialConfigs(): Map { + return apiConfigs.associateWith { it.defaultEnvironment } + } +} \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/managers/MutableApiConfigsManager.kt b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/managers/MutableApiConfigsManager.kt index 35107ad6d8..8b17b0af71 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/api/common/config/managers/MutableApiConfigsManager.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/api/common/config/managers/MutableApiConfigsManager.kt @@ -16,4 +16,7 @@ interface MutableApiConfigsManager : ApiConfigsManager { /** Change api environment [environment] by [id] */ suspend fun changeEnvironment(id: String, environment: ApiEnvironment) + + /** Change api environment [environment] for all configs */ + suspend fun changeEnvironment(environment: ApiEnvironment) } \ No newline at end of file diff --git a/core/datasource/src/main/java/com/tangem/datasource/di/NetworkModule.kt b/core/datasource/src/main/java/com/tangem/datasource/di/NetworkModule.kt index 4122660756..3001458ab9 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/di/NetworkModule.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/di/NetworkModule.kt @@ -6,18 +6,20 @@ import com.tangem.core.analytics.api.AnalyticsErrorHandler import com.tangem.datasource.BuildConfig import com.tangem.datasource.api.common.blockaid.BlockAidApi import com.tangem.datasource.api.common.config.ApiConfig +import com.tangem.datasource.api.common.config.ApiConfig.Companion.MOCKED_BUILD_TYPE import com.tangem.datasource.api.common.config.ApiConfigs import com.tangem.datasource.api.common.config.managers.ApiConfigsManager import com.tangem.datasource.api.common.config.managers.DevApiConfigsManager +import com.tangem.datasource.api.common.config.managers.MockApiConfigsManager import com.tangem.datasource.api.common.config.managers.ProdApiConfigsManager import com.tangem.datasource.api.common.response.ApiResponseCallAdapterFactory import com.tangem.datasource.api.express.TangemExpressApi import com.tangem.datasource.api.markets.TangemTechMarketsApi import com.tangem.datasource.api.onramp.OnrampApi +import com.tangem.datasource.api.pay.TangemPayApi import com.tangem.datasource.api.stakekit.StakeKitApi import com.tangem.datasource.api.tangemTech.TangemTechApi import com.tangem.datasource.api.tangemTech.TangemTechApiV2 -import com.tangem.datasource.api.pay.TangemPayApi import com.tangem.datasource.local.logs.AppLogsStore import com.tangem.datasource.local.preferences.AppPreferencesStore import com.tangem.datasource.utils.* @@ -45,7 +47,7 @@ internal object NetworkModule { private const val STAKE_KIT_API_TIMEOUT_SECONDS = 60L private val excludedApiForLogging: Set = setOf( - // ApiConfig.ID.StakeKit, + ApiConfig.ID.StakeKit, ) @Provides @@ -55,10 +57,10 @@ internal object NetworkModule { appPreferencesStore: AppPreferencesStore, dispatchers: CoroutineDispatcherProvider, ): ApiConfigsManager { - return if (BuildConfig.TESTER_MENU_ENABLED) { - DevApiConfigsManager(apiConfigs, appPreferencesStore, dispatchers) - } else { - ProdApiConfigsManager(apiConfigs) + return when { + BuildConfig.BUILD_TYPE == MOCKED_BUILD_TYPE -> MockApiConfigsManager(apiConfigs) + BuildConfig.TESTER_MENU_ENABLED -> DevApiConfigsManager(apiConfigs, appPreferencesStore, dispatchers) + else -> ProdApiConfigsManager(apiConfigs) } } diff --git a/core/datasource/src/main/java/com/tangem/datasource/utils/HttpClientExt.kt b/core/datasource/src/main/java/com/tangem/datasource/utils/HttpClientExt.kt index 676cebfdaf..ed7d4c62b3 100644 --- a/core/datasource/src/main/java/com/tangem/datasource/utils/HttpClientExt.kt +++ b/core/datasource/src/main/java/com/tangem/datasource/utils/HttpClientExt.kt @@ -5,6 +5,7 @@ import com.chuckerteam.chucker.api.ChuckerInterceptor import com.tangem.datasource.BuildConfig import com.tangem.datasource.api.common.SwitchEnvironmentInterceptor import com.tangem.datasource.api.common.config.ApiConfig +import com.tangem.datasource.api.common.config.ApiConfig.Companion.MOCKED_BUILD_TYPE import com.tangem.datasource.api.common.config.managers.ApiConfigsManager import com.tangem.datasource.api.common.createNetworkLoggingInterceptor import com.tangem.datasource.api.utils.ConnectTimeout @@ -93,7 +94,7 @@ internal fun OkHttpClient.Builder.applyApiConfig( id: ApiConfig.ID, apiConfigsManager: ApiConfigsManager, ): OkHttpClient.Builder { - return if (BuildConfig.TESTER_MENU_ENABLED) { + return if (BuildConfig.TESTER_MENU_ENABLED || BuildConfig.BUILD_TYPE == MOCKED_BUILD_TYPE) { addInterceptor( interceptor = SwitchEnvironmentInterceptor( id = id, diff --git a/data/visa/src/main/kotlin/com/tangem/data/visa/DefaultVisaActivationRepository.kt b/data/visa/src/main/kotlin/com/tangem/data/visa/DefaultVisaActivationRepository.kt index 8d10a750ff..db2117b06a 100644 --- a/data/visa/src/main/kotlin/com/tangem/data/visa/DefaultVisaActivationRepository.kt +++ b/data/visa/src/main/kotlin/com/tangem/data/visa/DefaultVisaActivationRepository.kt @@ -167,6 +167,7 @@ internal class DefaultVisaActivationRepository @AssistedInject constructor( return when (env) { ApiEnvironment.DEV, ApiEnvironment.STAGE, + ApiEnvironment.MOCK, -> rsaPublicKey.dev ApiEnvironment.PROD -> rsaPublicKey.prod } diff --git a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/environments/utils/ApiEnvironmentComparator.kt b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/environments/utils/ApiEnvironmentComparator.kt index 72b950a9e5..d20eb06ced 100644 --- a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/environments/utils/ApiEnvironmentComparator.kt +++ b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/environments/utils/ApiEnvironmentComparator.kt @@ -14,7 +14,8 @@ internal object ApiEnvironmentComparator : Comparator { when (it) { ApiEnvironment.DEV -> 0 ApiEnvironment.STAGE -> 1 - ApiEnvironment.PROD -> 2 + ApiEnvironment.MOCK -> 2 + ApiEnvironment.PROD -> 3 } } diff --git a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/environments/viewmodels/EnvironmentsTogglesViewModel.kt b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/environments/viewmodels/EnvironmentsTogglesViewModel.kt index cf2864d2a3..336f45d72d 100644 --- a/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/environments/viewmodels/EnvironmentsTogglesViewModel.kt +++ b/features/tester/impl/src/main/java/com/tangem/feature/tester/presentation/environments/viewmodels/EnvironmentsTogglesViewModel.kt @@ -111,8 +111,10 @@ internal class EnvironmentsTogglesViewModel @Inject constructor( cardSdkConfigRepository.setTangemApiProdEnvFlag( flag = when (environment) { ApiEnvironment.PROD -> true - ApiEnvironment.DEV -> false - ApiEnvironment.STAGE -> false + ApiEnvironment.DEV, + ApiEnvironment.STAGE, + ApiEnvironment.MOCK, + -> false }, ) }