messenger-android

Android graphical user interfaces for GNUnet Messenger
Log | Files | Refs | README | LICENSE

GnunetChatRemoteTest.kt (15672B)


      1 package org.gnunet.gnunetmessenger.ipc
      2 
      3 import androidx.test.ext.junit.runners.AndroidJUnit4
      4 import androidx.test.core.app.ApplicationProvider
      5 import kotlinx.coroutines.Dispatchers
      6 import kotlinx.coroutines.test.runTest
      7 import kotlinx.coroutines.withContext
      8 import kotlinx.coroutines.withTimeout
      9 import org.gnunet.gnunetmessenger.model.ChatAccount
     10 import org.gnunet.gnunetmessenger.model.ChatContext
     11 import org.gnunet.gnunetmessenger.model.ChatMessage
     12 import org.gnunet.gnunetmessenger.model.ChatHandle
     13 import org.gnunet.gnunetmessenger.model.ChatGroup
     14 import org.gnunet.gnunetmessenger.model.GnunetReturnValue
     15 import org.gnunet.gnunetmessenger.model.MessengerApp
     16 import org.gnunet.gnunetmessenger.service.GnunetChat
     17 import org.gnunet.gnunetmessenger.service.boundimpl.GnunetChatBoundService
     18 import org.junit.After
     19 import org.junit.Assert.assertEquals
     20 import org.junit.Assert.assertTrue
     21 import org.junit.Assert.assertNotNull
     22 import org.junit.Before
     23 import org.junit.Test
     24 import org.junit.runner.RunWith
     25 import kotlinx.coroutines.delay
     26 
     27 @RunWith(AndroidJUnit4::class)
     28 class GnunetChatRemoteTest {
     29 
     30     private val appContext = ApplicationProvider.getApplicationContext<android.content.Context>()
     31     private val gnunetChat: GnunetChatBoundService = GnunetChatBoundService(appContext)
     32     private var messageLog = mutableListOf<Pair<ChatContext, ChatMessage>>()
     33 
     34     @Before
     35     fun setUp() {
     36         messageLog.clear()
     37     }
     38 
     39     @After
     40     fun tearDown() = runTest {
     41         // sauber vom Service abmelden
     42         gnunetChat.unbind()
     43         // Wait for unbind to complete and clean up
     44         delay(1000)
     45     }
     46 
     47     @Test
     48     fun startChat_and_getProfileName_works() = runTest {
     49         // 1. Chat starten – callback ignorieren wir erstmal
     50         val handle: ChatHandle = gnunetChat.startChat(
     51             messengerApp = MessengerApp()
     52         ) { ctx: ChatContext, msg: ChatMessage ->
     53             // Messages sammeln für Tests
     54             messageLog.add(ctx to msg)
     55         }
     56 
     57         // 2. Wait for handle to be initialized with pointer from async operation
     58         withContext(Dispatchers.Default.limitedParallelism(1)) {
     59             withTimeout(5_000) {
     60                 while (handle.pointer == 0L) {
     61                     delay(100)
     62                 }
     63             }
     64         }
     65         
     66         // 3. Verify handle is ready
     67         assertTrue("Handle.pointer sollte != 0 sein", handle.pointer != 0L)
     68 
     69         // 4. Remote-Call auf die Server-App: getProfileName()
     70         val profileName = gnunetChat.getProfileName(handle)
     71 
     72         // Aktuell sollte der Default-Name aus deiner Session-Struktur kommen
     73         assertEquals("GNUnet", profileName)
     74     }
     75 
     76     @Test
     77     fun createAccount_then_iterateAccounts_sees_it() = runTest {
     78         val handle = gnunetChat.startChat(MessengerApp()) { ctx, msg ->
     79             messageLog.add(ctx to msg)
     80         }
     81         
     82         // Wait for handle to be initialized
     83         withContext(Dispatchers.Default.limitedParallelism(1)) {
     84             withTimeout(5_000) {
     85                 while (handle.pointer == 0L) {
     86                     delay(100)
     87                 }
     88             }
     89         }
     90 
     91         val name = "MyTestAccount"
     92 
     93         val result = gnunetChat.createAccount(handle, name)
     94         assertEquals(GnunetReturnValue.OK, result)
     95 
     96         val accounts = mutableListOf<ChatAccount>()
     97 
     98         // iterateAccounts ist nicht suspend -> wir warten mit Timeout,
     99         // bis mindestens ein Account mit passendem Namen im Callback war.
    100         gnunetChat.iterateAccounts(handle) { acc ->
    101             accounts += acc
    102         }
    103 
    104         withContext(Dispatchers.Default.limitedParallelism(1)) {
    105             withTimeout(3_000) {
    106                 while (accounts.none { it.name == name }) {
    107                     delay(50)
    108                 }
    109             }
    110         }
    111 
    112         assertTrue(accounts.any { it.name == name })
    113     }
    114 
    115     @Test
    116     fun testMultipleAccountCreation() = runTest {
    117         val handle = gnunetChat.startChat(MessengerApp()) { ctx, msg ->
    118             messageLog.add(ctx to msg)
    119         }
    120         
    121         // Wait for handle to be initialized
    122         withContext(Dispatchers.Default.limitedParallelism(1)) {
    123             withTimeout(5_000) {
    124                 while (handle.pointer == 0L) {
    125                     delay(100)
    126                 }
    127             }
    128         }
    129 
    130         val accountNames = listOf("Account1", "Account2", "Account3")
    131         
    132         // Create multiple accounts
    133         accountNames.forEach { name ->
    134             val result = gnunetChat.createAccount(handle, name)
    135             assertEquals("Failed to create account: $name", GnunetReturnValue.OK, result)
    136         }
    137 
    138         // Verify all accounts are returned
    139         val accounts = mutableListOf<ChatAccount>()
    140         gnunetChat.iterateAccounts(handle) { acc ->
    141             accounts += acc
    142         }
    143 
    144         withContext(Dispatchers.Default.limitedParallelism(1)) {
    145             withTimeout(5_000) {
    146                 while (accounts.size < accountNames.size) {
    147                     delay(50)
    148                 }
    149             }
    150         }
    151 
    152         accountNames.forEach { name ->
    153             assertTrue("Account $name not found in iteration", 
    154                 accounts.any { it.name == name })
    155         }
    156     }
    157 
    158     @Test
    159     fun testProfileNameUpdate() = runTest {
    160         val handle = gnunetChat.startChat(MessengerApp()) { ctx, msg ->
    161             messageLog.add(ctx to msg)
    162         }
    163         
    164         // Wait for handle to be initialized
    165         withContext(Dispatchers.Default.limitedParallelism(1)) {
    166             withTimeout(5_000) {
    167                 while (handle.pointer == 0L) {
    168                     delay(100)
    169                 }
    170             }
    171         }
    172 
    173         val newName = "TestProfileName"
    174         
    175         // Update profile name
    176         gnunetChat.setProfileName(handle, newName)
    177         
    178         // Verify update
    179         val retrievedName = gnunetChat.getProfileName(handle)
    180         assertEquals(newName, retrievedName)
    181     }
    182 
    183     @Test
    184     fun testGroupCreation() = runTest {
    185         val handle = gnunetChat.startChat(MessengerApp()) { ctx, msg ->
    186             messageLog.add(ctx to msg)
    187         }
    188 
    189         // Wait for handle to be initialized
    190         withContext(Dispatchers.Default.limitedParallelism(1)) {
    191             withTimeout(30_000) {
    192                 while (handle.pointer == 0L) {
    193                     delay(100)
    194                 }
    195             }
    196         }
    197         val groupName = "TestGroup"
    198         
    199         // Create group
    200         val group = gnunetChat.createGroup(handle, groupName)
    201         assertNotNull("Group should not be null", group)
    202         assertEquals(groupName, group.name)
    203         
    204         // Verify group appears in iteration
    205         val groups = mutableListOf<ChatGroup>()
    206         gnunetChat.iterateGroups(handle) { grp ->
    207             groups += grp
    208             0  // Return GNUNet_OK (Int as required by interface)
    209         }
    210         
    211         withContext(Dispatchers.Default.limitedParallelism(1)) {
    212             withTimeout(3_000) {
    213                 while (groups.none { it.name == groupName }) {
    214                     delay(50)
    215                 }
    216             }
    217         }
    218         
    219         assertTrue("Group $groupName not found in iteration", 
    220             groups.any { it.name == groupName })
    221     }
    222 
    223     @Test
    224     fun testContactsIteration() = runTest {
    225         val handle = gnunetChat.startChat(MessengerApp()) { ctx, msg ->
    226             messageLog.add(ctx to msg)
    227         }
    228         
    229         // Wait for handle to be initialized
    230         withContext(Dispatchers.Default.limitedParallelism(1)) {
    231             withTimeout(5_000) {
    232                 while (handle.pointer == 0L) {
    233                     delay(100)
    234                 }
    235             }
    236         }
    237         
    238         // Wait a bit for any initial messages to clear
    239         delay(500)
    240 
    241         val contacts = mutableListOf<String>()
    242         
    243         gnunetChat.iterateContacts(handle) { contact ->
    244             contacts.add(contact.name ?: "Unknown")
    245             0  // Return GNUNet_OK (Int as required by interface)
    246         }
    247         
    248         // Wait longer for contacts to arrive - server needs to process the iteration
    249         withContext(Dispatchers.Default.limitedParallelism(1)) {
    250             withTimeout(5_000) {
    251                 var attempts = 0
    252                 while (contacts.isEmpty() && attempts < 100) {
    253                     delay(50)
    254                     attempts++
    255                 }
    256             }
    257         }
    258         
    259         assertTrue("Should receive at least one contact, got: $contacts", contacts.isNotEmpty())
    260     }
    261 
    262     @Test
    263     fun testAttributeOperations() = runTest {
    264         val handle = gnunetChat.startChat(MessengerApp()) { ctx, msg ->
    265             messageLog.add(ctx to msg)
    266         }
    267         
    268         // Wait for handle to be initialized
    269         withContext(Dispatchers.Default.limitedParallelism(1)) {
    270             withTimeout(5_000) {
    271                 while (handle.pointer == 0L) {
    272                     delay(100)
    273                 }
    274             }
    275         }
    276 
    277         // Set attribute
    278         val testKey = "test_key"
    279         val testValue = "test_value"
    280         gnunetChat.setAttribute(handle, testKey, testValue)
    281         
    282         // Get attributes and verify
    283         val attributes = mutableListOf<Pair<String, String>>()
    284         gnunetChat.getAttributes(handle) { key, value ->
    285             attributes.add(key to value)
    286         }
    287         
    288         withContext(Dispatchers.Default.limitedParallelism(1)) {
    289             withTimeout(3_000) {
    290                 while (attributes.none { it.first == testKey }) {
    291                     delay(50)
    292                 }
    293             }
    294         }
    295         
    296         assertTrue("Attribute $testKey not found", 
    297             attributes.any { it.first == testKey && it.second == testValue })
    298     }
    299 
    300     @Test
    301     fun testMessageReception() = runTest {
    302         val handle = gnunetChat.startChat(MessengerApp()) { ctx, msg ->
    303             messageLog.add(ctx to msg)
    304         }
    305         
    306         // Wait for handle to be initialized
    307         withContext(Dispatchers.Default.limitedParallelism(1)) {
    308             withTimeout(5_000) {
    309                 while (handle.pointer == 0L) {
    310                     delay(100)
    311                 }
    312             }
    313         }
    314 
    315         // Create account which should trigger message
    316         val accountName = "MessageTestAccount"
    317         gnunetChat.createAccount(handle, accountName)
    318         
    319         // Wait for message to be received
    320         withContext(Dispatchers.Default.limitedParallelism(1)) {
    321             withTimeout(3_000) {
    322                 while (messageLog.isEmpty()) {
    323                     delay(50)
    324                 }
    325             }
    326         }
    327         
    328         assertTrue("Should receive at least one message", messageLog.isNotEmpty())
    329         val (ctx, msg) = messageLog.first()
    330         assertNotNull("Message context should not be null", ctx)
    331         assertNotNull("Message should not be null", msg)
    332         assertNotNull("Message text should not be null", msg.text)
    333     }
    334 
    335     @Test
    336     fun testLobbyOperations() = runTest {
    337         val handle = gnunetChat.startChat(MessengerApp()) { ctx, msg ->
    338             messageLog.add(ctx to msg)
    339         }
    340         
    341         // Wait for handle to be initialized
    342         withContext(Dispatchers.Default.limitedParallelism(1)) {
    343             withTimeout(5_000) {
    344                 while (handle.pointer == 0L) {
    345                     delay(100)
    346                 }
    347             }
    348         }
    349 
    350         var lobbyUri = ""
    351         
    352         gnunetChat.lobbyOpen(handle) { uri ->
    353             lobbyUri = uri
    354         }
    355         
    356         withContext(Dispatchers.Default.limitedParallelism(1)) {
    357             withTimeout(3_000) {
    358                 while (lobbyUri.isEmpty()) {
    359                     delay(50)
    360                 }
    361             }
    362         }
    363         
    364         assertTrue("Lobby URI should not be empty", lobbyUri.isNotEmpty())
    365     }
    366 
    367     @Test
    368     fun testResetClearsAllData() = runTest {
    369         val handle = gnunetChat.startChat(MessengerApp()) { ctx, msg ->
    370             messageLog.add(ctx to msg)
    371         }
    372         
    373         // Wait for handle to be initialized
    374         withContext(Dispatchers.Default.limitedParallelism(1)) {
    375             withTimeout(5_000) {
    376                 while (handle.pointer == 0L) {
    377                     delay(100)
    378                 }
    379             }
    380         }
    381 
    382         // Create some test data
    383         val accountName = "TestAccountReset"
    384         val groupName = "TestGroupReset"
    385         val profileName = "TestProfileReset"
    386         
    387         // Create account
    388         val createResult = gnunetChat.createAccount(handle, accountName)
    389         assertEquals("Account creation should succeed", GnunetReturnValue.OK, createResult)
    390         
    391         // Create group
    392         val group = gnunetChat.createGroup(handle, groupName)
    393         assertNotNull("Group should be created", group)
    394         assertEquals(groupName, group.name)
    395         
    396         // Set profile name
    397         gnunetChat.setProfileName(handle, profileName)
    398         assertEquals("Profile name should be set", profileName, gnunetChat.getProfileName(handle))
    399         
    400         // Verify data exists before reset
    401         val accountsBefore = mutableListOf<ChatAccount>()
    402         gnunetChat.iterateAccounts(handle) { acc ->
    403             accountsBefore += acc
    404         }
    405         
    406         withContext(Dispatchers.Default.limitedParallelism(1)) {
    407             withTimeout(3_000) {
    408                 while (accountsBefore.none { it.name == accountName }) {
    409                     delay(50)
    410                 }
    411             }
    412         }
    413         
    414         assertTrue("Account should exist before reset", 
    415             accountsBefore.any { it.name == accountName })
    416         
    417         val groupsBefore = mutableListOf<ChatGroup>()
    418         gnunetChat.iterateGroups(handle) { grp ->
    419             groupsBefore += grp
    420             0
    421         }
    422         
    423         withContext(Dispatchers.Default.limitedParallelism(1)) {
    424             withTimeout(3_000) {
    425                 while (groupsBefore.none { it.name == groupName }) {
    426                     delay(50)
    427                 }
    428             }
    429         }
    430         
    431         assertTrue("Group should exist before reset", 
    432             groupsBefore.any { it.name == groupName })
    433         
    434         // Perform reset
    435         gnunetChat.reset()
    436         
    437         // Note: The local ChatHandle object's pointer is not automatically set to 0
    438         // because it's a local variable. The reset clears server state, but we need
    439         // to start a new session with a fresh handle.
    440         
    441         // Start a new session after reset
    442         val newHandle = gnunetChat.startChat(MessengerApp()) { ctx, msg ->
    443             messageLog.add(ctx to msg)
    444         }
    445         
    446         // Wait for new handle to be initialized
    447         withContext(Dispatchers.Default.limitedParallelism(1)) {
    448             withTimeout(5_000) {
    449                 while (newHandle.pointer == 0L) {
    450                     delay(100)
    451                 }
    452             }
    453         }
    454         
    455         // Verify old data is gone
    456         val accountsAfter = mutableListOf<ChatAccount>()
    457         gnunetChat.iterateAccounts(newHandle) { acc ->
    458             accountsAfter += acc
    459         }
    460         
    461         // Give time for iteration to complete
    462         delay(500)
    463         
    464         // The created account should be gone (only default mock accounts remain)
    465         assertTrue("Created account should not exist after reset", 
    466             !accountsAfter.any { it.name == accountName })
    467         
    468         // Profile should be back to default
    469         val defaultProfile = gnunetChat.getProfileName(newHandle)
    470         assertTrue("Profile should be reset to default", profileName != defaultProfile)
    471         assertEquals("Profile should be default 'GNUnet'", "GNUnet", defaultProfile)
    472     }
    473 }