diff options
| author | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2024-01-12 16:29:03 +0100 |
|---|---|---|
| committer | Jonatan Rhodin <jonatan.rhodin@mullvad.net> | 2024-01-19 11:31:31 +0100 |
| commit | 1a20b9875f140d4911116dcd683264bb4bebbb64 (patch) | |
| tree | 088d8f0db342cfaad696319f8bf501c3c71ffe1d /android/test/mockapi | |
| parent | fccd8f71bcbb33733428999099fc863c943a7165 (diff) | |
| download | mullvadvpn-1a20b9875f140d4911116dcd683264bb4bebbb64.tar.xz mullvadvpn-1a20b9875f140d4911116dcd683264bb4bebbb64.zip | |
Add mockapi test for handling too many devices
Diffstat (limited to 'android/test/mockapi')
7 files changed, 179 insertions, 41 deletions
diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/CreateAccountMockApiTest.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/CreateAccountMockApiTest.kt index a07a9e5abb..b0ad767e31 100644 --- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/CreateAccountMockApiTest.kt +++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/CreateAccountMockApiTest.kt @@ -4,6 +4,8 @@ import net.mullvad.mullvadvpn.lib.common.util.groupWithSpaces import net.mullvad.mullvadvpn.test.common.extension.clickAgreeOnPrivacyDisclaimer import net.mullvad.mullvadvpn.test.common.extension.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove import net.mullvad.mullvadvpn.test.common.extension.dismissChangelogDialogIfShown +import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_DEVICE_NAME_2 +import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID_2 import org.junit.jupiter.api.Test class CreateAccountMockApiTest : MockApiTest() { @@ -11,7 +13,10 @@ class CreateAccountMockApiTest : MockApiTest() { fun testCreateAccountSuccessful() { // Arrange val createdAccountToken = "1234123412341234" - apiDispatcher.apply { expectedAccountToken = createdAccountToken } + apiDispatcher.apply { + expectedAccountToken = createdAccountToken + devicePendingToGetCreated = DUMMY_ID_2 to DUMMY_DEVICE_NAME_2 + } app.launch(endpoint) // Act 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 3f3d882835..75925a08d5 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 @@ -8,6 +8,9 @@ import net.mullvad.mullvadvpn.test.common.extension.clickAgreeOnPrivacyDisclaime import net.mullvad.mullvadvpn.test.common.extension.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove import net.mullvad.mullvadvpn.test.common.extension.dismissChangelogDialogIfShown import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout +import net.mullvad.mullvadvpn.test.mockapi.constant.DEFAULT_DEVICE_LIST +import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_DEVICE_NAME_2 +import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID_2 import net.mullvad.mullvadvpn.test.mockapi.util.currentUtcTimeWithOffsetZero import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test @@ -46,6 +49,8 @@ class LoginMockApiTest : MockApiTest() { apiDispatcher.apply { expectedAccountToken = validAccountToken accountExpiry = currentUtcTimeWithOffsetZero().plusDays(1) + devices = DEFAULT_DEVICE_LIST.toMutableMap() + devicePendingToGetCreated = DUMMY_ID_2 to DUMMY_DEVICE_NAME_2 } // Act @@ -67,6 +72,8 @@ class LoginMockApiTest : MockApiTest() { apiDispatcher.apply { expectedAccountToken = validAccountToken accountExpiry = currentUtcTimeWithOffsetZero().minusDays(1) + devices = DEFAULT_DEVICE_LIST.toMutableMap() + devicePendingToGetCreated = DUMMY_ID_2 to DUMMY_DEVICE_NAME_2 } // Act diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LogoutMockApiTest.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LogoutMockApiTest.kt index 266fe73977..1fd266c5d6 100644 --- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LogoutMockApiTest.kt +++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LogoutMockApiTest.kt @@ -5,6 +5,9 @@ import net.mullvad.mullvadvpn.test.common.extension.clickAgreeOnPrivacyDisclaime import net.mullvad.mullvadvpn.test.common.extension.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove import net.mullvad.mullvadvpn.test.common.extension.dismissChangelogDialogIfShown import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout +import net.mullvad.mullvadvpn.test.mockapi.constant.DEFAULT_DEVICE_LIST +import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_DEVICE_NAME_2 +import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID_2 import net.mullvad.mullvadvpn.test.mockapi.util.currentUtcTimeWithOffsetZero import org.junit.jupiter.api.Assertions.assertNotNull import org.junit.jupiter.api.Test @@ -18,6 +21,8 @@ class LogoutMockApiTest : MockApiTest() { apiDispatcher.apply { expectedAccountToken = validAccountToken accountExpiry = currentUtcTimeWithOffsetZero().plusMonths(1) + devices = DEFAULT_DEVICE_LIST.toMutableMap() + devicePendingToGetCreated = DUMMY_ID_2 to DUMMY_DEVICE_NAME_2 } // 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 74214501a1..821a95f68a 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 @@ -6,14 +6,14 @@ import net.mullvad.mullvadvpn.test.mockapi.constant.AUTH_TOKEN_URL_PATH import net.mullvad.mullvadvpn.test.mockapi.constant.CREATE_ACCOUNT_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.DUMMY_ID_1 import net.mullvad.mullvadvpn.test.mockapi.constant.LOG_TAG import net.mullvad.mullvadvpn.test.mockapi.util.accessTokenJsonResponse import net.mullvad.mullvadvpn.test.mockapi.util.accountCreationJson import net.mullvad.mullvadvpn.test.mockapi.util.accountInfoJson import net.mullvad.mullvadvpn.test.mockapi.util.currentUtcTimeWithOffsetZero import net.mullvad.mullvadvpn.test.mockapi.util.deviceJson +import net.mullvad.mullvadvpn.test.mockapi.util.tooManyDevicesJsonResponse import okhttp3.mockwebserver.Dispatcher import okhttp3.mockwebserver.MockResponse import okhttp3.mockwebserver.RecordedRequest @@ -25,12 +25,17 @@ class MockApiDispatcher : Dispatcher() { var expectedAccountToken: String? = null var accountExpiry: DateTime? = null + var devices: MutableMap<String, String>? = null + private val canAddDevices: Boolean + get() = (devices?.size ?: 0) < 5 + + var devicePendingToGetCreated: Pair<String, String>? = null private var cachedPubKeyFromAppUnderTest: String? = null override fun dispatch(request: RecordedRequest): MockResponse { Log.d(LOG_TAG, "Request: $request (body=${request.body.peek().readUtf8()})") - return when (request.path) { + return when (request.path ?: "") { AUTH_TOKEN_URL_PATH -> handleLoginRequest(request.body) DEVICES_URL_PATH -> { when (request.method) { @@ -41,10 +46,29 @@ class MockApiDispatcher : Dispatcher() { else -> MockResponse().setResponseCode(404) } } - "$DEVICES_URL_PATH/$DUMMY_ID" -> handleDeviceInfoRequest() ACCOUNT_URL_PATH -> handleAccountInfoRequest() CREATE_ACCOUNT_URL_PATH -> handleAccountCreationRequest() - else -> MockResponse().setResponseCode(404) + else -> { + if (request.path?.contains(DEVICES_URL_PATH) == true) { + val deviceId = request.path?.split("/")?.lastOrNull() + if (deviceId != null && devices?.contains(deviceId) == true) { + when (request.method) { + "get", + "GET" -> handleDeviceInfoRequest(deviceId) + "delete", + "DELETE" -> { + devices?.remove(deviceId) + MockResponse().setResponseCode(204) + } + else -> MockResponse().setResponseCode(404) + } + } else { + MockResponse().setResponseCode(404) + } + } else { + MockResponse().setResponseCode(404) + } + } }.also { response -> Log.d(LOG_TAG, "Response: $response (body=${response.getBody()?.peek()?.readUtf8()})") } @@ -78,20 +102,20 @@ class MockApiDispatcher : Dispatcher() { MockResponse() .setResponseCode(200) .addJsonHeader() - .setBody(accountInfoJson(id = DUMMY_ID, expiry = expiry).toString()) + .setBody(accountInfoJson(id = DUMMY_ID_1, expiry = expiry).toString()) } ?: MockResponse().setResponseCode(400) } - private fun handleDeviceInfoRequest(): MockResponse { + private fun handleDeviceInfoRequest(deviceId: String): MockResponse { return cachedPubKeyFromAppUnderTest?.let { cachedKey -> MockResponse() .setResponseCode(200) .addJsonHeader() .setBody( deviceJson( - id = DUMMY_ID, - name = DUMMY_DEVICE_NAME, + id = deviceId, + name = devices!![deviceId]!!, // Should always exist publicKey = cachedKey, creationDate = currentUtcTimeWithOffsetZero().minusDays(1) ) @@ -106,53 +130,57 @@ class MockApiDispatcher : Dispatcher() { .getPubKey() .also { newKey -> cachedPubKeyFromAppUnderTest = newKey } ?.let { newKey -> - MockResponse() - .setResponseCode(201) - .addJsonHeader() - .setBody( - deviceJson( - id = DUMMY_ID, - name = DUMMY_DEVICE_NAME, - publicKey = newKey, - creationDate = currentUtcTimeWithOffsetZero().minusDays(1) - ) - .toString() - ) + if (canAddDevices && devicePendingToGetCreated != null) { + MockResponse() + .setResponseCode(201) + .addJsonHeader() + .setBody( + deviceJson( + id = devicePendingToGetCreated!!.first, + name = devicePendingToGetCreated!!.second, + publicKey = newKey, + creationDate = currentUtcTimeWithOffsetZero().minusDays(1) + ) + .toString() + ) + } else { + MockResponse() + .setResponseCode(400) + .addJsonHeader() + .setBody(tooManyDevicesJsonResponse().toString()) + } } ?: MockResponse().setResponseCode(400) } private fun handleDeviceListRequest(): MockResponse { return cachedPubKeyFromAppUnderTest?.let { cachedKey -> - MockResponse() - .setResponseCode(200) - .addJsonHeader() - .setBody( - JSONArray() - .put( - deviceJson( - id = DUMMY_ID, - name = DUMMY_DEVICE_NAME, - publicKey = cachedKey, - creationDate = currentUtcTimeWithOffsetZero().minusDays(1) - ) - ) - .toString() + val body = JSONArray() + devices?.onEachIndexed { index, entry -> + body.put( + deviceJson( + id = entry.key, + name = entry.value, + publicKey = cachedKey, + creationDate = currentUtcTimeWithOffsetZero().minusDays(index + 1) + ) ) + } + MockResponse().setResponseCode(200).addJsonHeader().setBody(body.toString()) } ?: MockResponse().setResponseCode(400) } private fun handleAccountCreationRequest(): MockResponse { - return expectedAccountToken?.let { expiry -> + return expectedAccountToken?.let { expectedAccountToken -> MockResponse() .setResponseCode(201) .addJsonHeader() .setBody( accountCreationJson( - id = DUMMY_ID, + id = DUMMY_ID_1, expiry = DateTime(), - accountToken = expectedAccountToken!! + accountToken = expectedAccountToken ) .toString() ) diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/TooManyDevicesMockApiTest.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/TooManyDevicesMockApiTest.kt new file mode 100644 index 0000000000..b4963b5272 --- /dev/null +++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/TooManyDevicesMockApiTest.kt @@ -0,0 +1,67 @@ +package net.mullvad.mullvadvpn.test.mockapi + +import androidx.test.uiautomator.By +import net.mullvad.mullvadvpn.test.common.extension.clickAgreeOnPrivacyDisclaimer +import net.mullvad.mullvadvpn.test.common.extension.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove +import net.mullvad.mullvadvpn.test.common.extension.dismissChangelogDialogIfShown +import net.mullvad.mullvadvpn.test.common.extension.findObjectWithTimeout +import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_DEVICE_NAME_1 +import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_DEVICE_NAME_2 +import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_DEVICE_NAME_3 +import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_DEVICE_NAME_4 +import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_DEVICE_NAME_5 +import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_DEVICE_NAME_6 +import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID_1 +import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID_2 +import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID_3 +import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID_4 +import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID_5 +import net.mullvad.mullvadvpn.test.mockapi.constant.DUMMY_ID_6 +import net.mullvad.mullvadvpn.test.mockapi.util.currentUtcTimeWithOffsetZero +import org.junit.jupiter.api.Test + +class TooManyDevicesMockApiTest : MockApiTest() { + @Test + fun testRemoveDeviceSuccessfulAndLogin() { + // Arrange + val validAccountToken = "1234123412341234" + apiDispatcher.apply { + expectedAccountToken = validAccountToken + accountExpiry = currentUtcTimeWithOffsetZero().plusMonths(1) + devices = + mutableMapOf( + DUMMY_ID_1 to DUMMY_DEVICE_NAME_1, + DUMMY_ID_2 to DUMMY_DEVICE_NAME_2, + DUMMY_ID_3 to DUMMY_DEVICE_NAME_3, + DUMMY_ID_4 to DUMMY_DEVICE_NAME_4, + DUMMY_ID_5 to DUMMY_DEVICE_NAME_5 + ) + devicePendingToGetCreated = DUMMY_ID_6 to DUMMY_DEVICE_NAME_6 + } + + // Act + app.launch(endpoint) + device.clickAgreeOnPrivacyDisclaimer() + device.clickAllowOnNotificationPermissionPromptIfApiLevel33AndAbove() + device.dismissChangelogDialogIfShown() + app.waitForLoginPrompt() + app.attemptLogin(validAccountToken) + + // Assert that we have too many devices + device.findObjectWithTimeout(By.text("Too many devices")) + // And that the continue with login button is disabled + device.findObjectWithTimeout(By.text("Continue with login")).isEnabled + + // Act + app.attemptToRemoveDevice() + + // Assert that a device was removed + device.findObjectWithTimeout(By.text("Super!")) + + // Act + app.clickActionButtonByText("Continue with login") + + // Assert that we are logged in + device.findObjectWithTimeout(By.text("UNSECURED CONNECTION")) + } +} diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/constant/Constants.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/constant/Constants.kt index 37e782af11..27099cc67a 100644 --- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/constant/Constants.kt +++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/constant/Constants.kt @@ -9,7 +9,27 @@ const val DEVICES_URL_PATH = "/accounts/v1/devices" const val ACCOUNT_URL_PATH = "/accounts/v1/accounts/me" const val CREATE_ACCOUNT_URL_PATH = "/accounts/v1/accounts" -const val DUMMY_ID = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" -const val DUMMY_DEVICE_NAME = "mole mole" +const val DUMMY_ID_1 = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" +const val DUMMY_DEVICE_NAME_1 = "mole mole" +const val DUMMY_ID_2 = "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb" +const val DUMMY_DEVICE_NAME_2 = "elom elom" +const val DUMMY_ID_3 = "cccccccc-cccc-cccc-cccc-cccccccccccc" +const val DUMMY_DEVICE_NAME_3 = "mole elom" +const val DUMMY_ID_4 = "dddddddd-dddd-dddd-dddd-dddddddddddd" +const val DUMMY_DEVICE_NAME_4 = "yellow hat" +const val DUMMY_ID_5 = "eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee" +const val DUMMY_DEVICE_NAME_5 = "secure tunnel" +const val DUMMY_ID_6 = "ffffffff-ffff-ffff-ffff-ffffffffffff" +const val DUMMY_DEVICE_NAME_6 = "red lobster" const val DUMMY_ACCESS_TOKEN = "mva_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + +val DEFAULT_DEVICE_LIST = mapOf(DUMMY_ID_1 to DUMMY_DEVICE_NAME_1) +val FULL_DEVICE_LIST = + mapOf( + DUMMY_ID_1 to DUMMY_DEVICE_NAME_1, + DUMMY_ID_2 to DUMMY_DEVICE_NAME_2, + DUMMY_ID_3 to DUMMY_DEVICE_NAME_3, + DUMMY_ID_4 to DUMMY_DEVICE_NAME_4, + DUMMY_ID_5 to DUMMY_DEVICE_NAME_5 + ) diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/util/JsonUtils.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/util/JsonUtils.kt index eea4f3e973..a258d5daf8 100644 --- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/util/JsonUtils.kt +++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/util/JsonUtils.kt @@ -30,3 +30,9 @@ fun accessTokenJsonResponse(accessToken: String, expiry: DateTime) = put("access_token", accessToken) put("expiry", expiry.formatStrictlyAccordingToIso8601AndRfc3339()) } + +fun tooManyDevicesJsonResponse() = + JSONObject().apply { + put("code", "MAX_DEVICES_REACHED") + put("detail", "This account already has the maximum number of devices.") + } |
