Merge pull request #43 from fknives/issue#30-adjust-mockwebserver-readability
Issue#30 adjust mockwebserver readability
This commit is contained in:
commit
2f26467558
14 changed files with 399 additions and 90 deletions
|
|
@ -17,12 +17,7 @@ object SetupAuthenticationState : KoinTest {
|
|||
mainDispatcherTestRule: MainDispatcherTestRule,
|
||||
mockServerScenarioSetup: MockServerScenarioSetup
|
||||
) {
|
||||
mockServerScenarioSetup.setScenario(
|
||||
AuthScenario.Success(
|
||||
username = "a",
|
||||
password = "b"
|
||||
)
|
||||
)
|
||||
mockServerScenarioSetup.setScenario(AuthScenario.Success(username = "a", password = "b"))
|
||||
val activityScenario = ActivityScenario.launch(AuthActivity::class.java)
|
||||
activityScenario.moveToState(Lifecycle.State.RESUMED)
|
||||
val loginRobot = LoginRobot()
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ class MainActivityTest : KoinTest {
|
|||
@JvmField
|
||||
val mockServerScenarioSetupTestRule = MockServerScenarioSetupTestRule()
|
||||
|
||||
val mockServerScenarioSetup get() = mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val mainDispatcherTestRule = SpecificTestConfigurationsFactory.createMainDispatcherTestRule()
|
||||
|
|
@ -60,12 +62,12 @@ class MainActivityTest : KoinTest {
|
|||
@Before
|
||||
fun setUp() {
|
||||
SpecificTestConfigurationsFactory.createServerTypeConfiguration()
|
||||
.invoke(mockServerScenarioSetupTestRule.mockServerScenarioSetup)
|
||||
.invoke(mockServerScenarioSetup)
|
||||
|
||||
disposable = NetworkSynchronization.registerNetworkingSynchronization()
|
||||
homeRobot.setupLogin(
|
||||
mainDispatcherTestRule,
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
mockServerScenarioSetup
|
||||
)
|
||||
}
|
||||
|
||||
|
|
@ -78,8 +80,7 @@ class MainActivityTest : KoinTest {
|
|||
/** GIVEN initialized MainActivity WHEN signout is clicked THEN user is signed out */
|
||||
@Test
|
||||
fun signOutClickedResultsInNavigation() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Error(false))
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Error(usingRefreshedToken = false))
|
||||
activityScenario = ActivityScenario.launch(MainActivity::class.java)
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
||||
|
|
@ -92,8 +93,7 @@ class MainActivityTest : KoinTest {
|
|||
/** GIVEN success response WHEN data is returned THEN it is shown on the ui */
|
||||
@Test
|
||||
fun successfulDataLoadingShowsTheElementsOnTheUI() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Success(false))
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Success(usingRefreshedToken = false))
|
||||
activityScenario = ActivityScenario.launch(MainActivity::class.java)
|
||||
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
|
@ -106,8 +106,7 @@ class MainActivityTest : KoinTest {
|
|||
/** GIVEN success response WHEN item is clicked THEN ui is updated */
|
||||
@Test
|
||||
fun clickingOnListElementUpdatesTheElementsFavouriteState() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Success(false))
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Success(usingRefreshedToken = false))
|
||||
activityScenario = ActivityScenario.launch(MainActivity::class.java)
|
||||
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
|
@ -122,8 +121,7 @@ class MainActivityTest : KoinTest {
|
|||
/** GIVEN success response WHEN item is clicked THEN ui is updated even if activity is recreated */
|
||||
@Test
|
||||
fun elementFavouritedIsKeptEvenIfActivityIsRecreated() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Success(false))
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Success(usingRefreshedToken = false))
|
||||
activityScenario = ActivityScenario.launch(MainActivity::class.java)
|
||||
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
|
@ -143,8 +141,7 @@ class MainActivityTest : KoinTest {
|
|||
/** GIVEN success response WHEN item is clicked then clicked again THEN ui is updated */
|
||||
@Test
|
||||
fun clickingAnElementMultipleTimesProperlyUpdatesIt() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Success(false))
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Success(usingRefreshedToken = false))
|
||||
activityScenario = ActivityScenario.launch(MainActivity::class.java)
|
||||
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
|
@ -161,8 +158,7 @@ class MainActivityTest : KoinTest {
|
|||
/** GIVEN error response WHEN loaded THEN error is Shown */
|
||||
@Test
|
||||
fun networkErrorResultsInUIErrorStateShown() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Error(false))
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Error(usingRefreshedToken = false))
|
||||
activityScenario = ActivityScenario.launch(MainActivity::class.java)
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
||||
|
|
@ -174,10 +170,9 @@ class MainActivityTest : KoinTest {
|
|||
/** GIVEN error response then success WHEN retried THEN success is shown */
|
||||
@Test
|
||||
fun retryingFromErrorStateAndSucceedingShowsTheData() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(
|
||||
ContentScenario.Error(false)
|
||||
.then(ContentScenario.Success(false))
|
||||
mockServerScenarioSetup.setScenario(
|
||||
ContentScenario.Error(usingRefreshedToken = false)
|
||||
.then(ContentScenario.Success(usingRefreshedToken = false))
|
||||
)
|
||||
activityScenario = ActivityScenario.launch(MainActivity::class.java)
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
|
@ -195,10 +190,9 @@ class MainActivityTest : KoinTest {
|
|||
/** GIVEN success then error WHEN retried THEN error is shown */
|
||||
@Test
|
||||
fun errorIsShownIfTheDataIsFetchedAndErrorIsReceived() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(
|
||||
ContentScenario.Success(false)
|
||||
.then(ContentScenario.Error(false))
|
||||
mockServerScenarioSetup.setScenario(
|
||||
ContentScenario.Success(usingRefreshedToken = false)
|
||||
.then(ContentScenario.Error(usingRefreshedToken = false))
|
||||
)
|
||||
activityScenario = ActivityScenario.launch(MainActivity::class.java)
|
||||
mainDispatcherTestRule.advanceUntilIdleWithIdlingResources()
|
||||
|
|
@ -218,10 +212,9 @@ class MainActivityTest : KoinTest {
|
|||
/** GIVEN unauthenticated then success WHEN loaded THEN success is shown */
|
||||
@Test
|
||||
fun authenticationIsHandledWithASingleLoading() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(
|
||||
ContentScenario.Unauthorized(false)
|
||||
.then(ContentScenario.Success(true))
|
||||
mockServerScenarioSetup.setScenario(
|
||||
ContentScenario.Unauthorized(usingRefreshedToken = false)
|
||||
.then(ContentScenario.Success(usingRefreshedToken = true))
|
||||
)
|
||||
.setScenario(RefreshTokenScenario.Success)
|
||||
|
||||
|
|
@ -237,8 +230,7 @@ class MainActivityTest : KoinTest {
|
|||
/** GIVEN unauthenticated then error WHEN loaded THEN navigated to auth */
|
||||
@Test
|
||||
fun sessionExpirationResultsInNavigation() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
.setScenario(ContentScenario.Unauthorized(false))
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Unauthorized(usingRefreshedToken = false))
|
||||
.setScenario(RefreshTokenScenario.Error)
|
||||
|
||||
activityScenario = ActivityScenario.launch(MainActivity::class.java)
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ class AuthActivityTest : KoinTest {
|
|||
@Rule
|
||||
@JvmField
|
||||
val mockServerScenarioSetupTestRule = MockServerScenarioSetupTestRule()
|
||||
val mockServerScenarioSetup get() = mockServerScenarioSetupTestRule.mockServerScenarioSetup
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
|
|
@ -56,7 +57,7 @@ class AuthActivityTest : KoinTest {
|
|||
@Before
|
||||
fun setUp() {
|
||||
SpecificTestConfigurationsFactory.createServerTypeConfiguration()
|
||||
.invoke(mockServerScenarioSetupTestRule.mockServerScenarioSetup)
|
||||
.invoke(mockServerScenarioSetup)
|
||||
disposable = NetworkSynchronization.registerNetworkingSynchronization()
|
||||
}
|
||||
|
||||
|
|
@ -69,11 +70,8 @@ class AuthActivityTest : KoinTest {
|
|||
/** GIVEN non empty password and username and successful response WHEN signIn THEN no error is shown and navigating to home */
|
||||
@Test
|
||||
fun properLoginResultsInNavigationToHome() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup.setScenario(
|
||||
AuthScenario.Success(
|
||||
password = "alma",
|
||||
username = "banan"
|
||||
)
|
||||
mockServerScenarioSetup.setScenario(
|
||||
AuthScenario.Success(password = "alma", username = "banan")
|
||||
)
|
||||
activityScenario = ActivityScenario.launch(AuthActivity::class.java)
|
||||
loginRobot
|
||||
|
|
@ -123,7 +121,7 @@ class AuthActivityTest : KoinTest {
|
|||
/** GIVEN password and username and invalid credentials response WHEN signIn THEN error invalid credentials is shown */
|
||||
@Test
|
||||
fun invalidCredentialsGivenShowsProperErrorMessage() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup.setScenario(
|
||||
mockServerScenarioSetup.setScenario(
|
||||
AuthScenario.InvalidCredentials(username = "alma", password = "banan")
|
||||
)
|
||||
activityScenario = ActivityScenario.launch(AuthActivity::class.java)
|
||||
|
|
@ -144,7 +142,7 @@ class AuthActivityTest : KoinTest {
|
|||
/** GIVEN password and username and error response WHEN signIn THEN error invalid credentials is shown */
|
||||
@Test
|
||||
fun networkErrorShowsProperErrorMessage() {
|
||||
mockServerScenarioSetupTestRule.mockServerScenarioSetup.setScenario(
|
||||
mockServerScenarioSetup.setScenario(
|
||||
AuthScenario.GenericError(username = "alma", password = "banan")
|
||||
)
|
||||
activityScenario = ActivityScenario.launch(AuthActivity::class.java)
|
||||
|
|
|
|||
|
|
@ -31,6 +31,13 @@ subprojects { module ->
|
|||
includeAndroidResources = true
|
||||
}
|
||||
}
|
||||
module.tasks.configureEach { task ->
|
||||
if (task.taskIdentity.type.toString() == "class org.jetbrains.kotlin.gradle.tasks.KotlinCompile") {
|
||||
task.kotlinOptions {
|
||||
freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugins.withId("com.android.library") {
|
||||
|
|
@ -47,5 +54,12 @@ subprojects { module ->
|
|||
includeAndroidResources = true
|
||||
}
|
||||
}
|
||||
module.tasks.configureEach { task ->
|
||||
if (task.taskIdentity.type.toString() == "class org.jetbrains.kotlin.gradle.tasks.KotlinCompile") {
|
||||
task.kotlinOptions {
|
||||
freeCompilerArgs += "-opt-in=kotlin.RequiresOptIn"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -38,6 +38,7 @@ internal class ScenarioToRequestScenario {
|
|||
is AuthScenario.Success -> CreateAuthSuccessResponse()
|
||||
is AuthScenario.MalformedJsonAsSuccessResponse -> CreateMalformedJsonSuccessResponse()
|
||||
is AuthScenario.UnexpectedJsonAsSuccessResponse -> CreateGenericSuccessResponseByJson("[]")
|
||||
is AuthScenario.MissingFieldJson -> CreateGenericSuccessResponseByJson("{}")
|
||||
}
|
||||
val requestMatchingChecker = AuthRequestMatchingChecker(authScenario, validateArguments)
|
||||
return SpecificRequestScenario(requestMatchingChecker, createResponse)
|
||||
|
|
|
|||
|
|
@ -12,4 +12,5 @@ sealed class AuthScenario : GenericScenario<AuthScenario>() {
|
|||
class GenericError(override val username: String, override val password: String) : AuthScenario()
|
||||
class UnexpectedJsonAsSuccessResponse(override val username: String, override val password: String) : AuthScenario()
|
||||
class MalformedJsonAsSuccessResponse(override val username: String, override val password: String) : AuthScenario()
|
||||
class MissingFieldJson(override val username: String, override val password: String) : AuthScenario()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@ package org.fnives.test.showcase.network.mockserver.scenario.createresponse
|
|||
import okhttp3.mockwebserver.MockResponse
|
||||
|
||||
internal class CreateMalformedJsonSuccessResponse : CreateResponse {
|
||||
override fun getResponse(): MockResponse = MockResponse().setResponseCode(200).setBody("[")
|
||||
override fun getResponse(): MockResponse = MockResponse().setResponseCode(200).setBody("{")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,11 @@ class CodeKataLoginRemoteSourceTest {
|
|||
fun invalidJsonMeansParsingException() {
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN json response with missing field WHEN request is fired THEN network exception is thrown")
|
||||
@Test
|
||||
fun missingFieldJsonMeansParsingException() {
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN malformed json response WHEN request is fired THEN network exception is thrown")
|
||||
@Test
|
||||
fun malformedJsonMeansParsingException() {
|
||||
|
|
@ -66,5 +71,13 @@ class CodeKataLoginRemoteSourceTest {
|
|||
} while (true)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun getLoginBodyJson(username: String, password: String): String =
|
||||
"""
|
||||
{
|
||||
"username": "$username",
|
||||
"password": "$password"
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,8 +30,7 @@ class LoginRemoteSourceRefreshActionImplTest : KoinTest {
|
|||
@RegisterExtension
|
||||
@JvmField
|
||||
val mockServerScenarioSetupExtensions = MockServerScenarioSetupExtensions()
|
||||
private val mockServerScenarioSetup
|
||||
get() = mockServerScenarioSetupExtensions.mockServerScenarioSetup
|
||||
private val mockServerScenarioSetup get() = mockServerScenarioSetupExtensions.mockServerScenarioSetup
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
|
|
@ -56,7 +55,7 @@ class LoginRemoteSourceRefreshActionImplTest : KoinTest {
|
|||
@DisplayName("GIVEN successful response WHEN refresh request is fired THEN session is returned")
|
||||
@Test
|
||||
fun successResponseResultsInSession() = runBlocking {
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Success)
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Success, validateArguments = false)
|
||||
val expected = ContentData.refreshSuccessResponse
|
||||
|
||||
val actual = sut.refresh(ContentData.refreshSuccessResponse.refreshToken)
|
||||
|
|
@ -67,7 +66,7 @@ class LoginRemoteSourceRefreshActionImplTest : KoinTest {
|
|||
@DisplayName("GIVEN successful response WHEN refresh request is fired THEN the request is setup properly")
|
||||
@Test
|
||||
fun refreshRequestIsSetupProperly() = runBlocking {
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Success, false)
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Success, validateArguments = false)
|
||||
|
||||
sut.refresh(ContentData.refreshSuccessResponse.refreshToken)
|
||||
val request = mockServerScenarioSetup.takeRequest()
|
||||
|
|
@ -82,7 +81,7 @@ class LoginRemoteSourceRefreshActionImplTest : KoinTest {
|
|||
@DisplayName("GIVEN internal error response WHEN refresh request is fired THEN network exception is thrown")
|
||||
@Test
|
||||
fun generalErrorResponseResultsInNetworkException() {
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Error)
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Error, validateArguments = false)
|
||||
|
||||
Assertions.assertThrows(NetworkException::class.java) {
|
||||
runBlocking { sut.refresh(ContentData.refreshSuccessResponse.refreshToken) }
|
||||
|
|
@ -92,7 +91,7 @@ class LoginRemoteSourceRefreshActionImplTest : KoinTest {
|
|||
@DisplayName("GIVEN invalid json response WHEN refresh request is fired THEN network exception is thrown")
|
||||
@Test
|
||||
fun jsonErrorResponseResultsInParsingException() {
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.UnexpectedJsonAsSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.UnexpectedJsonAsSuccessResponse, validateArguments = false)
|
||||
|
||||
Assertions.assertThrows(ParsingException::class.java) {
|
||||
runBlocking { sut.refresh(ContentData.loginSuccessResponse.refreshToken) }
|
||||
|
|
@ -102,7 +101,7 @@ class LoginRemoteSourceRefreshActionImplTest : KoinTest {
|
|||
@DisplayName("GIVEN malformed json response WHEN refresh request is fired THEN parsing exception is thrown")
|
||||
@Test
|
||||
fun malformedJsonErrorResponseResultsInParsingException() {
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.MalformedJson)
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.MalformedJson, validateArguments = false)
|
||||
|
||||
Assertions.assertThrows(ParsingException::class.java) {
|
||||
runBlocking { sut.refresh(ContentData.loginSuccessResponse.refreshToken) }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package org.fnives.test.showcase.network.auth
|
||||
|
||||
import com.squareup.moshi.JsonDataException
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import okio.EOFException
|
||||
import org.fnives.test.showcase.model.auth.LoginCredentials
|
||||
import org.fnives.test.showcase.model.network.BaseUrl
|
||||
import org.fnives.test.showcase.network.auth.model.LoginStatusResponses
|
||||
|
|
@ -25,6 +27,7 @@ import org.koin.test.inject
|
|||
import org.mockito.kotlin.mock
|
||||
import org.skyscreamer.jsonassert.JSONAssert
|
||||
import org.skyscreamer.jsonassert.JSONCompareMode
|
||||
import retrofit2.HttpException
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
class LoginRemoteSourceTest : KoinTest {
|
||||
|
|
@ -34,8 +37,7 @@ class LoginRemoteSourceTest : KoinTest {
|
|||
@RegisterExtension
|
||||
@JvmField
|
||||
val mockServerScenarioSetupExtensions = MockServerScenarioSetupExtensions()
|
||||
private val mockServerScenarioSetup
|
||||
get() = mockServerScenarioSetupExtensions.mockServerScenarioSetup
|
||||
private val mockServerScenarioSetup get() = mockServerScenarioSetupExtensions.mockServerScenarioSetup
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
|
|
@ -60,10 +62,10 @@ class LoginRemoteSourceTest : KoinTest {
|
|||
@DisplayName("GIVEN successful response WHEN request is fired THEN login status success is returned")
|
||||
@Test
|
||||
fun successResponseIsParsedProperly() = runBlocking {
|
||||
mockServerScenarioSetup.setScenario(AuthScenario.Success("a", "b"))
|
||||
mockServerScenarioSetup.setScenario(AuthScenario.Success(username = "a", password = "b"), validateArguments = false)
|
||||
val expected = LoginStatusResponses.Success(ContentData.loginSuccessResponse)
|
||||
|
||||
val actual = sut.login(LoginCredentials("a", "b"))
|
||||
val actual = sut.login(LoginCredentials(username = "a", password = "b"))
|
||||
|
||||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
|
@ -71,16 +73,16 @@ class LoginRemoteSourceTest : KoinTest {
|
|||
@DisplayName("GIVEN successful response WHEN request is fired THEN the request is setup properly")
|
||||
@Test
|
||||
fun requestProperlySetup() = runBlocking {
|
||||
mockServerScenarioSetup.setScenario(AuthScenario.Success("a", "b"), false)
|
||||
mockServerScenarioSetup.setScenario(AuthScenario.Success(username = "a", password = "b"), validateArguments = false)
|
||||
|
||||
sut.login(LoginCredentials("a", "b"))
|
||||
sut.login(LoginCredentials(username = "a", password = "b"))
|
||||
val request = mockServerScenarioSetup.takeRequest()
|
||||
|
||||
Assertions.assertEquals("POST", request.method)
|
||||
Assertions.assertEquals("Android", request.getHeader("Platform"))
|
||||
Assertions.assertEquals(null, request.getHeader("Authorization"))
|
||||
Assertions.assertEquals("/login", request.path)
|
||||
val loginRequest = createExpectedLoginRequestJson("a", "b")
|
||||
val loginRequest = createExpectedLoginRequestJson(username = "a", password = "b")
|
||||
JSONAssert.assertEquals(
|
||||
loginRequest,
|
||||
request.body.readUtf8(),
|
||||
|
|
@ -91,10 +93,10 @@ class LoginRemoteSourceTest : KoinTest {
|
|||
@DisplayName("GIVEN bad request response WHEN request is fired THEN login status invalid credentials is returned")
|
||||
@Test
|
||||
fun badRequestMeansInvalidCredentials() = runBlocking {
|
||||
mockServerScenarioSetup.setScenario(AuthScenario.InvalidCredentials("a", "b"))
|
||||
mockServerScenarioSetup.setScenario(AuthScenario.InvalidCredentials(username = "a", password = "b"), validateArguments = false)
|
||||
val expected = LoginStatusResponses.InvalidCredentials
|
||||
|
||||
val actual = sut.login(LoginCredentials("a", "b"))
|
||||
val actual = sut.login(LoginCredentials(username = "a", password = "b"))
|
||||
|
||||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
|
@ -102,30 +104,55 @@ class LoginRemoteSourceTest : KoinTest {
|
|||
@DisplayName("GIVEN internal error response WHEN request is fired THEN network exception is thrown")
|
||||
@Test
|
||||
fun genericErrorMeansNetworkError() {
|
||||
mockServerScenarioSetup.setScenario(AuthScenario.GenericError("a", "b"))
|
||||
mockServerScenarioSetup.setScenario(AuthScenario.GenericError(username = "a", password = "b"), validateArguments = false)
|
||||
|
||||
Assertions.assertThrows(NetworkException::class.java) {
|
||||
runBlocking { sut.login(LoginCredentials("a", "b")) }
|
||||
val actual = Assertions.assertThrows(NetworkException::class.java) {
|
||||
runBlocking { sut.login(LoginCredentials(username = "a", password = "b")) }
|
||||
}
|
||||
|
||||
Assertions.assertEquals("HTTP 500 Server Error", actual.message)
|
||||
Assertions.assertTrue(actual.cause is HttpException)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN invalid json response WHEN request is fired THEN network exception is thrown")
|
||||
@Test
|
||||
fun invalidJsonMeansParsingException() {
|
||||
mockServerScenarioSetup.setScenario(AuthScenario.UnexpectedJsonAsSuccessResponse("a", "b"))
|
||||
val response = AuthScenario.UnexpectedJsonAsSuccessResponse(username = "a", password = "b")
|
||||
mockServerScenarioSetup.setScenario(response, validateArguments = false)
|
||||
|
||||
Assertions.assertThrows(ParsingException::class.java) {
|
||||
runBlocking { sut.login(LoginCredentials("a", "b")) }
|
||||
val actual = Assertions.assertThrows(ParsingException::class.java) {
|
||||
runBlocking { sut.login(LoginCredentials(username = "a", password = "b")) }
|
||||
}
|
||||
|
||||
Assertions.assertEquals("Expected BEGIN_OBJECT but was BEGIN_ARRAY at path \$", actual.message)
|
||||
Assertions.assertTrue(actual.cause is JsonDataException)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN json response with missing field WHEN request is fired THEN network exception is thrown")
|
||||
@Test
|
||||
fun missingFieldJsonMeansParsingException() {
|
||||
val response = AuthScenario.MissingFieldJson(username = "a", password = "b")
|
||||
mockServerScenarioSetup.setScenario(response, validateArguments = false)
|
||||
|
||||
val actual = Assertions.assertThrows(ParsingException::class.java) {
|
||||
runBlocking { sut.login(LoginCredentials(username = "a", password = "b")) }
|
||||
}
|
||||
|
||||
Assertions.assertEquals("Required value 'accessToken' missing at \$", actual.message)
|
||||
Assertions.assertTrue(actual.cause is JsonDataException)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN malformed json response WHEN request is fired THEN network exception is thrown")
|
||||
@Test
|
||||
fun malformedJsonMeansParsingException() {
|
||||
mockServerScenarioSetup.setScenario(AuthScenario.MalformedJsonAsSuccessResponse("a", "b"))
|
||||
val response = AuthScenario.MalformedJsonAsSuccessResponse(username = "a", "b")
|
||||
mockServerScenarioSetup.setScenario(response, validateArguments = false)
|
||||
|
||||
Assertions.assertThrows(ParsingException::class.java) {
|
||||
runBlocking { sut.login(LoginCredentials("a", "b")) }
|
||||
val actual = Assertions.assertThrows(ParsingException::class.java) {
|
||||
runBlocking { sut.login(LoginCredentials(username = "a", "b")) }
|
||||
}
|
||||
|
||||
Assertions.assertEquals("End of input", actual.message)
|
||||
Assertions.assertTrue(actual.cause is EOFException)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,155 @@
|
|||
package org.fnives.test.showcase.network.auth
|
||||
|
||||
import com.squareup.moshi.JsonDataException
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import okhttp3.mockwebserver.MockResponse
|
||||
import okhttp3.mockwebserver.MockWebServer
|
||||
import okio.EOFException
|
||||
import org.fnives.test.showcase.model.auth.LoginCredentials
|
||||
import org.fnives.test.showcase.model.network.BaseUrl
|
||||
import org.fnives.test.showcase.model.session.Session
|
||||
import org.fnives.test.showcase.network.auth.CodeKataLoginRemoteSourceTest.Companion.getLoginBodyJson
|
||||
import org.fnives.test.showcase.network.auth.CodeKataLoginRemoteSourceTest.Companion.readResourceFile
|
||||
import org.fnives.test.showcase.network.auth.model.LoginStatusResponses
|
||||
import org.fnives.test.showcase.network.di.createNetworkModules
|
||||
import org.fnives.test.showcase.network.shared.exceptions.NetworkException
|
||||
import org.fnives.test.showcase.network.shared.exceptions.ParsingException
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.koin.core.context.GlobalContext.stopKoin
|
||||
import org.koin.core.context.startKoin
|
||||
import org.koin.test.KoinTest
|
||||
import org.koin.test.inject
|
||||
import org.mockito.kotlin.mock
|
||||
import org.skyscreamer.jsonassert.JSONAssert
|
||||
import org.skyscreamer.jsonassert.JSONCompareMode
|
||||
import retrofit2.HttpException
|
||||
|
||||
class PlainLoginRemoteSourceTest : KoinTest {
|
||||
|
||||
private val sut by inject<LoginRemoteSource>()
|
||||
private lateinit var mockWebServer: MockWebServer
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
mockWebServer = MockWebServer()
|
||||
mockWebServer.start()
|
||||
startKoin {
|
||||
modules(
|
||||
createNetworkModules(
|
||||
baseUrl = BaseUrl(mockWebServer.url("mockserver/").toString()),
|
||||
enableLogging = true,
|
||||
networkSessionExpirationListenerProvider = { mock() },
|
||||
networkSessionLocalStorageProvider = { mock() }
|
||||
).toList()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
fun tearDown() {
|
||||
stopKoin()
|
||||
mockWebServer.shutdown()
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN successful response WHEN request is fired THEN login status success is returned")
|
||||
@Test
|
||||
fun successResponseIsParsedProperly() = runBlocking {
|
||||
mockWebServer.enqueue(MockResponse().setResponseCode(200).setBody(readResourceFile("success_response_login.json")))
|
||||
val session = Session(accessToken = "login-access", refreshToken = "login-refresh")
|
||||
val expected = LoginStatusResponses.Success(session = session)
|
||||
|
||||
val actual = sut.login(LoginCredentials(username = "alma", password = "banan"))
|
||||
|
||||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN successful response WHEN request is fired THEN the request is setup properly")
|
||||
@Test
|
||||
fun requestProperlySetup() = runBlocking {
|
||||
|
||||
mockWebServer.enqueue(MockResponse().setResponseCode(200).setBody(readResourceFile("success_response_login.json")))
|
||||
|
||||
sut.login(LoginCredentials(username = "alma", password = "banan"))
|
||||
|
||||
val request = mockWebServer.takeRequest()
|
||||
|
||||
Assertions.assertEquals("POST", request.method)
|
||||
Assertions.assertEquals("Android", request.getHeader("Platform"))
|
||||
Assertions.assertEquals(null, request.getHeader("Authorization"))
|
||||
Assertions.assertEquals("/mockserver/login", request.path)
|
||||
val loginRequestBody = getLoginBodyJson(username = "alma", password = "banan")
|
||||
JSONAssert.assertEquals(
|
||||
loginRequestBody,
|
||||
request.body.readUtf8(),
|
||||
JSONCompareMode.NON_EXTENSIBLE
|
||||
)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN bad request response WHEN request is fired THEN login status invalid credentials is returned")
|
||||
@Test
|
||||
fun badRequestMeansInvalidCredentials() = runBlocking {
|
||||
mockWebServer.enqueue(MockResponse().setResponseCode(400).setBody("{}"))
|
||||
|
||||
val expected = LoginStatusResponses.InvalidCredentials
|
||||
|
||||
val actual = sut.login(LoginCredentials(username = "a", password = "b"))
|
||||
|
||||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN internal error response WHEN request is fired THEN network exception is thrown")
|
||||
@Test
|
||||
fun genericErrorMeansNetworkError() {
|
||||
mockWebServer.enqueue(MockResponse().setResponseCode(500).setBody("{}"))
|
||||
|
||||
val actual = Assertions.assertThrows(NetworkException::class.java) {
|
||||
runBlocking { sut.login(LoginCredentials(username = "a", password = "b")) }
|
||||
}
|
||||
|
||||
Assertions.assertEquals("HTTP 500 Server Error", actual.message)
|
||||
Assertions.assertTrue(actual.cause is HttpException)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN invalid json response WHEN request is fired THEN network exception is thrown")
|
||||
@Test
|
||||
fun invalidJsonMeansParsingException() {
|
||||
mockWebServer.enqueue(MockResponse().setResponseCode(200).setBody("[]"))
|
||||
|
||||
val actual = Assertions.assertThrows(ParsingException::class.java) {
|
||||
runBlocking { sut.login(LoginCredentials(username = "a", password = "b")) }
|
||||
}
|
||||
|
||||
Assertions.assertEquals("Expected BEGIN_OBJECT but was BEGIN_ARRAY at path \$", actual.message)
|
||||
Assertions.assertTrue(actual.cause is JsonDataException)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN json response with missing field WHEN request is fired THEN network exception is thrown")
|
||||
@Test
|
||||
fun missingFieldJsonMeansParsingException() {
|
||||
mockWebServer.enqueue(MockResponse().setResponseCode(200).setBody("{}"))
|
||||
|
||||
val actual = Assertions.assertThrows(ParsingException::class.java) {
|
||||
runBlocking { sut.login(LoginCredentials(username = "a", password = "b")) }
|
||||
}
|
||||
|
||||
Assertions.assertEquals("Required value 'accessToken' missing at \$", actual.message)
|
||||
Assertions.assertTrue(actual.cause is JsonDataException)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN malformed json response WHEN request is fired THEN network exception is thrown")
|
||||
@Test
|
||||
fun malformedJsonMeansParsingException() {
|
||||
mockWebServer.enqueue(MockResponse().setResponseCode(200).setBody("{"))
|
||||
|
||||
val actual = Assertions.assertThrows(ParsingException::class.java) {
|
||||
runBlocking { sut.login(LoginCredentials(username = "a", password = "b")) }
|
||||
}
|
||||
|
||||
Assertions.assertEquals("End of input", actual.message)
|
||||
Assertions.assertTrue(actual.cause is EOFException)
|
||||
}
|
||||
}
|
||||
|
|
@ -32,8 +32,7 @@ class ContentRemoteSourceImplTest : KoinTest {
|
|||
@JvmField
|
||||
val mockServerScenarioSetupExtensions = MockServerScenarioSetupExtensions()
|
||||
private lateinit var mockNetworkSessionLocalStorage: NetworkSessionLocalStorage
|
||||
private val mockServerScenarioSetup
|
||||
get() = mockServerScenarioSetupExtensions.mockServerScenarioSetup
|
||||
private val mockServerScenarioSetup get() = mockServerScenarioSetupExtensions.mockServerScenarioSetup
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
|
|
@ -59,7 +58,7 @@ class ContentRemoteSourceImplTest : KoinTest {
|
|||
@Test
|
||||
fun successResponseParsing() = runBlocking {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Success(false))
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Success(usingRefreshedToken = false), validateArguments = false)
|
||||
val expected = ContentData.contentSuccess
|
||||
|
||||
val actual = sut.get()
|
||||
|
|
@ -71,7 +70,7 @@ class ContentRemoteSourceImplTest : KoinTest {
|
|||
@Test
|
||||
fun successResponseRequestIsCorrect() = runBlocking {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Success(false), false)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Success(usingRefreshedToken = false), validateArguments = false)
|
||||
|
||||
sut.get()
|
||||
val request = mockServerScenarioSetup.takeRequest()
|
||||
|
|
@ -87,7 +86,8 @@ class ContentRemoteSourceImplTest : KoinTest {
|
|||
@Test
|
||||
fun dataMissingFieldIsIgnored() = runBlocking {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.SuccessWithMissingFields(false))
|
||||
val response = ContentScenario.SuccessWithMissingFields(usingRefreshedToken = false)
|
||||
mockServerScenarioSetup.setScenario(response, validateArguments = false)
|
||||
|
||||
val expected = ContentData.contentSuccessWithMissingFields
|
||||
|
||||
|
|
@ -100,7 +100,7 @@ class ContentRemoteSourceImplTest : KoinTest {
|
|||
@Test
|
||||
fun errorResponseResultsInNetworkException() {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Error(false))
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Error(usingRefreshedToken = false), validateArguments = false)
|
||||
|
||||
Assertions.assertThrows(NetworkException::class.java) {
|
||||
runBlocking { sut.get() }
|
||||
|
|
@ -111,7 +111,8 @@ class ContentRemoteSourceImplTest : KoinTest {
|
|||
@Test
|
||||
fun unexpectedJSONResultsInParsingException() {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.UnexpectedJsonAsSuccessResponse(false))
|
||||
val response = ContentScenario.UnexpectedJsonAsSuccessResponse(usingRefreshedToken = false)
|
||||
mockServerScenarioSetup.setScenario(response, validateArguments = false)
|
||||
|
||||
Assertions.assertThrows(ParsingException::class.java) {
|
||||
runBlocking { sut.get() }
|
||||
|
|
@ -122,7 +123,8 @@ class ContentRemoteSourceImplTest : KoinTest {
|
|||
@Test
|
||||
fun malformedJSONResultsInParsingException() {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.MalformedJsonAsSuccessResponse(false))
|
||||
val response = ContentScenario.MalformedJsonAsSuccessResponse(usingRefreshedToken = false)
|
||||
mockServerScenarioSetup.setScenario(response, validateArguments = false)
|
||||
|
||||
Assertions.assertThrows(ParsingException::class.java) {
|
||||
runBlocking { sut.get() }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,111 @@
|
|||
package org.fnives.test.showcase.network.content
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import okhttp3.mockwebserver.MockResponse
|
||||
import okhttp3.mockwebserver.MockWebServer
|
||||
import org.fnives.test.showcase.model.network.BaseUrl
|
||||
import org.fnives.test.showcase.model.session.Session
|
||||
import org.fnives.test.showcase.network.auth.CodeKataLoginRemoteSourceTest.Companion.readResourceFile
|
||||
import org.fnives.test.showcase.network.di.createNetworkModules
|
||||
import org.fnives.test.showcase.network.session.NetworkSessionExpirationListener
|
||||
import org.fnives.test.showcase.network.session.NetworkSessionLocalStorage
|
||||
import org.fnives.test.showcase.network.shared.exceptions.NetworkException
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.BeforeEach
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.koin.core.context.startKoin
|
||||
import org.koin.core.context.stopKoin
|
||||
import org.koin.test.KoinTest
|
||||
import org.koin.test.inject
|
||||
import org.mockito.kotlin.anyOrNull
|
||||
import org.mockito.kotlin.doAnswer
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.times
|
||||
import org.mockito.kotlin.verify
|
||||
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||
import org.mockito.kotlin.verifyZeroInteractions
|
||||
import org.mockito.kotlin.whenever
|
||||
import retrofit2.HttpException
|
||||
|
||||
class PlainSessionExpirationTest : KoinTest {
|
||||
|
||||
private val sut by inject<ContentRemoteSource>()
|
||||
private lateinit var mockWebServer: MockWebServer
|
||||
private lateinit var mockNetworkSessionLocalStorage: NetworkSessionLocalStorage
|
||||
private lateinit var mockNetworkSessionExpirationListener: NetworkSessionExpirationListener
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
mockWebServer = MockWebServer()
|
||||
mockWebServer.start()
|
||||
mockNetworkSessionLocalStorage = mock()
|
||||
mockNetworkSessionExpirationListener = mock()
|
||||
startKoin {
|
||||
modules(
|
||||
createNetworkModules(
|
||||
baseUrl = BaseUrl(mockWebServer.url("mockserver/").toString()),
|
||||
enableLogging = true,
|
||||
networkSessionExpirationListenerProvider = { mockNetworkSessionExpirationListener },
|
||||
networkSessionLocalStorageProvider = { mockNetworkSessionLocalStorage }
|
||||
).toList()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
fun tearDown() {
|
||||
stopKoin()
|
||||
mockWebServer.shutdown()
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN 401 THEN refresh token ok response WHEN content requested THE tokens are refreshed and request retried with new tokens")
|
||||
@Test
|
||||
fun successRefreshResultsInRequestRetry() = runBlocking {
|
||||
mockWebServer.enqueue(MockResponse().setResponseCode(401))
|
||||
mockWebServer.enqueue(MockResponse().setResponseCode(200).setBody(readResourceFile("success_response_login.json")))
|
||||
mockWebServer.enqueue(MockResponse().setResponseCode(200).setBody("[]"))
|
||||
|
||||
var sessionToReturnByMock: Session? = Session(accessToken = "expired-access", refreshToken = "expired-refresh")
|
||||
whenever(mockNetworkSessionLocalStorage.session).doAnswer { sessionToReturnByMock }
|
||||
doAnswer { sessionToReturnByMock = it.arguments[0] as Session? }
|
||||
.whenever(mockNetworkSessionLocalStorage).session = anyOrNull()
|
||||
|
||||
sut.get()
|
||||
|
||||
mockWebServer.takeRequest()
|
||||
val refreshRequest = mockWebServer.takeRequest()
|
||||
val contentRequestAfterRefreshed = mockWebServer.takeRequest()
|
||||
|
||||
Assertions.assertEquals("PUT", refreshRequest.method)
|
||||
Assertions.assertEquals("/mockserver/login/expired-refresh", refreshRequest.path)
|
||||
Assertions.assertEquals(null, refreshRequest.getHeader("Authorization"))
|
||||
Assertions.assertEquals("Android", refreshRequest.getHeader("Platform"))
|
||||
Assertions.assertEquals("", refreshRequest.body.readUtf8())
|
||||
|
||||
Assertions.assertEquals("login-access", contentRequestAfterRefreshed.getHeader("Authorization"))
|
||||
verifyZeroInteractions(mockNetworkSessionExpirationListener)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN 401 THEN failing refresh WHEN content requested THE error is returned and callback is Called")
|
||||
@Test
|
||||
fun failingRefreshResultsInSessionExpiration() = runBlocking {
|
||||
val currentSession = Session(accessToken = "expired-access", refreshToken = "expired-refresh")
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(currentSession)
|
||||
mockWebServer.enqueue(MockResponse().setResponseCode(401))
|
||||
mockWebServer.enqueue(MockResponse().setResponseCode(400))
|
||||
|
||||
val actual = Assertions.assertThrows(NetworkException::class.java) {
|
||||
runBlocking { sut.get() }
|
||||
}
|
||||
|
||||
Assertions.assertEquals("HTTP 401 Client Error", actual.message)
|
||||
Assertions.assertTrue(actual.cause is HttpException)
|
||||
verify(mockNetworkSessionLocalStorage, times(3)).session
|
||||
verify(mockNetworkSessionLocalStorage, times(1)).session = null
|
||||
verifyNoMoreInteractions(mockNetworkSessionLocalStorage)
|
||||
verify(mockNetworkSessionExpirationListener, times(1)).onSessionExpired()
|
||||
}
|
||||
}
|
||||
|
|
@ -30,6 +30,7 @@ import org.mockito.kotlin.verify
|
|||
import org.mockito.kotlin.verifyNoMoreInteractions
|
||||
import org.mockito.kotlin.verifyZeroInteractions
|
||||
import org.mockito.kotlin.whenever
|
||||
import retrofit2.HttpException
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
class SessionExpirationTest : KoinTest {
|
||||
|
|
@ -39,8 +40,7 @@ class SessionExpirationTest : KoinTest {
|
|||
@RegisterExtension
|
||||
@JvmField
|
||||
val mockServerScenarioSetupExtensions = MockServerScenarioSetupExtensions()
|
||||
private val mockServerScenarioSetup
|
||||
get() = mockServerScenarioSetupExtensions.mockServerScenarioSetup
|
||||
private val mockServerScenarioSetup get() = mockServerScenarioSetupExtensions.mockServerScenarioSetup
|
||||
private lateinit var mockNetworkSessionLocalStorage: NetworkSessionLocalStorage
|
||||
private lateinit var mockNetworkSessionExpirationListener: NetworkSessionExpirationListener
|
||||
|
||||
|
|
@ -70,11 +70,11 @@ class SessionExpirationTest : KoinTest {
|
|||
fun successRefreshResultsInRequestRetry() = runBlocking {
|
||||
var sessionToReturnByMock: Session? = ContentData.loginSuccessResponse
|
||||
mockServerScenarioSetup.setScenario(
|
||||
ContentScenario.Unauthorized(false)
|
||||
.then(ContentScenario.Success(true)),
|
||||
false
|
||||
ContentScenario.Unauthorized(usingRefreshedToken = false)
|
||||
.then(ContentScenario.Success(usingRefreshedToken = true)),
|
||||
validateArguments = false
|
||||
)
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Success, false)
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Success, validateArguments = false)
|
||||
whenever(mockNetworkSessionLocalStorage.session).doAnswer { sessionToReturnByMock }
|
||||
doAnswer { sessionToReturnByMock = it.arguments[0] as Session? }
|
||||
.whenever(mockNetworkSessionLocalStorage).session = anyOrNull()
|
||||
|
|
@ -97,8 +97,6 @@ class SessionExpirationTest : KoinTest {
|
|||
ContentData.refreshSuccessResponse.accessToken,
|
||||
retryAfterTokenRefreshRequest.getHeader("Authorization")
|
||||
)
|
||||
verify(mockNetworkSessionLocalStorage, times(1)).session =
|
||||
ContentData.refreshSuccessResponse
|
||||
verifyZeroInteractions(mockNetworkSessionExpirationListener)
|
||||
}
|
||||
|
||||
|
|
@ -106,12 +104,15 @@ class SessionExpirationTest : KoinTest {
|
|||
@Test
|
||||
fun failingRefreshResultsInSessionExpiration() = runBlocking {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Unauthorized(false))
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Error)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Unauthorized(usingRefreshedToken = false), validateArguments = false)
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Error, validateArguments = false)
|
||||
|
||||
Assertions.assertThrows(NetworkException::class.java) {
|
||||
val actual = Assertions.assertThrows(NetworkException::class.java) {
|
||||
runBlocking { sut.get() }
|
||||
}
|
||||
|
||||
Assertions.assertEquals("HTTP 401 Client Error", actual.message)
|
||||
Assertions.assertTrue(actual.cause is HttpException)
|
||||
verify(mockNetworkSessionLocalStorage, times(3)).session
|
||||
verify(mockNetworkSessionLocalStorage, times(1)).session = null
|
||||
verifyNoMoreInteractions(mockNetworkSessionLocalStorage)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue