From 2d1c0b3c023e8c40445a4a8ed25f5b0f867a29b7 Mon Sep 17 00:00:00 2001 From: 0x330a <92654767+0x330a@users.noreply.github.com> Date: Wed, 19 Apr 2023 10:43:24 +1000 Subject: [PATCH] fix: remove hilt testing, add spy on app context storage field instead, update libsession-util to fixed sodium cmake branch --- app/build.gradle | 6 +- .../network/loki/messenger/LibSessionTests.kt | 25 +-- .../messenger/util/HiltApplicationRunner.kt | 17 -- .../securesms/ApplicationContext.java | 5 +- .../thoughtcrime/securesms/BaseApplication.kt | 19 -- .../securesms/dependencies/ConfigFactory.kt | 183 ++++++++++-------- 6 files changed, 117 insertions(+), 138 deletions(-) delete mode 100644 app/src/androidTest/java/network/loki/messenger/util/HiltApplicationRunner.kt delete mode 100644 app/src/main/java/org/thoughtcrime/securesms/BaseApplication.kt diff --git a/app/build.gradle b/app/build.gradle index bd5b7e337a..02928b761a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -127,10 +127,6 @@ dependencies { testImplementation 'org.assertj:assertj-core:3.11.1' testImplementation "org.mockito:mockito-inline:4.10.0" testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion" - - androidTestImplementation "com.google.dagger:hilt-android-testing:$daggerVersion" - kaptAndroidTest "com.google.dagger:hilt-android-compiler:$daggerVersion" - androidTestImplementation "org.mockito:mockito-android:4.10.0" androidTestImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion" testImplementation "androidx.test:core:$testCoreVersion" @@ -226,7 +222,7 @@ android { buildConfigField "int", "CANONICAL_VERSION_CODE", "$canonicalVersionCode" resConfigs autoResConfig() - testInstrumentationRunner "network.loki.messenger.util.HiltApplicationRunner" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" // The following argument makes the Android Test Orchestrator run its // "pm clear" command after each test invocation. This command ensures // that the app's state is completely cleared between tests. diff --git a/app/src/androidTest/java/network/loki/messenger/LibSessionTests.kt b/app/src/androidTest/java/network/loki/messenger/LibSessionTests.kt index 0cf7ad399d..73ae2e16bc 100644 --- a/app/src/androidTest/java/network/loki/messenger/LibSessionTests.kt +++ b/app/src/androidTest/java/network/loki/messenger/LibSessionTests.kt @@ -3,21 +3,17 @@ package network.loki.messenger import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.filters.SmallTest import androidx.test.platform.app.InstrumentationRegistry -import dagger.hilt.android.testing.CustomTestApplication -import dagger.hilt.android.testing.HiltAndroidRule -import dagger.hilt.android.testing.HiltAndroidTest import network.loki.messenger.libsession_util.ConfigBase import network.loki.messenger.libsession_util.Contacts import network.loki.messenger.libsession_util.util.Contact import network.loki.messenger.libsession_util.util.ExpiryMode import org.junit.Before -import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith -import org.mockito.kotlin.any +import org.mockito.kotlin.argThat +import org.mockito.kotlin.eq import org.mockito.kotlin.spy import org.mockito.kotlin.verify -import org.mockito.kotlin.whenever import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.utilities.TextSecurePreferences import org.session.libsignal.utilities.KeyHelper @@ -26,17 +22,10 @@ import org.thoughtcrime.securesms.ApplicationContext import org.thoughtcrime.securesms.crypto.KeyPairUtilities import kotlin.random.Random -@CustomTestApplication(ApplicationContext::class) -interface HiltApplicationContext - @RunWith(AndroidJUnit4::class) @SmallTest -@HiltAndroidTest class LibSessionTests { - @get:Rule - val hiltRule = HiltAndroidRule(this) - private fun randomSeedBytes() = (0 until 16).map { Random.nextInt(UByte.MAX_VALUE.toInt()).toByte() } private fun randomKeyPair() = KeyPairUtilities.generate(randomSeedBytes().toByteArray()) private fun randomSessionId() = randomKeyPair().x25519KeyPair.hexEncodedPublicKey @@ -86,8 +75,9 @@ class LibSessionTests { @Test fun migration_one_to_ones() { - val storageSpy = spy(MessagingModuleConfiguration.shared.storage) - whenever(MessagingModuleConfiguration.shared.storage).thenReturn(storageSpy) + val app = InstrumentationRegistry.getInstrumentation().targetContext.applicationContext as ApplicationContext + val storageSpy = spy(app.storage) + app.storage = storageSpy val newContactId = randomSessionId() val singleContact = Contact( @@ -98,7 +88,10 @@ class LibSessionTests { val newContactMerge = buildContactMessage(listOf(singleContact)) val contacts = MessagingModuleConfiguration.shared.configFactory.contacts!! fakePollNewConfig(contacts, newContactMerge) - verify(storageSpy).addLibSessionContacts(any()) + verify(storageSpy).addLibSessionContacts(argThat { + first().let { it.id == newContactId && it.approved } && size == 1 + }) + verify(storageSpy).setRecipientApproved(argThat { address.serialize() == newContactId }, eq(true)) } } \ No newline at end of file diff --git a/app/src/androidTest/java/network/loki/messenger/util/HiltApplicationRunner.kt b/app/src/androidTest/java/network/loki/messenger/util/HiltApplicationRunner.kt deleted file mode 100644 index 39570c3d2e..0000000000 --- a/app/src/androidTest/java/network/loki/messenger/util/HiltApplicationRunner.kt +++ /dev/null @@ -1,17 +0,0 @@ -package network.loki.messenger.util - -import android.app.Application -import android.content.Context -import androidx.test.runner.AndroidJUnitRunner -import network.loki.messenger.HiltApplicationContext - -class HiltApplicationRunner: AndroidJUnitRunner() { - - override fun newApplication( - cl: ClassLoader?, - className: String?, - context: Context? - ): Application { - return super.newApplication(cl, HiltApplicationContext::class.java.name, context) - } -} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java index a47871f59e..d54e7cb808 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java +++ b/app/src/main/java/org/thoughtcrime/securesms/ApplicationContext.java @@ -127,7 +127,7 @@ import network.loki.messenger.libsession_util.UserProfile; * @author Moxie Marlinspike */ @HiltAndroidApp -public class ApplicationContext extends BaseApplication implements DefaultLifecycleObserver, ConfigFactoryUpdateListener { +public class ApplicationContext extends Application implements DefaultLifecycleObserver, ConfigFactoryUpdateListener { public static final String PREFERENCES_NAME = "SecureSMS-Preferences"; @@ -149,7 +149,7 @@ public class ApplicationContext extends BaseApplication implements DefaultLifecy private PersistentLogger persistentLogger; @Inject LokiAPIDatabase lokiAPIDatabase; - @Inject Storage storage; + @Inject public Storage storage; @Inject MessageDataProvider messageDataProvider; @Inject JobDatabase jobDatabase; @Inject TextSecurePreferences textSecurePreferences; @@ -209,6 +209,7 @@ public class ApplicationContext extends BaseApplication implements DefaultLifecy } storage.notifyConfigUpdates(forConfigObject); } + @Override public void onCreate() { DatabaseModule.init(this); diff --git a/app/src/main/java/org/thoughtcrime/securesms/BaseApplication.kt b/app/src/main/java/org/thoughtcrime/securesms/BaseApplication.kt deleted file mode 100644 index 7bb711ab1d..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/BaseApplication.kt +++ /dev/null @@ -1,19 +0,0 @@ -package org.thoughtcrime.securesms - -import android.app.Application -import org.session.libsession.database.MessageDataProvider -import org.session.libsession.utilities.TextSecurePreferences -import org.thoughtcrime.securesms.database.JobDatabase -import org.thoughtcrime.securesms.database.LokiAPIDatabase -import org.thoughtcrime.securesms.database.Storage -import org.thoughtcrime.securesms.dependencies.ConfigFactory -import javax.inject.Inject - -abstract class BaseApplication: Application() { - lateinit var lokiAPIDatabase: LokiAPIDatabase - lateinit var storage: Storage - lateinit var messageDataProvider: MessageDataProvider - lateinit var jobDatabase: JobDatabase - lateinit var textSecurePreferences: TextSecurePreferences - lateinit var configFactory: ConfigFactory -} \ No newline at end of file diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ConfigFactory.kt b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ConfigFactory.kt index 5083edd34d..0e57d8264e 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ConfigFactory.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ConfigFactory.kt @@ -14,9 +14,11 @@ import org.thoughtcrime.securesms.database.ConfigDatabase import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities import java.util.concurrent.Executors -class ConfigFactory(private val context: Context, - private val configDatabase: ConfigDatabase, - private val maybeGetUserInfo: ()->Pair?): +class ConfigFactory( + private val context: Context, + private val configDatabase: ConfigDatabase, + private val maybeGetUserInfo: () -> Pair? +) : ConfigFactoryProtocol { fun keyPairChanged() { // this should only happen restoring or clearing data @@ -36,77 +38,99 @@ class ConfigFactory(private val context: Context, private var _convoVolatileConfig: ConversationVolatileConfig? = null private val userGroupsLock = Object() private var _userGroups: UserGroupsConfig? = null - private val factoryExecutor = Executors.newSingleThreadExecutor() private val listeners: MutableList = mutableListOf() - fun registerListener(listener: ConfigFactoryUpdateListener) { listeners += listener } - fun unregisterListener(listener: ConfigFactoryUpdateListener) { listeners -= listener } - - override val user: UserProfile? get() = synchronized(userLock) { - if (!ConfigBase.isNewConfigEnabled) return null - if (_userConfig == null) { - val (secretKey, publicKey) = maybeGetUserInfo() ?: return@synchronized null - val userDump = configDatabase.retrieveConfigAndHashes(SharedConfigMessage.Kind.USER_PROFILE.name, publicKey) - _userConfig = if (userDump != null) { - UserProfile.newInstance(secretKey, userDump) - } else { - ConfigurationMessageUtilities.generateUserProfileConfigDump()?.let { dump -> - UserProfile.newInstance(secretKey, dump) - } ?: UserProfile.newInstance(secretKey) - } - } - _userConfig + fun registerListener(listener: ConfigFactoryUpdateListener) { + listeners += listener } - override val contacts: Contacts? get() = synchronized(contactsLock) { - if (!ConfigBase.isNewConfigEnabled) return null - if (_contacts == null) { - val (secretKey, publicKey) = maybeGetUserInfo() ?: return@synchronized null - val contactsDump = configDatabase.retrieveConfigAndHashes(SharedConfigMessage.Kind.CONTACTS.name, publicKey) - _contacts = if (contactsDump != null) { - Contacts.newInstance(secretKey, contactsDump) - } else { - ConfigurationMessageUtilities.generateContactConfigDump()?.let { dump -> - Contacts.newInstance(secretKey, dump) - } ?: Contacts.newInstance(secretKey) - } - } - _contacts + fun unregisterListener(listener: ConfigFactoryUpdateListener) { + listeners -= listener } - override val convoVolatile: ConversationVolatileConfig? get() = synchronized(convoVolatileLock) { - if (!ConfigBase.isNewConfigEnabled) return null - if (_convoVolatileConfig == null) { - val (secretKey, publicKey) = maybeGetUserInfo() ?: return@synchronized null - val convoDump = configDatabase.retrieveConfigAndHashes(SharedConfigMessage.Kind.CONVO_INFO_VOLATILE.name, publicKey) - _convoVolatileConfig = if (convoDump != null) { - ConversationVolatileConfig.newInstance(secretKey, convoDump) - } else { - ConfigurationMessageUtilities.generateConversationVolatileDump(context)?.let { dump -> - ConversationVolatileConfig.newInstance(secretKey, dump) - } ?: ConversationVolatileConfig.newInstance(secretKey) + override val user: UserProfile? + get() = synchronized(userLock) { + if (!ConfigBase.isNewConfigEnabled) return null + if (_userConfig == null) { + val (secretKey, publicKey) = maybeGetUserInfo() ?: return@synchronized null + val userDump = configDatabase.retrieveConfigAndHashes( + SharedConfigMessage.Kind.USER_PROFILE.name, + publicKey + ) + _userConfig = if (userDump != null) { + UserProfile.newInstance(secretKey, userDump) + } else { + ConfigurationMessageUtilities.generateUserProfileConfigDump()?.let { dump -> + UserProfile.newInstance(secretKey, dump) + } ?: UserProfile.newInstance(secretKey) + } } + _userConfig } - _convoVolatileConfig - } - override val userGroups: UserGroupsConfig? get() = synchronized(userGroupsLock) { - if (!ConfigBase.isNewConfigEnabled) return null - if (_userGroups == null) { - val (secretKey, publicKey) = maybeGetUserInfo() ?: return@synchronized null - val userGroupsDump = configDatabase.retrieveConfigAndHashes(SharedConfigMessage.Kind.GROUPS.name, publicKey) - _userGroups = if (userGroupsDump != null) { - UserGroupsConfig.Companion.newInstance(secretKey, userGroupsDump) - } else { - ConfigurationMessageUtilities.generateUserGroupDump(context)?.let { dump -> - UserGroupsConfig.Companion.newInstance(secretKey, dump) - } ?: UserGroupsConfig.newInstance(secretKey) + override val contacts: Contacts? + get() = synchronized(contactsLock) { + if (!ConfigBase.isNewConfigEnabled) return null + if (_contacts == null) { + val (secretKey, publicKey) = maybeGetUserInfo() ?: return@synchronized null + val contactsDump = configDatabase.retrieveConfigAndHashes( + SharedConfigMessage.Kind.CONTACTS.name, + publicKey + ) + _contacts = if (contactsDump != null) { + Contacts.newInstance(secretKey, contactsDump) + } else { + ConfigurationMessageUtilities.generateContactConfigDump()?.let { dump -> + Contacts.newInstance(secretKey, dump) + } ?: Contacts.newInstance(secretKey) + } } + _contacts } - _userGroups - } - override fun getUserConfigs(): List = listOfNotNull(user, contacts, convoVolatile, userGroups) + override val convoVolatile: ConversationVolatileConfig? + get() = synchronized(convoVolatileLock) { + if (!ConfigBase.isNewConfigEnabled) return null + if (_convoVolatileConfig == null) { + val (secretKey, publicKey) = maybeGetUserInfo() ?: return@synchronized null + val convoDump = configDatabase.retrieveConfigAndHashes( + SharedConfigMessage.Kind.CONVO_INFO_VOLATILE.name, + publicKey + ) + _convoVolatileConfig = if (convoDump != null) { + ConversationVolatileConfig.newInstance(secretKey, convoDump) + } else { + ConfigurationMessageUtilities.generateConversationVolatileDump(context) + ?.let { dump -> + ConversationVolatileConfig.newInstance(secretKey, dump) + } ?: ConversationVolatileConfig.newInstance(secretKey) + } + } + _convoVolatileConfig + } + + override val userGroups: UserGroupsConfig? + get() = synchronized(userGroupsLock) { + if (!ConfigBase.isNewConfigEnabled) return null + if (_userGroups == null) { + val (secretKey, publicKey) = maybeGetUserInfo() ?: return@synchronized null + val userGroupsDump = configDatabase.retrieveConfigAndHashes( + SharedConfigMessage.Kind.GROUPS.name, + publicKey + ) + _userGroups = if (userGroupsDump != null) { + UserGroupsConfig.Companion.newInstance(secretKey, userGroupsDump) + } else { + ConfigurationMessageUtilities.generateUserGroupDump(context)?.let { dump -> + UserGroupsConfig.Companion.newInstance(secretKey, dump) + } ?: UserGroupsConfig.newInstance(secretKey) + } + } + _userGroups + } + + override fun getUserConfigs(): List = + listOfNotNull(user, contacts, convoVolatile, userGroups) private fun persistUserConfigDump() = synchronized(userLock) { @@ -121,10 +145,14 @@ class ConfigFactory(private val context: Context, configDatabase.storeConfig(SharedConfigMessage.Kind.CONTACTS.name, publicKey, dumped) } - private fun persistConvoVolatileConfigDump() = synchronized (convoVolatileLock) { + private fun persistConvoVolatileConfigDump() = synchronized(convoVolatileLock) { val dumped = convoVolatile?.dump() ?: return val (_, publicKey) = maybeGetUserInfo() ?: return - configDatabase.storeConfig(SharedConfigMessage.Kind.CONVO_INFO_VOLATILE.name, publicKey, dumped) + configDatabase.storeConfig( + SharedConfigMessage.Kind.CONVO_INFO_VOLATILE.name, + publicKey, + dumped + ) } private fun persistUserGroupsConfigDump() = synchronized(userGroupsLock) { @@ -134,22 +162,19 @@ class ConfigFactory(private val context: Context, } override fun persist(forConfigObject: ConfigBase) { - factoryExecutor.submit { - try { - listeners.forEach { listener -> - listener.notifyUpdates(forConfigObject) - } - when (forConfigObject) { - is UserProfile -> persistUserConfigDump() - is Contacts -> persistContactsConfigDump() - is ConversationVolatileConfig -> persistConvoVolatileConfigDump() - is UserGroupsConfig -> persistUserGroupsConfigDump() - else -> throw UnsupportedOperationException("Can't support type of ${forConfigObject::class.simpleName} yet") - } - } catch (e: Exception){ - Log.e("Loki-DBG", e) + try { + listeners.forEach { listener -> + listener.notifyUpdates(forConfigObject) } + when (forConfigObject) { + is UserProfile -> persistUserConfigDump() + is Contacts -> persistContactsConfigDump() + is ConversationVolatileConfig -> persistConvoVolatileConfigDump() + is UserGroupsConfig -> persistUserGroupsConfigDump() + else -> throw UnsupportedOperationException("Can't support type of ${forConfigObject::class.simpleName} yet") + } + } catch (e: Exception) { + Log.e("Loki-DBG", e) } } - } \ No newline at end of file