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.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.

View File

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

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
*/
@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);

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 java.util.concurrent.Executors
class ConfigFactory(private val context: Context,
private val configDatabase: ConfigDatabase,
private val maybeGetUserInfo: ()->Pair<ByteArray, String>?):
class ConfigFactory(
private val context: Context,
private val configDatabase: ConfigDatabase,
private val maybeGetUserInfo: () -> Pair<ByteArray, String>?
) :
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<ConfigFactoryUpdateListener> = 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<ConfigBase> = 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<ConfigBase> =
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)
}
}
}