Skip to content

Commit

Permalink
fix: Receivers should await setup
Browse files Browse the repository at this point in the history
  • Loading branch information
sdsantos committed Sep 26, 2023
1 parent 2152e28 commit 4fe2873
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 21 deletions.
48 changes: 34 additions & 14 deletions lib/src/main/java/tech/relaycorp/awaladroid/Awala.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package tech.relaycorp.awaladroid

import android.content.Context
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.TimeoutCancellationException
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withTimeout
import tech.relaycorp.awala.keystores.file.FileCertificateStore
import tech.relaycorp.awala.keystores.file.FileKeystoreRoot
import tech.relaycorp.awala.keystores.file.FileSessionPublicKeystore
Expand All @@ -15,6 +18,8 @@ import tech.relaycorp.awaladroid.storage.StorageImpl
import tech.relaycorp.awaladroid.storage.persistence.DiskPersistence
import tech.relaycorp.relaynet.nodes.EndpointManager
import java.io.File
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds

public object Awala {
internal const val POWEB_PORT = 13276
Expand All @@ -39,19 +44,21 @@ public object Awala {
val fileSessionPublicKeystore = FileSessionPublicKeystore(keystoreRoot)
val fileCertificateStore = FileCertificateStore(keystoreRoot)

this.context = AwalaContext(
StorageImpl(DiskPersistence(context.filesDir.path.toString())),
GatewayClientImpl(
serviceInteractorBuilder = { ServiceInteractor(context) },
contextDeferred.complete(
AwalaContext(
StorageImpl(DiskPersistence(context.filesDir.path.toString())),
GatewayClientImpl(
serviceInteractorBuilder = { ServiceInteractor(context) },
),
EndpointManager(androidPrivateKeyStore, fileSessionPublicKeystore),
ChannelManager {
context.getSharedPreferences("awaladroid-channels", Context.MODE_PRIVATE)
},
androidPrivateKeyStore,
fileSessionPublicKeystore,
fileCertificateStore,
HandleGatewayCertificateChange(androidPrivateKeyStore),
),
EndpointManager(androidPrivateKeyStore, fileSessionPublicKeystore),
ChannelManager {
context.getSharedPreferences("awaladroid-channels", Context.MODE_PRIVATE)
},
androidPrivateKeyStore,
fileSessionPublicKeystore,
fileCertificateStore,
HandleGatewayCertificateChange(androidPrivateKeyStore),
)

coroutineScope {
Expand All @@ -62,8 +69,21 @@ public object Awala {
}
}

internal var context: AwalaContext? = null
internal fun getContextOrThrow(): AwalaContext = context ?: throw SetupPendingException()
internal var contextDeferred: CompletableDeferred<AwalaContext> = CompletableDeferred()

internal fun getContextOrThrow(): AwalaContext = try {
contextDeferred.getCompleted()
} catch (e: IllegalStateException) {
throw SetupPendingException()
}

internal suspend fun awaitContextOrThrow(timeout: Duration = 3.seconds): AwalaContext = try {
withTimeout(timeout) {
contextDeferred.await()
}
} catch (e: TimeoutCancellationException) {
throw SetupPendingException()
}
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ internal class GatewayCertificateChangeBroadcastReceiver : BroadcastReceiver() {

override fun onReceive(context: Context?, intent: Intent?) {
CoroutineScope(coroutineContext).launch {
Awala.getContextOrThrow().handleGatewayCertificateChange()
Awala.awaitContextOrThrow().handleGatewayCertificateChange()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ internal class IncomingParcelBroadcastReceiver : BroadcastReceiver() {

override fun onReceive(context: Context?, intent: Intent?) {
CoroutineScope(coroutineContext).launch {
Awala.getContextOrThrow().gatewayClient.checkForNewMessages()
Awala.awaitContextOrThrow().gatewayClient.checkForNewMessages()
}
}
}
33 changes: 30 additions & 3 deletions lib/src/test/java/tech/relaycorp/awaladroid/AwalaTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,16 @@ package tech.relaycorp.awaladroid
import android.content.Context
import com.nhaarman.mockitokotlin2.spy
import com.nhaarman.mockitokotlin2.verify
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertThrows
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
Expand All @@ -26,16 +29,17 @@ import tech.relaycorp.relaynet.wrappers.nodeId
import java.io.File
import java.time.Duration
import java.time.ZonedDateTime
import kotlin.time.Duration.Companion.milliseconds

@RunWith(RobolectricTestRunner::class)
public class AwalaTest {
@Before
@After
public fun tearDownAwala(): Unit = unsetAwalaContext()

@Test
@Test(expected = SetupPendingException::class)
public fun useBeforeSetup() {
assertThrows(SetupPendingException::class.java) { Awala.getContextOrThrow() }
Awala.getContextOrThrow()
}

@Test
Expand All @@ -45,6 +49,29 @@ public class AwalaTest {
Awala.getContextOrThrow()
}

@Test(expected = SetupPendingException::class)
public fun awaitWithoutSetup(): Unit = runTest {
Awala.awaitContextOrThrow(100.milliseconds)
}

@Test(expected = SetupPendingException::class)
public fun awaitWithLateSetup(): Unit = runTest {
CoroutineScope(UnconfinedTestDispatcher()).launch {
delay(200.milliseconds)
Awala.setUp(RuntimeEnvironment.getApplication())
}
Awala.awaitContextOrThrow(100.milliseconds)
}

@Test(expected = SetupPendingException::class)
public fun awaitAfterSetup(): Unit = runTest {
CoroutineScope(UnconfinedTestDispatcher()).launch {
delay(500.milliseconds)
Awala.setUp(RuntimeEnvironment.getApplication())
}
Awala.awaitContextOrThrow(1000.milliseconds)
}

@Test
public fun keystores(): Unit = runTest {
val androidContext = RuntimeEnvironment.getApplication()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package tech.relaycorp.awaladroid.test

import kotlinx.coroutines.CompletableDeferred
import tech.relaycorp.awaladroid.Awala
import tech.relaycorp.awaladroid.AwalaContext

internal fun setAwalaContext(context: AwalaContext) {
Awala.context = context
Awala.contextDeferred = CompletableDeferred(context)
}

internal fun unsetAwalaContext() {
Awala.context = null
Awala.contextDeferred = CompletableDeferred()
}

0 comments on commit 4fe2873

Please sign in to comment.