diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 7fa3fa7f55..84d98bee94 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -650,7 +650,6 @@ dependencies { androidTestImplementation(testLibs.androidx.test.ext.junit.ktx) androidTestImplementation(testLibs.assertk) androidTestImplementation(testLibs.mockk.android) - androidTestImplementation(testLibs.square.okhttp.mockserver) androidTestImplementation(testLibs.diff.utils) androidTestUtil(testLibs.androidx.test.orchestrator) diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/dependencies/InstrumentationApplicationDependencyProvider.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/dependencies/InstrumentationApplicationDependencyProvider.kt index f6f35c81cb..ba84a9125c 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/dependencies/InstrumentationApplicationDependencyProvider.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/dependencies/InstrumentationApplicationDependencyProvider.kt @@ -1,29 +1,11 @@ package org.thoughtcrime.securesms.dependencies import android.app.Application -import io.mockk.every import io.mockk.mockk import io.mockk.spyk -import okhttp3.ConnectionSpec -import okhttp3.Response -import okhttp3.WebSocket -import okhttp3.WebSocketListener -import okhttp3.mockwebserver.Dispatcher -import okhttp3.mockwebserver.MockResponse -import okhttp3.mockwebserver.MockWebServer -import okhttp3.mockwebserver.RecordedRequest -import okio.ByteString -import org.signal.core.util.Base64 import org.signal.core.util.billing.BillingApi -import org.signal.core.util.logging.Log -import org.thoughtcrime.securesms.BuildConfig import org.thoughtcrime.securesms.push.SignalServiceNetworkAccess -import org.thoughtcrime.securesms.push.SignalServiceTrustStore import org.thoughtcrime.securesms.recipients.LiveRecipientCache -import org.thoughtcrime.securesms.testing.Get -import org.thoughtcrime.securesms.testing.Verb -import org.thoughtcrime.securesms.testing.runSync -import org.thoughtcrime.securesms.testing.success import org.whispersystems.signalservice.api.SignalServiceDataStore import org.whispersystems.signalservice.api.SignalServiceMessageSender import org.whispersystems.signalservice.api.account.AccountApi @@ -32,17 +14,8 @@ import org.whispersystems.signalservice.api.attachment.AttachmentApi import org.whispersystems.signalservice.api.donations.DonationsApi import org.whispersystems.signalservice.api.keys.KeysApi import org.whispersystems.signalservice.api.message.MessageApi -import org.whispersystems.signalservice.api.push.TrustStore import org.whispersystems.signalservice.api.websocket.SignalWebSocket -import org.whispersystems.signalservice.internal.configuration.SignalCdnUrl -import org.whispersystems.signalservice.internal.configuration.SignalCdsiUrl -import org.whispersystems.signalservice.internal.configuration.SignalServiceConfiguration -import org.whispersystems.signalservice.internal.configuration.SignalServiceUrl -import org.whispersystems.signalservice.internal.configuration.SignalStorageUrl -import org.whispersystems.signalservice.internal.configuration.SignalSvr2Url import org.whispersystems.signalservice.internal.push.PushServiceSocket -import java.net.InetAddress -import java.util.Optional /** * Dependency provider used for instrumentation tests (aka androidTests). @@ -51,70 +24,12 @@ import java.util.Optional */ class InstrumentationApplicationDependencyProvider(val application: Application, private val default: ApplicationDependencyProvider) : AppDependencies.Provider by default { - private val serviceTrustStore: TrustStore - private val uncensoredConfiguration: SignalServiceConfiguration - private val serviceNetworkAccessMock: SignalServiceNetworkAccess private val recipientCache: LiveRecipientCache private var signalServiceMessageSender: SignalServiceMessageSender? = null private var billingApi: BillingApi = mockk() private var accountApi: AccountApi = mockk() init { - runSync { - webServer = MockWebServer() - webServer.start(InetAddress.getByAddress(byteArrayOf(0x7f, 0x0, 0x0, 0x1)), 8080) - - baseUrl = webServer.url("").toString() - - addMockWebRequestHandlers( - Get("/v1/websocket/?login=") { - MockResponse().success().withWebSocketUpgrade(mockIdentifiedWebSocket) - }, - Get("/v1/websocket", { - val path = it.path - return@Get path == null || !path.contains("login") - }) { - MockResponse().success().withWebSocketUpgrade(object : WebSocketListener() {}) - } - ) - } - - webServer.dispatcher = object : Dispatcher() { - override fun dispatch(request: RecordedRequest): MockResponse { - val handler = handlers.firstOrNull { it.requestPredicate(request) } - return handler?.responseFactory?.invoke(request) ?: MockResponse().setResponseCode(500) - } - } - - serviceTrustStore = SignalServiceTrustStore(application) - uncensoredConfiguration = SignalServiceConfiguration( - signalServiceUrls = arrayOf(SignalServiceUrl(baseUrl, "localhost", serviceTrustStore, ConnectionSpec.CLEARTEXT)), - signalCdnUrlMap = mapOf( - 0 to arrayOf(SignalCdnUrl(baseUrl, "localhost", serviceTrustStore, ConnectionSpec.CLEARTEXT)), - 2 to arrayOf(SignalCdnUrl(baseUrl, "localhost", serviceTrustStore, ConnectionSpec.CLEARTEXT)) - ), - signalStorageUrls = arrayOf(SignalStorageUrl(baseUrl, "localhost", serviceTrustStore, ConnectionSpec.CLEARTEXT)), - signalCdsiUrls = arrayOf(SignalCdsiUrl(baseUrl, "localhost", serviceTrustStore, ConnectionSpec.CLEARTEXT)), - signalSvr2Urls = arrayOf(SignalSvr2Url(baseUrl, serviceTrustStore, "localhost", ConnectionSpec.CLEARTEXT)), - networkInterceptors = emptyList(), - dns = Optional.of(SignalServiceNetworkAccess.DNS), - signalProxy = Optional.empty(), - systemHttpProxy = Optional.empty(), - zkGroupServerPublicParams = Base64.decode(BuildConfig.ZKGROUP_SERVER_PUBLIC_PARAMS), - genericServerPublicParams = Base64.decode(BuildConfig.GENERIC_SERVER_PUBLIC_PARAMS), - backupServerPublicParams = Base64.decode(BuildConfig.BACKUP_SERVER_PUBLIC_PARAMS), - censored = false - ) - - serviceNetworkAccessMock = mockk() - - every { serviceNetworkAccessMock.isCensored() } returns false - every { serviceNetworkAccessMock.isCensored(any()) } returns false - every { serviceNetworkAccessMock.isCountryCodeCensoredByDefault(any()) } returns false - every { serviceNetworkAccessMock.getConfiguration() } returns uncensoredConfiguration - every { serviceNetworkAccessMock.getConfiguration(any()) } returns uncensoredConfiguration - every { serviceNetworkAccessMock.uncensoredConfiguration } returns uncensoredConfiguration - recipientCache = LiveRecipientCache(application) { r -> r.run() } } @@ -122,10 +37,6 @@ class InstrumentationApplicationDependencyProvider(val application: Application, override fun provideAccountApi(authWebSocket: SignalWebSocket.AuthenticatedWebSocket): AccountApi = accountApi - override fun provideSignalServiceNetworkAccess(): SignalServiceNetworkAccess { - return serviceNetworkAccessMock - } - override fun provideRecipientCache(): LiveRecipientCache { return recipientCache } @@ -150,54 +61,4 @@ class InstrumentationApplicationDependencyProvider(val application: Application, } return signalServiceMessageSender!! } - - class MockWebSocket : WebSocketListener() { - private val TAG = "MockWebSocket" - - var webSocket: WebSocket? = null - private set - - override fun onOpen(webSocket: WebSocket, response: Response) { - Log.i(TAG, "onOpen(${webSocket.hashCode()})") - this.webSocket = webSocket - } - - override fun onClosing(webSocket: WebSocket, code: Int, reason: String) { - Log.i(TAG, "onClosing(${webSocket.hashCode()}): $code, $reason") - this.webSocket = null - } - - override fun onClosed(webSocket: WebSocket, code: Int, reason: String) { - Log.i(TAG, "onClosed(${webSocket.hashCode()}): $code, $reason") - this.webSocket = null - } - - override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) { - Log.w(TAG, "onFailure(${webSocket.hashCode()})", t) - this.webSocket = null - } - } - - companion object { - lateinit var webServer: MockWebServer - private set - lateinit var baseUrl: String - private set - - val mockIdentifiedWebSocket = MockWebSocket() - - private val handlers: MutableList = mutableListOf() - - fun addMockWebRequestHandlers(vararg verbs: Verb) { - handlers.addAll(verbs) - } - - fun injectWebSocketMessage(value: ByteString) { - mockIdentifiedWebSocket.webSocket!!.send(value) - } - - fun clearHandlers() { - handlers.clear() - } - } } diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/jobs/InAppPaymentAuthCheckJobTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/jobs/InAppPaymentAuthCheckJobTest.kt index 00334354d5..a4cefddf2f 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/jobs/InAppPaymentAuthCheckJobTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/jobs/InAppPaymentAuthCheckJobTest.kt @@ -3,7 +3,6 @@ package org.thoughtcrime.securesms.jobs import androidx.test.ext.junit.runners.AndroidJUnit4 import assertk.assertThat import assertk.assertions.isEmpty -import okhttp3.mockwebserver.MockResponse import org.junit.Before import org.junit.Rule import org.junit.Test @@ -11,19 +10,13 @@ import org.junit.runner.RunWith import org.signal.core.util.deleteAll import org.signal.core.util.money.FiatMoney import org.signal.donations.InAppPaymentType -import org.signal.donations.json.StripeIntentStatus -import org.signal.donations.json.StripePaymentIntent import org.thoughtcrime.securesms.components.settings.app.subscription.DonationSerializationHelper.toFiatValue import org.thoughtcrime.securesms.database.DonationReceiptTable import org.thoughtcrime.securesms.database.InAppPaymentTable import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.database.model.InAppPaymentReceiptRecord import org.thoughtcrime.securesms.database.model.databaseprotos.InAppPaymentData -import org.thoughtcrime.securesms.dependencies.InstrumentationApplicationDependencyProvider -import org.thoughtcrime.securesms.testing.Get import org.thoughtcrime.securesms.testing.SignalActivityRule -import org.thoughtcrime.securesms.testing.success -import org.thoughtcrime.securesms.util.TestStripePaths import java.math.BigDecimal import java.util.Currency @@ -46,8 +39,6 @@ class InAppPaymentAuthCheckJobTest { @Test fun givenCanceledOneTimeAuthRequiredPayment_whenICheck_thenIDoNotExpectAReceipt() { - initializeMockGetPaymentIntent(status = StripeIntentStatus.CANCELED) - SignalDatabase.inAppPayments.insert( type = InAppPaymentType.ONE_TIME_DONATION, state = InAppPaymentTable.State.WAITING_FOR_AUTHORIZATION, @@ -67,19 +58,4 @@ class InAppPaymentAuthCheckJobTest { val receipts = SignalDatabase.donationReceipts.getReceipts(InAppPaymentReceiptRecord.Type.ONE_TIME_DONATION) assertThat(receipts).isEmpty() } - - private fun initializeMockGetPaymentIntent(status: StripeIntentStatus) { - InstrumentationApplicationDependencyProvider.addMockWebRequestHandlers( - Get(TestStripePaths.getPaymentIntentPath(TEST_INTENT_ID, TEST_CLIENT_SECRET)) { - MockResponse().success( - StripePaymentIntent( - id = TEST_INTENT_ID, - clientSecret = TEST_CLIENT_SECRET, - status = status, - paymentMethod = null - ) - ) - } - ) - } } diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/MessageProcessingPerformanceTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/messages/MessageProcessingPerformanceTest.kt index 42bbfe5592..362336196a 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/messages/MessageProcessingPerformanceTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/messages/MessageProcessingPerformanceTest.kt @@ -16,7 +16,6 @@ import org.signal.core.util.logging.Log import org.signal.libsignal.protocol.ecc.ECKeyPair import org.signal.libsignal.zkgroup.profiles.ProfileKey import org.thoughtcrime.securesms.crypto.SealedSenderAccessUtil -import org.thoughtcrime.securesms.dependencies.InstrumentationApplicationDependencyProvider import org.thoughtcrime.securesms.recipients.Recipient import org.thoughtcrime.securesms.testing.AliceClient import org.thoughtcrime.securesms.testing.BobClient @@ -94,13 +93,7 @@ class MessageProcessingPerformanceTest { val lastTimestamp = envelopes.last().timestamp ?: 0 // Inject the envelopes into the websocket - Thread { - for (envelope in envelopes) { - Log.i(TIMING_TAG, "Retrieved envelope! ${envelope.timestamp}") - InstrumentationApplicationDependencyProvider.injectWebSocketMessage(envelope.toWebSocketPayload()) - } - InstrumentationApplicationDependencyProvider.injectWebSocketMessage(webSocketTombstone()) - }.start() + // TODO: mock websocket messages // Wait until they've all been fully decrypted + processed harness diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/profiles/manage/UsernameEditFragmentTest.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/profiles/manage/UsernameEditFragmentTest.kt index 8489be3f60..25400b4245 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/profiles/manage/UsernameEditFragmentTest.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/profiles/manage/UsernameEditFragmentTest.kt @@ -22,20 +22,14 @@ import assertk.assertThat import assertk.assertions.isNotNull import assertk.assertions.isNull import io.reactivex.rxjava3.schedulers.TestScheduler -import okhttp3.mockwebserver.MockResponse -import org.junit.After import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.thoughtcrime.securesms.R -import org.thoughtcrime.securesms.dependencies.InstrumentationApplicationDependencyProvider -import org.thoughtcrime.securesms.testing.Put import org.thoughtcrime.securesms.testing.RxTestSchedulerRule import org.thoughtcrime.securesms.testing.SignalActivityRule -import org.thoughtcrime.securesms.testing.success import org.whispersystems.signalservice.api.util.Usernames -import org.whispersystems.signalservice.internal.push.ReserveUsernameResponse import java.util.concurrent.TimeUnit @RunWith(AndroidJUnit4::class) @@ -53,11 +47,6 @@ class UsernameEditFragmentTest { computationTestScheduler = computationScheduler ) - @After - fun tearDown() { - InstrumentationApplicationDependencyProvider.clearHandlers() - } - @Ignore("Flakey espresso test.") @Test fun testUsernameCreationOutsideOfRegistration() { @@ -82,14 +71,7 @@ class UsernameEditFragmentTest { val discriminator = "4578" val username = "$nickname${Usernames.DELIMITER}$discriminator" - InstrumentationApplicationDependencyProvider.addMockWebRequestHandlers( - Put("/v1/accounts/username/reserved") { - MockResponse().success(ReserveUsernameResponse(username)) - }, - Put("/v1/accounts/username/confirm") { - MockResponse().success() - } - ) + // TODO: mock network requests as necessary val scenario = createScenario(UsernameEditMode.NORMAL) scenario.moveToState(Lifecycle.State.RESUMED) diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/ResponseMocking.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/ResponseMocking.kt deleted file mode 100644 index 3d3ca25567..0000000000 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/ResponseMocking.kt +++ /dev/null @@ -1,59 +0,0 @@ -package org.thoughtcrime.securesms.testing - -import okhttp3.mockwebserver.MockResponse -import okhttp3.mockwebserver.RecordedRequest -import okhttp3.mockwebserver.SocketPolicy -import org.thoughtcrime.securesms.util.JsonUtils -import java.util.concurrent.TimeUnit - -typealias ResponseFactory = (request: RecordedRequest) -> MockResponse -typealias RequestPredicate = (request: RecordedRequest) -> Boolean - -/** - * Represent an HTTP verb for mocking web requests. - */ -sealed class Verb(val requestPredicate: RequestPredicate, val responseFactory: ResponseFactory) - -class Get(path: String, predicate: RequestPredicate, responseFactory: ResponseFactory) : Verb(defaultRequestPredicate("GET", path, predicate), responseFactory) { - constructor(path: String, responseFactory: ResponseFactory) : this(path, { true }, responseFactory) -} - -class Put(path: String, responseFactory: ResponseFactory) : Verb(defaultRequestPredicate("PUT", path), responseFactory) - -class Post(path: String, responseFactory: ResponseFactory) : Verb(defaultRequestPredicate("POST", path), responseFactory) - -class Delete(path: String, responseFactory: ResponseFactory) : Verb(defaultRequestPredicate("DELETE", path), responseFactory) - -fun MockResponse.success(response: Any? = null): MockResponse { - return setResponseCode(200).apply { - if (response != null) { - setBody(JsonUtils.toJson(response)) - } - } -} - -fun MockResponse.failure(code: Int, response: Any? = null): MockResponse { - return setResponseCode(code).apply { - if (response != null) { - setBody(JsonUtils.toJson(response)) - } - } -} - -fun MockResponse.connectionFailure(): MockResponse { - return setSocketPolicy(SocketPolicy.DISCONNECT_AT_START) -} - -fun MockResponse.timeout(): MockResponse { - return setHeadersDelay(1, TimeUnit.DAYS) - .setBodyDelay(1, TimeUnit.DAYS) -} - -inline fun RecordedRequest.parsedRequestBody(): T { - val bodyString = String(body.readByteArray()) - return JsonUtils.fromJson(bodyString, T::class.java) -} - -private fun defaultRequestPredicate(verb: String, path: String, predicate: RequestPredicate = { true }): RequestPredicate = { request -> - request.method == verb && request.path?.startsWith("/$path") == true && predicate(request) -} diff --git a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/SignalActivityRule.kt b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/SignalActivityRule.kt index 75447220c9..8c2588d414 100644 --- a/app/src/androidTest/java/org/thoughtcrime/securesms/testing/SignalActivityRule.kt +++ b/app/src/androidTest/java/org/thoughtcrime/securesms/testing/SignalActivityRule.kt @@ -9,7 +9,6 @@ import android.preference.PreferenceManager import androidx.test.core.app.ActivityScenario import androidx.test.platform.app.InstrumentationRegistry import kotlinx.coroutines.runBlocking -import okhttp3.mockwebserver.MockResponse import org.junit.rules.ExternalResource import org.signal.libsignal.protocol.IdentityKey import org.signal.libsignal.protocol.IdentityKeyPair @@ -21,7 +20,6 @@ import org.thoughtcrime.securesms.database.IdentityTable import org.thoughtcrime.securesms.database.SignalDatabase import org.thoughtcrime.securesms.database.model.databaseprotos.RestoreDecisionState import org.thoughtcrime.securesms.dependencies.AppDependencies -import org.thoughtcrime.securesms.dependencies.InstrumentationApplicationDependencyProvider import org.thoughtcrime.securesms.keyvalue.NewAccount import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.profiles.ProfileName @@ -80,8 +78,6 @@ class SignalActivityRule(private val othersCount: Int = 4, private val createGro others[1].asMember() ) } - - InstrumentationApplicationDependencyProvider.clearHandlers() } private fun setupSelf(): Recipient { @@ -94,7 +90,6 @@ class SignalActivityRule(private val othersCount: Int = 4, private val createGro SignalStore.account.generateAciIdentityKeyIfNecessary() SignalStore.account.generatePniIdentityKeyIfNecessary() - InstrumentationApplicationDependencyProvider.addMockWebRequestHandlers(Put("/v2/keys") { MockResponse().success() }) runBlocking { val registrationData = RegistrationData( code = "123123", diff --git a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java index 58a7d4dd16..4bc79841fa 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java +++ b/app/src/main/java/org/thoughtcrime/securesms/dependencies/ApplicationDependencyProvider.java @@ -347,7 +347,7 @@ public class ApplicationDependencyProvider implements AppDependencies.Provider { }; SignalWebSocket.AuthenticatedWebSocket webSocket = new SignalWebSocket.AuthenticatedWebSocket(authFactory, - () -> !SignalStore.misc().isClientDeprecated() && !DeviceTransferBlockingInterceptor.getInstance().isBlockingNetwork(), + () -> !SignalStore.misc().isClientDeprecated() && !DeviceTransferBlockingInterceptor.getInstance().isBlockingNetwork() && BuildConfig.BUILD_TYPE != "instrumentation", sleepTimer, TimeUnit.SECONDS.toMillis(30)); if (AppForegroundObserver.isForegrounded()) { @@ -374,7 +374,7 @@ public class ApplicationDependencyProvider implements AppDependencies.Provider { }; SignalWebSocket.UnauthenticatedWebSocket webSocket = new SignalWebSocket.UnauthenticatedWebSocket(unauthFactory, - () -> !SignalStore.misc().isClientDeprecated() && !DeviceTransferBlockingInterceptor.getInstance().isBlockingNetwork(), + () -> !SignalStore.misc().isClientDeprecated() && !DeviceTransferBlockingInterceptor.getInstance().isBlockingNetwork() && BuildConfig.BUILD_TYPE != "instrumentation", sleepTimer, TimeUnit.SECONDS.toMillis(30)); if (AppForegroundObserver.isForegrounded()) { diff --git a/gradle/test-libs.versions.toml b/gradle/test-libs.versions.toml index 1d65867ed6..c388d7889a 100644 --- a/gradle/test-libs.versions.toml +++ b/gradle/test-libs.versions.toml @@ -21,7 +21,6 @@ robolectric-robolectric = { module = "org.robolectric:robolectric", version.ref bouncycastle-bcprov-jdk15on = "org.bouncycastle:bcprov-jdk15on:1.70" bouncycastle-bcpkix-jdk15on = "org.bouncycastle:bcpkix-jdk15on:1.70" assertk = "com.willowtreeapps.assertk:assertk:0.28.1" -square-okhttp-mockserver = "com.squareup.okhttp3:mockwebserver:5.0.0-alpha.16" mockk = "io.mockk:mockk:1.13.17" mockk-android = "io.mockk:mockk-android:1.13.17"