diff --git a/app/src/main/java/com/schibsted/account/example/MainActivity.kt b/app/src/main/java/com/schibsted/account/example/MainActivity.kt index 4f5ca0ad6..e61921abc 100644 --- a/app/src/main/java/com/schibsted/account/example/MainActivity.kt +++ b/app/src/main/java/com/schibsted/account/example/MainActivity.kt @@ -51,7 +51,7 @@ class MainActivity : AppCompatActivity() { } private fun observeAuthResultLiveData() { - AuthResultLiveData.get().observe(this, Observer { result: Either -> + AuthResultLiveData.get(ExampleApp.client).observe(this, Observer { result: Either -> result .onSuccess { user: User -> startLoggedInActivity(user) } .onFailure { state: NotAuthed -> diff --git a/webflows/src/main/java/com/schibsted/account/webflows/activities/AuthResultLiveData.kt b/webflows/src/main/java/com/schibsted/account/webflows/activities/AuthResultLiveData.kt index 8b4f458bf..24449ab62 100644 --- a/webflows/src/main/java/com/schibsted/account/webflows/activities/AuthResultLiveData.kt +++ b/webflows/src/main/java/com/schibsted/account/webflows/activities/AuthResultLiveData.kt @@ -67,6 +67,7 @@ class AuthResultLiveData private constructor(private val client: Client) : SchibstedAccountTracker.track(SchibstedAccountTrackingEvent.UserLoginCanceled) NotAuthed.CancelledByUser } + else -> NotAuthed.LoginFailed(result.value) } ) @@ -91,7 +92,12 @@ class AuthResultLiveData private constructor(private val client: Client) : if (::instance.isInitialized) instance else null @JvmStatic - fun get(): AuthResultLiveData = instance + fun get(client: Client): AuthResultLiveData { + if (!::instance.isInitialized) { + instance = create(client) + } + return instance + } @JvmStatic @MainThread diff --git a/webflows/src/main/java/com/schibsted/account/webflows/activities/AuthorizationManagementActivity.kt b/webflows/src/main/java/com/schibsted/account/webflows/activities/AuthorizationManagementActivity.kt index 182ba46c6..bee6fc3ba 100644 --- a/webflows/src/main/java/com/schibsted/account/webflows/activities/AuthorizationManagementActivity.kt +++ b/webflows/src/main/java/com/schibsted/account/webflows/activities/AuthorizationManagementActivity.kt @@ -131,7 +131,7 @@ class AuthorizationManagementActivity : Activity() { override fun onResume() { super.onResume() - AuthResultLiveData.get().update(Left(NotAuthed.AuthInProgress)) + AuthResultLiveData.get(client).update(Left(NotAuthed.AuthInProgress)) /* * If this is the first run of the activity, start the auth intent. @@ -173,14 +173,14 @@ class AuthorizationManagementActivity : Activity() { } private fun handleAuthorizationComplete() { - AuthResultLiveData.get().update(intent) + AuthResultLiveData.get(client).update(intent) completionIntent?.send() } private fun handleAuthorizationCanceled() { Timber.d("Authorization flow canceled by user") SchibstedAccountTracker.track(SchibstedAccountTrackingEvent.UserLoginCanceled) - AuthResultLiveData.get().update(Left(NotAuthed.CancelledByUser)) + AuthResultLiveData.get(client).update(Left(NotAuthed.CancelledByUser)) cancelIntent?.send() } @@ -196,6 +196,7 @@ class AuthorizationManagementActivity : Activity() { internal var completionIntent: PendingIntent? = null internal var cancelIntent: PendingIntent? = null + internal lateinit var client: Client @JvmStatic fun setup( @@ -203,6 +204,7 @@ class AuthorizationManagementActivity : Activity() { completionIntent: PendingIntent? = null, cancelIntent: PendingIntent? = null ) { + Companion.client = client AuthResultLiveData.create(client) Companion.completionIntent = completionIntent Companion.cancelIntent = cancelIntent @@ -211,7 +213,6 @@ class AuthorizationManagementActivity : Activity() { /** * Creates an intent to start an authorization flow. * @param context the package context for the app. - * @param request the authorization request which is to be sent. * @param authIntent the intent to be used to get authorization from the user. * @throws IllegalStateException if {@link AuthorizationManagementActivity#setup) has not * been called before this @@ -227,7 +228,7 @@ class AuthorizationManagementActivity : Activity() { /** * Creates an intent to handle the completion of an authorization flow. This restores - * the original AuthorizationManagementActivity that was created at the start of the flow. + * the original [AuthorizationManagementActivity] that was created at the start of the flow. * @param context the package context for the app. * @param responseUri the response URI, which carries the parameters describing the response. */ diff --git a/webflows/src/test/java/com/schibsted/account/webflows/activities/AuthResultLiveDataTest.kt b/webflows/src/test/java/com/schibsted/account/webflows/activities/AuthResultLiveDataTest.kt index 9762792e3..d8f3443de 100644 --- a/webflows/src/test/java/com/schibsted/account/webflows/activities/AuthResultLiveDataTest.kt +++ b/webflows/src/test/java/com/schibsted/account/webflows/activities/AuthResultLiveDataTest.kt @@ -53,6 +53,13 @@ class AuthResultLiveDataTest { assertNotNull(AuthResultLiveData.getIfInitialised()) } + @Test + fun getIfNotInitialisedReturnsNewInstance() { + assertNull(AuthResultLiveData.getIfInitialised()) + assertNotNull(AuthResultLiveData.get(mockk(relaxed = true))) + assertNotNull(AuthResultLiveData.getIfInitialised()) + } + @Test fun initResumesLoggedInUser() { val client = mockk(relaxed = true) @@ -63,7 +70,7 @@ class AuthResultLiveDataTest { } AuthResultLiveData.create(client) - AuthResultLiveData.get().value!!.assertRight { assertEquals(user, it) } + AuthResultLiveData.get(client).value!!.assertRight { assertEquals(user, it) } } @Test @@ -75,7 +82,7 @@ class AuthResultLiveDataTest { } AuthResultLiveData.create(client) - AuthResultLiveData.get().value!!.assertLeft { assertEquals(NotAuthed.NoLoggedInUser, it) } + AuthResultLiveData.get(client).value!!.assertLeft { assertEquals(NotAuthed.NoLoggedInUser, it) } } @Test @@ -87,7 +94,7 @@ class AuthResultLiveDataTest { } AuthResultLiveData.create(client) - AuthResultLiveData.get().value!!.assertLeft { assertEquals(NotAuthed.NoLoggedInUser, it) } + AuthResultLiveData.get(client).value!!.assertLeft { assertEquals(NotAuthed.NoLoggedInUser, it) } } @Test @@ -100,10 +107,10 @@ class AuthResultLiveDataTest { } AuthResultLiveData.create(client) - AuthResultLiveData.get().update(Intent().apply { + AuthResultLiveData.get(client).update(Intent().apply { data = Uri.parse("https://client.example.com/redirect?code=12345&state=test") }) - AuthResultLiveData.get().value!!.assertRight { assertEquals(user, it) } + AuthResultLiveData.get(client).value!!.assertRight { assertEquals(user, it) } } @Test @@ -117,10 +124,10 @@ class AuthResultLiveDataTest { } AuthResultLiveData.create(client) - AuthResultLiveData.get().update(Intent().apply { + AuthResultLiveData.get(client).update(Intent().apply { data = Uri.parse("https://client.example.com/redirect?code=12345&state=test") }) - AuthResultLiveData.get().value!!.assertLeft { + AuthResultLiveData.get(client).value!!.assertLeft { when (it) { is NotAuthed.LoginFailed -> assertEquals(errorResult, it.error) else -> fail("Unexpected error: $it") @@ -138,12 +145,12 @@ class AuthResultLiveDataTest { } AuthResultLiveData.create(client) - AuthResultLiveData.get().value!!.assertRight { assertEquals(user, it) } + AuthResultLiveData.get(client).value!!.assertRight { assertEquals(user, it) } user.logout() shadowOf(Looper.getMainLooper()).idle() - AuthResultLiveData.get().value!!.assertLeft { + AuthResultLiveData.get(client).value!!.assertLeft { assertEquals( NotAuthed.NoLoggedInUser, it diff --git a/webflows/src/test/java/com/schibsted/account/webflows/activities/AuthorizationManagementActivityTest.kt b/webflows/src/test/java/com/schibsted/account/webflows/activities/AuthorizationManagementActivityTest.kt index 9d6d8bb7a..ebb81618a 100644 --- a/webflows/src/test/java/com/schibsted/account/webflows/activities/AuthorizationManagementActivityTest.kt +++ b/webflows/src/test/java/com/schibsted/account/webflows/activities/AuthorizationManagementActivityTest.kt @@ -12,12 +12,12 @@ import androidx.test.core.app.ApplicationProvider.getApplicationContext import androidx.test.espresso.intent.Intents import androidx.test.espresso.intent.matcher.IntentMatchers import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.schibsted.account.webflows.testsupport.TestActivity import com.schibsted.account.testutil.Fixtures import com.schibsted.account.testutil.assertLeft import com.schibsted.account.testutil.assertRight import com.schibsted.account.webflows.client.Client import com.schibsted.account.webflows.client.LoginResultHandler +import com.schibsted.account.webflows.testsupport.TestActivity import com.schibsted.account.webflows.user.User import com.schibsted.account.webflows.util.Either.Right import io.mockk.every @@ -27,10 +27,11 @@ import io.mockk.verify import org.hamcrest.Matchers import org.junit.After import org.junit.Assert.assertEquals +import org.junit.Assert.assertNotNull import org.junit.Before import org.junit.Test import org.junit.runner.RunWith - +import org.robolectric.Robolectric @RunWith(AndroidJUnit4::class) class AuthorizationManagementActivityTest { @@ -39,11 +40,13 @@ class AuthorizationManagementActivityTest { TestActivity::class.java ) + private val client: Client = mockk(relaxed = true) + @Before @UiThreadTest fun setup() { Intents.init() - setupAuthorizationManagementActivity(mockk(relaxed = true)) + setupAuthorizationManagementActivity(client) } @After @@ -71,7 +74,12 @@ class AuthorizationManagementActivityTest { Intents.intending(IntentMatchers.hasExtras(Matchers.equalTo(authIntent.extras))) .respondWith(Instrumentation.ActivityResult(Activity.RESULT_OK, Intent())) launch(intent) - AuthResultLiveData.get().value!!.assertLeft { assertEquals(NotAuthed.AuthInProgress, it) } + AuthResultLiveData.get(client).value!!.assertLeft { + assertEquals( + NotAuthed.AuthInProgress, + it + ) + } } @Test @@ -95,7 +103,7 @@ class AuthorizationManagementActivityTest { launch(intent) - AuthResultLiveData.get().value!!.assertRight { assertEquals(user, it) } + AuthResultLiveData.get(client).value!!.assertRight { assertEquals(user, it) } verify(exactly = 1) { client.handleAuthenticationResponse(withArg { intent -> assertEquals(authResponse, intent.data) @@ -111,8 +119,59 @@ class AuthorizationManagementActivityTest { val intent = Intent(ctx, AuthorizationManagementActivity::class.java) // intent without data launch(intent) - AuthResultLiveData.get().value!!.assertLeft { assertEquals(NotAuthed.CancelledByUser, it) } + AuthResultLiveData.get(client).value!!.assertLeft { + assertEquals( + NotAuthed.CancelledByUser, + it + ) + } verify(exactly = 1) { AuthorizationManagementActivity.cancelIntent?.send() } verify(exactly = 0) { AuthorizationManagementActivity.completionIntent?.send() } } + + @Test + fun testActivityWithStressOnResumeTest() { + val authIntent = Intent().apply { + putExtra("AUTH", true) + } + val startIntent = + AuthorizationManagementActivity.createStartIntent(getApplicationContext(), authIntent) + + Intents.intending(IntentMatchers.hasExtras(Matchers.equalTo(authIntent.extras))) + .respondWith(Instrumentation.ActivityResult(Activity.RESULT_OK, Intent())) + + // Stress test on resume which should result in Cancelled by user + Robolectric.buildActivity(AuthorizationManagementActivity::class.java, startIntent) + .create() + .start() + .resume() + .pause() + .resume() + .pause() + .resume() + .get() + + // checking if AuthResultLiveData is not null + assertNotNull(AuthResultLiveData.get(client)) + + // AuthResultLiveData should be CancelledByUser since we've minimized and maximized the activity + AuthResultLiveData.get(client).value!!.assertLeft { + assertEquals( + NotAuthed.CancelledByUser, + it + ) + } + + // Launching the activity again should result in AuthInProgress + launch(startIntent) + // checking if AuthResultLiveData is not null + assertNotNull(AuthResultLiveData.get(client)) + // AuthResultLiveData should be AuthInProgress since we've launched the activity again with start intent + AuthResultLiveData.get(client).value!!.assertLeft { + assertEquals( + NotAuthed.AuthInProgress, + it + ) + } + } } diff --git a/webflows/src/test/java/com/schibsted/account/webflows/user/UserTest.kt b/webflows/src/test/java/com/schibsted/account/webflows/user/UserTest.kt index 84a89c8c6..72db0f30b 100644 --- a/webflows/src/test/java/com/schibsted/account/webflows/user/UserTest.kt +++ b/webflows/src/test/java/com/schibsted/account/webflows/user/UserTest.kt @@ -306,7 +306,7 @@ class UserTest { every { client.refreshTokensForUser(user) } answers { Thread.sleep(20) // artificial delay to simulate network request Right(Fixtures.userTokens.copy(accessToken = "accessToken1")) - } andThen { + } andThenAnswer { Right(Fixtures.userTokens.copy(accessToken = "accessToken2")) } @@ -381,9 +381,9 @@ class UserTest { } AuthResultLiveData.create(client) - AuthResultLiveData.get().logout() + AuthResultLiveData.get(client).logout() shadowOf(Looper.getMainLooper()).idle() - AuthResultLiveData.get().value!!.assertLeft { assertEquals(NotAuthed.NoLoggedInUser, it) } + AuthResultLiveData.get(client).value!!.assertLeft { assertEquals(NotAuthed.NoLoggedInUser, it) } AuthResultLiveDataTest.resetInstance() }