feat: add linux native library support for libsession to enable junit testing (might not be the best way)

This commit is contained in:
0x330a 2023-10-04 09:59:10 +11:00
parent fb2a7a8fed
commit e419024f6b
8 changed files with 98 additions and 29 deletions

View File

@ -21,7 +21,6 @@ import network.loki.messenger.libsession_util.util.UserPic
import org.session.libsession.avatars.AvatarHelper
import org.session.libsession.database.StorageProtocol
import org.session.libsession.messaging.BlindedIdMapping
import org.session.libsession.messaging.MessagingModuleConfiguration
import org.session.libsession.messaging.calls.CallMessageType
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.messaging.jobs.AttachmentUploadJob
@ -920,7 +919,6 @@ open class Storage(
val userGroups = configFactory.userGroups ?: return Optional.absent()
val convoVolatile = configFactory.convoVolatile ?: return Optional.absent()
val ourSessionId = getUserPublicKey() ?: return Optional.absent()
val userKp = MessagingModuleConfiguration.shared.getUserED25519KeyPair() ?: return Optional.absent()
val groupCreationTimestamp = SnodeAPI.nowWithOffset
@ -939,13 +937,11 @@ open class Storage(
LibSessionGroupMember(ourSessionId, "admin", admin = true)
)
val groupKeys = GroupKeysConfig.newInstance(
userKp.secretKey.asBytes,
Hex.fromStringCondensed(group.groupSessionId.publicKey),
adminKey,
members.forEach { groupMembers.set(LibSessionGroupMember(it.hexString(), "member", invitePending = true)) }
val groupKeys = configFactory.constructGroupKeysConfig(group.groupSessionId,
info = groupInfo,
members = groupMembers
)
members = groupMembers) ?: return Optional.absent()
val newGroupRecipient = group.groupSessionId.hexString()
val configTtl = 1 * 24 * 60 * 60 * 1000L // TODO: just testing here, 1 day so we don't fill large space on network

View File

@ -230,6 +230,21 @@ class ConfigFactory(
)
}
override fun constructGroupKeysConfig(
groupSessionId: SessionId,
info: GroupInfoConfig,
members: GroupMembersConfig
): GroupKeysConfig? = getGroupAuthInfo(groupSessionId)?.let { (sk, _) ->
val (userSk, _) = maybeGetUserInfo() ?: return null
GroupKeysConfig.newInstance(
userSk,
Hex.fromStringCondensed(groupSessionId.hexString()),
sk,
info = info,
members = members
)
}
override fun getUserConfigs(): List<ConfigBase> =
listOfNotNull(user, contacts, convoVolatile, userGroups)

View File

