feat: setup android unit tests for verifying storage behaviours and state of shared configs

This commit is contained in:
0x330a 2023-04-17 18:17:03 +10:00
parent 2e673901ba
commit fdff11c535
No known key found for this signature in database
GPG Key ID: 267811D6E6A2698C
6 changed files with 108 additions and 32 deletions

View File

@ -125,37 +125,35 @@ dependencies {
implementation "com.opencsv:opencsv:4.6"
testImplementation "junit:junit:$junitVersion"
testImplementation 'org.assertj:assertj-core:3.11.1'
testImplementation "org.mockito:mockito-inline:4.0.0"
testImplementation "org.mockito:mockito-inline:4.10.0"
testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion"
testImplementation 'org.powermock:powermock-api-mockito:1.6.1'
testImplementation 'org.powermock:powermock-module-junit4:1.6.1'
testImplementation 'org.powermock:powermock-module-junit4-rule:1.6.1'
testImplementation 'org.powermock:powermock-classloading-xstream:1.6.1'
androidTestImplementation "org.mockito:mockito-android:4.10.0"
androidTestImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion"
testImplementation "androidx.test:core:$testCoreVersion"
testImplementation "androidx.arch.core:core-testing:2.1.0"
testImplementation "androidx.arch.core:core-testing:2.2.0"
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion"
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion"
// Core library
androidTestImplementation 'androidx.test:core:1.4.0'
androidTestImplementation "androidx.test:core:$testCoreVersion"
// AndroidJUnitRunner and JUnit Rules
androidTestImplementation 'androidx.test:runner:1.4.0'
androidTestImplementation 'androidx.test:rules:1.4.0'
androidTestImplementation 'androidx.test:runner:1.5.2'
androidTestImplementation 'androidx.test:rules:1.5.0'
// Assertions
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.ext:truth:1.4.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.ext:truth:1.5.0'
androidTestImplementation 'com.google.truth:truth:1.1.3'
// Espresso dependencies
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.4.0'
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.4.0'
androidTestImplementation 'androidx.test.espresso:espresso-accessibility:3.4.0'
androidTestImplementation 'androidx.test.espresso:espresso-web:3.4.0'
androidTestImplementation 'androidx.test.espresso.idling:idling-concurrent:3.4.0'
androidTestImplementation 'androidx.test.espresso:espresso-idling-resource:3.4.0'
androidTestUtil 'androidx.test:orchestrator:1.4.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.5.1'
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.5.1'
androidTestImplementation 'androidx.test.espresso:espresso-accessibility:3.5.1'
androidTestImplementation 'androidx.test.espresso:espresso-web:3.5.1'
androidTestImplementation 'androidx.test.espresso.idling:idling-concurrent:3.5.1'
androidTestImplementation 'androidx.test.espresso:espresso-idling-resource:3.5.1'
androidTestUtil 'androidx.test:orchestrator:1.4.2'
testImplementation 'org.robolectric:robolectric:4.4'
testImplementation 'org.robolectric:shadows-multidex:4.4'

View File

@ -0,0 +1,81 @@
package network.loki.messenger
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
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.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.any
import org.mockito.kotlin.spy
import org.mockito.kotlin.verify
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.utilities.KeyHelper
import org.session.libsignal.utilities.hexEncodedPublicKey
import org.thoughtcrime.securesms.ApplicationContext
import org.thoughtcrime.securesms.crypto.KeyPairUtilities
import kotlin.random.Random
@RunWith(AndroidJUnit4::class)
@SmallTest
class LibSessionTests {
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
private fun maybeGetUserInfo(): Pair<ByteArray, String>? {
val appContext = InstrumentationRegistry.getInstrumentation().targetContext.applicationContext as ApplicationContext
val prefs = appContext.prefs
val localUserPublicKey = prefs.getLocalNumber()
val secretKey = with(appContext) {
val edKey = KeyPairUtilities.getUserED25519KeyPair(this) ?: return null
edKey.secretKey.asBytes
}
return if (localUserPublicKey == null || secretKey == null) null
else secretKey to localUserPublicKey
}
private fun buildContactMessage(contactList: List<Contact>): ByteArray {
val (key,_) = maybeGetUserInfo()!!
val contacts = Contacts.Companion.newInstance(key)
contactList.forEach { contact ->
contacts.set(contact)
}
return contacts.dump()
}
@Before
fun setupUser() {
val newBytes = randomSeedBytes().toByteArray()
val context = InstrumentationRegistry.getInstrumentation().targetContext.applicationContext
val kp = KeyPairUtilities.generate(newBytes)
KeyPairUtilities.store(context, kp.seed, kp.ed25519KeyPair, kp.x25519KeyPair)
val registrationID = KeyHelper.generateRegistrationId(false)
TextSecurePreferences.setLocalRegistrationId(context, registrationID)
TextSecurePreferences.setLocalNumber(context, kp.x25519KeyPair.hexEncodedPublicKey)
TextSecurePreferences.setRestorationTime(context, 0)
TextSecurePreferences.setHasViewedSeed(context, false)
}
@Test
fun migration_one_to_ones() {
val storageSpy = spy(MessagingModuleConfiguration.shared.storage)
val newContactId = randomSessionId()
val singleContact = Contact(
id = newContactId,
approved = true,
expiryMode = ExpiryMode.NONE
)
val newContactMerge = buildContactMessage(listOf(singleContact))
MessagingModuleConfiguration.shared.configFactory.contacts!!.merge("abc123" to newContactMerge)
verify(storageSpy).addLibSessionContacts(any())
}
}

View File

@ -89,7 +89,7 @@ import org.thoughtcrime.securesms.util.SessionMetaProtocol
import java.security.MessageDigest
import network.loki.messenger.libsession_util.util.Contact as LibSessionContact
class Storage(context: Context, helper: SQLCipherOpenHelper, private val configFactory: ConfigFactory) : Database(context, helper), StorageProtocol,
open class Storage(context: Context, helper: SQLCipherOpenHelper, private val configFactory: ConfigFactory) : Database(context, helper), StorageProtocol,
ThreadDatabase.ConversationThreadUpdateListener {
init {

View File

@ -17,6 +17,7 @@ import org.session.libsignal.messages.SignalServiceGroup;
import org.session.libsignal.utilities.Log;
import org.session.libsignal.utilities.guava.Optional;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.dependencies.DatabaseComponent;
@ -37,12 +38,14 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM
private final SmsDatabase smsDatabase;
private final MmsDatabase mmsDatabase;
private final MmsSmsDatabase mmsSmsDatabase;
private final Context context;
public ExpiringMessageManager(Context context) {
this.context = context.getApplicationContext();
this.smsDatabase = DatabaseComponent.get(context).smsDatabase();
this.mmsDatabase = DatabaseComponent.get(context).mmsDatabase();
this.mmsSmsDatabase = DatabaseComponent.get(context).mmsSmsDatabase();
executor.execute(new LoadTask());
executor.execute(new ProcessTask());
@ -81,12 +84,11 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM
}
if (message.getId() != null) {
DatabaseComponent.get(context).smsDatabase().deleteMessage(message.getId());
smsDatabase.deleteMessage(message.getId());
}
}
private void insertIncomingExpirationTimerMessage(ExpirationTimerUpdate message) {
MmsDatabase database = DatabaseComponent.get(context).mmsDatabase();
String senderPublicKey = message.getSender();
Long sentTimestamp = message.getSentTimestamp();
@ -126,7 +128,7 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM
Optional.absent(),
Optional.absent());
//insert the timer update message
database.insertSecureDecryptedMessageInbox(mediaMessage, threadId, true);
mmsDatabase.insertSecureDecryptedMessageInbox(mediaMessage, threadId, true);
//set the timer to the conversation
MessagingModuleConfiguration.getShared().getStorage().setExpirationTimer(recipient.getAddress().serialize(), duration);
@ -137,7 +139,6 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM
}
private void insertOutgoingExpirationTimerMessage(ExpirationTimerUpdate message) {
MmsDatabase database = DatabaseComponent.get(context).mmsDatabase();
Long sentTimestamp = message.getSentTimestamp();
String groupId = message.getGroupPublicKey();
@ -152,7 +153,7 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM
try {
OutgoingExpirationUpdateMessage timerUpdateMessage = new OutgoingExpirationUpdateMessage(recipient, sentTimestamp, duration * 1000L, groupId);
database.insertSecureDecryptedMessageOutbox(timerUpdateMessage, -1, sentTimestamp, true);
mmsDatabase.insertSecureDecryptedMessageOutbox(timerUpdateMessage, -1, sentTimestamp, true);
if (groupId != null) {
// we need the group ID as recipient for setExpireMessages below
@ -173,7 +174,7 @@ public class ExpiringMessageManager implements SSKEnvironment.MessageExpirationM
@Override
public void startAnyExpiration(long timestamp, @NotNull String author) {
MessageRecord messageRecord = DatabaseComponent.get(context).mmsSmsDatabase().getMessageFor(timestamp, author);
MessageRecord messageRecord = mmsSmsDatabase.getMessageFor(timestamp, author);
if (messageRecord != null) {
boolean mms = messageRecord.isMms();
Recipient recipient = messageRecord.getRecipient();

View File

@ -21,6 +21,6 @@ preferenceVersion=1.2.0
coreVersion=1.8.0
junitVersion=4.13.2
mockitoKotlinVersion=4.0.0
testCoreVersion=1.4.0
mockitoKotlinVersion=4.1.0
testCoreVersion=1.5.0
pagingVersion=3.0.0

View File

@ -46,10 +46,6 @@ dependencies {
testImplementation 'org.assertj:assertj-core:3.11.1'
testImplementation "org.mockito:mockito-inline:4.0.0"
testImplementation "org.mockito.kotlin:mockito-kotlin:$mockitoKotlinVersion"
testImplementation 'org.powermock:powermock-api-mockito:1.6.1'
testImplementation 'org.powermock:powermock-module-junit4:1.6.1'
testImplementation 'org.powermock:powermock-module-junit4-rule:1.6.1'
testImplementation 'org.powermock:powermock-classloading-xstream:1.6.1'
testImplementation "androidx.test:core:$testCoreVersion"
testImplementation "androidx.arch.core:core-testing:2.1.0"
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutinesVersion"