Merge pull request #4429 from vector-im/feature/adm/relogin-sanity-check

Sign out - Sign in sanity check & nightly sanity check
This commit is contained in:
Adam Brown 2021-11-08 20:21:15 +00:00 committed by GitHub
commit 9dd01d5b20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 104 additions and 85 deletions

View File

@ -1,9 +1,9 @@
name: Sanity Test
on:
pull_request: { }
push:
branches: [ main, develop ]
schedule:
# At 20:00 every day UTC
- cron: '0 20 * * *'
# Enrich gradle.properties for CI/CD
env:
@ -14,13 +14,15 @@ env:
jobs:
integration-tests:
name: Sanity Tests (Synapse)
runs-on: ubuntu-latest
runs-on: macos-latest
strategy:
fail-fast: false
matrix:
api-level: [28]
steps:
- uses: actions/checkout@v2
with:
ref: develop
- name: Set up Python 3.8
uses: actions/setup-python@v2
with:
@ -46,8 +48,12 @@ jobs:
python3 -m venv .synapse
source .synapse/bin/activate
pip install synapse matrix-synapse
curl -sL https://raw.githubusercontent.com/matrix-org/synapse/develop/demo/start.sh --no-rate-limit \
| sed s/127.0.0.1/0.0.0.0/g | bash
curl -sL https://raw.githubusercontent.com/matrix-org/synapse/develop/demo/start.sh \
| sed s/127.0.0.1/0.0.0.0/g | sed 's/http:\/\/localhost/http:\/\/10.0.2.2/g' | bash -s -- --no-rate-limit
- uses: actions/setup-java@v2
with:
distribution: 'adopt'
java-version: '11'
- name: Run sanity tests on API ${{ matrix.api-level }}
uses: reactivecircus/android-emulator-runner@v2
with:

View File

@ -51,6 +51,11 @@ internal class SessionManager @Inject constructor(private val matrixComponent: M
}
}
fun stopSession(sessionId: String) {
val sessionComponent = sessionComponents[sessionId] ?: throw RuntimeException("You don't have a session for id $sessionId")
sessionComponent.session().stopSync()
}
fun getOrCreateSessionComponent(sessionParams: SessionParams): SessionComponent {
return sessionComponents.getOrPut(sessionParams.credentials.sessionId()) {
DaggerSessionComponent

View File

@ -44,7 +44,7 @@ internal class DefaultDeactivateAccountTask @Inject constructor(
override suspend fun execute(params: DeactivateAccountTask.Params) {
val deactivateAccountParams = DeactivateAccountParams.create(params.userAuthParam, params.eraseAllData)
cleanupSession.stopActiveTasks()
val canCleanup = try {
executeRequest(globalErrorReceiver) {
accountAPI.deactivate(deactivateAccountParams)
@ -71,7 +71,7 @@ internal class DefaultDeactivateAccountTask @Inject constructor(
runCatching { identityDisconnectTask.execute(Unit) }
.onFailure { Timber.w(it, "Unable to disconnect identity server") }
cleanupSession.handle()
cleanupSession.cleanup()
}
}
}

View File

@ -50,20 +50,26 @@ internal class CleanupSession @Inject constructor(
@CryptoDatabase private val realmCryptoConfiguration: RealmConfiguration,
@UserMd5 private val userMd5: String
) {
suspend fun handle() {
fun stopActiveTasks() {
Timber.d("Cleanup: cancel pending works...")
workManagerProvider.cancelAllWorks()
Timber.d("Cleanup: stop session...")
sessionManager.stopSession(sessionId)
}
suspend fun cleanup() {
val sessionRealmCount = Realm.getGlobalInstanceCount(realmSessionConfiguration)
val cryptoRealmCount = Realm.getGlobalInstanceCount(realmCryptoConfiguration)
Timber.d("Realm instance ($sessionRealmCount - $cryptoRealmCount)")
Timber.d("Cleanup: delete session params...")
sessionParamsStore.delete(sessionId)
Timber.d("Cleanup: cancel pending works...")
workManagerProvider.cancelAllWorks()
Timber.d("Cleanup: release session...")
sessionManager.releaseSession(sessionId)
Timber.d("Cleanup: delete session params...")
sessionParamsStore.delete(sessionId)
Timber.d("Cleanup: clear session data...")
clearSessionDataTask.execute(Unit)

View File

@ -43,6 +43,7 @@ internal class DefaultSignOutTask @Inject constructor(
override suspend fun execute(params: SignOutTask.Params) {
// It should be done even after a soft logout, to be sure the deviceId is deleted on the
if (params.signOutFromHomeserver) {
cleanupSession.stopActiveTasks()
Timber.d("SignOut: send request...")
try {
executeRequest(globalErrorReceiver) {
@ -67,6 +68,6 @@ internal class DefaultSignOutTask @Inject constructor(
.onFailure { Timber.w(it, "Unable to disconnect identity server") }
Timber.d("SignOut: cleanup session...")
cleanupSession.handle()
cleanupSession.cleanup()
}
}

View File

@ -160,6 +160,9 @@ internal class SyncThread @Inject constructor(private val syncTask: SyncTask,
synchronized(lock) { lock.wait() }
Timber.tag(loggerTag.value).d("...retry")
} else if (!isTokenValid) {
if (state == SyncState.Killing) {
continue
}
Timber.tag(loggerTag.value).d("Token is invalid. Waiting...")
updateStateTo(SyncState.InvalidToken)
synchronized(lock) { lock.wait() }

View File

@ -16,23 +16,14 @@
package im.vector.app.ui
import android.view.View
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.matcher.ViewMatchers.isRoot
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import com.adevinta.android.barista.assertion.BaristaVisibilityAssertions.assertDisplayed
import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
import im.vector.app.EspressoHelper
import im.vector.app.R
import im.vector.app.SleepViewAction
import im.vector.app.features.MainActivity
import im.vector.app.ui.robot.ElementRobot
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import java.lang.Thread.sleep
import java.util.UUID
/**
@ -55,7 +46,7 @@ class UiAllScreensSanityTest {
fun allScreensTest() {
// Create an account
val userId = "UiTest_" + UUID.randomUUID().toString()
elementRobot.login(userId)
elementRobot.signUp(userId)
elementRobot.settings {
general { crawl() }
@ -89,34 +80,12 @@ class UiAllScreensSanityTest {
verifyCreatedRoom()
}
// Disable until the "you don't have a session for id %d" sign out bug is fixed
// elementRobot.signout()
// // Login again on the same account
// elementRobot.login(userId)
//
// ignoreVerification()
//
// elementRobot.signout()
// clickDialogPositiveButton()
elementRobot.signout(expectSignOutWarning = true)
// Login again on the same account
elementRobot.login(userId)
elementRobot.dismissVerificationIfPresent()
// TODO Deactivate account instead of logout?
}
private fun ignoreVerification() {
sleep(6000)
val activity = EspressoHelper.getCurrentActivity()!!
val popup = activity.findViewById<View>(com.tapadoo.alerter.R.id.llAlertBackground)
activity.runOnUiThread {
popup.performClick()
}
assertDisplayed(R.id.bottomSheetFragmentContainer)
onView(isRoot()).perform(SleepViewAction.sleep(2000))
clickOn(R.string.skip)
assertDisplayed(R.string.are_you_sure)
clickOn(R.string.skip)
elementRobot.signout(expectSignOutWarning = false)
}
}

View File

@ -16,15 +16,17 @@
package im.vector.app.ui.robot
import android.view.View
import androidx.test.espresso.Espresso.pressBack
import androidx.test.espresso.action.ViewActions
import androidx.test.espresso.matcher.ViewMatchers
import androidx.test.espresso.matcher.ViewMatchers.withId
import com.adevinta.android.barista.assertion.BaristaVisibilityAssertions
import com.adevinta.android.barista.assertion.BaristaVisibilityAssertions.assertDisplayed
import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
import com.adevinta.android.barista.interaction.BaristaDialogInteractions.clickDialogNegativeButton
import com.adevinta.android.barista.interaction.BaristaDialogInteractions.clickDialogPositiveButton
import com.adevinta.android.barista.interaction.BaristaDrawerInteractions.openDrawer
import im.vector.app.EspressoHelper
import im.vector.app.R
import im.vector.app.activityIdlingResource
import im.vector.app.espresso.tools.waitUntilActivityVisible
import im.vector.app.espresso.tools.waitUntilViewVisible
import im.vector.app.features.createdirect.CreateDirectRoomActivity
@ -33,25 +35,31 @@ import im.vector.app.features.login.LoginActivity
import im.vector.app.initialSyncIdlingResource
import im.vector.app.ui.robot.settings.SettingsRobot
import im.vector.app.withIdlingResource
import timber.log.Timber
class ElementRobot {
fun login(userId: String) {
fun signUp(userId: String) {
val onboardingRobot = OnboardingRobot()
onboardingRobot.createAccount(userId = userId)
waitForHome()
}
withIdlingResource(activityIdlingResource(HomeActivity::class.java)) {
BaristaVisibilityAssertions.assertDisplayed(R.id.roomListContainer)
ViewActions.closeSoftKeyboard()
fun login(userId: String) {
val onboardingRobot = OnboardingRobot()
onboardingRobot.login(userId = userId)
waitForHome()
}
private fun waitForHome() {
waitUntilActivityVisible<HomeActivity> {
waitUntilViewVisible(withId(R.id.roomListContainer))
}
val activity = EspressoHelper.getCurrentActivity()!!
val uiSession = (activity as HomeActivity).activeSessionHolder.getActiveSession()
withIdlingResource(initialSyncIdlingResource(uiSession)) {
BaristaVisibilityAssertions.assertDisplayed(R.id.roomListContainer)
waitUntilViewVisible(withId(R.id.bottomNavigationView))
}
waitUntilViewVisible(withId(R.id.bottomNavigationView))
}
fun settings(block: SettingsRobot.() -> Unit) {
@ -87,10 +95,49 @@ class ElementRobot {
waitUntilViewVisible(withId(R.id.bottomNavigationView))
}
fun signout() {
OnboardingRobot().signout()
fun signout(expectSignOutWarning: Boolean) {
clickOn(R.id.groupToolbarAvatarImageView)
clickOn(R.id.homeDrawerHeaderSignoutView)
val isShowingSignOutWarning = kotlin.runCatching {
waitUntilViewVisible(withId(R.id.exitAnywayButton))
}.isSuccess
if (expectSignOutWarning != isShowingSignOutWarning) {
Timber.w("Unexpected sign out flow, expected warning to be: ${expectSignOutWarning.toWarningType()} but was ${isShowingSignOutWarning.toWarningType()}")
}
if (isShowingSignOutWarning) {
// We have sent a message in a e2e room, accept to loose it
clickOn(R.id.exitAnywayButton)
// Dark pattern
waitUntilViewVisible(withId(android.R.id.button2))
clickDialogNegativeButton()
} else {
waitUntilViewVisible(withId(android.R.id.button1))
clickDialogPositiveButton()
}
waitUntilActivityVisible<LoginActivity> {
BaristaVisibilityAssertions.assertDisplayed(R.id.loginSplashLogo)
assertDisplayed(R.id.loginSplashLogo)
}
}
fun dismissVerificationIfPresent() {
kotlin.runCatching {
Thread.sleep(6000)
val activity = EspressoHelper.getCurrentActivity()!!
val popup = activity.findViewById<View>(com.tapadoo.alerter.R.id.llAlertBackground)!!
activity.runOnUiThread { popup.performClick() }
waitUntilViewVisible(withId(R.id.bottomSheetFragmentContainer))
waitUntilViewVisible(ViewMatchers.withText(R.string.skip))
clickOn(R.string.skip)
assertDisplayed(R.string.are_you_sure)
clickOn(R.string.skip)
waitUntilViewVisible(withId(R.id.bottomSheetFragmentContainer))
}.onFailure { Timber.w("Verification popup missing", it) }
}
}
private fun Boolean.toWarningType() = if (this) "shown" else "skipped"

View File

@ -24,11 +24,8 @@ import com.adevinta.android.barista.assertion.BaristaEnabledAssertions.assertDis
import com.adevinta.android.barista.assertion.BaristaEnabledAssertions.assertEnabled
import com.adevinta.android.barista.assertion.BaristaVisibilityAssertions.assertDisplayed
import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn
import com.adevinta.android.barista.interaction.BaristaDialogInteractions
import com.adevinta.android.barista.interaction.BaristaEditTextInteractions.writeTo
import im.vector.app.R
import im.vector.app.espresso.tools.waitUntilActivityVisible
import im.vector.app.features.home.HomeActivity
import im.vector.app.waitForView
class OnboardingRobot {
@ -78,20 +75,5 @@ class OnboardingRobot {
closeSoftKeyboard()
clickOn(R.id.loginSubmit)
// Wait
waitUntilActivityVisible<HomeActivity> {
assertDisplayed(R.id.homeDetailFragmentContainer)
}
}
fun signout() {
clickOn(R.id.groupToolbarAvatarImageView)
clickOn(R.id.homeDrawerHeaderSignoutView)
// We have sent a message in a e2e room, accept to loose it
clickOn(R.id.exitAnywayButton)
// Dark pattern
BaristaDialogInteractions.clickDialogNegativeButton()
}
}