diff options
| author | Albin <albin@mullvad.net> | 2023-02-02 11:26:21 +0100 |
|---|---|---|
| committer | Albin <albin@mullvad.net> | 2023-02-02 11:26:21 +0100 |
| commit | 31c4ff2cc21cd6656f179ea4b261b007f7000cfe (patch) | |
| tree | 04716f14287e12dc6e90529fcc7ab72ce859a0d3 | |
| parent | 423d3e7ae0f6a54a6ea4506df4ea9ad2df9b6eab (diff) | |
| parent | ebc182333bef909b0d7fe4ce3e85a41c14638bdc (diff) | |
| download | mullvadvpn-31c4ff2cc21cd6656f179ea4b261b007f7000cfe.tar.xz mullvadvpn-31c4ff2cc21cd6656f179ea4b261b007f7000cfe.zip | |
Merge branch 'fix-device-state-timing-issue'
12 files changed, 63 insertions, 33 deletions
diff --git a/.github/workflows/android-app.yml b/.github/workflows/android-app.yml index c2dd84ee99..f800fbe138 100644 --- a/.github/workflows/android-app.yml +++ b/.github/workflows/android-app.yml @@ -151,7 +151,7 @@ jobs: strategy: fail-fast: false matrix: - test-type: [app] + test-type: [app, mockapi] steps: - name: Checkout repository uses: actions/checkout@v3 diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/AccountRepository.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/AccountRepository.kt index a402d985f9..9d59ff6843 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/AccountRepository.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/AccountRepository.kt @@ -43,9 +43,6 @@ class AccountRepository( .flatMapReadyConnectionOrDefault(flowOf()) { state -> state.container.accountDataSource.accountExpiry } - .onStart { - fetchAccountExpiry() - } .stateIn( CoroutineScope(dispatcher), SharingStarted.WhileSubscribed(), diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/DeviceRepository.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/DeviceRepository.kt index 044888e9af..bd47e8719f 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/DeviceRepository.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/DeviceRepository.kt @@ -30,9 +30,6 @@ class DeviceRepository( .flatMapLatest { state -> if (state is ServiceConnectionState.ConnectedReady) { state.container.deviceDataSource.deviceStateUpdates - .onStart { - state.container.deviceDataSource.getDevice() - } } else { flowOf(DeviceState.Unknown) } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionAccountDataSource.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionAccountDataSource.kt index 23edd1efbf..05f6740a42 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionAccountDataSource.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionAccountDataSource.kt @@ -26,6 +26,7 @@ class ServiceConnectionAccountDataSource( trySend(event.expiry) } dispatcher.registerHandler(Event.AccountExpiryEvent::class, handler) + connection.send(Request.FetchAccountExpiry.message) awaitClose { // The current dispatcher doesn't support unregistration of handlers. } diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionDeviceDataSource.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionDeviceDataSource.kt index 56e7ee4d28..39159a1a17 100644 --- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionDeviceDataSource.kt +++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/ui/serviceconnection/ServiceConnectionDeviceDataSource.kt @@ -17,6 +17,7 @@ class ServiceConnectionDeviceDataSource( trySend(event.newState) } dispatcher.registerHandler(Event.DeviceStateEvent::class, handler) + connection.trySendRequest(Request.GetDevice, false) awaitClose { // The current dispatcher doesn't support unregistration of handlers. } diff --git a/android/scripts/run-instrumented-tests-repeat.sh b/android/scripts/run-instrumented-tests-repeat.sh new file mode 100755 index 0000000000..146cbf3d05 --- /dev/null +++ b/android/scripts/run-instrumented-tests-repeat.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash + +set -eu + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +cd "$SCRIPT_DIR" + +TEST_TYPE=$1 +REPEAT_COUNT=$2 + +for ((i=1; i <= REPEAT_COUNT; i++)) +do + echo "### Run $i ###" + ./run-instrumented-tests.sh "$TEST_TYPE" +done diff --git a/android/test/mockapi/build.gradle.kts b/android/test/mockapi/build.gradle.kts index cbdd8c0295..5ac80e2ea5 100644 --- a/android/test/mockapi/build.gradle.kts +++ b/android/test/mockapi/build.gradle.kts @@ -54,6 +54,7 @@ dependencies { implementation(Dependencies.AndroidX.testRunner) implementation(Dependencies.AndroidX.testRules) implementation(Dependencies.AndroidX.testUiAutomator) + implementation(Dependencies.jodaTime) implementation(Dependencies.Kotlin.stdlib) implementation(Dependencies.mockkWebserver) diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/Extensions.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/Extensions.kt index 60bd0e293a..4626468026 100644 --- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/Extensions.kt +++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/Extensions.kt @@ -1,5 +1,7 @@ package net.mullvad.mullvadvpn.test.mockapi +import android.util.Log +import net.mullvad.mullvadvpn.test.mockapi.constant.LOG_TAG import okhttp3.mockwebserver.MockResponse import okio.Buffer import org.json.JSONException @@ -13,6 +15,8 @@ fun Buffer.getAccountToken(): String? { return try { JSONObject(readUtf8()).getString("account_number") } catch (ex: JSONException) { + Log.e(LOG_TAG, "Unable to parse account number") + ex.printStackTrace() null } } diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LoginMockApiTest.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LoginMockApiTest.kt index 51d0ac7ee6..ef118d35e2 100644 --- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LoginMockApiTest.kt +++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LoginMockApiTest.kt @@ -2,10 +2,9 @@ package net.mullvad.mullvadvpn.test.mockapi import androidx.test.runner.AndroidJUnit4 import androidx.test.uiautomator.By -import java.time.OffsetDateTime -import java.time.temporal.ChronoUnit import net.mullvad.mullvadvpn.test.common.extension.clickAllowOnNotificationPermissionPromptIfApiLevel31AndAbove import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout +import net.mullvad.mullvadvpn.test.mockapi.util.currentUtcTimeWithOffsetZero import org.junit.Test import org.junit.runner.RunWith @@ -17,8 +16,7 @@ class LoginMockApiTest : MockApiTest() { val validAccountToken = "1234123412341234" apiDispatcher.apply { expectedAccountToken = null - accountExpiry = - OffsetDateTime.now().plusDays(1).truncatedTo(ChronoUnit.SECONDS) + accountExpiry = currentUtcTimeWithOffsetZero().plusDays(1) } app.launch(endpoint) @@ -37,8 +35,7 @@ class LoginMockApiTest : MockApiTest() { val validAccountToken = "1234123412341234" apiDispatcher.apply { expectedAccountToken = validAccountToken - accountExpiry = - OffsetDateTime.now().plusDays(1).truncatedTo(ChronoUnit.SECONDS) + accountExpiry = currentUtcTimeWithOffsetZero().plusDays(1) } // Act @@ -57,8 +54,7 @@ class LoginMockApiTest : MockApiTest() { val validAccountToken = "1234123412341234" apiDispatcher.apply { expectedAccountToken = validAccountToken - accountExpiry = - OffsetDateTime.now().minusDays(1).truncatedTo(ChronoUnit.SECONDS) + accountExpiry = currentUtcTimeWithOffsetZero().minusDays(1) } // Act diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiDispatcher.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiDispatcher.kt index b41ad34fa6..e3708a47f1 100644 --- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiDispatcher.kt +++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiDispatcher.kt @@ -1,29 +1,30 @@ package net.mullvad.mullvadvpn.test.mockapi import android.util.Log -import java.time.OffsetDateTime -import java.time.temporal.ChronoUnit import net.mullvad.mullvadvpn.test.mockapi.constant.ACCOUNT_URL_PATH import net.mullvad.mullvadvpn.test.mockapi.constant.AUTH_TOKEN_URL_PATH import net.mullvad.mullvadvpn.test.mockapi.constant.DEVICES_URL_PATH import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ACCESS_TOKEN import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_DEVICE_NAME import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID +import net.mullvad.mullvadvpn.test.mockapi.constant.LOG_TAG +import net.mullvad.mullvadvpn.test.mockapi.util.currentUtcTimeWithOffsetZero import okhttp3.mockwebserver.Dispatcher import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.RecordedRequest import okio.Buffer +import org.joda.time.DateTime import org.json.JSONArray class MockApiDispatcher : Dispatcher() { var expectedAccountToken: String? = null - var accountExpiry: OffsetDateTime? = null + var accountExpiry: DateTime? = null private var cachedPubKeyFromAppUnderTest: String? = null override fun dispatch(request: RecordedRequest): MockResponse { - Log.d("mullvad", "Request: $request") + Log.d(LOG_TAG, "Request: $request (body=${request.body.peek().readUtf8()})") return when (request.path) { AUTH_TOKEN_URL_PATH -> handleLoginRequest(request.body) DEVICES_URL_PATH -> { @@ -36,6 +37,8 @@ class MockApiDispatcher : Dispatcher() { "$DEVICES_URL_PATH/$DUMMY_ID" -> handleDeviceInfoRequest() ACCOUNT_URL_PATH -> handleAccountInfoRequest() else -> MockResponse().setResponseCode(404) + }.also { response -> + Log.d(LOG_TAG, "Response: $response (body=${response.getBody()?.peek()?.readUtf8()})") } } @@ -49,10 +52,14 @@ class MockApiDispatcher : Dispatcher() { .setBody( accessTokenJsonResponse( accessToken = DUMMY_ACCESS_TOKEN, - expiry = OffsetDateTime.now().plusDays(1).truncatedTo(ChronoUnit.SECONDS) + expiry = currentUtcTimeWithOffsetZero().plusDays(1) ).toString() ) } else { + Log.e( + LOG_TAG, + "Unexpected account token (expected=$expectedAccountToken was=$accountToken)" + ) MockResponse().setResponseCode(400) } } @@ -81,8 +88,7 @@ class MockApiDispatcher : Dispatcher() { id = DUMMY_ID, name = DUMMY_DEVICE_NAME, publicKey = cachedKey, - creationDate = OffsetDateTime.now().minusDays(1) - .truncatedTo(ChronoUnit.SECONDS) + creationDate = currentUtcTimeWithOffsetZero().minusDays(1) ).toString() ) } ?: MockResponse().setResponseCode(400) @@ -102,8 +108,7 @@ class MockApiDispatcher : Dispatcher() { id = DUMMY_ID, name = DUMMY_DEVICE_NAME, publicKey = newKey, - creationDate = OffsetDateTime.now().minusDays(1) - .truncatedTo(ChronoUnit.SECONDS) + creationDate = currentUtcTimeWithOffsetZero().minusDays(1) ).toString() ) } ?: MockResponse().setResponseCode(400) @@ -120,8 +125,7 @@ class MockApiDispatcher : Dispatcher() { id = DUMMY_ID, name = DUMMY_DEVICE_NAME, publicKey = cachedKey, - creationDate = OffsetDateTime.now().minusDays(1) - .truncatedTo(ChronoUnit.SECONDS) + creationDate = currentUtcTimeWithOffsetZero().minusDays(1) ) ).toString() ) diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/util/DateTimeUtils.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/util/DateTimeUtils.kt new file mode 100644 index 0000000000..81042f70d2 --- /dev/null +++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/util/DateTimeUtils.kt @@ -0,0 +1,13 @@ +package net.mullvad.mullvadvpn.test.mockapi.util + +import org.joda.time.DateTime +import org.joda.time.DateTimeZone +import org.joda.time.format.DateTimeFormat + +private const val STRICT_ISO8601_AND_RFC3339_PATTERN = "yyyy-MM-dd'T'HH:mm:ssZZ" + +fun currentUtcTimeWithOffsetZero() = DateTime.now(DateTimeZone.forOffsetHours(0)) + +fun DateTime.formatStrictlyAccordingToIso8601AndRfc3339(): String { + return toString(DateTimeFormat.forPattern(STRICT_ISO8601_AND_RFC3339_PATTERN)) +} diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/JsonUtils.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/util/JsonUtils.kt index d6ee2bc6cb..145cbafbd2 100644 --- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/JsonUtils.kt +++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/util/JsonUtils.kt @@ -1,15 +1,16 @@ package net.mullvad.mullvadvpn.test.mockapi -import java.time.OffsetDateTime +import net.mullvad.mullvadvpn.test.mockapi.util.formatStrictlyAccordingToIso8601AndRfc3339 +import org.joda.time.DateTime import org.json.JSONArray import org.json.JSONObject fun accountInfoJson( id: String, - expiry: OffsetDateTime + expiry: DateTime ) = JSONObject().apply { put("id", id) - put("expiry", expiry.toString()) + put("expiry", expiry.formatStrictlyAccordingToIso8601AndRfc3339()) put("max_ports", 5) put("can_add_ports", true) put("max_devices", 5) @@ -20,13 +21,13 @@ fun deviceJson( id: String, name: String, publicKey: String, - creationDate: OffsetDateTime + creationDate: DateTime ) = JSONObject().apply { put("id", id) put("name", name) put("pubkey", publicKey) put("hijack_dns", true) - put("created", creationDate.toString()) + put("created", creationDate.formatStrictlyAccordingToIso8601AndRfc3339()) put("ipv4_address", "127.0.0.1/32") put("ipv6_address", "fc00::1/128") put("ports", JSONArray()) @@ -34,8 +35,8 @@ fun deviceJson( fun accessTokenJsonResponse( accessToken: String, - expiry: OffsetDateTime + expiry: DateTime ) = JSONObject().apply { put("access_token", accessToken) - put("expiry", expiry.toString()) + put("expiry", expiry.formatStrictlyAccordingToIso8601AndRfc3339()) } |
