diff --git a/build.gradle b/build.gradle index d7a691a3b6..f4a5eac85e 100644 --- a/build.gradle +++ b/build.gradle @@ -9,6 +9,7 @@ buildscript { } dependencies { classpath 'com.android.tools.build:gradle:3.2.1' + classpath "com.airbnb.okreplay:gradle-plugin:1.4.0" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" // NOTE: Do not place your application dependencies here; they belong diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index 49a9a3b72f..09d01fceae 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -2,6 +2,7 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' apply plugin: 'kotlin-kapt' apply plugin: 'realm-android' +apply plugin: 'okreplay' buildscript { @@ -38,6 +39,10 @@ android { } } + adbOptions { + installOptions "-g" + } + } dependencies { @@ -94,14 +99,20 @@ dependencies { // Logging implementation 'com.jakewharton.timber:timber:4.7.1' + debugImplementation 'com.airbnb.okreplay:okreplay:1.4.0' + releaseImplementation 'com.airbnb.okreplay:noop:1.4.0' + androidTestImplementation 'com.airbnb.okreplay:espresso:1.4.0' testImplementation 'junit:junit:4.12' testImplementation 'org.robolectric:robolectric:4.0.2' + testImplementation "org.koin:koin-test:$koin_version" testImplementation 'org.robolectric:shadows-support-v4:3.0' testImplementation "io.mockk:mockk:1.8.13.kotlin13" testImplementation 'org.amshove.kluent:kluent-android:1.44' + androidTestImplementation "org.koin:koin-test:$koin_version" androidTestImplementation 'com.android.support.test:runner:1.0.2' + androidTestImplementation "com.android.support.test:rules:1.0.2" androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' androidTestImplementation 'org.amshove.kluent:kluent-android:1.44' diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/InstrumentedTest.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/InstrumentedTest.kt index c726b7eb0f..b40f8a8ada 100644 --- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/InstrumentedTest.kt +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/InstrumentedTest.kt @@ -4,7 +4,7 @@ import android.content.Context import android.support.test.InstrumentationRegistry import java.io.File -abstract class InstrumentedTest { +interface InstrumentedTest { fun context(): Context { return InstrumentationRegistry.getTargetContext() } diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/OkReplayRuleChainNoActivity.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/OkReplayRuleChainNoActivity.kt new file mode 100644 index 0000000000..9ed443f53e --- /dev/null +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/OkReplayRuleChainNoActivity.kt @@ -0,0 +1,16 @@ +package im.vector.matrix.android + +import okreplay.OkReplayConfig +import okreplay.PermissionRule +import okreplay.RecorderRule +import org.junit.rules.RuleChain +import org.junit.rules.TestRule + +class OkReplayRuleChainNoActivity( + private val configuration: OkReplayConfig) { + + fun get(): TestRule { + return RuleChain.outerRule(PermissionRule(configuration)) + .around(RecorderRule(configuration)) + } +} \ No newline at end of file diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/auth/AuthenticatorTest.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/auth/AuthenticatorTest.kt new file mode 100644 index 0000000000..e0c1c0f534 --- /dev/null +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/auth/AuthenticatorTest.kt @@ -0,0 +1,64 @@ +package im.vector.matrix.android.auth + +import android.support.test.annotation.UiThreadTest +import android.support.test.rule.GrantPermissionRule +import android.support.test.runner.AndroidJUnit4 +import com.zhuinden.monarchy.Monarchy +import im.vector.matrix.android.InstrumentedTest +import im.vector.matrix.android.OkReplayRuleChainNoActivity +import im.vector.matrix.android.api.MatrixOptions +import im.vector.matrix.android.api.auth.Authenticator +import im.vector.matrix.android.internal.auth.AuthModule +import im.vector.matrix.android.internal.di.MatrixModule +import im.vector.matrix.android.internal.di.NetworkModule +import okreplay.* +import org.junit.ClassRule +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.koin.standalone.StandAloneContext.loadKoinModules +import org.koin.standalone.inject +import org.koin.test.KoinTest + + +@RunWith(AndroidJUnit4::class) +internal class AuthenticatorTest : InstrumentedTest, KoinTest { + + init { + Monarchy.init(context()) + val matrixModule = MatrixModule(MatrixOptions(context())).definition + val networkModule = NetworkModule().definition + val authModule = AuthModule().definition + loadKoinModules(listOf(matrixModule, networkModule, authModule)) + } + + private val authenticator: Authenticator by inject() + private val okReplayInterceptor: OkReplayInterceptor by inject() + + private val okReplayConfig = OkReplayConfig.Builder() + .tapeRoot(AndroidTapeRoot( + context(), javaClass)) + .defaultMode(TapeMode.READ_WRITE) // or TapeMode.READ_ONLY + .sslEnabled(true) + .interceptor(okReplayInterceptor) + .build() + + @get:Rule + val testRule = OkReplayRuleChainNoActivity(okReplayConfig).get() + + @Test + @UiThreadTest + @OkReplay(tape = "auth", mode = TapeMode.READ_WRITE) + fun auth() { + + } + + companion object { + @ClassRule + @JvmField + val grantExternalStoragePermissionRule: GrantPermissionRule = + GrantPermissionRule.grant(android.Manifest.permission.WRITE_EXTERNAL_STORAGE) + } + + +} \ No newline at end of file diff --git a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/ChunkEntityTest.kt b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/ChunkEntityTest.kt index b1c8993501..137ec790e1 100644 --- a/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/ChunkEntityTest.kt +++ b/matrix-sdk-android/src/androidTest/java/im/vector/matrix/android/session/room/timeline/ChunkEntityTest.kt @@ -22,7 +22,7 @@ import org.junit.Test import kotlin.random.Random -internal class ChunkEntityTest : InstrumentedTest() { +internal class ChunkEntityTest : InstrumentedTest { private lateinit var monarchy: Monarchy diff --git a/matrix-sdk-android/src/main/AndroidManifest.xml b/matrix-sdk-android/src/main/AndroidManifest.xml index 44b519b0b0..fc705e553c 100644 --- a/matrix-sdk-android/src/main/AndroidManifest.xml +++ b/matrix-sdk-android/src/main/AndroidManifest.xml @@ -3,4 +3,5 @@ + diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/Matrix.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/Matrix.kt index 88bf3c3eb3..689f05645a 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/Matrix.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/api/Matrix.kt @@ -23,12 +23,10 @@ class Matrix(matrixOptions: MatrixOptions) : KoinComponent { init { Monarchy.init(matrixOptions.context) - - val matrixModule = MatrixModule(matrixOptions) - val networkModule = NetworkModule() - val authModule = AuthModule() + val matrixModule = MatrixModule(matrixOptions).definition + val networkModule = NetworkModule().definition + val authModule = AuthModule().definition loadKoinModules(listOf(matrixModule, networkModule, authModule)) - ProcessLifecycleOwner.get().lifecycle.addObserver(backgroundDetectionObserver) val lastActiveSession = authenticator.getLastActiveSession() diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthModule.kt index ab5443e0d1..10f760e860 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/auth/AuthModule.kt @@ -4,13 +4,11 @@ import im.vector.matrix.android.api.auth.Authenticator import im.vector.matrix.android.internal.auth.db.RealmSessionParamsStore import im.vector.matrix.android.internal.auth.db.SessionParamsMapper import io.realm.RealmConfiguration -import org.koin.dsl.context.ModuleDefinition -import org.koin.dsl.module.Module import org.koin.dsl.module.module -class AuthModule : Module { +class AuthModule { - override fun invoke(): ModuleDefinition = module { + val definition = module { single { DefaultAuthenticator(get(), get(), get()) as Authenticator @@ -22,5 +20,5 @@ class AuthModule : Module { RealmSessionParamsStore(mapper, realmConfiguration) as SessionParamsStore } - }.invoke() + } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixModule.kt index d5dfd618e7..154777d0e4 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/MatrixModule.kt @@ -6,14 +6,12 @@ import im.vector.matrix.android.internal.util.BackgroundDetectionObserver import im.vector.matrix.android.internal.util.MatrixCoroutineDispatchers import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.asCoroutineDispatcher -import org.koin.dsl.context.ModuleDefinition -import org.koin.dsl.module.Module import org.koin.dsl.module.module -class MatrixModule(private val options: MatrixOptions) : Module { +class MatrixModule(private val options: MatrixOptions) { - override fun invoke(): ModuleDefinition = module { + val definition = module { single { options.context @@ -27,5 +25,5 @@ class MatrixModule(private val options: MatrixOptions) : Module { BackgroundDetectionObserver() } - }.invoke() + } } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/NetworkModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/NetworkModule.kt index 69f2c68f0f..fe9709b24e 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/NetworkModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/di/NetworkModule.kt @@ -4,8 +4,7 @@ import im.vector.matrix.android.internal.network.AccessTokenInterceptor import im.vector.matrix.android.internal.network.NetworkConnectivityChecker import okhttp3.OkHttpClient import okhttp3.logging.HttpLoggingInterceptor -import org.koin.dsl.context.ModuleDefinition -import org.koin.dsl.module.Module +import okreplay.OkReplayInterceptor import org.koin.dsl.module.module import retrofit2.Converter import retrofit2.Retrofit @@ -13,9 +12,9 @@ import retrofit2.converter.moshi.MoshiConverterFactory import timber.log.Timber import java.util.concurrent.TimeUnit -class NetworkModule : Module { +class NetworkModule { - override fun invoke(): ModuleDefinition = module { + val definition = module { single { AccessTokenInterceptor(get()) @@ -28,13 +27,18 @@ class NetworkModule : Module { interceptor } + single { + OkReplayInterceptor() + } + single { OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS) .writeTimeout(30, TimeUnit.SECONDS) - .addInterceptor(get() as AccessTokenInterceptor) - .addInterceptor(get() as HttpLoggingInterceptor) + .addInterceptor(get()) + .addInterceptor(get()) + .addInterceptor(get()) .build() } @@ -56,5 +60,5 @@ class NetworkModule : Module { .addConverterFactory(get()) } - }.invoke() + } } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt index d474c8d926..e5d86c1d41 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/DefaultSession.kt @@ -3,6 +3,7 @@ package im.vector.matrix.android.internal.session import android.arch.lifecycle.LiveData import android.os.Looper import android.support.annotation.MainThread +import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.group.Group import im.vector.matrix.android.api.session.group.GroupService @@ -10,7 +11,6 @@ import im.vector.matrix.android.api.session.group.model.GroupSummary import im.vector.matrix.android.api.session.room.Room import im.vector.matrix.android.api.session.room.RoomService import im.vector.matrix.android.api.session.room.model.RoomSummary -import im.vector.matrix.android.api.auth.data.SessionParams import im.vector.matrix.android.internal.database.LiveEntityObserver import im.vector.matrix.android.internal.session.group.GroupModule import im.vector.matrix.android.internal.session.room.RoomModule @@ -39,13 +39,13 @@ internal class DefaultSession(override val sessionParams: SessionParams) : Sessi @MainThread override fun open() { - checkIsMainThread() + assertMainThread() assert(!isOpen) isOpen = true - val sessionModule = SessionModule(sessionParams) - val syncModule = SyncModule() - val roomModule = RoomModule() - val groupModule = GroupModule() + val sessionModule = SessionModule(sessionParams).definition + val syncModule = SyncModule().definition + val roomModule = RoomModule().definition + val groupModule = GroupModule().definition StandAloneContext.loadKoinModules(listOf(sessionModule, syncModule, roomModule, groupModule)) scope = getKoin().getOrCreateScope(SCOPE) liveEntityUpdaters.forEach { it.start() } @@ -55,7 +55,7 @@ internal class DefaultSession(override val sessionParams: SessionParams) : Sessi @MainThread override fun close() { - checkIsMainThread() + assertMainThread() assert(isOpen) syncThread.kill() liveEntityUpdaters.forEach { it.dispose() } @@ -109,9 +109,9 @@ internal class DefaultSession(override val sessionParams: SessionParams) : Sessi // Private methods ***************************************************************************** - private fun checkIsMainThread() { - if (Looper.myLooper() != Looper.getMainLooper()) { - throw IllegalStateException("Should be called on main thread") + private fun assertMainThread() { + if (Looper.getMainLooper().thread !== Thread.currentThread()) { + throw IllegalStateException("This method can only be called on the main thread!") } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt index 8c88122c55..55990d4ed3 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/SessionModule.kt @@ -16,15 +16,13 @@ import im.vector.matrix.android.internal.session.room.members.RoomDisplayNameRes import im.vector.matrix.android.internal.session.room.members.RoomMemberDisplayNameResolver import im.vector.matrix.android.internal.util.md5 import io.realm.RealmConfiguration -import org.koin.dsl.context.ModuleDefinition -import org.koin.dsl.module.Module import org.koin.dsl.module.module import retrofit2.Retrofit import java.io.File -internal class SessionModule(private val sessionParams: SessionParams) : Module { +internal class SessionModule(private val sessionParams: SessionParams) { - override fun invoke(): ModuleDefinition = module(override = true) { + val definition = module(override = true) { scope(DefaultSession.SCOPE) { sessionParams @@ -85,7 +83,7 @@ internal class SessionModule(private val sessionParams: SessionParams) : Module } - }.invoke() + } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupModule.kt index 1f8bf99ce3..d1dd75ffdb 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/group/GroupModule.kt @@ -1,14 +1,12 @@ package im.vector.matrix.android.internal.session.group import im.vector.matrix.android.internal.session.DefaultSession -import org.koin.dsl.context.ModuleDefinition -import org.koin.dsl.module.Module import org.koin.dsl.module.module import retrofit2.Retrofit -class GroupModule : Module { +class GroupModule { - override fun invoke(): ModuleDefinition = module(override = true) { + val definition = module(override = true) { scope(DefaultSession.SCOPE) { val retrofit: Retrofit = get() @@ -19,5 +17,5 @@ class GroupModule : Module { GetGroupDataRequest(get(), get(), get()) } - }.invoke() + } } \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt index 9a7e897eaf..a823124c54 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/room/RoomModule.kt @@ -9,16 +9,14 @@ import im.vector.matrix.android.internal.session.room.members.LoadRoomMembersReq import im.vector.matrix.android.internal.session.room.send.DefaultSendService import im.vector.matrix.android.internal.session.room.timeline.* import im.vector.matrix.android.internal.util.PagingRequestHelper -import org.koin.dsl.context.ModuleDefinition -import org.koin.dsl.module.Module import org.koin.dsl.module.module import retrofit2.Retrofit import java.util.concurrent.Executors -class RoomModule : Module { +class RoomModule { - override fun invoke(): ModuleDefinition = module(override = true) { + val definition = module(override = true) { scope(DefaultSession.SCOPE) { val retrofit: Retrofit = get() @@ -56,5 +54,5 @@ class RoomModule : Module { DefaultSendService(roomId, get(), get()) as SendService } - }.invoke() + } } diff --git a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncModule.kt b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncModule.kt index 0ae3e61837..dca339c018 100644 --- a/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncModule.kt +++ b/matrix-sdk-android/src/main/java/im/vector/matrix/android/internal/session/sync/SyncModule.kt @@ -2,15 +2,13 @@ package im.vector.matrix.android.internal.session.sync import im.vector.matrix.android.internal.session.DefaultSession import im.vector.matrix.android.internal.session.sync.job.SyncThread -import org.koin.dsl.context.ModuleDefinition -import org.koin.dsl.module.Module import org.koin.dsl.module.module import retrofit2.Retrofit -internal class SyncModule : Module { +internal class SyncModule { - override fun invoke(): ModuleDefinition = module(override = true) { + val definition = module(override = true) { scope(DefaultSession.SCOPE) { val retrofit: Retrofit = get() @@ -49,5 +47,5 @@ internal class SyncModule : Module { SyncThread(get(), get(), get(), get()) } - }.invoke() + } }