@ -48,18 +48,18 @@ class CreateGroupViewModel @Inject constructor(
val members = createGroupState.members
// do some validation
// need a name
if (name.isEmpty()) {
_viewState.postValue(
CreateGroupFragment.ViewState(false, R.string.error)
)
return null
}
if (members.isEmpty()) {
// TODO: need at least two members
if (members.size <= 1) {
_viewState.postValue(
CreateGroupFragment.ViewState(false, R.string.error)
CreateGroupFragment.ViewState(false, R.string.activity_create_closed_group_not_enough_group_members_error)
)
return null
}
// make a group

View File

@ -1,21 +1,42 @@
package org.thoughtcrime.securesms.groups
import android.content.Context
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import junit.framework.TestCase.assertNotNull
import kotlinx.coroutines.ExperimentalCoroutinesApi
import network.loki.messenger.libsession_util.util.Sodium
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.junit.MockitoJUnitRunner
import org.mockito.kotlin.any
import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
import org.mockito.kotlin.whenever
import org.session.libsession.utilities.TextSecurePreferences
import org.session.libsignal.utilities.Hex
import org.session.libsignal.utilities.IdPrefix
import org.session.libsignal.utilities.SessionId
import org.thoughtcrime.securesms.MainCoroutineRule
import org.thoughtcrime.securesms.database.ConfigDatabase
import org.thoughtcrime.securesms.database.Storage
import org.thoughtcrime.securesms.dependencies.ConfigFactory
@OptIn(ExperimentalCoroutinesApi::class)
@RunWith(MockitoJUnitRunner::class)
class ClosedGroupViewTests {
companion object {
private const val OTHER_ID = "051000000000000000000000000000000000000000000000000000000000000000"
}
private val seed =
Hex.fromStringCondensed("0123456789abcdef0123456789abcdef00000000000000000000000000000000")
private val keyPair = Sodium.ed25519KeyPair(seed)
private val userSessionId = SessionId(IdPrefix.STANDARD, Sodium.ed25519PkToCurve25519(keyPair.pubKey))
@ExperimentalCoroutinesApi
@get:Rule
var mainCoroutineRule = MainCoroutineRule()
@ -24,7 +45,22 @@ class ClosedGroupViewTests {
var taskRule = InstantTaskExecutorRule()
@Mock lateinit var textSecurePreferences: TextSecurePreferences
@Mock lateinit var storage: Storage
lateinit var storage: Storage
@Before
fun setup() {
whenever(textSecurePreferences.getLocalNumber()).thenReturn(userSessionId.hexString())
val context = mock<Context>()
val emptyDb = mock<ConfigDatabase> { db ->
whenever(db.retrieveConfigAndHashes(any(), any())).thenReturn(byteArrayOf())
}
val overridenStorage = Storage(mock(), mock(), ConfigFactory(context, emptyDb) {
keyPair.secretKey to userSessionId.hexString()
}, mock())
storage = spy(overridenStorage) { storage ->
whenever(storage.createNewGroup(any(), any(), any())).thenCallRealMethod()
}
}
@Test
fun `Should error on empty name`() {
@ -50,6 +86,17 @@ class ClosedGroupViewTests {
assertNotNull(viewModel.viewState.value?.error)
}
@Test
fun `Should work with valid name and members`() {
val viewModel = createViewModel()
val state = CreateGroupState(
groupName = "group",
groupDescription = "",
members = emptySet()
)
assertNotNull(viewModel.tryCreateGroup(state))
}
private fun createViewModel() = CreateGroupViewModel(textSecurePreferences, storage)
}

View File

@ -42,18 +42,25 @@ add_library( # Sets the name of the library.
# Provides a relative path to your source file(s).
${SOURCES})
if (LINUX)
message("Linux machine detected")
set(JAVA_INCLUDE_PATH "$ENV{JAVA_HOME}/include;$ENV{JAVA_HOME}/include/linux")
find_package(JNI REQUIRED)
include_directories(${JAVA_INCLUDE_PATH})
endif()
# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.
find_library( # Sets the name of the path variable.
log-lib
# Specifies the name of the NDK library that
# you want CMake to locate.
log)
#find_library( # Sets the name of the path variable.
# log-lib
#
# # Specifies the name of the NDK library that
# # you want CMake to locate.
# log)
# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
@ -66,4 +73,5 @@ target_link_libraries( # Specifies the target library.
libsession::crypto
# Links the target library to the log library
# included in the NDK.
${log-lib})
)
#${log-lib})

View File

@ -203,7 +203,6 @@ inline jobject iterator_as_java_stack(JNIEnv *env, const session::config::UserGr
} else if (auto* community = std::get_if<session::config::community_info>(&item)) {
serialized = serialize_community_info(env, *community);
} else if (auto* closed = std::get_if<session::config::group_info>(&item)) {
LOGD("Item is closed group");
serialized = serialize_closed_group_info(env, *closed);
}
if (serialized != nullptr) {
@ -219,8 +218,6 @@ JNIEXPORT jobject JNICALL
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_all(JNIEnv *env, jobject thiz) {
std::lock_guard lock{util::util_mutex_};
auto conf = ptrToUserGroups(env, thiz);
bool isFin = conf->begin().done();
LOGD("Group iterator has more: %d", isFin);
jobject all_stack = iterator_as_java_stack(env, conf->begin(), conf->end());
return all_stack;
}

View File

@ -2,6 +2,7 @@
#define SESSION_ANDROID_UTIL_H
#include <jni.h>
#include <mutex>
#include <array>
#include <optional>
#include "session/types.hpp"
@ -11,13 +12,13 @@
#include "session/config/profile_pic.hpp"
#include "session/config/user_groups.hpp"
#include "session/config/expiring.hpp"
#include <android/log.h>
//#include <android/log.h>
#define LOG_TAG "libsession-jni"
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
//#define LOG_TAG "libsession-jni"
//#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
//#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
//#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
//#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
namespace util {
extern std::mutex util_mutex_;

View File

@ -34,6 +34,11 @@ interface ConfigFactoryProtocol {
)
fun scheduleUpdate(destination: Destination)
fun constructGroupKeysConfig(
groupSessionId: SessionId,
info: GroupInfoConfig,
members: GroupMembersConfig
): GroupKeysConfig?
}
interface ConfigFactoryUpdateListener {