diff --git a/app/build.gradle b/app/build.gradle index a02a4f76..1e000369 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,7 +10,7 @@ buildscript { classpath 'de.mannodermaus.gradle.plugins:android-junit5:1.8.2.1' } ext { - ktorVersion = '1.6.8' + ktorVersion = '2.3.7' junitVersion = '5.8.2' awalaTestingVersion = '1.5.10' } @@ -152,8 +152,8 @@ dependencies { // Awala implementation 'tech.relaycorp:awala:1.67.10' implementation 'tech.relaycorp:awala-keystore-file:1.6.31' - implementation 'tech.relaycorp:cogrpc:1.1.31' - implementation 'tech.relaycorp:cogrpc-okhttp:1.1.22' + implementation 'tech.relaycorp:cogrpc:1.1.32' + implementation 'tech.relaycorp:cogrpc-okhttp:1.1.28' testImplementation "tech.relaycorp:awala-testing:$awalaTestingVersion" androidTestImplementation "tech.relaycorp:awala-testing:$awalaTestingVersion" @@ -162,14 +162,14 @@ dependencies { implementation 'org.conscrypt:conscrypt-android:2.5.2' // Local and Internet-based Parcel Delivery Connections (PDCs) - implementation 'tech.relaycorp:poweb:1.5.69' + implementation 'tech.relaycorp:poweb:1.5.80' implementation "io.ktor:ktor-server-core:$ktorVersion" implementation "io.ktor:ktor-server-netty:$ktorVersion" + implementation "io.ktor:ktor-server-websockets:$ktorVersion" implementation "io.ktor:ktor-utils:$ktorVersion" - implementation "io.ktor:ktor-websockets:$ktorVersion" implementation "io.ktor:ktor-client-websockets:$ktorVersion" implementation "io.ktor:ktor-client-cio:$ktorVersion" - implementation 'tech.relaycorp:doh:1.0.10' + implementation 'tech.relaycorp:doh:1.0.51' testImplementation "io.ktor:ktor-server-test-host:$ktorVersion" testImplementation "io.ktor:ktor-test-dispatcher:$ktorVersion" diff --git a/app/lint.xml b/app/lint.xml index 9c3e2f09..1672a29e 100644 --- a/app/lint.xml +++ b/app/lint.xml @@ -18,6 +18,8 @@ + + diff --git a/app/src/androidTest/java/tech/relaycorp/gateway/background/endpoint/EndpointPreRegistrationServiceTest.kt b/app/src/androidTest/java/tech/relaycorp/gateway/background/endpoint/EndpointPreRegistrationServiceTest.kt index 23b8ef67..537b8748 100644 --- a/app/src/androidTest/java/tech/relaycorp/gateway/background/endpoint/EndpointPreRegistrationServiceTest.kt +++ b/app/src/androidTest/java/tech/relaycorp/gateway/background/endpoint/EndpointPreRegistrationServiceTest.kt @@ -8,7 +8,8 @@ import android.os.Message import android.os.Messenger import androidx.test.core.app.ApplicationProvider.getApplicationContext import androidx.test.rule.ServiceTestRule -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.runTest import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull import org.junit.Assert.assertTrue @@ -43,18 +44,19 @@ class EndpointPreRegistrationServiceTest { @Inject lateinit var internetGatewayPreferences: InternetGatewayPreferences - private val coroutineContext get() = app.backgroundScope.coroutineContext + private val coroutineContext + get() = app.backgroundScope.coroutineContext + UnconfinedTestDispatcher() @Before fun setUp() { AppTestProvider.component.inject(this) - runBlocking(coroutineContext) { + runTest(coroutineContext) { internetGatewayPreferences.setRegistrationState(RegistrationState.Done) } } @Test - fun requestPreRegistration() = runBlocking(coroutineContext) { + fun requestPreRegistration() = runTest(coroutineContext) { val serviceIntent = Intent( getApplicationContext(), EndpointPreRegistrationService::class.java, @@ -111,7 +113,7 @@ class EndpointPreRegistrationServiceTest { } @Test - fun errorReturnedWhenGatewayIsNotRegisteredYet() = runBlocking(coroutineContext) { + fun errorReturnedWhenGatewayIsNotRegisteredYet() = runTest(coroutineContext) { internetGatewayPreferences.setRegistrationState(RegistrationState.ToDo) val serviceIntent = Intent( diff --git a/app/src/androidTest/java/tech/relaycorp/gateway/background/endpoint/GatewaySyncServiceParcelCollectionTest.kt b/app/src/androidTest/java/tech/relaycorp/gateway/background/endpoint/GatewaySyncServiceParcelCollectionTest.kt index 11ef26cc..4594e34f 100644 --- a/app/src/androidTest/java/tech/relaycorp/gateway/background/endpoint/GatewaySyncServiceParcelCollectionTest.kt +++ b/app/src/androidTest/java/tech/relaycorp/gateway/background/endpoint/GatewaySyncServiceParcelCollectionTest.kt @@ -1,13 +1,14 @@ package tech.relaycorp.gateway.background.endpoint -import android.content.Context import android.content.Intent import androidx.test.core.app.ApplicationProvider.getApplicationContext import androidx.test.rule.ServiceTestRule import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.take -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.UnconfinedTestDispatcher +import kotlinx.coroutines.test.runTest +import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Before @@ -43,19 +44,22 @@ class GatewaySyncServiceParcelCollectionTest { @Inject lateinit var storeParcel: StoreParcel + private val coroutineContext + get() = UnconfinedTestDispatcher() + @Before fun setUp() { AppTestProvider.component.inject(this) - serviceRule.bindService( - Intent( - getApplicationContext(), - GatewaySyncService::class.java, - ), - ) + serviceRule.bindService(Intent(getApplicationContext(), GatewaySyncService::class.java)) + } + + @After + fun tearDown() { + Thread.sleep(3000) // Wait for netty to properly stop, to avoid a RejectedExecutionException } @Test - fun parcelCollection_receiveParcel() = runBlocking { + fun parcelCollection_receiveParcel() = runTest(coroutineContext) { val parcel = ParcelFactory.buildSerialized() val storeResult = storeParcel.store(parcel, RecipientLocation.LocalEndpoint) assertTrue(storeResult is StoreParcel.Result.Success) @@ -79,7 +83,7 @@ class GatewaySyncServiceParcelCollectionTest { } @Test(expected = ServerConnectionException::class) - fun parcelCollection_invalidHandshake() = runBlocking { + fun parcelCollection_invalidHandshake() = runTest(coroutineContext) { val parcel = ParcelFactory.buildSerialized() val storeResult = storeParcel.store(parcel, RecipientLocation.LocalEndpoint) assertTrue(storeResult is StoreParcel.Result.Success) diff --git a/app/src/androidTest/java/tech/relaycorp/gateway/background/endpoint/GatewaySyncServiceParcelDeliveryTest.kt b/app/src/androidTest/java/tech/relaycorp/gateway/background/endpoint/GatewaySyncServiceParcelDeliveryTest.kt index d9adb103..5806602b 100644 --- a/app/src/androidTest/java/tech/relaycorp/gateway/background/endpoint/GatewaySyncServiceParcelDeliveryTest.kt +++ b/app/src/androidTest/java/tech/relaycorp/gateway/background/endpoint/GatewaySyncServiceParcelDeliveryTest.kt @@ -1,11 +1,11 @@ package tech.relaycorp.gateway.background.endpoint -import android.content.Context import android.content.Intent import androidx.test.core.app.ApplicationProvider.getApplicationContext import androidx.test.rule.ServiceTestRule import kotlinx.coroutines.flow.first -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runTest +import org.junit.After import org.junit.Assert.assertEquals import org.junit.Before import org.junit.Rule @@ -44,16 +44,16 @@ class GatewaySyncServiceParcelDeliveryTest { @Before fun setUp() { AppTestProvider.component.inject(this) - serviceRule.bindService( - Intent( - getApplicationContext(), - GatewaySyncService::class.java, - ), - ) + serviceRule.bindService(Intent(getApplicationContext(), GatewaySyncService::class.java)) + } + + @After + fun tearDown() { + Thread.sleep(3000) // Wait for netty to properly stop, to avoid a RejectedExecutionException } @Test - fun parcelDelivery_validParcel() = runBlocking { + fun parcelDelivery_validParcel() = runTest { setGatewayCertificate(PDACertPath.PRIVATE_GW) val recipientId = "0deadbeef" val recipientInternetAddress = "example.org" @@ -76,7 +76,7 @@ class GatewaySyncServiceParcelDeliveryTest { } @Test(expected = RejectedParcelException::class) - fun parcelDelivery_invalidParcel() = runBlocking { + fun parcelDelivery_invalidParcel() = runTest { val fiveMinutesAgo = ZonedDateTime.now().minusMinutes(5) val recipientId = "0deadbeef" val recipientInternetAddress = "example.org" diff --git a/app/src/androidTest/java/tech/relaycorp/gateway/data/database/LocalEndpointDaoTest.kt b/app/src/androidTest/java/tech/relaycorp/gateway/data/database/LocalEndpointDaoTest.kt index aaa1925e..89882669 100644 --- a/app/src/androidTest/java/tech/relaycorp/gateway/data/database/LocalEndpointDaoTest.kt +++ b/app/src/androidTest/java/tech/relaycorp/gateway/data/database/LocalEndpointDaoTest.kt @@ -4,7 +4,7 @@ import android.content.Context import androidx.room.Room import androidx.test.core.app.ApplicationProvider.getApplicationContext import kotlinx.coroutines.flow.first -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runTest import org.junit.Assert.assertEquals import org.junit.Test import tech.relaycorp.gateway.test.factory.LocalEndpointFactory @@ -17,31 +17,27 @@ class LocalEndpointDaoTest { .localEndpointDao() @Test - internal fun countApplicationIds() { - runBlocking { - val endpoint1 = LocalEndpointFactory.build() - val endpoint2 = LocalEndpointFactory.build() - val endpoint3 = - LocalEndpointFactory.build().copy(applicationId = endpoint2.applicationId) - - listOf(endpoint1, endpoint2, endpoint3).forEach { dao.insert(it) } - - val result = dao.countApplicationIds().first() - assertEquals(2, result) - } + internal fun countApplicationIds() = runTest { + val endpoint1 = LocalEndpointFactory.build() + val endpoint2 = LocalEndpointFactory.build() + val endpoint3 = + LocalEndpointFactory.build().copy(applicationId = endpoint2.applicationId) + + listOf(endpoint1, endpoint2, endpoint3).forEach { dao.insert(it) } + + val result = dao.countApplicationIds().first() + assertEquals(2, result) } @Test - internal fun listAll() { - runBlocking { - val endpoint1 = LocalEndpointFactory.build() - val endpoint2 = LocalEndpointFactory.build() - val endpoint3 = LocalEndpointFactory.build() + internal fun listAll() = runTest { + val endpoint1 = LocalEndpointFactory.build() + val endpoint2 = LocalEndpointFactory.build() + val endpoint3 = LocalEndpointFactory.build() - listOf(endpoint1, endpoint2, endpoint3).forEach { dao.insert(it) } + listOf(endpoint1, endpoint2, endpoint3).forEach { dao.insert(it) } - val result = dao.list() - assertEquals(3, result.size) - } + val result = dao.list() + assertEquals(3, result.size) } } diff --git a/app/src/androidTest/java/tech/relaycorp/gateway/data/database/ParcelCollectionDaoTest.kt b/app/src/androidTest/java/tech/relaycorp/gateway/data/database/ParcelCollectionDaoTest.kt index e001fe52..adf95769 100644 --- a/app/src/androidTest/java/tech/relaycorp/gateway/data/database/ParcelCollectionDaoTest.kt +++ b/app/src/androidTest/java/tech/relaycorp/gateway/data/database/ParcelCollectionDaoTest.kt @@ -3,7 +3,7 @@ package tech.relaycorp.gateway.data.database import android.content.Context import androidx.room.Room import androidx.test.core.app.ApplicationProvider.getApplicationContext -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runTest import org.junit.Assert.assertFalse import org.junit.Assert.assertTrue import org.junit.Test @@ -17,17 +17,15 @@ class ParcelCollectionDaoTest { .parcelCollectionDao() @Test - internal fun exists() { - runBlocking { - val element = ParcelCollectionFactory.build() - assertFalse( - dao.exists(element.recipientAddress, element.senderAddress, element.messageId), - ) + internal fun exists() = runTest { + val element = ParcelCollectionFactory.build() + assertFalse( + dao.exists(element.recipientAddress, element.senderAddress, element.messageId), + ) - dao.insert(element) - assertTrue( - dao.exists(element.recipientAddress, element.senderAddress, element.messageId), - ) - } + dao.insert(element) + assertTrue( + dao.exists(element.recipientAddress, element.senderAddress, element.messageId), + ) } } diff --git a/app/src/androidTest/java/tech/relaycorp/gateway/data/database/StoredParcelDaoTest.kt b/app/src/androidTest/java/tech/relaycorp/gateway/data/database/StoredParcelDaoTest.kt index c1151c63..42ed08a7 100644 --- a/app/src/androidTest/java/tech/relaycorp/gateway/data/database/StoredParcelDaoTest.kt +++ b/app/src/androidTest/java/tech/relaycorp/gateway/data/database/StoredParcelDaoTest.kt @@ -4,7 +4,7 @@ import android.content.Context import androidx.room.Room import androidx.test.core.app.ApplicationProvider.getApplicationContext import kotlinx.coroutines.flow.first -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runTest import org.junit.Assert.assertEquals import org.junit.Test import tech.relaycorp.gateway.common.nowInUtc @@ -19,43 +19,39 @@ class StoredParcelDaoTest { .storedParcelDao() @Test - internal fun countSizeForRecipientLocation() { - runBlocking { - val parcels = - (1..3).map { - StoredParcelFactory.build() - .copy(recipientLocation = RecipientLocation.ExternalGateway) - .also { dao.insert(it) } - } - val totalSize = parcels.map { it.size }.reduce { acc, size -> size + acc } - - val result = - dao.countSizeForRecipientLocation(RecipientLocation.ExternalGateway).first() - assertEquals(totalSize, result) - } + internal fun countSizeForRecipientLocation() = runTest { + val parcels = + (1..3).map { + StoredParcelFactory.build() + .copy(recipientLocation = RecipientLocation.ExternalGateway) + .also { dao.insert(it) } + } + val totalSize = parcels.map { it.size }.reduce { acc, size -> size + acc } + + val result = + dao.countSizeForRecipientLocation(RecipientLocation.ExternalGateway).first() + assertEquals(totalSize, result) } @Test - internal fun listForRecipientLocation_skipsExpired() { - runBlocking { - // expired - StoredParcelFactory.build() - .copy( - recipientLocation = RecipientLocation.ExternalGateway, - expirationTimeUtc = nowInUtc().minusMinutes(5), - ) - .also { dao.insert(it) } - val parcelUnexpired = StoredParcelFactory.build() - .copy( - recipientLocation = RecipientLocation.ExternalGateway, - expirationTimeUtc = nowInUtc().plusMinutes(5), - ) - .also { dao.insert(it) } - - val result = dao.listForRecipientLocation(RecipientLocation.ExternalGateway) - - assertEquals(1, result.size) - assertEquals(parcelUnexpired, result.first()) - } + internal fun listForRecipientLocation_skipsExpired() = runTest { + // expired + StoredParcelFactory.build() + .copy( + recipientLocation = RecipientLocation.ExternalGateway, + expirationTimeUtc = nowInUtc().minusMinutes(5), + ) + .also { dao.insert(it) } + val parcelUnexpired = StoredParcelFactory.build() + .copy( + recipientLocation = RecipientLocation.ExternalGateway, + expirationTimeUtc = nowInUtc().plusMinutes(5), + ) + .also { dao.insert(it) } + + val result = dao.listForRecipientLocation(RecipientLocation.ExternalGateway) + + assertEquals(1, result.size) + assertEquals(parcelUnexpired, result.first()) } } diff --git a/app/src/androidTest/java/tech/relaycorp/gateway/data/disk/AndroidPrivateKeyStoreTest.kt b/app/src/androidTest/java/tech/relaycorp/gateway/data/disk/AndroidPrivateKeyStoreTest.kt index e10bd656..978d7a04 100644 --- a/app/src/androidTest/java/tech/relaycorp/gateway/data/disk/AndroidPrivateKeyStoreTest.kt +++ b/app/src/androidTest/java/tech/relaycorp/gateway/data/disk/AndroidPrivateKeyStoreTest.kt @@ -1,7 +1,7 @@ package tech.relaycorp.gateway.data.disk import androidx.test.core.app.ApplicationProvider -import kotlinx.coroutines.test.runBlockingTest +import kotlinx.coroutines.test.runTest import org.junit.Assert.assertEquals import org.junit.Test import tech.relaycorp.awala.keystores.file.FileKeystoreRoot @@ -14,7 +14,7 @@ class AndroidPrivateKeyStoreTest { private val privateKey = KeyPairSet.PRIVATE_GW.private @Test - fun saveAndRetrieve() = runBlockingTest { + fun saveAndRetrieve() = runTest { val androidContext = ApplicationProvider.getApplicationContext() val root = FileKeystoreRoot(File(androidContext.filesDir, "tmp-keystore")) val store = AndroidPrivateKeyStore(root, androidContext) @@ -25,7 +25,7 @@ class AndroidPrivateKeyStoreTest { } @Test - fun overrideKey() = runBlockingTest { + fun overrideKey() = runTest { val androidContext = ApplicationProvider.getApplicationContext() val root = FileKeystoreRoot(File(androidContext.filesDir, "tmp-keystore")) val store = AndroidPrivateKeyStore(root, androidContext) diff --git a/app/src/androidTest/java/tech/relaycorp/gateway/data/disk/DiskMessageOperationsTest.kt b/app/src/androidTest/java/tech/relaycorp/gateway/data/disk/DiskMessageOperationsTest.kt index e1f95572..8b129d83 100644 --- a/app/src/androidTest/java/tech/relaycorp/gateway/data/disk/DiskMessageOperationsTest.kt +++ b/app/src/androidTest/java/tech/relaycorp/gateway/data/disk/DiskMessageOperationsTest.kt @@ -2,7 +2,7 @@ package tech.relaycorp.gateway.data.disk import androidx.test.core.app.ApplicationProvider.getApplicationContext import androidx.test.ext.junit.runners.AndroidJUnit4 -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runTest import org.junit.After import org.junit.Assert.assertEquals import org.junit.Assert.assertFalse @@ -34,56 +34,46 @@ class DiskMessageOperationsTest { } @Test - fun writeMessage() { - runBlocking { - val size = Random.nextLong(1, 10) - val message = ByteArray(size.toInt()) - diskMessageOperations.writeMessage(folder.name, "file_", message) + fun writeMessage() = runTest { + val size = Random.nextLong(1, 10) + val message = ByteArray(size.toInt()) + diskMessageOperations.writeMessage(folder.name, "file_", message) - val files = folder.listFiles()!! - assertEquals(1, files.size) - assertEquals(size, files.first().length()) - } + val files = folder.listFiles()!! + assertEquals(1, files.size) + assertEquals(size, files.first().length()) } @Test - fun listMessages() { - runBlocking { - assertEquals(0, diskMessageOperations.listMessages(folder.name).size) - diskMessageOperations.writeMessage(folder.name, "file_", ByteArray(1)) - assertEquals(1, diskMessageOperations.listMessages(folder.name).size) - } + fun listMessages() = runTest { + assertEquals(0, diskMessageOperations.listMessages(folder.name).size) + diskMessageOperations.writeMessage(folder.name, "file_", ByteArray(1)) + assertEquals(1, diskMessageOperations.listMessages(folder.name).size) } @Test - fun writeAndReadMessage() { - runBlocking { - val message = "123456" - val path = - diskMessageOperations.writeMessage(folder.name, "file_", message.toByteArray()) - val result = diskMessageOperations.readMessage(folder.name, path)() - .readBytes().toString(Charset.defaultCharset()) - assertEquals(message, result) - } + fun writeAndReadMessage() = runTest { + val message = "123456" + val path = + diskMessageOperations.writeMessage(folder.name, "file_", message.toByteArray()) + val result = diskMessageOperations.readMessage(folder.name, path)() + .readBytes().toString(Charset.defaultCharset()) + assertEquals(message, result) } @Test - fun deleteMessage() { - runBlocking { - val path = diskMessageOperations.writeMessage(folder.name, "file_", ByteArray(1)) - diskMessageOperations.deleteMessage(folder.name, path) - assertFalse(File(folder, path).exists()) - } + fun deleteMessage() = runTest { + val path = diskMessageOperations.writeMessage(folder.name, "file_", ByteArray(1)) + diskMessageOperations.deleteMessage(folder.name, path) + assertFalse(File(folder, path).exists()) } @Test - fun deleteAllMessages() { - runBlocking { - repeat(3) { - diskMessageOperations.writeMessage(folder.name, "file_", ByteArray(1)) - } - diskMessageOperations.deleteAllMessages(folder.name) - assertEquals(0, folder.list()?.size ?: 0) + fun deleteAllMessages() = runTest { + repeat(3) { + diskMessageOperations.writeMessage(folder.name, "file_", ByteArray(1)) } + diskMessageOperations.deleteAllMessages(folder.name) + assertEquals(0, folder.list()?.size ?: 0) } } diff --git a/app/src/androidTest/java/tech/relaycorp/gateway/domain/endpoint/NotifyEndpointsTest.kt b/app/src/androidTest/java/tech/relaycorp/gateway/domain/endpoint/NotifyEndpointsTest.kt index d8b3b685..caed437b 100644 --- a/app/src/androidTest/java/tech/relaycorp/gateway/domain/endpoint/NotifyEndpointsTest.kt +++ b/app/src/androidTest/java/tech/relaycorp/gateway/domain/endpoint/NotifyEndpointsTest.kt @@ -10,7 +10,7 @@ import com.nhaarman.mockitokotlin2.times import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.verifyNoMoreInteractions import com.nhaarman.mockitokotlin2.whenever -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.runTest import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Test @@ -28,95 +28,85 @@ class NotifyEndpointsTest { } @Test - fun notifyAllPending_oncePerEndpoint() { - runBlocking { - val parcel1 = StoredParcelFactory.build() - .copy(recipientLocation = RecipientLocation.LocalEndpoint) - val parcel2 = StoredParcelFactory.build() - .copy(recipientLocation = RecipientLocation.LocalEndpoint) - - val endpoint1 = LocalEndpointFactory.build().copy(address = parcel1.recipientAddress) - val endpoint2 = LocalEndpointFactory.build().copy(address = parcel2.recipientAddress) - - whenever(getEndpointReceiver.get(any(), any())).thenReturn(".Receiver") - - notifyEndpoints.notify( - listOf(endpoint1, endpoint2), - NotificationType.IncomingParcel, - ) - - verify(context, times(2)).sendBroadcast( - check { - assertTrue( - listOf(endpoint1.applicationId, endpoint2.applicationId) - .contains(it.component?.packageName), - ) - assertEquals(".Receiver", it.component?.className) - }, - ) - verifyNoMoreInteractions(context) - } + fun notifyAllPending_oncePerEndpoint() = runTest { + val parcel1 = StoredParcelFactory.build() + .copy(recipientLocation = RecipientLocation.LocalEndpoint) + val parcel2 = StoredParcelFactory.build() + .copy(recipientLocation = RecipientLocation.LocalEndpoint) + + val endpoint1 = LocalEndpointFactory.build().copy(address = parcel1.recipientAddress) + val endpoint2 = LocalEndpointFactory.build().copy(address = parcel2.recipientAddress) + + whenever(getEndpointReceiver.get(any(), any())).thenReturn(".Receiver") + + notifyEndpoints.notify( + listOf(endpoint1, endpoint2), + NotificationType.IncomingParcel, + ) + + verify(context, times(2)).sendBroadcast( + check { + assertTrue( + listOf(endpoint1.applicationId, endpoint2.applicationId) + .contains(it.component?.packageName), + ) + assertEquals(".Receiver", it.component?.className) + }, + ) + verifyNoMoreInteractions(context) } @Test - fun notifyAllPending_oncePerApplicationId() { - runBlocking { - val appId = "123" - val endpoint = LocalEndpointFactory.build() - .copy(applicationId = "123") - - whenever(getEndpointReceiver.get(any(), any())).thenReturn(".Receiver") - - notifyEndpoints.notify( - listOf(endpoint, endpoint), - NotificationType.IncomingParcel, - ) - - verify(context, times(1)).sendBroadcast( - check { - assertEquals(appId, it.component?.packageName) - assertEquals(".Receiver", it.component?.className) - }, - ) - verifyNoMoreInteractions(context) - } + fun notifyAllPending_oncePerApplicationId() = runTest { + val appId = "123" + val endpoint = LocalEndpointFactory.build() + .copy(applicationId = "123") + + whenever(getEndpointReceiver.get(any(), any())).thenReturn(".Receiver") + + notifyEndpoints.notify( + listOf(endpoint, endpoint), + NotificationType.IncomingParcel, + ) + + verify(context, times(1)).sendBroadcast( + check { + assertEquals(appId, it.component?.packageName) + assertEquals(".Receiver", it.component?.className) + }, + ) + verifyNoMoreInteractions(context) } @Test - fun notify_withKnownAddressAndReceiver() { - runBlocking { - val endpoint = LocalEndpointFactory.build() - val receiverName = "${endpoint.applicationId}.Receiver" - whenever(getEndpointReceiver.get(any(), any())).thenReturn(receiverName) - - notifyEndpoints.notify(endpoint, NotificationType.IncomingParcel) - - verify(context).sendBroadcast( - check { - assertEquals(endpoint.applicationId, it.component?.packageName) - assertEquals(receiverName, it.component?.className) - }, - ) - } + fun notify_withKnownAddressAndReceiver() = runTest { + val endpoint = LocalEndpointFactory.build() + val receiverName = "${endpoint.applicationId}.Receiver" + whenever(getEndpointReceiver.get(any(), any())).thenReturn(receiverName) + + notifyEndpoints.notify(endpoint, NotificationType.IncomingParcel) + + verify(context).sendBroadcast( + check { + assertEquals(endpoint.applicationId, it.component?.packageName) + assertEquals(receiverName, it.component?.className) + }, + ) } @Test - fun notify_withKnownAddressButWithoutReceiver() { - runBlocking { - whenever(getEndpointReceiver.get(any(), any())).thenReturn(null) - verifyNoMoreInteractions(context) - } + fun notify_withKnownAddressButWithoutReceiver() = runTest { + whenever(getEndpointReceiver.get(any(), any())).thenReturn(null) + verifyNoMoreInteractions(context) } @Test - fun notify_withUnknownAddress() { - runBlocking { - whenever(getEndpointReceiver.get(any(), any())).thenReturn(null) - notifyEndpoints.notify( - LocalEndpointFactory.build(), - NotificationType.IncomingParcel, - ) - verify(context, never()).sendBroadcast(any(), any()) - } + fun notify_withUnknownAddress() = runTest { + whenever(getEndpointReceiver.get(any(), any())).thenReturn(null) + notifyEndpoints.notify( + LocalEndpointFactory.build(), + NotificationType.IncomingParcel, + ) + verify(context, never()).sendBroadcast(any(), any()) } } diff --git a/app/src/main/java/tech/relaycorp/gateway/background/PingRemoteServer.kt b/app/src/main/java/tech/relaycorp/gateway/background/PingRemoteServer.kt index a3b4f565..0218d4f2 100644 --- a/app/src/main/java/tech/relaycorp/gateway/background/PingRemoteServer.kt +++ b/app/src/main/java/tech/relaycorp/gateway/background/PingRemoteServer.kt @@ -2,8 +2,8 @@ package tech.relaycorp.gateway.background import io.ktor.client.HttpClient import io.ktor.client.engine.android.Android -import io.ktor.client.features.ResponseException -import io.ktor.client.features.UserAgent +import io.ktor.client.plugins.ResponseException +import io.ktor.client.plugins.UserAgent import io.ktor.client.request.head import io.ktor.network.selector.ActorSelectorManager import io.ktor.network.sockets.aSocket @@ -42,7 +42,7 @@ class PingRemoteServer suspend fun pingURL(url: String) = try { withTimeout(TIMEOUT) { - ktorClient.head(url) + ktorClient.head(url) true } } catch (e: IOException) { diff --git a/app/src/main/java/tech/relaycorp/gateway/pdc/local/PDCServer.kt b/app/src/main/java/tech/relaycorp/gateway/pdc/local/PDCServer.kt index 6276c0b3..dac23acc 100644 --- a/app/src/main/java/tech/relaycorp/gateway/pdc/local/PDCServer.kt +++ b/app/src/main/java/tech/relaycorp/gateway/pdc/local/PDCServer.kt @@ -1,11 +1,11 @@ package tech.relaycorp.gateway.pdc.local -import io.ktor.application.Application -import io.ktor.application.install -import io.ktor.routing.routing +import io.ktor.server.application.Application +import io.ktor.server.application.install import io.ktor.server.engine.embeddedServer import io.ktor.server.netty.Netty -import io.ktor.websocket.WebSockets +import io.ktor.server.routing.routing +import io.ktor.server.websocket.WebSockets import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import tech.relaycorp.gateway.pdc.local.routes.EndpointRegistrationRoute diff --git a/app/src/main/java/tech/relaycorp/gateway/pdc/local/routes/EndpointRegistrationRoute.kt b/app/src/main/java/tech/relaycorp/gateway/pdc/local/routes/EndpointRegistrationRoute.kt index dfeb63a0..7a8f8157 100644 --- a/app/src/main/java/tech/relaycorp/gateway/pdc/local/routes/EndpointRegistrationRoute.kt +++ b/app/src/main/java/tech/relaycorp/gateway/pdc/local/routes/EndpointRegistrationRoute.kt @@ -1,13 +1,13 @@ package tech.relaycorp.gateway.pdc.local.routes -import io.ktor.application.call import io.ktor.http.HttpStatusCode -import io.ktor.request.contentType -import io.ktor.request.receive -import io.ktor.response.respondBytes -import io.ktor.response.respondText -import io.ktor.routing.Routing -import io.ktor.routing.post +import io.ktor.server.application.call +import io.ktor.server.request.contentType +import io.ktor.server.request.receive +import io.ktor.server.response.respondBytes +import io.ktor.server.response.respondText +import io.ktor.server.routing.Routing +import io.ktor.server.routing.post import tech.relaycorp.gateway.domain.endpoint.EndpointRegistration import tech.relaycorp.gateway.domain.endpoint.InvalidPNRAException import tech.relaycorp.gateway.pdc.local.utils.ContentType diff --git a/app/src/main/java/tech/relaycorp/gateway/pdc/local/routes/PDCServerRoute.kt b/app/src/main/java/tech/relaycorp/gateway/pdc/local/routes/PDCServerRoute.kt index 1ea290db..48542bee 100644 --- a/app/src/main/java/tech/relaycorp/gateway/pdc/local/routes/PDCServerRoute.kt +++ b/app/src/main/java/tech/relaycorp/gateway/pdc/local/routes/PDCServerRoute.kt @@ -1,6 +1,6 @@ package tech.relaycorp.gateway.pdc.local.routes -import io.ktor.routing.Routing +import io.ktor.server.routing.Routing interface PDCServerRoute { fun register(routing: Routing) diff --git a/app/src/main/java/tech/relaycorp/gateway/pdc/local/routes/ParcelCollectionRoute.kt b/app/src/main/java/tech/relaycorp/gateway/pdc/local/routes/ParcelCollectionRoute.kt index 9aca8ea2..2a3fc2c7 100644 --- a/app/src/main/java/tech/relaycorp/gateway/pdc/local/routes/ParcelCollectionRoute.kt +++ b/app/src/main/java/tech/relaycorp/gateway/pdc/local/routes/ParcelCollectionRoute.kt @@ -1,14 +1,14 @@ package tech.relaycorp.gateway.pdc.local.routes import androidx.annotation.VisibleForTesting -import io.ktor.http.cio.websocket.CloseReason -import io.ktor.http.cio.websocket.Frame -import io.ktor.http.cio.websocket.close -import io.ktor.http.cio.websocket.readText -import io.ktor.request.header -import io.ktor.routing.Routing -import io.ktor.websocket.DefaultWebSocketServerSession -import io.ktor.websocket.webSocket +import io.ktor.server.request.header +import io.ktor.server.routing.Routing +import io.ktor.server.websocket.DefaultWebSocketServerSession +import io.ktor.server.websocket.webSocket +import io.ktor.websocket.CloseReason +import io.ktor.websocket.Frame +import io.ktor.websocket.close +import io.ktor.websocket.readText import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.channels.ClosedReceiveChannelException diff --git a/app/src/main/java/tech/relaycorp/gateway/pdc/local/routes/ParcelDeliveryRoute.kt b/app/src/main/java/tech/relaycorp/gateway/pdc/local/routes/ParcelDeliveryRoute.kt index 645990ad..fc72f1ac 100644 --- a/app/src/main/java/tech/relaycorp/gateway/pdc/local/routes/ParcelDeliveryRoute.kt +++ b/app/src/main/java/tech/relaycorp/gateway/pdc/local/routes/ParcelDeliveryRoute.kt @@ -1,13 +1,13 @@ package tech.relaycorp.gateway.pdc.local.routes -import io.ktor.application.call import io.ktor.http.HttpStatusCode -import io.ktor.request.contentType -import io.ktor.request.receive -import io.ktor.response.respond -import io.ktor.response.respondText -import io.ktor.routing.Routing -import io.ktor.routing.post +import io.ktor.server.application.call +import io.ktor.server.request.contentType +import io.ktor.server.request.receive +import io.ktor.server.response.respond +import io.ktor.server.response.respondText +import io.ktor.server.routing.Routing +import io.ktor.server.routing.post import tech.relaycorp.gateway.data.model.RecipientLocation import tech.relaycorp.gateway.domain.StoreParcel import tech.relaycorp.gateway.pdc.local.utils.ContentType diff --git a/app/src/main/java/tech/relaycorp/gateway/pdc/local/utils/ParcelCollectionHandshake.kt b/app/src/main/java/tech/relaycorp/gateway/pdc/local/utils/ParcelCollectionHandshake.kt index e16b541f..be18787b 100644 --- a/app/src/main/java/tech/relaycorp/gateway/pdc/local/utils/ParcelCollectionHandshake.kt +++ b/app/src/main/java/tech/relaycorp/gateway/pdc/local/utils/ParcelCollectionHandshake.kt @@ -1,10 +1,10 @@ package tech.relaycorp.gateway.pdc.local.utils -import io.ktor.http.cio.websocket.CloseReason -import io.ktor.http.cio.websocket.Frame -import io.ktor.http.cio.websocket.close -import io.ktor.http.cio.websocket.readBytes -import io.ktor.websocket.DefaultWebSocketServerSession +import io.ktor.server.websocket.DefaultWebSocketServerSession +import io.ktor.websocket.CloseReason +import io.ktor.websocket.Frame +import io.ktor.websocket.close +import io.ktor.websocket.readBytes import tech.relaycorp.gateway.domain.LocalConfig import tech.relaycorp.relaynet.bindings.pdc.DetachedSignatureType import tech.relaycorp.relaynet.bindings.pdc.InvalidSignatureException diff --git a/app/src/test/java/tech/relaycorp/gateway/data/doh/ResolveServiceAddressTest.kt b/app/src/test/java/tech/relaycorp/gateway/data/doh/ResolveServiceAddressTest.kt index 5d8bbb93..a704ec2c 100644 --- a/app/src/test/java/tech/relaycorp/gateway/data/doh/ResolveServiceAddressTest.kt +++ b/app/src/test/java/tech/relaycorp/gateway/data/doh/ResolveServiceAddressTest.kt @@ -3,13 +3,16 @@ package tech.relaycorp.gateway.data.doh import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.whenever -import kotlinx.coroutines.test.runBlockingTest +import kotlinx.coroutines.test.runTest import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import tech.relaycorp.doh.Answer import tech.relaycorp.doh.DoHClient import tech.relaycorp.doh.LookupFailureException +import kotlin.test.assertEquals +import kotlin.test.assertNull +import kotlin.test.assertTrue class ResolveServiceAddressTest { private val mockDoHClient = mock() @@ -22,19 +25,19 @@ class ResolveServiceAddressTest { @Nested inner class ResolvePoWebAddress { @Test - fun `Target host and port should be returned`() = runBlockingTest { + fun `Target host and port should be returned`() = runTest { whenever(mockDoHClient.lookUp("_awala-gsc._tcp.$internetGatewayAddress", "SRV")) .thenReturn( Answer(listOf("0 1 $internetGatewayTargetPort $internetGatewayTargetHost.")), ) val address = subject.resolvePoWeb(internetGatewayAddress) - kotlin.test.assertEquals(internetGatewayTargetHost, address.host) - kotlin.test.assertEquals(internetGatewayTargetPort, address.port) + assertEquals(internetGatewayTargetHost, address.host) + assertEquals(internetGatewayTargetPort, address.port) } @Test - fun `SRV data with fewer than four fields should be refused`() = runBlockingTest { + fun `SRV data with fewer than four fields should be refused`() = runTest { val malformedSRVData = "0 1 3" whenever(mockDoHClient.lookUp("_awala-gsc._tcp.$internetGatewayAddress", "SRV")) .thenReturn(Answer(listOf(malformedSRVData))) @@ -43,15 +46,15 @@ class ResolveServiceAddressTest { subject.resolvePoWeb(internetGatewayAddress) } - kotlin.test.assertEquals( + assertEquals( "Malformed SRV for $internetGatewayAddress ($malformedSRVData)", exception.message, ) - kotlin.test.assertNull(exception.cause) + assertNull(exception.cause) } @Test - fun `Lookup errors should be wrapped`() = runBlockingTest { + fun `Lookup errors should be wrapped`() = runTest { val lookupException = LookupFailureException("Whoops") whenever(mockDoHClient.lookUp(any(), any())).thenThrow(lookupException) @@ -59,8 +62,8 @@ class ResolveServiceAddressTest { subject.resolvePoWeb(internetGatewayAddress) } - kotlin.test.assertEquals("Failed to resolve DNS for PoWeb address", exception.message) - kotlin.test.assertTrue(exception.cause is LookupFailureException) + assertEquals("Failed to resolve DNS for PoWeb address", exception.message) + assertTrue(exception.cause is LookupFailureException) } } } diff --git a/app/src/test/java/tech/relaycorp/gateway/pdc/local/routes/ParcelCollectionHandshakeTest.kt b/app/src/test/java/tech/relaycorp/gateway/pdc/local/routes/ParcelCollectionHandshakeTest.kt index 44d06544..3257ad8c 100644 --- a/app/src/test/java/tech/relaycorp/gateway/pdc/local/routes/ParcelCollectionHandshakeTest.kt +++ b/app/src/test/java/tech/relaycorp/gateway/pdc/local/routes/ParcelCollectionHandshakeTest.kt @@ -3,11 +3,13 @@ package tech.relaycorp.gateway.pdc.local.routes import com.nhaarman.mockitokotlin2.any import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.whenever -import io.ktor.http.cio.websocket.CloseReason -import io.ktor.http.cio.websocket.Frame -import io.ktor.http.cio.websocket.FrameType -import io.ktor.http.cio.websocket.readBytes -import io.ktor.http.cio.websocket.readReason +import io.ktor.server.testing.handleWebSocketConversation +import io.ktor.websocket.CloseReason +import io.ktor.websocket.Frame +import io.ktor.websocket.FrameType +import io.ktor.websocket.readBytes +import io.ktor.websocket.readReason +import io.netty.handler.codec.http.HttpHeaders.addHeader import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.runBlockingTest import org.junit.jupiter.api.Assertions diff --git a/app/src/test/java/tech/relaycorp/gateway/pdc/local/routes/ParcelCollectionRouteTest.kt b/app/src/test/java/tech/relaycorp/gateway/pdc/local/routes/ParcelCollectionRouteTest.kt index b2b78342..38ff32e3 100644 --- a/app/src/test/java/tech/relaycorp/gateway/pdc/local/routes/ParcelCollectionRouteTest.kt +++ b/app/src/test/java/tech/relaycorp/gateway/pdc/local/routes/ParcelCollectionRouteTest.kt @@ -7,10 +7,11 @@ import com.nhaarman.mockitokotlin2.mock import com.nhaarman.mockitokotlin2.never import com.nhaarman.mockitokotlin2.verify import com.nhaarman.mockitokotlin2.whenever -import io.ktor.http.cio.websocket.CloseReason -import io.ktor.http.cio.websocket.Frame -import io.ktor.http.cio.websocket.FrameType -import io.ktor.http.cio.websocket.readReason +import io.ktor.server.testing.handleWebSocketConversation +import io.ktor.websocket.CloseReason +import io.ktor.websocket.Frame +import io.ktor.websocket.FrameType +import io.ktor.websocket.readReason import kotlinx.coroutines.delay import kotlinx.coroutines.flow.emptyFlow import kotlinx.coroutines.flow.flowOf