feat: add linux native library support for libsession to enable junit testing (might not be the best way)
This commit is contained in:
parent
fb2a7a8fed
commit
e419024f6b
|
@ -21,7 +21,6 @@ import network.loki.messenger.libsession_util.util.UserPic
|
||||||
import org.session.libsession.avatars.AvatarHelper
|
import org.session.libsession.avatars.AvatarHelper
|
||||||
import org.session.libsession.database.StorageProtocol
|
import org.session.libsession.database.StorageProtocol
|
||||||
import org.session.libsession.messaging.BlindedIdMapping
|
import org.session.libsession.messaging.BlindedIdMapping
|
||||||
import org.session.libsession.messaging.MessagingModuleConfiguration
|
|
||||||
import org.session.libsession.messaging.calls.CallMessageType
|
import org.session.libsession.messaging.calls.CallMessageType
|
||||||
import org.session.libsession.messaging.contacts.Contact
|
import org.session.libsession.messaging.contacts.Contact
|
||||||
import org.session.libsession.messaging.jobs.AttachmentUploadJob
|
import org.session.libsession.messaging.jobs.AttachmentUploadJob
|
||||||
|
@ -920,7 +919,6 @@ open class Storage(
|
||||||
val userGroups = configFactory.userGroups ?: return Optional.absent()
|
val userGroups = configFactory.userGroups ?: return Optional.absent()
|
||||||
val convoVolatile = configFactory.convoVolatile ?: return Optional.absent()
|
val convoVolatile = configFactory.convoVolatile ?: return Optional.absent()
|
||||||
val ourSessionId = getUserPublicKey() ?: return Optional.absent()
|
val ourSessionId = getUserPublicKey() ?: return Optional.absent()
|
||||||
val userKp = MessagingModuleConfiguration.shared.getUserED25519KeyPair() ?: return Optional.absent()
|
|
||||||
|
|
||||||
val groupCreationTimestamp = SnodeAPI.nowWithOffset
|
val groupCreationTimestamp = SnodeAPI.nowWithOffset
|
||||||
|
|
||||||
|
@ -939,13 +937,11 @@ open class Storage(
|
||||||
LibSessionGroupMember(ourSessionId, "admin", admin = true)
|
LibSessionGroupMember(ourSessionId, "admin", admin = true)
|
||||||
)
|
)
|
||||||
|
|
||||||
val groupKeys = GroupKeysConfig.newInstance(
|
members.forEach { groupMembers.set(LibSessionGroupMember(it.hexString(), "member", invitePending = true)) }
|
||||||
userKp.secretKey.asBytes,
|
|
||||||
Hex.fromStringCondensed(group.groupSessionId.publicKey),
|
val groupKeys = configFactory.constructGroupKeysConfig(group.groupSessionId,
|
||||||
adminKey,
|
|
||||||
info = groupInfo,
|
info = groupInfo,
|
||||||
members = groupMembers
|
members = groupMembers) ?: return Optional.absent()
|
||||||
)
|
|
||||||
|
|
||||||
val newGroupRecipient = group.groupSessionId.hexString()
|
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
|
val configTtl = 1 * 24 * 60 * 60 * 1000L // TODO: just testing here, 1 day so we don't fill large space on network
|
||||||
|
|
|
@ -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> =
|
override fun getUserConfigs(): List<ConfigBase> =
|
||||||
listOfNotNull(user, contacts, convoVolatile, userGroups)
|
listOfNotNull(user, contacts, convoVolatile, userGroups)
|
||||||
|
|
||||||
|
|
|
@ -48,18 +48,18 @@ class CreateGroupViewModel @Inject constructor(
|
||||||
val members = createGroupState.members
|
val members = createGroupState.members
|
||||||
|
|
||||||
// do some validation
|
// do some validation
|
||||||
|
// need a name
|
||||||
if (name.isEmpty()) {
|
if (name.isEmpty()) {
|
||||||
_viewState.postValue(
|
_viewState.postValue(
|
||||||
CreateGroupFragment.ViewState(false, R.string.error)
|
CreateGroupFragment.ViewState(false, R.string.error)
|
||||||
)
|
)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
// TODO: need at least two members
|
||||||
if (members.isEmpty()) {
|
if (members.size <= 1) {
|
||||||
_viewState.postValue(
|
_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
|
// make a group
|
||||||
|
|
|
@ -1,21 +1,42 @@
|
||||||
package org.thoughtcrime.securesms.groups
|
package org.thoughtcrime.securesms.groups
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
|
||||||
import junit.framework.TestCase.assertNotNull
|
import junit.framework.TestCase.assertNotNull
|
||||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||||
|
import network.loki.messenger.libsession_util.util.Sodium
|
||||||
|
import org.junit.Before
|
||||||
import org.junit.Rule
|
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.Mock
|
import org.mockito.Mock
|
||||||
import org.mockito.junit.MockitoJUnitRunner
|
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.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.MainCoroutineRule
|
||||||
|
import org.thoughtcrime.securesms.database.ConfigDatabase
|
||||||
import org.thoughtcrime.securesms.database.Storage
|
import org.thoughtcrime.securesms.database.Storage
|
||||||
|
import org.thoughtcrime.securesms.dependencies.ConfigFactory
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
@RunWith(MockitoJUnitRunner::class)
|
@RunWith(MockitoJUnitRunner::class)
|
||||||
class ClosedGroupViewTests {
|
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
|
@ExperimentalCoroutinesApi
|
||||||
@get:Rule
|
@get:Rule
|
||||||
var mainCoroutineRule = MainCoroutineRule()
|
var mainCoroutineRule = MainCoroutineRule()
|
||||||
|
@ -24,7 +45,22 @@ class ClosedGroupViewTests {
|
||||||
var taskRule = InstantTaskExecutorRule()
|
var taskRule = InstantTaskExecutorRule()
|
||||||
|
|
||||||
@Mock lateinit var textSecurePreferences: TextSecurePreferences
|
@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
|
@Test
|
||||||
fun `Should error on empty name`() {
|
fun `Should error on empty name`() {
|
||||||
|
@ -50,6 +86,17 @@ class ClosedGroupViewTests {
|
||||||
assertNotNull(viewModel.viewState.value?.error)
|
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)
|
private fun createViewModel() = CreateGroupViewModel(textSecurePreferences, storage)
|
||||||
|
|
||||||
}
|
}
|
|
@ -42,18 +42,25 @@ add_library( # Sets the name of the library.
|
||||||
# Provides a relative path to your source file(s).
|
# Provides a relative path to your source file(s).
|
||||||
${SOURCES})
|
${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
|
# Searches for a specified prebuilt library and stores the path as a
|
||||||
# variable. Because CMake includes system libraries in the search path by
|
# variable. Because CMake includes system libraries in the search path by
|
||||||
# default, you only need to specify the name of the public NDK library
|
# default, you only need to specify the name of the public NDK library
|
||||||
# you want to add. CMake verifies that the library exists before
|
# you want to add. CMake verifies that the library exists before
|
||||||
# completing its build.
|
# completing its build.
|
||||||
|
|
||||||
find_library( # Sets the name of the path variable.
|
#find_library( # Sets the name of the path variable.
|
||||||
log-lib
|
# log-lib
|
||||||
|
#
|
||||||
# Specifies the name of the NDK library that
|
# # Specifies the name of the NDK library that
|
||||||
# you want CMake to locate.
|
# # you want CMake to locate.
|
||||||
log)
|
# log)
|
||||||
|
|
||||||
# Specifies libraries CMake should link to your target library. You
|
# Specifies libraries CMake should link to your target library. You
|
||||||
# can link multiple libraries, such as libraries you define in this
|
# can link multiple libraries, such as libraries you define in this
|
||||||
|
@ -66,4 +73,5 @@ target_link_libraries( # Specifies the target library.
|
||||||
libsession::crypto
|
libsession::crypto
|
||||||
# Links the target library to the log library
|
# Links the target library to the log library
|
||||||
# included in the NDK.
|
# included in the NDK.
|
||||||
${log-lib})
|
)
|
||||||
|
#${log-lib})
|
||||||
|
|
|
@ -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)) {
|
} else if (auto* community = std::get_if<session::config::community_info>(&item)) {
|
||||||
serialized = serialize_community_info(env, *community);
|
serialized = serialize_community_info(env, *community);
|
||||||
} else if (auto* closed = std::get_if<session::config::group_info>(&item)) {
|
} else if (auto* closed = std::get_if<session::config::group_info>(&item)) {
|
||||||
LOGD("Item is closed group");
|
|
||||||
serialized = serialize_closed_group_info(env, *closed);
|
serialized = serialize_closed_group_info(env, *closed);
|
||||||
}
|
}
|
||||||
if (serialized != nullptr) {
|
if (serialized != nullptr) {
|
||||||
|
@ -219,8 +218,6 @@ JNIEXPORT jobject JNICALL
|
||||||
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_all(JNIEnv *env, jobject thiz) {
|
Java_network_loki_messenger_libsession_1util_UserGroupsConfig_all(JNIEnv *env, jobject thiz) {
|
||||||
std::lock_guard lock{util::util_mutex_};
|
std::lock_guard lock{util::util_mutex_};
|
||||||
auto conf = ptrToUserGroups(env, thiz);
|
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());
|
jobject all_stack = iterator_as_java_stack(env, conf->begin(), conf->end());
|
||||||
return all_stack;
|
return all_stack;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define SESSION_ANDROID_UTIL_H
|
#define SESSION_ANDROID_UTIL_H
|
||||||
|
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
|
#include <mutex>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include "session/types.hpp"
|
#include "session/types.hpp"
|
||||||
|
@ -11,13 +12,13 @@
|
||||||
#include "session/config/profile_pic.hpp"
|
#include "session/config/profile_pic.hpp"
|
||||||
#include "session/config/user_groups.hpp"
|
#include "session/config/user_groups.hpp"
|
||||||
#include "session/config/expiring.hpp"
|
#include "session/config/expiring.hpp"
|
||||||
#include <android/log.h>
|
//#include <android/log.h>
|
||||||
|
|
||||||
#define LOG_TAG "libsession-jni"
|
//#define LOG_TAG "libsession-jni"
|
||||||
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
|
//#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 LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
|
||||||
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,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 LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
|
||||||
|
|
||||||
namespace util {
|
namespace util {
|
||||||
extern std::mutex util_mutex_;
|
extern std::mutex util_mutex_;
|
||||||
|
|
|
@ -34,6 +34,11 @@ interface ConfigFactoryProtocol {
|
||||||
)
|
)
|
||||||
|
|
||||||
fun scheduleUpdate(destination: Destination)
|
fun scheduleUpdate(destination: Destination)
|
||||||
|
fun constructGroupKeysConfig(
|
||||||
|
groupSessionId: SessionId,
|
||||||
|
info: GroupInfoConfig,
|
||||||
|
members: GroupMembersConfig
|
||||||
|
): GroupKeysConfig?
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ConfigFactoryUpdateListener {
|
interface ConfigFactoryUpdateListener {
|
||||||
|
|
Loading…
Reference in New Issue