Skip to content

Commit

Permalink
Flaker (#190)
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelbel authored Nov 26, 2023
1 parent fa21c79 commit 9b6bc74
Show file tree
Hide file tree
Showing 25 changed files with 105 additions and 340 deletions.
25 changes: 25 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,31 @@
android:name="preloaded_fonts"
android:resource="@array/preloaded_fonts" />

<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">

<meta-data
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup"
tools:node="remove" />

<!--<meta-data
android:name="org.michaelbel.movies.common.crashlytics.FirebaseCrashlyticsInitializer"
android:value="androidx.startup"/>-->

<meta-data
android:name="org.michaelbel.movies.common.timber.TimberInitializer"
android:value="androidx.startup" />

<meta-data
android:name="org.michaelbel.movies.network.flaker.FlakerInitializer"
android:value="androidx.startup" />

</provider>

</application>

</manifest>
4 changes: 2 additions & 2 deletions app/src/main/kotlin/org/michaelbel/movies/App.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package org.michaelbel.movies
import android.app.Application
import androidx.hilt.work.HiltWorkerFactory
import androidx.work.Configuration
import com.google.firebase.FirebaseApp
import dagger.hilt.android.HiltAndroidApp
import javax.inject.Inject
import org.michaelbel.movies.common.config.ktx.installFirebaseApp
import org.michaelbel.movies.ui.appicon.installLauncherIcon

@HiltAndroidApp
Expand All @@ -19,6 +19,6 @@ internal class App: Application(), Configuration.Provider {
override fun onCreate() {
super.onCreate()
installLauncherIcon()
FirebaseApp.initializeApp(this)
installFirebaseApp()
}
}
2 changes: 1 addition & 1 deletion core/common/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ dependencies {
api(libs.androidx.activity.compose)
api(libs.androidx.core.ktx)
api(libs.androidx.paging.compose)
api(libs.androidx.startup.runtime)
api(libs.androidx.work.runtime.ktx)
api(libs.androidx.hilt.work)
api(libs.bundles.lifecycle)
api(libs.timber)
implementation(libs.bundles.appcompat)
implementation(libs.firebase.crashlytics.ktx)
implementation(libs.androidx.startup.runtime)
implementation(libs.androidx.browser)

lintChecks(libs.lint.checks)
Expand Down
31 changes: 1 addition & 30 deletions core/common/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,31 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<application>

<provider
android:name="androidx.startup.InitializationProvider"
android:authorities="${applicationId}.androidx-startup"
android:exported="false"
tools:node="merge">

<meta-data
android:name="androidx.work.WorkManagerInitializer"
android:value="androidx.startup"
tools:node="remove" />

<!--<meta-data
android:name="org.michaelbel.movies.common.crashlytics.FirebaseCrashlyticsInitializer"
android:value="androidx.startup"/>-->

<meta-data
android:name="org.michaelbel.movies.common.timber.TimberInitializer"
android:value="androidx.startup"/>

</provider>

</application>

</manifest>
<manifest />
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.michaelbel.movies.common.config.ktx

import android.content.Context
import com.google.firebase.FirebaseApp

fun Context.installFirebaseApp() {
FirebaseApp.initializeApp(this)
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import org.michaelbel.movies.common.crashlytics.CrashlyticsTree
import timber.log.Timber

@Suppress("unused")
internal class TimberInitializer: Initializer<Unit> {
class TimberInitializer: Initializer<Unit> {

override fun create(context: Context) {
Timber.plant(if (BuildConfig.DEBUG) Timber.DebugTree() else CrashlyticsTree())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,17 @@ package org.michaelbel.movies.interactor.impl

import javax.inject.Inject
import javax.inject.Singleton
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.withContext
import org.michaelbel.movies.common.dispatchers.MoviesDispatchers
import org.michaelbel.movies.interactor.AccountInteractor
import org.michaelbel.movies.interactor.usecase.DelayUseCase
import org.michaelbel.movies.persistence.database.entity.AccountDb
import org.michaelbel.movies.repository.AccountRepository

@Singleton
internal class AccountInteractorImpl @Inject constructor(
private val dispatchers: MoviesDispatchers,
private val accountRepository: AccountRepository,
private val delayUseCase: DelayUseCase
private val accountRepository: AccountRepository
): AccountInteractor {

override val account: Flow<AccountDb?> = accountRepository.account
Expand All @@ -34,7 +31,6 @@ internal class AccountInteractorImpl @Inject constructor(

override suspend fun accountDetails() {
return withContext(dispatchers.io) {
delay(delayUseCase.networkRequestDelay())
accountRepository.accountDetails()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,17 @@ package org.michaelbel.movies.interactor.impl

import javax.inject.Inject
import javax.inject.Singleton
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
import org.michaelbel.movies.common.dispatchers.MoviesDispatchers
import org.michaelbel.movies.interactor.AuthenticationInteractor
import org.michaelbel.movies.interactor.usecase.DelayUseCase
import org.michaelbel.movies.network.model.Session
import org.michaelbel.movies.network.model.Token
import org.michaelbel.movies.repository.AuthenticationRepository

@Singleton
internal class AuthenticationInteractorImpl @Inject constructor(
private val dispatchers: MoviesDispatchers,
private val authenticationRepository: AuthenticationRepository,
private val delayUseCase: DelayUseCase
private val authenticationRepository: AuthenticationRepository
): AuthenticationInteractor {

override suspend fun createRequestToken(): Token {
Expand All @@ -39,8 +36,6 @@ internal class AuthenticationInteractorImpl @Inject constructor(
}

override suspend fun deleteSession() {
delay(delayUseCase.networkRequestDelay())

return withContext(dispatchers.io) {
authenticationRepository.deleteSession()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,9 @@ package org.michaelbel.movies.interactor.impl
import androidx.paging.PagingSource
import javax.inject.Inject
import javax.inject.Singleton
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
import org.michaelbel.movies.common.dispatchers.MoviesDispatchers
import org.michaelbel.movies.interactor.MovieInteractor
import org.michaelbel.movies.interactor.usecase.DelayUseCase
import org.michaelbel.movies.network.Either
import org.michaelbel.movies.network.model.MovieResponse
import org.michaelbel.movies.network.model.Result
Expand All @@ -17,25 +15,20 @@ import org.michaelbel.movies.repository.MovieRepository
@Singleton
internal class MovieInteractorImpl @Inject constructor(
private val dispatchers: MoviesDispatchers,
private val movieRepository: MovieRepository,
private val delayUseCase: DelayUseCase
private val movieRepository: MovieRepository
): MovieInteractor {

override fun moviesPagingSource(movieList: String): PagingSource<Int, MovieDb> {
return movieRepository.moviesPagingSource(movieList)
}

override suspend fun moviesResult(movieList: String, page: Int): Result<MovieResponse> {
delay(delayUseCase.networkRequestDelay())

return withContext(dispatchers.io) {
movieRepository.moviesResult(movieList, page)
}
}

override suspend fun movieDetails(movieId: Int): Either<MovieDb> {
delay(delayUseCase.networkRequestDelay())

return withContext(dispatchers.io) {
movieRepository.movieDetails(movieId)
}
Expand Down

This file was deleted.

3 changes: 3 additions & 0 deletions core/network/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,14 @@ android {
}

dependencies {
implementation(libs.androidx.startup.runtime)
api(libs.kotlin.serialization.json)
implementation(libs.okhttp.logging.interceptor)
implementation(libs.retrofit.converter.serialization)
api(libs.retrofit)
debugImplementation(libs.chucker.library)
releaseImplementation(libs.chucker.library.no.op)
debugImplementation(libs.flaker.android.okhttp)
releaseImplementation(libs.flaker.android.okhttp.noop)
// implementation(libs.chucker.library.no.op) enable for benchmark
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.michaelbel.movies.network.flaker

import android.content.Context
import androidx.startup.Initializer
import io.github.rotbolt.flakerandroidokhttp.di.FlakerAndroidOkhttpContainer

@Suppress("unused")
class FlakerInitializer: Initializer<Unit> {

override fun create(context: Context) {
FlakerAndroidOkhttpContainer.install(context)
}

override fun dependencies(): List<Class<out Initializer<*>>> {
return emptyList()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.michaelbel.movies.network.flaker.di

import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import io.github.rotbolt.flakerokhttpcore.FlakerInterceptor
import io.github.rotbolt.flakerokhttpcore.dto.FlakerFailResponse

@Module
@InstallIn(SingletonComponent::class)
internal object FlakerModule {

@Provides
fun provideFlakerInterceptor(): FlakerInterceptor {
val flakerFailResponse = FlakerFailResponse(
httpCode = 500,
message = "Flaker is enabled. This is a flaky response",
responseBodyString = "Test Failure"
)
return FlakerInterceptor.Builder()
.failResponse(flakerFailResponse)
.build()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import io.github.rotbolt.flakerokhttpcore.FlakerInterceptor
import java.util.concurrent.TimeUnit
import javax.inject.Singleton
import okhttp3.Cache
Expand All @@ -19,28 +20,6 @@ import org.michaelbel.movies.network.okhttp.interceptor.ApikeyInterceptor
@InstallIn(SingletonComponent::class)
internal object OkhttpModule {

private const val HTTP_CACHE_SIZE_BYTES = 1024 * 1024 * 50L

/**
* Суммарное время на выполнение запроса (0 - нет ограничений).
*/
private const val CALL_TIMEOUT_SECONDS = 0L

/**
* Время на подключение к заданному хосту.
*/
private const val CONNECT_TIMEOUT_SECONDS = 10L

/**
* Время на получение ответа сервера.
*/
private const val READ_TIMEOUT_SECONDS = 10L

/**
* Время на передачу запроса серверу.
*/
private const val WRITE_TIMEOUT_SECONDS = 10L

@Provides
@Singleton
fun httpCache(
Expand All @@ -67,12 +46,14 @@ internal object OkhttpModule {
@Singleton
fun provideOkHttp(
chuckerInterceptor: ChuckerInterceptor,
flakerInterceptor: FlakerInterceptor,
httpLoggingInterceptor: HttpLoggingInterceptor,
apikeyInterceptor: ApikeyInterceptor,
cache: Cache
): OkHttpClient {
val builder = OkHttpClient.Builder().apply {
addInterceptor(chuckerInterceptor)
addInterceptor(flakerInterceptor)
addInterceptor(httpLoggingInterceptor)
addInterceptor(apikeyInterceptor)
callTimeout(CALL_TIMEOUT_SECONDS, TimeUnit.SECONDS)
Expand All @@ -86,4 +67,10 @@ internal object OkhttpModule {
}
return builder.build()
}

private const val HTTP_CACHE_SIZE_BYTES = 1024 * 1024 * 50L
private const val CALL_TIMEOUT_SECONDS = 0L
private const val CONNECT_TIMEOUT_SECONDS = 10L
private const val READ_TIMEOUT_SECONDS = 10L
private const val WRITE_TIMEOUT_SECONDS = 10L
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ import retrofit2.Converter
@InstallIn(SingletonComponent::class)
internal object ConverterFactoryModule {

private const val MEDIA_TYPE_APPLICATION_JSON = "application/json"

@Provides
@Singleton
fun provideSerializationConverterFactory(): Converter.Factory {
val contentType: MediaType = MEDIA_TYPE_APPLICATION_JSON.toMediaType()
val format = Json { ignoreUnknownKeys = true }
return format.asConverterFactory(contentType)
}

private const val MEDIA_TYPE_APPLICATION_JSON = "application/json"
}
Loading

0 comments on commit 9b6bc74

Please sign in to comment.