fix: remove hilt testing, add spy on app context storage field instead, update libsession-util to fixed sodium cmake branch

This commit is contained in:
0x330a 2023-04-19 10:43:24 +10:00
parent c445267ed9
commit 2d1c0b3c02
6 changed files with 117 additions and 138 deletions

View File

@ -127,10 +127,6 @@ dependencies {
testImplementation 'org.assertj:assertj-core:3.11.1' testImplementation 'org.assertj:assertj-core:3.11.1'
testImplementation "org.mockito:mockito-inline:4.10.0" testImplementation "org.mockito:mockito-inline:4.10.0"
testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion" 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:mockito-android:4.10.0"
androidTestImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion" androidTestImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion"
testImplementation "androidx.test:core:$testCoreVersion" testImplementation "androidx.test:core:$testCoreVersion"
@ -226,7 +222,7 @@ android {
buildConfigField "int", "CANONICAL_VERSION_CODE", "$canonicalVersionCode" buildConfigField "int", "CANONICAL_VERSION_CODE", "$canonicalVersionCode"
resConfigs autoResConfig() resConfigs autoResConfig()
testInstrumentationRunner "network.loki.messenger.util.HiltApplicationRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
// The following argument makes the Android Test Orchestrator run its // The following argument makes the Android Test Orchestrator run its
// "pm clear" command after each test invocation. This command ensures // "pm clear" command after each test invocation. This command ensures
// that the app's state is completely cleared between tests. // that the app's state is completely cleared between tests.

View File

@ -3,21 +3,17 @@ package network.loki.messenger
import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry 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.ConfigBase
import network.loki.messenger.libsession_util.Contacts import network.loki.messenger.libsession_util.Contacts
import network.loki.messenger.libsession_util.util.Contact import network.loki.messenger.libsession_util.util.Contact
import network.loki.messenger.libsession_util.util.ExpiryMode import network.loki.messenger.libsession_util.util.ExpiryMode
import org.junit.Before import org.junit.Before
import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith 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.spy
import org.mockito.kotlin.verify import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import org.session.libsession.messaging.MessagingModuleConfiguration import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.utilities.TextSecurePreferences import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.utilities.KeyHelper import org.session.libsignal.utilities.KeyHelper
@ -26,17 +22,10 @@ import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.crypto.KeyPairUtilities import org.thoughtcrime.securesms.crypto.KeyPairUtilities
import kotlin.random.Random import kotlin.random.Random
@CustomTestApplication(ApplicationContext::class)
interface HiltApplicationContext
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
@SmallTest @SmallTest
@HiltAndroidTest
class LibSessionTests { class LibSessionTests {
@get:Rule
val hiltRule = HiltAndroidRule(this)
private fun randomSeedBytes() = (0 until 16).map { Random.nextInt(UByte.MAX_VALUE.toInt()).toByte() } private fun randomSeedBytes() = (0 until 16).map { Random.nextInt(UByte.MAX_VALUE.toInt()).toByte() }
private fun randomKeyPair() = KeyPairUtilities.generate(randomSeedBytes().toByteArray()) private fun randomKeyPair() = KeyPairUtilities.generate(randomSeedBytes().toByteArray())
private fun randomSessionId() = randomKeyPair().x25519KeyPair.hexEncodedPublicKey private fun randomSessionId() = randomKeyPair().x25519KeyPair.hexEncodedPublicKey
@ -86,8 +75,9 @@ class LibSessionTests {
@Test @Test
fun migration_one_to_ones() { fun migration_one_to_ones() {
val storageSpy = spy(MessagingModuleConfiguration.shared.storage) val app = InstrumentationRegistry.getInstrumentation().targetContext.applicationContext as ApplicationContext
whenever(MessagingModuleConfiguration.shared.storage).thenReturn(storageSpy) val storageSpy = spy(app.storage)
app.storage = storageSpy
val newContactId = randomSessionId() val newContactId = randomSessionId()
val singleContact = Contact( val singleContact = Contact(
@ -98,7 +88,10 @@ class LibSessionTests {
val newContactMerge = buildContactMessage(listOf(singleContact)) val newContactMerge = buildContactMessage(listOf(singleContact))
val contacts = MessagingModuleConfiguration.shared.configFactory.contacts!! val contacts = MessagingModuleConfiguration.shared.configFactory.contacts!!
fakePollNewConfig(contacts, newContactMerge) 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))
} }
} }

View File

@ -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)
}
}

View File

@ -127,7 +127,7 @@ import network.loki.messenger.libsession_util.UserProfile;
* @author Moxie Marlinspike * @author Moxie Marlinspike
*/ */
@HiltAndroidApp @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"; public static final String PREFERENCES_NAME = "SecureSMS-Preferences";
@ -149,7 +149,7 @@ public class ApplicationContext extends BaseApplication implements DefaultLifecy
private PersistentLogger persistentLogger; private PersistentLogger persistentLogger;
@Inject LokiAPIDatabase lokiAPIDatabase; @Inject LokiAPIDatabase lokiAPIDatabase;
@Inject Storage storage; @Inject public Storage storage;
@Inject MessageDataProvider messageDataProvider; @Inject MessageDataProvider messageDataProvider;
@Inject JobDatabase jobDatabase; @Inject JobDatabase jobDatabase;
@Inject TextSecurePreferences textSecurePreferences; @Inject TextSecurePreferences textSecurePreferences;
@ -209,6 +209,7 @@ public class ApplicationContext extends BaseApplication implements DefaultLifecy
} }
storage.notifyConfigUpdates(forConfigObject); storage.notifyConfigUpdates(forConfigObject);
} }
@Override @Override
public void onCreate() { public void onCreate() {
DatabaseModule.init(this); DatabaseModule.init(this);

View File

@ -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
}

View File

@ -14,9 +14,11 @@ import org.thoughtcrime.securesms.database.ConfigDatabase
import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities import org.thoughtcrime.securesms.util.ConfigurationMessageUtilities
import java.util.concurrent.Executors import java.util.concurrent.Executors
class ConfigFactory(private val context: Context, class ConfigFactory(
private val context: Context,
private val configDatabase: ConfigDatabase, private val configDatabase: ConfigDatabase,
private val maybeGetUserInfo: ()->Pair<ByteArray, String>?): private val maybeGetUserInfo: () -> Pair<ByteArray, String>?
) :
ConfigFactoryProtocol { ConfigFactoryProtocol {
fun keyPairChanged() { // this should only happen restoring or clearing data fun keyPairChanged() { // this should only happen restoring or clearing data
@ -36,17 +38,25 @@ class ConfigFactory(private val context: Context,
private var _convoVolatileConfig: ConversationVolatileConfig? = null private var _convoVolatileConfig: ConversationVolatileConfig? = null
private val userGroupsLock = Object() private val userGroupsLock = Object()
private var _userGroups: UserGroupsConfig? = null private var _userGroups: UserGroupsConfig? = null
private val factoryExecutor = Executors.newSingleThreadExecutor()
private val listeners: MutableList<ConfigFactoryUpdateListener> = mutableListOf() private val listeners: MutableList<ConfigFactoryUpdateListener> = mutableListOf()
fun registerListener(listener: ConfigFactoryUpdateListener) { listeners += listener } fun registerListener(listener: ConfigFactoryUpdateListener) {
fun unregisterListener(listener: ConfigFactoryUpdateListener) { listeners -= listener } listeners += listener
}
override val user: UserProfile? get() = synchronized(userLock) { fun unregisterListener(listener: ConfigFactoryUpdateListener) {
listeners -= listener
}
override val user: UserProfile?
get() = synchronized(userLock) {
if (!ConfigBase.isNewConfigEnabled) return null if (!ConfigBase.isNewConfigEnabled) return null
if (_userConfig == null) { if (_userConfig == null) {
val (secretKey, publicKey) = maybeGetUserInfo() ?: return@synchronized null val (secretKey, publicKey) = maybeGetUserInfo() ?: return@synchronized null
val userDump = configDatabase.retrieveConfigAndHashes(SharedConfigMessage.Kind.USER_PROFILE.name, publicKey) val userDump = configDatabase.retrieveConfigAndHashes(
SharedConfigMessage.Kind.USER_PROFILE.name,
publicKey
)
_userConfig = if (userDump != null) { _userConfig = if (userDump != null) {
UserProfile.newInstance(secretKey, userDump) UserProfile.newInstance(secretKey, userDump)
} else { } else {
@ -58,11 +68,15 @@ class ConfigFactory(private val context: Context,
_userConfig _userConfig
} }
override val contacts: Contacts? get() = synchronized(contactsLock) { override val contacts: Contacts?
get() = synchronized(contactsLock) {
if (!ConfigBase.isNewConfigEnabled) return null if (!ConfigBase.isNewConfigEnabled) return null
if (_contacts == null) { if (_contacts == null) {
val (secretKey, publicKey) = maybeGetUserInfo() ?: return@synchronized null val (secretKey, publicKey) = maybeGetUserInfo() ?: return@synchronized null
val contactsDump = configDatabase.retrieveConfigAndHashes(SharedConfigMessage.Kind.CONTACTS.name, publicKey) val contactsDump = configDatabase.retrieveConfigAndHashes(
SharedConfigMessage.Kind.CONTACTS.name,
publicKey
)
_contacts = if (contactsDump != null) { _contacts = if (contactsDump != null) {
Contacts.newInstance(secretKey, contactsDump) Contacts.newInstance(secretKey, contactsDump)
} else { } else {
@ -74,15 +88,20 @@ class ConfigFactory(private val context: Context,
_contacts _contacts
} }
override val convoVolatile: ConversationVolatileConfig? get() = synchronized(convoVolatileLock) { override val convoVolatile: ConversationVolatileConfig?
get() = synchronized(convoVolatileLock) {
if (!ConfigBase.isNewConfigEnabled) return null if (!ConfigBase.isNewConfigEnabled) return null
if (_convoVolatileConfig == null) { if (_convoVolatileConfig == null) {
val (secretKey, publicKey) = maybeGetUserInfo() ?: return@synchronized null val (secretKey, publicKey) = maybeGetUserInfo() ?: return@synchronized null
val convoDump = configDatabase.retrieveConfigAndHashes(SharedConfigMessage.Kind.CONVO_INFO_VOLATILE.name, publicKey) val convoDump = configDatabase.retrieveConfigAndHashes(
SharedConfigMessage.Kind.CONVO_INFO_VOLATILE.name,
publicKey
)
_convoVolatileConfig = if (convoDump != null) { _convoVolatileConfig = if (convoDump != null) {
ConversationVolatileConfig.newInstance(secretKey, convoDump) ConversationVolatileConfig.newInstance(secretKey, convoDump)
} else { } else {
ConfigurationMessageUtilities.generateConversationVolatileDump(context)?.let { dump -> ConfigurationMessageUtilities.generateConversationVolatileDump(context)
?.let { dump ->
ConversationVolatileConfig.newInstance(secretKey, dump) ConversationVolatileConfig.newInstance(secretKey, dump)
} ?: ConversationVolatileConfig.newInstance(secretKey) } ?: ConversationVolatileConfig.newInstance(secretKey)
} }
@ -90,11 +109,15 @@ class ConfigFactory(private val context: Context,
_convoVolatileConfig _convoVolatileConfig
} }
override val userGroups: UserGroupsConfig? get() = synchronized(userGroupsLock) { override val userGroups: UserGroupsConfig?
get() = synchronized(userGroupsLock) {
if (!ConfigBase.isNewConfigEnabled) return null if (!ConfigBase.isNewConfigEnabled) return null
if (_userGroups == null) { if (_userGroups == null) {
val (secretKey, publicKey) = maybeGetUserInfo() ?: return@synchronized null val (secretKey, publicKey) = maybeGetUserInfo() ?: return@synchronized null
val userGroupsDump = configDatabase.retrieveConfigAndHashes(SharedConfigMessage.Kind.GROUPS.name, publicKey) val userGroupsDump = configDatabase.retrieveConfigAndHashes(
SharedConfigMessage.Kind.GROUPS.name,
publicKey
)
_userGroups = if (userGroupsDump != null) { _userGroups = if (userGroupsDump != null) {
UserGroupsConfig.Companion.newInstance(secretKey, userGroupsDump) UserGroupsConfig.Companion.newInstance(secretKey, userGroupsDump)
} else { } else {
@ -106,7 +129,8 @@ class ConfigFactory(private val context: Context,
_userGroups _userGroups
} }
override fun getUserConfigs(): List<ConfigBase> = listOfNotNull(user, contacts, convoVolatile, userGroups) override fun getUserConfigs(): List<ConfigBase> =
listOfNotNull(user, contacts, convoVolatile, userGroups)
private fun persistUserConfigDump() = synchronized(userLock) { private fun persistUserConfigDump() = synchronized(userLock) {
@ -121,10 +145,14 @@ class ConfigFactory(private val context: Context,
configDatabase.storeConfig(SharedConfigMessage.Kind.CONTACTS.name, publicKey, dumped) configDatabase.storeConfig(SharedConfigMessage.Kind.CONTACTS.name, publicKey, dumped)
} }
private fun persistConvoVolatileConfigDump() = synchronized (convoVolatileLock) { private fun persistConvoVolatileConfigDump() = synchronized(convoVolatileLock) {
val dumped = convoVolatile?.dump() ?: return val dumped = convoVolatile?.dump() ?: return
val (_, publicKey) = maybeGetUserInfo() ?: 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) { private fun persistUserGroupsConfigDump() = synchronized(userGroupsLock) {
@ -134,7 +162,6 @@ class ConfigFactory(private val context: Context,
} }
override fun persist(forConfigObject: ConfigBase) { override fun persist(forConfigObject: ConfigBase) {
factoryExecutor.submit {
try { try {
listeners.forEach { listener -> listeners.forEach { listener ->
listener.notifyUpdates(forConfigObject) listener.notifyUpdates(forConfigObject)
@ -146,10 +173,8 @@ class ConfigFactory(private val context: Context,
is UserGroupsConfig -> persistUserGroupsConfigDump() is UserGroupsConfig -> persistUserGroupsConfigDump()
else -> throw UnsupportedOperationException("Can't support type of ${forConfigObject::class.simpleName} yet") else -> throw UnsupportedOperationException("Can't support type of ${forConfigObject::class.simpleName} yet")
} }
} catch (e: Exception){ } catch (e: Exception) {
Log.e("Loki-DBG", e) Log.e("Loki-DBG", e)
} }
} }
}
} }