Issue#31 Remove hilt completely
This commit is contained in:
parent
e3bf7fd3e2
commit
b29870c90c
84 changed files with 75 additions and 1875 deletions
|
|
@ -21,9 +21,6 @@ dependencies {
|
|||
// koin
|
||||
api "io.insert-koin:koin-core:$koin_version"
|
||||
|
||||
// hilt
|
||||
implementation "com.google.dagger:hilt-core:$hilt_version"
|
||||
|
||||
api project(":model")
|
||||
|
||||
testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$coroutines_version"
|
||||
|
|
@ -33,6 +30,4 @@ dependencies {
|
|||
testImplementation "io.insert-koin:koin-test-junit5:$koin_version"
|
||||
testImplementation "org.skyscreamer:jsonassert:$testing_json_assert_version"
|
||||
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$testing_junit5_version"
|
||||
kapt "com.google.dagger:hilt-compiler:$hilt_version"
|
||||
kaptTest "com.google.dagger:dagger-compiler:$hilt_version"
|
||||
}
|
||||
|
|
@ -7,9 +7,8 @@ import org.fnives.test.showcase.network.shared.ExceptionWrapper
|
|||
import org.fnives.test.showcase.network.shared.exceptions.ParsingException
|
||||
import retrofit2.HttpException
|
||||
import retrofit2.Response
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class LoginErrorConverter @Inject constructor() {
|
||||
internal class LoginErrorConverter {
|
||||
|
||||
@Throws(ParsingException::class)
|
||||
suspend fun invoke(request: suspend () -> Response<LoginResponse>): LoginStatusResponses =
|
||||
|
|
|
|||
|
|
@ -7,9 +7,8 @@ import org.fnives.test.showcase.network.auth.model.LoginStatusResponses
|
|||
import org.fnives.test.showcase.network.shared.ExceptionWrapper
|
||||
import org.fnives.test.showcase.network.shared.exceptions.NetworkException
|
||||
import org.fnives.test.showcase.network.shared.exceptions.ParsingException
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class LoginRemoteSourceImpl @Inject constructor(
|
||||
internal class LoginRemoteSourceImpl(
|
||||
private val loginService: LoginService,
|
||||
private val loginErrorConverter: LoginErrorConverter
|
||||
) : LoginRemoteSource {
|
||||
|
|
|
|||
|
|
@ -4,9 +4,8 @@ import org.fnives.test.showcase.model.content.Content
|
|||
import org.fnives.test.showcase.model.content.ContentId
|
||||
import org.fnives.test.showcase.model.content.ImageUrl
|
||||
import org.fnives.test.showcase.network.shared.ExceptionWrapper
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class ContentRemoteSourceImpl @Inject constructor(
|
||||
internal class ContentRemoteSourceImpl(
|
||||
private val contentService: ContentService
|
||||
) : ContentRemoteSource {
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
package org.fnives.test.showcase.network.di.koin
|
||||
package org.fnives.test.showcase.network.di
|
||||
|
||||
import okhttp3.OkHttpClient
|
||||
import org.fnives.test.showcase.model.network.BaseUrl
|
||||
|
|
@ -9,7 +9,6 @@ import org.fnives.test.showcase.network.auth.LoginService
|
|||
import org.fnives.test.showcase.network.content.ContentRemoteSource
|
||||
import org.fnives.test.showcase.network.content.ContentRemoteSourceImpl
|
||||
import org.fnives.test.showcase.network.content.ContentService
|
||||
import org.fnives.test.showcase.network.di.setupLogging
|
||||
import org.fnives.test.showcase.network.session.AuthenticationHeaderInterceptor
|
||||
import org.fnives.test.showcase.network.session.AuthenticationHeaderUtils
|
||||
import org.fnives.test.showcase.network.session.NetworkSessionExpirationListener
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
package org.fnives.test.showcase.network.di.hilt
|
||||
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import okhttp3.OkHttpClient
|
||||
import org.fnives.test.showcase.hilt.SessionLessQualifier
|
||||
|
||||
@InstallIn(SingletonComponent::class)
|
||||
@Module
|
||||
abstract class BindsBaseOkHttpClient {
|
||||
|
||||
@Binds
|
||||
@SessionLessQualifier
|
||||
abstract fun bindsSessionLess(okHttpClient: OkHttpClient): OkHttpClient
|
||||
}
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
package org.fnives.test.showcase.network.di.hilt
|
||||
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import okhttp3.OkHttpClient
|
||||
import org.fnives.test.showcase.hilt.SessionLessQualifier
|
||||
import org.fnives.test.showcase.hilt.SessionQualifier
|
||||
import org.fnives.test.showcase.network.auth.LoginRemoteSource
|
||||
import org.fnives.test.showcase.network.auth.LoginRemoteSourceImpl
|
||||
import org.fnives.test.showcase.network.auth.LoginService
|
||||
import org.fnives.test.showcase.network.content.ContentRemoteSource
|
||||
import org.fnives.test.showcase.network.content.ContentRemoteSourceImpl
|
||||
import org.fnives.test.showcase.network.content.ContentService
|
||||
import org.fnives.test.showcase.network.di.setupLogging
|
||||
import org.fnives.test.showcase.network.session.AuthenticationHeaderInterceptor
|
||||
import org.fnives.test.showcase.network.session.AuthenticationHeaderUtils
|
||||
import org.fnives.test.showcase.network.session.SessionAuthenticator
|
||||
import org.fnives.test.showcase.network.shared.PlatformInterceptor
|
||||
import retrofit2.Converter
|
||||
import retrofit2.Retrofit
|
||||
import retrofit2.converter.moshi.MoshiConverterFactory
|
||||
import javax.inject.Singleton
|
||||
|
||||
@InstallIn(SingletonComponent::class)
|
||||
@Module
|
||||
object HiltNetworkModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideConverterFactory(): Converter.Factory = MoshiConverterFactory.create()
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideSessionLessOkHttpClient(enableLogging: Boolean) =
|
||||
OkHttpClient.Builder()
|
||||
.addInterceptor(PlatformInterceptor())
|
||||
.setupLogging(enableLogging)
|
||||
.build()
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@SessionLessQualifier
|
||||
fun provideSessionLessRetrofit(
|
||||
baseUrl: String,
|
||||
converterFactory: Converter.Factory,
|
||||
@SessionLessQualifier okHttpClient: OkHttpClient
|
||||
) = Retrofit.Builder()
|
||||
.baseUrl(baseUrl)
|
||||
.addConverterFactory(converterFactory)
|
||||
.client(okHttpClient)
|
||||
.build()
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@SessionQualifier
|
||||
internal fun provideSessionOkHttpClient(
|
||||
@SessionLessQualifier okHttpClient: OkHttpClient,
|
||||
sessionAuthenticator: SessionAuthenticator,
|
||||
authenticationHeaderUtils: AuthenticationHeaderUtils
|
||||
) =
|
||||
okHttpClient
|
||||
.newBuilder()
|
||||
.authenticator(sessionAuthenticator)
|
||||
.addInterceptor(AuthenticationHeaderInterceptor(authenticationHeaderUtils))
|
||||
.build()
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@SessionQualifier
|
||||
fun provideSessionRetrofit(
|
||||
@SessionLessQualifier retrofit: Retrofit,
|
||||
@SessionQualifier okHttpClient: OkHttpClient
|
||||
) = retrofit.newBuilder()
|
||||
.client(okHttpClient)
|
||||
.build()
|
||||
|
||||
@Provides
|
||||
internal fun bindContentRemoteSource(
|
||||
contentRemoteSourceImpl: ContentRemoteSourceImpl
|
||||
): ContentRemoteSource = contentRemoteSourceImpl
|
||||
|
||||
@Provides
|
||||
internal fun bindLoginRemoteSource(
|
||||
loginRemoteSource: LoginRemoteSourceImpl
|
||||
): LoginRemoteSource = loginRemoteSource
|
||||
|
||||
@Provides
|
||||
internal fun provideLoginService(@SessionLessQualifier retrofit: Retrofit): LoginService =
|
||||
retrofit.create(LoginService::class.java)
|
||||
|
||||
@Provides
|
||||
internal fun provideContentService(@SessionQualifier retrofit: Retrofit): ContentService =
|
||||
retrofit.create(ContentService::class.java)
|
||||
}
|
||||
|
|
@ -1,9 +1,8 @@
|
|||
package org.fnives.test.showcase.network.session
|
||||
|
||||
import okhttp3.Request
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class AuthenticationHeaderUtils @Inject constructor(
|
||||
internal class AuthenticationHeaderUtils(
|
||||
private val networkSessionLocalStorage: NetworkSessionLocalStorage
|
||||
) {
|
||||
|
||||
|
|
|
|||
|
|
@ -6,9 +6,8 @@ import okhttp3.Request
|
|||
import okhttp3.Response
|
||||
import okhttp3.Route
|
||||
import org.fnives.test.showcase.network.auth.LoginRemoteSourceImpl
|
||||
import javax.inject.Inject
|
||||
|
||||
internal class SessionAuthenticator @Inject constructor(
|
||||
internal class SessionAuthenticator(
|
||||
private val networkSessionLocalStorage: NetworkSessionLocalStorage,
|
||||
private val loginRemoteSource: LoginRemoteSourceImpl,
|
||||
private val authenticationHeaderUtils: AuthenticationHeaderUtils,
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
package org.fnives.test.showcase.network
|
||||
|
||||
import dagger.BindsInstance
|
||||
import dagger.Component
|
||||
import org.fnives.test.showcase.network.auth.hilt.LoginRemoteSourceRefreshActionImplTest
|
||||
import org.fnives.test.showcase.network.auth.hilt.LoginRemoteSourceTest
|
||||
import org.fnives.test.showcase.network.content.hilt.ContentRemoteSourceImplTest
|
||||
import org.fnives.test.showcase.network.content.hilt.SessionExpirationTest
|
||||
import org.fnives.test.showcase.network.di.hilt.BindsBaseOkHttpClient
|
||||
import org.fnives.test.showcase.network.di.hilt.HiltNetworkModule
|
||||
import org.fnives.test.showcase.network.session.NetworkSessionExpirationListener
|
||||
import org.fnives.test.showcase.network.session.NetworkSessionLocalStorage
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
@Component(modules = [HiltNetworkModule::class, BindsBaseOkHttpClient::class])
|
||||
interface TestNetworkComponent {
|
||||
|
||||
@Component.Builder
|
||||
interface Builder {
|
||||
|
||||
@BindsInstance
|
||||
fun setBaseUrl(baseUrl: String): Builder
|
||||
|
||||
@BindsInstance
|
||||
fun setEnableLogging(enableLogging: Boolean): Builder
|
||||
|
||||
@BindsInstance
|
||||
fun setNetworkSessionLocalStorage(storage: NetworkSessionLocalStorage): Builder
|
||||
|
||||
@BindsInstance
|
||||
fun setNetworkSessionExpirationListener(listener: NetworkSessionExpirationListener): Builder
|
||||
|
||||
fun build(): TestNetworkComponent
|
||||
}
|
||||
|
||||
fun inject(contentRemoteSourceImplTest: ContentRemoteSourceImplTest)
|
||||
|
||||
fun inject(sessionExpirationTest: SessionExpirationTest)
|
||||
|
||||
fun inject(loginRemoteSourceRefreshActionImplTest: LoginRemoteSourceRefreshActionImplTest)
|
||||
|
||||
fun inject(loginRemoteSourceTest: LoginRemoteSourceTest)
|
||||
}
|
||||
|
|
@ -1,9 +1,8 @@
|
|||
package org.fnives.test.showcase.network.auth.koin
|
||||
package org.fnives.test.showcase.network.auth
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.fnives.test.showcase.model.network.BaseUrl
|
||||
import org.fnives.test.showcase.network.auth.LoginRemoteSourceImpl
|
||||
import org.fnives.test.showcase.network.di.koin.createNetworkModules
|
||||
import org.fnives.test.showcase.network.di.createNetworkModules
|
||||
import org.fnives.test.showcase.network.mockserver.ContentData
|
||||
import org.fnives.test.showcase.network.mockserver.scenario.refresh.RefreshTokenScenario
|
||||
import org.fnives.test.showcase.network.session.NetworkSessionLocalStorage
|
||||
|
|
@ -1,11 +1,10 @@
|
|||
package org.fnives.test.showcase.network.auth.koin
|
||||
package org.fnives.test.showcase.network.auth
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.fnives.test.showcase.model.auth.LoginCredentials
|
||||
import org.fnives.test.showcase.model.network.BaseUrl
|
||||
import org.fnives.test.showcase.network.auth.LoginRemoteSource
|
||||
import org.fnives.test.showcase.network.auth.model.LoginStatusResponses
|
||||
import org.fnives.test.showcase.network.di.koin.createNetworkModules
|
||||
import org.fnives.test.showcase.network.di.createNetworkModules
|
||||
import org.fnives.test.showcase.network.mockserver.ContentData
|
||||
import org.fnives.test.showcase.network.mockserver.ContentData.createExpectedLoginRequestJson
|
||||
import org.fnives.test.showcase.network.mockserver.scenario.auth.AuthScenario
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
package org.fnives.test.showcase.network.auth.hilt
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.fnives.test.showcase.network.DaggerTestNetworkComponent
|
||||
import org.fnives.test.showcase.network.auth.LoginRemoteSourceImpl
|
||||
import org.fnives.test.showcase.network.mockserver.ContentData
|
||||
import org.fnives.test.showcase.network.mockserver.scenario.refresh.RefreshTokenScenario
|
||||
import org.fnives.test.showcase.network.session.NetworkSessionLocalStorage
|
||||
import org.fnives.test.showcase.network.shared.MockServerScenarioSetupExtensions
|
||||
import org.fnives.test.showcase.network.shared.exceptions.NetworkException
|
||||
import org.fnives.test.showcase.network.shared.exceptions.ParsingException
|
||||
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.junit.jupiter.api.extension.RegisterExtension
|
||||
import org.mockito.kotlin.mock
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
class LoginRemoteSourceRefreshActionImplTest {
|
||||
|
||||
@Inject
|
||||
internal lateinit var sut: LoginRemoteSourceImpl
|
||||
private lateinit var mockNetworkSessionLocalStorage: NetworkSessionLocalStorage
|
||||
|
||||
@RegisterExtension
|
||||
@JvmField
|
||||
val mockServerScenarioSetupExtensions = MockServerScenarioSetupExtensions()
|
||||
private val mockServerScenarioSetup
|
||||
get() = mockServerScenarioSetupExtensions.mockServerScenarioSetup
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
mockNetworkSessionLocalStorage = mock()
|
||||
DaggerTestNetworkComponent.builder()
|
||||
.setBaseUrl(mockServerScenarioSetupExtensions.url)
|
||||
.setEnableLogging(true)
|
||||
.setNetworkSessionLocalStorage(mockNetworkSessionLocalStorage)
|
||||
.setNetworkSessionExpirationListener(mock())
|
||||
.build()
|
||||
.inject(this)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN successful response WHEN refresh request is fired THEN session is returned")
|
||||
@Test
|
||||
fun successResponseResultsInSession() = runBlocking {
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Success)
|
||||
val expected = ContentData.refreshSuccessResponse
|
||||
|
||||
val actual = sut.refresh(ContentData.refreshSuccessResponse.refreshToken)
|
||||
|
||||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN successful response WHEN refresh request is fired THEN the request is setup properly")
|
||||
@Test
|
||||
fun refreshRequestIsSetupProperly() = runBlocking {
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Success, false)
|
||||
|
||||
sut.refresh(ContentData.refreshSuccessResponse.refreshToken)
|
||||
val request = mockServerScenarioSetup.takeRequest()
|
||||
|
||||
Assertions.assertEquals("PUT", request.method)
|
||||
Assertions.assertEquals("Android", request.getHeader("Platform"))
|
||||
Assertions.assertEquals(null, request.getHeader("Authorization"))
|
||||
Assertions.assertEquals(
|
||||
"/login/${ContentData.refreshSuccessResponse.refreshToken}",
|
||||
request.path
|
||||
)
|
||||
Assertions.assertEquals("", request.body.readUtf8())
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN internal error response WHEN refresh request is fired THEN network exception is thrown")
|
||||
@Test
|
||||
fun generalErrorResponseResultsInNetworkException() {
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Error)
|
||||
|
||||
Assertions.assertThrows(NetworkException::class.java) {
|
||||
runBlocking { sut.refresh(ContentData.refreshSuccessResponse.refreshToken) }
|
||||
}
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN invalid json response WHEN refresh request is fired THEN network exception is thrown")
|
||||
@Test
|
||||
fun jsonErrorResponseResultsInParsingException() {
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.UnexpectedJsonAsSuccessResponse)
|
||||
|
||||
Assertions.assertThrows(ParsingException::class.java) {
|
||||
runBlocking { sut.refresh(ContentData.loginSuccessResponse.refreshToken) }
|
||||
}
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN malformed json response WHEN refresh request is fired THEN parsing exception is thrown")
|
||||
@Test
|
||||
fun malformedJsonErrorResponseResultsInParsingException() {
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.MalformedJson)
|
||||
|
||||
Assertions.assertThrows(ParsingException::class.java) {
|
||||
runBlocking { sut.refresh(ContentData.loginSuccessResponse.refreshToken) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,120 +0,0 @@
|
|||
package org.fnives.test.showcase.network.auth.hilt
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.fnives.test.showcase.model.auth.LoginCredentials
|
||||
import org.fnives.test.showcase.network.DaggerTestNetworkComponent
|
||||
import org.fnives.test.showcase.network.auth.LoginRemoteSource
|
||||
import org.fnives.test.showcase.network.auth.model.LoginStatusResponses
|
||||
import org.fnives.test.showcase.network.mockserver.ContentData
|
||||
import org.fnives.test.showcase.network.mockserver.ContentData.createExpectedLoginRequestJson
|
||||
import org.fnives.test.showcase.network.mockserver.scenario.auth.AuthScenario
|
||||
import org.fnives.test.showcase.network.session.NetworkSessionLocalStorage
|
||||
import org.fnives.test.showcase.network.shared.MockServerScenarioSetupExtensions
|
||||
import org.fnives.test.showcase.network.shared.exceptions.NetworkException
|
||||
import org.fnives.test.showcase.network.shared.exceptions.ParsingException
|
||||
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.junit.jupiter.api.extension.RegisterExtension
|
||||
import org.mockito.kotlin.mock
|
||||
import org.skyscreamer.jsonassert.JSONAssert
|
||||
import org.skyscreamer.jsonassert.JSONCompareMode
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
class LoginRemoteSourceTest {
|
||||
|
||||
@Inject
|
||||
internal lateinit var sut: LoginRemoteSource
|
||||
|
||||
@RegisterExtension
|
||||
@JvmField
|
||||
val mockServerScenarioSetupExtensions = MockServerScenarioSetupExtensions()
|
||||
private val mockServerScenarioSetup
|
||||
get() = mockServerScenarioSetupExtensions.mockServerScenarioSetup
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
val mockNetworkSessionLocalStorage = mock<NetworkSessionLocalStorage>()
|
||||
DaggerTestNetworkComponent.builder()
|
||||
.setBaseUrl(mockServerScenarioSetupExtensions.url)
|
||||
.setEnableLogging(true)
|
||||
.setNetworkSessionLocalStorage(mockNetworkSessionLocalStorage)
|
||||
.setNetworkSessionExpirationListener(mock())
|
||||
.build()
|
||||
.inject(this)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN successful response WHEN request is fired THEN login status success is returned")
|
||||
@Test
|
||||
fun successResponseIsParsedProperly() = runBlocking {
|
||||
mockServerScenarioSetup.setScenario(AuthScenario.Success("a", "b"))
|
||||
val expected = LoginStatusResponses.Success(ContentData.loginSuccessResponse)
|
||||
|
||||
val actual = sut.login(LoginCredentials("a", "b"))
|
||||
|
||||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@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)
|
||||
|
||||
sut.login(LoginCredentials("a", "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")
|
||||
JSONAssert.assertEquals(
|
||||
loginRequest,
|
||||
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 {
|
||||
mockServerScenarioSetup.setScenario(AuthScenario.InvalidCredentials("a", "b"))
|
||||
val expected = LoginStatusResponses.InvalidCredentials
|
||||
|
||||
val actual = sut.login(LoginCredentials("a", "b"))
|
||||
|
||||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN internal error response WHEN request is fired THEN network exception is thrown")
|
||||
@Test
|
||||
fun genericErrorMeansNetworkError() {
|
||||
mockServerScenarioSetup.setScenario(AuthScenario.GenericError("a", "b"))
|
||||
|
||||
Assertions.assertThrows(NetworkException::class.java) {
|
||||
runBlocking { sut.login(LoginCredentials("a", "b")) }
|
||||
}
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN invalid json response WHEN request is fired THEN network exception is thrown")
|
||||
@Test
|
||||
fun invalidJsonMeansParsingException() {
|
||||
mockServerScenarioSetup.setScenario(AuthScenario.UnexpectedJsonAsSuccessResponse("a", "b"))
|
||||
|
||||
Assertions.assertThrows(ParsingException::class.java) {
|
||||
runBlocking { sut.login(LoginCredentials("a", "b")) }
|
||||
}
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN malformed json response WHEN request is fired THEN network exception is thrown")
|
||||
@Test
|
||||
fun malformedJsonMeansParsingException() {
|
||||
mockServerScenarioSetup.setScenario(AuthScenario.MalformedJsonAsSuccessResponse("a", "b"))
|
||||
|
||||
Assertions.assertThrows(ParsingException::class.java) {
|
||||
runBlocking { sut.login(LoginCredentials("a", "b")) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ package org.fnives.test.showcase.network.content
|
|||
import kotlinx.coroutines.runBlocking
|
||||
import okhttp3.mockwebserver.MockWebServer
|
||||
import org.fnives.test.showcase.model.network.BaseUrl
|
||||
import org.fnives.test.showcase.network.di.koin.createNetworkModules
|
||||
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.junit.jupiter.api.AfterEach
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
package org.fnives.test.showcase.network.content.koin
|
||||
package org.fnives.test.showcase.network.content
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.fnives.test.showcase.model.network.BaseUrl
|
||||
import org.fnives.test.showcase.network.content.ContentRemoteSourceImpl
|
||||
import org.fnives.test.showcase.network.di.koin.createNetworkModules
|
||||
import org.fnives.test.showcase.network.di.createNetworkModules
|
||||
import org.fnives.test.showcase.network.mockserver.ContentData
|
||||
import org.fnives.test.showcase.network.mockserver.scenario.content.ContentScenario
|
||||
import org.fnives.test.showcase.network.session.NetworkSessionLocalStorage
|
||||
|
|
@ -1,10 +1,9 @@
|
|||
package org.fnives.test.showcase.network.content.koin
|
||||
package org.fnives.test.showcase.network.content
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.fnives.test.showcase.model.network.BaseUrl
|
||||
import org.fnives.test.showcase.model.session.Session
|
||||
import org.fnives.test.showcase.network.content.ContentRemoteSourceImpl
|
||||
import org.fnives.test.showcase.network.di.koin.createNetworkModules
|
||||
import org.fnives.test.showcase.network.di.createNetworkModules
|
||||
import org.fnives.test.showcase.network.mockserver.ContentData
|
||||
import org.fnives.test.showcase.network.mockserver.scenario.content.ContentScenario
|
||||
import org.fnives.test.showcase.network.mockserver.scenario.refresh.RefreshTokenScenario
|
||||
|
|
@ -1,121 +0,0 @@
|
|||
package org.fnives.test.showcase.network.content.hilt
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.fnives.test.showcase.network.DaggerTestNetworkComponent
|
||||
import org.fnives.test.showcase.network.content.ContentRemoteSourceImpl
|
||||
import org.fnives.test.showcase.network.mockserver.ContentData
|
||||
import org.fnives.test.showcase.network.mockserver.scenario.content.ContentScenario
|
||||
import org.fnives.test.showcase.network.session.NetworkSessionLocalStorage
|
||||
import org.fnives.test.showcase.network.shared.MockServerScenarioSetupExtensions
|
||||
import org.fnives.test.showcase.network.shared.exceptions.NetworkException
|
||||
import org.fnives.test.showcase.network.shared.exceptions.ParsingException
|
||||
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.junit.jupiter.api.extension.RegisterExtension
|
||||
import org.koin.test.inject
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.whenever
|
||||
import javax.inject.Inject
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
class ContentRemoteSourceImplTest {
|
||||
|
||||
@Inject
|
||||
internal lateinit var sut: ContentRemoteSourceImpl
|
||||
|
||||
@RegisterExtension
|
||||
@JvmField
|
||||
val mockServerScenarioSetupExtensions = MockServerScenarioSetupExtensions()
|
||||
private lateinit var mockNetworkSessionLocalStorage: NetworkSessionLocalStorage
|
||||
private val mockServerScenarioSetup
|
||||
get() = mockServerScenarioSetupExtensions.mockServerScenarioSetup
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
mockNetworkSessionLocalStorage = mock()
|
||||
DaggerTestNetworkComponent.builder()
|
||||
.setBaseUrl(mockServerScenarioSetupExtensions.url)
|
||||
.setEnableLogging(true)
|
||||
.setNetworkSessionLocalStorage(mockNetworkSessionLocalStorage)
|
||||
.setNetworkSessionExpirationListener(mock())
|
||||
.build()
|
||||
.inject(this)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN successful response WHEN getting content THEN its parsed and returned correctly")
|
||||
@Test
|
||||
fun successResponseParsing() = runBlocking {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Success(false))
|
||||
val expected = ContentData.contentSuccess
|
||||
|
||||
val actual = sut.get()
|
||||
|
||||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN successful response WHEN getting content THEN the request is setup properly")
|
||||
@Test
|
||||
fun successResponseRequestIsCorrect() = runBlocking {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Success(false), false)
|
||||
|
||||
sut.get()
|
||||
val request = mockServerScenarioSetup.takeRequest()
|
||||
|
||||
Assertions.assertEquals("GET", request.method)
|
||||
Assertions.assertEquals("Android", request.getHeader("Platform"))
|
||||
Assertions.assertEquals(ContentData.loginSuccessResponse.accessToken, request.getHeader("Authorization"))
|
||||
Assertions.assertEquals("/content", request.path)
|
||||
Assertions.assertEquals("", request.body.readUtf8())
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN response with missing Field WHEN getting content THEN invalid is ignored others are returned")
|
||||
@Test
|
||||
fun dataMissingFieldIsIgnored() = runBlocking {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.SuccessWithMissingFields(false))
|
||||
|
||||
val expected = ContentData.contentSuccessWithMissingFields
|
||||
|
||||
val actual = sut.get()
|
||||
|
||||
Assertions.assertEquals(expected, actual)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN error response WHEN getting content THEN network request is thrown")
|
||||
@Test
|
||||
fun errorResponseResultsInNetworkException() {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Error(false))
|
||||
|
||||
Assertions.assertThrows(NetworkException::class.java) {
|
||||
runBlocking { sut.get() }
|
||||
}
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN unexpected json response WHEN getting content THEN parsing request is thrown")
|
||||
@Test
|
||||
fun unexpectedJSONResultsInParsingException() {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.UnexpectedJsonAsSuccessResponse(false))
|
||||
|
||||
Assertions.assertThrows(ParsingException::class.java) {
|
||||
runBlocking { sut.get() }
|
||||
}
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN malformed json response WHEN getting content THEN parsing request is thrown")
|
||||
@Test
|
||||
fun malformedJSONResultsInParsingException() {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.MalformedJsonAsSuccessResponse(false))
|
||||
|
||||
Assertions.assertThrows(ParsingException::class.java) {
|
||||
runBlocking { sut.get() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,110 +0,0 @@
|
|||
package org.fnives.test.showcase.network.content.hilt
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.fnives.test.showcase.model.session.Session
|
||||
import org.fnives.test.showcase.network.DaggerTestNetworkComponent
|
||||
import org.fnives.test.showcase.network.content.ContentRemoteSourceImpl
|
||||
import org.fnives.test.showcase.network.mockserver.ContentData
|
||||
import org.fnives.test.showcase.network.mockserver.scenario.content.ContentScenario
|
||||
import org.fnives.test.showcase.network.mockserver.scenario.refresh.RefreshTokenScenario
|
||||
import org.fnives.test.showcase.network.session.NetworkSessionExpirationListener
|
||||
import org.fnives.test.showcase.network.session.NetworkSessionLocalStorage
|
||||
import org.fnives.test.showcase.network.shared.MockServerScenarioSetupExtensions
|
||||
import org.fnives.test.showcase.network.shared.exceptions.NetworkException
|
||||
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.junit.jupiter.api.extension.RegisterExtension
|
||||
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 javax.inject.Inject
|
||||
|
||||
@Suppress("TestFunctionName")
|
||||
class SessionExpirationTest {
|
||||
|
||||
@Inject
|
||||
internal lateinit var sut: ContentRemoteSourceImpl
|
||||
|
||||
@RegisterExtension
|
||||
@JvmField
|
||||
val mockServerScenarioSetupExtensions = MockServerScenarioSetupExtensions()
|
||||
private val mockServerScenarioSetup
|
||||
get() = mockServerScenarioSetupExtensions.mockServerScenarioSetup
|
||||
private lateinit var mockNetworkSessionLocalStorage: NetworkSessionLocalStorage
|
||||
private lateinit var mockNetworkSessionExpirationListener: NetworkSessionExpirationListener
|
||||
|
||||
@BeforeEach
|
||||
fun setUp() {
|
||||
mockNetworkSessionLocalStorage = mock()
|
||||
mockNetworkSessionExpirationListener = mock()
|
||||
DaggerTestNetworkComponent.builder()
|
||||
.setBaseUrl(mockServerScenarioSetupExtensions.url)
|
||||
.setEnableLogging(true)
|
||||
.setNetworkSessionLocalStorage(mockNetworkSessionLocalStorage)
|
||||
.setNetworkSessionExpirationListener(mockNetworkSessionExpirationListener)
|
||||
.build()
|
||||
.inject(this)
|
||||
}
|
||||
|
||||
@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 {
|
||||
var sessionToReturnByMock: Session? = ContentData.loginSuccessResponse
|
||||
mockServerScenarioSetup.setScenario(
|
||||
ContentScenario.Unauthorized(false)
|
||||
.then(ContentScenario.Success(true)),
|
||||
false
|
||||
)
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Success, false)
|
||||
whenever(mockNetworkSessionLocalStorage.session).doAnswer { sessionToReturnByMock }
|
||||
doAnswer { sessionToReturnByMock = it.arguments[0] as Session? }
|
||||
.whenever(mockNetworkSessionLocalStorage).session = anyOrNull()
|
||||
|
||||
sut.get()
|
||||
|
||||
mockServerScenarioSetup.takeRequest()
|
||||
val refreshRequest = mockServerScenarioSetup.takeRequest()
|
||||
val retryAfterTokenRefreshRequest = mockServerScenarioSetup.takeRequest()
|
||||
|
||||
Assertions.assertEquals("PUT", refreshRequest.method)
|
||||
Assertions.assertEquals(
|
||||
"/login/${ContentData.loginSuccessResponse.refreshToken}",
|
||||
refreshRequest.path
|
||||
)
|
||||
Assertions.assertEquals(null, refreshRequest.getHeader("Authorization"))
|
||||
Assertions.assertEquals("Android", refreshRequest.getHeader("Platform"))
|
||||
Assertions.assertEquals("", refreshRequest.body.readUtf8())
|
||||
Assertions.assertEquals(
|
||||
ContentData.refreshSuccessResponse.accessToken,
|
||||
retryAfterTokenRefreshRequest.getHeader("Authorization")
|
||||
)
|
||||
verify(mockNetworkSessionLocalStorage, times(1)).session =
|
||||
ContentData.refreshSuccessResponse
|
||||
verifyZeroInteractions(mockNetworkSessionExpirationListener)
|
||||
}
|
||||
|
||||
@DisplayName("GIVEN 401 THEN failing refresh WHEN content requested THE error is returned and callback is Called")
|
||||
@Test
|
||||
fun failingRefreshResultsInSessionExpiration() = runBlocking {
|
||||
whenever(mockNetworkSessionLocalStorage.session).doReturn(ContentData.loginSuccessResponse)
|
||||
mockServerScenarioSetup.setScenario(ContentScenario.Unauthorized(false))
|
||||
mockServerScenarioSetup.setScenario(RefreshTokenScenario.Error)
|
||||
|
||||
Assertions.assertThrows(NetworkException::class.java) {
|
||||
runBlocking { sut.get() }
|
||||
}
|
||||
verify(mockNetworkSessionLocalStorage, times(3)).session
|
||||
verify(mockNetworkSessionLocalStorage, times(1)).session = null
|
||||
verifyNoMoreInteractions(mockNetworkSessionLocalStorage)
|
||||
verify(mockNetworkSessionExpirationListener, times(1)).onSessionExpired()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue